Skip to content

Commit 115b628

Browse files
committed
docs: clarify trusted-download spot-check scope; fix asset-preference docstring
Address review nits on the TRUSTED_DOWNLOAD_PROVENANCE escape hatch: - verify_trusted_download_provenance docstring listed checksums.txt / SHA256SUMS as preferred spot-check assets, contradicting _PROVENANCE_ASSET_PREFERENCES (which intentionally excludes them, as they carry in-toto rather than SLSA provenance and would 404 under `gh attestation verify`). Rewrite to match the actual preference list. - Add a scope caveat in both the docstring and README: the spot-check proves the release repo's pipeline attests and that its latest release is immutable, but does not machine-verify the action->release_repo binding nor that the specific fetched version is itself immutable (only releases/latest is checked). Those remain review-time assertions. Docs/comment-only; all 144 security tests still pass. Generated-by: Claude Opus 4.8 (claude-opus-4-8) via Claude Code
1 parent 9eb759a commit 115b628

2 files changed

Lines changed: 17 additions & 4 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ When reviewing an action (new or updated), watch for these potential issues in t
233233
- **File-system tampering**: writing to locations outside the workspace (`$GITHUB_WORKSPACE`), modifying `$GITHUB_ENV`, `$GITHUB_PATH`, or `$GITHUB_OUTPUT` in unexpected ways to influence subsequent workflow steps.
234234
- **Compiled JS mismatch**: any unexplained diff between the published `dist/` and a clean rebuild — this is the primary check the verification script performs.
235235
- **Pre-compiled native binaries shipped in-tree**: actions that commit Go/Rust/C-style binaries (`main-linux-amd64`, `*.exe`, `*.dll`, `*.so`, `*.dylib`, `*.jar`, `*.wasm`, etc.) directly in the repo and exec them from a small launcher are running opaque executable code on the runner. The JS-rebuild check verifies the launcher but **cannot** reconcile the binaries with source on its own. `verify-action-build`'s **In-tree binary check** tries to close the gap automatically: each detected binary is verified first via `gh attestation verify --owner <org>` (the SLSA attestation transparency log populated by [`actions/attest-build-provenance`](https://github.com/actions/attest-build-provenance)), then by SHA256-comparing each binary against the release's `SHA256SUMS` asset. Binaries that pass either check are ✓; binaries that pass neither are a hard reject. Push back on actions in this shape until upstream adds attestation or `SHA256SUMS` so the chain from release to artifact can be verified.
236-
- **Runtime binary downloads without an in-source checksum**: some actions pull their tool binary at runtime via `tc.downloadTool` / `curl` / `fetch` and rely on the publishing pipeline (GitHub release immutability + Sigstore attestation) for integrity rather than an inline `sha256sum -c` / `cosign verify-blob`. The **Binary Download Verification** check fails these by default. A per-action escape hatch lives in `utils/verify_action_build/security.py` as the `TRUSTED_DOWNLOAD_PROVENANCE` dict — an entry asserts that the configured `release_repo` publishes immutable releases AND emits Sigstore attestations via `actions/attest-build-provenance`. Adding an entry is a security review decision and the rationale must link the upstream confirmation (e.g. a maintainer comment). The config alone is not enough: at scan time the verify pipeline GETs `releases/latest` of the configured `release_repo`, confirms `release.immutable` is true, downloads one small attested asset (`.sbom.json` preferred), and runs `gh attestation verify` against it. Only when both halves pass are the action's unverified-download findings reclassified as warnings; if the runtime check fails, failures stay failures and the reason is printed.
236+
- **Runtime binary downloads without an in-source checksum**: some actions pull their tool binary at runtime via `tc.downloadTool` / `curl` / `fetch` and rely on the publishing pipeline (GitHub release immutability + Sigstore attestation) for integrity rather than an inline `sha256sum -c` / `cosign verify-blob`. The **Binary Download Verification** check fails these by default. A per-action escape hatch lives in `utils/verify_action_build/security.py` as the `TRUSTED_DOWNLOAD_PROVENANCE` dict — an entry asserts that the configured `release_repo` publishes immutable releases AND emits Sigstore attestations via `actions/attest-build-provenance`. Adding an entry is a security review decision and the rationale must link the upstream confirmation (e.g. a maintainer comment). The config alone is not enough: at scan time the verify pipeline GETs `releases/latest` of the configured `release_repo`, confirms `release.immutable` is true, downloads one small attested asset (`.sbom.json` preferred), and runs `gh attestation verify` against it. Only when both halves pass are the action's unverified-download findings reclassified as warnings; if the runtime check fails, failures stay failures and the reason is printed. Note the scope: the spot-check proves the *release repo's pipeline* attests and that its latest release is immutable — it does not machine-verify that the action downloads from that `release_repo`, nor that the *specific version* it fetches is itself immutable (only `releases/latest` is checked). That binding remains the reviewer's call, backed by the entry's `rationale`.
237237

238238
For the full approval policy and requirements, see the [ASF GitHub Actions Policy](https://infra.apache.org/github-actions-policy.html).
239239

utils/verify_action_build/security.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2032,11 +2032,24 @@ def verify_trusted_download_provenance(
20322032
``passed`` reflects whether both checks succeeded and ``reason`` is a
20332033
one-line summary suitable for the check-result display.
20342034
2035-
The asset attestation spot-check downloads exactly one small text
2036-
asset (checksums.txt / SHA256SUMS / .sbom.json by preference,
2037-
smallest available otherwise) — enough to confirm the release's
2035+
The asset attestation spot-check downloads exactly one small asset
2036+
(SBOM / in-toto / archive by preference — see
2037+
:data:`_PROVENANCE_ASSET_PREFERENCES`; a combined ``checksums.txt`` /
2038+
``SHA256SUMS`` is intentionally *not* preferred, as it usually carries
2039+
only an in-toto release attestation rather than SLSA provenance and
2040+
would 404 under ``gh attestation verify``). Downloading the smallest
2041+
available asset otherwise is enough to confirm the release's
20382042
publishing process emits attestations without paying the cost of
20392043
every per-platform binary.
2044+
2045+
Scope caveat: this proves the *release repo's publishing pipeline*
2046+
emits attestations and that its latest release is immutable. It does
2047+
**not** machine-verify the binding asserted in
2048+
:data:`TRUSTED_DOWNLOAD_PROVENANCE` — that the action actually
2049+
downloads from ``release_repo``, nor that the *specific version* it
2050+
fetches is itself immutable (only ``releases/latest`` is checked).
2051+
Those remain review-time assertions backed by the entry's
2052+
``rationale``.
20402053
"""
20412054
config = TRUSTED_DOWNLOAD_PROVENANCE.get(f"{action_org}/{action_repo}")
20422055
if not config:

0 commit comments

Comments
 (0)