diff --git a/contrib/bootstrap b/contrib/bootstrap index ec2fdf2d1f5459cb8f980741bd6a974447d6b58a..bf1778767b88d0392d9d83dfeb3aa6602be65378 100755 --- a/contrib/bootstrap +++ b/contrib/bootstrap @@ -311,6 +311,7 @@ Other targets: * make mostlyclean clean everything except source tarballs * make clean clean everything * make package prepare prebuilt packages + * make cyclonedx generate a CycloneDX SBOM file EOF mkdir -p ../tarballs || exit $? diff --git a/contrib/src/cyclonedx.sh b/contrib/src/cyclonedx.sh new file mode 100755 index 0000000000000000000000000000000000000000..8ada2ac6e9149f068f17346a3562ffbe38dfa19d --- /dev/null +++ b/contrib/src/cyclonedx.sh @@ -0,0 +1,85 @@ +#!/bin/bash +# +# Take as input a list of CPE id (string), parse them and output a minimal CycloneDX SBOM file in JSON format +# +# Copyright (C) 2024 Savoir-faire Linux, Inc. + +set -euo pipefail # Enable error checking + + +function main() { + local list_cpe=$1 + local output="common-jami-daemon.cdx.json" + + cat <<EOF > $output +{ + "bomFormat": "CycloneDX", + "specVersion": "1.5", + "serialNumber": "urn:uuid:$(uuidgen)", + "version": 1, + "metadata": { + "timestamp": "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" + }, + "components": [ +EOF + + local already_done=() + local components_writed=0 + + for cpe in $list_cpe; do + # Skip duplicates + # shellcheck disable=SC2076 # CPE is not a regex + if [[ " ${already_done[*]} " =~ " ${cpe} " ]]; then + continue + fi + + # Split CPE v2.3 string to extract vendor, product, and version + IFS=':' read -r -a cpe_parts <<< "$cpe" + # Assuming standard CPE v2.3 format: cpe:2.3:a:vendor:product:version:... + vendor="${cpe_parts[3]}" + product="${cpe_parts[4]}" + version="${cpe_parts[5]}" + + case "${cpe_parts[2]}" in + o) + kind="operating-system" + ;; + h) + kind="device" + ;; + *) + kind="library" + ;; + esac + + if (( components_writed >= 1 )); then + echo " }," >> $output + fi + + cat <<EOF >> $output + { + "type": "$kind", + "bom-ref": "$cpe", + "publisher": "$vendor", + "name": "$product", + "version": "$version", + "cpe": "$cpe" +EOF + + already_done+=("$cpe") + components_writed=$((components_writed + 1)) + done + + if (( components_writed >= 1 )); then + echo " }" >> $output + fi + + cat <<EOF >> $output + ] +} +EOF + + echo "CycloneDX SBOM file generated: $output (contains $components_writed components)" +} + +main "$@" diff --git a/contrib/src/main.mak b/contrib/src/main.mak index 8c0a2fbb4a7261d68cf0528b03438e2540e1849b..b46e85f2dab8191453b20590798a557b3095d714 100644 --- a/contrib/src/main.mak +++ b/contrib/src/main.mak @@ -506,6 +506,9 @@ package: install pprint = @echo ' $(or $(sort $1), None)' | fmt +cyclonedx: + @$(SRC)/cyclonedx.sh "$(PKG_CPE)" + list: @echo All packages: $(call pprint,$(PKGS_ALL))