Zum Hauptinhalt springen

README

<!--
SPDX-License-Identifier: Apache-2.0
SPDX-FileCopyrightText: 2026 ndaal Gesellschaft für Sicherheit in der Informationstechnik mbH & Co KG, Cologne
SPDX-FileCopyrightText: Author: Pierre Gronau <Pierre.Gronau@ndaal.eu>
-->

# ndaal SBOM Auditor

A single-binary, offline web application to **investigate SBOM (Software
Bill of Materials) files**. Upload an SBOM or import a folder of them, analyse
each with an ensemble of independent tools, review the normalised findings in
one local UI, and export the result in eight formats. No installation, no
network access, no telemetry.

> Translations: [Deutsch](LIESMICH.md) · [Français](LISEZMOI.md)

## What it does

1. **Ingest** — upload an SBOM in the browser, or import every SBOM in a
   configurable folder. CycloneDX (JSON/XML), SPDX (JSON/tag-value and 3.0
   JSON-LD) and syft-json are detected; files are content-hashed and
   deduplicated.
2. **Analyse** — run the enabled tools against the SBOM, each as an isolated
   subprocess under a deadline and a concurrency limit. A missing tool is a
   clean, visibly distinct *skip* — never reported as a clean result.
3. **Findings** — each tool's output is normalised to a common shape, with the
   CVE alias resolved from the tool's GHSA/OSV identifier, and shown per tool
   with severity badges.
4. **Score** — grade the SBOM against all seventeen CISA 2026 minimum
   elements, distinguishing a supplier's explicit `NOASSERTION` from a
   field that is simply absent.
5. **Search** — find which of your SBOMs declare a given component, across
   the whole corpus, by name or package URL.
6. **Export** — write the analysis as SARIF 2.1.0, SARIF 2.2, Markdown, ODT,
   DOCX, PDF and CSAF 2.1 / 2.2 advisories, each accompanied by five
   cryptographic hash sidecars.

## Analyzer ensemble

Each tool is optional at runtime and detected on `PATH` (override the binary
with `SBA_TOOL_<NAME>_BIN`). Findings never depend on any single tool.

| Tool | Role |
| --- | --- |
| [syft](https://github.com/anchore/syft) | SBOM normaliser / CycloneDX 1.6 converter |
| [grype](https://github.com/anchore/grype) | CVE matcher |
| [trivy](https://github.com/aquasecurity/trivy) | Vulnerability scanner |
| [osv-scanner](https://github.com/google/osv-scanner) | OSV database lookups |
| [bomber](https://github.com/devops-kung-fu/bomber) | Independent ensemble matcher |
| [bomdrift](https://crates.io/crates/bomdrift) | Supply-chain drift / typosquat (SARIF) |
| [inspektr](https://crates.io/crates/inspektr) | SBOM vulnerability scanner (JSON) |
| [shieldbom](https://crates.io/crates/shieldbom-core) | Offline embedded/IoT CVE scanner (SARIF) |
| [provenant](https://crates.io/crates/provenant-cli) | Licence / copyright / provenance (ScanCode) |

The first eight tools contribute CVE-shaped **vulnerability findings**;
`provenant` is different — it reports **licence, copyright, holder and author**
provenance, which the auditor stores and displays as its own finding shape (a
"Licence & provenance" section per run, included in the Markdown export) rather
than discarding it.

The scanners cannot read every format directly: `bomber` consumes only
CycloneDX ≤ 1.6, and none of the scanners read SPDX 3.0 JSON-LD. In both cases
the auditor normalises the input to CycloneDX via `syft convert` first, and
skips with a documented reason when syft is unavailable rather than let a tool
report zero packages. grype's vulnerability database is refreshed once per run
(out of band) so a routine staleness is a fresh scan, not a failed one.

## Security posture

- **Transport:** HTTPS only, TLS 1.3 (rustls + aws-lc-rs) with post-quantum
  key exchange (X25519MLKEM768) offered first. Self-signed dev certificate,
  regenerated at start-up; operator PEM files supported.
- **Memory safety:** written in Rust with `#![forbid(unsafe_code)]`; the lint
  policy denies panicking shortcuts, unchecked arithmetic and unchecked
  indexing in production code.
- **Filesystem confinement:** all data / import / export I/O is confined by a
  cap-std capability handle (path-traversal, symlink and TOCTOU classes
  closed). Stored file names are server-derived, never client-supplied.
- **Storage encryption (optional):** XChaCha20-Poly1305 seals stored SBOM
  bytes and raw tool output while they sit on disk (`--encryption-key-file`).
- **Web hardening:** defence-in-depth response headers on every response, a
  hash-pinned Content-Security-Policy, same-origin checks on every POST, and a
  request-body size limit.
- **No telemetry, no backdoors.** Everything runs locally. Meets the TeleTrusT
  "IT Security made in Germany / Europe" criteria.

## Build and run

Requires a recent stable Rust toolchain.

```bash
cargo build --release
./target/release/sbom-auditor
```

Then open <https://127.0.0.1:8680> (the browser will warn once about the
self-signed certificate).

### Common options

```text
--port <PORT>              Listen port (default 8680, env SBA_PORT)
--bind <ADDR>              Bind address (default 127.0.0.1, env SBA_BIND)
--data-dir <DIR>           Data directory (SQLite store + stored SBOMs)
--db <PATH>                Database path (default <data-dir>/auditor.db)
--encryption-key-file <F>  Enable storage encryption with this 32-byte key
--tls-cert <F> --tls-key <F>  Operator certificate instead of self-signed
--allow-non-loopback       Permit binding a non-loopback address
--check-update             Check gitlab.com for a newer release, then exit
--self-update              Download + verify + install the latest release
--help                     Full option list
```

Ports: **8680** serves the API and web UI over TLS 1.3 (HTTP/1.1 + HTTP/2);
**8681** is reserved for a future QUIC / HTTP-3 listener (not yet implemented).

## Testing

```bash
cargo nextest run          # unit + integration suite
cargo test --doc           # doctests
```

Additional harnesses: `loom-harness/` (concurrency permutation models),
`test/bruno/` (API collection), `test/playwright/` (browser E2E),
`test/example-corpus/` (API + GUI upload→analyze→export over the bundled
`example/` SBOM corpus) and `loadtest/` (Goose load scenarios). The `example/`
directory carries 651 public test SBOMs (Git LFS); see
[example/PROVENANCE.md](example/PROVENANCE.md). See
[documentation/structure.md](documentation/structure.md) for the module map
and the request flow.

## Documentation

- [REFERENCE.md](REFERENCE.md) — CLI, environment, routes, settings and
  export-format reference
- [documentation/structure.md](documentation/structure.md) — architecture map
- [documentation/User_Guide.md](documentation/User_Guide.md) — end-user
  walkthrough
- [documentation/Administrator_Guide.md](documentation/Administrator_Guide.md)
  — deployment and operations
- [documentation/arc42/en/](documentation/arc42/en/01-introduction-and-goals.md)
  — arc42 architecture views
- [documentation/compliance/CSI_2026_cisa_sbom_minimum_elements_508c.md](documentation/compliance/CSI_2026_cisa_sbom_minimum_elements_508c.md)
  — conformance assessment against the CISA 2026 SBOM Minimum Elements
- [CHANGELOG.md](CHANGELOG.md) — release history

## Licence

Code is licensed Apache-2.0. Bundled UI assets carry their own licences
(Bootstrap MIT, htmx 0BSD, Roboto OFL-1.1); see the per-file `.license`
sidecars under `src/static/`.