From 558707d78ecfcfe018f92b4371e3209c7b29523f Mon Sep 17 00:00:00 2001 From: Leo Galambos Date: Wed, 15 Apr 2026 22:33:48 +0200 Subject: [PATCH] chore: harden Gradle dependency reproducibility feat: enable Gradle dependency locking for all configurations feat: enforce strict lock-state usage in the build feat: centralize repository declaration in settings.gradle feat: enable strict Gradle dependency verification via gradle.properties feat: add committed dependency lock state and verification metadata fix: defer mockito agent resolution to test execution phase for locked builds ci: validate reproducibility inputs before workflow builds ci: include lock and verification inputs in workflow change detection docs: establish explicit dependency update workflow for locks and verification metadata --- .github/workflows/benchmarks.yml | 11 + .github/workflows/build.yml | 16 + .github/workflows/pages.yml | 10 + build.gradle | 15 +- gradle.lockfile | 47 + gradle.properties | 1 + gradle/libs.versions.toml | 21 +- gradle/verification-metadata.xml | 1704 ++++++++++++++++++++++++++++++ settings-gradle.lockfile | 4 + settings.gradle | 7 + 10 files changed, 1830 insertions(+), 6 deletions(-) create mode 100644 gradle.lockfile create mode 100644 gradle.properties create mode 100644 gradle/verification-metadata.xml create mode 100644 settings-gradle.lockfile diff --git a/.github/workflows/benchmarks.yml b/.github/workflows/benchmarks.yml index 9b51665..ead51db 100644 --- a/.github/workflows/benchmarks.yml +++ b/.github/workflows/benchmarks.yml @@ -11,6 +11,9 @@ on: - 'src/main/**' - 'src/jmh/**' - 'build.gradle' + - 'gradle.properties' + - 'gradle.lockfile' + - 'settings.gradle' - 'gradle/**' - 'gradlew' - 'gradlew.bat' @@ -38,6 +41,14 @@ jobs: - name: Make Gradle executable run: chmod +x ./gradlew + - name: Verify reproducibility inputs + shell: bash + run: | + set -euo pipefail + test -f gradle.lockfile + test -f gradle.properties + test -f gradle/verification-metadata.xml + - name: Run JMH benchmarks run: ./gradlew clean jmh --no-daemon diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 7d35cd0..db8bd6c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -42,6 +42,14 @@ jobs: - name: Set up Gradle caching and instrumentation uses: gradle/actions/setup-gradle@v4 + - name: Verify reproducibility inputs + shell: bash + run: | + set -euo pipefail + test -f gradle.lockfile + test -f gradle.properties + test -f gradle/verification-metadata.xml + - name: Execute build, tests, PMD, coverage, Javadoc, distribution packaging, and SBOM generation run: ./gradlew --no-daemon clean build pmdMain javadoc jacocoTestReport distZip cyclonedxBom @@ -140,6 +148,14 @@ jobs: - name: Set up Gradle caching and instrumentation uses: gradle/actions/setup-gradle@v4 + - name: Verify reproducibility inputs + shell: bash + run: | + set -euo pipefail + test -f gradle.lockfile + test -f gradle.properties + test -f gradle/verification-metadata.xml + - name: Build release distribution and SBOM run: ./gradlew --no-daemon clean build pmdMain javadoc jacocoTestReport distZip cyclonedxBom diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index a3be564..f493e7d 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -9,6 +9,8 @@ on: - 'src/test/**' - 'src/jmh/**' - 'build.gradle' + - 'gradle.properties' + - 'gradle.lockfile' - 'settings.gradle' - 'gradle/**' - 'dependency-suppression.xml' @@ -46,6 +48,14 @@ jobs: - name: Set up Gradle caching and instrumentation uses: gradle/actions/setup-gradle@v4 + + - name: Verify reproducibility inputs + shell: bash + run: | + set -euo pipefail + test -f gradle.lockfile + test -f gradle.properties + test -f gradle/verification-metadata.xml - name: Build reports for publication run: ./gradlew --no-daemon clean build pmdMain javadoc jacocoTestReport pitest jmh cyclonedxBom diff --git a/build.gradle b/build.gradle index 304f04d..994c7c7 100644 --- a/build.gradle +++ b/build.gradle @@ -41,8 +41,10 @@ tasks.withType(JavaCompile).configureEach { options.release = 21 } -repositories { - mavenCentral() +dependencyLocking { + lockAllConfigurations() + + lockMode = LockMode.STRICT } dependencies { @@ -94,10 +96,13 @@ dependencyCheck { tasks.withType(Test).configureEach { useJUnitPlatform() - jvmArgs += "-javaagent:${configurations.mockitoAgent.singleFile}" - + + doFirst { + jvmArgs "-javaagent:${configurations.mockitoAgent.singleFile}" + } + finalizedBy(tasks.named('jacocoTestReport')) - + reports { junitXml.required = true html.required = true diff --git a/gradle.lockfile b/gradle.lockfile new file mode 100644 index 0000000..11566a3 --- /dev/null +++ b/gradle.lockfile @@ -0,0 +1,47 @@ +# This is a Gradle generated file for dependency locking. +# Manual edits can break the build and are not advised. +# This file is expected to be part of source control. +com.github.oowekyala.ooxml:nice-xml-messages:3.1=pmd +com.google.code.gson:gson:2.13.2=pmd +com.google.errorprone:error_prone_annotations:2.41.0=pmd +net.bytebuddy:byte-buddy-agent:1.17.7=jmhRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +net.bytebuddy:byte-buddy:1.17.7=jmhRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +net.sf.jopt-simple:jopt-simple:5.0.4=jmh,jmhCompileClasspath,jmhRuntimeClasspath +net.sf.saxon:Saxon-HE:12.9=pmd +net.sourceforge.pmd:pmd-ant:7.20.0=pmd +net.sourceforge.pmd:pmd-core:7.20.0=pmd +net.sourceforge.pmd:pmd-java:7.20.0=pmd +org.antlr:antlr4-runtime:4.9.3=pmd +org.apache.commons:commons-lang3:3.20.0=pmd +org.apache.commons:commons-math3:3.6.1=jmh,jmhCompileClasspath,jmhRuntimeClasspath +org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath +org.checkerframework:checker-qual:3.52.1=pmd +org.jacoco:org.jacoco.agent:0.8.14=jacocoAgent,jacocoAnt +org.jacoco:org.jacoco.ant:0.8.14=jacocoAnt +org.jacoco:org.jacoco.core:0.8.14=jacocoAnt +org.jacoco:org.jacoco.report:0.8.14=jacocoAnt +org.junit.jupiter:junit-jupiter-api:5.14.3=jmhRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-engine:5.14.3=jmhRuntimeClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-params:5.14.3=jmhRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter:5.14.3=jmhRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-commons:1.14.3=jmhRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-engine:1.14.3=jmhRuntimeClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-launcher:1.14.3=jmhRuntimeClasspath,testRuntimeClasspath +org.junit:junit-bom:5.14.3=jmhRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.mockito:mockito-core:5.23.0=jmhRuntimeClasspath,mockitoAgent,testCompileClasspath,testRuntimeClasspath +org.mockito:mockito-junit-jupiter:5.23.0=jmhRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.objenesis:objenesis:3.3=jmhRuntimeClasspath,testRuntimeClasspath +org.openjdk.jmh:jmh-core:1.37=jmh,jmhCompileClasspath,jmhRuntimeClasspath +org.openjdk.jmh:jmh-generator-asm:1.37=jmh,jmhCompileClasspath,jmhRuntimeClasspath +org.openjdk.jmh:jmh-generator-bytecode:1.37=jmh,jmhCompileClasspath,jmhRuntimeClasspath +org.openjdk.jmh:jmh-generator-reflection:1.37=jmh,jmhCompileClasspath,jmhRuntimeClasspath +org.opentest4j:opentest4j:1.3.0=jmhRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.ow2.asm:asm-commons:9.9=jacocoAnt +org.ow2.asm:asm-tree:9.9=jacocoAnt +org.ow2.asm:asm:9.0=jmh,jmhCompileClasspath,jmhRuntimeClasspath +org.ow2.asm:asm:9.9=jacocoAnt +org.ow2.asm:asm:9.9.1=pmd +org.pcollections:pcollections:4.0.2=pmd +org.slf4j:jul-to-slf4j:1.7.36=pmd +org.xmlresolver:xmlresolver:5.3.3=pmd +empty=annotationProcessor,compileClasspath,cyclonedxBom,jmhAnnotationProcessor,mainPmdAuxClasspath,runtimeClasspath,testAnnotationProcessor diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..a47b4eb --- /dev/null +++ b/gradle.properties @@ -0,0 +1 @@ +org.gradle.dependency.verification=strict diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index b8ce83a..7ec0bc2 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,3 +1,23 @@ +# +# After changing dependency versions: +# +# run: +# ./gradlew --write-locks classes testClasses jmh distZip cyclonedxBom +# +# if needed, refresh verification metadata: +# ./gradlew --write-verification-metadata sha256 test jmh distZip cyclonedxBom +# +# (optional - for Eclipse IDE) +# insert trusted-artifacts into gradle/verification-metadata.xml/verification-metadata/configuration: +# +# +# +# +# +# commit: +# gradle.lockfile +# gradle/verification-metadata.xml +# [versions] junit = "5.14.3" mockito = "5.23.0" @@ -9,4 +29,3 @@ junit-platform-launcher = { module = "org.junit.platform:junit-platform-launcher mockito-core = { module = "org.mockito:mockito-core", version.ref = "mockito" } mockito-junit-jupiter = { module = "org.mockito:mockito-junit-jupiter", version.ref = "mockito" } - diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml new file mode 100644 index 0000000..dd76ef0 --- /dev/null +++ b/gradle/verification-metadata.xml @@ -0,0 +1,1704 @@ + + + + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/settings-gradle.lockfile b/settings-gradle.lockfile new file mode 100644 index 0000000..709a43f --- /dev/null +++ b/settings-gradle.lockfile @@ -0,0 +1,4 @@ +# This is a Gradle generated file for dependency locking. +# Manual edits can break the build and are not advised. +# This file is expected to be part of source control. +empty=incomingCatalogForLibs0 diff --git a/settings.gradle b/settings.gradle index f9e6be3..c3d5c2a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,8 @@ rootProject.name = 'Radixor' + +dependencyResolutionManagement { + repositoriesMode = RepositoriesMode.FAIL_ON_PROJECT_REPOS + repositories { + mavenCentral() + } +}