Skip to content

Commit 8c05ff6

Browse files
wrkodeclaude
andcommitted
fix(ci): emit CycloneDX SBOM so attestation fits the 16 MiB cap
The v0.2.1 release failed at "Attest image SBOM": Error: SBOM file exceeds maximum allowed size: 16777216 bytes A full Kairos OS-image SBOM in SPDX-json is ~23.4 MiB, over the actions/attest-sbom 16 MiB predicate cap. The same SBOM in CycloneDX-json is ~2.8 MiB (measured with syft on kairos-kubeadm:v1.34.0). Switch both the image and binary SBOMs to cyclonedx-json (one consistent, compact format). Also drop the predicate-typed SBOM self-verify: the Attest-*-SBOM step failing (as it just did) is the real guard, and a predicate-type filter couples R-4 to the SBOM spec version. R-4 keeps the load-bearing provenance verify. This is the zero-coupling option the security review flagged. Docs updated: SBOMs are CycloneDX; verify with --predicate-type https://cyclonedx.org/bom. actionlint clean. Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: William Rizzo <william.rizzo@gmail.com>
1 parent 92cbb28 commit 8c05ff6

3 files changed

Lines changed: 32 additions & 29 deletions

File tree

.github/workflows/release.yml

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ name: Release
88
# ghcr.io/<owner>/provider-kubernetes:<tag>-k8s<minor> (e.g. v0.1.0-k8s1.34).
99
# The newest supported minor is additionally tagged <tag> and latest.
1010
# - a GitHub Release with the provider binary + sha256 checksum.
11-
# - SLSA build-provenance + SPDX SBOM attestations for every image (by digest)
11+
# - SLSA build-provenance + CycloneDX SBOM attestations for every image (by digest)
1212
# and for the binary, signed keyless via the workflow's OIDC identity (ADR-15).
1313
# Verify with `gh attestation verify` -- see the GitHub Release notes / README.
1414
#
@@ -144,12 +144,15 @@ jobs:
144144
done
145145
fi
146146
147-
- name: Generate image SBOM (SPDX)
147+
# CycloneDX, not SPDX: a full OS-image SPDX SBOM is ~23 MiB and exceeds the
148+
# actions/attest-sbom 16 MiB predicate cap; the equivalent CycloneDX SBOM is
149+
# ~3 MiB. CycloneDX is the compact format for image-scale SBOMs.
150+
- name: Generate image SBOM (CycloneDX)
148151
uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
149152
with:
150153
image: ${{ steps.build.outputs.image }}@${{ steps.build.outputs.digest }}
151-
format: spdx-json
152-
output-file: image.spdx.json
154+
format: cyclonedx-json
155+
output-file: image.cdx.json
153156
upload-artifact: false
154157
upload-release-assets: false # we attest the SBOM; do not auto-attach it to the Release
155158

@@ -165,24 +168,23 @@ jobs:
165168
with:
166169
subject-name: ${{ steps.build.outputs.image }}
167170
subject-digest: ${{ steps.build.outputs.digest }}
168-
sbom-path: image.spdx.json
171+
sbom-path: image.cdx.json
169172
push-to-registry: true
170173

171-
# R-4: prove the attestations are real before a tester relies on them. A
172-
# broken signing step fails the release here, not in the field.
173-
- name: Self-verify image attestations
174+
# R-4: prove the attestation is real before a tester relies on it. A broken
175+
# signing step fails the release here, not in the field. We verify provenance
176+
# (the load-bearing integrity check); the SBOM attestation's existence is
177+
# already guaranteed by the Attest-image-SBOM step above failing otherwise, so
178+
# we do not add a predicate-type filter here (avoids coupling to the SBOM
179+
# format/spec version).
180+
- name: Self-verify image attestation
174181
env:
175182
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
176183
run: |
177184
set -euo pipefail
178185
ref="${{ steps.build.outputs.image }}@${{ steps.build.outputs.digest }}"
179186
echo "verifying provenance for oci://${ref}"
180187
gh attestation verify "oci://${ref}" --repo "${{ github.repository }}"
181-
echo "verifying SBOM attestation for oci://${ref}"
182-
# The SPDX predicate-type suffix tracks the SBOM's spdxVersion (syft emits
183-
# SPDX-2.3 -> /v2.3). Bump this if the SBOM SPDX version changes.
184-
gh attestation verify "oci://${ref}" --repo "${{ github.repository }}" \
185-
--predicate-type https://spdx.dev/Document/v2.3
186188
187189
# Build the provider binary and publish a GitHub Release with a checksum.
188190
binary:
@@ -214,12 +216,14 @@ jobs:
214216
sha256sum agent-provider-kubernetes_*.tar.gz > checksums.txt
215217
cat checksums.txt
216218
217-
- name: Generate binary SBOM (SPDX)
219+
# CycloneDX for consistency with the image SBOM (one SBOM format across all
220+
# published artifacts; well under the attest-sbom 16 MiB cap).
221+
- name: Generate binary SBOM (CycloneDX)
218222
uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
219223
with:
220224
file: bin/agent-provider-kubernetes
221-
format: spdx-json
222-
output-file: binary.spdx.json
225+
format: cyclonedx-json
226+
output-file: binary.cdx.json
223227
upload-artifact: false
224228
upload-release-assets: false # we attest the SBOM; do not auto-attach it to the Release
225229

