mirror of https://github.com/wolfSSL/wolfMQTT.git
feat: add SBOM generation for autotools and cmake
Add `sbom`, `install-sbom` and `uninstall-sbom` targets to both build systems, producing CycloneDX and SPDX output for CRA compliance. The recipe is the canonical scripts/sbom.am fragment from wolfSSL (wolfSSL/wolfssl#10343), vendored byte-identical; Makefile.am only declares the wolfMQTT-specific inputs. Feature macros come from the generated wolfmqtt/options.h via SBOM_OPTIONS_H rather than config.h, since wolfMQTT uses no AC_DEFINE. Both paths stage an install to hash the real installed library, record wolfSSL as a dependency component, validate the SPDX with pyspdxtools, and are exercised in CI. Requires a wolfssl source tree via WOLFSSL_DIR for scripts/gen-sbom, plus python3 and spdx-tools on the build host.pull/557/head
parent
6a94b741f1
commit
07d08d5995
|
|
@ -0,0 +1,267 @@
|
|||
name: SBOM Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ 'master', 'main', 'release/**' ]
|
||||
pull_request:
|
||||
branches: [ '**' ]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
wolfssl_ref:
|
||||
description: 'wolfssl git ref that provides scripts/gen-sbom'
|
||||
default: 'master'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
# This workflow only reads the repo and uploads artefacts; no API writes.
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
sbom:
|
||||
name: wolfMQTT SBOM generation (linux)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Checkout wolfmqtt
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: wolfmqtt
|
||||
|
||||
# wolfMQTT links wolfSSL for TLS, so its SBOM records wolfSSL as a
|
||||
# dependency. wolfSSL is built + installed here so wolfMQTT has a library
|
||||
# to link, and the same source tree (scripts/gen-sbom + wolfssl/version.h)
|
||||
# is passed to `make sbom` via WOLFSSL_DIR -- so the recorded wolfSSL
|
||||
# dependency version matches the linked one. scripts/gen-sbom lives on
|
||||
# wolfssl master (wolfSSL/wolfssl#10343); the wolfssl_ref input overrides
|
||||
# it for testing against a different ref.
|
||||
- name: Checkout wolfssl (gen-sbom + library source)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: wolfSSL/wolfssl
|
||||
ref: ${{ github.event.inputs.wolfssl_ref || 'master' }}
|
||||
path: wolfssl
|
||||
|
||||
- name: Install build tooling and SBOM validator (pyspdxtools)
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential autoconf automake libtool \
|
||||
pkg-config
|
||||
python3 -m pip install --user 'spdx-tools==0.8.*'
|
||||
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Build and install wolfssl
|
||||
working-directory: wolfssl
|
||||
run: |
|
||||
autoreconf -ivf
|
||||
./configure --enable-all \
|
||||
--prefix="$GITHUB_WORKSPACE/wolfssl-install"
|
||||
make -j"$(nproc)"
|
||||
make install
|
||||
|
||||
# gen-sbom lives in wolfssl and may not be on the checked-out ref yet (the
|
||||
# wolfSSL SBOM change can land separately). Gate on its presence and on
|
||||
# --dep-wolfssl so this workflow is safe against a gen-sbom that predates
|
||||
# it.
|
||||
- name: Detect gen-sbom availability and capabilities
|
||||
id: gate
|
||||
run: |
|
||||
GS="$GITHUB_WORKSPACE/wolfssl/scripts/gen-sbom"
|
||||
if [ ! -f "$GS" ]; then
|
||||
echo "have=no" >> "$GITHUB_OUTPUT"
|
||||
echo "::notice::wolfssl scripts/gen-sbom not present on this ref; skipping SBOM generation."
|
||||
exit 0
|
||||
fi
|
||||
echo "have=yes" >> "$GITHUB_OUTPUT"
|
||||
if python3 "$GS" --help 2>/dev/null | grep -q -- '--dep-wolfssl'; then
|
||||
echo "dep_wolfssl=yes" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "dep_wolfssl=no" >> "$GITHUB_OUTPUT"
|
||||
echo "::notice::gen-sbom on this ref has no --dep-wolfssl; the wolfssl dependency + name-derived identity assertions will be skipped."
|
||||
fi
|
||||
|
||||
- name: Configure and build wolfmqtt
|
||||
if: steps.gate.outputs.have == 'yes'
|
||||
working-directory: wolfmqtt
|
||||
run: |
|
||||
autoreconf -ivf
|
||||
./configure --enable-tls \
|
||||
--with-libwolfssl-prefix="$GITHUB_WORKSPACE/wolfssl-install"
|
||||
make -j"$(nproc)"
|
||||
|
||||
- name: Generate SBOM
|
||||
if: steps.gate.outputs.have == 'yes'
|
||||
working-directory: wolfmqtt
|
||||
run: make sbom WOLFSSL_DIR="$GITHUB_WORKSPACE/wolfssl"
|
||||
|
||||
- name: Outputs exist and SPDX validates
|
||||
if: steps.gate.outputs.have == 'yes'
|
||||
working-directory: wolfmqtt
|
||||
run: |
|
||||
ls wolfmqtt-*.cdx.json wolfmqtt-*.spdx.json wolfmqtt-*.spdx
|
||||
pyspdxtools --infile wolfmqtt-*.spdx.json
|
||||
|
||||
- name: CycloneDX identity, licence, and captured options
|
||||
if: steps.gate.outputs.have == 'yes'
|
||||
working-directory: wolfmqtt
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
import glob, json
|
||||
cdx = json.load(open(glob.glob('wolfmqtt-*.cdx.json')[0]))
|
||||
assert cdx['bomFormat'] == 'CycloneDX', cdx.get('bomFormat')
|
||||
assert cdx['specVersion'] == '1.6', cdx.get('specVersion')
|
||||
m = cdx['metadata']['component']
|
||||
assert m['name'] == 'wolfmqtt', m['name']
|
||||
assert m['purl'].startswith('pkg:github/wolfSSL/wolfmqtt@'), m['purl']
|
||||
# Default override must land as GPL-3.0-or-later (matches source headers).
|
||||
ids = [l.get('license', {}).get('id') for l in m.get('licenses', [])]
|
||||
assert 'GPL-3.0-or-later' in ids, ids
|
||||
# Identity is the hashed library artifact.
|
||||
assert {h['alg'] for h in m.get('hashes', [])}, 'no component hash'
|
||||
# SBOM_OPTIONS_H must have been parsed: wolfMQTT stores its feature
|
||||
# macros in wolfmqtt/options.h (no config.h AC_DEFINE), so the SBOM's
|
||||
# build properties must be populated.
|
||||
props = [p for p in m.get('properties', [])
|
||||
if p.get('name', '').startswith('wolfssl:build:')]
|
||||
assert props, 'no wolfssl:build:* properties captured from options.h'
|
||||
print('CDX ok:', m['name'], m['purl'], ids, f'{len(props)} build props')
|
||||
PY
|
||||
|
||||
- name: Reproducible across two runs (SOURCE_DATE_EPOCH)
|
||||
if: steps.gate.outputs.have == 'yes'
|
||||
working-directory: wolfmqtt
|
||||
run: |
|
||||
rm -f wolfmqtt-*.cdx.json wolfmqtt-*.spdx.json wolfmqtt-*.spdx
|
||||
SOURCE_DATE_EPOCH=1700000000 make sbom \
|
||||
WOLFSSL_DIR="$GITHUB_WORKSPACE/wolfssl"
|
||||
sha256sum wolfmqtt-*.cdx.json wolfmqtt-*.spdx.json > /tmp/a.sums
|
||||
rm -f wolfmqtt-*.cdx.json wolfmqtt-*.spdx.json wolfmqtt-*.spdx
|
||||
SOURCE_DATE_EPOCH=1700000000 make sbom \
|
||||
WOLFSSL_DIR="$GITHUB_WORKSPACE/wolfssl"
|
||||
sha256sum wolfmqtt-*.cdx.json wolfmqtt-*.spdx.json > /tmp/b.sums
|
||||
diff /tmp/a.sums /tmp/b.sums
|
||||
|
||||
- name: wolfssl recorded as a dependency
|
||||
if: steps.gate.outputs.have == 'yes' && steps.gate.outputs.dep_wolfssl == 'yes'
|
||||
working-directory: wolfmqtt
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
import glob, json
|
||||
d = json.load(open(glob.glob('wolfmqtt-*.spdx.json')[0]))
|
||||
assert 'wolfssl' in {p['name'] for p in d['packages']}, \
|
||||
[p['name'] for p in d['packages']]
|
||||
rels = [(r['spdxElementId'], r['relationshipType'],
|
||||
r['relatedSpdxElement']) for r in d['relationships']]
|
||||
assert ('SPDXRef-Package-wolfmqtt', 'DEPENDS_ON',
|
||||
'SPDXRef-Package-wolfssl') in rels, rels
|
||||
print('wolfssl dependency ok')
|
||||
PY
|
||||
|
||||
- name: Upload SBOM artefacts
|
||||
if: always() && steps.gate.outputs.have == 'yes'
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: wolfmqtt-sbom-${{ github.sha }}
|
||||
path: |
|
||||
wolfmqtt/wolfmqtt-*.cdx.json
|
||||
wolfmqtt/wolfmqtt-*.spdx.json
|
||||
wolfmqtt/wolfmqtt-*.spdx
|
||||
if-no-files-found: warn
|
||||
retention-days: 90
|
||||
|
||||
# The CMake `sbom` custom target is a separate implementation from the
|
||||
# autotools recipe above; build it too so a regression in either path
|
||||
# fails CI. The reproducibility and CycloneDX assertions live in the
|
||||
# autotools job; the wolfssl dependency is asserted in both.
|
||||
sbom-cmake:
|
||||
name: wolfMQTT SBOM generation (cmake)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- name: Checkout wolfmqtt
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: wolfmqtt
|
||||
|
||||
- name: Checkout wolfssl (gen-sbom + library source)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: wolfSSL/wolfssl
|
||||
ref: ${{ github.event.inputs.wolfssl_ref || 'master' }}
|
||||
path: wolfssl
|
||||
|
||||
- name: Install build tooling and SBOM validator (pyspdxtools)
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential autoconf automake libtool \
|
||||
pkg-config cmake
|
||||
python3 -m pip install --user 'spdx-tools==0.8.*'
|
||||
echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
||||
|
||||
- name: Build and install wolfssl
|
||||
working-directory: wolfssl
|
||||
run: |
|
||||
autoreconf -ivf
|
||||
./configure --enable-all \
|
||||
--prefix="$GITHUB_WORKSPACE/wolfssl-install"
|
||||
make -j"$(nproc)"
|
||||
make install
|
||||
|
||||
- name: Detect gen-sbom availability
|
||||
id: gate
|
||||
run: |
|
||||
GS="$GITHUB_WORKSPACE/wolfssl/scripts/gen-sbom"
|
||||
if [ ! -f "$GS" ]; then
|
||||
echo "have=no" >> "$GITHUB_OUTPUT"
|
||||
echo "::notice::wolfssl scripts/gen-sbom not present on this ref; skipping CMake SBOM job."
|
||||
exit 0
|
||||
fi
|
||||
echo "have=yes" >> "$GITHUB_OUTPUT"
|
||||
if python3 "$GS" --help 2>/dev/null | grep -q -- '--dep-wolfssl'; then
|
||||
echo "dep_wolfssl=yes" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "dep_wolfssl=no" >> "$GITHUB_OUTPUT"
|
||||
echo "::notice::gen-sbom on this ref has no --dep-wolfssl; the wolfssl dependency assertion will be skipped."
|
||||
fi
|
||||
|
||||
- name: Configure and build wolfmqtt (cmake)
|
||||
if: steps.gate.outputs.have == 'yes'
|
||||
working-directory: wolfmqtt
|
||||
run: |
|
||||
cmake -B build \
|
||||
-DWITH_WOLFSSL="$GITHUB_WORKSPACE/wolfssl-install" \
|
||||
-DWOLFSSL_DIR="$GITHUB_WORKSPACE/wolfssl"
|
||||
cmake --build build -j"$(nproc)"
|
||||
|
||||
- name: Generate SBOM via CMake target
|
||||
if: steps.gate.outputs.have == 'yes'
|
||||
working-directory: wolfmqtt
|
||||
run: cmake --build build --target sbom
|
||||
|
||||
- name: Outputs exist and SPDX validates
|
||||
if: steps.gate.outputs.have == 'yes'
|
||||
working-directory: wolfmqtt/build
|
||||
run: |
|
||||
ls wolfmqtt-*.cdx.json wolfmqtt-*.spdx.json wolfmqtt-*.spdx
|
||||
pyspdxtools --infile wolfmqtt-*.spdx.json
|
||||
|
||||
# The CMake target passes --dep-wolfssl independently of scripts/sbom.am,
|
||||
# so assert it here too; file existence alone would pass on an SBOM that
|
||||
# silently dropped the dependency component.
|
||||
- name: wolfssl recorded as a dependency (cmake)
|
||||
if: steps.gate.outputs.have == 'yes' && steps.gate.outputs.dep_wolfssl == 'yes'
|
||||
working-directory: wolfmqtt/build
|
||||
run: |
|
||||
python3 - <<'PY'
|
||||
import glob, json
|
||||
d = json.load(open(glob.glob('wolfmqtt-*.spdx.json')[0]))
|
||||
assert 'wolfssl' in {p['name'] for p in d['packages']}, \
|
||||
[p['name'] for p in d['packages']]
|
||||
rels = [(r['spdxElementId'], r['relationshipType'],
|
||||
r['relatedSpdxElement']) for r in d['relationships']]
|
||||
assert ('SPDXRef-Package-wolfmqtt', 'DEPENDS_ON',
|
||||
'SPDXRef-Package-wolfssl') in rels, rels
|
||||
print('cmake wolfssl dependency ok')
|
||||
PY
|
||||
|
|
@ -132,3 +132,8 @@ tests/test_broker_connect
|
|||
tests/test_mqtt_sn
|
||||
tests/test_mqtt_sn_client
|
||||
tests/unit_tests
|
||||
|
||||
# SBOM output (make sbom)
|
||||
wolfmqtt-*.cdx.json
|
||||
wolfmqtt-*.spdx
|
||||
wolfmqtt-*.spdx.json
|
||||
|
|
|
|||
175
CMakeLists.txt
175
CMakeLists.txt
|
|
@ -418,3 +418,178 @@ message("\tMultithread: ${ENABLE_MULTITHREAD}")
|
|||
message("\tCurl: ${ENABLE_CURL}")
|
||||
message("\tBroker: ${WOLFMQTT_BROKER}")
|
||||
message("-----------------------------------------------")
|
||||
|
||||
# ── SBOM generation target ────────────────────────────────────────────────────
|
||||
#
|
||||
# Usage:
|
||||
# cmake -B build -DWOLFSSL_DIR=/path/to/wolfssl/source .
|
||||
# cmake --build build
|
||||
# cmake --build build --target sbom
|
||||
#
|
||||
# WOLFSSL_DIR must point to a wolfssl source tree containing scripts/gen-sbom
|
||||
# (feat/sbom-embedded branch). wolfSSL is NOT required to be installed for
|
||||
# SBOM generation — only the source tree is needed to locate gen-sbom.
|
||||
#
|
||||
# Outputs in build directory:
|
||||
# wolfmqtt-<version>.cdx.json
|
||||
# wolfmqtt-<version>.spdx.json
|
||||
# wolfmqtt-<version>.spdx
|
||||
#
|
||||
# This mirrors the autotools `make sbom` target: same package metadata, licence,
|
||||
# option fingerprint and wolfSSL dependency component. The hashed artifact is
|
||||
# whatever that build system actually installs, so the recorded file name and
|
||||
# checksum legitimately differ between the two (autotools installs the
|
||||
# SONAME-versioned library, cmake an unversioned one).
|
||||
|
||||
# Location of the wolfssl source tree that ships scripts/gen-sbom. A cache PATH
|
||||
# (not a plain var) so it can be set on the command line with -DWOLFSSL_DIR=...
|
||||
# and persists across reconfigures.
|
||||
set(WOLFSSL_DIR "" CACHE PATH
|
||||
"Path to wolfssl source tree containing scripts/gen-sbom (for the sbom target)")
|
||||
|
||||
# Derive the SBOM version from wolfmqtt/version.h, NOT from PROJECT_VERSION.
|
||||
# version.h is the single source of truth shared with the autotools build
|
||||
# (PACKAGE_VERSION is generated from it); project(VERSION ...) is hand-maintained
|
||||
# and can drift, which would make the cmake SBOM disagree with the autotools one.
|
||||
file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/wolfmqtt/version.h" WOLFMQTT_VERSION_LINE
|
||||
REGEX "^#define[ \t]+LIBWOLFMQTT_VERSION_STRING[ \t]+\"")
|
||||
string(REGEX REPLACE "^.*\"([^\"]+)\".*$" "\\1"
|
||||
WOLFMQTT_SBOM_VERSION "${WOLFMQTT_VERSION_LINE}")
|
||||
|
||||
set(SBOM_CDX "wolfmqtt-${WOLFMQTT_SBOM_VERSION}.cdx.json")
|
||||
set(SBOM_SPDX "wolfmqtt-${WOLFMQTT_SBOM_VERSION}.spdx.json")
|
||||
set(SBOM_SPDX_TV "wolfmqtt-${WOLFMQTT_SBOM_VERSION}.spdx")
|
||||
|
||||
# gen-sbom runs under python3; pyspdxtools validates the SPDX tag-value output.
|
||||
# Both are required — fail at configure time so the user fixes their environment
|
||||
# before building rather than hitting a confusing failure mid-`--target sbom`.
|
||||
find_program(PYTHON3_EXECUTABLE python3)
|
||||
find_program(PYSPDXTOOLS_EXECUTABLE pyspdxtools)
|
||||
|
||||
# WOLFSSL_DIR (a wolfssl source tree with scripts/gen-sbom) is required only to
|
||||
# actually build the sbom target. CI and default builds never set it, so checking
|
||||
# it at configure time would abort every build. Mirror the autotools `make sbom`
|
||||
# recipe: configure always succeeds; if WOLFSSL_DIR is unset, define a stub sbom
|
||||
# target that fails clearly at BUILD time. An empty WOLFSSL_DIR is the common
|
||||
# first-run mistake.
|
||||
if(WOLFSSL_DIR STREQUAL "")
|
||||
add_custom_target(sbom
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
"ERROR: WOLFSSL_DIR is not set. Cannot locate gen-sbom."
|
||||
COMMAND ${CMAKE_COMMAND} -E echo
|
||||
" Reconfigure with: cmake -B build -DWOLFSSL_DIR=/path/to/wolfssl ."
|
||||
COMMAND ${CMAKE_COMMAND} -E false
|
||||
COMMENT "SBOM target requires -DWOLFSSL_DIR")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# WOLFSSL_DIR is set: the operator opted into SBOM generation. Validate the rest
|
||||
# of the environment now so they get immediate, actionable feedback.
|
||||
if(NOT EXISTS "${WOLFSSL_DIR}/scripts/gen-sbom")
|
||||
message(FATAL_ERROR
|
||||
"gen-sbom not found at ${WOLFSSL_DIR}/scripts/gen-sbom.\n"
|
||||
" WOLFSSL_DIR must point to a wolfssl source tree (feat/sbom-embedded).")
|
||||
endif()
|
||||
if(NOT PYTHON3_EXECUTABLE)
|
||||
message(FATAL_ERROR "python3 not found in PATH. Cannot generate SBOM.")
|
||||
endif()
|
||||
if(NOT PYSPDXTOOLS_EXECUTABLE)
|
||||
message(FATAL_ERROR
|
||||
"pyspdxtools not found in PATH. Cannot validate SBOM.\n"
|
||||
" Install with: pip install spdx-tools")
|
||||
endif()
|
||||
|
||||
# Staging dir for `cmake --install` so gen-sbom hashes the as-installed
|
||||
# library without polluting the system or requiring root.
|
||||
set(SBOM_STAGING "${CMAKE_BINARY_DIR}/_sbom_staging")
|
||||
|
||||
# Subdirectory of the staging prefix that holds the installed library. The
|
||||
# install(TARGETS) rule above sends LIBRARY/ARCHIVE to lib and RUNTIME to bin,
|
||||
# and a shared build on the Windows-family toolchains (MSVC, MinGW, Cygwin) is
|
||||
# the only case whose artifact - the DLL - is a RUNTIME output.
|
||||
# CMAKE_IMPORT_LIBRARY_SUFFIX is set exactly on those platforms. The file name
|
||||
# itself comes from $<TARGET_FILE_NAME:wolfmqtt>, so .so/.dylib/.dll/.a/.lib
|
||||
# are all handled without hardcoding a suffix.
|
||||
if(BUILD_SHARED_LIBS AND CMAKE_IMPORT_LIBRARY_SUFFIX)
|
||||
set(SBOM_ARTIFACT_DIR "bin")
|
||||
else()
|
||||
set(SBOM_ARTIFACT_DIR "lib")
|
||||
endif()
|
||||
|
||||
# wolfMQTT links wolfSSL for TLS, so the SBOM records it as a dependency
|
||||
# component -- the same thing SBOM_DEP_WOLFSSL = yes does in Makefile.am.
|
||||
# gen-sbom only learned --dep-wolfssl in wolfSSL/wolfssl#10343, so probe for it
|
||||
# the way scripts/sbom.am does: an older gen-sbom still emits a valid SBOM
|
||||
# (just without the dependency) instead of dying on an unknown flag.
|
||||
execute_process(
|
||||
COMMAND ${PYTHON3_EXECUTABLE} ${WOLFSSL_DIR}/scripts/gen-sbom --help
|
||||
OUTPUT_VARIABLE SBOM_GEN_HELP
|
||||
ERROR_VARIABLE SBOM_GEN_HELP
|
||||
RESULT_VARIABLE SBOM_GEN_HELP_RC)
|
||||
set(SBOM_DEP_ARGS "")
|
||||
if(SBOM_GEN_HELP_RC EQUAL 0 AND SBOM_GEN_HELP MATCHES "--dep-wolfssl")
|
||||
list(APPEND SBOM_DEP_ARGS --dep-wolfssl yes)
|
||||
# Record the version of the wolfSSL that WOLFSSL_DIR points at, matching the
|
||||
# version scrape in scripts/sbom.am.
|
||||
if(EXISTS "${WOLFSSL_DIR}/wolfssl/version.h")
|
||||
file(STRINGS "${WOLFSSL_DIR}/wolfssl/version.h" WOLFSSL_VERSION_LINE
|
||||
REGEX "^#define[ \t]+LIBWOLFSSL_VERSION_STRING[ \t]+\"")
|
||||
string(REGEX REPLACE "^.*\"([^\"]+)\".*$" "\\1"
|
||||
WOLFSSL_SBOM_VERSION "${WOLFSSL_VERSION_LINE}")
|
||||
if(NOT WOLFSSL_SBOM_VERSION STREQUAL "")
|
||||
list(APPEND SBOM_DEP_ARGS --dep-version wolfssl=${WOLFSSL_SBOM_VERSION})
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
message(STATUS
|
||||
"gen-sbom has no --dep-wolfssl support, so the SBOM will not list "
|
||||
"wolfssl as a dependency component. That support is added by "
|
||||
"wolfSSL/wolfssl#10343. The generated SBOM is valid either way.")
|
||||
endif()
|
||||
|
||||
add_custom_target(sbom
|
||||
# Install into the staging dir so the SBOM hashes the real installed
|
||||
# artifact rather than a build-tree intermediate.
|
||||
# --config is required for multi-config generators (Visual Studio, Ninja
|
||||
# Multi-Config): without it the install script falls back to "Release" and
|
||||
# cannot find a library built in any other configuration. It expands to an
|
||||
# empty (harmless) argument under single-config generators.
|
||||
COMMAND ${CMAKE_COMMAND} --install ${CMAKE_BINARY_DIR}
|
||||
--config $<CONFIG>
|
||||
--prefix ${SBOM_STAGING}/usr/local
|
||||
|
||||
# The generated options.h is passed to gen-sbom directly, the same input
|
||||
# the autotools `make sbom` feeds it, so both build systems record an
|
||||
# identical compile-time option fingerprint. (No shell redirection here:
|
||||
# add_custom_target COMMANDs do not run through a shell under VERBATIM.)
|
||||
COMMAND ${PYTHON3_EXECUTABLE} ${WOLFSSL_DIR}/scripts/gen-sbom
|
||||
--name wolfmqtt
|
||||
--version ${WOLFMQTT_SBOM_VERSION}
|
||||
--supplier "wolfSSL Inc."
|
||||
--license-file ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE
|
||||
# Match the autotools default (SBOM_LICENSE_OVERRIDE in
|
||||
# scripts/sbom.am): source headers say GPLv3 or later, which
|
||||
# LICENSE-file detection alone records as GPL-3.0-only.
|
||||
--license-override GPL-3.0-or-later
|
||||
${SBOM_DEP_ARGS}
|
||||
--options-h ${WOLFMQTT_OUTPUT_BASE}/wolfmqtt/options.h
|
||||
--lib ${SBOM_STAGING}/usr/local/${SBOM_ARTIFACT_DIR}/$<TARGET_FILE_NAME:wolfmqtt>
|
||||
--cdx-out ${CMAKE_BINARY_DIR}/${SBOM_CDX}
|
||||
--spdx-out ${CMAKE_BINARY_DIR}/${SBOM_SPDX}
|
||||
|
||||
# Validate the SPDX output and emit the tag-value (.spdx) rendering.
|
||||
COMMAND ${PYSPDXTOOLS_EXECUTABLE}
|
||||
--infile ${CMAKE_BINARY_DIR}/${SBOM_SPDX}
|
||||
--outfile ${CMAKE_BINARY_DIR}/${SBOM_SPDX_TV}
|
||||
|
||||
# Remove the staging tree; keep only the three SBOM files.
|
||||
# (-E remove_directory, not -E rm: the latter needs CMake >= 3.17 and
|
||||
# this project's minimum is 3.16.)
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory ${SBOM_STAGING}
|
||||
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
COMMENT "Generating SBOM for wolfMQTT ${WOLFMQTT_SBOM_VERSION}"
|
||||
VERBATIM)
|
||||
|
||||
# The library must exist before we install/hash it.
|
||||
add_dependencies(sbom wolfmqtt)
|
||||
|
|
|
|||
24
Makefile.am
24
Makefile.am
|
|
@ -74,6 +74,30 @@ test: check
|
|||
|
||||
DISTCLEANFILES+= wolfmqtt-config
|
||||
|
||||
# SBOM generation (CRA compliance). The recipe is shared across the wolfSSL
|
||||
# stack's autotools products in scripts/sbom.am; wolfMQTT just declares what it
|
||||
# is (a libwolfmqtt library that links wolfSSL for TLS) and includes it.
|
||||
# WOLFSSL_DIR must point to a wolfssl source tree containing scripts/gen-sbom.
|
||||
SBOM_PKGNAME = wolfmqtt
|
||||
SBOM_LICENSE_FILE = $(srcdir)/LICENSE
|
||||
SBOM_DEP_WOLFSSL = yes
|
||||
|
||||
# wolfMQTT records its feature macros in its own generated options header (it
|
||||
# uses no AC_DEFINE / config.h defines), so point gen-sbom at that header rather
|
||||
# than at the compiler-derived defaults.
|
||||
SBOM_OPTIONS_H = $(abs_builddir)/wolfmqtt/options.h
|
||||
|
||||
# wolfMQTT is GPLv3-or-later (per the per-file source headers: "either version 3
|
||||
# of the License, or (at your option) any later version") or commercial. Pin
|
||||
# the header-accurate SPDX id here so the SBOM is correct regardless of the
|
||||
# gen-sbom version's licence detection; commercial licensees can override it
|
||||
# (e.g. LicenseRef-wolfSSL-Commercial).
|
||||
SBOM_LICENSE_OVERRIDE ?= GPL-3.0-or-later
|
||||
|
||||
EXTRA_DIST += scripts/sbom.am
|
||||
|
||||
include scripts/sbom.am
|
||||
|
||||
clean-local:
|
||||
-rm -rf tests/fuzz/corpus
|
||||
@if test "$(abs_srcdir)" != "$(abs_builddir)"; then \
|
||||
|
|
|
|||
45
README.md
45
README.md
|
|
@ -571,3 +571,48 @@ You can test the wolfMQTT client against public brokers supporting websockets:
|
|||
* HiveMQ secure websockets
|
||||
|
||||
`./examples/websocket/websocket_client -h broker.hivemq.com -p8884 -t`
|
||||
|
||||
## SBOM / EU CRA Compliance
|
||||
|
||||
wolfMQTT generates a Software Bill of Materials (SBOM) in CycloneDX 1.6 and
|
||||
SPDX 2.3 formats to support compliance with the EU Cyber Resilience Act (CRA).
|
||||
The SBOM records the configured build options (from `wolfmqtt/options.h`),
|
||||
hashes the built `libwolfmqtt` library artifact (shared or static; ELF, Mach-O,
|
||||
or PE), and (with a sufficiently new `gen-sbom`) lists wolfSSL as a dependency
|
||||
so vulnerability scanners can associate wolfSSL advisories with a TLS-enabled
|
||||
wolfMQTT deployment. Output is reproducible: set `SOURCE_DATE_EPOCH` (or build
|
||||
from a git checkout, which uses the last commit time) and repeated runs are
|
||||
byte-identical.
|
||||
|
||||
```sh
|
||||
make sbom WOLFSSL_DIR=/path/to/wolfssl
|
||||
```
|
||||
|
||||
Requires `python3` and `pyspdxtools` (`pip install spdx-tools`). `WOLFSSL_DIR`
|
||||
must point to a wolfssl source tree containing `scripts/gen-sbom` (branch
|
||||
`feat/sbom-embedded`, or `master` once wolfSSL/wolfssl#10343 merges).
|
||||
|
||||
Output: `wolfmqtt-<version>.cdx.json`, `wolfmqtt-<version>.spdx.json`, `wolfmqtt-<version>.spdx`
|
||||
|
||||
Optional overrides:
|
||||
|
||||
- `SBOM_LICENSE_OVERRIDE` - SPDX expression to use instead of the licence
|
||||
parsed from `LICENSE` (e.g. `LicenseRef-wolfSSL-Commercial` for commercial
|
||||
licensees). Defaults to `GPL-3.0-or-later` (the per-file header licence).
|
||||
- `SBOM_LICENSE_TEXT` - path to the 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` (or wolfSSL's `pkg-config`
|
||||
entry) when unset.
|
||||
|
||||
```sh
|
||||
make install-sbom # installs to $(datadir)/doc/wolfmqtt/
|
||||
make uninstall-sbom
|
||||
```
|
||||
|
||||
Note: recording wolfSSL as a dependency and emitting wolfMQTT-specific project
|
||||
URLs require the `gen-sbom` from wolfSSL/wolfssl#10343. Against an older
|
||||
`gen-sbom`, `make sbom` still succeeds and produces a valid SBOM, but omits the
|
||||
wolfSSL dependency entry and inherits wolfSSL's project URLs.
|
||||
|
||||
For further CRA guidance see [wolfssl/doc/CRA.md](https://github.com/wolfSSL/wolfssl/blob/master/doc/CRA.md).
|
||||
|
|
|
|||
10
configure.ac
10
configure.ac
|
|
@ -571,6 +571,16 @@ AC_SUBST([AM_CPPFLAGS])
|
|||
AC_SUBST([AM_CFLAGS])
|
||||
AC_SUBST([AM_LDFLAGS])
|
||||
|
||||
# Tools used by the SBOM targets (see scripts/sbom.am `make sbom`). GIT is used
|
||||
# only to derive SOURCE_DATE_EPOCH for reproducible SBOM output; all three are
|
||||
# optional and the target reports a clear error when a required one is missing.
|
||||
AC_PATH_PROG([PYTHON3], [python3])
|
||||
AC_PATH_PROG([PYSPDXTOOLS], [pyspdxtools])
|
||||
AC_PATH_PROG([GIT], [git])
|
||||
AC_SUBST([PYTHON3])
|
||||
AC_SUBST([PYSPDXTOOLS])
|
||||
AC_SUBST([GIT])
|
||||
|
||||
# FINAL
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_CONFIG_FILES([wolfmqtt/version.h])
|
||||
|
|
|
|||
|
|
@ -0,0 +1,229 @@
|
|||
# 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
|
||||
Loading…
Reference in New Issue