From 799049f3f0114e1cf7867f0e31c2be17013b2f08 Mon Sep 17 00:00:00 2001 From: Ashley Childress <6563688+anchildress1@users.noreply.github.com> Date: Sat, 31 Jan 2026 17:53:55 -0500 Subject: [PATCH 1/3] chore(release): add Release Please automation - add a standalone Release Please workflow (pinned to v4.4.0 by SHA) - add manifest config to track version + use plain vX.Y.Z tags - tighten existing security workflows to avoid push-trigger noise Generated-by: GitHub Copilot Signed-off-by: Ashley Childress <6563688+anchildress1@users.noreply.github.com> --- .github/workflows/codeql.yml | 6 +---- .github/workflows/release-please.yml | 33 ++++++++++++++++++++++++++++ .github/workflows/security-ci.yml | 4 +--- .release-please-manifest.json | 3 +++ release-please-config.json | 14 ++++++++++++ 5 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/release-please.yml create mode 100644 .release-please-manifest.json create mode 100644 release-please-config.json diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f9dec0f..7862a29 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,11 +1,7 @@ --- name: "CodeQL Analysis" -"on": - push: - branches: ["main"] - pull_request: - branches: ["main"] +on: schedule: - cron: "23 2 * * 1" # Weekly on Mondays at 2:23 AM UTC workflow_dispatch: {} diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 0000000..6a3fdb8 --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,33 @@ +name: Release Please + +on: + push: + branches: + - main + workflow_dispatch: {} + +permissions: + contents: write + pull-requests: write + issues: write + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + release-please: + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: write + pull-requests: write + issues: write + + steps: + - name: Run Release Please + id: release + uses: googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38 # v4.4.0 + with: + config-file: release-please-config.json + manifest-file: .release-please-manifest.json diff --git a/.github/workflows/security-ci.yml b/.github/workflows/security-ci.yml index 267c937..df63c18 100644 --- a/.github/workflows/security-ci.yml +++ b/.github/workflows/security-ci.yml @@ -1,10 +1,8 @@ name: Security and Quality CI on: - push: - branches: [main] pull_request: - types: [opened, synchronize, reopened] + types: [opened, synchronize, reopened, ready_for_review] workflow_dispatch: {} permissions: diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..466df71 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "0.1.0" +} diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..e8c853e --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,14 @@ +{ + "release-type": "python", + "include-component-in-tag": false, + "packages": { + ".": { + "release-type": "python", + "package-name": "devto-mirror", + "extra-files": [ + "pyproject.toml", + "src/devto_mirror/__init__.py" + ] + } + } +} From 4077239c3aede562694aab52078956b7c2ec27c4 Mon Sep 17 00:00:00 2001 From: Ashley Childress <6563688+anchildress1@users.noreply.github.com> Date: Sat, 31 Jan 2026 18:11:31 -0500 Subject: [PATCH 2/3] ci(actionlint): enforce GitHub Actions linting - add actionlint checks to lefthook pre-commit and pre-push hooks - quote $GITHUB_STEP_SUMMARY in workflows to satisfy shellcheck/actionlint - consolidate multi-echo summary writes into a single redirect block Generated-by: GitHub Copilot Signed-off-by: Ashley Childress <6563688+anchildress1@users.noreply.github.com> --- .github/workflows/publish.yaml | 28 +++++++++++++++------------- .github/workflows/security-ci.yml | 8 ++++---- lefthook.yml | 5 +++++ 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 4c3b784..4abaef2 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -66,19 +66,19 @@ jobs: if git show origin/gh-pages:last_run.txt >/dev/null 2>&1; then TIMESTAMP=$(git show origin/gh-pages:last_run.txt) echo "$TIMESTAMP" > last_run.txt - echo "🔄 Restored last_run.txt from gh-pages: \`$TIMESTAMP\`" >> $GITHUB_STEP_SUMMARY + echo "🔄 Restored last_run.txt from gh-pages: \`$TIMESTAMP\`" >> "$GITHUB_STEP_SUMMARY" else - echo "⚠️ last_run.txt not found on gh-pages branch" >> $GITHUB_STEP_SUMMARY + echo "⚠️ last_run.txt not found on gh-pages branch" >> "$GITHUB_STEP_SUMMARY" fi if git show origin/gh-pages:posts_data.json >/dev/null 2>&1; then git show origin/gh-pages:posts_data.json > posts_data.json - echo "🔄 Restored posts_data.json from gh-pages" >> $GITHUB_STEP_SUMMARY + echo "🔄 Restored posts_data.json from gh-pages" >> "$GITHUB_STEP_SUMMARY" else - echo "⚠️ posts_data.json not found on gh-pages branch" >> $GITHUB_STEP_SUMMARY + echo "⚠️ posts_data.json not found on gh-pages branch" >> "$GITHUB_STEP_SUMMARY" fi else - echo "🆕 gh-pages branch does not exist yet; skipping last_run restore" >> $GITHUB_STEP_SUMMARY + echo "🆕 gh-pages branch does not exist yet; skipping last_run restore" >> "$GITHUB_STEP_SUMMARY" fi - name: Set up uv @@ -107,14 +107,16 @@ jobs: PAGES_REPO: ${{ github.repository }} FORCE_FULL_REGEN: ${{ github.event.inputs.force_full_regen || 'false' }} run: | - echo "## 🏗️ Site Generation" >> $GITHUB_STEP_SUMMARY - echo "- 👤 Dev.to: \`${DEVTO_USERNAME}\`" >> $GITHUB_STEP_SUMMARY - echo "- 📦 Repo: \`${{ github.repository }}\`" >> $GITHUB_STEP_SUMMARY + { + echo "## 🏗️ Site Generation" + echo "- 👤 Dev.to: \`${DEVTO_USERNAME}\`" + echo "- 📦 Repo: \`${{ github.repository }}\`" + } >> "$GITHUB_STEP_SUMMARY" uv run python -m devto_mirror.site_generation.generator - name: Note site generation success if: steps.generate.outputs.no_new_posts != 'true' - run: echo "✅ Generated" >> $GITHUB_STEP_SUMMARY + run: echo "✅ Generated" >> "$GITHUB_STEP_SUMMARY" - name: Prepare timestamp-only deployment if: steps.generate.outputs.no_new_posts == 'true' @@ -140,16 +142,16 @@ jobs: - name: Validate generated site if: steps.generate.outputs.no_new_posts != 'true' run: | - echo "## ✅ Site Validation" >> $GITHUB_STEP_SUMMARY + echo "## ✅ Site Validation" >> "$GITHUB_STEP_SUMMARY" uv run python scripts/validate_site_generation.py - echo "✅ Validation passed" >> $GITHUB_STEP_SUMMARY + echo "✅ Validation passed" >> "$GITHUB_STEP_SUMMARY" - name: Generate sitemap and index if: steps.generate.outputs.no_new_posts != 'true' run: | - echo "## 📄 Generating Sitemap" >> $GITHUB_STEP_SUMMARY + echo "## 📄 Generating Sitemap" >> "$GITHUB_STEP_SUMMARY" uv run python -m devto_mirror.site_generation.renderer - echo "✅ Sitemap generated" >> $GITHUB_STEP_SUMMARY + echo "✅ Sitemap generated" >> "$GITHUB_STEP_SUMMARY" - name: Prepare deployment directory if: steps.generate.outputs.no_new_posts != 'true' diff --git a/.github/workflows/security-ci.yml b/.github/workflows/security-ci.yml index df63c18..728a5df 100644 --- a/.github/workflows/security-ci.yml +++ b/.github/workflows/security-ci.yml @@ -31,16 +31,16 @@ jobs: - name: Install dependencies run: | - echo "## 🔧 Installing dependencies" >> $GITHUB_STEP_SUMMARY + echo "## 🔧 Installing dependencies" >> "$GITHUB_STEP_SUMMARY" uv sync --locked --group dev make install - echo "✅ Dependencies installed" >> $GITHUB_STEP_SUMMARY + echo "✅ Dependencies installed" >> "$GITHUB_STEP_SUMMARY" - name: Run validation run: | - echo "## 🔍 Validation Results" >> $GITHUB_STEP_SUMMARY + echo "## 🔍 Validation Results" >> "$GITHUB_STEP_SUMMARY" make ai-checks - echo "✅ All checks passed" >> $GITHUB_STEP_SUMMARY + echo "✅ All checks passed" >> "$GITHUB_STEP_SUMMARY" - name: Generate coverage and reports run: | diff --git a/lefthook.yml b/lefthook.yml index ece601a..afca6e2 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -15,6 +15,9 @@ pre-commit: security: run: make security stage_fixed: true + actionlint: + glob: ".github/workflows/*.y*ml" + run: actionlint {staged_files} pre-push: parallel: true @@ -25,3 +28,5 @@ pre-push: run: uv run python scripts/check_detect_secrets.py validate-site: run: uv run python scripts/validate_site_generation.py + actionlint: + run: actionlint From 82277b98c0e07b5afdb8c760745b9fad351b5758 Mon Sep 17 00:00:00 2001 From: Ashley Childress <6563688+anchildress1@users.noreply.github.com> Date: Sat, 31 Jan 2026 21:47:21 -0500 Subject: [PATCH 3/3] ci(workflows): pin GitHub Actions to SHAs - Pin github/codeql-action to v4 commit SHA and scope permissions per-job - Pin astral-sh/setup-uv and peaceiris/actions-gh-pages to commit SHAs Generated-by: GitHub Copilot Signed-off-by: Ashley Childress <6563688+anchildress1@users.noreply.github.com> --- .github/workflows/codeql.yml | 15 +++++++-------- .github/workflows/publish.yaml | 6 +++--- .github/workflows/security-ci.yml | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 7862a29..980bc36 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -2,16 +2,13 @@ name: "CodeQL Analysis" on: + pull_request: + branches: [main] + types: [opened, synchronize, reopened, ready_for_review] schedule: - cron: "23 2 * * 1" # Weekly on Mondays at 2:23 AM UTC workflow_dispatch: {} -permissions: - security-events: write - contents: read - actions: read - packages: read - concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -23,6 +20,8 @@ jobs: timeout-minutes: 360 permissions: security-events: write + contents: read + actions: read packages: read strategy: @@ -36,13 +35,13 @@ jobs: uses: actions/checkout@v6 - name: Initialize CodeQL - uses: github/codeql-action/init@v4 + uses: github/codeql-action/init@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} queries: +security-extended,security-and-quality - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v4 + uses: github/codeql-action/analyze@b20883b0cd1f46c72ae0ba6d1090936928f9fa30 # v4 with: category: "/language:${{matrix.language}}" diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 4abaef2..1984e28 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -82,7 +82,7 @@ jobs: fi - name: Set up uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7 with: version: "latest" python-version: "3.12" @@ -128,7 +128,7 @@ jobs: - name: Deploy timestamp-only update if: steps.generate.outputs.no_new_posts == 'true' timeout-minutes: 5 - uses: peaceiris/actions-gh-pages@v4 + uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./_deploy @@ -185,7 +185,7 @@ jobs: - name: Deploy to gh-pages if: steps.generate.outputs.no_new_posts != 'true' timeout-minutes: 5 - uses: peaceiris/actions-gh-pages@v4 + uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./_deploy diff --git a/.github/workflows/security-ci.yml b/.github/workflows/security-ci.yml index 728a5df..ff22e0b 100644 --- a/.github/workflows/security-ci.yml +++ b/.github/workflows/security-ci.yml @@ -23,7 +23,7 @@ jobs: fetch-depth: 0 - name: Set up uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@803947b9bd8e9f986429fa0c5a41c367cd732b41 # v7 with: version: "latest" python-version: "3.12"