Sign in

Search issue titles and bodies, change requests and comments. Private repositories you cannot read are not included.

vole
Clone

Read only, no credentials:

https://rodent.software/git/vole.git

Write over SSH with a registered key:

git clone ssh://git@0.0.0.0:2222/vole.git

A free and open-source forge that lives in your Git repo.

#93

P2: Publish a software bill of materials with each release

closed · opened by keenan 10d ago

keenan opened this 10d ago

Why

A release attaches the binaries, the packages, and SHA256SUMS, but not the component list they were built from. Someone answering “is this instance affected by an advisory in a dependency” has to check out the tag and rebuild go.mod’s graph by hand, and a downstream packager has no authoritative list to compare against.

Nothing has to be invented to produce that list: go.mod and go.sum pin every module, the release image pins the toolchain and the SQLite development library, and the build is already reproducible (SOURCE_DATE_EPOCH, no build id).

Scope

  • Generate one SBOM per release from the pinned build, in a machine-readable format (SPDX-JSON or CycloneDX), naming every Go module version, the Go toolchain, and the SQLite library version the binary links through cgo.
  • Generate it with a pinned tool, the way govulncheck and nfpm are pinned, so a local run and the release run agree.
  • Attach it to the tag’s release beside SHA256SUMS in .vole/workflows/release.yaml with release: true.
  • Keep it reproducible: the same tag produces the same SBOM bytes.
  • Document in docs/releases.md what it covers and what it does not.

Out of scope: the runner images in .vole/images. They are built on the runner host, not by the release, so their contents are a runner concern.

Acceptance

  • A release page lists the SBOM next to SHA256SUMS.
  • It names github.com/mattn/go-sqlite3 and the linked SQLite version, not just the module names.
  • Rebuilding the same tag produces an identical SBOM.
  • docs/releases.md says what the SBOM covers, who consumes it, and how to regenerate it.

Part of #14.

Comments (1)

keenan 10d ago

Implemented on sbom-per-release. Two notes from doing it.

The acceptance line about naming the linked SQLite version does not hold as written, and I did not fix it by bending the build. CycloneDX analysis of a Go application reads the module graph, so it names github.com/mattn/go-sqlite3 v1.14.52 — the binding — and cannot see the libsqlite3-0 version the package depends on. Getting the library version into the same file needs a second component injected into the JSON: either python3 in the release image plus a bespoke post-processor, or cyclonedx-cli merge as another pinned tool. Both are more machinery than the fact is worth, because the packages already declare Depends: libsqlite3-0 and dpkg -s vole / rpm -q --requires vole answer it authoritatively for the installed system.

So the rule the section now states is: the SBOM covers the Go build; the system library comes from the package. If you want the library in the BOM anyway, say so and I will add the merge step rather than leave this as a silent narrowing.

Two acceptance lines are evidenced rather than assumed:

  • Reproducibility: the same tag, run twice, is byte-identical. The only field the tool takes from the clock is metadata.timestamp; the step rewrites it from SOURCE_DATE_EPOCH (the tag’s commit time) and then fails if the rewrite did not land, so a silent no-op cannot ship the build clock.
  • One file for both architectures: go list -deps under goarch=amd64 and goarch=arm64 produces the same module set for ./cmd/vole (same hash over the module list). Only the compiled files differ, and the SBOM is module-level.

Licences come through as CycloneDX evidence rather than asserted conclusions: 10 MIT, 5 BSD-3-Clause, 2 Apache-2.0, 4 BSD-Source-Code across 22 components. That is one pinned tool doing the detection, which #95 can build its allowlist on instead of adding a second scanner.