Repository navigation
ci: attach the SBOMs to the GitHub release - #4
Merged
Merged
Conversation
SECURITY.md says each release ships a CycloneDX SBOM. It did — as a workflow artifact, which expires after 90 days, and nuget.org has no slot for one. The releases for v1.0.0 through v6.2.0 carry no assets, so the statement was true for one quarter per release and then quietly false. A third job, `release`, now runs after `publish`: it creates the GitHub release if none exists (notes taken from this version's section of CHANGELOG.md, which ChangelogConventionTests already requires for the shipped version — an empty extraction fails the job rather than publishing a blank release; the heading's self-referential link brackets are dropped) and attaches the per-package `.cdx.json` files. A release created by hand before the tag is pushed is left as written; only the assets are added. It runs after the push so what is attached describes what is on nuget.org, and a failure here costs nothing but a manual upload. Only the SBOMs are attached, deliberately. nuget.org repository-signs every package on ingestion, so a .nupkg downloaded from there never matches ours byte-for-byte; attaching ours would invite a hash comparison that fails for a benign reason, and nuget.org is already the immutable store for the packages. The SBOM has no other home. The job holds contents: write and no id-token; publish holds id-token: write and contents: read. No job holds both. Verified: actionlint clean; the two run blocks executed locally, extracted verbatim from the YAML, with `gh release create/upload` stubbed and `gh release view` live — existing release (v6.2.0) leaves notes alone and exits 0, missing release creates with the extracted section, a version with no CHANGELOG section fails, and a missing SBOM glob fails. The extraction was checked against all ten shipped versions. ReleaseWiringConventionTests still pass. Not exercised: an actual tag push — the first real run is the next release. Co-Authored-By: Claude Fable 5 <[email protected]>
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.
Why
SECURITY.md says each release ships a CycloneDX SBOM. It did — as a workflow artifact, which expires after 90 days, and nuget.org has no slot for one. The GitHub releases for v1.0.0–v6.2.0 carry no assets. So the statement holds for one quarter per release and then goes quietly false — the exact shape of claim the security policy warns against overstating.
What
A third job in
release.yml,release, runs afterpublish:CHANGELOG.mdas the notes — the sectionChangelogConventionTestsalready requires for the shipped version. An empty extraction fails the job rather than publishing a blank release. The heading's[6.2.0]link brackets are dropped (their target is the release page itself). A release created by hand before the tag was pushed is left as written; only the assets are added.*.cdx.jsonfiles (--clobber, so a re-run is safe).Runs after the push, so what is attached describes what is on nuget.org; a failure here is loud and costs a manual upload, nothing more.
Only the SBOMs are attached, deliberately. nuget.org repository-signs every package on ingestion, so a
.nupkgdownloaded from there never matches ours byte-for-byte. Attaching ours would invite a hash comparison that fails for a benign reason, and nuget.org is already the immutable store for the packages. The SBOM has no other home.Permissions:
releaseholdscontents: writeand noid-token;publishholdsid-token: writeandcontents: read. No job holds both — the split that was already the security boundary is kept.Docs updated to match: SECURITY.md and the README's project-practices line now say where the SBOM lives.
Same change as EFCore.ComplexIndexes#17, with the notes source adapted (README "What changed" section there,
CHANGELOG.mdhere — the README's "What's new in v6.2" is per minor, so a patch release would have no section).Verified
actionlintclean.run:blocks were extracted verbatim from the YAML and executed locally withgh release create/uploadstubbed andgh release viewlive: existing release (v6.2.0) → leaves notes alone, exit 0; missing release → creates with the extracted section;viewfailing for a reason other than "release not found" → fails loudly instead of attempting a create; no CHANGELOG section for the version → fails; no.cdx.jsonin the artifact → fails.CodoMetis.ValueRanges.Conventions.Tests(31, incl.ReleaseWiringConventionTests) pass.Not exercised: an actual tag push. The first real run of the job is the next release; if it fails, the packages are already on nuget.org and the SBOMs are still in the run's artifact for a manual upload.
🤖 Generated with Claude Code