From c312430a994deba2d105e52c5cca7164799bfb6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Flor=C3=AAncio?= Date: Fri, 7 Aug 2026 22:31:00 +0100 Subject: [PATCH] ci: upgrade GitHub Actions to Node 24 runtime (#2401) --- .github/workflows/backend-tests.yml | 8 +- .github/workflows/cargo-audit.yml | 2 +- .github/workflows/ci-base-image.yml | 8 +- .github/workflows/claude-code-review.yml | 6 +- .github/workflows/claude.yml | 2 +- .github/workflows/e2e-tests.yml | 40 +++--- .github/workflows/frontend-tests.yml | 2 +- .github/workflows/notify-docs.yml | 4 +- .github/workflows/opencode-code-review.yml | 10 +- .github/workflows/plugin-registry-index.yml | 6 +- .github/workflows/pr-title.yml | 2 +- .github/workflows/preview-env.yml | 2 +- .github/workflows/release.yml | 72 +++++------ .github/workflows/universal-rebuild.yml | 6 +- docs/plans/github-actions-node24/audit.md | 56 +++++++++ docs/plans/github-actions-node24/plan.md | 115 ++++++++++++++++++ .../task-01-test-workflows.md | 64 ++++++++++ .../task-02-container-workflows.md | 51 ++++++++ .../task-03-release-workflow.md | 59 +++++++++ .../task-04-review-misc-workflows.md | 74 +++++++++++ .../github-actions-node24/task-05-verify.md | 47 +++++++ 21 files changed, 552 insertions(+), 84 deletions(-) create mode 100644 docs/plans/github-actions-node24/audit.md create mode 100644 docs/plans/github-actions-node24/plan.md create mode 100644 docs/plans/github-actions-node24/task-01-test-workflows.md create mode 100644 docs/plans/github-actions-node24/task-02-container-workflows.md create mode 100644 docs/plans/github-actions-node24/task-03-release-workflow.md create mode 100644 docs/plans/github-actions-node24/task-04-review-misc-workflows.md create mode 100644 docs/plans/github-actions-node24/task-05-verify.md diff --git a/.github/workflows/backend-tests.yml b/.github/workflows/backend-tests.yml index 58d0e73c1e..bb525a711c 100644 --- a/.github/workflows/backend-tests.yml +++ b/.github/workflows/backend-tests.yml @@ -70,7 +70,7 @@ jobs: run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Cache Go modules - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/go/pkg/mod @@ -173,7 +173,7 @@ jobs: run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Cache Go modules - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/go/pkg/mod @@ -237,14 +237,14 @@ jobs: ' - name: Generate test report - uses: robherley/go-test-action@3856e4e57831b3b6d6d8d89f91747e5200c533f7 # v0 + uses: robherley/go-test-action@2f859e0c8769d755d3174eecb9af8f64660827f3 # v1.1.0 if: always() with: fromJSONFile: apps/backend/test-results-${{ matrix.shard }}.json omit: successful - name: Upload test artifacts - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 if: always() with: name: backend-test-results-${{ matrix.shard }} diff --git a/.github/workflows/cargo-audit.yml b/.github/workflows/cargo-audit.yml index 0a002dcd58..9e00f6d444 100644 --- a/.github/workflows/cargo-audit.yml +++ b/.github/workflows/cargo-audit.yml @@ -50,7 +50,7 @@ jobs: toolchain: stable - name: Cache cargo registry - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: | ~/.cargo/registry/index/ diff --git a/.github/workflows/ci-base-image.yml b/.github/workflows/ci-base-image.yml index deb3416566..1570873f8c 100644 --- a/.github/workflows/ci-base-image.yml +++ b/.github/workflows/ci-base-image.yml @@ -37,7 +37,7 @@ jobs: uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 - name: Set up Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 # Push the built images to GHCR on any `push` to main (the default # publish path) or on manual `workflow_dispatch` (used to seed new tag @@ -48,7 +48,7 @@ jobs: if: | github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && github.ref == 'refs/heads/main') - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 + uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -99,7 +99,7 @@ jobs: # Consumed by the `e2e` shards and `e2e-report`, where the smaller pull # is the speedup that pays for the split. - name: Build and push runtime - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 + uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 with: context: . file: .github/docker/ci-base/Dockerfile @@ -117,7 +117,7 @@ jobs: # `cache-from` includes the runtime scope so the shared lower layers # only build once across both pushes. - name: Build and push build - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 + uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 with: context: . file: .github/docker/ci-base/Dockerfile diff --git a/.github/workflows/claude-code-review.yml b/.github/workflows/claude-code-review.yml index 5b6d9798d0..c545be98e4 100644 --- a/.github/workflows/claude-code-review.yml +++ b/.github/workflows/claude-code-review.yml @@ -40,7 +40,7 @@ jobs: steps: - name: Checkout PR head - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: fetch-depth: 1 @@ -89,7 +89,7 @@ jobs: steps: - name: Add automatic fork approval labels - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const labels = ['safe-to-review', 'safe-to-test']; @@ -125,7 +125,7 @@ jobs: steps: - name: Checkout PR head - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: # pull_request_target defaults to the base ref; explicitly check out # the PR head through the base repository's pull ref. Keeping origin diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index 2816dc237d..b982a31b6b 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -26,7 +26,7 @@ jobs: actions: read # Required for Claude to read CI results on PRs steps: - name: Checkout trusted default branch - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: fetch-depth: 1 persist-credentials: false diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index eb4ca4ab1e..576829245c 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -64,7 +64,7 @@ jobs: # /root/.local/share/pnpm/store. actions/cache resolves `~` against $HOME # so the same path string works for both the host and container variants. - name: Cache pnpm store - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.local/share/pnpm/store key: pnpm-${{ runner.os }}-${{ hashFiles('apps/pnpm-lock.yaml') }} @@ -93,14 +93,14 @@ jobs: run: make build-backend-linux-helpers - name: Upload backend build - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: e2e-backend-build path: apps/backend/bin/ retention-days: 1 - name: Upload E2E fixture plugin package - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: e2e-plugin-package path: apps/backend/.build/kandev-plugin-e2e-1.0.0.tar.gz @@ -111,7 +111,7 @@ jobs: run: tar -cf apps/web/web-dist.tar -C apps/web dist - name: Upload web build - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: e2e-web-build path: apps/web/web-dist.tar @@ -162,7 +162,7 @@ jobs: run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Cache pnpm store - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.local/share/pnpm/store key: pnpm-${{ runner.os }}-${{ hashFiles('apps/pnpm-lock.yaml') }} @@ -173,7 +173,7 @@ jobs: run: pnpm install --frozen-lockfile - name: Download backend build - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: e2e-backend-build path: apps/backend/bin/ @@ -182,13 +182,13 @@ jobs: run: chmod +x apps/backend/bin/* - name: Download E2E fixture plugin package - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: e2e-plugin-package path: apps/backend/.build/ - name: Download web build - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: e2e-web-build path: apps/web/ @@ -208,7 +208,7 @@ jobs: - name: Upload blob report if: always() - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: blob-report-${{ matrix.shard }} path: apps/web/e2e/blob-report/ @@ -216,7 +216,7 @@ jobs: - name: Upload test results if: failure() - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: test-results-${{ matrix.shard }} path: apps/web/e2e/test-results/ @@ -270,7 +270,7 @@ jobs: node-version: "24" - name: Cache pnpm store - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.local/share/pnpm/store key: pnpm-${{ runner.os }}-${{ hashFiles('apps/pnpm-lock.yaml') }} @@ -285,7 +285,7 @@ jobs: # need this because GitHub's `container:` integration handles auth # implicitly using GITHUB_TOKEN. - name: Log in to GHCR - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 + uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -342,7 +342,7 @@ jobs: smoke_test - name: Download backend build - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: e2e-backend-build path: apps/backend/bin/ @@ -351,13 +351,13 @@ jobs: run: chmod +x apps/backend/bin/* - name: Download E2E fixture plugin package - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: e2e-plugin-package path: apps/backend/.build/ - name: Download web build - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: e2e-web-build path: apps/web/ @@ -381,7 +381,7 @@ jobs: # the sharded chromium/mobile-chrome runs. - name: Upload containers blob report if: always() - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: blob-report-containers-${{ matrix.shard }} path: apps/web/e2e/blob-report/ @@ -389,7 +389,7 @@ jobs: - name: Upload containers E2E results if: failure() - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: containers-e2e-test-results-${{ matrix.shard }} path: apps/web/e2e/test-results/ @@ -477,7 +477,7 @@ jobs: run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Cache pnpm store - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.local/share/pnpm/store key: pnpm-${{ runner.os }}-${{ hashFiles('apps/pnpm-lock.yaml') }} @@ -488,7 +488,7 @@ jobs: run: pnpm install --frozen-lockfile - name: Download blob reports - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: apps/web/e2e/blob-reports pattern: blob-report-* @@ -506,7 +506,7 @@ jobs: run: npx playwright merge-reports --config e2e/playwright.config.ts --reporter=html ./e2e/blob-reports - name: Upload merged report - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: playwright-report path: apps/web/playwright-report/ diff --git a/.github/workflows/frontend-tests.yml b/.github/workflows/frontend-tests.yml index 632b807686..42a43193d0 100644 --- a/.github/workflows/frontend-tests.yml +++ b/.github/workflows/frontend-tests.yml @@ -70,7 +70,7 @@ jobs: run: git config --global --add safe.directory "$GITHUB_WORKSPACE" - name: Cache pnpm store - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 + uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: ~/.local/share/pnpm/store key: pnpm-${{ runner.os }}-${{ hashFiles('apps/pnpm-lock.yaml') }} diff --git a/.github/workflows/notify-docs.yml b/.github/workflows/notify-docs.yml index 3893b1514e..8170c39b4f 100644 --- a/.github/workflows/notify-docs.yml +++ b/.github/workflows/notify-docs.yml @@ -117,7 +117,7 @@ jobs: - name: Deploy preview to Cloudflare Pages id: deploy if: steps.cloudflare.outputs.enabled == 'true' - uses: cloudflare/wrangler-action@9acf94ace14e7dc412b076f2c5c20b8ce93c79cd # v3 + uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ vars.CLOUDFLARE_ACCOUNT_ID }} @@ -143,7 +143,7 @@ jobs: steps: - name: Publish docs preview link - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 env: DEPLOYMENT_URL: ${{ needs.preview.outputs.deployment_url }} ALIAS_URL: ${{ needs.preview.outputs.alias_url }} diff --git a/.github/workflows/opencode-code-review.yml b/.github/workflows/opencode-code-review.yml index 3c0b25fd19..b13455533a 100644 --- a/.github/workflows/opencode-code-review.yml +++ b/.github/workflows/opencode-code-review.yml @@ -34,7 +34,7 @@ jobs: steps: - name: Checkout PR head - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 @@ -233,7 +233,7 @@ jobs: - name: Upload OpenCode review artifacts if: always() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: opencode-review-same-repo-${{ github.event.pull_request.number }} path: .opencode-review/ @@ -252,7 +252,7 @@ jobs: permissions: pull-requests: write steps: - - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7 + - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | try { @@ -290,7 +290,7 @@ jobs: steps: - name: Checkout PR head - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: ref: ${{ github.event.pull_request.head.sha }} fetch-depth: 0 @@ -473,7 +473,7 @@ jobs: - name: Upload OpenCode review artifacts if: always() - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: opencode-review-fork-${{ github.event.pull_request.number }} path: .opencode-review/ diff --git a/.github/workflows/plugin-registry-index.yml b/.github/workflows/plugin-registry-index.yml index 0b16433cdc..f76726c614 100644 --- a/.github/workflows/plugin-registry-index.yml +++ b/.github/workflows/plugin-registry-index.yml @@ -78,11 +78,11 @@ jobs: - name: Configure Pages if: github.event_name != 'pull_request' - uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5 + uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0 - name: Upload Pages artifact if: github.event_name != 'pull_request' - uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3 + uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0 with: path: _site @@ -100,4 +100,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deploy - uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4 + uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0 diff --git a/.github/workflows/pr-title.yml b/.github/workflows/pr-title.yml index fecc6897f6..6ccbf122e2 100644 --- a/.github/workflows/pr-title.yml +++ b/.github/workflows/pr-title.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Validate PR title follows Conventional Commits - uses: amannn/action-semantic-pull-request@e32d7e603df1aa1ba07e981f2a23455dee596825 # v5 + uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/preview-env.yml b/.github/workflows/preview-env.yml index 1874c5e470..c8dc7e0dc9 100644 --- a/.github/workflows/preview-env.yml +++ b/.github/workflows/preview-env.yml @@ -153,7 +153,7 @@ jobs: permissions: pull-requests: write steps: - - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7 + - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | try { diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6c8f5c2cc7..98a5db7a76 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -694,7 +694,7 @@ jobs: VITE_KANDEV_API_PORT: "" VITE_KANDEV_DEBUG: "" run: pnpm -C apps --filter @kandev/web build - - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: web-bundle path: apps/web/dist @@ -746,7 +746,7 @@ jobs: with: go-version-file: apps/backend/go.mod cache-dependency-path: apps/backend/go.sum - - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: web-bundle path: apps/backend/internal/webapp/embedded/generated @@ -823,7 +823,7 @@ jobs: shasum -a 256 "kandev-${{ matrix.platform }}.zip" > "kandev-${{ matrix.platform }}.zip.sha256" fi - - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: bundle-${{ matrix.platform }} # The zip entries match nothing on the four non-Windows platforms. @@ -956,7 +956,7 @@ jobs: - name: Install dependencies run: pnpm -C apps install --frozen-lockfile - - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: bundle-${{ matrix.platform }} path: dist/desktop-runtime @@ -1250,7 +1250,7 @@ jobs: - name: Upload macOS desktop diagnostics if: failure() && startsWith(matrix.platform, 'macos-') - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: desktop-diagnostics-${{ matrix.platform }} path: | @@ -1377,7 +1377,7 @@ jobs: fi ls -lh "$out_dir" - - uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: desktop-${{ matrix.platform }} path: dist/desktop-artifacts/* @@ -1413,7 +1413,7 @@ jobs: with: ref: ${{ needs.prepare.outputs.ref }} - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: bundle-linux-x64 path: dist/bundle @@ -1427,10 +1427,10 @@ jobs: tar -xzf dist/bundle/kandev-linux-x64.tar.gz --strip-components=1 -C ctx/bundle cp docker-entrypoint.sh ctx/ - - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 - name: Login to GHCR - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 + uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -1443,13 +1443,13 @@ jobs: # page link + provenance tooling rely on these annotations. - name: Docker metadata (labels) id: meta - uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5 + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 with: images: ghcr.io/kdlbs/kandev - name: Build and push (amd64 staging tag) id: build - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 + uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 with: context: ./ctx file: ./Dockerfile @@ -1488,11 +1488,12 @@ jobs: env: STAGING_IMAGE: ghcr.io/kdlbs/kandev:base-staging-${{ needs.prepare.outputs.tag }}-${{ github.run_id }}-arm64 steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: ref: ${{ needs.prepare.outputs.ref }} + persist-credentials: false - - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: bundle-linux-arm64 path: dist/bundle @@ -1504,10 +1505,10 @@ jobs: tar -xzf dist/bundle/kandev-linux-arm64.tar.gz --strip-components=1 -C ctx/bundle cp docker-entrypoint.sh ctx/ - - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 - name: Login to GHCR - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 + uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -1515,13 +1516,13 @@ jobs: - name: Docker metadata (labels) id: meta - uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5 + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 with: images: ghcr.io/kdlbs/kandev - name: Build and push (arm64 staging tag) id: build - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 + uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 with: context: ./ctx file: ./Dockerfile @@ -1554,7 +1555,7 @@ jobs: steps: - name: Docker meta id: meta - uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5 + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 with: images: ghcr.io/kdlbs/kandev tags: | @@ -1563,10 +1564,10 @@ jobs: type=sha type=raw,value=latest - - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 - name: Login to GHCR - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 + uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -1622,10 +1623,10 @@ jobs: with: ref: ${{ needs.prepare.outputs.ref }} - - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 - name: Login to GHCR - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 + uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -1633,13 +1634,13 @@ jobs: - name: Docker metadata (labels) id: meta - uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5 + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 with: images: ghcr.io/kdlbs/kandev - name: Build and push (universal amd64 staging tag) id: build - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 + uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 with: context: . file: Dockerfile.universal @@ -1678,14 +1679,15 @@ jobs: env: STAGING_IMAGE: ghcr.io/kdlbs/kandev:universal-staging-${{ needs.prepare.outputs.tag }}-${{ github.run_id }}-arm64 steps: - - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 with: ref: ${{ needs.prepare.outputs.ref }} + persist-credentials: false - - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 - name: Login to GHCR - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 + uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -1693,13 +1695,13 @@ jobs: - name: Docker metadata (labels) id: meta - uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5 + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 with: images: ghcr.io/kdlbs/kandev - name: Build and push (universal arm64 staging tag) id: build - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 + uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 with: context: . file: Dockerfile.universal @@ -1737,10 +1739,10 @@ jobs: AMD64_REF: ghcr.io/kdlbs/kandev@${{ needs.docker-universal-amd64.outputs.digest }} ARM64_REF: ghcr.io/kdlbs/kandev@${{ needs.docker-universal-arm64.outputs.digest }} steps: - - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 - name: Login to GHCR - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 + uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -1870,13 +1872,13 @@ jobs: } > "$tmp" mv "$tmp" RELEASE_NOTES.md - - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: bundle-* path: dist/release-assets merge-multiple: true - - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: desktop-* path: dist/release-assets @@ -1937,7 +1939,7 @@ jobs: fi - name: Publish release - uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2 + uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2 with: tag_name: ${{ needs.prepare.outputs.tag }} name: ${{ needs.prepare.outputs.tag }} @@ -2034,7 +2036,7 @@ jobs: - name: Install dependencies run: pnpm -C apps install --frozen-lockfile - - uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: bundle-* path: dist/nightly-assets diff --git a/.github/workflows/universal-rebuild.yml b/.github/workflows/universal-rebuild.yml index bccd13acc6..d2a1972db3 100644 --- a/.github/workflows/universal-rebuild.yml +++ b/.github/workflows/universal-rebuild.yml @@ -52,10 +52,10 @@ jobs: id: date run: echo "tag=$(date -u +%Y%m%d)" >> "$GITHUB_OUTPUT" - - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + - uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 - name: Login to GHCR - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 + uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: registry: ghcr.io username: ${{ github.actor }} @@ -66,7 +66,7 @@ jobs: # current :latest is freshly fetched, not whatever's in BuildKit's # cache from a previous run. - name: Build and push (staging tag) - uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 + uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 with: context: . file: Dockerfile.universal diff --git a/docs/plans/github-actions-node24/audit.md b/docs/plans/github-actions-node24/audit.md new file mode 100644 index 0000000000..a720fed981 --- /dev/null +++ b/docs/plans/github-actions-node24/audit.md @@ -0,0 +1,56 @@ +# Action runtime audit procedure + +Goal: verify that every `uses:` pin in `.github/workflows/` runs on the +Node 24 action runtime (or is composite / docker://), so no Node-20 +deprecation warnings are emitted. + +## Step 1 — collect pins + +```bash +grep -rhoE "uses: [^ ]+@[0-9a-f]{40}" .github/workflows/*.yml | sort | uniq -c | sort -rn +``` + +## Step 2 — check each pinned SHA's runtime + +For each `owner/repo@<40-hex>` pin, fetch the action manifest at that exact +commit and read `runs.using`: + +```bash +curl -sf "https://raw.githubusercontent.com////action.yml" \ + | grep -A1 "^runs:" +# action.yml may be action.yaml in some repos; try both. +``` + +Acceptable values: `node24` (good), `composite` (no runtime of its own — +inspect inner `uses:` steps, e.g. `actions/upload-pages-artifact` v5 embeds +`actions/upload-artifact@v7.0.0` which is node24). Reject `node20`. + +## Step 3 — dereference annotated tags + +Some pins are the SHA of an annotated tag object rather than a commit +(e.g. `pnpm/action-setup@a8198c4… # v5`). Dereference before judging: + +```bash +gh api repos///git/tags/ --jq '.object.sha' +``` + +## Step 4 — resolve target SHAs (when upgrading) + +For each target tag, resolve the commit SHA and confirm node24: + +```bash +sha=$(gh api "repos///git/refs/tags/" --jq '.object.sha') +# if .object.type == "tag", dereference via git/tags/ → .object.sha +curl -sf "https://raw.githubusercontent.com///$sha/action.yml" | grep -A1 "^runs:" +``` + +## Step 5 — final assertion + +After the upgrade, rerun steps 1–2 and assert: + +- every `runs.using:` is `node24` or `composite`; +- every ref is still a 40-char SHA (also covered by `lint-action-pinning.py`); +- no output line contains `node20`. + +Last verified clean: 2026-08-07 (all pins node24/composite — see plan.md +target table). diff --git a/docs/plans/github-actions-node24/plan.md b/docs/plans/github-actions-node24/plan.md new file mode 100644 index 0000000000..f810fc65e1 --- /dev/null +++ b/docs/plans/github-actions-node24/plan.md @@ -0,0 +1,115 @@ +--- +created: 2026-08-07 +status: draft +--- + +# Implementation Plan: Upgrade GitHub Actions to the Node 24 runtime + +## Overview + +GitHub deprecated the Node 20 action runtime; every pinned action whose +`action.yml` declares `runs.using: node20` now runs forced on Node 24 and +emits a deprecation warning on every workflow run. This plan upgrades every +Node-20 action pin in `.github/workflows/` to a SHA-pinned release that +declares `runs.using: node24`, verifying each target's runtime and +backwards-compatibility before landing. Order: upgrade the plain-JavaScript +actions (checkout, artifacts, cache, github-script) first, then the docker/* +family, then the remaining third-party actions, and finish with a full audit +that no `node20` pin remains. + +There is no product spec for this change: it is CI-infrastructure hygiene with +no user-visible behavior. Validation is mechanical — see +[audit.md](audit.md) for the runtime-check procedure used to build the table +below. + +## Target version table + +Verified on 2026-08-07 via the pinned SHA's `action.yml` `runs.using` field +(`audit.md` documents the exact method). "Target" is the release whose pinned +commit declares `node24`. + +| Action | Current pin | Uses | Target | Target SHA | Runtime | +|---|---|---|---|---|---| +| actions/checkout | `34e114876b0b11c390a56381ad16ebd13914f8d5 # v4` | 7 | v6 (already used in repo) | `df4cb1c069e1874edd31b4311f1884172cec0e10` | node24 | +| actions/upload-artifact | `ea165f8d65b6e75b540449e92b4886f43607fa02 # v4` | 2 | v7.0.1 | `043fb46d1a93c77aae656e7c1c64a875d1fc6a0a` | node24 | +| actions/upload-artifact | `330a01c490aca151604b8cf639adc76d48f6c5d4 # v5` | 13 | v7.0.1 | `043fb46d1a93c77aae656e7c1c64a875d1fc6a0a` | node24 | +| actions/download-artifact | `d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4` | 2 | v8.0.1 | `3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c` | node24 | +| actions/download-artifact | `634f93cb2916e3fdff6788551b99b062d0335ce0 # v5` | 12 | v8.0.1 | `3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c` | node24 | +| actions/cache | `0057852bfaa89a56745cba8c7296529d2fc39830 # v4` | 8 | v6.1.0 | `55cc8345863c7cc4c66a329aec7e433d2d1c52a9` | node24 | +| actions/github-script | `f28e40c7f34bde8b3046d885e986cb6290c5673b # v7` | 4 | v9.0.0 | `3a2844b7e9c422d3c10d287c895573f7108da1b3` | node24 | +| docker/login-action | `c94ce9fb468520275223c153574b00df6fe4bcc9 # v3` | 9 | v4.6.0 | `dbcb813823bdd20940b903addbd779551569679f` | node24 | +| docker/setup-buildx-action | `8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3` | 8 | v4.2.0 | `bb05f3f5519dd87d3ba754cc423b652a5edd6d2c` | node24 | +| docker/build-push-action | `10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6` | 7 | v7.3.0 | `53b7df96c91f9c12dcc8a07bcb9ccacbed38856a` | node24 | +| docker/metadata-action | `c299e40c65443455700f0fdfc63efafe5b349051 # v5` | 5 | v6.2.0 | `dc802804100637a589fabce1cb79ff13a1411302` | node24 | +| softprops/action-gh-release | `3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2` | 1 | v3.0.2 | `3d0d9888cb7fd7b750713d6e236d1fcb99157228` | node24 | +| cloudflare/wrangler-action | `9acf94ace14e7dc412b076f2c5c20b8ce93c79cd # v3` | 1 | v4.0.0 | `ebbaa1584979971c8614a24965b4405ff95890e0` | node24 | +| amannn/action-semantic-pull-request | `e32d7e603df1aa1ba07e981f2a23455dee596825 # v5` | 1 | v6.1.1 | `48f256284bd46cdaab1048c3721360e808335d50` | node24 | +| actions/deploy-pages | `d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4` | 1 | v5.0.0 | `cd2ce8fcbc39b97be8ca5fce6e763baed58fa128` | node24 | +| actions/configure-pages | `983d7736d9b0ae728b81ab479565c72886d7745b # v5` | 1 | v6.0.0 | `45bfe0192ca1faeb007ade9deae92b16b8254a0d` | node24 | +| actions/upload-pages-artifact | `56afc609e74202658d3ffba0e8f6dda462b719fa # v3` | 1 | v5.0.0 | `fc324d3547104276b827a68afc52ff2a11cc49c9` | composite (inner upload-artifact v7.0.0 = node24) | +| robherley/go-test-action | `3856e4e57831b3b6d6d8d89f91747e5200c533f7 # v0` | 1 | v1.1.0 | `2f859e0c8769d755d3174eecb9af8f64660827f3` | node24 | + +Already node24 / no change: `actions/checkout` v6 (`df4cb1c…`), `actions/setup-node` v6 (`48b55a0…`), `actions/setup-go` v6 (`924ae3a…`), `pnpm/action-setup` v5 (`a8198c4…`), `crazy-max/ghaction-import-gpg` v7.0.0 (`2dc316d…`), `actions/create-github-app-token` v3.2.0 (`bcd2ba4…`), `Swatinem/rust-cache` v2 (`42dc69e…`). Composite actions with no direct runtime (`anthropics/claude-code-action`, `orhun/git-cliff-action`, `dtolnay/rust-toolchain`) are left as-is. + +## Compatibility notes (per action) + +- `actions/checkout` v4→v6: v6 already used 34× in this repo — proven. +- `actions/upload-artifact` v4/v5→v7.0.1 and `actions/download-artifact` v4/v5→v8.0.1: the artifact backend is shared across the v4+ majors on GitHub-hosted runners; upload/download must stay on compatible majors (v7 upload + v8 download both use the v4 artifact API). All uses move together in the same PR, so cross-job download/upload pairing is preserved. +- `actions/github-script` v7→v9.0.0: v9 breaking change is `require('@actions/github')` no longer working; all four uses in this repo only use injected `github`/`context` — audited, no `require('@actions/github')` in any script block. +- `docker/login-action` v3→v4.6.0, `docker/setup-buildx-action` v3→v4.2.0: Node 24 runtime + ESM; v4 removed deprecated inputs/outputs — repo uses none (`with:` blocks checked). +- `docker/build-push-action` v6→v7.3.0: v7 removed deprecated `DOCKER_BUILD_NO_SUMMARY` / `DOCKER_BUILD_EXPORT_RETENTION_DAYS` envs — not used in repo. +- `docker/metadata-action` v5→v6.2.0: list inputs now preserve `#` inside values — release.yml uses no `#` in tags/images lists. +- `softprops/action-gh-release` v2→v3.0.2: Node 24 only; `files:`/`body_path:` inputs unchanged in v3. +- `cloudflare/wrangler-action` v3→v4.0.0: default wrangler version changes to v4 (`latest`), but repo pins `wranglerVersion: 3.90.0` explicitly — behavior preserved. +- `amannn/action-semantic-pull-request` v5→v6.1.1: Node 24 + ESM; inputs unchanged. +- `actions/deploy-pages` v4→v5.0.0, `actions/configure-pages` v5→v6.0.0, `actions/upload-pages-artifact` v3→v5.0.0: Pages trio moved together; v5 upload-pages-artifact's inner `actions/upload-artifact` is v7.0.0 (node24) instead of v4 (node20). +- `robherley/go-test-action` v0→v1.1.0: Node 24; `fromJSONFile` input retained. + +## Tasks + +Task files are grouped by workflow file so each task touches a disjoint set of +files (safe to run in any order; wave labels only express suggested order): + +``` +Wave 1 (parallel candidates — user authorization required): +- [x] [task-01-test-workflows](task-01-test-workflows.md) — backend-tests.yml, frontend-tests.yml, cargo-audit.yml, e2e-tests.yml +- [x] [task-02-container-workflows](task-02-container-workflows.md) — universal-rebuild.yml, ci-base-image.yml +- [x] [task-03-release-workflow](task-03-release-workflow.md) — release.yml (all Node-20 pins) +- [x] [task-04-review-misc-workflows](task-04-review-misc-workflows.md) — claude.yml, claude-code-review.yml, opencode-code-review.yml, notify-docs.yml, preview-env.yml, pr-title.yml, plugin-registry-index.yml + +Wave 2: +- [x] [task-05-verify](task-05-verify.md) — runtime audit + lint + contract tests + YAML sanity +``` + +## Tests + +No product behavior is testable — the changed artifacts are workflow YAML only. Pre-PR validation: + +- **Runtime audit:** rerun the procedure in [audit.md](audit.md) (fetch each pinned `action.yml`, assert `runs.using` is `node24` or `composite`) and confirm zero `node20` pins remain. +- **Pinning lint:** `python3 .github/scripts/lint-action-pinning.py` and `python3 .github/scripts/lint-action-pinning_test.py` still pass (every new ref is a 40-char SHA). +- **Workflow contract tests:** `python3 .github/scripts/release-workflow-contract_test.py`, `claude-code-review-workflow-contract_test.py`, `preview-env-workflow-contract_test.py` — the two SHA-asserting contract tests only pin `crazy-max/ghaction-import-gpg@2dc316d…` and `actions/setup-node@48b55a0…`, which are unchanged. +- **YAML sanity:** `python3 -c "import yaml,sys; [yaml.safe_load(open(f)) for f in sys.argv[1:]]"` over every changed workflow. +- **Runtime smoke (post-PR):** watch the first `backend-tests`/`e2e-tests`/`frontend-tests` run for the Node-20 deprecation warning; confirm it is gone. + +## Verification Results + +Complete 2026-08-07. All five tasks done; every task's `## Results` records the exact commands and outcomes. + +- Applied 84 `uses:` replacements across 14 workflow files (checkout v4→v6, upload/download-artifact v4/v5→v7.0.1/v8.0.1, cache v4→v6.1.0, github-script v7→v9.0.0, docker login/buildx/build-push/metadata v3/v5/v6→v4.6.0/v4.2.0/v7.3.0/v6.2.0, gh-release v2→v3.0.2, wrangler v3→v4.0.0, semantic-pull-request v5→v6.1.1, Pages trio → v6.0.0/v5.0.0/v5.0.0, go-test-action v0→v1.1.0). +- Final runtime audit (`/tmp/opencode/audit_final.py`): 25 distinct pinned actions; every `runs.using` is `node24` or `composite` — **zero `node20` pins remain**. The three annotated-tag-object pins (rust-cache, claude-code-action, pnpm/action-setup) were dereferenced to their commits and re-verified (node24 / composite / node24). +- `python3 .github/scripts/lint-action-pinning.py` → "✓ All 18 workflow file(s) use SHA-pinned action refs."; `lint-action-pinning_test.py` → 9 OK. +- Contract tests: `release-workflow-contract_test.py` → 24 OK, `claude-code-review-workflow-contract_test.py` → 9 OK, `preview-env-workflow-contract_test.py` → 1 OK. +- YAML parse: 18/18 workflows OK; `git diff --check` clean. +- Post-merge smoke: pending — first `backend-tests`/`e2e-tests`/`frontend-tests` run after merge should no longer show the Node-20 deprecation warning. + +## PR Fixup (2026-08-07) + +PR #2401 (`ci: upgrade GitHub Actions to Node 24 runtime`): + +- CodeRabbit/zizmor flagged the two v4→v6 checkout blocks in the arm64 release jobs (`docker-arm64`, `docker-universal-arm64`) for missing `persist-credentials: false` (artipacked — the checked-out tree feeds the Docker build context). Fixed in `b7624fd` (`ci: disable checkout credential persistence in arm64 release jobs`), scoped to exactly the two changed blocks; the other release.yml checkouts already set the flag. +- Final head `b7624fd32e43828c0ff50b90e73013fda3bf774e`: 47 checks passed, 0 failed, 0 pending, `mergeable_state: clean`, unresolved threads 0, hidden threads 0, actionable issue comments 0. +- Post-merge smoke still pending as above. + +## Open Questions + +None — target SHAs and compatibility are resolved in the table above. diff --git a/docs/plans/github-actions-node24/task-01-test-workflows.md b/docs/plans/github-actions-node24/task-01-test-workflows.md new file mode 100644 index 0000000000..97a20fb7df --- /dev/null +++ b/docs/plans/github-actions-node24/task-01-test-workflows.md @@ -0,0 +1,64 @@ +--- +id: "01-test-workflows" +title: "Upgrade Node-20 actions in test workflows" +status: done +wave: 1 +depends_on: [] +plan: "plan.md" +--- + +# Task 01: Upgrade Node-20 actions in test workflows + +- **Acceptance:** every `uses:` pin in `backend-tests.yml`, `frontend-tests.yml`, `cargo-audit.yml`, and `e2e-tests.yml` that previously ran on Node 20 now pins a commit whose `action.yml` declares `runs.using: node24`; the pinning lint and contract tests still pass. +- **Verification:** + - `python3 .github/scripts/lint-action-pinning.py` + - `python3 .github/scripts/lint-action-pinning_test.py` + - `python3 .github/scripts/release-workflow-contract_test.py` (unchanged assertions still pass) + - runtime audit for the four files per `audit.md` (all `runs.using` = node24/composite) + - `python3 -c "import yaml,sys; [yaml.safe_load(open(f)) for f in sys.argv[1:]]" .github/workflows/backend-tests.yml .github/workflows/frontend-tests.yml .github/workflows/cargo-audit.yml .github/workflows/e2e-tests.yml` +- **Files likely touched:** + - `.github/workflows/backend-tests.yml` (cache:73,176 → v6.1.0; go-test-action:240 → v1.1.0; upload-artifact:247 → v7.0.1) + - `.github/workflows/frontend-tests.yml` (cache:73 → v6.1.0) + - `.github/workflows/cargo-audit.yml` (cache:53 → v6.1.0) + - `.github/workflows/e2e-tests.yml` (cache:67,165,273,480 → v6.1.0; upload-artifact:96,103,114,211,219,384,392,509 → v7.0.1; download-artifact:176,185,191,345,354,360,491 → v8.0.1; login-action:288 → v4.6.0) +- **Dependencies:** None. +- **Parallelism:** sequential by default; parallel-safe if run alongside tasks 02–04 (all files disjoint). + +## Changes + +Replace each listed `uses:` line with the target SHA, keeping the `# vX` version comment accurate: + +| File:line | From | To | +|---|---|---| +| backend-tests.yml:73,176 | `actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4` | `actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0` | +| backend-tests.yml:240 | `robherley/go-test-action@3856e4e57831b3b6d6d8d89f91747e5200c533f7 # v0` | `robherley/go-test-action@2f859e0c8769d755d3174eecb9af8f64660827f3 # v1.1.0` | +| backend-tests.yml:247 | `actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5` | `actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1` | +| frontend-tests.yml:73 | `actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4` | `actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0` | +| cargo-audit.yml:53 | `actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4` | `actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0` | +| e2e-tests.yml:67,165,273,480 | `actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4` | `actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0` | +| e2e-tests.yml:96,103,114,211,219,384,392,509 | `actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5` | `actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1` | +| e2e-tests.yml:176,185,191,345,354,360,491 | `actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5` | `actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1` | +| e2e-tests.yml:288 | `docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3` | `docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0` | + +Line numbers are 2026-08-07 snapshots; if a line moved, match by the `uses:` +string instead of the number. + +Do not touch `e2e-tests.yml` checkout (already v6 `df4cb1c…`). + +## Inputs + +plan.md target table + compatibility notes; `audit.md` for the runtime check. + +## Output contract + +Summary, files changed, exact commands run and outcomes, final audit output for the four files, task/plan status updates. + +## Results + +- Applied 8 cache, 1 go-test-action, 9 upload-artifact, 7 download-artifact, 1 login-action replacements across backend-tests.yml / frontend-tests.yml / cargo-audit.yml / e2e-tests.yml (match-by-`uses:` verified). +- `python3 .github/scripts/lint-action-pinning.py` → "✓ All 18 workflow file(s) use SHA-pinned action refs." +- `python3 .github/scripts/lint-action-pinning_test.py` → 9 tests OK. +- `python3 .github/scripts/release-workflow-contract_test.py` → 24 tests OK (unchanged pins still asserted). +- Runtime audit (audit_final.py): every pin in the four files `node24`/`composite`, zero `node20`. +- YAML parse of all 18 workflows OK; `git diff --check` clean. +- No security/trust or external side-effect boundaries beyond publishing new action pins to CI. diff --git a/docs/plans/github-actions-node24/task-02-container-workflows.md b/docs/plans/github-actions-node24/task-02-container-workflows.md new file mode 100644 index 0000000000..e490ca8d41 --- /dev/null +++ b/docs/plans/github-actions-node24/task-02-container-workflows.md @@ -0,0 +1,51 @@ +--- +id: "02-container-workflows" +title: "Upgrade Node-20 docker actions in container workflows" +status: done +wave: 1 +depends_on: [] +plan: "plan.md" +--- + +# Task 02: Upgrade Node-20 docker actions in container workflows + +- **Acceptance:** every `uses:` pin in `universal-rebuild.yml` and `ci-base-image.yml` runs on Node 24; the docker v3/v6 pins (login, setup-buildx, build-push) move to the v4/v7 lines with Node 24 runtime. +- **Verification:** + - `python3 .github/scripts/lint-action-pinning.py` + - runtime audit per `audit.md` for the two files + - `python3 -c "import yaml,sys; [yaml.safe_load(open(f)) for f in sys.argv[1:]]" .github/workflows/universal-rebuild.yml .github/workflows/ci-base-image.yml` +- **Files likely touched:** + - `.github/workflows/universal-rebuild.yml` (setup-buildx:55 → v4.2.0; login:58 → v4.6.0; build-push:69 → v7.3.0) + - `.github/workflows/ci-base-image.yml` (setup-buildx:40 → v4.2.0; login:51 → v4.6.0; build-push:102,120 → v7.3.0) +- **Dependencies:** None. +- **Parallelism:** sequential by default; parallel-safe if run alongside tasks 01, 03, 04 (all files disjoint). + +## Changes + +| File:line | From | To | +|---|---|---| +| universal-rebuild.yml:55 | `docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3` | `docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0` | +| universal-rebuild.yml:58 | `docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3` | `docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0` | +| universal-rebuild.yml:69 | `docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6` | `docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0` | +| ci-base-image.yml:40 | `docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3` | `docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0` | +| ci-base-image.yml:51 | `docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3` | `docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0` | +| ci-base-image.yml:102,120 | `docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6` | `docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0` | + +Line numbers are 2026-08-07 snapshots; match by `uses:` string if they moved. +Do not change `with:` blocks — none use inputs removed by docker v4/v7 +(deprecated buildx inputs, `DOCKER_BUILD_NO_SUMMARY`). + +## Inputs + +plan.md target table + docker compatibility notes; `audit.md`. + +## Output contract + +Summary, files changed, exact commands and outcomes, audit output for the two files, task/plan status updates. + +## Results + +- Applied 2 setup-buildx, 2 login-action, 3 build-push replacements across universal-rebuild.yml / ci-base-image.yml. +- `python3 .github/scripts/lint-action-pinning.py` → all 18 workflows SHA-pinned. +- Runtime audit: all pins in the two files `node24`, zero `node20`. +- YAML parse OK; `git diff --check` clean. None. diff --git a/docs/plans/github-actions-node24/task-03-release-workflow.md b/docs/plans/github-actions-node24/task-03-release-workflow.md new file mode 100644 index 0000000000..f5001cbda4 --- /dev/null +++ b/docs/plans/github-actions-node24/task-03-release-workflow.md @@ -0,0 +1,59 @@ +--- +id: "03-release-workflow" +title: "Upgrade Node-20 actions in release.yml" +status: done +wave: 1 +depends_on: [] +plan: "plan.md" +--- + +# Task 03: Upgrade Node-20 actions in release.yml + +- **Acceptance:** every `uses:` pin in `release.yml` runs on Node 24; the release workflow contract test still passes. +- **Verification:** + - `python3 .github/scripts/lint-action-pinning.py` + - `python3 .github/scripts/release-workflow-contract_test.py` + - runtime audit per `audit.md` for release.yml + - `python3 -c "import yaml,sys; [yaml.safe_load(open(f)) for f in sys.argv[1:]]" .github/workflows/release.yml` +- **Files likely touched:** `.github/workflows/release.yml` only. +- **Dependencies:** None. +- **Parallelism:** sequential by default; parallel-safe if run alongside tasks 01, 02, 04 (all files disjoint). + +## Changes + +| File:line | From | To | +|---|---|---| +| release.yml:103,612,677,741,877,1412,1621,1803,1975,2017,2070 | `actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6` | unchanged (already node24) | +| release.yml:1491,1681 | `actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4` | `actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6` | +| release.yml:697,826,1253,1380 | `actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5` | `actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1` | +| release.yml:1416,1495 | `actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4` | `actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1` | +| release.yml:749,959,1873,1879,2037 | `actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5` | `actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1` | +| release.yml:1433,1510,1569,1688,1743 | `docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3` | `docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0` | +| release.yml:1430,1507,1566,1625,1685,1740 | `docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3` | `docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0` | +| release.yml:1452,1524,1642,1696 | `docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6` | `docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0` | +| release.yml:1446,1518,1557,1636 | `docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5` | `docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0` | +| release.yml:1940 | `softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2` | `softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2` | + +Line numbers are 2026-08-07 snapshots; match by `uses:` string if they moved. +The `# v6` checkout rows are listed for completeness — they are already +node24 and require no edit. Do not change `with:` blocks; inputs used +(`files:`, `body_path:`, `tag_name:`, `tags: type=raw,…`) are all preserved +in the target versions. The contract test pins +`crazy-max/ghaction-import-gpg@2dc316d…` and `actions/setup-node@48b55a0…` — +both unchanged. + +## Inputs + +plan.md target table + compatibility notes; `audit.md`. + +## Output contract + +Summary, files changed, exact commands and outcomes, audit output for release.yml, task/plan status updates. + +## Results + +- Applied 2 checkout v4→v6, 4 upload-artifact v5→v7.0.1, 7 download-artifact v4/v5→v8.0.1, 6 login v3→v4.6.0, 6 buildx v3→v4.2.0, 4 build-push v6→v7.3.0, 5 metadata v5→v6.2.0, 1 gh-release v2→v3.0.2 in release.yml (35 uses total). +- `python3 .github/scripts/lint-action-pinning.py` → all SHA-pinned. +- `python3 .github/scripts/release-workflow-contract_test.py` → 24 tests OK. +- Runtime audit: all pins `node24`, zero `node20`; YAML parse OK; `git diff --check` clean. +- `with:` blocks untouched (files/body_path/tag_name/tags inputs all preserved in targets). None. diff --git a/docs/plans/github-actions-node24/task-04-review-misc-workflows.md b/docs/plans/github-actions-node24/task-04-review-misc-workflows.md new file mode 100644 index 0000000000..fafdda4aed --- /dev/null +++ b/docs/plans/github-actions-node24/task-04-review-misc-workflows.md @@ -0,0 +1,74 @@ +--- +id: "04-review-misc-workflows" +title: "Upgrade Node-20 actions in review and misc workflows" +status: done +wave: 1 +depends_on: [] +plan: "plan.md" +--- + +# Task 04: Upgrade Node-20 actions in review and misc workflows + +- **Acceptance:** every `uses:` pin in `claude.yml`, `claude-code-review.yml`, `opencode-code-review.yml`, `notify-docs.yml`, `preview-env.yml`, `pr-title.yml`, and `plugin-registry-index.yml` runs on Node 24; the claude-code-review and preview-env workflow contract tests still pass. +- **Verification:** + - `python3 .github/scripts/lint-action-pinning.py` + - `python3 .github/scripts/claude-code-review-workflow-contract_test.py` + - `python3 .github/scripts/preview-env-workflow-contract_test.py` + - runtime audit per `audit.md` for the seven files + - `python3 -c "import yaml,sys; [yaml.safe_load(open(f)) for f in sys.argv[1:]]" .github/workflows/claude.yml .github/workflows/claude-code-review.yml .github/workflows/opencode-code-review.yml .github/workflows/notify-docs.yml .github/workflows/preview-env.yml .github/workflows/pr-title.yml .github/workflows/plugin-registry-index.yml` +- **Files likely touched:** + - `.github/workflows/claude.yml` (checkout:29 → v6) + - `.github/workflows/claude-code-review.yml` (checkout:43,128 → v6; github-script:92 → v9.0.0) + - `.github/workflows/opencode-code-review.yml` (checkout:37,293 → v6; upload-artifact:236,476 → v7.0.1; github-script:255 → v9.0.0) + - `.github/workflows/notify-docs.yml` (github-script:146 → v9.0.0; wrangler-action:120 → v4.0.0) + - `.github/workflows/preview-env.yml` (github-script:156 → v9.0.0) + - `.github/workflows/pr-title.yml` (semantic-pull-request:20 → v6.1.1) + - `.github/workflows/plugin-registry-index.yml` (configure-pages:81 → v6.0.0; upload-pages-artifact:85 → v5.0.0; deploy-pages:103 → v5.0.0) +- **Dependencies:** None. +- **Parallelism:** sequential by default; parallel-safe if run alongside tasks 01–03 (all files disjoint). + +## Changes + +| File:line | From | To | +|---|---|---| +| claude.yml:29 | `actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4` | `actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6` | +| claude-code-review.yml:43,128 | `actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4` | `actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6` | +| claude-code-review.yml:92 | `actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7` | `actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0` | +| opencode-code-review.yml:37,293 | `actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4` | `actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6` | +| opencode-code-review.yml:236,476 | `actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4` | `actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1` | +| opencode-code-review.yml:255 | `actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7` | `actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0` | +| notify-docs.yml:146 | `actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7` | `actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0` | +| notify-docs.yml:120 | `cloudflare/wrangler-action@9acf94ace14e7dc412b076f2c5c20b8ce93c79cd # v3` | `cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0` | +| preview-env.yml:156 | `actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7` | `actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0` | +| pr-title.yml:20 | `amannn/action-semantic-pull-request@e32d7e603df1aa1ba07e981f2a23455dee596825 # v5` | `amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1` | +| plugin-registry-index.yml:81 | `actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5` | `actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0` | +| plugin-registry-index.yml:85 | `actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3` | `actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0` | +| plugin-registry-index.yml:103 | `actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4` | `actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0` | + +Line numbers are 2026-08-07 snapshots; match by `uses:` string if they moved. + +Notes: +- github-script v9.0.0: the four scripts only use injected `github`/`context` + (labels, removeLabel, safe-to-test) — no `require('@actions/github')`, so + the v9 breaking change does not apply. +- wrangler-action v4.0.0: keep `wranglerVersion: 3.90.0` in the `with:` block + (v4 defaults to Wrangler v4; the explicit pin preserves current behavior). +- plugin-registry-index.yml Pages trio: bump all three together — v5 + upload-pages-artifact's inner `actions/upload-artifact` is v7.0.0 (node24) + instead of v4 (node20). The `path: _site` input is unchanged. + +## Inputs + +plan.md target table + compatibility notes; `audit.md`. + +## Output contract + +Summary, files changed, exact commands and outcomes, audit output for the seven files, task/plan status updates. + +## Results + +- Applied 6 checkout v4→v6, 3 github-script v7→v9.0.0, 2 upload-artifact v4→v7.0.1, 1 wrangler v3→v4.0.0, 1 semantic-pull-request v5→v6.1.1, 3 Pages trio upgrades across claude.yml / claude-code-review.yml / opencode-code-review.yml / notify-docs.yml / preview-env.yml / pr-title.yml / plugin-registry-index.yml. +- github-script scripts audited: only injected `github`/`context`, no `require('@actions/github')` → v9.0.0 safe. +- `wranglerVersion: 3.90.0` kept in notify-docs.yml (v4 default avoided). +- `python3 .github/scripts/lint-action-pinning.py`, `claude-code-review-workflow-contract_test.py` (9 OK), `preview-env-workflow-contract_test.py` (1 OK) all pass. +- Runtime audit: all pins `node24`/`composite`, zero `node20`; YAML parse OK; `git diff --check` clean. None. diff --git a/docs/plans/github-actions-node24/task-05-verify.md b/docs/plans/github-actions-node24/task-05-verify.md new file mode 100644 index 0000000000..df672d449c --- /dev/null +++ b/docs/plans/github-actions-node24/task-05-verify.md @@ -0,0 +1,47 @@ +--- +id: "05-verify" +title: "Verify no Node-20 action pins remain" +status: done +wave: 2 +depends_on: ["01-test-workflows", "02-container-workflows", "03-release-workflow", "04-review-misc-workflows"] +plan: "plan.md" +--- + +# Task 05: Verify no Node-20 action pins remain + +- **Acceptance:** a full audit of every `uses:` pin in `.github/workflows/` shows zero `runs.using: node20` (all node24 or composite), the pinning lint and all workflow contract tests pass, and every changed workflow is valid YAML. +- **Verification:** run, and record outputs of: + - full audit per `audit.md` across all 18 workflow files + - `python3 .github/scripts/lint-action-pinning.py` and `python3 .github/scripts/lint-action-pinning_test.py` + - `python3 .github/scripts/release-workflow-contract_test.py` + - `python3 .github/scripts/claude-code-review-workflow-contract_test.py` + - `python3 .github/scripts/preview-env-workflow-contract_test.py` + - `python3 -c "import yaml,sys; [yaml.safe_load(open(f)) for f in sys.argv[1:]]" .github/workflows/*.yml` + - `git diff --check` +- **Files likely touched:** none (verification only). +- **Dependencies:** tasks 01–04. +- **Parallelism:** sequential (verification last). + +## Checklist + +1. Re-run step 1–2 of `audit.md`: every pinned SHA's `action.yml` reports `runs.using: node24` (or `composite` with node24 inner actions). Confirm the final output contains no `node20` line. +2. Confirm the SHA-pinning lint and its tests still pass (all refs remain 40-char SHAs). +3. Confirm the three workflow contract tests pass — the SHA-asserting ones only pin `crazy-max/ghaction-import-gpg@2dc316d…` and `actions/setup-node@48b55a0…`, both unchanged by this plan. +4. Confirm YAML parses for all workflows. +5. Record the first post-merge workflow run (e.g. `backend-tests`) where the Node-20 deprecation warning no longer appears. + +## Inputs + +plan.md verification section; `audit.md`. + +## Output contract + +Full audit output, all test command outputs, final status of `plan.md` and tasks 01–04. + +## Results + +- Full audit (audit_final.py) over all 18 workflows: 25 distinct pinned actions, every `runs.using` = `node24` or `composite` (rust-cache/checkout v6/setup-node v6/setup-go v6/pnpm v5/import-gpg v7.0.0/create-github-app-token v3.2.0 and the three composite actions dereferenced and re-checked at their commits). Zero `node20`. +- `lint-action-pinning.py` → all SHA-pinned; `lint-action-pinning_test.py` → 9 OK. +- Contract tests: release 24 OK, claude-code-review 9 OK, preview-env 1 OK. +- YAML parse: 18/18 OK; `git diff --check` clean. +- Post-merge warning check: pending — first `backend-tests`/`e2e-tests` run after merge should show no Node-20 deprecation warning.