Skip to main content

BOMpage

BOMpage

Software License semantic-release: angular Pipeline Status

Live demo BOMpage tracking its own dependencies

Track what your software is made of, across every project, over time.

Your CI already generates an SBOM — the list of every library your application depends on. But each one is a snapshot in a single pipeline: nobody can see them side by side, and nobody keeps yesterday's.

BOMpage collects those SBOMs into one Git repository and turns them into a dashboard you can publish on GitLab or GitHub Pages. It needs no server, no database and no account: the result is a folder of static files.

You can then answer, in a few clicks:

  • Which version of openssl does each of our services ship?
  • What changed in this application's dependencies since last month?
  • Are we still pulling a strong-copyleft licence anywhere?
  • Which project has stopped reporting? (its pipeline is probably broken)

How it fits together

Three pieces, set up in this order:

  your projects                central repo                  published site
 ┌──────────────┐        ┌───────────────────────┐        ┌─────────────────┐
 │ app-api   CI │──push─▶│ reports/app-api/      │        │                 │
 │ web-front CI │──push─▶│ reports/web-front/    │─build─▶│  a static page  │
 │ batch-etl CI │──push─▶│ reports/batch-etl/    │        │  (Pages)        │
 └──────────────┘        └───────────────────────┘        └─────────────────┘
   bompage push            one folder per project            bompage build
   (from each pipeline)    one file per day                  (from that repo's CI)
  1. Each project pushes its SBOM into the central repository at the end of its pipeline. A snapshot is only committed when the content actually changed, so the history stays readable.
  2. The central repository is just folders and JSON files. One directory per project, discovered automatically — nothing to declare, nothing to configure when a new project appears.
  3. Its own pipeline rebuilds the dashboard and publishes it.

Both SPDX and CycloneDX are accepted, so whatever your scanner emits (Trivy, Syft, the CycloneDX Maven plugin…) will work.

Install

Python 3.12 or later:

python3 -m pip install bompage
bompage --help

The published package already contains the dashboard, so you need nothing from the JavaScript world to use BOMpage.

Try it in two minutes

If you already have an SBOM file, put it in a folder named after your project and build:

mkdir -p reports/my-service
cp sbom.json reports/my-service/sbom-20260914.json   # sbom-YYYYMMDD.json

bompage build --reports reports --output public
python3 -m http.server -d public      # then open http://localhost:8000

A local file server is required: the page loads its data with fetch, which browsers refuse over file://.

The file name carries the date — sbom-YYYYMMDD.json, optionally sbom-YYYYMMDD-1.4.2.json to record a version. That is the whole convention; files that do not follow it are skipped with a warning rather than breaking the build.

The six commands

Every command accepts --help, and the full option reference is generated from the code, so it is always current.

bompage build — make the site

Runs in the central repository's pipeline. No network access needed.

bompage build --reports reports --output public \
  --stale-after 2 \
  --recent-days 30 \
  --metadata "team=platform"
  • --stale-after 2 — flag a project that has not reported for 2+ days.
  • --recent-days 30 — window covered by the "recent changes" panel.
  • --metadata "key=value" — free rows shown in the dashboard header; repeat it, or use --metadata-component "app-api:owner=backend" for one project.

Careful: --output is emptied on every build. BOMpage refuses to write into a folder it did not create itself; add --force only if you are sure.

bompage push — send one SBOM

Runs in each project's pipeline. Needs the git command and a write token.

export BOMPAGE_TOKEN=…

bompage push \
  --component app-api \
  --sbom build/sbom.cdx.json \
  --repo https://gitlab.com/acme/bompage.git
  • --component app-api — becomes reports/app-api/ in the central repo.
  • BOMPAGE_TOKEN — pass the token through the environment, not with --token: anything on a command line is readable by other processes on the same runner, and BOMpage warns you when you do.

Optionally, set BOMPAGE_SIGN_KEY to a private SSH key and push also writes a signed attestation sidecar (.att / .att.sig) beside the SBOM, which build then verifies (see bompage verify below). Leave it unset and nothing changes — signing is entirely opt-in.

On GitLab you usually do not call it by hand — include the ready-made bompage-push job instead (signing, if BOMPAGE_SIGN_KEY is set in the project, is picked up automatically — see deploy/README.md):

stages:
  - sbom-release # bompage_push_stage default; declare it or override the input

include:
  - component: gitlab.com/op_so/components/pages/bompage-push@v1.1.1
    inputs:
      bompage_push_repo: https://gitlab.com/acme/bompage.git
      bompage_push_component: app-api
      bompage_push_sbom: build/sbom.cdx.json

bompage prune — keep the repository small

Deletes snapshots older than --keep-days in a single ordinary commit — no history rewriting. The most recent snapshot of each project is always kept, so a project that went quiet stays visible on the dashboard.

export BOMPAGE_TOKEN=…

bompage prune \
  --repo https://gitlab.com/acme/bompage.git \
  --keep-days 90 \
  --dry-run

--dry-run lists what would go without changing anything; drop it to actually commit. Best run as a scheduled job in the central repository.

bompage scan — refresh known vulnerabilities

Scans each component's latest SBOM snapshot with Trivy and writes/updates reports/<component>/vulnerabilities.json, committing only when the findings actually changed. bompage build then shows them on the dashboard.

export BOMPAGE_TOKEN=…

bompage scan \
  --repo https://gitlab.com/acme/bompage.git \
  --dry-run

--dry-run lists which components would change without committing; drop it to actually commit. Best run as a scheduled job in the central repository, alongside bompage prune (see deploy/README.md).

Notes:

  • Findings are matched to packages by purl, tolerating differences Trivy may introduce (qualifiers, percent-encoding), then by name@version. A finding that still matches no package of the latest snapshot is dropped with a warning in the build log.
  • A component's Vulnerabilities last changed row shows when its findings last changed, not when the last scan ran: an unchanged result is never re-committed. The row only appears once at least one component has been scanned, and its name is reserved (a --metadata-component or pushed metadata.json key with that name is rejected).

bompage verify — check a download

Run by anyone who downloaded an SBOM, not by a pipeline. Needs no repository access, only the file, its .att / .att.sig sidecars, and the trust root. Today those sidecars live only in the central repo's reports/<component>/ tree — the published site does not yet serve them (a planned dashboard change, see the spec):

bompage verify reports/app-api/sbom-20260914.json --allowed-signers ./allowed_signers

It is a convenience only: the same check can always be done with stock ssh-keygen, jq and sha256sum alone, which is documented in docs/verify.md for anyone who does not want to trust bompage itself for that. This only matters for a deployment that signs its pushes (see BOMPAGE_SIGN_KEY above) — an unsigned one has nothing here to verify.

bompage check — gate a pipeline

Run by a CI job in the central repository, before pages. Verifies every attestation under reports/ and exits 1 on a forged signature (bad) or a broken chain (broken); missing, gap, unknown and slow are only reported. --fail-on overrides that set, and --min-checked N fails instead of silently passing an empty or misconfigured reports/. See docs/check.md.

bompage check --reports reports --allowed-signers trust/allowed_signers

Set up a central repository

The deploy/ folder is a ready-to-copy skeleton: the layout, the Pages job and the scheduled prune job. See deploy/README.md for the steps.

What the dashboard shows

A live one is published at op_so.gitlab.io/pages/sbom-bompage: BOMpage runs the whole flow on itself, so that page is built by the released version from an SBOM its own pipeline pushed.

Per project: the current inventory (name, version, ecosystem, licence), with strong-copyleft dependencies flagged; the version history of any package; what was added and removed recently; a comparison between any two snapshots; and a warning when a project has stopped reporting.

Across projects: a search for any package name, and the list of dependencies sitting at diverging versions in several projects of the same ecosystem.

Not built yet: the versioned api/v1/ REST surface, for tools that would read this data rather than look at it.

Contributing

Bug reports and merge requests are welcome. The development setup, the test suite and the quality gates are documented in CONTRIBUTING.md.

Authors

License

This program is free software: you can redistribute it and/or modify it under the terms of the MIT License (MIT). See the LICENSE for details.

Release files for bompage 2.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bompage 2.0.1
File Size Uploaded
bompage-2.0.1.tar.gz 1.1 MB Details

Built distribution (wheel)

Table of built distributions (wheels) for bompage 2.0.1
File Interpreter ABI Platform
bompage-2.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 1.7 MB

Release files / bompage-2.0.1.tar.gz

Download URL bompage-2.0.1.tar.gz
Size 1.1 MB
Tags Source
SHA-256 checksum
How to use checksums
badfaa7fb4974c99573a90541e15541bd332d5e5a7357b8494217ed1247452a3
BLAKE2b-256 checksum
How to use checksums
9dfb0f7099e5c4eb04def653357d55344ca33f19f099a26e75bc708c60f86f89
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.18 {"installer":{"name":"uv","version":"0.12.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / bompage-2.0.1-py3-none-any.whl

Download URL bompage-2.0.1-py3-none-any.whl
Size 630.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
02be1ba7fce70a18a08dd42b75b9a2a180753f0ce7bdcae43fb3c70d8a68c30a
BLAKE2b-256 checksum
How to use checksums
b9193119fb5efe32d9842be992a7de26fddfa32cfa65c686d64b954b15aad74b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.18 {"installer":{"name":"uv","version":"0.12.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"13","id":"trixie","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release history Release notifications | RSS feed

This release

2.0.1 This release

2 release files

2.0.0

2 release files

1.5.1

2 release files

1.4.0

2 release files

1.3.1

2 release files

1.3.0

2 release files

1.2.2

2 release files

1.2.1

2 release files

1.2.0

2 release files

1.1.2

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page