diff --git a/cyclonedx-lib/src/temurin/sbom/TemurinGenSBOM.java b/cyclonedx-lib/src/temurin/sbom/TemurinGenSBOM.java index 9d1a4308bd..5b16e326e4 100644 --- a/cyclonedx-lib/src/temurin/sbom/TemurinGenSBOM.java +++ b/cyclonedx-lib/src/temurin/sbom/TemurinGenSBOM.java @@ -52,7 +52,7 @@ public static void main(final String[] args) { String compName = null; String description = null; String fileName = null; - String hashes = null; + String hash = null; String name = null; String tool = null; String type = null; @@ -73,8 +73,8 @@ public static void main(final String[] args) { url = args[++i]; } else if (args[i].equals("--comment")) { comment = args[++i]; - } else if (args[i].equals("--hashes")) { - hashes = args[++i]; + } else if (args[i].equals("--hash")) { + hash = args[++i]; } else if (args[i].equals("--compName")) { compName = args[++i]; } else if (args[i].equals("--description")) { @@ -91,8 +91,10 @@ public static void main(final String[] args) { cmd = "addMetadataComponent"; } else if (args[i].equals("--addMetadataProp")) { // MetaData Component --> Property -> name-value cmd = "addMetadataProperty"; - } else if (args[i].equals("--addComponent")) { // Components->Property: will add name-value. + } else if (args[i].equals("--addComponent")) { cmd = "addComponent"; + } else if (args[i].equals("--addComponentHash")) { + cmd = "addComponentHash"; } else if (args[i].equals("--addComponentProp")) { // Components->Property: will add name-value. cmd = "addComponentProp"; } else if (args[i].equals("--addExternalReference")) { @@ -106,22 +108,22 @@ public static void main(final String[] args) { } } switch (cmd) { - case "createNewSBOM": // Creates JSON file + case "createNewSBOM": // Creates JSON file Bom bom = createBom(); writeJSONfile(bom, fileName); break; - case "addMetadata": // Adds Metadata --> name + case "addMetadata": // Adds Metadata --> name bom = addMetadata(fileName); writeJSONfile(bom, fileName); break; - case "addMetadataComponent": // Adds Metadata --> Component--> name + case "addMetadataComponent": // Adds Metadata --> Component --> name bom = addMetadataComponent(fileName, name, type, version, description); writeJSONfile(bom, fileName); break; - case "addMetadataProperty": // Adds MetaData--> Property --> name-value: + case "addMetadataProperty": // Adds MetaData --> Property --> name-value: bom = addMetadataProperty(fileName, name, value); writeJSONfile(bom, fileName); break; @@ -131,23 +133,28 @@ public static void main(final String[] args) { writeJSONfile(bom, fileName); break; - case "addComponent": // Adds Component + case "addComponent": // Adds Components --> Component --> name bom = addComponent(fileName, compName, version, description); writeJSONfile(bom, fileName); break; - case "addComponentProp": // Adds Components --> name-value pairs + case "addComponentHash": // Adds Components --> Component --> hash + bom = addComponentHash(fileName, compName, hash); + writeJSONfile(bom, fileName); + break; + + case "addComponentProp": // Adds Components --> Component --> name-value pairs bom = addComponentProperty(fileName, compName, name, value); writeJSONfile(bom, fileName); break; - case "addExternalReference": // Adds external Reference - bom = addExternalReference(fileName, hashes, url, comment); + case "addExternalReference": // Adds external Reference + bom = addExternalReference(fileName, hash, url, comment); writeJSONfile(bom, fileName); break; - case "addComponentExternalReference": // Adds external Reference to component - bom = addComponentExternalReference(fileName, hashes, url, comment); + case "addComponentExternalReference": // Adds external Reference to component + bom = addComponentExternalReference(fileName, hash, url, comment); writeJSONfile(bom, fileName); break; default: @@ -231,6 +238,17 @@ static Bom addComponent(final String fileName, final String compName, final Stri bom.addComponent(comp); return bom; } + static Bom addComponentHash(final String fileName, final String compName, final String hash) { + Bom bom = readJSONfile(fileName); + List componentArrayList = bom.getComponents(); + for (Component item : componentArrayList) { + if (item.getName().equals(compName)) { + Hash hash1 = new Hash(Hash.Algorithm.SHA_256, hash); + item.addHash(hash1); + } + } + return bom; + } static Bom addComponentProperty(final String fileName, final String compName, final String name, final String value) { // Method to add Component --> Property --> name-value pairs Bom bom = readJSONfile(fileName); List componentArrayList = bom.getComponents(); @@ -244,10 +262,10 @@ static Bom addComponentProperty(final String fileName, final String compName, fi } return bom; } - static Bom addExternalReference(final String fileName, final String hashes, final String url, final String comment) { // Method to store externalReferences: dependency_version_alsa + static Bom addExternalReference(final String fileName, final String hash, final String url, final String comment) { // Method to store externalReferences: dependency_version_alsa Bom bom = readJSONfile(fileName); ExternalReference extRef = new ExternalReference(); - Hash hash1 = new Hash(Hash.Algorithm.SHA3_256, hashes); + Hash hash1 = new Hash(Hash.Algorithm.SHA3_256, hash); extRef.setType(ExternalReference.Type.BUILD_SYSTEM); //required extRef.setUrl(url); // required must be a valid URL with protocal extRef.setComment(comment); @@ -255,10 +273,10 @@ static Bom addExternalReference(final String fileName, final String hashes, fina bom.addExternalReference(extRef); return bom; } - static Bom addComponentExternalReference(final String fileName, final String hashes, final String url, final String comment) { // Method to store externalReferences to store: openjdk_source + static Bom addComponentExternalReference(final String fileName, final String hash, final String url, final String comment) { // Method to store externalReferences to store: openjdk_source Bom bom = readJSONfile(fileName); ExternalReference extRef = new ExternalReference(); - Hash hash1 = new Hash(Hash.Algorithm.SHA3_256, hashes); + Hash hash1 = new Hash(Hash.Algorithm.SHA3_256, hash); Component comp = new Component(); extRef.addHash(hash1); extRef.setUrl(url); diff --git a/sbin/build.sh b/sbin/build.sh index 64dc87e389..8f44b63a6a 100755 --- a/sbin/build.sh +++ b/sbin/build.sh @@ -851,35 +851,6 @@ generateSBoM() { addSBOMMetadataProperty "${javaHome}" "${classpath}" "${sbomJson}" "OS version" "${BUILD_CONFIG[OS_FULL_VERSION]^}" addSBOMMetadataProperty "${javaHome}" "${classpath}" "${sbomJson}" "OS architecture" "${BUILD_CONFIG[OS_ARCHITECTURE]^}" - # Create JDK Component - addSBOMComponent "${javaHome}" "${classpath}" "${sbomJson}" "Eclipse Temurin" "${fullVer}" "${BUILD_CONFIG[BUILD_VARIANT]^} JDK Component" - - # Below add different properties to JDK component - # Add variant as JDK Component Property - addSBOMComponentProperty "${javaHome}" "${classpath}" "${sbomJson}" "Eclipse Temurin" "JDK Variant" "${BUILD_CONFIG[BUILD_VARIANT]^}" - # Add scmRef as JDK Component Property - addSBOMComponentPropertyFromFile "${javaHome}" "${classpath}" "${sbomJson}" "Eclipse Temurin" "SCM Ref" "${BUILD_CONFIG[WORKSPACE_DIR]}/${BUILD_CONFIG[TARGET_DIR]}/metadata/scmref.txt" - # Add OpenJDK source ref commit as JDK Component Property - addSBOMComponentPropertyFromFile "${javaHome}" "${classpath}" "${sbomJson}" "Eclipse Temurin" "OpenJDK Source Commit" "${BUILD_CONFIG[WORKSPACE_DIR]}/${BUILD_CONFIG[TARGET_DIR]}/metadata/openjdkSource.txt" - # Add buildRef as JDK Component Property - addSBOMComponentPropertyFromFile "${javaHome}" "${classpath}" "${sbomJson}" "Eclipse Temurin" "Temurin Build Ref" "${BUILD_CONFIG[WORKSPACE_DIR]}/${BUILD_CONFIG[TARGET_DIR]}/metadata/buildSource.txt" - - # Add build timestamp - addSBOMComponentProperty "${javaHome}" "${classpath}" "${sbomJson}" "Eclipse Temurin" "Build Timestamp" "${BUILD_CONFIG[BUILD_TIMESTAMP]}" - - # Add Tool Summary section from configure.txt - checkingToolSummary - addSBOMComponentPropertyFromFile "${javaHome}" "${classpath}" "${sbomJson}" "Eclipse Temurin" "Build Tools Summary" "${BUILD_CONFIG[WORKSPACE_DIR]}/${BUILD_CONFIG[TARGET_DIR]}/metadata/dependency_tool_sum.txt" - # Add builtConfig JDK Component Property, load as Json string - built_config=$(createConfigToJsonString) - addSBOMComponentProperty "${javaHome}" "${classpath}" "${sbomJson}" "Eclipse Temurin" "Build Config" "${built_config}" - # Add full_version_output JDK Component Property - addSBOMComponentProperty "${javaHome}" "${classpath}" "${sbomJson}" "Eclipse Temurin" "full_version_output" "${fullVerOutput}" - # Add makejdk_any_platform_args JDK Component Property - addSBOMComponentPropertyFromFile "${javaHome}" "${classpath}" "${sbomJson}" "Eclipse Temurin" "makejdk_any_platform_args" "${BUILD_CONFIG[WORKSPACE_DIR]}/config/makejdk-any-platform.args" - # Add make_command_args JDK Component Property - addSBOMComponentPropertyFromFile "${javaHome}" "${classpath}" "${sbomJson}" "Eclipse Temurin" "make_command_args" "${BUILD_CONFIG[WORKSPACE_DIR]}/${BUILD_CONFIG[TARGET_DIR]}/metadata/makeCommandArg.txt" - # Below add build tools into metadata tools if [ "${BUILD_CONFIG[OS_KERNEL_NAME]}" == "linux" ]; then addGLIBCforLinux @@ -911,6 +882,98 @@ generateSBoM() { echo "" } +finishSBoM() { + local javaHome="${1}" + + # classpath to run CycloneDX java app TemurinGenSBOM + CYCLONEDB_JAR_DIR="${CYCLONEDB_DIR}/build/jar" + classpath="${CYCLONEDB_JAR_DIR}/temurin-gen-sbom.jar:${CYCLONEDB_JAR_DIR}/cyclonedx-core-java.jar:${CYCLONEDB_JAR_DIR}/jackson-core.jar:${CYCLONEDB_JAR_DIR}/jackson-dataformat-xml.jar:${CYCLONEDB_JAR_DIR}/jackson-databind.jar:${CYCLONEDB_JAR_DIR}/jackson-annotations.jar:${CYCLONEDB_JAR_DIR}/json-schema.jar:${CYCLONEDB_JAR_DIR}/commons-codec.jar:${CYCLONEDB_JAR_DIR}/commons-io.jar:${CYCLONEDB_JAR_DIR}/github-package-url.jar" + local sbomJson=$(echo "${BUILD_CONFIG[TARGET_FILE_NAME]//-jdk/-sbom}.json") + + # Remove the tarball extension from the name to be used for the SBOM + if [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]]; then + sbomJson="${sbomJson//\.zip/}" + else + sbomJson="${sbomJson//\.tar\.gz/}" + fi + + sbomJson="${BUILD_CONFIG[WORKSPACE_DIR]}"/"${BUILD_CONFIG[TARGET_DIR]}"/"${sbomJson}" + + if [[ "$OSTYPE" == "cygwin" ]] || [[ "$OSTYPE" == "msys" ]]; then + classpath="" + for jarfile in "${CYCLONEDB_JAR_DIR}/temurin-gen-sbom.jar" "${CYCLONEDB_JAR_DIR}/cyclonedx-core-java.jar" \ + "${CYCLONEDB_JAR_DIR}/jackson-core.jar" "${CYCLONEDB_JAR_DIR}/jackson-dataformat-xml.jar" \ + "${CYCLONEDB_JAR_DIR}/jackson-databind.jar" "${CYCLONEDB_JAR_DIR}/jackson-annotations.jar" \ + "${CYCLONEDB_JAR_DIR}/json-schema.jar" "${CYCLONEDB_JAR_DIR}/commons-codec.jar" "${CYCLONEDB_JAR_DIR}/commons-io.jar" \ + "${CYCLONEDB_JAR_DIR}/github-package-url.jar" ; + do + classpath+=$(cygpath -w "${jarfile}")";" + done + sbomJson=$(cygpath -w "${sbomJson}") + javaHome=$(cygpath -w "${javaHome}") + fi + + # Run a series of SBOM API commands to generate the required SBOM + JAVA_LOC="$PRODUCT_HOME/bin/java" + local fullVer=$($JAVA_LOC -XshowSettings:properties -version 2>&1 | grep 'java.runtime.version' | sed 's/^.*= //' | tr -d '\r') + local fullVerOutput=$($JAVA_LOC -version 2>&1) + + components=("JDK" "JRE" "SRC" "STATIC-LIBS" "DEBUGIMAGE" "TESTIMAGE") + for component in "${components[@]}" + do + componentLowerCase=$(echo "${component}" | tr '[:upper:]' '[:lower:]') + echo "${component}" + + local archiveName=$(echo "${BUILD_CONFIG[TARGET_FILE_NAME]}" | sed "s/-jdk/-${componentLowerCase}/") + local archiveFile="${BUILD_CONFIG[WORKSPACE_DIR]}"/"${BUILD_CONFIG[TARGET_DIR]}"/"${archiveName}" + + echo "${archiveFile}" + + if [ ! -f "${archiveFile}" ]; then + continue + else + sha=$(sha256sum "${archiveFile}" | cut -f1 -d' ') + echo "${sha}" + fi + + # Create JDK Component + addSBOMComponent "${javaHome}" "${classpath}" "${sbomJson}" "${archiveName}" "${fullVer}" "${BUILD_CONFIG[BUILD_VARIANT]^} ${component} Component" + + # Add SHA256 hash for the component + addSBOMComponentHash "${javaHome}" "${classpath}" "${sbomJson}" "${archiveName}" "${sha}" + + # Below add different properties to JDK component + # Add variant as JDK Component Property + addSBOMComponentProperty "${javaHome}" "${classpath}" "${sbomJson}" "${archiveName}" "${component} Variant" "${BUILD_CONFIG[BUILD_VARIANT]^}" + # Add scmRef as JDK Component Property + addSBOMComponentPropertyFromFile "${javaHome}" "${classpath}" "${sbomJson}" "${archiveName}" "SCM Ref" "${BUILD_CONFIG[WORKSPACE_DIR]}/${BUILD_CONFIG[TARGET_DIR]}/metadata/scmref.txt" + # Add OpenJDK source ref commit as JDK Component Property + addSBOMComponentPropertyFromFile "${javaHome}" "${classpath}" "${sbomJson}" "${archiveName}" "OpenJDK Source Commit" "${BUILD_CONFIG[WORKSPACE_DIR]}/${BUILD_CONFIG[TARGET_DIR]}/metadata/openjdkSource.txt" + # Add buildRef as JDK Component Property + addSBOMComponentPropertyFromFile "${javaHome}" "${classpath}" "${sbomJson}" "${archiveName}" "Temurin Build Ref" "${BUILD_CONFIG[WORKSPACE_DIR]}/${BUILD_CONFIG[TARGET_DIR]}/metadata/buildSource.txt" + + # Add build timestamp + addSBOMComponentProperty "${javaHome}" "${classpath}" "${sbomJson}" "${archiveName}" "Build Timestamp" "${BUILD_CONFIG[BUILD_TIMESTAMP]}" + + # Add Tool Summary section from configure.txt + checkingToolSummary + addSBOMComponentPropertyFromFile "${javaHome}" "${classpath}" "${sbomJson}" "${archiveName}" "Build Tools Summary" "${BUILD_CONFIG[WORKSPACE_DIR]}/${BUILD_CONFIG[TARGET_DIR]}/metadata/dependency_tool_sum.txt" + # Add builtConfig JDK Component Property, load as Json string + built_config=$(createConfigToJsonString) + addSBOMComponentProperty "${javaHome}" "${classpath}" "${sbomJson}" "${archiveName}" "Build Config" "${built_config}" + # Add full_version_output JDK Component Property + addSBOMComponentProperty "${javaHome}" "${classpath}" "${sbomJson}" "${archiveName}" "full_version_output" "${fullVerOutput}" + # Add makejdk_any_platform_args JDK Component Property + addSBOMComponentPropertyFromFile "${javaHome}" "${classpath}" "${sbomJson}" "${archiveName}" "makejdk_any_platform_args" "${BUILD_CONFIG[WORKSPACE_DIR]}/config/makejdk-any-platform.args" + # Add make_command_args JDK Component Property + addSBOMComponentPropertyFromFile "${javaHome}" "${classpath}" "${sbomJson}" "${archiveName}" "make_command_args" "${BUILD_CONFIG[WORKSPACE_DIR]}/${BUILD_CONFIG[TARGET_DIR]}/metadata/makeCommandArg.txt" + done + + # Print SBOM json + echo "CycloneDX SBOM:" + cat "${sbomJson}" + echo "" +} # Generate build tools info into dependency file checkingToolSummary() { @@ -2044,6 +2107,11 @@ if [[ "${BUILD_CONFIG[ASSEMBLE_EXPLODED_IMAGE]}" == "true" ]]; then setPlistForMacOS addNoticeFile createOpenJDKTarArchive + if [[ "${BUILD_CONFIG[CREATE_SBOM]}" == "true" ]] && [[ -d "${CYCLONEDB_DIR}" ]]; then + javaHome="$(setupAntEnv)" + finishSBoM "${javaHome}" + unset javaHome + fi exit 0 fi @@ -2080,6 +2148,11 @@ if [[ "${BUILD_CONFIG[MAKE_EXPLODED]}" != "true" ]]; then setPlistForMacOS addNoticeFile createOpenJDKTarArchive + if [[ "${BUILD_CONFIG[CREATE_SBOM]}" == "true" ]] && [[ -d "${CYCLONEDB_DIR}" ]]; then + javaHome="$(setupAntEnv)" + finishSBoM "${javaHome}" + unset javaHome + fi fi echo "build.sh : $(date +%T) : All done!" diff --git a/sbin/common/sbom.sh b/sbin/common/sbom.sh index 1cc3d07bd4..f7fe0caf9b 100755 --- a/sbin/common/sbom.sh +++ b/sbin/common/sbom.sh @@ -23,7 +23,7 @@ verifySBOMSignature() { "${javaHome}"/bin/java -cp "${classpath}" temurin.sbom.TemurinSignSBOM --verifySBOMSignature --jsonFile "${jsonFile}" --publicKeyFile "${publicKeyFile}" } -# Set basic SBMO metadata with timestamp, authors, manufacture to ${sbomJson} +# Set basic SBOM metadata with timestamp, authors, manufacture to ${sbomJson} addSBOMMetadata() { local javaHome="${1}" local classpath="${2}" @@ -120,6 +120,17 @@ addSBOMComponentFromFile() { "${javaHome}"/bin/java -cp "${classpath}" temurin.sbom.TemurinGenSBOM --addComponentProp --jsonFile "${jsonFile}" --compName "${compName}" --name "${name}" --value "${value}" } +# Ref: https://cyclonedx.org/docs/1.4/json/#components_items_hashes +# Add the given sha256 hash to the given SBOM Component +addSBOMComponentHash() { + local javaHome="${1}" + local classpath="${2}" + local jsonFile="${3}" + local compName="${4}" + local hash="${5}" + "${javaHome}"/bin/java -cp "${classpath}" temurin.sbom.TemurinGenSBOM --addComponentHash --jsonFile "${jsonFile}" --compName "${compName}" --hash "${hash}" +} + # Ref: https://cyclonedx.org/docs/1.4/json/#components_items_properties # Add the given Property name & value to the given SBOM Component addSBOMComponentProperty() {