diff --git a/.github/workflows/maven-central-release.yml b/.github/workflows/maven-central-release.yml index aa113c30..429e916a 100644 --- a/.github/workflows/maven-central-release.yml +++ b/.github/workflows/maven-central-release.yml @@ -21,6 +21,9 @@ jobs: contents: write # Needed to open the version-bump pull request instead of pushing to main. pull-requests: write + # Required to create build-provenance attestations for the released jars. + id-token: write + attestations: write steps: - name: Checkout code @@ -70,6 +73,14 @@ jobs: # Update module POMs mvn versions:set -DnewVersion=$VERSION -DgenerateBackupPoms=false -pl core mvn versions:set -DnewVersion=$VERSION -DgenerateBackupPoms=false -pl processor + + - name: Update reproducible build timestamp + run: | + VERSION=${{ steps.version.outputs.VERSION }} + TIMESTAMP="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" + echo "Setting project.build.outputTimestamp to $TIMESTAMP for release $VERSION" + # Pin archive entry timestamps to the release moment for reproducible builds. + mvn versions:set-property -Dproperty=project.build.outputTimestamp -DnewVersion="$TIMESTAMP" -DgenerateBackupPoms=false -pl core,processor - name: Commit version changes id: commit @@ -113,6 +124,12 @@ jobs: env: MAVEN_GPG_PASSPHRASE: ${{ secrets.GPG_SIGNING_KEY_PASSWORD }} run: mvn -B clean verify -Prelease + + - name: Generate SBOM (CycloneDX) + run: | + # Emit a CycloneDX SBOM (JSON + XML) for each published module. + mvn -B -Prelease -pl core,processor \ + org.cyclonedx:cyclonedx-maven-plugin:makeBom -DskipTests - name: Deploy (stage) to Maven Central env: @@ -126,6 +143,18 @@ jobs: # manually publish the staged deployment, so nothing is auto-released # to Maven Central without human approval. mvn -B deploy -Prelease -pl core,processor -Dcentral.autoPublish=false + + # Generates a signed build-provenance attestation for the released JARs. This is + # GitHub's official attestation action; the resulting SLSA attestation is stored in + # the repository's Attestations page and can be verified by consumers with: + # gh attestation verify --repo java-helpers/simple-builders + - name: Attest build provenance for published jars + if: success() + uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1 (GitHub official) + with: + subject-path: | + core/target/simple-builders-core-*.jar + processor/target/simple-builders-processor-*.jar - name: Push release branch and tag if: success() @@ -199,9 +228,13 @@ jobs: core/target/simple-builders-core-${VERSION}.jar \ core/target/simple-builders-core-${VERSION}-sources.jar \ core/target/simple-builders-core-${VERSION}-javadoc.jar \ + core/target/simple-builders-core-${VERSION}-sbom.json \ + core/target/simple-builders-core-${VERSION}-sbom.xml \ processor/target/simple-builders-processor-${VERSION}.jar \ processor/target/simple-builders-processor-${VERSION}-sources.jar \ - processor/target/simple-builders-processor-${VERSION}-javadoc.jar + processor/target/simple-builders-processor-${VERSION}-javadoc.jar \ + processor/target/simple-builders-processor-${VERSION}-sbom.json \ + processor/target/simple-builders-processor-${VERSION}-sbom.xml # Clean up rm -f release_notes.md diff --git a/RELEASE.md b/RELEASE.md index 0f0e8f30..8c5ecd27 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -19,11 +19,13 @@ Configure these GitHub secrets in **Settings** → **Secrets and variables** → 1. Updates POM versions to release version 2. Commits changes and creates tag `v0.2.0` -3. Builds and verifies project with `-Prelease` +3. Builds and verifies project with `-Prelease` (reproducible builds via `project.build.outputTimestamp`) 4. Signs artifacts with GPG -5. Runs tests and **stages** the deployment to the Sonatype Central portal (does **not** auto-publish) -6. Pushes commit and tag to `main` -7. Creates **draft** GitHub release (requires manual publish) +5. Generates a CycloneDX **SBOM** (JSON + XML) for each published module +6. Runs tests and **stages** the deployment to the Sonatype Central portal (does **not** auto-publish) +7. Creates a **build-provenance attestation** for the published jars +8. Pushes commit and tag to `main` +9. Creates **draft** GitHub release (jars, sources, javadoc **and SBOMs** attached; requires manual publish) ## After Release @@ -61,6 +63,14 @@ mvn clean deploy -Prelease -Dcentral.autoPublish=true - **Version conflicts**: Maven Central versions are immutable; increment and re-release - **Workflow fails on push**: Ensure GitHub Actions has write permissions (**Settings** → **Actions** → **General** → **Workflow permissions**) +## Supply-chain artifacts + +Each release produces, in addition to the GPG-signed jars: + +- **SBOM** (CycloneDX `*-sbom.json` / `*-sbom.xml`) per module, attached to the GitHub release, so consumers can inventory/scan transitive dependencies. +- **Build provenance** attestation (`actions/attest-build-provenance`) for the jars, verifiable with `gh attestation verify --repo java-helpers/simple-builders`. +- **Reproducible builds**: `project.build.outputTimestamp` is set so archive entries are deterministic. The release workflow updates it automatically; it can be overridden per build with `-Dproject.build.outputTimestamp=`. + ## Notes - Project uses [Semantic Versioning](https://semver.org/) (MAJOR.MINOR.PATCH) diff --git a/core/pom.xml b/core/pom.xml index d2d601f2..532d0d47 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -54,6 +54,9 @@ UTF-8 + + 2025-01-01T00:00:00Z 17 @@ -70,6 +73,7 @@ 0.11.0 + 2.9.1 2.29 3.15.0 3.4.0 @@ -169,6 +173,28 @@ ${central.autoPublish} + + + org.cyclonedx + cyclonedx-maven-plugin + ${plugin.cyclonedx.version} + + + generate-sbom + package + + makeBom + + + + + + ${project.build.finalName}-sbom + all + library + false + + org.apache.maven.plugins maven-source-plugin diff --git a/processor/pom.xml b/processor/pom.xml index 6e87c1e9..8a5af0ca 100644 --- a/processor/pom.xml +++ b/processor/pom.xml @@ -51,6 +51,9 @@ UTF-8 + + 2025-01-01T00:00:00Z 1.1.1 @@ -72,6 +75,7 @@ 0.11.0 + 2.9.1 3.15.0 3.4.0 3.12.0 @@ -251,6 +255,28 @@ ${central.autoPublish} + + + org.cyclonedx + cyclonedx-maven-plugin + ${plugin.cyclonedx.version} + + + generate-sbom + package + + makeBom + + + + + + ${project.build.finalName}-sbom + all + library + false + + org.apache.maven.plugins maven-source-plugin