This plugin is a state-of-the-art solution for validating the integrity of a maven build and guarding the build against malicious actors that might tamper with the artifacts. Features: * generating a lock file that contains the checksums of all the artifacts and dependencies. * validate the integrity of a build environment prior to building. * rebuild old versions with the pinned versions from the lockfile
Reference: Maven-Lockfile: High Integrity Rebuild of Past Java Releases, Technical report 2510.00730, arXiv, 2025.
Video Demo
Video Demo available in full quality on YouTube or compressed below:
https://github.com/user-attachments/assets/4fac8229-d80b-4832-93c1-8cc8bf83e72b
This plugin is available on maven central. See https://search.maven.org/artifact/io.github.chains-project/maven-lockfile for the latest version.
To generate a lock file, run the following command:
mvn io.github.chains-project:maven-lockfile:generate
This generates a lockfile.json file in each module of the repository, in readable JSON. This file contains the checksums of all the artifacts in the repository. The complete dependency tree, with transitive dependencies, is stored in the lockfile (akin a sbom). For multi-module projects, there is one lockfile per module.
Run the following command to validate the repository:
mvn io.github.chains-project:maven-lockfile:validate
If this runs successfully, the repository is valid. All dependencies defined are still the same as when the lock file was generated. If the command fails, this means a dependency has changed.
First create pom.lockfile.xml
mvn io.github.chains-project:maven-lockfile:freeze
This creates a new pom file with the default name pom.lockfile.xml. A custom name can be passed with the flag pomLockfileOutput.
In the new pom file, every version of direct dependencies in the original pom will be replaced with the versions from the lockfile. Also, every transitive dependency is added to the pom inside the dependencyManagement section with the version and scope from the lockfile.
Then, invoke maven with the -f flag
mvn -f pom.lockfile.xml
reduced (-Dreduced=false) will reduce the lockfile only containing the dependencies after dependency resolution conflicts are resolved. This format is smaller, and easier to review and read. Only use this if you do not need the full dependency tree.includeMavenPlugins (-DincludeMavenPlugins=true, default=true) controls whether Maven plugins are included in the lockfile. Maven plugins are included by default so plugin artifacts are validated as part of the build. Set -DincludeMavenPlugins=false to opt out.allowValidationFailure (-DallowValidationFailure=true, default=false) allow validation failures, printing a warning instead of an error. This is useful if you want to only validate the Maven lockfile, but do not need to fail the build in case the lockfile is not valid. Use with caution, you loose all guarantees.allowPomValidationFailure (-DallowPomValidationFailure=true, default=false) allow validation failure of the pom specifically, dependency validation still occurs (assuming allowValidationFailure is false). In case of checksum mismatch of pom prints a warning instead of default exception.allowEnvironmentalValidationFailure (-DallowEnvironmentalValidationFailure=true, default=false) allow validation failure of the environment. In case of environment mismatch prints a warning instead of default exception.includeEnvironment (-DincludeEnvironment=true) will include the environment metadata in the lockfile. This is useful if you want to have warnings when the environment changes.includeBoms (-DincludeBoms=true, default=true) controls whether BOM (bill of materials) POMs are included in the lockfile.allowBomValidationFailure (-DallowBomValidationFailure=true, default=false) allow BOM validation failures, printing a warning instead of an error.includeParentPom (-DincludeParentPom=true, default=true) controls whether parent POM data is included in the lockfile for dependencies and plugins.allowParentPomValidationFailure (-DallowParentPomValidationFailure=true, default=false) allow parent POM validation failures, printing a warning instead of an error.includeMavenExtensions (-DincludeMavenExtensions=true, default=true) controls whether Maven build extensions are included in the lockfile.allowMavenExtensionsValidationFailure (-DallowMavenExtensionsValidationFailure=true, default=false) allow Maven extensions validation failures, printing a warning instead of an error.checksumAlgorithm (-DchecksumAlgorithm=SHA-256) will set the checksum algorithm used to generate the lockfile. If not explicitly provided it will use SHA-256.checksumMode will set the checksum mode used to generate the lockfile. See Checksum Modes for more information.skip (-Dskip=true) will skip the execution of the plugin. This is useful if you would like to disable the plugin for a specific module.lockfileName (-DlockfileName=my-lockfile.json default="lockfile.json") will set the name of the lockfile file to be generated/read.getConfigFromFile will read the configuration of maven lockfile from the existing lockfile.For :freeze target:
- pomLockfileOutput (-DpomLockfileOutput=pom.xml, default=pom.lockfile.xml) sets the name of the generated flattened pom file. Default is to create a new file with the name pom.lockfile.xml, but you can also set it to pom.xml to overwrite the original pom file.
- exactVersionStrings (-DexactVersionStrings=false, default=true) provide version string as exact parameter [1.0.0], instead of soft requirement 1.0.0.
The flags are passed by the maven -D (--define) property. For example, to set the lockfileName to my-lockfile.json while keeping the default Maven plugin inclusion, you would run the following command:
mvn io.github.chains-project:maven-lockfile:generate -DlockfileName=my-lockfile.json
An example lockfile is shown below. Note that large parts of it has been minimzed to {...} for readability.
For a full example, see the lockfile.json file in this repository.
```json
{
"artifactId": "single-dependency",
"groupId": "com.mycompany.app",
"version": "1",
"pom": {
"groupId": "com.mycompany.app",
"artifactId": "single-dependency",
"version": "1",
"relativePath": "pom.xml",
"checksumAlgorithm": "SHA-256",
"checksum": "2152cc00c16d72fbf9430e6a95a56e9edf0180a500155490bf33a7349df75a1b"
},
"lockFileVersion": 1,
"dependencies": [
{
"groupId": "fr.inria.gforge.spoon",
"artifactId": "spoon-core",
"version": "10.3.0",
"checksumAlgorithm": "SHA-256",
"checksum": "37a43de039cf9a6701777106e3c5921e7131e5417fa707709abf791d3d8d9174",
"scope": "compile",
"resolved": "https://repo.maven.apache.org/maven2/fr/inria/gforge/spoon/spoon-core/10.3.0/spoon-core-10.3.0.jar",
"repositoryId": "central",
"selectedVersion": "10.3.0",
"included": true,
"id": "fr.inria.gforge.spoon:spoon-core:10.3.0",
"children": [
{
"groupId": "com.fasterxml.jackson.core",
"artifactId": "jackson-databind",
"version": "2.14.2",
"checksumAlgorithm": "SHA-256",
"checksum": "501d3abce4d18dcc381058ec593c5b94477906bba6efbac14dae40a642f77424",
"scope": "compile",
"resolved": "https://repo.maven.apache.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.14.2/jackson-databind-2.14.2.jar",
"repositoryId": "central",
"selectedVersion": "2.14.2",
"included": true,
"id": "com.fasterxml.jackson.core:jackson-databind:2.14.2",
"parent": "fr.inria.gforge.spoon:spoon-core:10.3.0",
"children": [
{
"groupId": "com.fasterxml.jackson.core",
"artifactId": "jackson-annotations",
"version": "2.14.2",
"checksumAlgorithm": "SHA-256",
"checksum": "2c6869d505cf60dc066734b7d50339f975bd3adc635e26a78abb71acb4473c0d",
"scope": "compile",
"resolved": "https://repo.maven.apache.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.14.2/jackson-annotations-2.14.2.jar",
"repositoryId": "central",
"selectedVersion": "2.14.2",
"included": true,
"id": "com.fasterxml.jackson.core:jackson-annotations:2.14.2",
"parent": "com.fasterxml.jackson.core:jackson-databind:2.14.2",
"children": []
},
{
"groupId": "com.fasterxml.jackson.core",
"artifactId": "jackson-core",
"version": "2.14.2",
"checksumAlgorithm": "SHA-256",
"checksum": "b5d37a77c88277b97e3593c8740925216c06df8e4172bbde058528df04ad3e7a",
"scope": "compile",
"resolved": "https://repo.maven.apache.org/maven2/com/fasterxml/jackson/core/jackson-core/2.14.2/jackson-core-2.14.2.jar",
"repositoryId": "central",
"selectedVersion": "2.14.2",
"included": true,
"id": "com.fasterxml.jackson.core:jackson-core:2.14.2",
"parent": "com.fasterxml.jackson.core:jackson-databind:2.14.2",
"children": []
}
]
},
{
"groupId": "com.martiansoftware",
"artifactId": "jsap",
"version": "2.1",
"checksumAlgorithm": "SHA-256",
"checksum": "331746fa62cfbc3368260c5a2e660936ad11be612308c120a044e120361d474e",
"scope": "compile",
"resolved": "https://repo.maven.apache.org/maven2/com/martiansoftware/jsap/2.1/jsap-2.1.jar",
"repositoryId": "central",
"selectedVersion": "2.1",
"included": true,
"id": "com.martiansoftware:jsap:2.1",
"parent": "fr.inria.gforge.spoon:spoon-core:10.3.0",
"children": []
},
{...}
]
}
],
"mavenPlugins": [
{
"groupId": "org.apache.maven.plugins",
"artifactId": "maven-clean-plugin",
"version": "3.2.0",
"checksumAlgorithm": "SHA-256",
"checksum": "b657bef2e1eb11e029a70cd688bde6adad29e4e99dacb18516bf651ecca32435",
"resolved": "https://repo.maven.apache.org/maven2/org/apache/maven/plugins/maven-clean-plugin/3.2.0/maven-clean-plugin-3.2.0.jar",
"repositoryId": "central",
"dependencies": [
{
"groupId": "org.apache.maven",
"artifactId": "maven-core",
"version": "3.2.5",
"checksumAlgorithm": "SHA-256",
"checksum": "4f1a0af8997e1daf778b91c5ae9e973f92df699439d909fdec7fc6055c09de12",
"scope": "provided",
"resolved": "https://repo.maven.apache.org/maven2/org/apache/maven/maven-core/3.2.5/maven-core-3.2.5.jar",
"repositoryId": "central",
"selectedVersion": "3.2.5",
"included": true,
"id": "org.apache.maven:maven-core:3.2.5",
"children": [
{
"groupId": "org.apache.maven",
"artifactId": "maven-aether-provider",
"version": "3.2.5",
"checksumAlgorithm": "SHA-256",
"checksum": "703944b922d5351aad53b842f7dd38439b7213425f13c6c7f034b8b699b7d578",
"scope": "provided",
"resolved": "https://repo.maven.apache.org/maven2/org/apache/maven/maven-aether-provider/3.2.5/maven-aether-provider-3.2.5.jar",
"repositoryId": "central",
"selectedVersion": "3.2.5",
"included": true,
"id": "org.apache.maven:maven-aether-provider:3.2.5",
"parent": "org.apache.maven:maven-core:3.2.5",
"children": [
{...}
]
},
{...}
]
},
{...}
]
},
{...}
],
"metaData": {
"environment": {
"osName": "Linux",
"mavenVersion": "3.9.12",
"javaVersion": "21.0.8"
},
"config": {
"includeMavenPlugins": true,
"allowValidationFailure": false,
"allowPomValidat
$ claude mcp add maven-lockfile \
-- python -m otcore.mcp_server <graph>