Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions share/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
# share/
# wolfssl-compliance-tooling SBOM files

This is the only vendorable set. Use `tools/wolfssl-compliance-tooling-sync` to copy these files
into a product at `tools/sbom/`, together with the pin files (`VERSION` and
`.wolfssl-compliance-tooling-rev`). Do not copy the `share/` folder name; copy the files.
These are the SBOM files that a product vendors from
[wolfssl-compliance-tooling](https://github.com/wolfSSL/wolfssl-compliance-tooling).
The source is the `share/` folder of that repository. A product keeps a copy in
`tools/sbom/`, together with the pin files (`VERSION` and
`.wolfssl-compliance-tooling-rev`). Do not edit the copy in a product.

To change the pin, run the sync tool from a checkout of
wolfssl-compliance-tooling. The tool is not vendored into the product:

<tooling-checkout>/tools/wolfssl-compliance-tooling-sync --dest <product> --prune

Add `--check` to find drift, including lost executable bits, without a copy.

## Contents

Expand All @@ -17,6 +26,10 @@ into a product at `tools/sbom/`, together with the pin files (`VERSION` and
| `frontends/zephyr_sbom.py` | Zephyr module, from a west build's `compile_commands.json`. |
| `build/sbom.mk` | Shared plain-Make fragment and `wolfssl_compliance_tooling_sbom_rule` macro. |
| `build/sbom.cmake` | Shared CMake helper: `wolfssl_compliance_tooling_add_sbom()`. |
| `build/sbom-with-sde.cmake` | Runs the driver with `SOURCE_DATE_EPOCH`, after the `STAGE_TARGET` install. |
| `build/sbom-validate.cmake` | `VALIDATE` step: pyspdxtools check and SPDX tag-value file. |
| `build/sbom-fail.cmake` | Target body when python3 or pyspdxtools is missing. |
| `build/install-sbom.cmake`, `build/uninstall-sbom.cmake`, `build/sbom-paths.cmake` | `install-sbom` and `uninstall-sbom`. |
| `gen-sbom` | The vendored SBOM generator. |
| `sbom.am` | Shared autotools fragment. |

Expand Down Expand Up @@ -78,7 +91,11 @@ A product does not copy logic. It describes itself:
`<prefix>/share/doc/<NAME>`) and read `DESTDIR` when the target runs.
Pass `CDX_OUT` / `SPDX_OUT`
when the file name is not `<name>-<version>` (wolfBoot's config tag).
wolfTPM writes the tag-value file in a later `sbom` target: pass
To hash the installed library and validate the SPDX file as `make sbom`
does, pass `STAGE_TARGET <library target>` and `VALIDATE`. Then
`install-sbom` also installs the tag-value file. A missing python3 or
pyspdxtools does not fail configure; the `sbom` target fails when it is built.
A product that writes the tag-value file in its own later target can pass
`NO_INSTALL` and call `wolfssl_compliance_tooling_add_sbom_install(DEPENDS sbom TV ...)`
after that target exists.
`SBOM_GEN` is the canonical generator override; `GEN_SBOM` remains a legacy
Expand Down
6 changes: 6 additions & 0 deletions share/build/sbom-fail.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# cmake -P script: stop the build of an SBOM target that cannot run.
# sbom.cmake uses it when python3, or pyspdxtools for VALIDATE, was not
# found at configure time. Configure succeeds, and the build of the target
# gives the reason.

message(FATAL_ERROR "sbom: ${WOLFSSL_COMPLIANCE_TOOLING_SBOM_ERROR}")
10 changes: 8 additions & 2 deletions share/build/sbom-paths.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
# The names match the driver default: <bindir>/<name>-<version>.cdx.json
# and the .spdx.json sibling. A caller that set CDX_OUT / SPDX_OUT passes
# those paths and this file leaves them unchanged. The tag-value path is
# used only when the caller sets TV / TV_OUT. A .spdx sibling is not
# inferred, so a stale file is not installed or removed.
# used only when the caller sets TV / TV_OUT, or when VALIDATE writes the
# .spdx sibling. Otherwise the sibling is not inferred, so a stale file is
# not installed or removed.

function(_wolfssl_compliance_tooling_read_version file macro out_var)
set(_ver "")
Expand Down Expand Up @@ -71,6 +72,11 @@ function(wolfssl_compliance_tooling_sbom_resolve_outputs out_cdx out_spdx out_tv
endif()
endif()

# VALIDATE writes the tag-value file next to the SPDX file.
if(_tv STREQUAL "" AND WOLFSSL_COMPLIANCE_TOOLING_SBOM_TV_FROM_SPDX)
string(REGEX REPLACE "\\.json$" "" _tv "${_spdx}")
endif()
Comment on lines +76 to +78

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reproduced: SPDX_OUT b.spdx with VALIDATE left b.spdx holding the tag-value output instead of the SPDX JSON.


set(${out_cdx} "${_cdx}" PARENT_SCOPE)
set(${out_spdx} "${_spdx}" PARENT_SCOPE)
set(${out_tv} "${_tv}" PARENT_SCOPE)
Expand Down
28 changes: 28 additions & 0 deletions share/build/sbom-validate.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# cmake -P script: validate the SPDX file and write the tag-value file.
# pyspdxtools fails on an invalid document, so this is the same check as
# the pyspdxtools step of `make sbom`.
#
# The paths use the rules of sbom-paths.cmake, so install-sbom installs the
# file that this script writes.

if(NOT DEFINED WOLFSSL_COMPLIANCE_TOOLING_PYSPDXTOOLS OR
WOLFSSL_COMPLIANCE_TOOLING_PYSPDXTOOLS STREQUAL "")
message(FATAL_ERROR "sbom-validate.cmake: WOLFSSL_COMPLIANCE_TOOLING_PYSPDXTOOLS is required")
endif()

include("${CMAKE_CURRENT_LIST_DIR}/sbom-paths.cmake")
set(WOLFSSL_COMPLIANCE_TOOLING_SBOM_TV_FROM_SPDX ON)
wolfssl_compliance_tooling_sbom_resolve_outputs(_cdx _spdx _tv)

if(NOT EXISTS "${_spdx}")
message(FATAL_ERROR "sbom-validate.cmake: missing SPDX file ${_spdx}")
endif()

execute_process(
COMMAND "${WOLFSSL_COMPLIANCE_TOOLING_PYSPDXTOOLS}"
--infile "${_spdx}" --outfile "${_tv}"
RESULT_VARIABLE _rc)
if(NOT _rc EQUAL 0)
file(REMOVE "${_tv}")
message(FATAL_ERROR "SPDX validation failed (${_rc}) for ${_spdx}")
endif()
46 changes: 46 additions & 0 deletions share/build/sbom-with-sde.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
# toplevel, so the outer commit time is not used. A tree with no git
# leaves the variable empty, and gen-sbom uses its own default.
#
# When SBOM_STAGE_DIR is set, the build tree SBOM_STAGE_BUILD_DIR is first
# installed with DESTDIR=SBOM_STAGE_DIR, and SBOM_STAGE_LIB must then exist.
# The staging directory is removed after the driver runs, also on failure.
#
# Arguments after "--" are the driver command.

if(NOT DEFINED SBOM_ROOT)
Expand Down Expand Up @@ -66,7 +70,49 @@ if(NOT _args)
message(FATAL_ERROR "sbom-with-sde.cmake: no command after --")
endif()

if(NOT DEFINED SBOM_STAGE_DIR)
set(SBOM_STAGE_DIR "")
endif()
if(NOT SBOM_STAGE_DIR STREQUAL "")
file(REMOVE_RECURSE "${SBOM_STAGE_DIR}")
# DESTDIR also moves absolute install directories, which --prefix does
# not. The prefix stays the real one, so the staged file has the same
# bytes (RPATH, install name) as an installed one. A DESTDIR that the
# caller set for install-sbom is not used here.
set(_saved_destdir_set FALSE)
if(DEFINED ENV{DESTDIR})
set(_saved_destdir_set TRUE)
set(_saved_destdir "$ENV{DESTDIR}")
endif()
set(ENV{DESTDIR} "${SBOM_STAGE_DIR}")
set(_install "${CMAKE_COMMAND}" --install "${SBOM_STAGE_BUILD_DIR}")
if(DEFINED SBOM_STAGE_CONFIG AND NOT SBOM_STAGE_CONFIG STREQUAL "")
list(APPEND _install --config "${SBOM_STAGE_CONFIG}")
endif()
execute_process(COMMAND ${_install} RESULT_VARIABLE _rc)
if(_saved_destdir_set)
set(ENV{DESTDIR} "${_saved_destdir}")
else()
unset(ENV{DESTDIR})
endif()
if(NOT _rc EQUAL 0)
file(REMOVE_RECURSE "${SBOM_STAGE_DIR}")
message(FATAL_ERROR
"SBOM staging install failed (${_rc}). Build the project first.")
endif()
if(NOT EXISTS "${SBOM_STAGE_LIB}")
file(REMOVE_RECURSE "${SBOM_STAGE_DIR}")
message(FATAL_ERROR
"SBOM staging: ${SBOM_STAGE_LIB} was not installed. Install the "
"STAGE_TARGET to CMAKE_INSTALL_LIBDIR, or to CMAKE_INSTALL_BINDIR "
"for a program or a Windows DLL.")
endif()
endif()

execute_process(COMMAND ${_args} RESULT_VARIABLE _rc)
if(NOT SBOM_STAGE_DIR STREQUAL "")
file(REMOVE_RECURSE "${SBOM_STAGE_DIR}")
endif()
if(NOT _rc EQUAL 0)
message(FATAL_ERROR "SBOM generation failed (${_rc})")
endif()
152 changes: 133 additions & 19 deletions share/build/sbom.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,25 @@
# LICENSE_OVERRIDE (required by SPDX 2.3).
# NO_ARTIFACT_HASH Record a placeholder checksum. Do not pass TARGETS
# or LIB with this option.
# STAGE_TARGET <t> Hash the installed copy of library or program <t>,
# as `make sbom` does. When the target runs, the whole
# project is installed with DESTDIR into a private
# staging directory under the build tree. The file is
# <t>'s file name in CMAKE_INSTALL_FULL_LIBDIR, or in
# CMAKE_INSTALL_FULL_BINDIR for a program or a Windows
# DLL. The staging directory is removed after the
# driver runs, also when it fails. A DESTDIR in the
# environment does not change the staging, and an
# absolute install directory stays inside it. Do not
# pass LIB with this option.
# VALIDATE Validate the SPDX file with pyspdxtools and write the
# SPDX tag-value file, as `make sbom` does. The
# tag-value file is TV_OUT, or the SPDX path without
# ".json". install-sbom then installs it.
# PYSPDXTOOLS <path> pyspdxtools for VALIDATE (default: find_program).
#
# When python3 is missing, or pyspdxtools is missing with VALIDATE, configure
# does not fail. The target fails with the reason when someone builds it.
#
# USER_SETTINGS <path> Path to wolfssl/wolfcrypt/settings.h. This is the
# generator's pcpp entry point. Also pass
Expand Down Expand Up @@ -102,9 +121,10 @@ get_filename_component(_WOLFSSL_COMPLIANCE_TOOLING_DRIVER
find_package(Python3 COMPONENTS Interpreter)

function(wolfssl_compliance_tooling_add_sbom)
set(_opts NO_ARTIFACT_HASH SOURCE_ONLY NO_INSTALL)
set(_opts NO_ARTIFACT_HASH SOURCE_ONLY NO_INSTALL VALIDATE)
set(_one NAME TARGET_NAME VERSION VERSION_FILE VERSION_MACRO LICENSE
SBOM_GEN GEN_SBOM HOSTCC ROOT LIB USER_SETTINGS OPTIONS_H SETTINGS_H
SBOM_GEN GEN_SBOM HOSTCC ROOT LIB STAGE_TARGET PYSPDXTOOLS
USER_SETTINGS OPTIONS_H SETTINGS_H
DEP_WOLFSSL DEP_WOLFCRYPT DEP_OPENSSL DEP_LIBZ CRYPTO_ONLY
CDX_OUT SPDX_OUT TV_OUT COMPONENT_TYPE DOCUMENT_NAMESPACE
COPYRIGHT_START
Expand All @@ -118,13 +138,26 @@ function(wolfssl_compliance_tooling_add_sbom)
message(FATAL_ERROR "wolfssl_compliance_tooling_add_sbom: NAME is required")
endif()
if(SB_NO_ARTIFACT_HASH)
if(SB_TARGETS OR SB_LIB)
if(SB_TARGETS OR SB_LIB OR SB_STAGE_TARGET)
message(FATAL_ERROR
"wolfssl_compliance_tooling_add_sbom: NO_ARTIFACT_HASH stands "
"alone. Do not pass TARGETS or LIB.")
"alone. Do not pass TARGETS, LIB or STAGE_TARGET.")
endif()
elseif(NOT SB_TARGETS AND NOT SB_LIB AND NOT SB_STAGE_TARGET)
message(FATAL_ERROR
"wolfssl_compliance_tooling_add_sbom: set TARGETS, LIB or STAGE_TARGET")
endif()
if(SB_STAGE_TARGET)
if(SB_LIB)
message(FATAL_ERROR
"wolfssl_compliance_tooling_add_sbom: STAGE_TARGET names the "
"hashed file. Do not pass LIB.")
Comment on lines +151 to +154
endif()
if(NOT TARGET ${SB_STAGE_TARGET})
message(FATAL_ERROR
"wolfssl_compliance_tooling_add_sbom: STAGE_TARGET "
"${SB_STAGE_TARGET} is not a target")
endif()
elseif(NOT SB_TARGETS AND NOT SB_LIB)
message(FATAL_ERROR "wolfssl_compliance_tooling_add_sbom: set TARGETS or LIB")
endif()
if(NOT SB_ROOT)
set(SB_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
Expand Down Expand Up @@ -166,9 +199,46 @@ function(wolfssl_compliance_tooling_add_sbom)
endforeach()
list(REMOVE_DUPLICATES _srcs)

set(_sbom_error "")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conflicts with #51 in sbom.cmake. After the rebase, #51's python3 fallback has to run before the _sbom_error check, and the new sbom-fail, sbom-validate and sbom-with-sde -P paths (L390, L408, L414) need ${_sbom_dir}.

if(NOT Python3_EXECUTABLE)
message(FATAL_ERROR
"wolfssl_compliance_tooling_add_sbom: python3 was not found")
set(_sbom_error
"python3 was not found. Cannot generate the ${SB_NAME} SBOM.")
elseif(SB_VALIDATE AND NOT SB_PYSPDXTOOLS)
find_program(WOLFSSL_COMPLIANCE_TOOLING_PYSPDXTOOLS pyspdxtools)
if(WOLFSSL_COMPLIANCE_TOOLING_PYSPDXTOOLS)
set(SB_PYSPDXTOOLS ${WOLFSSL_COMPLIANCE_TOOLING_PYSPDXTOOLS})
else()
set(_sbom_error
"pyspdxtools was not found (pip install spdx-tools). "
"Cannot validate the ${SB_NAME} SBOM.")
endif()
endif()

if(SB_STAGE_TARGET)
set(_stage_dir "${CMAKE_CURRENT_BINARY_DIR}/_sbom_staging")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reproduced: two STAGE_TARGET calls in one directory built with -j2 failed 5 of 15 runs with "SBOM staging install failed".

get_target_property(_stage_type ${SB_STAGE_TARGET} TYPE)
if(_stage_type STREQUAL "EXECUTABLE" OR
(WIN32 AND _stage_type STREQUAL "SHARED_LIBRARY"))
set(_stage_kind BINDIR)
set(_stage_default bin)
else()
set(_stage_kind LIBDIR)
set(_stage_default lib)
endif()
if(CMAKE_INSTALL_FULL_${_stage_kind})
set(_stage_inst "${CMAKE_INSTALL_FULL_${_stage_kind}}")
elseif(CMAKE_INSTALL_${_stage_kind})
set(_stage_inst "${CMAKE_INSTALL_${_stage_kind}}")
else()
set(_stage_inst "${_stage_default}")
endif()
if(NOT IS_ABSOLUTE "${_stage_inst}")
set(_stage_inst "${CMAKE_INSTALL_PREFIX}/${_stage_inst}")
endif()
# file(INSTALL) drops the drive letter when it prepends DESTDIR.
string(REGEX REPLACE "^[A-Za-z]:" "" _stage_inst "${_stage_inst}")
set(SB_LIB
"${_stage_dir}${_stage_inst}/$<TARGET_FILE_NAME:${SB_STAGE_TARGET}>")
endif()

set(_cmd ${CMAKE_COMMAND} -E env HOSTCC=${SB_HOSTCC}
Expand Down Expand Up @@ -302,15 +372,56 @@ function(wolfssl_compliance_tooling_add_sbom)
# SOURCE_DATE_EPOCH is applied when the target runs. A value set only
# for the build is kept. Git supplies the commit time only when the
# variable is empty. Configure time does not freeze it.
add_custom_target(${SB_TARGET_NAME}
COMMAND ${CMAKE_COMMAND}
-DSBOM_ROOT=${SB_ROOT}
-P "${_WOLFSSL_COMPLIANCE_TOOLING_SBOM_DIR}/sbom-with-sde.cmake"
--
${_cmd}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
VERBATIM
COMMENT "Generating ${SB_NAME} SBOM (CycloneDX 1.6 + SPDX 2.3)")
set(_paths
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_CDX=${SB_CDX_OUT}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_SPDX=${SB_SPDX_OUT}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_TV=${SB_TV_OUT}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_TV_FROM_SPDX=${SB_VALIDATE}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_NAME=${SB_NAME}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_VERSION=${SB_VERSION}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_VERSION_FILE=${SB_VERSION_FILE}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_VERSION_MACRO=${SB_VERSION_MACRO}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_BINDIR=${CMAKE_CURRENT_BINARY_DIR})

if(NOT _sbom_error STREQUAL "")
add_custom_target(${SB_TARGET_NAME}
COMMAND ${CMAKE_COMMAND}
"-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_ERROR=${_sbom_error}"
-P "${_WOLFSSL_COMPLIANCE_TOOLING_SBOM_DIR}/sbom-fail.cmake"
VERBATIM
COMMENT "${SB_NAME} SBOM prerequisites missing")
else()
set(_stage_args "")
if(SB_STAGE_TARGET)
set(_stage_args
-DSBOM_STAGE_DIR=${_stage_dir}
-DSBOM_STAGE_BUILD_DIR=${CMAKE_BINARY_DIR}
-DSBOM_STAGE_CONFIG=$<CONFIG>
-DSBOM_STAGE_LIB=${SB_LIB})
endif()
set(_validate "")
if(SB_VALIDATE)
set(_validate
COMMAND ${CMAKE_COMMAND}
-DWOLFSSL_COMPLIANCE_TOOLING_PYSPDXTOOLS=${SB_PYSPDXTOOLS}
${_paths}
-P "${_WOLFSSL_COMPLIANCE_TOOLING_SBOM_DIR}/sbom-validate.cmake")
endif()
add_custom_target(${SB_TARGET_NAME}
COMMAND ${CMAKE_COMMAND}
-DSBOM_ROOT=${SB_ROOT}
${_stage_args}
-P "${_WOLFSSL_COMPLIANCE_TOOLING_SBOM_DIR}/sbom-with-sde.cmake"
--
${_cmd}
${_validate}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
VERBATIM
COMMENT "Generating ${SB_NAME} SBOM (CycloneDX 1.6 + SPDX 2.3)")
if(SB_STAGE_TARGET)
add_dependencies(${SB_TARGET_NAME} ${SB_STAGE_TARGET})
endif()
endif()

if(NOT SB_NO_INSTALL)
set(_install_depends ${SB_TARGET_NAME})
Expand All @@ -323,6 +434,7 @@ function(wolfssl_compliance_tooling_add_sbom)
CDX "${SB_CDX_OUT}"
SPDX "${SB_SPDX_OUT}"
TV "${SB_TV_OUT}"
TV_FROM_SPDX "${SB_VALIDATE}"
VERSION "${SB_VERSION}"
VERSION_FILE "${SB_VERSION_FILE}"
VERSION_MACRO "${SB_VERSION_MACRO}"
Expand All @@ -339,8 +451,8 @@ endfunction()
# target validates SPDX and writes the tag-value file after the helper
# returns. Pass DEPENDS sbom and TV the tag-value path.
function(wolfssl_compliance_tooling_add_sbom_install)
set(_one NAME DEPENDS INSTALL_DIR CDX SPDX TV VERSION VERSION_FILE
VERSION_MACRO BINDIR INSTALL_TARGET UNINSTALL_TARGET)
set(_one NAME DEPENDS INSTALL_DIR CDX SPDX TV TV_FROM_SPDX VERSION
VERSION_FILE VERSION_MACRO BINDIR INSTALL_TARGET UNINSTALL_TARGET)
cmake_parse_arguments(SI "" "${_one}" "" ${ARGN})

if(NOT SI_NAME)
Expand Down Expand Up @@ -378,6 +490,7 @@ function(wolfssl_compliance_tooling_add_sbom_install)
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_CDX=${SI_CDX}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_SPDX=${SI_SPDX}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_TV=${SI_TV}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_TV_FROM_SPDX=${SI_TV_FROM_SPDX}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_NAME=${SI_NAME}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_VERSION=${SI_VERSION}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_VERSION_FILE=${SI_VERSION_FILE}
Expand All @@ -394,6 +507,7 @@ function(wolfssl_compliance_tooling_add_sbom_install)
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_CDX=${SI_CDX}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_SPDX=${SI_SPDX}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_TV=${SI_TV}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_TV_FROM_SPDX=${SI_TV_FROM_SPDX}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_NAME=${SI_NAME}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_VERSION=${SI_VERSION}
-DWOLFSSL_COMPLIANCE_TOOLING_SBOM_VERSION_FILE=${SI_VERSION_FILE}
Expand Down
Loading
Loading