From 77e2a14062ba6b1dd222308c0ba13dac80616023 Mon Sep 17 00:00:00 2001 From: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Date: Sat, 30 May 2026 15:38:07 +0100 Subject: [PATCH 1/2] =?UTF-8?q?ci:=20bump=202=20stale=20action=20pins=20(d?= =?UTF-8?q?enoland/setup-deno=20v2.0.3=E2=86=92v2.0.4,=20haskell-actions/s?= =?UTF-8?q?etup=20v2.10.3=E2=86=92v2.11.0)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Caught during the wider standards SHA-pin audit triggered by the rsr-template-repo fake-SHA cleanup arc. Both pins are real — just older than the rest of the estate now uses post-#289 (setup-beam v1.24.0 consolidation) and post-rsr-template-repo#81 (template fake-SHA fix). denoland/setup-deno e95548e56dfa95d4e1a28d6f422fafe75c4c26fb (v2.0.3, 2024-10) -> 667a34cdef165d8d2b2e98dde39547c9daac7282 (v2.0.4) Used in: governance-reusable.yml:172 deno-ci-reusable.yml:59 (load-bearing — wrapped by N estate callers, propagates fleet-wide) haskell-actions/setup f9150cb1d140e9a9271700670baa38991e6fa25c (v2.10.3, comment says "v2") -> cd0d9bdd65b20557f41bea4dbe43d0b5fbbfe553 (v2.11.0) Used in: casket-pages.yml:32 (matches what panll#61, reposystem#84, rsr-template-repo#81 now use) Both new SHAs verified via `gh api repos///commits/` and match the version pins now in use across the estate. No behavioral change expected — these are routine pin bumps within the same major. Companion to: rsr-template-repo#81 (template fake-SHA fix, merged) standards#289 (setup-beam consolidation, merged) Per-repo fan-out: snifs#30 + 5 active-fix PRs + 16-repo template-stub sweep in flight. --- .github/workflows/casket-pages.yml | 2 +- .github/workflows/deno-ci-reusable.yml | 2 +- .github/workflows/governance-reusable.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/casket-pages.yml b/.github/workflows/casket-pages.yml index 72722a1c..325a4835 100644 --- a/.github/workflows/casket-pages.yml +++ b/.github/workflows/casket-pages.yml @@ -29,7 +29,7 @@ jobs: path: .casket-ssg - name: Setup GHCup - uses: haskell-actions/setup@f9150cb1d140e9a9271700670baa38991e6fa25c # v2 + uses: haskell-actions/setup@cd0d9bdd65b20557f41bea4dbe43d0b5fbbfe553 # v2.11.0 with: ghc-version: '9.8.2' cabal-version: '3.10' diff --git a/.github/workflows/deno-ci-reusable.yml b/.github/workflows/deno-ci-reusable.yml index 413d9abc..b31fd1c6 100644 --- a/.github/workflows/deno-ci-reusable.yml +++ b/.github/workflows/deno-ci-reusable.yml @@ -56,7 +56,7 @@ jobs: repository: ${{ github.repository }} ref: ${{ github.ref }} - - uses: denoland/setup-deno@e95548e56dfa95d4e1a28d6f422fafe75c4c26fb # v2.0.3 + - uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282 # v2.0.4 with: deno-version: ${{ inputs.deno-version }} diff --git a/.github/workflows/governance-reusable.yml b/.github/workflows/governance-reusable.yml index 3c3bc91a..9e66be0e 100644 --- a/.github/workflows/governance-reusable.yml +++ b/.github/workflows/governance-reusable.yml @@ -169,7 +169,7 @@ jobs: # version and the script version — acceptable since scripts here # are read-only governance checks. - name: Set up Deno - uses: denoland/setup-deno@e95548e56dfa95d4e1a28d6f422fafe75c4c26fb # v2.0.3 + uses: denoland/setup-deno@667a34cdef165d8d2b2e98dde39547c9daac7282 # v2.0.4 with: deno-version: v2.x From a3829d4ed49fa8d9fd2e9679c0377df12017be23 Mon Sep 17 00:00:00 2001 From: hyperpolymath <6759885+hyperpolymath@users.noreply.github.com> Date: Sat, 30 May 2026 17:24:32 +0100 Subject: [PATCH 2/2] ci(scorecard-enforcer): split score-threshold from publish job (OSSF run-step ban) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Root cause OSSF's publish endpoint enforces a hard contract: webapp: scorecard job must only have steps with uses When a job that runs `ossf/scorecard-action` with `publish_results: true` also contains any `run:` step (in our case the "Check minimum score" threshold gate), the publish step fails and the entire workflow run is marked failed. The 2026-05-30 estate audit caught **49 repos** running this canonical-but-broken shape. ## Fix - `scorecard` job stays `uses:`-only (checkout → run-scorecard → upload-sarif → upload-artifact). All steps satisfy the OSSF contract. - New `check-score` job, `needs: scorecard`, downloads the SARIF artifact and runs the threshold check. `run:` step lives here. Real SHA pins verified via `gh api repos/.../commits/`: - actions/upload-artifact@330a01c4 (v5.0.0) - actions/download-artifact@018cc2cf (v5.0.0) ## Fan-out 49 estate repos carry per-repo clones of this file. Single template fix here; sweep fan-out follows in a separate API content-replace pass. ## Hypatia rule `Hypatia.Rules.WorkflowAudit.check_scorecard_publish_run_violation` (WF014) added in companion PR to hypatia (catches future regressions). Smoke-tested for sensitivity (fires on this exact shape) and specificity (does not fire on the reusable-only `scorecard.yml` or on jobs without `publish_results: true`). Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/scorecard-enforcer.yml | 29 +++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/.github/workflows/scorecard-enforcer.yml b/.github/workflows/scorecard-enforcer.yml index 6933b781..75e23854 100644 --- a/.github/workflows/scorecard-enforcer.yml +++ b/.github/workflows/scorecard-enforcer.yml @@ -21,6 +21,16 @@ permissions: contents: read jobs: + # The OSSF Scorecard publish endpoint enforces a hard contract: the job that + # runs `ossf/scorecard-action` with `publish_results: true` must contain + # ONLY steps with `uses:` (no `run:` steps in the same job). If a `run:` + # step is present, the publish step fails with: + # "webapp: scorecard job must only have steps with uses" + # (49 estate repos hit this; see ROADMAP audit 2026-05-30.) + # + # Fix: split the threshold check into a downstream job that depends on + # `scorecard` and consumes the SARIF artifact. The `scorecard` job stays + # uses-only; `check-score` is the gating job that emits the error. scorecard: runs-on: ubuntu-latest permissions: @@ -43,9 +53,26 @@ jobs: with: sarif_file: results.sarif + - name: Persist SARIF for downstream score-gate job + uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 + with: + name: scorecard-results + path: results.sarif + retention-days: 1 + + check-score: + needs: scorecard + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Download SARIF from scorecard job + uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v5.0.0 + with: + name: scorecard-results + - name: Check minimum score run: | - # Parse score from results SCORE=$(jq -r '.runs[0].tool.driver.properties.score // 0' results.sarif 2>/dev/null || echo "0") echo "OpenSSF Scorecard Score: $SCORE"