Skip to content

Repository files navigation

bom

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.

Start Here

Choose the section that matches how you use this repository:

  1. Users of the GitHub Action
  2. Users of the CLI
  3. Developers

Users Of The GitHub Action

This repository ships three composite Actions:

All Actions:

  • run a prebuilt binary from dist/linux-* directly on the runner
  • support Linux runners only

Generate BOMs In CI

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-json

Generate-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 request
  • sbom: generate CycloneDX and SPDX JSON SBOMs with Trivy for every referenced image. Files are written to the chart's sboms/ directory. Default: false
  • cosign: attest each generated image SBOM with keyless Cosign signing. This requires sbom: true, registry write access, and id-token: write permission. Default: false
  • force: regenerate digest-named image SBOMs and upload attestations even when they already exist. Requires sbom: true. Default: false
  • debug: enable extra action logs and pass --debug through to the CLI
  • format: output format. Default: csbom-v2-json
  • release-name: optional Helm release name override
  • namespace: Helm namespace passed to helm template. Default: default
  • validate-configured-image-exists: fail when configured extra images do not resolve from the rendered manifest
  • fail-on-no-matches: fail instead of succeeding when no chart paths remain after filtering

Generated files are written into each chart directory as:

  • bom.json for JSON formats
  • bom.yaml for 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-paths
  • matched-paths
  • processed-paths
  • changed-output-paths
  • changed-target-paths
  • any-processed-changed

How Generation Works

For each selected chart, the generate Action:

  1. runs helm template
  2. scans the rendered manifest for supported Kubernetes workload resources
  3. extracts OCI image references from those workloads
  4. generates CycloneDX and SPDX JSON SBOMs under sboms/ for every image when sbom is enabled, reusing files already present for the resolved image digest unless force is enabled
  5. uploads a keyless Cosign attestation for each image when cosign is also enabled, skipping predicate types already present for the image digest unless force is enabled
  6. writes the result as bom.json or bom.yaml in the chart directory, depending on the selected format

Supported Kubernetes workload primitives:

  • Pod
  • PodTemplate
  • ReplicationController
  • Deployment
  • ReplicaSet
  • DaemonSet
  • StatefulSet
  • Job
  • CronJob
  • List containing 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:

  • bomGenerationValues provides default Helm values used only for BOM generation
  • CLI- or Action-supplied chart inputs still override those defaults
  • additionalImages lets a chart declare literal image references that are not present in the chart, or select references from rendered resources outside the standard workload image fields
  • image may be a plain string (a literal OCI image reference, or, when resource is set, a yq expression), or an object with repository and tag and/or digest
  • when resource is omitted, the object form's repository, tag, and digest are used as literal values
  • when resource is present, it selects one rendered resource by apiVersion, kind, and metadata.name; a plain string image is evaluated as a yq expression and must resolve to exactly one scalar image reference. In the object form, any of repository, tag, or digest that 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, ...)
  • key optionally overrides the BOM key for that configured image
  • imageKeyMappings remaps auto-discovered repository keys in csbom-json and csbom-yaml

Output Formats

The generate Action accepts these formats:

  • csbom-v2-json default Action format
  • csbom-v2-yaml
  • csbom-v2
  • csbom-json
  • csbom-yaml
  • csbom
  • spdx-json
  • spdx

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.3

Example 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"
        }
      ]
    }
  ]
}

Check BOMs In CI

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: true

Registry-login inputs:

  • registry-server: registry host to authenticate with, such as ghcr.io
  • registry-username: registry username
  • registry-password: registry password or access token; the Action passes it to the CLI through standard input rather than a command-line argument
  • debug: 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 named bom.json from the repository root.
  • bom-paths: alias for include-paths; include-paths takes precedence when both are set
  • exclude-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 request
  • debug: enable extra action logs and pass --debug through to the CLI
  • bom-format: format used to parse every selected BOM. Default: csbom-v2. Supported values are spdx-json, csbom, csbom-json, csbom-yaml, csbom-v2, csbom-v2-json, and csbom-v2-yaml. The Action does not infer the format from file contents or extensions.
  • format: stdout check-summary format, either table (default) or yaml; the GitHub step summary always uses a Markdown table
  • fail-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-boms
  • matched-boms
  • processed-boms
  • failed-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.

Users Of The CLI

Use the CLI for local debugging, reproducing GitHub Action behavior, or developing chart/BOM logic outside CI.

Run The CLI

go run ./cmd/bom ./chart \
  --values values.yaml \
  --set image.tag=1.2.3

The 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-stdin

The 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.

Useful Flags For Local Debugging

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 \
  --debug

Main generate flags:

  • --format: spdx-json, spdx, csbom-json, csbom-yaml, csbom, csbom-v2-json, csbom-v2-yaml, or csbom-v2
  • --output: write to a file instead of stdout
  • --values: pass Helm values files
  • --set: pass Helm --set overrides
  • --set-string: pass Helm --set-string overrides
  • --helm-arg: append raw extra arguments to helm template
  • --namespace: namespace passed to helm template
  • --release-name: Helm release name override
  • --sbom: generate CycloneDX and SPDX JSON SBOMs with Trivy for every referenced image under the chart's sboms/ 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.

Validate A BOM Locally

go run ./cmd/bom check bom.json

The 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-json
  • csbom-json
  • csbom-yaml
  • csbom
  • csbom-v2-json
  • csbom-v2-yaml
  • csbom-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.

Configure BOM Checks

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:5000
  • excludePaths uses the same exact-path, directory-prefix, and glob matching as the check Action's exclude-paths input. Configured and Action-supplied exclusions are combined.
  • allowedRegistries accepts registry hosts with optional ports and repository path prefixes. A host-only entry allows every repository on that registry; for example, ghcr.io/codesphere-cloud allows that repository path and all paths below it, but not ghcr.io/another-org. Do not include a URL scheme. Unqualified image references such as busybox:latest resolve to docker.io.
  • If allowedRegistries is 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.json

Credentials are stored in the Docker config used by crane and the Docker CLI, honoring DOCKER_CONFIG when it is set.

Developers

Common Workflows

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 dist

make check-tools verifies that helm is installed before build and test workflows that need it.

Repository Layout

Action Development

The composite Actions execute the prebuilt bom-action binaries from dist/, so action changes usually need updated dist artifacts:

make build-action
make dist

The current dist matrix in this repository is:

  • dist/linux-amd64/bom
  • dist/linux-amd64/bom-action
  • dist/linux-arm64/bom
  • dist/linux-arm64/bom-action

Output Formats

Available output formats:

  • spdx-json default CLI format
  • csbom-v2-json default generate Action format
  • csbom-json
  • csbom-yaml
  • csbom
  • csbom-v2-yaml
  • csbom-v2
  • spdx

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.

About

Parses helm charts and extracts images for a bom

Resources

Code of conduct

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages