From 1a067c23fb71eb233a76e43ec82d82cabf4b2d51 Mon Sep 17 00:00:00 2001 From: Sameeh Jubran Date: Thu, 13 Aug 2026 10:11:05 +0300 Subject: [PATCH] sbom: fail when an object maps to no source, instead of shrinking the SBOM SBOM_SRCS runs the object list through $(wildcard), so a source that is not on disk disappears before the driver sees it. The driver's own --skip-missing warning then has nothing left to report, which is why it never fires on the Make path that every embedded user takes. The result is a document that under-reports the image with no diagnostic anywhere. A sim-tpm build without lib/wolfTPM checked out silently loses all eight tpm2*.c sources, and validate_sbom.py accepts the result even though the captured configuration still records WOLFBOOT_TPM=1. Compare the two lists instead. An object that maps to neither a .c nor a .S on disk means a submodule or a vendor SDK is absent, so stop and name the objects on stderr. SBOM_ALLOW_MISSING=1 accepts the partial document for the cases where the SDK genuinely cannot be present, and still lists what is missing; imx_rt is one, because it compiles three MCUXpresso drivers from outside the source tree. Every other example config either passes or names only submodule paths that CI checks out, so no job needs the escape hatch. Signed-off-by: Sameeh Jubran --- .github/workflows/test-sbom.yml | 8 ++++++++ Makefile | 28 ++++++++++++++++++++++++++-- docs/SBOM.md | 8 ++++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-sbom.yml b/.github/workflows/test-sbom.yml index 9e2f2ef5..4f76d667 100644 --- a/.github/workflows/test-sbom.yml +++ b/.github/workflows/test-sbom.yml @@ -290,6 +290,12 @@ jobs: - nxp-t1040 - renesas-rx65n - hifive1 + include: + # imx_rt compiles three MCUXpresso SDK drivers (fsl_clock, fsl_cache, + # fsl_flexspi) from outside the source tree. The SDK is not on a + # runner, so this target cannot produce a complete source set here. + - config: imx-rt1060 + allow_missing: 1 steps: - uses: actions/checkout@v4 @@ -313,6 +319,8 @@ jobs: # SBOM then described this bootloader with no target HAL at all (29 # sources, hal.c but no nrf52.c) while CI stayed green. - name: make sbom (no cross-toolchain present) + env: + SBOM_ALLOW_MISSING: ${{ matrix.allow_missing }} run: | cp config/examples/${{ matrix.config }}.config .config make sbom diff --git a/Makefile b/Makefile index 9c5d6466..0a47a798 100644 --- a/Makefile +++ b/Makefile @@ -901,6 +901,13 @@ WOLFBOOT_VERSION:=$(shell sed -n \ SBOM_ROOT:=$(WOLFBOOT_ROOT) SBOM_NAME:=wolfboot SBOM_SRCS=$(wildcard $(patsubst %.o,%.c,$(OBJS))) $(wildcard $(patsubst %.o,%.S,$(OBJS))) +# $(wildcard) above drops every object whose source is absent, and it does so +# before the driver can report it: --skip-missing then has nothing left to warn +# about. An absent submodule therefore shrinks the document silently. A +# sim-tpm build without lib/wolfTPM checked out loses all eight tpm2*.c sources, +# emits no diagnostic, and still validates. An object that maps to no source is +# the signal, so compare the two lists and stop. +SBOM_SRCS_MISSING=$(filter-out $(basename $(SBOM_SRCS)),$(basename $(OBJS))) SBOM_CFLAGS=$(CFLAGS) # wolfBoot's wolfCrypt configuration is derived, not literal: include/user_settings.h # turns WOLFBOOT_SIGN_ECC256 into HAVE_ECC, HAVE_ECC256, ECC_TIMING_RESISTANT and @@ -910,7 +917,7 @@ SBOM_SETTINGS_H:=$(WOLFBOOT_LIB_WOLFSSL)/wolfssl/wolfcrypt/settings.h SBOM_INCLUDE_DIRS:=$(WOLFBOOT_ROOT)/include $(WOLFBOOT_LIB_WOLFSSL) # user_settings.h includes the generated target.h, so it must exist before the # capture runs. It also carries the flash layout the SBOM records. -SBOM_PREREQS:=include/target.h +SBOM_PREREQS:=include/target.h sbom-check-sources # Coat: wolfssl (TLS/library CPE) + wolfcrypt (crypto CPE). Sources remain in # the merkle hash; the components give scanners resolvable identifiers. SBOM_DEP_WOLFSSL?=yes @@ -931,6 +938,23 @@ SBOM_CDX_OUT:=wolfboot-$(WOLFBOOT_VERSION).cdx.json SBOM_SPDX_OUT:=wolfboot-$(WOLFBOOT_VERSION).spdx.json SBOM_GEN?= +# Guards both SBOM targets: see SBOM_SRCS_MISSING above. SBOM_ALLOW_MISSING=1 +# accepts the partial document, and still lists what is absent. +sbom-check-sources: + $(Q)if [ -n "$(strip $(SBOM_SRCS_MISSING))" ]; then \ + echo "sbom: $(words $(SBOM_SRCS_MISSING)) object(s) map to no source on disk:" >&2; \ + for o in $(SBOM_SRCS_MISSING); do echo " $$o.c (or .S)" >&2; done; \ + if [ "$(SBOM_ALLOW_MISSING)" = "1" ]; then \ + echo "sbom: SBOM_ALLOW_MISSING=1 set; the SBOM will describe fewer" >&2; \ + echo "sbom: sources than the image really holds." >&2; \ + else \ + echo "sbom: a submodule or a vendor SDK is absent, so the SBOM would" >&2; \ + echo "sbom: under-report the image. Check the tree out (git submodule" >&2; \ + echo "sbom: update --init), or set SBOM_ALLOW_MISSING=1 to accept it." >&2; \ + exit 1; \ + fi; \ + fi + include tools/sbom/build/sbom.mk ## Per-HAL SBOM @@ -956,4 +980,4 @@ $(eval $(call wolfglass_sbom_rule,sbom-hal,SBOM_HAL_)) FORCE: -.PHONY: FORCE clean keytool_check squashelf_check sbom sbom-hal +.PHONY: FORCE clean keytool_check squashelf_check sbom sbom-hal sbom-check-sources diff --git a/docs/SBOM.md b/docs/SBOM.md index 84960b83..02b79e7d 100644 --- a/docs/SBOM.md +++ b/docs/SBOM.md @@ -61,6 +61,14 @@ Obey these limitations when you make an SBOM. `tools/sbom/sbom-driver.py` directly. As an alternative, use the compilation database tool (`compdb_sbom.py`). +### Missing sources + +Each object that the build compiles must map to a source file on disk. If one +does not, a submodule or a vendor SDK is absent, and the SBOM would record +fewer sources than the image really holds. The `sbom` and `sbom-hal` targets +stop and list the objects. Run `git submodule update --init`, or set +`SBOM_ALLOW_MISSING=1` to accept a partial document. + ## Coverage: the 11 build methods wolfBoot is built in many ways. Each maps to one of four SBOM routes: