ci(release): attest SLSA provenance over the release manifest's artifacts - #606
Merged
Merged
Conversation
…acts build-release writes an in-toto Statement v1 with a SLSA Provenance v1 predicate whose subjects are every artifact SHA256SUMS.txt lists, signs it with cosign keyless under the pipeline's CircleCI OIDC identity, verifies the attestation against built artifacts and against the manifest's lines, and publishes the statement and bundle beside the manifest. Co-Authored-By: jason.han <hanhuijun@gmail.com>
Contributor
Author
|
I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".
|
… mid-job Co-Authored-By: jason.han <hanhuijun@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
Releases now carry signed SLSA provenance over the artifacts they actually publish. The GitHub starter workflow proposed earlier (#414) would have attested two
echo'd placeholder files on a platform that does not build the release; this does it in the pipeline that does.build-releasegains two steps after the manifest is signed and verified:scripts/release-provenance.py --manifest dist/SHA256SUMS.txt --out dist/provenance.intoto.jsonwrites an in-toto Statement v1 whosesubjectis every line of the manifest (name+digest.sha256) and whosehttps://slsa.dev/provenance/v1predicate records the build: repository andrefs/tags/<tag>asexternalParameters, the release commit as aresolvedDependenciesgit URI, the CircleCI organization/project/workflow asinternalParameters, the project asrunDetails.builder.id, the job URL asinvocationId, buildTypehttps://github.com/Open-MBEE/OpenSysML/.circleci/build-release/v1. It fails closed rather than writing a vaguer statement: empty or malformed manifest lines, duplicate names, any missingCIRCLE_*field, a tag not matching^v[0-9], or a non-40-hexCIRCLE_SHA1.cosign attest-blob SHA256SUMS.txt --statement provenance.intoto.json --type slsaprovenance1 ...signs that statement as written (cosign keeps the supplied subjects, so one attestation covers every asset) keylessly under the same CircleCI OIDC identity as the manifest, intoprovenance.intoto.json.bundle.cosign verify-blob-attestationagainst a bundle archive, asysml-grpcbinary and the wheel under the identity regexp the clients pin, and adiffof the manifest's lines against the decoded DSSE payload's subjects, so a statement that names anything other than exactly the manifest's artifacts fails the release before anything is stored.publish-github-releaseuploadsprovenance.intoto.jsonandprovenance.intoto.json.bundlebesideSHA256SUMS.txt. The clients are unchanged; they keep verifying the signed manifest.docs/project/releasing.mddocuments the consumer check and, under "The release provenance", what the statement does and does not claim: SLSA Build L2 (provenance generated by the build itself, on a hosted runner, signed with an identity only this pipeline holds), not L3, since CircleCI does not issue provenance outside the job.How it was verified
scripts/release-provenance-test.py(13 tests) covers manifest parsing (blank lines,*binary marker, names with spaces, empty/malformed/duplicate lines), the environment validation, the statement's shape and metadata, and the CLI's success and failure paths. It runs in thego-staticCircleCI job and the PR workflow next to the changelog check.attest-blob --statementpreserves a two-subject statement;verify-blob-attestationpasses for a file whose digest is either subject and fails for one whose digest is not.python3 scripts/changelog.py check,scripts/check-doc-links.py,scripts/check-doc-ids.pypass; both YAML files parse.v*tag on CircleCI and cannot run outside a release; the new steps reuse the token acquisition, issuer, identity regexp and cosign install of the existing manifest-signing steps unchanged.Checklist
make testandmake lintpass locally (no Go code changed; the Python test and script checks above pass)changes/unreleased/<slug>.<section>.md, not as an edit toCHANGELOG.mdmake docs-countsrun if a gate count moved (none moved)F4,K5) in the body, docs, or changelog