Repository navigation
security: gate publication on verified attestations - #496
codeforester wants to merge 1 commit into
Conversation
| --repo "$GITHUB_REPOSITORY" \ | ||
| --signer-workflow "github.com/$GITHUB_REPOSITORY/.github/workflows/package.yml" \ | ||
| --source-digest "$SOURCE_COMMIT" \ | ||
| --source-ref "refs/tags/$RELEASE_TAG" |
There was a problem hiding this comment.
Correctness (breaks a documented flow): this hardcodes --source-ref "refs/tags/$RELEASE_TAG", but RELEASE_TAG is empty for a workflow_dispatch run that doesn't supply release_tag — exactly the documented TestPyPI rehearsal flow in docs/releasing.md (dispatch with publish_target=testpypi, leave release_tag blank, its documented default). build's metadata step leaves release_tag="" since source_ref_type is branch, so this becomes --source-ref "refs/tags/", which can never match the real attested ref (refs/heads/<branch>). Because publish now needs verify_attestations, this permanently breaks the TestPyPI rehearsal path.
| publish: | ||
| name: Publish reviewed distribution | ||
| needs: [build, smoke, provenance] | ||
| needs: [build, smoke, provenance, verify_attestations] |
There was a problem hiding this comment.
Fragility: publish's needs list dropped the direct attest dependency and now only lists verify_attestations; safe today only because verify_attestations itself needs attest — a fragile transitive assumption with no test guarding it. A later edit removing attest from verify_attestations.needs (e.g. someone 'simplifying' it, thinking attestations:read is unrelated to needing the attest job) would silently let publish start before attestations exist, defeating this PR's stated security goal with nothing to catch it.
| def test_package_workflow_verifies_attestations_before_publication() -> None: | ||
| workflow = (Path(__file__).resolve().parents[1] / ".github/workflows/package.yml").read_text(encoding="utf-8") | ||
| jobs = yaml.safe_load(workflow)["jobs"] | ||
|
|
There was a problem hiding this comment.
Test gap: this new test only asserts the literal strings '--source-digest "$SOURCE_COMMIT"' and '--source-ref "refs/tags/$RELEASE_TAG"' appear in the YAML text — it never exercises the case where RELEASE_TAG resolves to empty (non-tag workflow_dispatch). The workflow is functionally broken for branch-based dispatch runs (see the refs/tags/"" finding on package.yml) but this test still passes, since it only checks substring presence rather than resolved behavior for all trigger types.
Summary
GITHUB_SHA/GITHUB_REFin the final release verificationSecurity rationale
The previous graph allowed
publishandattestto run in parallel, so publication was not contingent on a verified attestation. This makes attestation verification an explicit prerequisite while preserving least-privilege permissions.Validation
UV_CACHE_DIR=/private/tmp/base-cli-uv-cache uv run --extra dev pytest -q tests/test_package_workflow.pygit diff --checkpassRelates to #487.