Add SBOM and provenance generation - #188
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds supply-chain metadata generation and publishing for Flashbox L1 builds by producing a CycloneDX 1.6 SBOM from the mkosi manifest and signing/verifying provenance + SBOM attestations during the publish workflow.
Changes:
- Add an mkosi post-output script to generate a deterministic CycloneDX 1.6 SBOM from the mkosi JSON manifest.
- Extend the build/publish workflow to generate combined
SHA256SUMS, create Sigstore (SLSA provenance + SBOM) attestations, verify them, and upload artifacts + bundles to R2 / attach to releases. - Update mkosi module configuration to run shared post-output scripts; ignore Python
__pycache__artifacts.
Reviewed changes
Copilot reviewed 4 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| shared/mkosi.postoutput.d/91-deb-sbom.py | New Python post-output script that converts mkosi manifests into a deterministic CycloneDX 1.6 SBOM. |
| modules/flashbox/flashbox-l1/mkosi.conf | Enables mkosi post-output scripts for flashbox-l1 builds. |
| .gitignore | Ignores Python __pycache__/ directories. |
| .github/workflows/flashbox-l1.yaml | Adds permissions needed to mint/verify attestations in the release job. |
| .github/workflows/_build-and-publish-image.yaml | Adds checksum generation, provenance/SBOM attestation creation, verification, and publishing of SBOM + bundles. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ExtraTrees=modules/flashbox/flashbox-l1/mkosi.extra | ||
| PostInstallationScripts=modules/flashbox/flashbox-l1/mkosi.postinst | ||
| BuildScripts=modules/flashbox/flashbox-l1/mkosi.build | ||
| PostOutputScripts=shared/mkosi.postoutput.d/* |
alexhulbert
left a comment
There was a problem hiding this comment.
Generally looks good except the python file looks a bit overengineered, the shared folder has some flashbots-specific stuff (other companies use it shared folder so we need to keep it generic), and ive run into reproducibility issues with python-based post output files in the past.
ill write up a small ~30-40 line jq script when i get back from my vacation on monday and you lmk if that's a suitable alternative to the python one you have here.
90f5c3b to
171abea
Compare
|
@alexhulbert should be better now |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.
Suppressed comments (4)
shared/mkosi.postoutput.d/91-deb-sbom.sh:46
- The glob-to-regex conversion only handles "*" and escapes "."/"+"; other glob characters like "?" or "["/" ]" will be interpreted as regex metacharacters by
test(), which can misclassify packages as local/non-local. Either document the limited supported glob syntax or escape all regex metacharacters (and optionally map "?" -> ".").
def glob_to_regex: "^" + (gsub("(?<c>[.+])"; "\\\(.c)") | gsub("\\*"; ".*")) + "$";
.github/workflows/_build-and-publish-image.yaml:175
sha256sum "${files[@]}"writes entries in the current glob/loop order, which can vary with locale/collation and affects the bytes of SHA256SUMS (and therefore the attestation). Sorting filenames withLC_ALL=Cmakes the checksums file deterministic.
sha256sum "${files[@]}" > SHA256SUMS
cat SHA256SUMS
.github/workflows/_build-and-publish-image.yaml:236
actions/attestis invoked withsubject-checksums: build/SHA256SUMS(multiple artifacts), but the verification step only verifies the provenance bundle against the.efi. This leaves the other artifacts (tar.gz/qcow2/manifest/SBOM/measurements) unverified before upload.
- name: Verify attestations
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
gh attestation verify "${EFI_FILE}" --repo "${GITHUB_REPOSITORY}" \
--bundle build/provenance.sigstore.json
gh attestation verify "${EFI_FILE}" --repo "${GITHUB_REPOSITORY}" \
--bundle build/sbom.sigstore.json \
--predicate-type https://cyclonedx.org/bom
.github/workflows/_build-and-publish-image.yaml:225
- The SBOM bundle export attempts to detect "appended" attestations by counting lines and
tail -n 1, but Sigstore bundle JSON is commonly multi-line. Tailing the last line risks producing invalid JSON and breaking verification. SinceBUNDLE_PATHcomes from the SBOM attestation step, it should already be the SBOM bundle; just copy it as-is.
set -euo pipefail
# If both attestations are appended, the SBOM is the last line
if [[ "$(wc -l < "${BUNDLE_PATH}")" -le 1 ]]; then
cp "${BUNDLE_PATH}" build/sbom.sigstore.json
else
tail -n 1 "${BUNDLE_PATH}" > build/sbom.sigstore.json
fi
jq -e . build/sbom.sigstore.json > /dev/null
|
Hey @shashial, thanks for implementing the jq based version. After looking at it, I think using a jq script is going to be more confusing and less maintainable than the original version. Also, the SBOM is still missing a lot of packages in the final image. I wrote up another SBOM PR (#192) which uses Syft to build a complete SBOM of the entire image, including components not installed from the Debian repo along with dependency trees and other metadata like maintainers and copyright. This should get us a lot further to proper SLSA compliance. Let me know if you think my solution is overkill. If so, I can strip it down a decent amount. |
This commit generates a CycloneDX 1.6 SBOM from the mkosi manifest at build time;
Then in the "publish" workflow: