feat: add CRA SBOM generation (make sbom)#10342
feat: add CRA SBOM generation (make sbom)#10342MarkAtwood wants to merge 1 commit intowolfSSL:masterfrom
Conversation
Adds `make sbom` producing CycloneDX 1.6 and SPDX 2.3 SBOMs for EU Cyber Resilience Act compliance. Generation is handled by scripts/gen-sbom (Python 3, stdlib only). The script stages a `make install`, hashes the installed libwolfssl.so, generates both formats, then removes the staging directory. pyspdxtools validates the SPDX JSON and converts it to tag-value (.spdx). Output files (all versioned): wolfssl-<ver>.cdx.json CycloneDX 1.6 JSON wolfssl-<ver>.spdx.json SPDX 2.3 JSON wolfssl-<ver>.spdx SPDX 2.3 tag-value SBOMs include: SHA-256 of the library, CPE, PURL, license detected from the LICENSING file, copyright, and build configuration (options.h defines as CDX properties). Optional external dependencies (liboqs, libxmss, liblms, libz) appear as separate components when enabled. Version detection for deps without pkg-config (libxmss, liblms) uses `git describe --tags --always` on the source tree root. configure.ac changes: - AC_SUBST ENABLED_LIBOQS/LIBXMSS/LIBLMS/LIBZ so the dep flags set during ./configure are visible in the generated Makefile - AC_SUBST LIBLMS_ROOT (XMSS_ROOT was already exported by wolfssl) so gen-sbom can locate the source tree for git describe - AC_PATH_PROG([GIT]) to find git robustly at configure time rather than relying on PATH at make sbom time - Initialize LIBLMS_ROOT="" before the liblms detection block, mirroring how XMSS_ROOT is defaulted in the disabled branch Also adds: doc/SBOM.md, INSTALL section 21, README one-liner, install-sbom / uninstall-sbom targets.
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR adds build-time SBOM generation and installation targets to support EU Cyber Resilience Act (CRA) compliance, producing CycloneDX 1.6 and SPDX 2.3 outputs.
Changes:
- Add a Python-based SBOM generator (
scripts/gen-sbom) to emit CycloneDX JSON and SPDX JSON. - Integrate SBOM generation/validation into Autotools (
make sbom,install-sbom,uninstall-sbom) and wire required tool detection viaconfigure.ac. - Add SBOM documentation and a README/INSTALL entry describing usage and outputs.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/gen-sbom | New Python generator that builds CycloneDX + SPDX JSON SBOMs and captures build/dependency metadata. |
| Makefile.am | Adds sbom targets, staging install for hashing, and pyspdxtools conversion to tag-value. |
| configure.ac | Exposes dependency enablement/root vars and detects python3, pyspdxtools, and git for SBOM generation. |
| doc/SBOM.md | Documents SBOM generation, outputs, manual validation, and dependency version detection behavior. |
| INSTALL | Adds a section describing SBOM prerequisites, usage, and install/uninstall targets. |
| README.md | Adds a short section pointing users to make sbom and SBOM docs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| AM_CFLAGS="$AM_CFLAGS -DHAVE_LIBLMS" | ||
| ENABLED_LIBLMS="yes" | ||
| LIBLMS_ROOT=$tryliblmsdir |
There was a problem hiding this comment.
LIBLMS_ROOT is assigned without quoting, so paths containing whitespace will be split by the shell during configure and the value exported into the Makefile will be incorrect. Quote the assignment (and any similar path-valued assignments) so --with-liblms="/path with spaces" works reliably.
| LIBLMS_ROOT=$tryliblmsdir | |
| LIBLMS_ROOT="$tryliblmsdir" |
| rm -rf $(abs_builddir)/_sbom_staging | ||
| $(MAKE) install DESTDIR=$(abs_builddir)/_sbom_staging | ||
| $(PYTHON3) $(srcdir)/scripts/gen-sbom \ |
There was a problem hiding this comment.
The staging directory is only removed on the success path. If make install, gen-sbom, or pyspdxtools fails, _sbom_staging can be left behind, which is messy and can affect subsequent runs (especially in CI). Consider making cleanup unconditional (e.g., using a shell trap or a single shell block that guarantees rm -rf ... executes on exit/failure).
| rm -rf $(abs_builddir)/_sbom_staging | ||
| $(PYSPDXTOOLS) --infile $(abs_builddir)/$(SBOM_SPDX) \ | ||
| --outfile $(abs_builddir)/$(SBOM_SPDX_TV) |
There was a problem hiding this comment.
The staging directory is only removed on the success path. If make install, gen-sbom, or pyspdxtools fails, _sbom_staging can be left behind, which is messy and can affect subsequent runs (especially in CI). Consider making cleanup unconditional (e.g., using a shell trap or a single shell block that guarantees rm -rf ... executes on exit/failure).
| prints a warning if the file cannot be parsed. | ||
| """ | ||
| try: | ||
| text = open(license_file).read() |
There was a problem hiding this comment.
These reads don’t use context managers and don’t specify an encoding. Using with open(..., encoding="utf-8", errors="replace") avoids file descriptor leaks and makes behavior deterministic across platforms/locales (especially for LICENSING text parsing).
| """Parse wolfssl/options.h and return sorted deduplicated list of | ||
| (name, value) pairs for every #define found.""" | ||
| try: | ||
| text = open(path).read() |
There was a problem hiding this comment.
These reads don’t use context managers and don’t specify an encoding. Using with open(..., encoding="utf-8", errors="replace") avoids file descriptor leaks and makes behavior deterministic across platforms/locales (especially for LICENSING text parsing).
| for chunk in iter(lambda: f.read(65536), b''): | ||
| h.update(chunk) | ||
| except OSError as e: | ||
| sys.exit(f"ERROR: cannot read library for hashing: {e}") |
There was a problem hiding this comment.
This error omits the library path being hashed, which makes diagnosing miscomputed/incorrect --lib paths harder. Include path in the message (e.g., “cannot read library for hashing at : ...”) so failures are actionable.
| sys.exit(f"ERROR: cannot read library for hashing: {e}") | |
| sys.exit(f"ERROR: cannot read library for hashing at {path}: {e}") |
| source tree is unavailable or `git` is not found, version is recorded as | ||
| `NOASSERTION`. |
There was a problem hiding this comment.
This statement doesn’t match the implementation for CycloneDX: when a dependency version is unknown, CycloneDX output omits version and purl (while SPDX uses NOASSERTION for versionInfo). Update this section to reflect the format-specific behavior to avoid confusing users comparing outputs.
| source tree is unavailable or `git` is not found, version is recorded as | |
| `NOASSERTION`. | |
| source tree is unavailable or `git` is not found, SPDX records `NOASSERTION` | |
| for `versionInfo`, while CycloneDX omits `version` and `purl`. |
|
Superseded by a combined SBOM + OmniBOR build provenance branch (feat/sbom-bomsh). Will re-submit as a single PR covering both features together. |
Summary
make sbomproducing CycloneDX 1.6 JSON, SPDX 2.3 JSON, and SPDX 2.3 tag-value SBOMs for EU Cyber Resilience Act (CRA) compliancescripts/gen-sbom(Python 3, stdlib only); validates viapyspdxtoolsLICENSING), copyright, build config fromoptions.h, and optional external deps (liboqs, libxmss, liblms, libz) as separate componentsgit describe --tags --alwayson the source tree rootinstall-sbom/uninstall-sbomtargets installing to$(datadir)/doc/wolfssl/doc/SBOM.md,INSTALLsection, andREADME.mdone-linerconfigure.ac changes
AC_SUBSTforENABLED_LIBOQS/LIBXMSS/LIBLMS/LIBZso dep flags set at./configuretime are visible in the generated MakefileAC_SUBST([LIBLMS_ROOT])+LIBLMS_ROOT=""default (mirrors existingXMSS_ROOThandling) so gen-sbom can locate the source tree forgit describeAC_PATH_PROG([GIT])to find git robustly at configure time rather than relying onPATHatmake sbomtimeTest plan
./configure && make && make sbomon a default build — produces all three output files, pyspdxtools validates without errormake sbomwithoutpython3in PATH — fails with clear error messagemake sbomwithoutpyspdxtoolsin PATH — fails with clear error message./configure --with-libz && make && make sbom— zlib appears as a component in both SBOMs with version from pkg-configmake install-sbom— installs three files under$(datadir)/doc/wolfssl/make uninstall-sbom— removes installed filesmake clean— removes generated SBOM files