SBOM
Each node of core has a software bill of materials (SBOM): a CycloneDX document of the runtime closure of the node, with the vendored dependencies of its packages (core/setups/nixos/sbom.nix, system.build.sbom). CI publishes the SBOM of each node of main to the package registry of the forge. This page tells where to find the SBOM of a commit, and what it describes.
What an SBOM describes
The SBOM describes the node as core declares it, with the tester apex (core/testers/apex.nix) and the options of the reference configuration of the node. A deployment can set other options. The SBOM of each node of a deployment comes from its deploy, and api gives it (GET /sbom/{deployment_id}).
Optional parts
Most options of a node change only its configuration files, or the reference configuration sets them on already. For example, the OpenID Connect plugin of PeerTube is in the SBOM of operator-peertube. Each contract of a reference configuration has a provider, thus no node runs its local fallback service (for example a local PostgreSQL). An operator deployment always has these providers. These options change the closure of a node, and the reference configuration does not set them on:
| Node | Option | Adds to the closure |
|---|---|---|
operator-peertube |
services.peertube.settings.video_transcription.enabled |
whisper-ctranslate2 and its Python dependencies |
core/setups/nixos/sbom-full.nix sets these options on for each node. core.lib.sbomConfigurations.<node> is the reference configuration of the node with that module. Its SBOM is the full SBOM of the node, which CI publishes as the node <node>-full. A node with no optional part has no full SBOM.
Software that is installed at run time
An SBOM describes only the Nix closure of a node. These are the applications that can take plugins or more software, and where it comes from:
- PeerTube: the plugin index is off,
peertube.servicehas nopnpmon its path (an assertion), and nginx refuses the install and update endpoints of plugins (/api/v1/plugins/install,/api/v1/plugins/update). An administrator thus cannot install a plugin or a theme. The plugins andyt-dlpcome from the Nix store. With automatic subtitles on, the transcription engine downloads its model at run time. No SBOM describes the model. - Mastodon and Pixelfed have no plugin system.
- Grafana, on the telemetry node, gets its plugins from the Nix store only (
declarativePlugins). It does not install its preinstalled plugins, and the node cannot connect tografana.com. - NetBox gets its plugins from the Nix store only (
services.netbox.plugins). - Windmill: a member of
fediversity-adminscan write a job script, and the worker gets the Python dependencies of that script withuvat run time. No SBOM describes those dependencies. The deploy scripts ofcoreuse only the Python standard library.
Where CI publishes it
The job of a node in nixosConfigurations-<group>.yaml builds the system of the node and its SBOM. On main, it then publishes the SBOM (.forgejo/workflows/sbom-publish.sh), and links the package to the repository. The Packages tab of the repository thus shows the package of each node:
| Item | Value |
|---|---|
| Package | sbom-<node>, of the type generic |
| Version | The full hash of the commit |
| File | <node>.cdx.json.gz, a gzipped CycloneDX JSON document |
For example, to get the SBOM of the node hypervisor-incus at the commit <commit>:
curl -fsSL https://git.fediversity.eu/api/packages/fediversity/generic/sbom-hypervisor-incus/<commit>/hypervisor-incus.cdx.json.gz | gunzip
A node with a full SBOM has a second job, <node>-full, in the same workflow and with the same path filter. That job publishes the full SBOM as the node <node>-full: the package sbom-<node>-full, with the file <node>-full.cdx.json.gz. For example, the full SBOM of operator-peertube:
curl -fsSL https://git.fediversity.eu/api/packages/fediversity/generic/sbom-operator-peertube-full/<commit>/operator-peertube-full.cdx.json.gz | gunzip
The registry keeps one copy of each file. A commit that does not change the SBOM of a node thus adds a version, but no storage.
Find the SBOM of a commit
The notes of a release give the commit of that release.
Not each commit of main has a version:
- The job of a node runs only when a commit changes a file that the node reads. The path filter of the workflow and the pin gate (
.forgejo/actions/pins) decide this. - A newer push to
mainstops the run of an older commit.
The SBOM of a node at a commit is thus the version of that commit, or else the version of its nearest ancestor on main. git rev-list <commit> gives the commit and its ancestors, newest first. The first one that is a version of sbom-<node> gives the SBOM. The API lists the versions, newest first. The search also gives packages whose name contains sbom-<node>, thus use only the items whose name is sbom-<node>. For example, the search for sbom-operator-peertube also gives sbom-operator-peertube-full:
curl -fsS 'https://git.fediversity.eu/api/v1/packages/fediversity?type=generic&q=sbom-hypervisor-incus&limit=50&page=1'
A run by hand of nixosConfigurations-<group>.yaml on main, from the Actions page of the repository, publishes the SBOMs of the nodes of that group for the head of main.
Retention
The versions stay: the organization has no cleanup rule for these packages. Do not add one. The Cyber Resilience Act (Regulation (EU) 2024/2847, Article 13(13)) tells manufacturers to keep the technical documentation for at least 10 years. The SBOM is a part of the technical documentation (Annex VII, point 8). A cleanup rule of the forge removes a version after at most 180 days.
The token
The publish uses the Actions secret SBOM_PACKAGE_TOKEN of the repository. It is a token with the scope write:package, of an account that can write the packages of the organization and of the repository. The link of a package to the repository needs both. The automatic token of a job cannot write packages.