From 6f01307e263d15cf8eaa94e0d9bc0f9dc7cd9953 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Wed, 23 Sep 2026 00:25:16 +0100 Subject: [PATCH] ci(scorecard): cure the 20/20 startup death and emit SARIF (#168) Root cause, read from the run page of every failed run since 09-07: "The workflow is requesting 'actions: read, contents: read', but is only allowed 'actions: none, contents: none'." A job-level `permissions:` block REPLACES the workflow-level map, so the job that carried only `security-events: write` + `id-token: write` left the callee's `actions: read` / `contents: read` at `none`, and the runner refused the call at startup (jobs=0, startup_failure). #158 added the two scopes on 09-21 but nothing has exercised the file since: it runs only on `branch_protection_rule` and a weekly cron, with no dispatch. Cure, in the shape of the standards canonical caller: - workflow-level `permissions: contents: read`, job-level the four scopes the callee's jobs request (actions/contents read, security-events/id-token write); - triggers: push to main, pull_request, workflow_dispatch, plus the existing branch_protection_rule and '23 4 * * 1' cron; - concurrency group per ref, cancel-in-progress; - callee pinned to standards 0f13f51f, which emits `results_format: sarif` and uploads it (bd0df9ea emitted JSON and uploaded nothing, so a green run would still have produced no Scorecard analysis); - `secrets: inherit` dropped: the callee references no secrets. Lock key `.github/workflows/scorecard.yml: []` is unchanged; the callee's steps are not validated against the caller's lock (hypatia-scan is the control). `gh actions-lock --verify-local`: all 16 workflows covered. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01QYY8Gp4v4x2J7iSNn1vZ57 --- .github/workflows/scorecard.yml | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index daab17b..a000aa5 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -1,22 +1,40 @@ # This workflow is managed by gh actions-lock. # SPDX-License-Identifier: MPL-2.0 -# This workflow is managed by gh actions-lock. -# This workflow is managed by gh actions-lock. +# Thin wrapper around hyperpolymath/standards scorecard-reusable.yml, in the +# shape of the standards caller (standards/.github/workflows/scorecard.yml). +# Deliberate differences from that caller: the cross-repo SHA pin, this repo's +# existing weekly cron, and the branch_protection_rule trigger. See #168. + name: Scorecards supply-chain security on: + push: + branches: [main] + pull_request: branch_protection_rule: schedule: - cron: '23 4 * * 1' + workflow_dispatch: + +# Estate guardrail: cancel superseded runs so re-pushes don't pile up. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true -permissions: read-all +# A job-level `permissions:` block REPLACES the workflow-level map, so the +# calling job below must itself grant every scope the callee's jobs request: +# actions: read (Scorecard's Packaging check), contents: read (checkout), +# security-events: write (SARIF upload), id-token: write (OIDC publication). +# This file died at startup 20/20 times while the job block carried only +# security-events + id-token, which left actions and contents at `none` (#168). +permissions: + contents: read jobs: - analysis: + scorecard: permissions: actions: read contents: read security-events: write id-token: write - uses: hyperpolymath/standards/.github/workflows/scorecard-reusable.yml@bd0df9ead7faf0cdfe0e13e7966d91e28d0101d4 - secrets: inherit + uses: hyperpolymath/standards/.github/workflows/scorecard-reusable.yml@0f13f51fafe9d2b670252aa2a18993223bffdece