Skip to content

Commit fee07db

Browse files
ci(scorecard-enforcer): split score-threshold from publish job (OSSF run-step ban — 49 repos affected) (#304)
## Summary Estate CI/CD audit 2026-05-30 caught **49 repos** failing on `OpenSSF Scorecard Enforcer` with: ``` webapp: scorecard job must only have steps with uses ``` ## Root cause OSSF's publish endpoint enforces a hard contract: the job that runs `ossf/scorecard-action` with `publish_results: true` must contain ONLY `uses:` steps. Any `run:` step in the same job — typically a "Check minimum score" threshold gate — fails the publish step and the whole workflow run. ## Fix - `scorecard` job: `uses:`-only (checkout → run-scorecard → upload-sarif → upload-artifact). Satisfies OSSF contract. - New `check-score` job, `needs: scorecard`, downloads the SARIF artifact and runs the threshold check. `run:` lives here. Real SHA pins verified via API: - `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; mechanical sweep follows in a separate API content-replace pass. ## Hypatia rule Companion PR adds WF014 (`scorecard_publish_with_run_step`) so this pattern is detected automatically going forward. Sensitivity + specificity smoke-tested: - Fires on pre-fix shape: ✓ - Does NOT fire on reusable-only (no publish): ✓ 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent d966c9d commit fee07db

1 file changed

Lines changed: 28 additions & 1 deletion

File tree

.github/workflows/scorecard-enforcer.yml

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ permissions:
2121
contents: read
2222

2323
jobs:
24+
# The OSSF Scorecard publish endpoint enforces a hard contract: the job that
25+
# runs `ossf/scorecard-action` with `publish_results: true` must contain
26+
# ONLY steps with `uses:` (no `run:` steps in the same job). If a `run:`
27+
# step is present, the publish step fails with:
28+
# "webapp: scorecard job must only have steps with uses"
29+
# (49 estate repos hit this; see ROADMAP audit 2026-05-30.)
30+
#
31+
# Fix: split the threshold check into a downstream job that depends on
32+
# `scorecard` and consumes the SARIF artifact. The `scorecard` job stays
33+
# uses-only; `check-score` is the gating job that emits the error.
2434
scorecard:
2535
runs-on: ubuntu-latest
2636
permissions:
@@ -43,9 +53,26 @@ jobs:
4353
with:
4454
sarif_file: results.sarif
4555

56+
- name: Persist SARIF for downstream score-gate job
57+
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
58+
with:
59+
name: scorecard-results
60+
path: results.sarif
61+
retention-days: 1
62+
63+
check-score:
64+
needs: scorecard
65+
runs-on: ubuntu-latest
66+
permissions:
67+
contents: read
68+
steps:
69+
- name: Download SARIF from scorecard job
70+
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v5.0.0
71+
with:
72+
name: scorecard-results
73+
4674
- name: Check minimum score
4775
run: |
48-
# Parse score from results
4976
SCORE=$(jq -r '.runs[0].tool.driver.properties.score // 0' results.sarif 2>/dev/null || echo "0")
5077
5178
echo "OpenSSF Scorecard Score: $SCORE"

0 commit comments

Comments
 (0)