bom renders Helm charts, extracts OCI image references from supported Kubernetes workload resources, writes BOM output in SPDX JSON or internal csbom / csbom-v2 formats, and can validate referenced images against upstream registries.
This repository primarily ships GitHub Actions for CI usage, plus the CLI those Actions wrap.
Choose the section that matches how you use this repository:
This repository ships three composite Actions:
- generate/action.yml generates BOM files for Helm charts
- registry-login/action.yml authenticates registry access for subsequent checks
- check/action.yml validates BOM files against upstream registries
All Actions:
- run a prebuilt binary from
dist/linux-*directly on the runner - support Linux runners only
jobs:
bom:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: codesphere-cloud/bom/generate@main
with:
include-paths: |
charts/*
exclude-paths: |
charts/legacy
changed-only: true
format: csbom-v2-jsonGenerate-specific inputs:
include-paths: newline-separated chart selectors to include. Selectors can be exact paths, path prefixes, or glob patterns. If omitted, the Action auto-discovers chart directories from the repository root.exclude-paths: newline-separated chart selectors to exclude after discovery. Selectors can be exact paths, path prefixes, or glob patterns.changed-only: only process charts whose directories contain files changed in the current push or pull requestsbom: generate CycloneDX and SPDX JSON SBOMs with Trivy for every referenced image. Files are written to the chart'ssboms/directory. Default:falsecosign: attest each generated image SBOM with keyless Cosign signing. This requiressbom: true, registry write access, andid-token: writepermission. Default:falseforce: regenerate digest-named image SBOMs and upload attestations even when they already exist. Requiressbom: true. Default:falsedebug: enable extra action logs and pass--debugthrough to the CLIformat: output format. Default:csbom-v2-jsonrelease-name: optional Helm release name overridenamespace: Helm namespace passed tohelm template. Default:defaultvalidate-configured-image-exists: fail when configured extra images do not resolve from the rendered manifestfail-on-no-matches: fail instead of succeeding when no chart paths remain after filtering
Generated files are written into each chart directory as:
bom.jsonfor JSON formatsbom.yamlfor YAML formats
When changed-only: true is set, the Action only processes charts whose directories contain files changed in the current push or pull request.
Generate outputs:
changed-pathsmatched-pathsprocessed-pathschanged-output-pathschanged-target-pathsany-processed-changed
For each selected chart, the generate Action:
- runs
helm template - scans the rendered manifest for supported Kubernetes workload resources
- extracts OCI image references from those workloads
- generates CycloneDX and SPDX JSON SBOMs under
sboms/for every image whensbomis enabled, reusing files already present for the resolved image digest unlessforceis enabled - uploads a keyless Cosign attestation for each image when
cosignis also enabled, skipping predicate types already present for the image digest unlessforceis enabled - writes the result as
bom.jsonorbom.yamlin the chart directory, depending on the selected format
Supported Kubernetes workload primitives:
PodPodTemplateReplicationControllerDeploymentReplicaSetDaemonSetStatefulSetJobCronJobListcontaining any of the above
Image reference parsing uses github.com/distribution/reference.
If a chart root contains .bomrc.yml or .bomrc.yaml, bom loads it automatically during generation.
Example:
bomGenerationValues:
image:
repository: ghcr.io/acme/api
tag: latest
additionalImages:
# Literal image references can be included even when they are not in the chart.
- key: support-tool
image: ghcr.io/acme/support-tool:2.1.0
# A literal reference can also be built from a repository and a tag and/or digest.
- key: support-tool-by-digest
image:
repository: ghcr.io/acme/support-tool
tag: 2.1.0
digest: sha256:1234567890123456789012345678901234567890123456789012345678901234
# Images can also be selected from non-workload rendered resources.
- resource:
apiVersion: v1
kind: ConfigMap
name: extra-images
key: metrics
image: .data.sidecars[] | select(.name == "metrics") | .image
# The repository/tag/digest object form also supports yq expressions
# per field when a resource is set, mixing literals and expressions freely.
- resource:
apiVersion: v1
kind: ConfigMap
name: extra-images
key: sidecar-by-tag
image:
repository: ghcr.io/acme/sidecar
tag: .data.sidecarTag
imageKeyMappings:
ghcr.io/acme/api: api
docker.io/library/busybox: busybox.bomrc.yml behavior:
bomGenerationValuesprovides default Helm values used only for BOM generation- CLI- or Action-supplied chart inputs still override those defaults
additionalImageslets a chart declare literal image references that are not present in the chart, or select references from rendered resources outside the standard workload image fieldsimagemay be a plain string (a literal OCI image reference, or, whenresourceis set, a yq expression), or an object withrepositoryandtagand/ordigest- when
resourceis omitted, the object form'srepository,tag, anddigestare used as literal values - when
resourceis present, it selects one rendered resource byapiVersion,kind, andmetadata.name; a plain stringimageis evaluated as a yq expression and must resolve to exactly one scalar image reference. In the object form, any ofrepository,tag, ordigestthat starts with.is evaluated as a yq expression against that resource too; other values are used literally - expressions are evaluated by yq itself, so the full yq expression language is available (paths,
select, string operators, arithmetic, pipes, ...) keyoptionally overrides the BOM key for that configured imageimageKeyMappingsremaps auto-discovered repository keys incsbom-jsonandcsbom-yaml
The generate Action accepts these formats:
csbom-v2-jsondefault Action formatcsbom-v2-yamlcsbom-v2csbom-jsoncsbom-yamlcsbomspdx-jsonspdx
Example csbom-v2-json output:
{
"version": "2",
"name": "chart",
"containerImages": {
"ghcr.io/acme/api": {
"ref": "ghcr.io/acme/api:1.2.3",
"digest": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
"sboms": {
"cyclonedx": {
"path": "sboms/sha256-0123456789abcdef....cdx.json",
"cosign": true
},
"spdxJson": {
"path": "sboms/sha256-0123456789abcdef....spdx.json",
"cosign": true
}
},
"sources": [
"Deployment/api spec.containers[0]"
]
}
}
}Example csbom-yaml output:
components:
chart:
containerImages:
ghcr.io/acme/api: ghcr.io/acme/api:1.2.3Example spdx-json output:
{
"spdxVersion": "SPDX-2.3",
"dataLicense": "CC0-1.0",
"SPDXID": "SPDXRef-DOCUMENT",
"name": "bom chart",
"documentNamespace": "https://codesphere-cloud.github.io/bom/spdx/...",
"creationInfo": {
"created": "2026-07-29T00:00:00Z",
"creators": [
"Tool: bom-dev"
]
},
"packages": [
{
"name": "ghcr.io/acme/api",
"SPDXID": "SPDXRef-Package-001",
"versionInfo": "1.2.3",
"downloadLocation": "NOASSERTION",
"filesAnalyzed": false,
"externalRefs": [
{
"referenceCategory": "PACKAGE-MANAGER",
"referenceType": "purl",
"referenceLocator": "pkg:oci/ghcr.io/acme/api@1.2.3"
}
]
}
]
}jobs:
validate-boms:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: codesphere-cloud/bom/registry-login@main
with:
registry-server: ghcr.io
registry-username: ${{ github.actor }}
registry-password: ${{ secrets.GITHUB_TOKEN }}
- uses: codesphere-cloud/bom/check@main
with:
include-paths: |
charts/*/bom.json
exclude-paths: |
charts/legacy/*
changed-only: trueRegistry-login inputs:
registry-server: registry host to authenticate with, such asghcr.ioregistry-username: registry usernameregistry-password: registry password or access token; the Action passes it to the CLI through standard input rather than a command-line argumentdebug: enable extra login logs
Check-specific inputs:
include-paths: newline-separated BOM selectors to include. Selectors can be exact paths, path prefixes, or glob patterns. Explicit selectors may target supported JSON or YAML BOM files. If omitted, the Action auto-discovers only files namedbom.jsonfrom the repository root.bom-paths: alias forinclude-paths;include-pathstakes precedence when both are setexclude-paths: newline-separated BOM selectors to exclude after discovery. Selectors can be exact paths, path prefixes, or glob patterns.changed-only: only validate BOM files that were changed in the current push or pull requestdebug: enable extra action logs and pass--debugthrough to the CLIbom-format: format used to parse every selected BOM. Default:csbom-v2. Supported values arespdx-json,csbom,csbom-json,csbom-yaml,csbom-v2,csbom-v2-json, andcsbom-v2-yaml. The Action does not infer the format from file contents or extensions.format: stdout check-summary format, eithertable(default) oryaml; the GitHub step summary always uses a Markdown tablefail-on-no-matches: fail instead of succeeding when no BOM paths remain after filtering
When changed-only: true is set, the Action only validates BOM files that were themselves changed in the current push or pull request.
Check outputs:
changed-bomsmatched-bomsprocessed-bomsfailed-boms
All selected BOMs are checked even when some fail. The Action exits unsuccessfully after processing every BOM and writes a step-summary table containing each BOM and its validation status or error. Its metrics include the total number of image references outside the allowed registries and the total number that could not be found upstream.
Use the CLI for local debugging, reproducing GitHub Action behavior, or developing chart/BOM logic outside CI.
go run ./cmd/bom ./chart \
--values values.yaml \
--set image.tag=1.2.3The top-level bom ./chart ... invocation is a compatibility alias for bom generate ./chart ....
Explicit subcommands:
go run ./cmd/bom generate ./chart --output bom.json
go run ./cmd/bom check bom.json --format csbom-v2
printf '%s\n' "$TOKEN" | go run ./cmd/bom registry login ghcr.io -u "$USER" --password-stdinThe CLI is built with cobra, so --help, --version, completion, and subcommand help are available.
If --release-name is omitted, both the Helm release name and the SPDX document name default to the chart name from Chart.yaml.
go run ./cmd/bom generate ./chart \
--format csbom-v2-json \
--namespace default \
--values values.yaml \
--set image.tag=1.2.3 \
--helm-arg=--include-crds \
--debugMain generate flags:
--format:spdx-json,spdx,csbom-json,csbom-yaml,csbom,csbom-v2-json,csbom-v2-yaml, orcsbom-v2--output: write to a file instead of stdout--values: pass Helm values files--set: pass Helm--setoverrides--set-string: pass Helm--set-stringoverrides--helm-arg: append raw extra arguments tohelm template--namespace: namespace passed tohelm template--release-name: Helm release name override--sbom: generate CycloneDX and SPDX JSON SBOMs with Trivy for every referenced image under the chart'ssboms/directory--cosign: attest generated image SBOMs using keyless Cosign signing; requires--sbom--force: regenerate image SBOMs and upload attestations even when they already exist; requires--sbom--validate-configured-image-exists: fail when configured extra image selectors do not resolve--debug: enable debug logging
The default CLI output format is spdx-json.
go run ./cmd/bom check bom.jsonThe check command parses the BOM only as the format selected with --format (default: csbom-v2); it does not infer the format from the file contents or extension. Supported input BOM formats:
spdx-jsoncsbom-jsoncsbom-yamlcsbomcsbom-v2-jsoncsbom-v2-yamlcsbom-v2
For each container image and Helm chart OCI reference found in the BOM, check validates that the upstream registry serves a manifest for that reference.
Add a .bomlint.yml file at the repository root to share checker settings between local CLI runs and the check Action:
excludePaths:
- charts/legacy
- charts/experimental/*/bom.yaml
allowedRegistries:
- docker.io
- ghcr.io/codesphere-cloud
- registry.example.com:5000excludePathsuses the same exact-path, directory-prefix, and glob matching as the check Action'sexclude-pathsinput. Configured and Action-supplied exclusions are combined.allowedRegistriesaccepts registry hosts with optional ports and repository path prefixes. A host-only entry allows every repository on that registry; for example,ghcr.io/codesphere-cloudallows that repository path and all paths below it, but notghcr.io/another-org. Do not include a URL scheme. Unqualified image references such asbusybox:latestresolve todocker.io.- If
allowedRegistriesis omitted or empty, registry allowlist enforcement is disabled for backward compatibility.
The CLI searches for .bomlint.yml from the BOM file's directory upward. Registry restrictions apply to every container image and Helm chart OCI reference in supported BOMs. The checker validates the existence of both kinds of reference in their upstream registries.
If a registry requires authentication first:
printf '%s\n' "$TOKEN" | go run ./cmd/bom registry login ghcr.io -u "$USER" --password-stdin
go run ./cmd/bom check bom.jsonCredentials are stored in the Docker config used by crane and the Docker CLI, honoring DOCKER_CONFIG when it is set.
Use the Makefile targets for standard development tasks:
make help
make check-tools
make build
make build-action
make test
make test-e2e
make fmt
make fmt-check
make lint
make distmake check-tools verifies that helm is installed before build and test workflows that need it.
- cmd/bom: CLI entrypoint
- cmd/bom-action: GitHub Action wrapper entrypoint
- internal/cli: Cobra command and flag wiring
- internal/check, internal/generate, and internal/login: reusable business workflows shared by the CLI and Actions
- internal/helm: Helm templating
- internal/images: image extraction, configured images, validation
- internal/sbom: SPDX and
csbom/csbom-v2formatting and parsing - internal/ghaction: shared action filtering, path resolution, and output handling
- generate/action.yml and check/action.yml: composite Action entrypoints
- scripts/build-dist.sh: dist artifact builder
The composite Actions execute the prebuilt bom-action binaries from dist/, so action changes usually need updated dist artifacts:
make build-action
make distThe current dist matrix in this repository is:
dist/linux-amd64/bomdist/linux-amd64/bom-actiondist/linux-arm64/bomdist/linux-arm64/bom-action
Available output formats:
spdx-jsondefault CLI formatcsbom-v2-jsondefault generate Action formatcsbom-jsoncsbom-yamlcsbomcsbom-v2-yamlcsbom-v2spdx
SPDX generation uses github.com/spdx/tools-golang. Registry validation uses github.com/google/go-containerregistry/pkg/crane. The internal BOM formats are defined in internal/csbom/bom.go and internal/csbom/v2/bom.go.