diff --git a/experimental/maven-plugin/README.md b/experimental/maven-plugin/README.md new file mode 100644 index 000000000..274a24643 --- /dev/null +++ b/experimental/maven-plugin/README.md @@ -0,0 +1,47 @@ +# Maven verification plugin + +The Maven verification plugin can be used to verify the provenance of the dependencies of a Java project. + +It is meant to make it easy for project owners and consumers to: +1: Check how many and which dependencies of a Maven-based project are released with provenance files. +2: Verify the provenance files of the dependencies of a given Maven-based project. + +The plugin wraps the [the slsa verifier](https://github.com/slsa-framework/slsa-verifier) and invokes it for all the dependencies in a `pom.xml`. + +## Prerequisites + +To use the plugin you must have Go, Java and Maven installed. It has currently only been tested on Ubuntu. + +The plugin requires that the slsa-verifier is already installed on the machine. + +## Development status + +The plugin is in its early stages and is not ready for production. + +Things that work well are: +1: Resolving dependencies and checking whether they have provenance files in the remote repository. +2: Running the slsa-verifier against dependencies with provenance files. +3: Outputting the result from the slsa-verifier. + +Things that are unfinished: +1: What to do with the results from the verifier. Currently we have not taken a stand on what the Maven verification plugin should do with the output from the slsa-verifier. This is a UX decision more than it is a technical decision. + +## Using the Maven verification plugin + +### Invoking it directly + +It can be run from the root of a given project file. +A pseudo-workflow looks like this: + 1: `git clone --depth=1 https://github.com/slsa-framework/slsa-verifier` + 2: `cd slsa-verifier/experimental/maven-plugin` + 3: `mvn clean install` + 4: `cd /tmp` + 5: `git clone your repository to text` + 6: `cd into your repository` + 7: `mvn io.github.slsa-framework:slsa-verification-plugin:0.0.1:verify` + +The plugin will now go through all the dependencies in the `pom.xml` file and check if they have a provenance statement attached to their release. If a dependency has a SLSA provenance file, the Maven verification plugin will fetch it from the remote repository and invoke the `slsa-verifier` binary against the dependency and the provenance file. + +### Integrating it into your Maven build cycle + +The plugin can also live in your Maven build cycle. If you add it to your own `pom.xml`, the plugin will execute during the validation phase of the Maven build cycle. diff --git a/experimental/maven-plugin/pom.xml b/experimental/maven-plugin/pom.xml new file mode 100644 index 000000000..fbe82eff0 --- /dev/null +++ b/experimental/maven-plugin/pom.xml @@ -0,0 +1,47 @@ + + + 4.0.0 + io.github.slsa-framework + slsa-verification-plugin + maven-plugin + 0.0.1 + + Slsa Verification Mojo + http://maven.apache.org + + + 1.8 + 1.8 + + + + + org.apache.maven + maven-core + 3.2.5 + + + org.apache.maven + maven-plugin-api + 3.6.3 + + + org.apache.maven.plugin-tools + maven-plugin-annotations + 3.6.0 + provided + + + org.apache.maven + maven-project + 2.2.1 + + + org.twdata.maven + mojo-executor + 2.4.0 + + + diff --git a/experimental/maven-plugin/src/main/java/io/github/slsa-framework/SlsaVerificationMojo.java b/experimental/maven-plugin/src/main/java/io/github/slsa-framework/SlsaVerificationMojo.java new file mode 100644 index 000000000..028800a9e --- /dev/null +++ b/experimental/maven-plugin/src/main/java/io/github/slsa-framework/SlsaVerificationMojo.java @@ -0,0 +1,157 @@ +// Copyright 2023 SLSA Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package io.github.slsaframework; + +import org.apache.maven.artifact.Artifact; +import org.apache.maven.execution.MavenSession; +import org.apache.maven.plugin.AbstractMojo; +import org.apache.maven.plugin.BuildPluginManager; +import org.apache.maven.plugin.MojoExecutionException; +import org.apache.maven.plugin.MojoFailureException; +import org.apache.maven.plugins.annotations.LifecyclePhase; +import org.apache.maven.plugins.annotations.Component; +import org.apache.maven.plugins.annotations.Mojo; +import org.apache.maven.plugins.annotations.Parameter; +import org.apache.maven.project.MavenProject; + +import static org.twdata.maven.mojoexecutor.MojoExecutor.*; + +import java.io.File; +import java.util.Set; + +/* + SlsaVerificationMojo is a Maven plugin that wraps https://github.com/slsa-framework/slsa-verifier. + At a high level, it does the following: + 1: Install the slsa-verifier. + 2: Loop through all dependencies of a pom.xml. Resolve each dependency. + 3: Check if each dependency also has a provenance file. + 4: Run the slsa-verifier for the dependency if there is a provenance file. + 5: Output the results. + + The plugin is meant to be installed and then run from the root of a given project file. + A pseudo-workflow looks like this: + 1: git clone --depth=1 https://github.com/slsa-framework/slsa-verifier + 2: cd slsa-verifier/experimental/maven-plugin + 3: mvn clean install + 4: cd /tmp + 5: git clone your repository + 6: cd into your repository + 7: mvn io.github.slsa-framework:slsa-verification-plugin:0.0.1:verify +*/ +@Mojo(name = "verify", defaultPhase = LifecyclePhase.VALIDATE) +public class SlsaVerificationMojo extends AbstractMojo { + @Parameter(defaultValue = "${project}", required = true, readonly = true) + private MavenProject project; + + /** + * Custom path of GOHOME, default value is $HOME/go + **/ + @Parameter(property = "slsa.verifier.path", required = true) + private String verifierPath; + + @Component + private MavenSession mavenSession; + + @Component + private BuildPluginManager pluginManager; + + + public void execute() throws MojoExecutionException, MojoFailureException { + // Verify the slsa of each dependency + Set dependencyArtifacts = project.getDependencyArtifacts(); + for (Artifact artifact : dependencyArtifacts ) { + // Retrieve the dependency jar and its slsa file + String artifactStr = artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion(); + try { + // Retrieve the slsa file of the artifact + executeMojo( + plugin( + groupId("com.googlecode.maven-download-plugin"), + artifactId("download-maven-plugin"), + version("1.7.0") + ), + goal("artifact"), + configuration( + element(name("outputDirectory"), "${project.build.directory}/slsa"), + element(name("groupId"), artifact.getGroupId()), + element(name("artifactId"), artifact.getArtifactId()), + element(name("version"), artifact.getVersion()), + element(name("type"), "intoto.build.slsa"), + element(name("classifier"), "jar") + ), + executionEnvironment( + project, + mavenSession, + pluginManager + ) + ); + + // Retrieve the dependency jar if slsa file does exists for this artifact + executeMojo( + plugin( + groupId("org.apache.maven.plugins"), + artifactId("maven-dependency-plugin"), + version("3.6.0") + ), + goal("copy"), + configuration( + element(name("outputDirectory"), "${project.build.directory}/slsa"), + element(name("artifact"), artifactStr) + ), + executionEnvironment( + project, + mavenSession, + pluginManager + ) + ); + } catch(MojoExecutionException e) { + getLog().info("Skipping slsa verification for " + artifactStr + ": No slsa file found."); + continue; + } + + // Verify slsa file + try { + // Run slsa verification on the artifact and print the result + // It will never fail the build process + // This might be prone to command-injections. TODO: Secure against that. + String arguments = "verify-artifact --provenance-path "; + arguments += "${project.build.directory}/slsa/" + artifact.getArtifactId() + "-" + artifact.getVersion() + "-jar.intoto.build.slsa "; + arguments += " --source-uri ./ ${project.build.directory}/slsa/" + artifact.getArtifactId() + "-" + artifact.getVersion() + ".jar"; + executeMojo( + plugin( + groupId("org.codehaus.mojo"), + artifactId("exec-maven-plugin"), + version("3.1.0") + ), + goal("exec"), + configuration( + element(name("executable"), verifierPath), + element(name("commandlineArgs"), arguments), + element(name("useMavenLogger"), "true") + ), + executionEnvironment( + project, + mavenSession, + pluginManager + ) + ); + } catch(MojoExecutionException e) { + // TODO: Properly interpret the output based on the verification plugin. + getLog().info("Skipping slsa verification: Fail to run slsa verifier."); + return; + } + } + } +}