diff --git a/.github/workflows/scorecard-analysis.yml b/.github/workflows/scorecard-analysis.yml index 3856a4666..4a63510ef 100644 --- a/.github/workflows/scorecard-analysis.yml +++ b/.github/workflows/scorecard-analysis.yml @@ -26,7 +26,7 @@ jobs: persist-credentials: false - name: Run analysis - uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 + uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4 with: results_file: results.sarif results_format: sarif diff --git a/.github/workflows/scorecard-pr.yml b/.github/workflows/scorecard-pr.yml index cb05d1a07..c2be733b7 100644 --- a/.github/workflows/scorecard-pr.yml +++ b/.github/workflows/scorecard-pr.yml @@ -46,7 +46,7 @@ jobs: persist-credentials: false - name: Run analysis - uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 + uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4 with: results_file: results.sarif results_format: sarif diff --git a/.github/workflows/security-scan.yml b/.github/workflows/security-scan.yml index 29376269d..83cb5e49e 100644 --- a/.github/workflows/security-scan.yml +++ b/.github/workflows/security-scan.yml @@ -409,7 +409,7 @@ jobs: with: persist-credentials: false - name: Run Scorecard - uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3 + uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4 with: results_file: results.sarif results_format: sarif diff --git a/CHANGELOG.md b/CHANGELOG.md index 1630c32d4..3ee62b45e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,9 @@ Semantic Versioning where the repository publishes a release. ### Fixed +- Aligned every central OpenSSF Scorecard Action use to the official v2.4.4 + commit so pull-request, scheduled, and combined security scans execute one + immutable, reviewed release. - Publish only the sanitized cumulative Strix report tree, avoiding a later copy of relative scanner output that could reintroduce known internal warning text into uploaded security evidence. diff --git a/docs/doctoring/scorecard-action-single-version.md b/docs/doctoring/scorecard-action-single-version.md new file mode 100644 index 000000000..a44486e37 --- /dev/null +++ b/docs/doctoring/scorecard-action-single-version.md @@ -0,0 +1,33 @@ +# Scorecard Action single-version boundary + +## Incident boundary + +The central pull-request, scheduled, and combined security workflows all use +OpenSSF Scorecard, but dependency automation updates workflow references +independently. A partial bump can leave posture evidence produced by different +action releases even though the jobs appear to provide one control. + +## Decision + +Pin every central `ossf/scorecard-action` use to +`2d1146689b8cda280b9bc96326124645441f03bc`, the commit referenced by the +official signed v2.4.4 tag. The current release updates Scorecard to v5.5.0 and +records POST failures without failing the entire action (Open Source Security +Foundation, 2026). + +GitHub documents that a full commit SHA is unique and immutable and should be +verified against the action repository (GitHub, n.d.). A repository-wide +contract therefore parses every central workflow occurrence, rejects malformed +pins, and admits only the reviewed v2.4.4 SHA and tag. Workflow permissions, +events, arguments, SARIF semantics, thresholds, and fail-closed gates are +unchanged. + +## References + +GitHub. (n.d.). *Using pre-written building blocks in your workflow*. +Retrieved August 24, 2026, from +https://docs.github.com/en/actions/how-tos/write-workflows/choose-what-workflows-do/find-and-customize-actions + +Open Source Security Foundation. (2026, July 23). *Scorecard Action v2.4.4* +[Software release]. +https://github.com/ossf/scorecard-action/releases/tag/v2.4.4 diff --git a/tests/test_scorecard_action_pin_contract.py b/tests/test_scorecard_action_pin_contract.py new file mode 100644 index 000000000..7bee0f392 --- /dev/null +++ b/tests/test_scorecard_action_pin_contract.py @@ -0,0 +1,31 @@ +"""Keep every central OpenSSF Scorecard Action use on one reviewed release.""" + +from __future__ import annotations + +import re +from pathlib import Path + + +REPO_ROOT = Path(__file__).resolve().parents[1] +SCORECARD_SHA = "2d1146689b8cda280b9bc96326124645441f03bc" +SCORECARD_TAG = "v2.4.4" +_PIN = re.compile( + r"ossf/scorecard-action@(?P[^\s]+)\s+#\s+(?Pv[^\s]+)" +) + + +def test_all_scorecard_actions_share_the_reviewed_current_release() -> None: + """Reject partial bumps, malformed refs, and stale Scorecard releases.""" + observed: set[tuple[str, str]] = set() + + for path in sorted((REPO_ROOT / ".github/workflows").glob("*.y*ml")): + for line_number, line in enumerate( + path.read_text(encoding="utf-8").splitlines(), start=1 + ): + if "uses:" not in line or "ossf/scorecard-action@" not in line: + continue + match = _PIN.search(line) + assert match is not None, f"malformed Scorecard pin: {path}:{line_number}" + observed.add((match.group("sha"), match.group("tag"))) + + assert observed == {(SCORECARD_SHA, SCORECARD_TAG)}