diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 30ad864d..f71982cb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -91,6 +91,14 @@ jobs: !product/target/openfasttrace-*-sources.jar if-no-files-found: error + - name: Upload SPDX SBOM + uses: actions/upload-artifact@v7 + if: ${{ env.DEFAULT_OS == matrix.os && env.DEFAULT_JAVA == matrix.java }} + with: + name: openfasttrace-spdx + path: product/target/site/*.spdx3.json + if-no-files-found: error + - name: Run self-trace run: ./oft-self-trace.sh diff --git a/.github/workflows/github_release.sh b/.github/workflows/github_release.sh index 36b81204..3a700c07 100755 --- a/.github/workflows/github_release.sh +++ b/.github/workflows/github_release.sh @@ -13,18 +13,21 @@ project_version=$(grep "" "$pom_file" | sed --regexp-extended 's/\s* "$checksum_file_name" -readonly checksum_file_path="$file_dir/$checksum_file_name" -cd "$base_dir" +readonly sbom_path="$base_dir/product/target/site/org.itsallcode.openfasttrace_openfasttrace-${project_version}.spdx3.json" + +calculate_checksum() { + local file_path="$1" + local checksum_file_path="${file_path}.sha256" + readonly file_path checksum_file_path + echo "Calculating SHA-256 checksum for '$file_path'" + (cd "$(dirname "$file_path")" && sha256sum "$(basename "$file_path")") > "$checksum_file_path" +} + +calculate_checksum "$artifact_path" +readonly artifact_checksum_path="${artifact_path}.sha256" +calculate_checksum "$sbom_path" +readonly sbom_checksum_path="${sbom_path}.sha256" # Create GitHub release @@ -39,8 +42,11 @@ echo "Git tag : $tag" echo "Title : $title" echo "Changes file : $changes_file" echo "Artifact file: $artifact_path" -echo "Checksum file: $checksum_file_path" +echo "Artifact checksum: $artifact_checksum_path" +echo "SBOM file : $sbom_path" +echo "SBOM checksum: $sbom_checksum_path" -release_url=$(gh release create --latest --title "$title" --notes "$notes" --target main "$tag" "$artifact_path" "$checksum_file_path") +release_url=$(gh release create --latest --title "$title" --notes "$notes" --target main "$tag" \ + "$artifact_path" "$artifact_checksum_path" "$sbom_path" "$sbom_checksum_path") readonly release_url echo "Release URL: $release_url" diff --git a/SECURITY.md b/SECURITY.md index 39f8bfed..fc5c8e61 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -15,3 +15,7 @@ If you discover a potential security issue, please report it privately via [GitH - **Disclose** the details publicly once a fix is available and users have had time to update. While we don't offer bug bounties, we'd be happy to publicly acknowledge your contribution in the advisory. + +## Software Bill of Materials (SBOM) + +Starting with version 4.10.0, each GitHub release includes an SPDX Software Bill of Materials (SBOM) for the OpenFastTrace product JAR and a SHA-256 checksum for the SBOM. diff --git a/api/pom.xml b/api/pom.xml index e0ee8615..9d7d0c13 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -4,6 +4,7 @@ 4.0.0 openfasttrace-api OpenFastTrace API + Public API of OpenFastTrace ../openfasttrace-mc-deployable-parent/pom.xml org.itsallcode.openfasttrace diff --git a/core/pom.xml b/core/pom.xml index 4f8b3a5b..265d929f 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -4,6 +4,7 @@ 4.0.0 openfasttrace-core OpenFastTrace Core + OpenFastTrace core logic (specification items, linking and base modules for importers, exporters and reporters) ../openfasttrace-mc-deployable-parent/pom.xml org.itsallcode.openfasttrace diff --git a/doc/changes/changes_4.10.0.md b/doc/changes/changes_4.10.0.md new file mode 100644 index 00000000..5124479f --- /dev/null +++ b/doc/changes/changes_4.10.0.md @@ -0,0 +1,17 @@ +# OpenFastTrace 4.10.0, released 2026-08-?? + +Code name: Lifecycle Information and SPDX3 SBOM + +## Summary + +The project lifecycle documentation now describes planned deprecations and removals in OFT 5.0.0, including migration guidance for the SpecObject format and short coverage tags. + +Each release now includes an SPDX 3 SBOM for the product JAR and a SHA-256 checksum for the SBOM. + +## Feature + +* #542: CI and releases now provide an SPDX 3 SBOM. + +## Documentation + +* #579: Documented planned deprecations and removals. diff --git a/doc/developer_guide.md b/doc/developer_guide.md index ea69b416..714d64f1 100644 --- a/doc/developer_guide.md +++ b/doc/developer_guide.md @@ -237,6 +237,21 @@ This project is configured to produce exactly the same artifacts each time when The build will use the last Git commit timestamp as timestamp for files in `.jar` archives. +## SBOM + +The project generates an [SPDX](https://spdx.dev/) SBOM using the [SPDX Maven Plugin](https://github.com/spdx/spdx-maven-plugin). + +The SPDX plugin runs during Maven's `package` phase and creates an SBOM for each Maven module. The product SBOM describes the product and its production dependencies. + +Build OFT and create the SBOMs with a single command: + +```shell +mvn package +``` + +> [!IMPORTANT] +> OFT does not include third-party packages in the production JAR. The JRE is provided by the machine on which OFT runs. Therefore, the product SBOM contains only OFT modules. Test dependencies are excluded because they are not relevant to OFT users. + ## Creating a Release **NOTE**: This currently only works for release version numbers, not SNAPSHOT versions. diff --git a/exporter/common/pom.xml b/exporter/common/pom.xml index 52b9e58a..5ad9570b 100644 --- a/exporter/common/pom.xml +++ b/exporter/common/pom.xml @@ -4,6 +4,7 @@ 4.0.0 openfasttrace-exporter-common OpenFastTrace Exporters Utils + Common logic for OpenFastTrace exporters ../../openfasttrace-mc-deployable-parent/pom.xml org.itsallcode.openfasttrace diff --git a/exporter/specobject/pom.xml b/exporter/specobject/pom.xml index 39b20762..55ae0d01 100644 --- a/exporter/specobject/pom.xml +++ b/exporter/specobject/pom.xml @@ -4,6 +4,7 @@ 4.0.0 openfasttrace-exporter-specobject OpenFastTrace Specobject Exporter + Specobject (ReqM2 exchange format) exporter ../../openfasttrace-mc-deployable-parent/pom.xml org.itsallcode.openfasttrace diff --git a/importer/lightweightmarkup/pom.xml b/importer/lightweightmarkup/pom.xml index 38f75827..f439c65c 100644 --- a/importer/lightweightmarkup/pom.xml +++ b/importer/lightweightmarkup/pom.xml @@ -4,6 +4,7 @@ 4.0.0 openfasttrace-importer-lightweightmarkup OpenFastTrace Lightweight Markup Importer Base + Base module for OpenFastTrace importers based on lightweight markup languages (e.g., Markdown and RST) ../../openfasttrace-mc-deployable-parent/pom.xml org.itsallcode.openfasttrace diff --git a/importer/markdown/pom.xml b/importer/markdown/pom.xml index 42c96065..3fb410fd 100644 --- a/importer/markdown/pom.xml +++ b/importer/markdown/pom.xml @@ -4,6 +4,7 @@ 4.0.0 openfasttrace-importer-markdown OpenFastTrace Markdown Importer + Importer for OpenFastTrace specification items embedded into Markdown text ../../openfasttrace-mc-deployable-parent/pom.xml org.itsallcode.openfasttrace diff --git a/importer/restructuredtext/pom.xml b/importer/restructuredtext/pom.xml index 4f66ed9d..db3c182d 100644 --- a/importer/restructuredtext/pom.xml +++ b/importer/restructuredtext/pom.xml @@ -4,6 +4,7 @@ 4.0.0 openfasttrace-importer-restructuredtext OpenFastTrace reStructuredText Importer + Importer for OpenFastTrace specification items embedded into reStructuredText (RST) ../../openfasttrace-mc-deployable-parent/pom.xml org.itsallcode.openfasttrace diff --git a/importer/specobject/pom.xml b/importer/specobject/pom.xml index 91dbab26..fe079d7a 100644 --- a/importer/specobject/pom.xml +++ b/importer/specobject/pom.xml @@ -4,6 +4,7 @@ 4.0.0 openfasttrace-importer-specobject OpenFastTrace Specobject Importer + Importer for OpenFastTrace specification items from Specobject (ReqM2 format) ../../openfasttrace-mc-deployable-parent/pom.xml org.itsallcode.openfasttrace diff --git a/importer/tag/pom.xml b/importer/tag/pom.xml index f037464c..a2dc31d2 100644 --- a/importer/tag/pom.xml +++ b/importer/tag/pom.xml @@ -4,6 +4,7 @@ 4.0.0 openfasttrace-importer-tag OpenFastTrace Tag Importer + Importer for OpenFastTrace specification items embedded source code marker tags ../../openfasttrace-mc-deployable-parent/pom.xml org.itsallcode.openfasttrace diff --git a/importer/xmlparser/pom.xml b/importer/xmlparser/pom.xml index b8723191..9a2ac786 100644 --- a/importer/xmlparser/pom.xml +++ b/importer/xmlparser/pom.xml @@ -4,6 +4,7 @@ 4.0.0 openfasttrace-importer-xmlparser OpenFastTrace Common XML Parser + Importer for OpenFastTrace specification items embedded into XML ../../openfasttrace-mc-deployable-parent/pom.xml org.itsallcode.openfasttrace diff --git a/importer/zip/pom.xml b/importer/zip/pom.xml index c82ff929..95055477 100644 --- a/importer/zip/pom.xml +++ b/importer/zip/pom.xml @@ -4,6 +4,7 @@ 4.0.0 openfasttrace-importer-zip OpenFastTrace Zip Importer + Recursive importer for OpenFastTrace specification items in ZIP archives ../../openfasttrace-mc-deployable-parent/pom.xml org.itsallcode.openfasttrace diff --git a/openfasttrace-mc-deployable-parent/pom.xml b/openfasttrace-mc-deployable-parent/pom.xml index 4c1f3090..1d45e0c9 100644 --- a/openfasttrace-mc-deployable-parent/pom.xml +++ b/openfasttrace-mc-deployable-parent/pom.xml @@ -16,6 +16,7 @@ It is maintained separately from the main parent POM for the following reasons: openfasttrace-mc-deployable-parent ${revision} OpenFastTrace Parent for modules deployed to Maven Central + Maven-central-specific deployment module for OpenFastTrace pom ../parent/pom.xml @@ -23,7 +24,6 @@ It is maintained separately from the main parent POM for the following reasons: openfasttrace-parent ${revision} - Free requirement tracking suite https://github.com/itsallcode/openfasttrace false diff --git a/parent/pom.xml b/parent/pom.xml index bb1d55ce..12bf8869 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -7,10 +7,9 @@ ${revision} OpenFastTrace Parent pom - Free requirement tracking suite https://github.com/itsallcode/openfasttrace - 4.9.0 + 4.10.0 17 6.1.0-M1 6.1.2 @@ -21,11 +20,13 @@ ${reproducible.build.timestamp} -Duser.language=en false + GPL-3.0-only + Copyright (c) itsallcode.org - GNU General Public License v3.0 - https://www.gnu.org/licenses/gpl-3.0.html + GPL-3.0-only + https://spdx.org/licenses/GPL-3.0-only.html repo @@ -539,7 +540,7 @@ 2.21.0 - + org.apache.maven.plugins maven-deploy-plugin 3.1.4 @@ -547,6 +548,35 @@ true + + org.spdx + spdx-maven-plugin + 1.0.3 + + + build-spdx + + createSPDX + + package + + + + ${project.reporting.outputDirectory}/${project.groupId}_${project.artifactId}-${project.version}.spdx3.json + build + JSON-LD + ${spdx.license} + ${spdx.license} + ${spdx.copyright} + false + ${spdx.license} + ${spdx.license} + ${spdx.copyright} + true + false + true + + diff --git a/pom.xml b/pom.xml index e0449b84..70eb3911 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,30 @@ + org.spdx + spdx-maven-plugin + 1.0.3 + + + aggregate-spdx + + aggregateSPDX + + + + + build + false + GPL-3.0-only + GPL-3.0-only + Copyright (c) itsallcode.org + false + GPL-3.0-only + GPL-3.0-only + Copyright (c) itsallcode.org + + + org.sonarsource.scanner.maven sonar-maven-plugin 5.7.0.6970 diff --git a/product/pom.xml b/product/pom.xml index 23d7f68f..7249c376 100644 --- a/product/pom.xml +++ b/product/pom.xml @@ -3,6 +3,7 @@ 4.0.0 openfasttrace OpenFastTrace Product + OpenFastTrace aggregated library (includes all official base modules) ../openfasttrace-mc-deployable-parent/pom.xml org.itsallcode.openfasttrace @@ -137,6 +138,112 @@ + + org.spdx + spdx-maven-plugin + 1.0.3 + + build + JSON-LD + false + ${spdx.license} + ${spdx.license} + ${spdx.copyright} + false + ${spdx.license} + ${spdx.license} + ${spdx.copyright} + + + + both + org.itsallcode.openfasttrace + openfasttrace-api + GPL-3.0-only + + + both + org.itsallcode.openfasttrace + openfasttrace-core + GPL-3.0-only + + + both + org.itsallcode.openfasttrace + openfasttrace-exporter-common + GPL-3.0-only + + + both + org.itsallcode.openfasttrace + openfasttrace-exporter-specobject + GPL-3.0-only + + + both + org.itsallcode.openfasttrace + openfasttrace-importer-lightweightmarkup + GPL-3.0-only + + + both + org.itsallcode.openfasttrace + openfasttrace-importer-markdown + GPL-3.0-only + + + both + org.itsallcode.openfasttrace + openfasttrace-importer-restructuredtext + GPL-3.0-only + + + both + org.itsallcode.openfasttrace + openfasttrace-importer-specobject + GPL-3.0-only + + + both + org.itsallcode.openfasttrace + openfasttrace-importer-tag + GPL-3.0-only + + + both + org.itsallcode.openfasttrace + openfasttrace-importer-xmlparser + GPL-3.0-only + + + both + org.itsallcode.openfasttrace + openfasttrace-importer-zip + GPL-3.0-only + + + both + org.itsallcode.openfasttrace + openfasttrace-reporter-aspec + GPL-3.0-only + + + both + org.itsallcode.openfasttrace + openfasttrace-reporter-html + GPL-3.0-only + + + both + org.itsallcode.openfasttrace + openfasttrace-reporter-plaintext + GPL-3.0-only + + + + diff --git a/product/src/test/java/org/itsallcode/openfasttrace/SpdxSbomIT.java b/product/src/test/java/org/itsallcode/openfasttrace/SpdxSbomIT.java new file mode 100644 index 00000000..1012a21d --- /dev/null +++ b/product/src/test/java/org/itsallcode/openfasttrace/SpdxSbomIT.java @@ -0,0 +1,52 @@ +package org.itsallcode.openfasttrace; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.matchesPattern; +import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertAll; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.stream.Stream; + +import org.junit.jupiter.api.Test; + +class SpdxSbomIT +{ + private static final Path SPDX_OUTPUT_DIRECTORY = Path.of("target", "site"); + private static final String SPDX_3_CONTEXT_PATTERN = + "(?s).*\"@context\"\\s*:\\s*\"https://spdx.org/rdf/3\\.[^\"]+/spdx-context.jsonld\".*"; + + @Test + void generatedSbomDescribesOpenFastTraceProduct() throws IOException + { + final List generatedSboms = findGeneratedSboms(); + assertThat("generated product SBOMs", generatedSboms, hasSize(1)); + + final String sbom = Files.readString(generatedSboms.get(0)); + + assertAll( + () -> assertThat("SPDX 3 JSON-LD context", sbom, + matchesPattern(SPDX_3_CONTEXT_PATTERN)), + () -> assertThat("SPDX document", sbom, containsString("\"type\" : \"SpdxDocument\"")), + () -> assertThat("software SBOM", sbom, containsString("\"type\" : \"software_Sbom\"")), + () -> assertThat("product identity", sbom, containsString("\"name\" : \"OpenFastTrace Product\"")), + () -> assertThat("API module", sbom, containsString("\"name\" : \"OpenFastTrace API\"")), + () -> assertThat("core module", sbom, containsString("\"name\" : \"OpenFastTrace Core\"")), + () -> assertThat("absence of JUnit test dependencies", sbom, not(containsString("JUnit"))), + () -> assertThat("absence of Maven build plugins", sbom, + not(containsString("maven-compiler-plugin")))); + } + + private List findGeneratedSboms() throws IOException + { + try (Stream files = Files.list(SPDX_OUTPUT_DIRECTORY)) + { + return files.filter(file -> file.getFileName().toString().endsWith(".spdx3.json")).toList(); + } + } +} diff --git a/product/src/test/java/org/itsallcode/openfasttrace/core/serviceloader/ServiceLoaderFactoryIT.java b/product/src/test/java/org/itsallcode/openfasttrace/core/serviceloader/ServiceLoaderFactoryIT.java index 8de5e2bc..5fcad73f 100644 --- a/product/src/test/java/org/itsallcode/openfasttrace/core/serviceloader/ServiceLoaderFactoryIT.java +++ b/product/src/test/java/org/itsallcode/openfasttrace/core/serviceloader/ServiceLoaderFactoryIT.java @@ -10,6 +10,7 @@ import java.util.List; import java.util.Optional; import java.util.regex.Pattern; +import java.util.stream.Stream; import org.itsallcode.openfasttrace.api.report.ReporterFactory; import org.junit.jupiter.api.Test; @@ -31,7 +32,7 @@ class ServiceLoaderFactoryIT void loadServiceFromWrongJar() throws IOException { preparePlugin(Path.of("../reporter/plaintext/target"), - Pattern.compile("openfasttrace-reporter-plaintext-\\d\\.\\d\\.\\d\\-javadoc.jar")); + Pattern.compile("openfasttrace-reporter-plaintext-\\d+\\.\\d+\\.\\d+-javadoc.jar")); try (Loader loader = createLoader()) { final List service = loader.load().toList(); @@ -48,7 +49,7 @@ private Loader createLoader() void loadServiceFromJar() throws IOException { preparePlugin(Path.of("../reporter/plaintext/target"), - Pattern.compile("openfasttrace-reporter-plaintext-\\d\\.\\d\\.\\d\\.jar")); + Pattern.compile("openfasttrace-reporter-plaintext-\\d+\\.\\d+\\.\\d+\\.jar")); try (Loader loader = createLoader()) { final List services = loader.load().toList(); @@ -76,8 +77,10 @@ private void preparePlugin(final Path targetDir, final Pattern filePattern) thro private Optional findMatchingFile(final Path dir, final Pattern filePattern) throws IOException { - return Files.list(dir).filter(file -> filePattern.matcher(file.getFileName().toString()).matches()) - .findFirst(); + try(final Stream files = Files.list(dir)) { + return files.filter(file -> filePattern.matcher(file.getFileName().toString()).matches()) + .findFirst(); + } } private void preparePlugin(final Path pluginJar) throws IOException diff --git a/reporter/aspec/pom.xml b/reporter/aspec/pom.xml index f47a75f3..80964064 100644 --- a/reporter/aspec/pom.xml +++ b/reporter/aspec/pom.xml @@ -4,6 +4,7 @@ 4.0.0 openfasttrace-reporter-aspec OpenFastTrace augmented specobject Reporter + Report an OpenFastTrace requirement trace as Augmented Specobject (ReqM2 format) ../../openfasttrace-mc-deployable-parent/pom.xml org.itsallcode.openfasttrace diff --git a/reporter/html/pom.xml b/reporter/html/pom.xml index 288f2a61..dc4a7711 100644 --- a/reporter/html/pom.xml +++ b/reporter/html/pom.xml @@ -4,6 +4,7 @@ 4.0.0 openfasttrace-reporter-html OpenFastTrace HTML Reporter + Generate HTML report from an OpenFastTrace requirement trace ../../openfasttrace-mc-deployable-parent/pom.xml org.itsallcode.openfasttrace diff --git a/reporter/plaintext/pom.xml b/reporter/plaintext/pom.xml index a0719c1d..fefd1284 100644 --- a/reporter/plaintext/pom.xml +++ b/reporter/plaintext/pom.xml @@ -4,6 +4,7 @@ 4.0.0 openfasttrace-reporter-plaintext OpenFastTrace Plaintext Reporter + Generate plain text report from an OpenFastTrace requirement trace ../../openfasttrace-mc-deployable-parent/pom.xml org.itsallcode.openfasttrace diff --git a/testutil/pom.xml b/testutil/pom.xml index 9f5f12f3..9d1a0536 100644 --- a/testutil/pom.xml +++ b/testutil/pom.xml @@ -4,6 +4,7 @@ 4.0.0 openfasttrace-testutil OpenFastTrace Test utilities + Shared test utilities used in multiple OpenFastTrace modules jar ../parent/pom.xml