Skip to content

feat(actions): add attest-chart and setup-cyclonedx - #40

Draft
tuxerrante wants to merge 5 commits into
mainfrom
feat/attest-chart-action
Draft

tuxerrante wants to merge 5 commits into
mainfrom
feat/attest-chart-action

Conversation

@tuxerrante

Copy link
Copy Markdown
Member

Tip

TL;DR — Adds attest-chart (merge a chart's image SBOMs into one CycloneDX 1.7 chart SBOM, attest it on the pushed chart digest) and setup-cyclonedx (the pinned cyclonedx-cli for callers that merge themselves).
Replaces the hand-pinned cyclonedx-cli installs in charts and tooling-pod-chart with one Renovate-managed pin, and gives the other chart-publishing repos a one-step way to ship attested chart SBOMs.

Important

Suggested merge order: #37 first, then this PR, then tag v0.2.0. Consumers then move to that tag in their own PRs.

Why

Only charts and a copy in tooling-pod-chart produce a chart-level SBOM. Both hard-code CYCLONEDX_VERSION and its SHA-256, and Renovate updates neither. Several charts that ship in the release get no chart SBOM at all: codesphere, mounter, ms-backend-postgres, ms-backend-opensearch, ms-backend-s3 and error-page-server. Their repos call generate, but generate only writes per-image SBOMs. It cannot attest the chart, because the chart's digest exists only after helm push.

Milestone: BOM and SBOM lifecycle refactor.

What changes

  • setup-cyclonedx/install.sh is now the only place the cyclonedx-cli version and its x64/arm64 checksums are pinned. It installs into $RUNNER_TEMP, with no sudo. Renovate bumps the version, and scripts/pin-cyclonedx.sh rewrites the checksums in the same commit (postUpgradeTasks).
  • setup-cyclonedx puts cyclonedx on PATH and exports CYCLONEDX_SPEC_VERSION. The default is v1_7, previously hard-coded as v1_6 in charts.
  • attest-chart does a hierarchical merge of <chart>/sboms/sha256-*.cdx.json. It then runs cosign attest --type cyclonedx on chart-ref@sha256:… from an empty per-step docker config, and verify-attestation. sbom-path attests an already merged SBOM, for jobs that split merge and attest. A chart without image SBOMs gets nothing, and the step still succeeds.
  • .yamllint.yaml: permissive layout rules for workflow and action files. It is a separate commit.

Evidence

  • The fixture merge in a Linux container produces a document with specVersion 1.7, subject codesphere/smoke@1.2.3 and nested image components. cyclonedx validate --input-version v1_7 --fail-on-errors passes on it.
  • A second call to install.sh reuses the already verified binary.
  • pin-cyclonedx.sh reproduces both checksums. They match GitHub's asset digests for v0.33.1.
  • actionlint and shellcheck pass on the workflow, both scripts and the action run: blocks. make test passes.
  • CI: action-smoke runs the merge-only path on PRs. attestation-smoke only runs on push to main. It now pushes the test chart, attests it, and checks the attested payload is 1.7 with the chart as subject.
  • Not verified: the attest path against GHCR (it runs only after merge), and a Renovate dry run of the new regex manager.

The default rules reject what GitHub workflow and action files need: long
run: lines, the on: key and SHA-pin comments one space after the value.
Keep the syntax rules and relax the layout ones.

Signed-off-by: Alessandro Affinito <alessandro.affinito@codesphere.com>
attest-chart merges a chart's per-image CycloneDX SBOMs, written by
generate with sbom: true, into one hierarchical chart SBOM and attests it
on the pushed chart's digest with keyless Cosign, then verifies it.

setup-cyclonedx installs the same pinned cyclonedx-cli for callers that
merge in their own scripts and exports CYCLONEDX_SPEC_VERSION.

The cyclonedx-cli version and per-arch checksums live only in
setup-cyclonedx/install.sh. Renovate bumps the version and
scripts/pin-cyclonedx.sh rewrites the checksums in the same commit. The
merged SBOM's spec version is an input, defaulting to CycloneDX 1.7.

Signed-off-by: Alessandro Affinito <alessandro.affinito@codesphere.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The action can attest stale image SBOMs, lose authentication for private non-GHCR registries, and accept certificate identities from unintended repositories because its default identity regex leaves repository names unescaped.

3 open issues
What changed in this PR

Adds reusable actions for producing and attesting chart-level SBOMs after Helm charts are pushed, with a shared, checksum-pinned CycloneDX CLI installer.

Changes:

  • Adds attest-chart for hierarchical SBOM merging and keyless attestation, plus setup-cyclonedx for callers that merge separately.
  • Centralizes CLI version and checksum maintenance through Renovate and a checksum-update script.
  • Documents both actions and extends CI with merge and chart-attestation smoke checks.
File Description
testdata/​attest-chart/​sboms/​sha256-bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cdx.json Adds the second image SBOM fixture for hierarchical merge checks.
testdata/​attest-chart/​sboms/​sha256-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.cdx.json Adds the first image SBOM fixture for hierarchical merge checks.
setup-cyclonedx/​install.sh Installs and reuses checksum-verified Linux CLI binaries.
setup-cyclonedx/​action.yml Exposes the CLI on PATH and exports the spec version.
scripts/​pin-cyclonedx.sh Refreshes checksums for the pinned CLI release.
renovate.json Configures CLI version updates and checksum regeneration.
README.md Documents action inputs and chart-attestation usage.
attest-chart/​action.yml Merges image SBOMs and attests and verifies the pushed chart.
.yamllint.yaml Relaxes YAML layout rules for workflow and action files.
.github/​workflows/​ci.yml Adds setup, merge, empty-input, and chart-attestation smoke checks.

Review effort: Balanced

Comment thread attest-chart/action.yml Resolved
Comment thread attest-chart/action.yml Resolved
Comment thread attest-chart/action.yml Resolved
Cosign gets registry credentials only through its GitHub keychain inside an
empty Docker config, so a chart on another registry could never be attested.
Reject such a chart-ref up front and document the action as GHCR-only.

Signed-off-by: Alessandro Affinito <alessandro.affinito@codesphere.com>
The default certificate identity interpolated the repository name into a
regex, so a '.' in it matched any character and accepted another
repository's workflows. Escape it, and the host.

Signed-off-by: Alessandro Affinito <alessandro.affinito@codesphere.com>
generate keeps SBOMs of image digests a chart no longer uses, so globbing
sboms/ merged and attested stale images into the chart SBOM. Read the paths
from the chart's bom.json, require them under sboms/, and fail when one is
missing. The fixture gains a bom.json and an unreferenced SBOM that CI
asserts is left out.

Signed-off-by: Alessandro Affinito <alessandro.affinito@codesphere.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The main-only GHCR signing and attestation retrieval path lacks end-to-end runtime evidence, and Renovate’s checksum hook lacks dry-run validation in the repository’s CI/bot environment.

No open issues 🎉

3 resolved since last review

Review effort: Balanced

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants