Metadata-Version: 2.5
Name: bompage
Version: 1.1.0
Summary: A generic, server-less system to track SBOM history of N components and publish a static dashboard
Project-URL: Homepage, https://gitlab.com/op_so/pages/bompage
Project-URL: Documentation, https://op_so.gitlab.io/pages/bompage/
Project-URL: Repository, https://gitlab.com/op_so/pages/bompage.git
Project-URL: Issues, https://gitlab.com/op_so/pages/bompage/-/issues
Project-URL: Changelog, https://gitlab.com/op_so/pages/bompage/-/releases
Author-email: FX Soubirou <soubirou@yahoo.fr>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: pydantic>=2.13.5
Requires-Dist: typer>=0.27.2
Description-Content-Type: text/markdown

# `BOMpage`

![BOMpage](https://gitlab.com/op_so/pages/bompage/-/raw/main/web-src/bompage.png)

[![Software License](https://img.shields.io/badge/license-MIT-informational.svg?style=for-the-badge)](https://gitlab.com/op_so/pages/bompage/-/blob/main/LICENSE)
[![semantic-release: angular](https://img.shields.io/badge/semantic--release-angular-e10079?logo=semantic-release&style=for-the-badge)](https://github.com/semantic-release/semantic-release)
[![Pipeline Status](https://img.shields.io/gitlab/pipeline-status/op_so%2Fpages%2Fbompage?style=for-the-badge)](https://gitlab.com/op_so/pages/bompage/pipelines)

[![Live demo](https://img.shields.io/badge/live_demo-open_the_dashboard-6750A4?style=for-the-badge&logo=gitlab&logoColor=white)](https://op_so.gitlab.io/pages/sbom-bompage/) `BOMpage` tracking its own dependencies

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

Your CI already generates an SBOM &mdash; 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:

```text
  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 &mdash; 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&hellip;) will work.

## Install

Python 3.12 or later:

```bash
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:

```bash
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 &mdash; `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 four commands

Every command accepts `--help`, and the
[full option reference](https://op_so.gitlab.io/pages/bompage/cli/) is generated
from the code, so it is always current.

### `bompage build` &mdash; make the site

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

```bash
bompage build --reports reports --output public \
  --stale-after 2 \
  --recent-days 30 \
  --metadata "team=platform"
```

- `--stale-after 2` &mdash; flag a project that has not reported for 2+ days.
- `--recent-days 30` &mdash; window covered by the "recent changes" panel.
- `--metadata "key=value"` &mdash; 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` &mdash; send one SBOM

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

```bash
export BOMPAGE_TOKEN=…

bompage push \
  --component app-api \
  --sbom build/sbom.cdx.json \
  --repo https://gitlab.com/acme/bompage.git
```

- `--component app-api` &mdash; becomes `reports/app-api/` in the central repo.
- `BOMPAGE_TOKEN` &mdash; 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 &mdash; signing is entirely opt-in.

On GitLab you usually do not call it by hand &mdash; include the ready-made
component instead:

```yaml
include:
  - component: gitlab.com/op_so/pages/bompage/push-report@v1
    inputs:
      component: app-api
      sbom_path: build/sbom.cdx.json
      bompage_repo: https://gitlab.com/acme/bompage.git
      bompage_version: "1.2.3"
      bompage_sign_key_var: BOMPAGE_SIGN_KEY # optional, see deploy/README.md
```

### `bompage prune` &mdash; keep the repository small

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

```bash
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 verify` &mdash; 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 &mdash; the published site does not yet serve them (a planned dashboard
change, see the spec):

```bash
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`](https://gitlab.com/op_so/pages/bompage/-/blob/main/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)
&mdash; an unsigned one has nothing here to verify.

## Set up a central repository

The [`deploy/`](https://gitlab.com/op_so/pages/bompage/-/tree/main/deploy) folder
is a ready-to-copy skeleton: the layout, the Pages job and the scheduled `prune`
job. See
[`deploy/README.md`](https://gitlab.com/op_so/pages/bompage/-/blob/main/deploy/README.md)
for the steps.

## What the dashboard shows

A live one is published at
[op_so.gitlab.io/pages/sbom-bompage](https://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`](https://gitlab.com/op_so/pages/bompage/-/blob/main/CONTRIBUTING.md).

## Authors

<!-- vale off -->

- **FX Soubirou** - _Initial work_ - [GitLab repositories](https://gitlab.com/op_so)
<!-- vale on -->

## License

<!-- vale off -->

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

<!-- vale on -->
