mirror of https://github.com/wolfSSL/wolfBoot.git
247 lines
12 KiB
Plaintext
247 lines
12 KiB
Plaintext
# 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 tools/sbom/sbom.am` to get the
|
|
# `sbom`, `install-sbom` and `uninstall-sbom` targets.
|
|
#
|
|
# This is the canonical copy in wolfGlass. Product repositories vendor it
|
|
# together with the sibling `gen-sbom`, so the SBOM path works offline with no
|
|
# build-time dependency on a separate wolfSSL checkout.
|
|
#
|
|
# ---------------------------------------------------------------------------
|
|
# The including Makefile.am MUST set, before `include tools/sbom/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.
|
|
# SBOM_HOSTCC Host C compiler used to expand the build macros (the
|
|
# -D/-U/-I tokens only, never the configured cross $(CC)),
|
|
# so the SBOM is byte-reproducible across toolchains.
|
|
# Default: cc.
|
|
#
|
|
# 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 in the vendored directory (SBOM_VENDOR_DIR, default
|
|
# $(srcdir)/tools/sbom), or, if not vendored, in a wolfSSL source tree via
|
|
# WOLFSSL_DIR (the wolfSSH-style route); SBOM_GEN overrides both. NOTE: this
|
|
# fragment cannot locate itself at make time -- Automake's `include` is textual,
|
|
# so $(MAKEFILE_LIST) resolves to the top Makefile, not this file -- which is why
|
|
# the vendored directory is named explicitly rather than derived from the
|
|
# fragment's own path. 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
|
|
# Host C compiler used to capture the build macros (matching the Make/CMake
|
|
# paths' HOSTCC), NOT the configured $(CC): on a cross build $(CC) would bake
|
|
# the cross compiler's target-specific predefined macros into the SBOM, so the
|
|
# same product built through a different toolchain would produce a different
|
|
# document. Only the -D/-U/-I tokens are fed to it (see the capture below), so
|
|
# it never sees target arch flags it cannot parse.
|
|
SBOM_HOSTCC ?= cc
|
|
# Directory the wolfGlass tooling (gen-sbom) is vendored into. Products that
|
|
# vendor elsewhere override this (or SBOM_GEN directly).
|
|
SBOM_VENDOR_DIR ?= $(srcdir)/tools/sbom
|
|
|
|
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 the vendored copy; else fall back to a wolfSSL source tree via
|
|
# WOLFSSL_DIR. Empty if neither exists -- the `test -f "$(SBOM_GEN)"` check in
|
|
# the recipe then fails with a clear error. Callers may override SBOM_GEN.
|
|
SBOM_GEN ?= $(abspath $(firstword \
|
|
$(wildcard $(SBOM_VENDOR_DIR)/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 tools/sbom/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 the -D/-U/-I tokens
|
|
# of AM_CPPFLAGS/AM_CFLAGS/CFLAGS + config.h, expanded through the HOST compiler
|
|
# SBOM_HOSTCC so the SBOM is reproducible across cross toolchains; 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 at $(SBOM_GEN)."; \
|
|
echo " Vendor tools/sbom/gen-sbom or override SBOM_GEN=/path/to/gen-sbom"; \
|
|
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"; \
|
|
sbom_cpp=""; \
|
|
for f in $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS); do \
|
|
case "$$f" in -D*|-U*|-I*) sbom_cpp="$$sbom_cpp $$f";; esac; \
|
|
done; \
|
|
$(SBOM_HOSTCC) -dM -E $(DEFAULT_INCLUDES) $$sbom_cpp \
|
|
$(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 -n "$(WOLFSSL_DIR)" && 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."; \
|
|
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
|