BOMs
Bills of Materials stand at the forefront of both BOMnipotents functionality and name. A BOM is a list of all components that make up a product. In the context of cybersecurity, the most prominent variant is the Software Bill of Materials (SBOM), but BOMs allow for more general considerations as well.
For BOM interactions beyond reading, you need the BOM_MANAGEMENT permission. The section about
Access Management
describes how it is granted.
Uploading
To upload a BOM, call:
Input
bomnipotent_client bom upload /home/your_project/sbom.cdx.json
Output
[INFO] Uploaded BOM Your Project_1.0.0
BOMnipotent expects its BOMs in the structured
CycloneDX
JSON format.
Consult the
Syft tutorial
to learn how to generate a BOM for your product.
The BOMnipotent Client will read the file at the provided path and upload its content. It can then be viewed by the consumers with appropriate permissions.
BOMs for Consumers
describes how to list and download the BOMs on the server.
To add a BOM to the database, the BOMnipotent Client has to have some additional information: a name, a version, and optionally a TLP label. The identifiers name and version can either be inferred (recommended), or overwritten, as described below.
Name and Version
Inference (recommended)
BOMnipotent uses name and version to identify a BOM. It tries to infer these from the provided CycloneDX JSON fields “metadata.component.name” and “metadata.component.version”. However, according to the
CycloneDX specification
, the metadata.component field is optional.
If no version is specified, BOMnipotent instead uses the date of “metadata.timestamp”, if available.
To avoid any complications, it is recommended that you specify a name and version when generating the BOM, as is shown in the
Syft tutorial
.
Overwriting (not particularly recommended)
If for some reason your BOM lacks a name or version, or if it is incorrect, the BOMnipotent Client offers to remedy that via command line arguments:
Input (long variant)
bomnipotent_client bom upload /home/your_project/dev_env_sbom.cdx.json --name-overwrite="Other Project" --version-overwrite="2.7.1"
Input (short variant)
bomnipotent_client bom upload /home/your_project/dev_env_sbom.cdx.json -n "Other Project" -v "2.7.1"
Output
[WARN] Warning: Overwriting name with 'Other Project'. The data stored on the server will differ from the provided file.
[WARN] Warning: Overwriting version with '2.7.1'. The data stored on the server will differ from the provided file.
[INFO] Uploaded BOM Other Project_2.7.1
Important: The BOMnipotent Client will in this case modify the data before sending it to the server. It does not modify the local file, as that would be overstepping. This means that your local file and the data on the server are now out-of-sync. What’s maybe worse, if you signed your BOM, your signature is now invalid.
If you do use this option, it is thus recommended that you immediately download the BOM from the server (as described in
BOMs for Consumers
) and replace your local file with the result.
TLP Classification
For consumers, BOMnipotent manages access to data using the
Traffic Light Protocol (TLP)
. The
CycloneDX Format
on the other hand does not currently support document classification.
To tell BOMnipotent how to classify a document, you have two options:
- Set a
default TLP Label
in the server config. This will then be used for all BOMs without further specifications.
- Provide a tlp classification via command line argument:
Input (long variant)
bomnipotent_client bom upload /home/your_project/container_sbom.cdx.json --tlp=WHITE # This makes the BOM public.
Input (short variant)
bomnipotent_client bom upload /home/your_project/container_sbom.cdx.json -t WHITE # This makes the BOM public.
Output
[INFO] Uploaded BOM Your Project Container_1.2.3
If you do neither, BOMnipotent will treat any unclassified documents as if they were labelled TLP:RED, and will log a warning every time it has to do that.
Conflict Handling
The combination of name and version of the main component of a BOM need to be unique. Trying to upload another document with the same combination results in an error.
Input
bomnipotent_client bom upload /home/your_project/sbom.cdx.json
Output
[ERROR] Received response:
409 Conflict
BOM Your Project_1.0.0 already exists in the database.
You can override this behaviour with the “on-existing” option, telling BOMnipotent to either skip or replace conflicting documents:
Input (long variant)
bomnipotent_client bom upload /home/your_project/sbom.cdx.json --on-existing=skip
Input (short variant)
bomnipotent_client bom upload /home/your_project/sbom.cdx.json -o skip
Output
Input (long variant)
bomnipotent_client bom upload /home/your_project/sbom.cdx.json --on-existing=replace
Input (short variant)
bomnipotent_client bom upload /home/your_project/sbom.cdx.json -o replace
Output
[INFO] Modified BOM Your Project_1.0.0.
Modifying
In the simplest case, modifying an existing BOM works very much like uploading a new one.
Input
bomnipotent_client bom modify /home/your_project/sbom.cdx.json
Output
[INFO] Modified BOM Your Project_1.0.0.
This will infer the name and version from the document, and overwrite the existing content on the server. If the data does not exist on the server, it will return a 404 Not Found error.
Modifying TLP Label
If a TLP label had previously been assigned to the BOM, a modification of the contents will not automatically alter it.
If you want to specify a new TLP label, you can do so via argument:
Input (long variant)
bomnipotent_client bom modify /home/your_project/sbom.cdx.json --tlp=AMBER
Input (short variant)
bomnipotent_client bom modify /home/your_project/sbom.cdx.json -t AMBER
Output
[INFO] Modified BOM Your Project_1.0.0.
If the contents of the BOM have not changed and you just want to modify the TLP label, you do not need to upload the document again. Instead of providing a path to a file, you can specify name and version of the BOM you want to reclassify:
Input (long variant)
bomnipotent_client bom modify --name="Other Project" --version="2.7.1" --tlp=GREEN
Input (short variant)
bomnipotent_client bom modify -n "Other Project" -v "2.7.1" -t GREEN
Output
[INFO] Modified BOM Other Project_2.7.1.
If you specify “none”, “default” or “unlabelled” as the TLP label, any existing classification will be removed, and the server falls back to the
default TLP Label
of the server config:
Input (long variant)
bomnipotent_client bom modify /home/your_project/sbom.cdx.json --tlp=none
bomnipotent_client bom modify /home/your_project/sbom.cdx.json --tlp=default # Does the same
bomnipotent_client bom modify /home/your_project/sbom.cdx.json --tlp=unlabeled # Does the same
Input (short variant)
bomnipotent_client bom modify /home/your_project/sbom.cdx.json -t none
bomnipotent_client bom modify /home/your_project/sbom.cdx.json -t default # Does the same
bomnipotent_client bom modify /home/your_project/sbom.cdx.json -t unlabeled # Does the same
Output
[INFO] Modified BOM Your Project_1.0.0.
[INFO] Modified BOM Your Project_1.0.0.
[INFO] Modified BOM Your Project_1.0.0.
Modifying Name or Version
If the document you are uploading has a different name or version than the data it shall modify, you need to provide that information to the BOMnipotent Client using command line arguments:
Input (long variant)
bomnipotent_client bom modify /home/your_project/dev_env_sbom.cdx.json --name="Other Project" --version="2.7.1"
Input (short variant)
bomnipotent_client bom modify /home/your_project/dev_env_sbom.cdx.json -n "Other Project" -v "2.7.1"
Output
[INFO] Modified BOM Your Development Environment_1.2.3.
BOMnipotent will infer the new data from the document you provide and change the database entries accordingly.
Overwriting Name or Version (not recommended)
As with uploading, it is possible to overwrite the name and/or version stored in the local document:
Input
bomnipotent_client bom modify /home/your_project/dev_env_sbom.cdx.json --name-overwrite="Other Project" --version-overwrite="2.7.1"
Important: As with uploading, this modifies the JSON data before uploading to the server! The same caveats apply.
If the data on the server has a different name and/or version than specified in the document, you can combine the specification with an overwrite of the data:
Input (long variant)
bomnipotent_client bom modify /home/your_project/dev_env_sbom.cdx.json --name="Your Development Environment" --version="1.2.3" --name-overwrite="Best Project" --version-overwrite="3.1.4"
Input (short variant)
bomnipotent_client bom modify /home/your_project/dev_env_sbom.cdx.json -n "Your Development Environment" -v "1.2.3" --name-overwrite="Best Project" --version-overwrite="3.1.4"
Output
[WARN] Warning: Overwriting name with 'Best Project'. The data stored on the server will differ from the provided file.
[WARN] Warning: Overwriting version with '3.1.4'. The data stored on the server will differ from the provided file.
[INFO] Modified BOM Best Project_3.1.4.
Changing name and/or version without providing the complete document is not supported.
Deleting
Deleting a BOM is very straightforward:
Input
bomnipotent_client bom delete "Best Project" "3.1.4"
Output
[INFO] Deleted BOM Best Project_3.1.4
If the BOM does not exist, the server will return 404 Not Found. If it does exists, it is removed from the database.
All components and vulnerabilities associated with the BOM are also deleted.
Vulnerabilities
An activity at the core of supply chain security is to compare the contents of a BOM, meaning all components of a product, to databases of known vulnerabilities.
For vulnerability interactions beyond reading, you need the VULN_MANAGEMENT permission. The section about
Access Management
describes how it is granted.
Detecting
BOMnipotent does not itself detect new vulnerabilities. One tool that can be used in combination with BOMnipotent is
grype
, which takes a BOM as input and produces a list of vulnerabilities as output. The
grype tutorial
contains some additional information on its usage. Other tools can be used as long as they provide output in
CycloneDX JSON format
.
Using the BOMnipotent Client, you can directly print the contents of a BOM and pipe it to grype.
Input (long variant)
bomnipotent_client bom get "Your Project" "1.0.0" | grype --output cyclonedx-json=/home/vuln.cdx.json
Input (short variant)
bomnipotent_client bom get "Your Project" "1.0.0" | grype -o cyclonedx-json=/home/vuln.cdx.json
This will check the software components agains several databases and add the result to the CycloneDX. It then stores all that in a file called “vuln.cdx.json” (or whichever other name you provide).
Grype currently has a small
known bug
that makes it forget the version of the main component when it adds the vulnerabilities. This is a bit problematic because BOMnipotent needs the version to uniquely identify a product. One possible workaround is to re-add the version to the document, for example via jq '.metadata.component.version = "<VERSION>"' "vuln.cdx.json" > "vuln_with_version.cdx.json"
. Starting with BOMnipotent v0.3.1 you can instead directly provide the version during the vulnerability upload, as described below.
Updating
The command to update the vulnerabilities associated with a BOM is:
Input
bomnipotent_client vulnerability update /home/your_project/vuln.cdx.json
Output
[INFO] Updated vulnerabilities of BOM Your Project_1.0.0
The “<VULNERABILITIES>” argument needs to be a path to a file in
CycloneDX JSON
format.
Ideally, this file contains the name and version of the associated BOM, in which case they will automatically be read. If one of the values is missing (due to a
known bug
in grype, for example), you can provide it with an optional argument:
Input (long variant)
bomnipotent_client vulnerability update /home/your_project/vuln_wrong_metadata.cdx.json --name="Your Project" --version="1.0.0"
Input (short variant)
bomnipotent_client vulnerability update /home/your_project/vuln_wrong_metadata.cdx.json -n "Your Project" -v "1.0.0"
Output
[INFO] Updated vulnerabilities of BOM Your Project_1.0.0
Vulnerabilities are meant to updated periodically. Doing so will completely replace any previous vulnerabilities associated a BOM. The uploaded CycloneDX document thus needs to contain a full list of all known vulnerabilities.
You can only update vulnerabilities for a BOM that exists on the server:
Input (long variant)
bomnipotent_client vulnerability update /home/your_project/vuln_wrong_metadata.cdx.json --name=Schlagsahne --version=2.7.1;
bomnipotent_client vulnerability update /home/your_project/vuln_wrong_metadata.cdx.json --version=1.0.1;
Input (short variant)
bomnipotent_client vulnerability update /home/your_project/vuln_wrong_metadata.cdx.json -n Schlagsahne -v 2.7.1;
bomnipotent_client vulnerability update /home/your_project/vuln_wrong_metadata.cdx.json -v 1.0.1;
Output
[ERROR] Received response:
404 Not Found
BOM Schlagsahne_2.7.1 not found in database
[ERROR] Received response:
404 Not Found
BOM Your Project_1.0.1 not found in database
Listing
The section about
listing vulnerabilities
in the documentation for consumers covers most aspects of listing vulnerabilities.
One aspect not mentioned there is the “–unassessed” option. With it, BOMnipotent Client lists only those vulnerabilities that have no CSAF document associated with it.
Input (long variant)
bomnipotent_client vulnerability list --unassessed
Input (short variant)
bomnipotent_client vulnerability list -u
Output
[INFO]
╭──────────────┬─────────┬─────────────────────┬────────────────────────────┬───────┬──────────┬─────────┬─────────────────╮
│ Product │ Version │ Vulnerability │ Description │ Score │ Severity │ TLP │ CSAF Assessment │
├──────────────┼─────────┼─────────────────────┼────────────────────────────┼───────┼──────────┼─────────┼─────────────────┤
│ Your Project │ 1.0.0 │ GHSA-qg5g-gv98-5ffh │ rustls network-reachable p │ │ medium │ Default │ │
│ │ │ │ anic in `Acceptor::accept` │ │ │ │ │
│ Your Project │ 1.1.0 │ GHSA-qg5g-gv98-5ffh │ rustls network-reachable p │ │ medium │ Default │ │
│ │ │ │ anic in `Acceptor::accept` │ │ │ │ │
╰──────────────┴─────────┴─────────────────────┴────────────────────────────┴───────┴──────────┴─────────┴─────────────────╯
[ERROR] Found 2 unassessed vulnerabilities.
In this mode, BOMnipotent Client exits with a code indicating an error if and only if there are unassessed vulnerabilites. This makes it easy to integrate this call in your periodic CI/CD.
You can freely combine this option with specifying a product name or version:
Input (long variant)
bomnipotent_client vulnerability list "Your Project" "1.0.0" --unassessed
Input (short variant)
bomnipotent_client vulnerability list "Your Project" "1.0.0" -u
Output
error: unexpected argument 'Your Project' found
Usage: bomnipotent_client vulnerability list [OPTIONS]
For more information, try '--help'.
CSAF Documents
A
Common Security Advisory Framework
(CSAF) document is a vendor’s response to a newly discovered vulnerability. It is a machine-readable format to spread information on how a user of your product should react: Do they need to update to a newer version? Do they need to modify a configuration? Is your product even truly affected, or does it maybe never call the affected part of the vulnerable library?
For CSAF interactions beyond reading, you need the CSAF_MANAGEMENT permission. The sectino about
Access Management
describes how it is granted.
Uploading
To upload a CSAF document, call
Input
bomnipotent_client csaf upload /home/your_project/advisory.json
Output
[INFO] Uploaded CSAF with id "ghsa-qg5g-gv98-5ffh_advisory".
Before your CSAF document is uploaded, BOMnipotent Client checks that it is valid according to the
OASIS CSAF Standard
.
Conflict Handling
CSAF documents are identified by their, well, identifier, which needs to be unique. Trying to upload another document with the same id results in an error:
Input
bomnipotent_client csaf upload /home/your_project/advisory.json
Output
[ERROR] Received response:
409 Conflict
CSAF with id 'ghsa-qg5g-gv98-5ffh_advisory' already exists in the database.
You can override this behaviour with the “on-existing” option, telling BOMnipotent to either skip or replace conflicting documents:
Input (long variant)
bomnipotent_client csaf upload /home/your_project/advisory.json --on-existing=skip
Input (short variant)
bomnipotent_client csaf upload /home/your_project/advisory.json -o skip
Output
Input (long variant)
bomnipotent_client csaf upload /home/your_project/advisory.json --on-existing=replace
Input (short variant)
bomnipotent_client csaf upload /home/your_project/advisory.json -o replace
Output
[INFO] Modified CSAF with id "ghsa-qg5g-gv98-5ffh_advisory".
Listing
You can view the result of the operation with
Input
bomnipotent_client csaf list
Output
[INFO]
╭────────────────────────────┬────────────────────────────┬─────────────────────────┬─────────────────────────┬────────┬───────────╮
│ ID │ Title │ Initial Release │ Current Release │ Status │ TLP │
├────────────────────────────┼────────────────────────────┼─────────────────────────┼─────────────────────────┼────────┼───────────┤
│ ghsa-qg5g-gv98-5ffh_adviso │ Network-reachable panic in │ 2025-01-01 10:11:12 UTC │ 2025-01-01 10:11:12 UTC │ final │ TLP:AMBER │
│ ry │ Your Product │ │ │ │ │
╰────────────────────────────┴────────────────────────────┴─────────────────────────┴─────────────────────────┴────────┴───────────╯
All data is taken from the CSAF document.
If the document does not have the optional TLP label entry, it is treated with the
default tlp
configured for the server.
...┬────────┬─────────╮
...│ Status │ TLP │
...┼────────┼─────────┤
...│ final │ Default │
...┴────────┴─────────╯
Modifying
When the status of your document changes, if you want to reclassify it, or if new information has come to light, you may want to modify your document. To upload the new version, call:
Input
bomnipotent_client csaf modify /home/your_project/advisory.json
Output
[INFO] Modified CSAF with id "ghsa-qg5g-gv98-5ffh_advisory".
The command can even modify the ID of the CSAF document. Because the old ID cannot be inferred from the new document in that case, it has to be provided as an optional argument:
Input (long variant)
bomnipotent_client csaf modify <PATH/TO/CSAF> --id=<OLD-ID>
Input (short variant)
bomnipotent_client csaf modify <PATH/TO/CSAF> -i <OLD-ID>
Deleting
To delete a CSAF document from your server (which you should really only do if something went completely wrong), simply call:
Input
bomnipotent_client csaf delete ghsa-qg5g-gv98-5ffh_advisory
Output
[INFO] Deleted CSAF with id ghsa-qg5g-gv98-5ffh_advisory