mirror of
https://github.com/wolfSSL/wolfssl.git
synced 2026-08-10 15:52:43 +02:00
Make the canonical SBOM fragment a true superset of the vendored copies so it can be re-vendored to every product without regressions. Products whose feature macros live in config.h (via AC_DEFINE) keep the existing behaviour: the recipe derives them from a CC -dM -E dump with AM_CPPFLAGS/AM_CFLAGS/CFLAGS and a force-included SBOM_CONFIG_H. Products whose feature flags are NOT in config.h (wolfMQTT, wolfTPM, wolfscep, which record them in a generated options.h) can now set SBOM_OPTIONS_H to point gen-sbom at that header directly. When unset the compiler-dump path is used exactly as before. This folds the options.h capture that had diverged into the wolfMQTT/ wolfTPM/wolfscep copies back into the single source of truth, while retaining the SBOM_CONFIG_H override, AM_CFLAGS/CFLAGS capture and $(docdir) install those copies were missing. Signed-off-by: Sameeh Jubran <sameeh@wolfssl.com>
230 lines
11 KiB
Plaintext
230 lines
11 KiB
Plaintext
# scripts/sbom.am - shared Automake recipe for CRA-compliant SBOM generation.
|
|
#
|
|
# One generator (gen-sbom) does the work; each product just describes itself and
|
|
# includes this fragment. It is deliberately product-agnostic: a Makefile.am
|
|
# sets a few variables (below) and does `include scripts/sbom.am` to get the
|
|
# `sbom`, `install-sbom` and `uninstall-sbom` targets.
|
|
#
|
|
# This is the canonical copy (wolfSSL repository, scripts/sbom.am); product
|
|
# repositories vendor a copy of it and must be kept in sync with this file.
|
|
# gen-sbom is taken from a vendored scripts/gen-sbom if a product ships one
|
|
# (used automatically), otherwise from a wolfSSL source tree via WOLFSSL_DIR.
|
|
# Products such as wolfSSH use the WOLFSSL_DIR route; vendoring gen-sbom for
|
|
# fully offline tarball builds can be added later with no change here.
|
|
#
|
|
# ---------------------------------------------------------------------------
|
|
# The including Makefile.am MUST set, before `include scripts/sbom.am`:
|
|
# SBOM_PKGNAME Product name recorded in the SBOM (e.g. wolfssh). Drives
|
|
# the output filenames and gen-sbom --name.
|
|
# SBOM_LICENSE_FILE Path to the product's LICENSING file
|
|
# (e.g. $(srcdir)/LICENSING).
|
|
#
|
|
# Optional (defaults shown):
|
|
# SBOM_OPTIONS_H Path to a product-generated options header (e.g.
|
|
# wolfMQTT's $(builddir)/wolfmqtt/options.h) that records
|
|
# the enabled build macros. Set this for products whose
|
|
# feature flags are NOT in config.h (no AC_DEFINE); when
|
|
# unset the recipe derives the macros from the compiler +
|
|
# config.h. Default: unset.
|
|
# SBOM_ARTIFACT lib | bin - which build output to hash. Default: lib.
|
|
# SBOM_LIB_STEM Library basename w/o extension. Default: lib$(SBOM_PKGNAME).
|
|
# SBOM_BIN_NAME Program name when SBOM_ARTIFACT = bin. Default: $(SBOM_PKGNAME).
|
|
# SBOM_DEP_WOLFSSL yes | no - record wolfSSL as a dependency. Default: no.
|
|
# SBOM_DEP_OPENSSL yes | no - record OpenSSL as a dependency (wolfProvider /
|
|
# wolfEngine). Default: no.
|
|
# SBOM_LICENSE_OVERRIDE SPDX expression to record instead of the licence
|
|
# detected from SBOM_LICENSE_FILE.
|
|
# SBOM_LICENSE_TEXT Path to licence text for any LicenseRef-* used in
|
|
# SBOM_LICENSE_OVERRIDE (required by SPDX 2.3).
|
|
# SBOM_WOLFSSL_VERSION Version recorded for the wolfSSL dependency;
|
|
# auto-detected from WOLFSSL_DIR/wolfssl/version.h when unset.
|
|
# SBOM_OPENSSL_VERSION Version recorded for the OpenSSL dependency;
|
|
# gen-sbom resolves it via pkg-config when unset.
|
|
# SBOM_CONFIG_H Path to the configure-generated config header to
|
|
# force-include when capturing the configured build
|
|
# macros. Products whose AC_CONFIG_HEADERS lives in a
|
|
# subdirectory MUST override this so config.h defines are
|
|
# captured (e.g. wolfEngine: $(abs_builddir)/include/config.h;
|
|
# wolfCLU: $(abs_builddir)/src/config.h).
|
|
# Default: $(abs_builddir)/config.h.
|
|
#
|
|
# The wolfSSL/OpenSSL dependency flags are feature-detected against gen-sbom
|
|
# --help, so a product wired for them still produces a valid SBOM (with a NOTE)
|
|
# against a gen-sbom that predates the flag.
|
|
#
|
|
# gen-sbom is located at $(srcdir)/scripts/gen-sbom if vendored, else at
|
|
# $(WOLFSSL_DIR)/scripts/gen-sbom. python3, pyspdxtools and git come from
|
|
# configure (AC_PATH_PROG); git is used only to derive SOURCE_DATE_EPOCH.
|
|
#
|
|
# NOTE: this fragment requires GNU make. It uses GNU conditional assignment
|
|
# (?=) and the GNU make functions $(wildcard), $(if), $(firstword) and
|
|
# $(addprefix); under a non-GNU make the SBOM targets will not work.
|
|
# ---------------------------------------------------------------------------
|
|
|
|
SBOM_ARTIFACT ?= lib
|
|
SBOM_LIB_STEM ?= lib$(SBOM_PKGNAME)
|
|
SBOM_BIN_NAME ?= $(SBOM_PKGNAME)
|
|
SBOM_DEP_WOLFSSL ?= no
|
|
SBOM_DEP_OPENSSL ?= no
|
|
SBOM_CONFIG_H ?= $(abs_builddir)/config.h
|
|
|
|
SBOM_CDX = $(SBOM_PKGNAME)-$(PACKAGE_VERSION).cdx.json
|
|
SBOM_SPDX = $(SBOM_PKGNAME)-$(PACKAGE_VERSION).spdx.json
|
|
SBOM_SPDX_TV = $(SBOM_PKGNAME)-$(PACKAGE_VERSION).spdx
|
|
# Use Automake's $(docdir) so a user's --docdir override is honoured (this
|
|
# equals $(datadir)/doc/$(PACKAGE) by default).
|
|
sbomdir = $(docdir)
|
|
|
|
# Prefer a vendored gen-sbom; fall back to an external wolfSSL source tree.
|
|
# The fallback is $(wildcard)-guarded and only consulted when WOLFSSL_DIR is
|
|
# set, so an unset WOLFSSL_DIR leaves SBOM_GEN empty (and the sbom recipe's
|
|
# `test -f` prints the "set WOLFSSL_DIR" error) rather than resolving to an
|
|
# absolute /scripts/gen-sbom that could run an unrelated host script.
|
|
SBOM_GEN = $(firstword $(wildcard $(srcdir)/scripts/gen-sbom) \
|
|
$(if $(WOLFSSL_DIR),$(wildcard $(WOLFSSL_DIR)/scripts/gen-sbom)))
|
|
|
|
# Library artifact search order (versioned first) covering ELF, Mach-O and PE.
|
|
# Windows import libs (.lib) come with and without the "lib" prefix.
|
|
SBOM_LIB_GLOBS = \
|
|
$(SBOM_LIB_STEM).so.[0-9]* \
|
|
$(SBOM_LIB_STEM).so \
|
|
$(SBOM_LIB_STEM).[0-9]*.dylib \
|
|
$(SBOM_LIB_STEM).dylib \
|
|
$(SBOM_LIB_STEM).dll \
|
|
$(SBOM_LIB_STEM).dll.a \
|
|
$(SBOM_LIB_STEM).lib \
|
|
$(SBOM_PKGNAME).lib \
|
|
$(SBOM_LIB_STEM).a
|
|
|
|
# Automake requires CLEANFILES to be initialised with `=` before `+=`; the
|
|
# including Makefile.am must declare `CLEANFILES =` (typically in its primaries
|
|
# init block) before `include scripts/sbom.am`.
|
|
CLEANFILES += $(SBOM_CDX) $(SBOM_SPDX) $(SBOM_SPDX_TV)
|
|
|
|
.PHONY: sbom install-sbom uninstall-sbom
|
|
|
|
# Stage a `make install` into a private tree, discover the installed artifact
|
|
# (shared/static library or program; ELF/Mach-O/PE), hash it, capture the
|
|
# configured build macros (from SBOM_OPTIONS_H if set, else AM_CPPFLAGS/
|
|
# AM_CFLAGS/CFLAGS + config.h; some products carry their feature -D flags in
|
|
# AM_CFLAGS rather than AM_CPPFLAGS, and some outside config.h entirely),
|
|
# generate SPDX+CDX, validate
|
|
# the SPDX, then convert to tag-value. The staging tree and temp defines file
|
|
# are removed unconditionally via `trap`, even on failure. SOURCE_DATE_EPOCH is
|
|
# honoured for reproducible output (defaults to the last git commit time).
|
|
sbom:
|
|
@test -n "$(PYTHON3)" || { \
|
|
echo "ERROR: 'python3' not found in PATH. Cannot generate SBOM."; \
|
|
exit 1; }
|
|
@test -n "$(PYSPDXTOOLS)" || { \
|
|
echo "ERROR: 'pyspdxtools' not found (pip install spdx-tools)."; \
|
|
exit 1; }
|
|
@test -f "$(SBOM_GEN)" || { \
|
|
echo "ERROR: gen-sbom not found. Vendor scripts/gen-sbom, or re-run:"; \
|
|
echo " make sbom WOLFSSL_DIR=/path/to/wolfssl"; \
|
|
exit 1; }
|
|
@rm -rf $(abs_builddir)/_sbom_staging
|
|
@set -e; \
|
|
_defines=`mktemp $(abs_builddir)/_sbom_defines.XXXXXX`; \
|
|
trap 'rm -rf $(abs_builddir)/_sbom_staging "$$_defines"' EXIT INT TERM HUP; \
|
|
$(MAKE) install DESTDIR=$(abs_builddir)/_sbom_staging; \
|
|
sbom_art=""; \
|
|
if test "$(SBOM_ARTIFACT)" = bin; then \
|
|
for art in \
|
|
"$(abs_builddir)/_sbom_staging$(bindir)/$(SBOM_BIN_NAME)" \
|
|
"$(abs_builddir)/_sbom_staging$(bindir)/$(SBOM_BIN_NAME)".exe; do \
|
|
if test -f "$$art"; then sbom_art="$$art"; break; fi; \
|
|
done; \
|
|
else \
|
|
for art in \
|
|
$(addprefix "$(abs_builddir)/_sbom_staging$(libdir)"/,$(SBOM_LIB_GLOBS)) \
|
|
$(addprefix "$(abs_builddir)/_sbom_staging$(bindir)"/,$(SBOM_LIB_STEM).dll $(SBOM_PKGNAME).dll); do \
|
|
if test -f "$$art"; then sbom_art="$$art"; break; fi; \
|
|
done; \
|
|
fi; \
|
|
if test -z "$$sbom_art"; then \
|
|
echo ""; \
|
|
echo "ERROR: no installed $(SBOM_PKGNAME) artifact found for SBOM."; \
|
|
echo " (configure with --enable-shared or --enable-static)"; \
|
|
echo ""; \
|
|
exit 1; \
|
|
fi; \
|
|
echo "SBOM: hashing $$sbom_art"; \
|
|
opts_h="$(SBOM_OPTIONS_H)"; \
|
|
if test -z "$$opts_h"; then \
|
|
opts_h="$$_defines"; \
|
|
$(CC) -dM -E $(DEFAULT_INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
|
|
$(AM_CFLAGS) $(CFLAGS) \
|
|
$(if $(wildcard $(SBOM_CONFIG_H)),-include $(SBOM_CONFIG_H)) \
|
|
-x c /dev/null > "$$_defines"; \
|
|
fi; \
|
|
if test -z "$${SOURCE_DATE_EPOCH:-}" && test -n "$(GIT)" && \
|
|
$(GIT) -C "$(srcdir)" rev-parse --git-dir >/dev/null 2>&1; then \
|
|
sde=`$(GIT) -C "$(srcdir)" log -1 --format=%ct 2>/dev/null`; \
|
|
if test -n "$$sde"; then SOURCE_DATE_EPOCH="$$sde"; export SOURCE_DATE_EPOCH; fi; \
|
|
fi; \
|
|
dep_args=""; \
|
|
if test "$(SBOM_DEP_WOLFSSL)" = yes; then \
|
|
if $(PYTHON3) "$(SBOM_GEN)" --help 2>/dev/null \
|
|
| $(GREP) -q -- '--dep-wolfssl'; then \
|
|
dep_args="$$dep_args --dep-wolfssl yes"; \
|
|
wv="$(SBOM_WOLFSSL_VERSION)"; \
|
|
if test -z "$$wv" && test -f "$(WOLFSSL_DIR)/wolfssl/version.h"; then \
|
|
wv=`sed -n 's/.*LIBWOLFSSL_VERSION_STRING[[:space:]]*"\([^"]*\)".*/\1/p' \
|
|
"$(WOLFSSL_DIR)/wolfssl/version.h"`; \
|
|
fi; \
|
|
if test -n "$$wv"; then \
|
|
dep_args="$$dep_args --dep-version wolfssl=$$wv"; \
|
|
fi; \
|
|
else \
|
|
echo "NOTE: this gen-sbom has no --dep-wolfssl support, so the SBOM"; \
|
|
echo " will not list wolfssl as a dependency component. That"; \
|
|
echo " support is added by wolfSSL/wolfssl#10343; until it merges"; \
|
|
echo " to wolfssl master, point WOLFSSL_DIR at that PR's branch"; \
|
|
echo " to enable it. The generated SBOM is valid either way."; \
|
|
fi; \
|
|
fi; \
|
|
if test "$(SBOM_DEP_OPENSSL)" = yes; then \
|
|
if $(PYTHON3) "$(SBOM_GEN)" --help 2>/dev/null \
|
|
| $(GREP) -q -- '--dep-openssl'; then \
|
|
dep_args="$$dep_args --dep-openssl yes"; \
|
|
if test -n "$(SBOM_OPENSSL_VERSION)"; then \
|
|
dep_args="$$dep_args --dep-version openssl=$(SBOM_OPENSSL_VERSION)"; \
|
|
fi; \
|
|
else \
|
|
echo "NOTE: this gen-sbom has no --dep-openssl support; openssl will"; \
|
|
echo " not be listed as a dependency component."; \
|
|
fi; \
|
|
fi; \
|
|
$(PYTHON3) "$(SBOM_GEN)" \
|
|
--name $(SBOM_PKGNAME) \
|
|
--version $(PACKAGE_VERSION) \
|
|
--supplier "wolfSSL Inc." \
|
|
--license-file $(SBOM_LICENSE_FILE) \
|
|
--options-h "$$opts_h" \
|
|
--lib "$$sbom_art" \
|
|
$$dep_args \
|
|
$(if $(SBOM_LICENSE_OVERRIDE),--license-override '$(SBOM_LICENSE_OVERRIDE)') \
|
|
$(if $(SBOM_LICENSE_TEXT),--license-text '$(SBOM_LICENSE_TEXT)') \
|
|
--cdx-out $(abs_builddir)/$(SBOM_CDX) \
|
|
--spdx-out $(abs_builddir)/$(SBOM_SPDX); \
|
|
$(PYSPDXTOOLS) --infile $(abs_builddir)/$(SBOM_SPDX) \
|
|
--outfile $(abs_builddir)/$(SBOM_SPDX_TV)
|
|
|
|
install-sbom: sbom
|
|
$(MKDIR_P) $(DESTDIR)$(sbomdir)
|
|
$(INSTALL_DATA) $(SBOM_CDX) $(DESTDIR)$(sbomdir)/
|
|
$(INSTALL_DATA) $(SBOM_SPDX) $(DESTDIR)$(sbomdir)/
|
|
$(INSTALL_DATA) $(SBOM_SPDX_TV) $(DESTDIR)$(sbomdir)/
|
|
|
|
uninstall-sbom:
|
|
-rm -f $(DESTDIR)$(sbomdir)/$(SBOM_CDX)
|
|
-rm -f $(DESTDIR)$(sbomdir)/$(SBOM_SPDX)
|
|
-rm -f $(DESTDIR)$(sbomdir)/$(SBOM_SPDX_TV)
|
|
|
|
# SBOM install is intentionally opt-in (`make install-sbom`), so `make install`
|
|
# does NOT place SBOM files. uninstall-sbom is still chained into the standard
|
|
# `make uninstall` via uninstall-hook so a prior `make install-sbom` is cleaned
|
|
# up; it uses `rm -f`, so it is a harmless no-op when no SBOM was installed.
|
|
uninstall-hook: uninstall-sbom
|