From e0313107f696d3b792b3f37c217bb690b44e8bdc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 18 Oct 2026 20:47:55 +0000 Subject: [PATCH 1/3] chore(actions): bump the github-actions group across 1 directory with 3 updates Bumps the github-actions group with 3 updates in the / directory: [actions/setup-node](https://github.com/actions/setup-node), [actions/upload-artifact](https://github.com/actions/upload-artifact) and [actions/download-artifact](https://github.com/actions/download-artifact). Updates `actions/setup-node` from 7.0.0 to 7.1.0 - [Release notes](https://github.com/actions/setup-node/releases) - [Commits](https://github.com/actions/setup-node/compare/820762786026740c76f36085b0efc47a31fe5020...949feb2413d6458794dcd2491c4babbbce0c15c1) Updates `actions/upload-artifact` from 7.0.1 to 7.0.2 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/043fb46d1a93c77aae656e7c1c64a875d1fc6a0a...cf430e030ddbb5b0abf93d22962f4752f3646cd9) Updates `actions/download-artifact` from 8.0.1 to 8.0.2 - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c...9000827ccba6bdab643e8b6fd33ac0654aef8333) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: 8.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/setup-node dependency-version: 7.1.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions - dependency-name: actions/upload-artifact dependency-version: 7.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 10 +++++----- .github/workflows/deploy-examples.yml | 8 ++++---- .github/workflows/publish-nightly.yml | 20 +++++++++---------- .../workflows/refresh-screenshot-evidence.yml | 4 ++-- .github/workflows/rollback-examples.yml | 2 +- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d09fabf..94db785 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,7 +45,7 @@ jobs: steps: - name: Set up exact Node - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: ${{ env.LFC_NODE_VERSION }} package-manager-cache: false @@ -114,7 +114,7 @@ jobs: head-ref: ${{ needs.source.outputs.head }} - name: Set up exact Node - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: ${{ env.LFC_NODE_VERSION }} package-manager-cache: false @@ -146,7 +146,7 @@ jobs: - name: Upload browser results and failure diagnostics if: always() - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: browser-diagnostics-${{ github.run_id }} if-no-files-found: ignore @@ -183,7 +183,7 @@ jobs: ref: ${{ github.event.pull_request.head.sha }} - name: Set up exact Node - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: ${{ env.LFC_NODE_VERSION }} package-manager-cache: false @@ -219,7 +219,7 @@ jobs: - name: Upload screenshot candidates and comparison gallery if: ${{ always() && steps.eligibility.outputs.eligible == 'true' }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: screenshot-candidate-${{ github.run_id }}-${{ github.run_attempt }} path: .cache/screenshots/candidate/ diff --git a/.github/workflows/deploy-examples.yml b/.github/workflows/deploy-examples.yml index 2ae6bc5..af408c4 100644 --- a/.github/workflows/deploy-examples.yml +++ b/.github/workflows/deploy-examples.yml @@ -131,7 +131,7 @@ jobs: - name: Set up exact Node if: ${{ steps.identity.outputs.eligible == 'true' }} - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: ${{ env.LFC_NODE_VERSION }} package-manager-cache: false @@ -168,7 +168,7 @@ jobs: - name: Upload the raw verified channel without deployment authority if: ${{ steps.identity.outputs.eligible == 'true' }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: ${{ steps.artifact.outputs.name }} if-no-files-found: error @@ -200,7 +200,7 @@ jobs: ref: ${{ needs.build.outputs.source-commit }} - name: Set up exact Node for canonical Pages assembly - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: ${{ env.LFC_NODE_VERSION }} package-manager-cache: false @@ -214,7 +214,7 @@ jobs: run: npm ci --ignore-scripts - name: Download the raw verified channel - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: ${{ needs.build.outputs.channel-artifact }} path: ${{ runner.temp }}/pages-channel diff --git a/.github/workflows/publish-nightly.yml b/.github/workflows/publish-nightly.yml index 997431b..06cee05 100644 --- a/.github/workflows/publish-nightly.yml +++ b/.github/workflows/publish-nightly.yml @@ -123,7 +123,7 @@ jobs: ref: ${{ github.sha }} - name: Set up exact Node - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: ${{ env.LFC_NODE_VERSION }} package-manager-cache: false @@ -257,7 +257,7 @@ jobs: - name: Upload browser diagnostics on failure if: failure() && steps.registry-state.outputs.eligible == 'true' - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: release-browser-diagnostics-${{ github.run_id }} if-no-files-found: ignore @@ -331,7 +331,7 @@ jobs: - name: Upload the exact npm release bundle if: ${{ steps.registry-state.outputs.eligible == 'true' }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: ${{ steps.identity.outputs.bundle-artifact }} if-no-files-found: error @@ -341,7 +341,7 @@ jobs: - name: Upload normalized release notes if: ${{ steps.registry-state.outputs.eligible == 'true' }} - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: ${{ steps.identity.outputs.notes-artifact }} if-no-files-found: error @@ -365,13 +365,13 @@ jobs: steps: - name: Download the verified bundle without checking out source - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: ${{ needs.verify.outputs.bundle-artifact }} path: ${{ runner.temp }}/release-bundle - name: Download normalized release notes - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: ${{ needs.verify.outputs.notes-artifact }} path: ${{ runner.temp }}/release-notes @@ -490,7 +490,7 @@ jobs: steps: - name: Set up exact Node for npm trusted publishing - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: ${{ env.LFC_NODE_VERSION }} package-manager-cache: false @@ -635,7 +635,7 @@ jobs: ' <<< "${comparison}" > /dev/null - name: Download the verified bundle without checking out source - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: ${{ needs.verify.outputs.bundle-artifact }} path: ${{ runner.temp }}/release-bundle @@ -847,7 +847,7 @@ jobs: steps: - name: Set up exact Node for registry verification - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: ${{ env.LFC_NODE_VERSION }} package-manager-cache: false @@ -857,7 +857,7 @@ jobs: run: npm install --global "npm@${LFC_NPM_VERSION}" --ignore-scripts - name: Download the retained bundle for provenance verification - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: name: ${{ needs.verify.outputs.bundle-artifact }} path: ${{ runner.temp }}/release-bundle diff --git a/.github/workflows/refresh-screenshot-evidence.yml b/.github/workflows/refresh-screenshot-evidence.yml index 01980d6..8c6e472 100644 --- a/.github/workflows/refresh-screenshot-evidence.yml +++ b/.github/workflows/refresh-screenshot-evidence.yml @@ -50,7 +50,7 @@ jobs: ref: ${{ github.sha }} - name: Set up exact Node - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: ${{ env.LFC_NODE_VERSION }} package-manager-cache: false @@ -61,7 +61,7 @@ jobs: - name: Download the validated candidate artifact if: ${{ steps.context.outputs.eligible == 'true' }} - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: github-token: ${{ github.token }} repository: ${{ github.repository }} diff --git a/.github/workflows/rollback-examples.yml b/.github/workflows/rollback-examples.yml index 810a9b6..c702310 100644 --- a/.github/workflows/rollback-examples.yml +++ b/.github/workflows/rollback-examples.yml @@ -47,7 +47,7 @@ jobs: ref: ${{ github.sha }} - name: Set up exact Node for canonical Pages assembly - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 with: node-version: ${{ env.LFC_NODE_VERSION }} package-manager-cache: false From 82994c29c0064f681661259549cddcfd6f3c701e Mon Sep 17 00:00:00 2001 From: Basi Angulo <6586019+redbasi@users.noreply.github.com> Date: Sun, 18 Oct 2026 14:08:03 -0700 Subject: [PATCH 2/3] test: allow consistent artifact action patch updates --- scripts/tests/workflow-contracts.test.mjs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/tests/workflow-contracts.test.mjs b/scripts/tests/workflow-contracts.test.mjs index 0db9a64..0514840 100644 --- a/scripts/tests/workflow-contracts.test.mjs +++ b/scripts/tests/workflow-contracts.test.mjs @@ -664,24 +664,25 @@ void test("workflow artifacts use bounded purpose-specific retention", async () } }); -void test("artifact downloads use the official Node 24 action", async () => { +void test("artifact downloads consistently pin the official v8 action", async () => { const workflows = [ "deploy-examples.yml", "publish-nightly.yml", "refresh-screenshot-evidence.yml", "rollback-examples.yml" ]; - const expected = - "actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1"; + const pins = new Set(); let downloads = 0; for (const name of workflows) { const source = await workflow(name); for (const match of source.matchAll(/^\s*uses:\s*(actions\/download-artifact@[^\r\n]+)$/gmu)) { downloads += 1; - assert.equal(match[1], expected, name); + assert.match(match[1], /^actions\/download-artifact@[0-9a-f]{40} # v8\.\d+\.\d+$/u, name); + pins.add(match[1]); } } assert.equal(downloads, 6); + assert.equal(pins.size, 1, "All artifact downloads must use the same reviewed action pin."); }); void test("workflow dependency caches stay disabled", async () => { From d8810e714bc3429d43f791084a810e59aebaeff5 Mon Sep 17 00:00:00 2001 From: Basi Angulo <6586019+redbasi@users.noreply.github.com> Date: Sun, 18 Oct 2026 20:28:31 -0700 Subject: [PATCH 3/3] fix: scope screenshot runner context to its step --- .github/workflows/refresh-screenshot-evidence.yml | 3 ++- scripts/tests/workflow-contracts.test.mjs | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/refresh-screenshot-evidence.yml b/.github/workflows/refresh-screenshot-evidence.yml index 8c6e472..15691d5 100644 --- a/.github/workflows/refresh-screenshot-evidence.yml +++ b/.github/workflows/refresh-screenshot-evidence.yml @@ -40,7 +40,6 @@ jobs: LFC_UPSTREAM_RUN_ID: ${{ github.event.workflow_run.id }} LFC_UPSTREAM_RUN_ATTEMPT: ${{ github.event.workflow_run.run_attempt }} LFC_UPSTREAM_HEAD_SHA: ${{ github.event.workflow_run.head_sha }} - LFC_CANDIDATE_DIRECTORY: ${{ runner.temp }}/screenshot-candidate steps: - name: Check out trusted promotion code without persisted credentials @@ -72,4 +71,6 @@ jobs: - name: Refresh identical evidence and verify the new exact head if: ${{ steps.context.outputs.eligible == 'true' }} + env: + LFC_CANDIDATE_DIRECTORY: ${{ runner.temp }}/screenshot-candidate run: node scripts/screenshot-automation.mjs promote diff --git a/scripts/tests/workflow-contracts.test.mjs b/scripts/tests/workflow-contracts.test.mjs index 0514840..77ca201 100644 --- a/scripts/tests/workflow-contracts.test.mjs +++ b/scripts/tests/workflow-contracts.test.mjs @@ -556,7 +556,11 @@ void test("screenshot promotion consumes a validated artifact without executing assert.match(promote, /LFC_UPSTREAM_RUN_ATTEMPT: \$\{\{ github\.event\.workflow_run\.run_attempt \}\}/u); assert.match(promote, /LFC_UPSTREAM_HEAD_SHA: \$\{\{ github\.event\.workflow_run\.head_sha \}\}/u); assert.match(promote, /screenshot-automation\.mjs promotion-context[\s\S]*?steps\.context\.outputs\.eligible == 'true'[\s\S]*?actions\/download-artifact@[0-9a-f]{40}[\s\S]*?run-id: \$\{\{ github\.event\.workflow_run\.id \}\}[\s\S]*?artifact-ids: \$\{\{ steps\.context\.outputs\.artifact-id \}\}[\s\S]*?screenshot-automation\.mjs promote/u); - assert.match(promote, /LFC_CANDIDATE_DIRECTORY: \$\{\{ runner\.temp \}\}\/screenshot-candidate/u); + const stepBoundary = promote.indexOf("\n steps:"); + assert.ok(stepBoundary > 0, "Promotion must declare its steps."); + assert.doesNotMatch(promote.slice(0, stepBoundary), /\$\{\{\s*runner\./u, + "The runner context is unavailable in job-level environment variables."); + assert.match(promote, /Refresh identical evidence and verify the new exact head[\s\S]*?\n {8}env:\s*\n {10}LFC_CANDIDATE_DIRECTORY: \$\{\{ runner\.temp \}\}\/screenshot-candidate\s*\n {8}run: node scripts\/screenshot-automation\.mjs promote/u); }); void test("hosted gates run Chromium and WebKit while local Playwright retains Firefox", async () => {