Skip to content

fix(gen-sbom): unique serialNumber/documentNamespace per build config - #15

Open
MarkAtwood wants to merge 2 commits into
masterfrom
fix/sbom-unique-identity
Open

fix(gen-sbom): unique serialNumber/documentNamespace per build config#15
MarkAtwood wants to merge 2 commits into
masterfrom
fix/sbom-unique-identity

Conversation

@MarkAtwood

Copy link
Copy Markdown

serial and doc_ns_uuid were derived only from (name, version), so two SBOMs for the same release but different build configuration (FIPS vs non-FIPS, a different --srcs set, a different feature-flag/dependency set) shared an identical CycloneDX serialNumber and SPDX documentNamespace despite differing content — an SPDX 2.3 §6.5 uniqueness violation, and a CycloneDX version:1 with a shared serial over differing content is self-contradictory.

Folds a config_identity digest (lib hash + licence + sorted build macros + enabled deps and versions) into the serial/documentNamespace seed. Different configs now get distinct identifiers; an identical config still reproduces byte-for-byte. bom-refs and the UUID namespace are unchanged.

Note: one-time value rotation for existing SBOMs (identity now encodes config); per-config reproducibility is preserved.

New tests/test_sbom_identity.py (unit on config_identity + end-to-end proving distinct-per-config, reproducible-per-config), wired into selftest.yml.

⚠️ This touches the shared gen-sbom engine (byte-identical to wolfssl#10343), so it diverges that copy — needs backporting to wolfssl#10343 to keep them in sync. Addresses SBOM-gpex.6.

sameehj and others added 2 commits July 23, 2026 15:54
Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
serial and doc_ns_uuid were derived only from (name, version), so two
SBOMs for the same release but different build configuration (FIPS vs
non-FIPS, a different --srcs set, a different feature-flag or dependency
set) shared an identical CycloneDX serialNumber and SPDX
documentNamespace despite differing content -- an SPDX 2.3 §6.5
uniqueness violation, and a CycloneDX version:1 with a shared serial over
differing content is self-contradictory.

Fold a config_identity digest (lib hash + licence + sorted build macros +
enabled deps and their versions) into the serial/documentNamespace seed.
Different configs now get distinct identifiers; an identical config still
reproduces byte-for-byte. bom-refs and the UUID namespace are unchanged.

Note: this is a one-time value rotation for existing SBOMs (the identity
now encodes config); the reproducibility contract is preserved per config.

Adds tests/test_sbom_identity.py (unit + end-to-end) and wires it in.
Copilot AI review requested due to automatic review settings July 24, 2026 01:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the shared share/gen-sbom generator so CycloneDX serialNumber and SPDX documentNamespace become unique per build configuration, not just per (name, version), by folding a stable config_identity digest into the UUID seed. It also adds unit + end-to-end tests and wires them into CI.

Changes:

  • Add config_identity() to hash build-distinguishing inputs (artifact hash, license ID, build macros, enabled deps + resolved versions).
  • Include config_identity in the derived UUID seed for serialNumber and documentNamespace.
  • Add tests/test_sbom_identity.py and run it in .github/workflows/selftest.yml.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
share/gen-sbom Adds config_identity() and folds it into UUID seeding for serial/document namespace uniqueness per config.
tests/test_sbom_identity.py New unit + end-to-end coverage for identity reproducibility and per-config uniqueness.
.github/workflows/selftest.yml Adds syntax-check and execution of the new SBOM identity tests.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +7 to +20
import json
import os
import subprocess
import sys
import tempfile
import unittest
from importlib.machinery import SourceFileLoader

REPO = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
GEN_SBOM = os.path.join(REPO, "share", "gen-sbom")

# gen-sbom has no .py extension, so load it by path with an explicit loader.
gs = SourceFileLoader("gen_sbom", GEN_SBOM).load_module()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants