mcptest docs GitHub

Software Bill of Materials (mcptest sbom)

Every release of mcptest carries a CycloneDX 1.5 Software Bill of Materials baked into the binary at compile time. The mcptest sbom subcommand reads it back out so a reviewer can answer "what does this thing depend on" without trusting any external SBOM file.

What gets embedded

The build.rs script runs cargo metadata on the workspace, walks the locked dependency graph, and writes a CycloneDX 1.5 document into the build's OUT_DIR. The CLI embeds the file via include_str!, so the BOM travels with the binary and survives a strip(1).

Each component carries:

The build also writes the SHA-256 of the serialized BOM into a sibling file the binary embeds, so mcptest sbom --verify can confirm the embedded bytes have not been swapped at runtime.

Reading the SBOM from the binary

The default invocation prints the raw CycloneDX JSON to stdout:

mcptest sbom > mcptest.cdx.json

Pipe it into any CycloneDX-aware scanner. cyclonedx-cli validate, Dependency-Track, Trivy, Grype, Snyk, OWASP DC, and Sigstore policy controller all consume this format directly.

Two summary modes are also available:

mcptest sbom --format licenses

prints one line per dep with its SPDX expression, useful when the question is "is there anything in here that is not OSI-approved":

adler2                         2.0.1           0BSD OR MIT OR Apache-2.0
ahash                          0.8.12          MIT OR Apache-2.0
anyhow                         1.0.102         MIT OR Apache-2.0
...

And:

mcptest sbom --format names

prints one line per dep with just the name and version, useful for piping into other tools:

adler2 2.0.1
ahash 0.8.12
anyhow 1.0.102
...

Verifying the embedded BOM

mcptest sbom --verify

re-hashes the embedded BOM bytes at runtime and compares against the SHA-256 the build stamped in. On match it prints:

mcptest sbom: embedded BOM verified
  sha256       : <hash>
  components   : <count>

and exits 0. On mismatch it prints the expected and actual hashes and exits 2.

What this check proves and does not prove:

To verify the binary matches a published release, use the signed release artifacts. Every release ships cosign signatures and a SLSA provenance attestation:

cosign verify-blob \
    --certificate-identity-regexp '/soapbucket/mcptest/' \
    --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
    --signature mcptest.sig \
    mcptest

gh attestation verify mcptest --repo soapbucket/mcptest

The first command verifies the binary was signed by the mcptest release workflow identity. The second confirms the SLSA provenance: this exact binary was built from this exact commit by this exact GitHub Actions workflow.

Reproducibility

The BOM omits its timestamp field unless SOURCE_DATE_EPOCH is set in the build environment. With Cargo.lock committed and pinned and the rust toolchain pinned, two clean builds on the same machine produce byte-identical SBOMs (and the same bom.sha256). The CI release workflow sets SOURCE_DATE_EPOCH from the tagged commit's date so the published BOM is reproducible from the same commit.

File this under

What is intentionally out of scope