@@ -232,9 +236,10 @@ jobs:
232236
uses: actions/attest-sbom@c604332985a26aa8cf1bdc465b92731239ec6b9e # v4.1.0
233237
with:
234238
subject-path: bin/agent-provider-kubernetes_*.tar.gz
235-
sbom-path: binary.spdx.json
239+
sbom-path: binary.cdx.json
236240

237-
# R-4: verify the binary attestation before publishing the Release.
241+
# R-4: verify provenance before publishing the Release (the SBOM attestation's
242+
# existence is guaranteed by the Attest-binary-SBOM step failing otherwise).
238243
- name: Self-verify binary attestation
239244
env:
240245
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -243,10 +248,6 @@ jobs:
243248
tarball="$(ls bin/agent-provider-kubernetes_*.tar.gz)"
244249
echo "verifying provenance for ${tarball}"
245250
gh attestation verify "${tarball}" --repo "${{ github.repository }}"
246-
echo "verifying SBOM attestation for ${tarball}"
247-
# SPDX predicate-type suffix tracks the SBOM spdxVersion (SPDX-2.3 -> /v2.3).
248-
gh attestation verify "${tarball}" --repo "${{ github.repository }}" \
249-
--predicate-type https://spdx.dev/Document/v2.3
250251
251252
- name: Create GitHub Release
252253
env:
@@ -264,7 +265,7 @@ jobs:
264265
for m in $(echo "${MINORS}" | jq -r '.[]'); do
265266
imglist="${imglist}${repo}:${TAG}-k8s${m}"$'\n'
266267
done
267-
verify="$(printf 'Verifying (every image + the binary carry keyless SLSA provenance + SPDX SBOM attestations):\n```\n# image (resolve the digest first, then verify by digest)\ngh attestation verify oci://%s:%s --repo %s\n# binary\ngh attestation verify agent-provider-kubernetes_%s_linux_amd64.tar.gz --repo %s\n```\n' \
268+
verify="$(printf 'Verifying (every image + the binary carry keyless SLSA provenance + CycloneDX SBOM attestations):\n```\n# image (resolve the digest first, then verify by digest)\ngh attestation verify oci://%s:%s --repo %s\n# binary\ngh attestation verify agent-provider-kubernetes_%s_linux_amd64.tar.gz --repo %s\n```\n' \
268269
"${repo}" "${TAG}" "${REPO_SLUG}" "${TAG}" "${REPO_SLUG}")"
269270
notes="$(printf 'Kairos images (one per supported Kubernetes minor):\n```\n%s```\nThe newest supported minor (%s) is also published as `%s:%s` and `%s:latest`.\n\n%s\nProvider binary (linux/amd64) attached below. This is a development release; not yet field-ready.\n' \
270271
"${imglist}" "${LATEST_MINOR}" "${repo}" "${TAG}" "${repo}" "${verify}")"

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ checksum. **These are development releases and are not field-ready.**
149149
### Verifying a release
150150

151151
Every published image and the release binary carry **keyless SLSA build-provenance
152-
and SPDX SBOM attestations**, signed via the release workflow's OIDC identity (no
152+
and CycloneDX SBOM attestations**, signed via the release workflow's OIDC identity (no
153153
private key). Verify them with the GitHub CLI -- no extra tooling:
154154

155155
```sh
@@ -168,8 +168,9 @@ gh attestation verify \
168168
```
169169

170170
A successful verification confirms the artifact was built by this repository's
171-
`Release` workflow from a tagged commit. Add `--predicate-type
172-
https://spdx.dev/Document/v2.3` to verify the SBOM attestation specifically. See
171+
`Release` workflow from a tagged commit. That command checks the provenance; add
172+
`--predicate-type https://cyclonedx.org/bom` to verify the CycloneDX SBOM
173+
attestation specifically. See
173174
[`docs/testing.md`](./docs/testing.md) for the full supply-chain picture.
174175

175176
Maintainers cut a release by pushing a signed semver tag; the `Release` workflow

docs/testing.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ is the one CI built. The two halves of the supply chain:
177177
HTTPS-served `.sha256`.
178178
- **Publish-time (outputs):** the `Release` workflow attaches, to every published
179179
image (by digest) and to the release binary, a **keyless SLSA build-provenance
180-
attestation** and an **SPDX SBOM attestation**, signed via the workflow's OIDC
180+
attestation** and a **CycloneDX SBOM attestation**, signed via the workflow's OIDC
181181
identity (no private key, ADR-15). The release job self-verifies its own
182182
attestations before publishing, so a broken signing step fails the release rather
183183
than reaching a tester.
@@ -193,8 +193,9 @@ gh attestation verify agent-provider-kubernetes_<tag>_linux_amd64.tar.gz \
193193
--repo kairos-io/provider-kubernetes
194194
```
195195

196-
Add `--predicate-type https://spdx.dev/Document/v2.3` to check the SBOM
197-
attestation specifically (the version suffix tracks the SBOM's SPDX version). See the [README](../README.md#verifying-a-release) for the
196+
The command above checks the build-provenance attestation. The SBOM is attested
197+
separately as CycloneDX; to verify it specifically add
198+
`--predicate-type https://cyclonedx.org/bom`. See the [README](../README.md#verifying-a-release) for the
198199
digest-resolution one-liner.
199200

200201
## See also

0 commit comments

Comments
 (0)