diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e4adf47f..bf3e097e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,18 +10,18 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup Node - uses: actions/setup-node@v4 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "22" cache: npm - name: Setup Python - uses: actions/setup-python@v5 + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.12" cache: pip @@ -62,7 +62,7 @@ jobs: steps: - name: Checkout NodeRoom - uses: actions/checkout@v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ github.event.pull_request.head.sha || github.sha }} path: noderoom @@ -75,14 +75,14 @@ jobs: echo "sha=$sha" >> "$GITHUB_OUTPUT" - name: Checkout NodeSlide package producer - uses: actions/checkout@v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: repository: HomenShum/NodeSlide ref: ${{ steps.nodeslide-release.outputs.sha }} path: nodeslide - name: Setup Node - uses: actions/setup-node@v4 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: "22" cache: npm @@ -126,7 +126,7 @@ jobs: run: npm run nodeslide:mounted:release:proof -- --json-out nodeslide-mounted-release-proof.json - name: Upload mounted release receipt - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: nodeslide-mounted-release-${{ github.run_id }} path: noderoom/nodeslide-mounted-release-proof.json diff --git a/.github/workflows/design-gate.yml b/.github/workflows/design-gate.yml index 3740cf01..ae0683aa 100644 --- a/.github/workflows/design-gate.yml +++ b/.github/workflows/design-gate.yml @@ -18,8 +18,8 @@ jobs: env: QA_BASE_URL: http://localhost:5301 steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 22 cache: npm @@ -50,7 +50,7 @@ jobs: - name: Upload design-QA reports if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: design-qa-reports path: .tmp-qa/** diff --git a/.github/workflows/node-platform-conformance.yml b/.github/workflows/node-platform-conformance.yml index e2e24402..72eae5a5 100644 --- a/.github/workflows/node-platform-conformance.yml +++ b/.github/workflows/node-platform-conformance.yml @@ -10,4 +10,4 @@ permissions: jobs: node-platform: - uses: HomenShum/node-platform/.github/workflows/repo-conformance.yml@ef4ac8a011b230efa3324892a193abe02ff2d673 + uses: HomenShum/node-platform/.github/workflows/repo-conformance.yml@5c9aa6443ca8e61dc8886fbf0a0b4a7b72858e63 # Node 24 action pins (PR #8) diff --git a/.github/workflows/proofloop-gate.yml b/.github/workflows/proofloop-gate.yml index b9759fd4..35d6de4b 100644 --- a/.github/workflows/proofloop-gate.yml +++ b/.github/workflows/proofloop-gate.yml @@ -15,8 +15,8 @@ jobs: proofloop-gate: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 22 - run: npm ci diff --git a/.github/workflows/proofloop-suites.yml b/.github/workflows/proofloop-suites.yml index ee077561..c62822f1 100644 --- a/.github/workflows/proofloop-suites.yml +++ b/.github/workflows/proofloop-suites.yml @@ -15,8 +15,8 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 20 steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 22 cache: npm @@ -28,7 +28,7 @@ jobs: CI: "true" - name: Upload proof artifacts if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: proofloop-accounting path: .proofloop/runs/latest/ @@ -39,8 +39,8 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 20 steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 22 cache: npm @@ -52,7 +52,7 @@ jobs: CI: "true" - name: Upload proof artifacts if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: proofloop-notion path: .proofloop/runs/latest/ diff --git a/.github/workflows/proofloop.yml b/.github/workflows/proofloop.yml index e304d04b..290c4853 100644 --- a/.github/workflows/proofloop.yml +++ b/.github/workflows/proofloop.yml @@ -9,8 +9,8 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 22 cache: npm @@ -23,7 +23,7 @@ jobs: VITE_CONVEX_URL: ${{ secrets.VITE_CONVEX_URL }} - name: Upload proof artifacts if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: proximitty-underwriting-pr0 path: .proofloop/runs/latest/ diff --git a/.github/workflows/refresh-design-baselines.yml b/.github/workflows/refresh-design-baselines.yml index d0c46f6c..fe740acc 100644 --- a/.github/workflows/refresh-design-baselines.yml +++ b/.github/workflows/refresh-design-baselines.yml @@ -13,8 +13,8 @@ jobs: env: QA_BASE_URL: http://localhost:5301 steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 22 cache: npm @@ -28,7 +28,7 @@ jobs: run: npx playwright test design-baseline --update-snapshots - name: Upload refreshed snapshots if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: design-baselines path: e2e/design-baseline.spec.ts-snapshots/** diff --git a/.github/workflows/scaffold-check.yml b/.github/workflows/scaffold-check.yml index 0dfa640d..b97b1d13 100644 --- a/.github/workflows/scaffold-check.yml +++ b/.github/workflows/scaffold-check.yml @@ -12,11 +12,11 @@ jobs: scaffold-check: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 22 @@ -46,7 +46,7 @@ jobs: - name: Post scaffold report as PR comment if: always() && steps.handoff.outputs.exists == 'true' continue-on-error: true - uses: actions/github-script@v7 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const fs = require('fs'); @@ -91,7 +91,7 @@ jobs: - name: Upload scaffold artifacts if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: scaffold-report path: | diff --git a/proofloop/templates/github-proofloop-gate.yml b/proofloop/templates/github-proofloop-gate.yml index a944cec1..a619ab97 100644 --- a/proofloop/templates/github-proofloop-gate.yml +++ b/proofloop/templates/github-proofloop-gate.yml @@ -15,8 +15,8 @@ jobs: proofloop-gate: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 22 - run: npm ci diff --git a/tests/githubActionsRuntimePins.test.ts b/tests/githubActionsRuntimePins.test.ts new file mode 100644 index 00000000..44114b8f --- /dev/null +++ b/tests/githubActionsRuntimePins.test.ts @@ -0,0 +1,57 @@ +import { readdirSync, readFileSync } from "node:fs"; +import { join } from "node:path"; +import { describe, expect, it } from "vitest"; + +const expectedPins = { + checkout: { + sha: "3d3c42e5aac5ba805825da76410c181273ba90b1", + version: "v7.0.1", + }, + "setup-node": { + sha: "820762786026740c76f36085b0efc47a31fe5020", + version: "v7.0.0", + }, + "setup-python": { + sha: "5fda3b95a4ea91299a34e894583c3862153e4b97", + version: "v7.0.0", + }, + "upload-artifact": { + sha: "043fb46d1a93c77aae656e7c1c64a875d1fc6a0a", + version: "v7.0.1", + }, + "github-script": { + sha: "3a2844b7e9c422d3c10d287c895573f7108da1b3", + version: "v9.0.0", + }, +} as const; + +const workflowDirectory = join(process.cwd(), ".github", "workflows"); +const workflowFiles = readdirSync(workflowDirectory) + .filter((name) => name.endsWith(".yml") || name.endsWith(".yaml")) + .map((name) => join(workflowDirectory, name)); +const files = [...workflowFiles, join(process.cwd(), "proofloop", "templates", "github-proofloop-gate.yml")]; + +describe("GitHub Actions JavaScript runtime pins", () => { + it("uses immutable Node 24 release commits with readable version comments", () => { + for (const file of files) { + const lines = readFileSync(file, "utf8").split(/\r?\n/); + + for (const [index, line] of lines.entries()) { + const action = Object.keys(expectedPins).find((name) => line.includes(`actions/${name}@`)); + if (!action) continue; + + const pin = expectedPins[action as keyof typeof expectedPins]; + expect(line.trim(), `${file}:${index + 1}`).toContain( + `uses: actions/${action}@${pin.sha} # ${pin.version}`, + ); + } + } + }); + + it("binds Node Platform conformance to the warning-free immutable producer", () => { + const workflow = readFileSync(join(workflowDirectory, "node-platform-conformance.yml"), "utf8"); + expect(workflow).toContain( + "HomenShum/node-platform/.github/workflows/repo-conformance.yml@5c9aa6443ca8e61dc8886fbf0a0b4a7b72858e63 # Node 24 action pins (PR #8)", + ); + }); +}); diff --git a/tests/proofloopCi.test.ts b/tests/proofloopCi.test.ts index f4e48804..68e950ca 100644 --- a/tests/proofloopCi.test.ts +++ b/tests/proofloopCi.test.ts @@ -37,7 +37,8 @@ describe("proofloop ci install github", () => { const workflow = readFileSync(result.workflowPath, "utf8"); // The exact gate contract from scripts/proofloop-cli.ts cmdGoalGate. expect(workflow).toContain("npx tsx scripts/proofloop-cli.ts gate --goal official-scores"); - expect(workflow).toContain("actions/setup-node@v4"); + expect(workflow).toContain("actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1"); + expect(workflow).toContain("actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0"); expect(workflow).toContain("node-version: 22"); expect(workflow).toContain("npm ci"); expect(workflow).not.toContain(PROOFLOOP_CI_GOAL_PLACEHOLDER);