diff --git a/.github/linters/.gitleaks.toml b/.github/linters/.gitleaks.toml
new file mode 100644
index 000000000..6012aaeb6
--- /dev/null
+++ b/.github/linters/.gitleaks.toml
@@ -0,0 +1,5 @@
+title = "gitleaks config"
+[allowlist]
+files = [
+ "cyclonedx-lib/dependency_data/dependency_data.properties"
+]
diff --git a/.github/linters/suppressed-java.xml b/.github/linters/suppressed-java.xml
index b9c1a256e..0acb11e80 100644
--- a/.github/linters/suppressed-java.xml
+++ b/.github/linters/suppressed-java.xml
@@ -28,4 +28,5 @@
-
\ No newline at end of file
+
+
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 11a7ffd93..b5fb32a3f 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -35,10 +35,6 @@ jobs:
build_linux:
name: Linux
runs-on: ubuntu-latest
- env:
- ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: 'true'
- container:
- image: ${{ matrix.image }}
strategy:
fail-fast: false
matrix:
@@ -80,24 +76,23 @@ jobs:
variant: bisheng
image: adoptopenjdk/centos7_build_image
steps:
- # pinned at v3 to as Node.js 20.x is not supported on Centos 7
- - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0
+ - uses: actions/checkout@v4
- - name: Build Linux
- run: ./build-farm/make-adopt-build-farm.sh
- env:
- JAVA_TO_BUILD: ${{ matrix.version }}
- ARCHITECTURE: x64
- VARIANT: ${{ matrix.variant }}
- TARGET_OS: ${{ matrix.os }}
- FILENAME: OpenJDK.tar.gz
- # Don't set the OS as we use both linux and alpine-linux
- PLATFORM_CONFIG_LOCATION: adoptium/temurin-build/master/build-farm/platform-specific-configurations
- BUILD_ARGS: --create-sbom
- CONFIGURE_ARGS: --with-native-debug-symbols=none
-
- # pinned at v3 to as Node.js 20.x is not supported on Centos 7
- - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
+ - name: Build Linux within container image "${{ matrix.image }}"
+ run: |
+ docker run --rm -w /home/jenkins -v "$PWD":"/home/jenkins" \
+ -e "JAVA_TO_BUILD=${{ matrix.version }}" \
+ -e "ARCHITECTURE=x64" \
+ -e "VARIANT=${{ matrix.variant }}" \
+ -e "TARGET_OS=${{ matrix.os }}" \
+ -e "FILENAME=OpenJDK.tar.gz" \
+ -e "PLATFORM_CONFIG_LOCATION=adoptium/temurin-build/master/build-farm/platform-specific-configurations" \
+ -e "BUILD_ARGS=--create-sbom" \
+ -e "CONFIGURE_ARGS=--with-native-debug-symbols=none" \
+ "${{ matrix.image }}" \
+ ./build-farm/make-adopt-build-farm.sh
+
+ - uses: actions/upload-artifact@v4
name: Collect and Archive Artifacts
with:
name: ${{matrix.version}}-${{matrix.os}}-${{matrix.variant}}
@@ -110,17 +105,33 @@ jobs:
- name: Set root of jdk image dir
run: |
imageroot=$(find "${HOME}/JDK" -name release -type f)
- echo "TEST_JDK_HOME=$(dirname "${imageroot}")" >> "$GITHUB_ENV"
- - name: Smoke test
- uses: adoptium/run-aqa@6bacb4e732ad546eda1b09665b9067cdc87651f4 # v2
+ # TEST_JDK_HOME needs to be mapped to the docker container /home/jenkins mapping
+ echo "TEST_JDK_HOME=$(dirname "${imageroot}")" | sed "s,${HOME},/home/jenkins," >> "$GITHUB_ENV"
+
+ - name: Checkout aqa-tests repo
+ uses: actions/checkout@v4
with:
- build_list: 'functional/buildAndPackage'
- target: '_extended.functional'
- vendor_testRepos: "${{ github.event.pull_request.head.repo.html_url }}.git"
- vendor_testBranches: "${{ github.head_ref }}"
- vendor_testDirs: "/test/functional"
- # pinned at v3 to as Node.js 20.x is not supported on Centos 7
- - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3
+ repository: adoptium/aqa-tests
+ path: aqa-tests
+ - name: Run Smoke test within container image "${{ matrix.image }}"
+ env:
+ VENDOR_REPOS: ${{ github.event.pull_request.head.repo.html_url }}.git
+ VENDOR_BRANCH: ${{ github.head_ref }}
+ run: |
+ WORK_DIR="${PWD//${HOME}//home/jenkins}"
+ docker run --rm -w /home/jenkins -v "$HOME":"/home/jenkins" \
+ -e "TEST_JDK_HOME=${TEST_JDK_HOME}" \
+ -e "BUILD_LIST=functional/buildAndPackage" \
+ "${{ matrix.image }}" \
+ sh -c "cd ${WORK_DIR}/aqa-tests && \
+ ./get.sh --vendor_repos ${VENDOR_REPOS} \
+ --vendor_branches ${VENDOR_BRANCH} \
+ --vendor_dirs /test/functional && \
+ cd TKG && \
+ make compile && \
+ make _extended.functional"
+
+ - uses: actions/upload-artifact@v4
name: Collect and Archive SmokeTest Results
if: failure()
with:
diff --git a/.github/workflows/ca-cert-updater.yml b/.github/workflows/ca-cert-updater.yml
index 71419dc9f..cfc616c39 100644
--- a/.github/workflows/ca-cert-updater.yml
+++ b/.github/workflows/ca-cert-updater.yml
@@ -35,7 +35,7 @@ jobs:
working-directory: ./security
run: "./mk-ca-bundle.pl"
- - uses: gr2m/create-or-update-pull-request-action@488876a65a2ca38b7eb05e9086166337087f5323 # v1.10.0
+ - uses: gr2m/create-or-update-pull-request-action@b65137ca591da0b9f43bad7b24df13050ea45d1b # v1.10.1
env:
GITHUB_TOKEN: ${{ secrets.ADOPTIUM_TEMURIN_BOT_TOKEN }}
with:
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
index 3522f6533..a23b92de7 100644
--- a/.github/workflows/codeql.yml
+++ b/.github/workflows/codeql.yml
@@ -58,7 +58,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
- uses: github/codeql-action/init@396bb3e45325a47dd9ef434068033c6d5bb0d11a # v3.27.3
+ uses: github/codeql-action/init@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@@ -68,7 +68,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
- uses: github/codeql-action/autobuild@396bb3e45325a47dd9ef434068033c6d5bb0d11a # v3.27.3
+ uses: github/codeql-action/autobuild@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
# âšī¸ Command-line programs to run using the OS shell.
# đ See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@@ -81,6 +81,6 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@396bb3e45325a47dd9ef434068033c6d5bb0d11a # v3.27.3
+ uses: github/codeql-action/analyze@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v3.27.5
with:
category: "/language:${{matrix.language}}"
diff --git a/.github/workflows/ossf-scorecard.yml b/.github/workflows/ossf-scorecard.yml
index 64e2de24c..bcb2d44cb 100644
--- a/.github/workflows/ossf-scorecard.yml
+++ b/.github/workflows/ossf-scorecard.yml
@@ -46,6 +46,6 @@ jobs:
name: SARIF file
path: results.sarif
retention-days: 5
- - uses: github/codeql-action/upload-sarif@396bb3e45325a47dd9ef434068033c6d5bb0d11a # v2.13.4
+ - uses: github/codeql-action/upload-sarif@f09c1c0a94de965c15400f5634aa42fac8fb8f88 # v2.13.4
with:
sarif_file: results.sarif
diff --git a/.github/workflows/testsbom.yml b/.github/workflows/testcyclonedx.yml
similarity index 52%
rename from .github/workflows/testsbom.yml
rename to .github/workflows/testcyclonedx.yml
index 073411098..f4f5703d9 100644
--- a/.github/workflows/testsbom.yml
+++ b/.github/workflows/testcyclonedx.yml
@@ -1,5 +1,5 @@
# ********************************************************************************
-# Copyright (c) 2023 Contributors to the Eclipse Foundation
+# Copyright (c) 2023, 2024 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) with this work for additional
# information regarding copyright ownership.
@@ -12,7 +12,7 @@
# ********************************************************************************
---
-name: TestSBOM
+name: TestCycloneDX
on:
pull_request:
@@ -30,21 +30,21 @@ permissions:
contents: read
jobs:
- test_sbom_gen:
- name: gen_sbom
+ test_cyclonedx_gen:
+ name: gen_cyclonedx
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- # Build with jdk8 to ensure TemurinGenSBOM meets min compatibility
+ # Build with jdk8 to ensure TemurinGen* meets min compatibility
- uses: actions/setup-java@8df1039502a15bceb9433410b1a100fbe190c53b # v4.5.0
id: setup-java
with:
java-version: 8
distribution: 'temurin'
- - name: Build TemurinGenSBOM.java
+ - name: Build TemurinGenSBOM.java and TemurinGenCDXA.java
run: |
ant -noinput -buildfile cyclonedx-lib/build.xml clean
ant -noinput -buildfile cyclonedx-lib/build.xml build
@@ -52,8 +52,27 @@ jobs:
- name: Run TemurinGenSBOM Unit test
run: ant -noinput -buildfile cyclonedx-lib/build.xml run
+ - name: Run TemurinGenCDXA Unit test
+ run: ant -noinput -buildfile cyclonedx-lib/build.xml runCDXA
+
+ - name: Validate generated SBOM and CDXA documents using cyclonedx-cli validate
+ run: |
+ curl -L -O https://github.com/CycloneDX/cyclonedx-cli/releases/latest/download/cyclonedx-linux-x64
+ chmod +x cyclonedx-linux-x64
+ ./cyclonedx-linux-x64 validate --input-file cyclonedx-lib/build/testSBOM.json --fail-on-errors --input-version v1_6
+ ./cyclonedx-linux-x64 validate --input-file cyclonedx-lib/build/testSBOM.xml --fail-on-errors --input-version v1_6
+ ./cyclonedx-linux-x64 validate --input-file cyclonedx-lib/build/testCDXA.json --fail-on-errors --input-version v1_6
+ ./cyclonedx-linux-x64 validate --input-file cyclonedx-lib/build/testCDXA.xml --fail-on-errors --input-version v1_6
+
- uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
name: Collect and Archive TemurinGenSBOM Artifacts
with:
name: testSBOM
- path: cyclonedx-lib/build/testSBOM.json
+ path: cyclonedx-lib/build/testSBOM.*
+
+ - uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
+ name: Collect and Archive TemurinGenCDXA Artifacts
+ with:
+ name: testCDXA
+ path: cyclonedx-lib/build/testCDXA.*
+
diff --git a/RELEASING.md b/RELEASING.md
index 5c6ec42db..c17e36ea6 100644
--- a/RELEASING.md
+++ b/RELEASING.md
@@ -149,7 +149,7 @@ flowchart TD
-Disable nightly testing so the release builds aren't delayed by any nightly test runs (set `enableTests : false` in [defaults.json](https://github.com/adoptium/ci-jenkins-pipelines/blob/master/pipelines/defaults.json)). Ensure the build pipeline generator job runs successfully (), and the flag is disabled by bringing up the Build pipeline job and check the `enableTests` checkbox is unticked.
+Scheduled pipeline Testing is automatically disabled from the Saturday prior to "release Tuesday", to the Sunday after, see: https://github.com/adoptium/ci-jenkins-pipelines/blob/5bd79eb1d95a033c4ee364a8f9fcc270ad653178/pipelines/build/common/trigger_beta_build.groovy#L51
Add a banner to the website to indicate that the releases are coming in the near future ([Example Changes](https://github.com/adoptium/adoptium.net/blob/main/src/components/Banner.tsx)).
diff --git a/SmokeTesting.md b/SmokeTesting.md
index f3179a09e..a57b0f26a 100644
--- a/SmokeTesting.md
+++ b/SmokeTesting.md
@@ -7,8 +7,9 @@ These are the general steps to execute the Smoke Tests found in[/test/functional
1. export TEST_JDK_HOME=/someLocation // set test JDK home. On windows, the windows path format is expected. (i.e., TEST_JDK_HOME=C:\someLocation )
1. git clone [https://github.com/adoptium/aqa-tests.git](https://github.com/adoptium/aqa-tests) to /testLocation
1. cd aqa-tests
-1. ./get.sh
+1. ./get.sh --vendor_repos https://github.com/adoptium/temurin-build --vendor_branches master --vendor_dirs /test/functional
+1. ( When running get.sh ensure the vendor parameters are passed correctly, the above example shows how to run the smoke tests contained within the temurin-build repository )
1. cd TKG
-1. Export environment variables suitable for the SDK under test and for the test materials being used (i.e., export BUILD_LIST=functional/buildAndPackage, VENDOR_TEST_REPOS=https://github.com/adoptium/temurin-build, VENDOR_TEST_BRANCHES=master, VENDOR_TEST_DIRS=/test/functional )
+1. Export environment variables suitable for the SDK under test and for the test materials being used (i.e., export BUILD_LIST=functional/buildAndPackage, this value details which test material that should be compiled.
1. make compile // fetches test material and compiles it, based on build.xml files in the test directories
1. make _extended.functional // executes the test target (can be test group, level, level.group or specific test). i.e., openjdk (all tests in openjdk group), sanity.functional (all functional tests labelled at sanity level), or in the case of smoke tests which are all tagged to belong to level=extended and group=functional, we use `_extended.functional` and because we have limited BUILD_LIST to the directory where the smoke test material lives, we will only run tests from that directory tagged as extended.functional.
diff --git a/cyclonedx-lib/build.xml b/cyclonedx-lib/build.xml
index f026a2611..f4e11f65c 100644
--- a/cyclonedx-lib/build.xml
+++ b/cyclonedx-lib/build.xml
@@ -30,7 +30,7 @@
-
+
@@ -42,8 +42,11 @@
+
+
+
@@ -67,7 +70,7 @@
-
+
@@ -114,11 +117,23 @@
+
+
+
+
-
+
+
+
+
+
+
+
+
+
@@ -134,11 +149,16 @@
-
+
+
+
+
+
+
@@ -179,9 +199,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -193,6 +274,7 @@
+
@@ -333,7 +415,7 @@
-
+
@@ -353,7 +435,7 @@
-
+
@@ -417,7 +499,7 @@
-
+
@@ -429,7 +511,7 @@
-
+
@@ -476,6 +558,289 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/cyclonedx-lib/dependency_data/dependency_data.properties b/cyclonedx-lib/dependency_data/dependency_data.properties
index 4b5607d50..cb2d15487 100644
--- a/cyclonedx-lib/dependency_data/dependency_data.properties
+++ b/cyclonedx-lib/dependency_data/dependency_data.properties
@@ -21,11 +21,14 @@ commons-codec.jar=commons-codec-${commons-codec.version}.jar
commons-collections4.version=4.4
commons-collections4.sha256=1df8b9430b5c8ed143d7815e403e33ef5371b2400aadbe9bda0883762e0846d1
commons-collections4.jar=commons-collections4-${commons-collections4.version}.jar
+commons-lang3.version=3.17.0
+commons-lang3.sha256=6ee731df5c8e5a2976a1ca023b6bb320ea8d3539fbe64c8a1d5cb765127c33b4
+commons-lang3.jar=commons-lang3-${commons-lang3.version}.jar
commons-io.version=2.16.1
commons-io.sha256=f41f7baacd716896447ace9758621f62c1c6b0a91d89acee488da26fc477c84f
commons-io.jar=commons-io-${commons-io.version}.jar
-cyclonedx-core-java.version=9.0.5
-cyclonedx-core-java.sha256=9474c73a81d9be6206367d357a3449e03e70c69bc672d82be04f15806ef170fa
+cyclonedx-core-java.version=9.1.0
+cyclonedx-core-java.sha256=a911ee5e5ebdabc2b2c08d08f9c92c673c21965ee1b982f40fc166d80f1eb088
cyclonedx-core-java.jar=cyclonedx-core-java-${cyclonedx-core-java.version}.jar
github-package-url.version=1.5.0
github-package-url.sha256=e45551727707acc0c56ac62d56964332ea0f138d6cc3656d988b9369150f5247
@@ -45,10 +48,17 @@ jackson-dataformat-xml.jar=jackson-dataformat-xml-${jackson-dataformat-xml.versi
json-schema-validator.version=1.5.1
json-schema-validator.sha256=de015f79d4a63d22c002bad76bb30c039cafa205465eef8770e2c6b85880ded7
json-schema-validator.jar=json-schema-validator-${json-schema-validator.version}.jar
+stax2-api.version=4.2.2
+stax2-api.sha256=a61c48d553efad78bc01fffc4ac528bebbae64cbaec170b2a5e39cf61eb51abe
+stax2-api.jar=stax2-api-${stax2-api.version}.jar
+woodstox-core.version=7.1.0
+woodstox-core.sha256=81266920a1cdc47306a8a2b4726c99ec89b3fbf31c2470e4f5e477d9d857ca9f
+woodstox-core.jar=woodstox-core-${woodstox-core.version}.jar
# Download URLs
commons-codec.url=${maven.central.repo}/commons-codec/commons-codec/${commons-codec.version}/${commons-codec.jar}
commons-collections4.url=${maven.central.repo}/org/apache/commons/commons-collections4/${commons-collections4.version}/${commons-collections4.jar}
+commons-lang3.url=${maven.central.repo}/org/apache/commons/commons-lang3/${commons-lang3.version}/${commons-lang3.jar}
commons-io.url=${maven.central.repo}/commons-io/commons-io/${commons-io.version}/${commons-io.jar}
cyclonedx-core-java.url=${maven.central.repo}/org/cyclonedx/cyclonedx-core-java/${cyclonedx-core-java.version}/${cyclonedx-core-java.jar}
github-package-url.url=${maven.central.repo}/com/github/package-url/packageurl-java/${github-package-url.version}/${github-package-url.jar}
@@ -57,4 +67,6 @@ jackson-core.url=${maven.central.repo}/com/fasterxml/jackson/core/jackson-core/$
jackson-databind.url=${maven.central.repo}/com/fasterxml/jackson/core/jackson-databind/${jackson-databind.version}/${jackson-databind.jar}
jackson-dataformat-xml.url=${maven.central.repo}/com/fasterxml/jackson/dataformat/jackson-dataformat-xml/${jackson-dataformat-xml.version}/${jackson-dataformat-xml.jar}
json-schema-validator.url=${maven.central.repo}/com/networknt/json-schema-validator/${json-schema-validator.version}/${json-schema-validator.jar}
+stax2-api.url=${maven.central.repo}/org/codehaus/woodstox/stax2-api/${stax2-api.version}/${stax2-api.jar}
+woodstox-core.url=${maven.central.repo}/com/fasterxml/woodstox/woodstox-core/${woodstox-core.version}/${woodstox-core.jar}
diff --git a/cyclonedx-lib/sign_src/TemurinSignSBOM.java b/cyclonedx-lib/sign_src/TemurinSignSBOM.java
index 14784fc76..d9d35f105 100644
--- a/cyclonedx-lib/sign_src/TemurinSignSBOM.java
+++ b/cyclonedx-lib/sign_src/TemurinSignSBOM.java
@@ -60,7 +60,7 @@ private TemurinSignSBOM() {
* @param args Arguments for sbom operation.
*/
public static void main(final String[] args) {
- String cmd = null;
+ String cmd = "";
String privateKeyFile = null;
String publicKeyFile = null;
String fileName = null;
@@ -95,6 +95,8 @@ public static void main(final String[] args) {
} else if (cmd.equals("verifySignature")) {
success = verifySignature(fileName, publicKeyFile); // set success to the result of verifySignature
System.out.println("Signature verification result: " + (success ? "Valid" : "Invalid"));
+ } else {
+ System.out.println("Please enter a command.");
}
// Set success to true only when the operation is completed successfully.
diff --git a/cyclonedx-lib/src/temurin/sbom/TemurinGenCDXA.java b/cyclonedx-lib/src/temurin/sbom/TemurinGenCDXA.java
new file mode 100644
index 000000000..a1f02c0f1
--- /dev/null
+++ b/cyclonedx-lib/src/temurin/sbom/TemurinGenCDXA.java
@@ -0,0 +1,336 @@
+/*
+ * ********************************************************************************
+ * Copyright (c) 2024 Contributors to the Eclipse Foundation
+ *
+ * See the NOTICE file(s) with this work for additional
+ * information regarding copyright ownership.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Apache Software License 2.0
+ * which is available at https://www.apache.org/licenses/LICENSE-2.0.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ********************************************************************************
+ */
+
+package temurin.sbom;
+
+import org.cyclonedx.exception.GeneratorException;
+import org.cyclonedx.generators.json.BomJsonGenerator;
+import org.cyclonedx.generators.xml.BomXmlGenerator;
+import org.cyclonedx.model.Bom;
+import org.cyclonedx.model.Component;
+import org.cyclonedx.model.ExternalReference;
+import org.cyclonedx.model.Hash;
+import org.cyclonedx.model.OrganizationalEntity;
+import org.cyclonedx.model.attestation.Declarations;
+import org.cyclonedx.model.attestation.Assessor;
+import org.cyclonedx.model.attestation.Attestation;
+import org.cyclonedx.model.attestation.AttestationMap;
+import org.cyclonedx.model.attestation.Claim;
+import org.cyclonedx.model.attestation.affirmation.Affirmation;
+import org.cyclonedx.model.attestation.affirmation.Signatory;
+import org.cyclonedx.model.attestation.Targets;
+import org.cyclonedx.parsers.JsonParser;
+import org.cyclonedx.parsers.XmlParser;
+import org.cyclonedx.Version;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.util.List;
+import java.util.LinkedList;
+import java.util.UUID;
+
+/**
+ * Command line tool to construct a CycloneDX CDXA.
+ */
+public final class TemurinGenCDXA {
+
+ private static boolean verbose = false;
+ private static boolean useJson = false;
+
+ // Valid predicates
+ enum CDXAPredicate {
+ VERIFIED_REPRODUCIBLE_BUILD
+ };
+
+ private TemurinGenCDXA() {
+ }
+
+ /**
+ * Main entry.
+ * @param args Arguments for operation.
+ */
+ public static void main(final String[] args) {
+ String cmd = "";
+ String fileName = null;
+ String attestingOrgName = null;
+ String predicate = null;
+ String targetName = null;
+ String targetUrl = null;
+ String targetHash = null;
+ String affirmationStmt = null;
+ String affirmationWebsite = null;
+ boolean thirdParty = true;
+
+ for (int i = 0; i < args.length; i++) {
+ if (args[i].equals("--jsonFile")) {
+ fileName = args[++i];
+ useJson = true;
+ } else if (args[i].equals("--xmlFile")) {
+ fileName = args[++i];
+ useJson = false;
+ } else if (args[i].equals("--attesting-org-name")) {
+ attestingOrgName = args[++i];
+ } else if (args[i].equals("--predicate")) {
+ predicate = args[++i];
+ } else if (args[i].equals("--target-name")) {
+ targetName = args[++i];
+ } else if (args[i].equals("--target-url")) {
+ targetUrl = args[++i];
+ } else if (args[i].equals("--target-sha256-hash")) {
+ targetHash = args[++i];
+ } else if (args[i].equals("--affirmation-stmt")) {
+ affirmationStmt = args[++i];
+ } else if (args[i].equals("--affirmation-website")) {
+ affirmationWebsite = args[++i];
+ } else if (args[i].equals("--not-third-party")) {
+ thirdParty = false;
+ } else if (args[i].equals("--createNewCDXA")) {
+ cmd = "createCDXA";
+ } else if (args[i].equals("--verbose")) {
+ verbose = true;
+ }
+ }
+
+ switch (cmd) {
+ case "createCDXA": // Create a new CDXA json file
+ Bom bom = createCdxa(fileName, attestingOrgName, predicate, targetName, targetUrl, targetHash, affirmationStmt, affirmationWebsite, thirdParty);
+ if (bom != null) {
+ writeFile(bom, fileName);
+ } else {
+ System.exit(1);
+ }
+ break;
+
+ default:
+ System.out.println("Please enter a command.");
+ System.exit(1);
+ }
+ }
+
+ static Bom createCdxa(final String fileName, final String attestingOrgName, final String predicate,
+ final String targetName, final String targetUrl, final String targetHash,
+ final String affirmationStmt, final String affirmationWebsite, final boolean thirdParty) {
+ // Validate inputs
+ boolean validInput = true;
+ if (fileName == null) {
+ System.out.println("--xmlFile|--jsonFile not specified");
+ validInput = false;
+ }
+ if (attestingOrgName == null) {
+ System.out.println("--attesting-org-name not specified");
+ validInput = false;
+ }
+ if (predicate == null) {
+ System.out.println("--predicate not specified"); validInput = false;
+ } else {
+ boolean validPred = false;
+ for (CDXAPredicate validPredicate : CDXAPredicate.values()) {
+ if (validPredicate.name().equals(predicate)) {
+ validPred = true;
+ break;
+ }
+ }
+ if (!validPred) {
+ System.out.println("--predicate " + predicate + " not a valid value");
+ validInput = false;
+ }
+ }
+ if (targetName == null) {
+ System.out.println("--target-name not specified");
+ validInput = false;
+ }
+ if (targetUrl == null) {
+ System.out.println("--target-url not specified");
+ validInput = false;
+ }
+ if (targetHash == null) {
+ System.out.println("--target-sha256-hash not specified");
+ validInput = false;
+ }
+ if (affirmationStmt == null) {
+ System.out.println("--affirmation-stmt not specified");
+ validInput = false;
+ }
+ if (affirmationWebsite == null) {
+ System.out.println("--affirmation-website not specified");
+ validInput = false;
+ }
+ if (!validInput) {
+ return null;
+ }
+
+ Declarations declarations = new Declarations();
+ Assessor assessor = new Assessor();
+ Claim claim = new Claim();
+ Targets targets = new Targets();
+ Affirmation affirmation = new Affirmation();
+ Signatory signatory = new Signatory();
+ Attestation attestation = new Attestation();
+ AttestationMap attestationMap = new AttestationMap();
+
+ final String targetJdkBomRef = "target-jdk-1";
+ final String assessorBomRef = "assessor-1";
+ final String claimBomRef = "claim-1";
+
+ // External reference to the target JDK
+ ExternalReference extRef = new ExternalReference();
+ Hash hash1 = new Hash(Hash.Algorithm.SHA_256, targetHash);
+ extRef.addHash(hash1);
+ extRef.setUrl(targetUrl);
+ extRef.setType(ExternalReference.Type.DISTRIBUTION);
+
+ // Target JDK Component
+ Component targetJDK = new Component();
+ targetJDK.setType(Component.Type.APPLICATION);
+ targetJDK.setName(targetName);
+ targetJDK.addExternalReference(extRef);
+ targetJDK.setBomRef(targetJdkBomRef);
+ List components = new LinkedList();
+ components.add(targetJDK);
+ targets.setComponents(components);
+ declarations.setTargets(targets);
+
+ // Assessor
+ assessor.setThirdParty(thirdParty);
+ OrganizationalEntity org = new OrganizationalEntity();
+ org.setName(attestingOrgName);
+ assessor.setOrganization(org);
+ assessor.setBomRef(assessorBomRef);
+ List assessors = new LinkedList();
+ assessors.add(assessor);
+ declarations.setAssessors(assessors);
+
+ // Claim
+ claim.setPredicate(predicate);
+ claim.setTarget(targetJDK.getBomRef());
+ claim.setBomRef(claimBomRef);
+ List claims = new LinkedList();
+ claims.add(claim);
+ declarations.setClaims(claims);
+
+ // Affirmation
+ affirmation.setStatement(affirmationStmt);
+ signatory.setOrganization(org);
+ ExternalReference orgExtRef = new ExternalReference();
+ orgExtRef.setUrl(affirmationWebsite);
+ orgExtRef.setType(ExternalReference.Type.WEBSITE);
+ signatory.setExternalReference(orgExtRef);
+ List signatories = new LinkedList();
+ signatories.add(signatory);
+ affirmation.setSignatories(signatories);
+ declarations.setAffirmation(affirmation);
+
+ // Construct the Attestation
+ attestation.setSummary("Eclipse Temurin Attestation");
+ attestation.setAssessor(assessor.getBomRef());
+ List claimsList = new LinkedList();
+ claimsList.add(claim.getBomRef());
+ attestationMap.setClaims(claimsList);
+ List attestationMaps = new LinkedList();
+ attestationMaps.add(attestationMap);
+ attestation.setMap(attestationMaps);
+ List attestations = new LinkedList();
+ attestations.add(attestation);
+ declarations.setAttestations(attestations);
+
+ // Create CDXA Bom
+ Bom cdxa = new Bom();
+ cdxa.setSerialNumber("urn:uuid:" + UUID.randomUUID());
+ cdxa.setDeclarations(declarations);
+
+ return cdxa;
+ }
+
+ static String generateBomJson(final Bom bom) throws GeneratorException {
+ // Use schema v16: https://cyclonedx.org/schema/bom-1.6.schema.json
+ BomJsonGenerator bomGen = new BomJsonGenerator(bom, Version.VERSION_16);
+ String json = bomGen.toJsonString();
+ return json;
+ }
+
+ static String generateBomXml(final Bom bom) throws GeneratorException {
+ BomXmlGenerator bomGen = new BomXmlGenerator(bom, Version.VERSION_16);
+ String xml = bomGen.toXmlString();
+ return xml;
+ }
+
+ // Writes the BOM object to the specified type of file
+ static void writeFile(final Bom bom, final String fileName) {
+ if (useJson) {
+ writeJSONfile(bom, fileName);
+ } else {
+ writeXMLfile(bom, fileName);
+ }
+ }
+
+ // Writes the BOM object to the specified JSON file.
+ static void writeJSONfile(final Bom bom, final String fileName) {
+ FileWriter file;
+ try {
+ String json = generateBomJson(bom);
+
+ file = new FileWriter(fileName);
+ file.write(json);
+ file.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ // Writes the BOM object to the specified XML file.
+ static void writeXMLfile(final Bom bom, final String fileName) {
+ FileWriter file;
+ try {
+ String xml = generateBomXml(bom);
+
+ file = new FileWriter(fileName);
+ file.write(xml);
+ file.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
+ // Returns a parsed BOM object from the specified file.
+ static Bom readJSONfile(final String fileName) {
+ Bom bom = null;
+ try {
+ FileReader reader = new FileReader(fileName);
+ JsonParser parser = new JsonParser();
+ bom = parser.parse(reader);
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ } finally {
+ return bom;
+ }
+ }
+
+ // Returns a parsed BOM object from the specified file.
+ static Bom readXMLfile(final String fileName) {
+ Bom bom = null;
+ try {
+ FileReader reader = new FileReader(fileName);
+ XmlParser parser = new XmlParser();
+ bom = parser.parse(reader);
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ } finally {
+ return bom;
+ }
+ }
+}
diff --git a/cyclonedx-lib/src/temurin/sbom/TemurinGenSBOM.java b/cyclonedx-lib/src/temurin/sbom/TemurinGenSBOM.java
index 639ed6737..4533a9c37 100644
--- a/cyclonedx-lib/src/temurin/sbom/TemurinGenSBOM.java
+++ b/cyclonedx-lib/src/temurin/sbom/TemurinGenSBOM.java
@@ -17,9 +17,9 @@
import org.cyclonedx.exception.GeneratorException;
import org.cyclonedx.generators.json.BomJsonGenerator;
+import org.cyclonedx.generators.xml.BomXmlGenerator;
import org.cyclonedx.model.Bom;
import org.cyclonedx.model.Component;
-import org.cyclonedx.model.ExternalReference;
import org.cyclonedx.model.formulation.Formula;
import org.cyclonedx.model.Hash;
import org.cyclonedx.model.Metadata;
@@ -28,12 +28,14 @@
import org.cyclonedx.model.Property;
import org.cyclonedx.model.Tool;
import org.cyclonedx.parsers.JsonParser;
+import org.cyclonedx.parsers.XmlParser;
import org.cyclonedx.Version;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.Collections;
import java.util.List;
import java.util.LinkedList;
+import java.util.UUID;
/**
* Command line tool to construct a CycloneDX SBOM.
@@ -41,6 +43,7 @@
public final class TemurinGenSBOM {
private static boolean verbose = false;
+ private static boolean useJson = false;
private TemurinGenSBOM() {
}
@@ -50,7 +53,7 @@ private TemurinGenSBOM() {
* @param args Arguments for sbom operation.
*/
public static void main(final String[] args) {
- String cmd = null;
+ String cmd = "";
String comment = null;
String compName = null;
String formulaName = null;
@@ -67,6 +70,10 @@ public static void main(final String[] args) {
for (int i = 0; i < args.length; i++) {
if (args[i].equals("--jsonFile")) {
fileName = args[++i];
+ useJson = true;
+ } else if (args[i].equals("--xmlFile")) {
+ fileName = args[++i];
+ useJson = false;
} else if (args[i].equals("--version")) {
version = args[++i];
} else if (args[i].equals("--name")) {
@@ -120,69 +127,60 @@ public static void main(final String[] args) {
}
}
switch (cmd) {
- case "createNewSBOM": // Creates JSON file
+ case "createNewSBOM": // Creates new SBOM
Bom bom = createBom();
- writeJSONfile(bom, fileName);
+ writeFile(bom, fileName);
break;
case "addMetadata": // Adds Metadata --> name
bom = addMetadata(fileName);
- writeJSONfile(bom, fileName);
+ writeFile(bom, fileName);
break;
case "addMetadataComponent": // Adds Metadata --> Component --> name
bom = addMetadataComponent(fileName, name, type, version, description);
- writeJSONfile(bom, fileName);
+ writeFile(bom, fileName);
break;
case "addMetadataProperty": // Adds MetaData --> Property --> name-value:
bom = addMetadataProperty(fileName, name, value);
- writeJSONfile(bom, fileName);
+ writeFile(bom, fileName);
break;
case "addFormulation": // Adds Formulation --> name
bom = addFormulation(fileName, formulaName);
- writeJSONfile(bom, fileName);
+ writeFile(bom, fileName);
break;
case "addFormulationComp": // Adds Formulation --> Component--> name
bom = addFormulationComp(fileName, formulaName, name, type);
- writeJSONfile(bom, fileName);
+ writeFile(bom, fileName);
break;
case "addFormulationCompProp": // Adds Formulation --> Component -> name-value:
bom = addFormulationCompProp(fileName, formulaName, compName, name, value);
- writeJSONfile(bom, fileName);
+ writeFile(bom, fileName);
break;
case "addMetadataTools":
bom = addMetadataTools(fileName, tool, version);
- writeJSONfile(bom, fileName);
+ writeFile(bom, fileName);
break;
case "addComponent": // Adds Components --> Component --> name
bom = addComponent(fileName, compName, version, description);
- writeJSONfile(bom, fileName);
+ writeFile(bom, fileName);
break;
case "addComponentHash": // Adds Components --> Component --> hash
bom = addComponentHash(fileName, compName, hash);
- writeJSONfile(bom, fileName);
+ writeFile(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, hash, url, comment);
- writeJSONfile(bom, fileName);
+ writeFile(bom, fileName);
break;
- case "addComponentExternalReference": // Adds external Reference to component
- bom = addComponentExternalReference(fileName, hash, url, comment);
- writeJSONfile(bom, fileName);
- break;
default:
System.out.println("Please enter a command.");
}
@@ -194,12 +192,13 @@ public static void main(final String[] args) {
*/
static Bom createBom() {
Bom bom = new Bom();
+ bom.setSerialNumber("urn:uuid:" + UUID.randomUUID());
return bom;
}
// Method to store Metadata --> name.
static Bom addMetadata(final String fileName) {
- Bom bom = readJSONfile(fileName);
+ Bom bom = readFile(fileName);
Metadata meta = new Metadata();
OrganizationalEntity org = new OrganizationalEntity();
org.setName("Eclipse Foundation");
@@ -213,7 +212,7 @@ static Bom addMetadata(final String fileName) {
}
static Bom addMetadataComponent(final String fileName, final String name, final String type, final String version, final String description) {
- Bom bom = readJSONfile(fileName);
+ Bom bom = readFile(fileName);
Metadata meta = new Metadata();
Component comp = new Component();
Component.Type compType = Component.Type.FRAMEWORK;
@@ -235,7 +234,7 @@ static Bom addMetadataComponent(final String fileName, final String name, final
// Method to store Metadata --> Properties List --> name-values.
static Bom addMetadataProperty(final String fileName, final String name, final String value) {
- Bom bom = readJSONfile(fileName);
+ Bom bom = readFile(fileName);
Metadata meta = new Metadata();
Property prop1 = new Property();
meta = bom.getMetadata();
@@ -247,7 +246,7 @@ static Bom addMetadataProperty(final String fileName, final String name, final S
}
static Bom addMetadataTools(final String fileName, final String toolName, final String version) {
- Bom bom = readJSONfile(fileName);
+ Bom bom = readFile(fileName);
Metadata meta = new Metadata();
Tool tool = new Tool();
meta = bom.getMetadata();
@@ -260,7 +259,7 @@ static Bom addMetadataTools(final String fileName, final String toolName, final
// Method to store Component --> name & single name-value pair.
static Bom addComponent(final String fileName, final String compName, final String version, final String description) {
- Bom bom = readJSONfile(fileName);
+ Bom bom = readFile(fileName);
Component comp = new Component();
comp.setName(compName);
comp.setVersion(version);
@@ -274,7 +273,7 @@ static Bom addComponent(final String fileName, final String compName, final Stri
}
static Bom addComponentHash(final String fileName, final String compName, final String hash) {
- Bom bom = readJSONfile(fileName);
+ Bom bom = readFile(fileName);
List componentArrayList = bom.getComponents();
for (Component item : componentArrayList) {
if (item.getName().equals(compName)) {
@@ -287,7 +286,7 @@ static Bom addComponentHash(final String fileName, final String compName, final
// Method to add Component --> Property --> name-value pairs.
static Bom addComponentProperty(final String fileName, final String compName, final String name, final String value) {
- Bom bom = readJSONfile(fileName);
+ Bom bom = readFile(fileName);
List componentArrayList = bom.getComponents();
for (Component item : componentArrayList) {
if (item.getName().equals(compName)) {
@@ -300,36 +299,8 @@ static Bom addComponentProperty(final String fileName, final String compName, fi
return bom;
}
- // Method to store externalReferences: dependency_version_alsa.
- static Bom addExternalReference(final String fileName, final String hash, final String url, final String comment) {
- Bom bom = readJSONfile(fileName);
- ExternalReference extRef = new ExternalReference();
- 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 protocol
- extRef.setComment(comment);
- extRef.addHash(hash1);
- bom.addExternalReference(extRef);
- return bom;
- }
-
- // Method to store externalReferences to store: openjdk_source.
- static Bom addComponentExternalReference(final String fileName, final String hash, final String url, final String comment) {
- Bom bom = readJSONfile(fileName);
- ExternalReference extRef = new ExternalReference();
- Hash hash1 = new Hash(Hash.Algorithm.SHA3_256, hash);
- Component comp = new Component();
- extRef.addHash(hash1);
- extRef.setUrl(url);
- extRef.setComment(comment); //"openjdk_source"
- extRef.setType(ExternalReference.Type.BUILD_SYSTEM);
- comp.addExternalReference(extRef);
- bom.addComponent(comp);
- return bom;
- }
-
static Bom addFormulation(final String fileName, final String name) {
- Bom bom = readJSONfile(fileName);
+ Bom bom = readFile(fileName);
List formulation = bom.getFormulation();
if (formulation == null) {
formulation = new LinkedList();
@@ -343,7 +314,7 @@ static Bom addFormulation(final String fileName, final String name) {
}
static Bom addFormulationComp(final String fileName, final String formulaName, final String name, final String type) {
- Bom bom = readJSONfile(fileName);
+ Bom bom = readFile(fileName);
if (formulaName == null) {
System.out.println("addFormulationComp: formulaName is null");
return bom;
@@ -376,7 +347,7 @@ static Bom addFormulationComp(final String fileName, final String formulaName, f
}
static Bom addFormulationCompProp(final String fileName, final String formulaName, final String componentName, final String name, final String value) {
- Bom bom = readJSONfile(fileName);
+ Bom bom = readFile(fileName);
boolean foundFormula = false;
boolean foundComponent = false;
List formulation = bom.getFormulation();
@@ -417,6 +388,32 @@ static String generateBomJson(final Bom bom) throws GeneratorException {
return json;
}
+ static String generateBomXml(final Bom bom) throws GeneratorException {
+ BomXmlGenerator bomGen = new BomXmlGenerator(bom, Version.VERSION_16);
+ String xml = bomGen.toXmlString();
+ return xml;
+ }
+
+ // Writes the BOM object to the specified type of file
+ static void writeFile(final Bom bom, final String fileName) {
+ if (useJson) {
+ writeJSONfile(bom, fileName);
+ } else {
+ writeXMLfile(bom, fileName);
+ }
+ }
+
+ // Read the BOM object from the specified type of file
+ static Bom readFile(final String fileName) {
+ Bom bom;
+ if (useJson) {
+ bom = readJSONfile(fileName);
+ } else {
+ bom = readXMLfile(fileName);
+ }
+ return bom;
+ }
+
// Writes the BOM object to the specified file.
static void writeJSONfile(final Bom bom, final String fileName) {
FileWriter file;
@@ -432,6 +429,21 @@ static void writeJSONfile(final Bom bom, final String fileName) {
}
}
+ // Writes the BOM object to the specified XML file.
+ static void writeXMLfile(final Bom bom, final String fileName) {
+ FileWriter file;
+ try {
+ String xml = generateBomXml(bom);
+
+ file = new FileWriter(fileName);
+ file.write(xml);
+ file.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
// Returns a parsed BOM object from the specified file.
static Bom readJSONfile(final String fileName) {
Bom bom = null;
@@ -446,4 +458,19 @@ static Bom readJSONfile(final String fileName) {
return bom;
}
}
+
+ // Returns a parsed BOM object from the specified file.
+ static Bom readXMLfile(final String fileName) {
+ Bom bom = null;
+ try {
+ FileReader reader = new FileReader(fileName);
+ XmlParser parser = new XmlParser();
+ bom = parser.parse(reader);
+ } catch (Exception e) {
+ e.printStackTrace();
+ System.exit(1);
+ } finally {
+ return bom;
+ }
+ }
}
diff --git a/sbin/build.sh b/sbin/build.sh
index e0bd66160..46dded89e 100755
--- a/sbin/build.sh
+++ b/sbin/build.sh
@@ -174,6 +174,17 @@ configureMacOSCodesignParameter() {
fi
}
+# JDK 24+ includes JEP 493 which allows for the JDK to enable
+# linking from the run-time image (instead of only from JMODs). Enable
+# this option. This has the effect, that no 'jmods' directory will be
+# produced in the resulting build. Thus, the tarball and, especially the
+# extracted tarball will be smaller in terms of disk space size.
+configureLinkableRuntimeParameter() {
+ if [[ "${BUILD_CONFIG[OPENJDK_FEATURE_NUMBER]}" -ge 24 ]]; then
+ addConfigureArg "--enable-linkable-runtime" ""
+ fi
+}
+
# Get the OpenJDK update version and build version
getOpenJDKUpdateAndBuildVersion() {
cd "${BUILD_CONFIG[WORKSPACE_DIR]}/${BUILD_CONFIG[WORKING_DIR]}"
@@ -574,6 +585,7 @@ configureCommandParameters() {
configureVersionStringParameter
configureBootJDKConfigureParameter
configureDevKitConfigureParameter
+ configureLinkableRuntimeParameter
configureShenandoahBuildParameter
configureMacOSCodesignParameter
configureDebugParameters
diff --git a/sbin/common/sbom.sh b/sbin/common/sbom.sh
index 945389b68..7fd7869aa 100755
--- a/sbin/common/sbom.sh
+++ b/sbin/common/sbom.sh
@@ -205,18 +205,3 @@ addSBOMComponentPropertyFromFile() {
fi
}
-# Function not in use
-# Ref: https://cyclonedx.org/docs/1.4/json/#externalReferences
-addExternalReference() {
- local javaHome="${1}"
- local classpath="${2}"
- local jsonFile="${3}"
- local url="${4}" # required
- local comment="${5}"
- local hash="${6}"
- if [ -z "${hash}" ]; then
- "${javaHome}"/bin/java -cp "${classpath}" temurin.sbom.TemurinGenSBOM --addExternalReference --jsonFile "${jsonFile}" --url "${url}" --comment "${comment}" --hash "${hash}"
- else
- "${javaHome}"/bin/java -cp "${classpath}" temurin.sbom.TemurinGenSBOM --addExternalReference --jsonFile "${jsonFile}" --url "${url}" --comment "${comment}"
- fi
-}
diff --git a/test/functional/buildAndPackage/src/net/adoptium/test/FeatureTests.java b/test/functional/buildAndPackage/src/net/adoptium/test/FeatureTests.java
index 6c22f83e6..976e92b74 100644
--- a/test/functional/buildAndPackage/src/net/adoptium/test/FeatureTests.java
+++ b/test/functional/buildAndPackage/src/net/adoptium/test/FeatureTests.java
@@ -15,12 +15,15 @@
package net.adoptium.test;
+import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import java.util.logging.Logger;
+import java.util.regex.Pattern;
import static net.adoptium.test.JdkPlatform.Architecture;
import static net.adoptium.test.JdkPlatform.OperatingSystem;
@@ -40,6 +43,71 @@ public class FeatureTests {
private final JdkPlatform jdkPlatform = new JdkPlatform();
+ private String testJdkHome = null;
+
+ /**
+ * Ensure TEST_JDK_HOME environment variable is set for every test in this class.
+ */
+ @BeforeTest
+ public final void ensureTestJDKSet() {
+ String tmpJdkHome = System.getenv("TEST_JDK_HOME");
+ if (tmpJdkHome == null) {
+ throw new AssertionError("TEST_JDK_HOME is not set");
+ }
+ this.testJdkHome = tmpJdkHome;
+ }
+
+ /**
+ * Tests whether JEP 493 is enabled for Eclipse Temurin builds.
+ *
+ * @see JEP 493: Linking Run-Time Images without JMODs
+ */
+ @Test
+ public void testLinkableRuntimeJDK24Plus() {
+ // Only JDK 24 and better and temurin builds have this enabled
+ if (jdkVersion.isNewerOrEqual(24) && isVendorAdoptium()) {
+ List command = new ArrayList<>();
+ command.add(String.format("%s/bin/jlink", testJdkHome));
+ command.add("-J-Duser.lang=en");
+ command.add("--help");
+
+ try {
+ ProcessBuilder processBuilder = new ProcessBuilder(command);
+ Process process = processBuilder.start();
+
+ String stdout = StreamUtils.consumeStream(process.getInputStream());
+ if (process.waitFor() != 0) {
+ throw new AssertionError("Could not run jlink --help");
+ }
+ String[] lines = stdout.split(Pattern.quote(System.lineSeparator()));
+ boolean seenCapabilities = false;
+ String capLine = "";
+ for (int i = 0; i < lines.length; i++) {
+ if (lines[i].trim().startsWith("Capabilities:")) {
+ seenCapabilities = true;
+ continue; // skip Capabilities line
+ }
+ if (!seenCapabilities) {
+ continue;
+ }
+ if (seenCapabilities) {
+ capLine = lines[i].trim();
+ break;
+ }
+ }
+ LOGGER.info(String.format("Matched 'Capabilities:' line: %s", capLine));
+ assertEquals(capLine, "Linking from run-time image enabled",
+ "jlink should have enabled run-time image link capability");
+ } catch (InterruptedException | IOException e) {
+ throw new RuntimeException("Failed to launch JVM", e);
+ }
+ }
+ }
+
+ private boolean isVendorAdoptium() {
+ return System.getProperty("java.vendor", "").toLowerCase(Locale.US).contains("adoptium");
+ }
+
/**
* Tests whether Shenandoah GC is available.
*
@@ -53,10 +121,6 @@ public class FeatureTests {
*/
@Test
public void testShenandoahAvailable() {
- String testJdkHome = System.getenv("TEST_JDK_HOME");
- if (testJdkHome == null) {
- throw new AssertionError("TEST_JDK_HOME is not set");
- }
boolean shouldBePresent = false;
if ((jdkVersion.isNewerOrEqual(15) || jdkVersion.isNewerOrEqualSameFeature(11, 0, 9))) {
@@ -73,7 +137,7 @@ public void testShenandoahAvailable() {
}
}
if (jdkVersion.isNewerOrEqual(17) && jdkPlatform.runsOn(OperatingSystem.LINUX, Architecture.PPC64LE)) {
- shouldBePresent = true;
+ shouldBePresent = true;
}
if (jdkVersion.isNewerOrEqual(19)
|| jdkVersion.isNewerOrEqualSameFeature(17, 0, 9)
@@ -116,10 +180,6 @@ public void testShenandoahAvailable() {
*/
@Test
public void testZGCAvailable() {
- String testJdkHome = System.getenv("TEST_JDK_HOME");
- if (testJdkHome == null) {
- throw new AssertionError("TEST_JDK_HOME is not set");
- }
boolean shouldBePresent = false;
if (jdkVersion.isNewerOrEqual(15)) {
@@ -184,10 +244,6 @@ public void testZGCAvailable() {
*/
@Test
public void testJFRAvailable() {
- String testJdkHome = System.getenv("TEST_JDK_HOME");
- if (testJdkHome == null) {
- throw new AssertionError("TEST_JDK_HOME is not set");
- }
boolean shouldBePresent = false;
if (jdkVersion.isNewerOrEqual(11) || jdkVersion.isNewerOrEqualSameFeature(8, 0, 262)) {
if (!jdkPlatform.runsOn(OperatingSystem.AIX) || jdkVersion.isNewerOrEqual(20)) {
@@ -213,4 +269,5 @@ public void testJFRAvailable() {
throw new RuntimeException("Failed to launch JVM", e);
}
}
+
}
diff --git a/tooling/build_autotriage/build_autotriage.sh b/tooling/build_autotriage/build_autotriage.sh
index 27bd40772..5445f050f 100644
--- a/tooling/build_autotriage/build_autotriage.sh
+++ b/tooling/build_autotriage/build_autotriage.sh
@@ -59,6 +59,7 @@ temurinPlatforms+=("mac-aarch64"); platformStart+=(11); platformEnd+=(9
temurinPlatforms+=("mac-x64"); platformStart+=(8); platformEnd+=(99)
temurinPlatforms+=("solaris-sparcv9"); platformStart+=(8); platformEnd+=(8)
temurinPlatforms+=("solaris-x64"); platformStart+=(8); platformEnd+=(8)
+temurinPlatforms+=("windows-aarch64"); platformStart+=(21); platformEnd+=(99)
temurinPlatforms+=("windows-x64"); platformStart+=(8); platformEnd+=(99)
temurinPlatforms+=("windows-x86-32"); platformStart+=(8); platformEnd+=(17)