Tooling producing SBOMs outputs for Standard Nix and Flakes
This applies to standard Nix use, and to Flakes.
Note
The fetching/pinning method is left unspecified. Use your preferred inputs pinning scheme!
When using Flakes, skip over Importing nix-sbom-helper
,
it is already ready to use as an input to your Flake.
Warning
Even though the argument exists to override it, nix-sbom-helper
only supports its own pinned pkgs
.
let
nix-sbom-helper =
import
(/* nix-sbom-helper */)) # From your preferred pinning scheme
{} # No arguments *supported* at the moment.
;
in
/* ... */
Note
Usage of angled-bracket paths references used as a placeholder for your preferred inputs pinning method.
The following example shows a simple scheme to expose a package from Nixpkgs and its sbom
.
let
pkgs = import <nixpkgs> {};
nix-sbom-helper = import <nix-sbom-helper> {};
in
{
inherit (pkgs) hello;
sboms = {
hello = nix-sbom-helper.support.buildSbom {
input = pkgs.hello;
};
};
}
This example also lives (slightly altered) in the documentation/samples
folder of this project.
The SBOM can be produced using nix-build
and --attr sboms.hello
.
.../nix-sbom-helper $ nix-build ./documentation/samples/standard-nix-hello.nix --attr sboms.hello
[...]
/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-sbom.hello-2.12.2
.../nix-sbom-helper $ ls -l result/
total 664
-r--r--r-- 7 root root 227135 Dec 31 1969 eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-hello-2.12.2.cdx.json
-r--r--r-- 7 root root 86024 Dec 31 1969 eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-hello-2.12.2.csv
-r--r--r-- 7 root root 356500 Dec 31 1969 eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-hello-2.12.2.spdx.json
The main takeaway here is you only need to pass { input = /* your input */;}
to buildSbom
,
and it handles all the inconvenient parts for you.
Building the SBOM for a NixOS system is slightly less convenient.
The following blurb shows the important details.
See documentation/samples/standard-nix-nixos-iso.nix
for the complete example.
nix-sbom-helper.support.buildSbom {
input = iso.config.system.build.toplevel;
}
Building the example produces:
.../nix-sbom-helper $ nix-build ./documentation/samples/standard-nix-nixos-iso.nix
/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-sbom.nixos-system-nixos-YY.MMpre000000.000000000000
.../nix-sbom-helper $ ls -l result/
total 11300
-r--r--r-- 2 root root 3678137 Dec 31 1969 eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-nixos-system-nixos-YY.MMpre000000.000000000000.cdx.json
-r--r--r-- 2 root root 1198225 Dec 31 1969 eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-nixos-system-nixos-YY.MMpre000000.000000000000.csv
-r--r--r-- 2 root root 6692602 Dec 31 1969 eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-nixos-system-nixos-YY.MMpre000000.000000000000.spdx.json
.../nix-sbom-helper $ grep 'bom-ref.*nixos-install' result/ eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-nixos-system-nixos-YY.MMpre000000.000000000000.cdx.json
"bom-ref": "/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-nixos-install.drv",
The simplest way, and correct for most conventional Flakes usage, is by using sbomsForFlakeOutputs
.
By default, it will produce attributes for every packages
and nixosConfigurations
of your Flake.
{
/* [...] */
inputs.nix-sbom-helper.url = "github:cyberus-technology/nix-sbom-helper";
outputs =
{ nix-sbom-helper, /* [...] */ }:
{
/* [...] */
sboms = nix-sbom-helper.sbomsForFlakeOutputs self;
}
;
}
See the reference for configuring the helper for Nix Flakes.
There is currently no helper for this, builtins.map
or /*nixpkgs.*/lib.mapAttrs
should be fine for most use cases.
If you think you have a useful generic standard Nix helper that could help, contributions welcome!
This library is usable both as a Flake, and with standard Nix.
The nixpkgs
input used by this library should be self-contained to the produced sbom
outputs only.
Overriding it may be fine, but no guarantees can be provided, especially regarding the sbomnix
dependency.
Note
When used within a Flake, the support
output is indexed by systems.
Either use Dried Nix Flakes to abstract this, or use your preferred pattern for using support.${currentSystem}.buildSbom
.
Provides the sbomnix-generated SBOMs for the given inputs as a Nix output.
Each input
gets its own set of files, named from the output store path name.
The name
argument allows overriding the name of the output.
By default it will use either the name of the (single) derivation in input
,
or a name including the count of inputs.
A pkgs
ref can be provided, if meta information is wanted.
The pkgs
ref should be a pkgs
reference close to the one used for the inputs, for more accurate metadata output.
If desired, note that builds that involve multiple nixpkgs
inputs have to pick a single one that will be used for metadata.
The buildTime
argument maps to the --buildtime
sbomnix parameter.
Defaults to true
.
The timestamp
argument can be used to force a different timestamp in the generated SBOM.
A timestamp is forced during the build to make the output reproducible.
The output will be as reproducible as sbomnix
allows, for the same sbomnix
input.
The default usage, when no metadata information is used,
the build should be reproducible since no metadata is used,
and sbomnix
will use a stable UUIDv5 in that case.
Warning
While currently exposed on support
, this function is not supported for external users yet.
When used within a standard Nix project, the default.nix
is the conventional entrypoint.
A pkgs
can be passed to it, which will dictate the builder system for the support.buildSbom
function (and associated dependencies).
A nixpkgs_path
can alternatively be provided, in which case the builtins.currentSystem
will be used.
When neither pkgs
nor nixpkgs_path
is given, the nixpkgs
Flake input will be used (with builtins.currentSystem
).
The support.buildSbom
can be used as needed to produce SBOMs for your projects.
In addition to support.${currentSystem}.buildSbom
, the Flake exposes the sbomsForFlakeOutputs
and sbomsForFlakeOutputs'
functions.
sbomsForFlakeOutputs /* derivation */
is a shortcut using the defaults for sbomsForFlakeOutputs'
.
This function takes a target
Flake's self
(its outputs) and builds SBOMs for the conventional outputs that produce packages or systems.
It is a "good defaults for most use-cases" version of the configurable sbomsForFlakeOutputs'
function.
Refer to its documentation for its defaults.
Be aware that, following the conventions from Flakes, this function will produce SBOM outputs for the system the target derivation would be built on.
So when using this function, a packages.aarch64-linux
output will use an aarch64-linux
builder system.
Note
The sbomsForFlakeOutputs'
function allows overriding the builderSystem
value if this is undesirable for your particular use-case.
The sbomsForFlakeOutputs'
function can extend the functionality past the conventional use of Flakes.
target
is theself
for the Flake being SBOM'd.outputs
is a list of outputs (indexed by systems) for which SBOMs will be produced.withNixosConfigurations
defines ifnixosConfigurations
SBOMs are produced for theirtoplevel
.builderSystem
allows overriding the system used to build SBOMs. The default (null
) uses the output'ssystem
.
The following arguments will be forwarded to support.${builderSystem}.buildSbom
.
pkgs
buildTime
timestamp
By default, it produces SBOMs for those outputs:
packages
⇒packages.${system}.${name}
nixosConfigurations
⇒nixosConfigurations.${name}.config.system.build.toplevel
Note
If SBOMs needs to be produced for attributes that are not indexed by systems,
manually use the support.${system}.buildSbom
function in your Flake.
It's possible!
sbomnix
may be re-hydrating incomplete information to build the SBOM.
The main culprit would be an output path being plausibly produced by many derivers.
The SBOM in the sandbox should be the most accurate one.
This is because the sandbox will include the exact .drv
files from the exact derivation
s used to produce the given inputs.
$ nix-store --query --valid-derivers /nix/store/qg2k9xl5af62zzlynwfim5f3ajwai88v-elfutils-0.193
/nix/store/91dd1l56j8pw22fvvybqyag4qwq6l5an-elfutils-0.193.drv
/nix/store/cjnd42qqkp3h14z17hjjgbz18ajgp0sd-elfutils-0.193.drv
$ diff -u sbom.cdx.json result/*[0-9].cdx.json | grep --max-count=1 -C4 elfutil
@@ -817,7 +817,7 @@
},
{
"type": "library",
- "bom-ref": "/nix/store/91dd1l56j8pw22fvvybqyag4qwq6l5an-elfutils-0.193.drv",
+ "bom-ref": "/nix/store/cjnd42qqkp3h14z17hjjgbz18ajgp0sd-elfutils-0.193.drv",
"name": "elfutils",
"version": "0.193",
"purl": "pkg:nix/elfutils@0.193",
In the grand scheme of things, both SBOMs are valid enough as the out paths are correct.
The bom-ref
will differ, as will the nix:drv_path
property.
This is not an issue because the output paths are encoding the most important truths about the output, including the meaningful inputs.
Make sure the actual derivation
values (and not their paths) are used.
Using the .drv
store paths will end-up bringing-in all the build inputs for the closure.