Skip to content

cyberus-technology/nix-sbom-helper

Repository files navigation

Nix SBOM Helper

Tooling producing SBOMs outputs for Standard Nix and Flakes


Usage

Using buildSbom

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.

Importing nix-sbom-helper.

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
/* ... */

Using buildSbom on derivations

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.

Using buildSbom for a NixOS system

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",

Automatic SBOMs with Flakes

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.

Automatic SBOMs without 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!


Reference

This library is usable both as a Flake, and with standard Nix.

About dependencies

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.

support/*.${system}*/.buildSbom

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.

support/*.${system}*/.mkRegistrationDb

Warning

While currently exposed on support, this function is not supported for external users yet.

Usage with standard Nix conventions

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.

Usage with Flakes

In addition to support.${currentSystem}.buildSbom, the Flake exposes the sbomsForFlakeOutputs and sbomsForFlakeOutputs' functions.

sbomsForFlakeOutputs

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.

sbomsForFlakeOutputs'

The sbomsForFlakeOutputs' function can extend the functionality past the conventional use of Flakes.

  • target is the self for the Flake being SBOM'd.
  • outputs is a list of outputs (indexed by systems) for which SBOMs will be produced.
  • withNixosConfigurations defines if nixosConfigurations SBOMs are produced for their toplevel.
  • builderSystem allows overriding the system used to build SBOMs. The default (null) uses the output's system.

The following arguments will be forwarded to support.${builderSystem}.buildSbom.

  • pkgs
  • buildTime
  • timestamp

By default, it produces SBOMs for those outputs:

  • packagespackages.${system}.${name}
  • nixosConfigurationsnixosConfigurations.${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.


Gotchas

Different SBOM from the sandboxed compared to outside

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

Large fetches of build-time 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.

About

Tooling producing SBOMs outputs for Standard Nix and Flakes

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published