Skip to content

Commit a32100b

Browse files
AdamKorczIan Lewis
authored andcommitted
feat: add maven verification plugin (slsa-framework#2380)
Adds a Maven plugin that makes it easy to verify the provenance files of all dependencies of a Maven-based project. The plugin can either run during the Maven build cycle, or users can invoke it manually from within a project directory. The plugin checks whether the dependencies in a `pom.xml` file are released with provenance attestations, and invokes the [slsa-verifier](https://github.com/slsa-framework/slsa-verifier) against the dependencies that have provenance files. @loosebazooka @laurentsimon --------- Signed-off-by: AdamKorcz <[email protected]> Signed-off-by: AdamKorcz <[email protected]> Co-authored-by: Ian Lewis <[email protected]> Signed-off-by: Noah Elzner <[email protected]>
1 parent 09291d5 commit a32100b

File tree

3 files changed

+251
-0
lines changed

3 files changed

+251
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Maven verification plugin
2+
3+
The Maven verification plugin can be used to verify the provenance of the dependencies of a Java project.
4+
5+
It is meant to make it easy for project owners and consumers to:
6+
1: Check how many and which dependencies of a Maven-based project are released with provenance files.
7+
2: Verify the provenance files of the dependencies of a given Maven-based project.
8+
9+
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`.
10+
11+
## Prerequisites
12+
13+
To use the plugin you must have Go, Java and Maven installed. It has currently only been tested on Ubuntu.
14+
15+
The plugin requires that the slsa-verifier is already installed on the machine.
16+
17+
## Development status
18+
19+
The plugin is in its early stages and is not ready for production.
20+
21+
Things that work well are:
22+
1: Resolving dependencies and checking whether they have provenance files in the remote repository.
23+
2: Running the slsa-verifier against dependencies with provenance files.
24+
3: Outputting the result from the slsa-verifier.
25+
26+
Things that are unfinished:
27+
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.
28+
29+
## Using the Maven verification plugin
30+
31+
### Invoking it directly
32+
33+
It can be run from the root of a given project file.
34+
A pseudo-workflow looks like this:
35+
1: `git clone --depth=1 https://github.com/slsa-framework/slsa-github-generator`
36+
2: `cd slsa-github-generator/internal/builders/maven/plugins/verification-plugin`
37+
3: `mvn clean install`
38+
4: `cd /tmp`
39+
5: `git clone your repository to text`
40+
6: `cd into your repository`
41+
7: `mvn io.github.adamkorcz:slsa-verification-plugin:0.0.1:verify`
42+
43+
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.
44+
45+
### Integrating it into your Maven build cycle
46+
47+
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.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0"
2+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4+
5+
<modelVersion>4.0.0</modelVersion>
6+
<groupId>io.github.adamkorcz</groupId>
7+
<artifactId>slsa-verification-plugin</artifactId>
8+
<packaging>maven-plugin</packaging>
9+
<version>0.0.1</version>
10+
11+
<name>Slsa Verification Mojo</name>
12+
<url>http://maven.apache.org</url>
13+
14+
<properties>
15+
<maven.compiler.target>1.8</maven.compiler.target>
16+
<maven.compiler.source>1.8</maven.compiler.source>
17+
</properties>
18+
19+
<dependencies>
20+
<dependency>
21+
<groupId>org.apache.maven</groupId>
22+
<artifactId>maven-core</artifactId>
23+
<version>3.2.5</version>
24+
</dependency>
25+
<dependency>
26+
<groupId>org.apache.maven</groupId>
27+
<artifactId>maven-plugin-api</artifactId>
28+
<version>3.6.3</version>
29+
</dependency>
30+
<dependency>
31+
<groupId>org.apache.maven.plugin-tools</groupId>
32+
<artifactId>maven-plugin-annotations</artifactId>
33+
<version>3.6.0</version>
34+
<scope>provided</scope>
35+
</dependency>
36+
<dependency>
37+
<groupId>org.apache.maven</groupId>
38+
<artifactId>maven-project</artifactId>
39+
<version>2.2.1</version>
40+
</dependency>
41+
<dependency>
42+
<groupId>org.twdata.maven</groupId>
43+
<artifactId>mojo-executor</artifactId>
44+
<version>2.4.0</version>
45+
</dependency>
46+
</dependencies>
47+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
// Copyright 2023 SLSA Authors
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package io.github.adamkorcz;
16+
17+
import org.apache.maven.artifact.Artifact;
18+
import org.apache.maven.execution.MavenSession;
19+
import org.apache.maven.plugin.AbstractMojo;
20+
import org.apache.maven.plugin.BuildPluginManager;
21+
import org.apache.maven.plugin.MojoExecutionException;
22+
import org.apache.maven.plugin.MojoFailureException;
23+
import org.apache.maven.plugins.annotations.LifecyclePhase;
24+
import org.apache.maven.plugins.annotations.Component;
25+
import org.apache.maven.plugins.annotations.Mojo;
26+
import org.apache.maven.plugins.annotations.Parameter;
27+
import org.apache.maven.project.MavenProject;
28+
29+
import static org.twdata.maven.mojoexecutor.MojoExecutor.*;
30+
31+
import java.io.File;
32+
import java.util.Set;
33+
34+
/*
35+
SlsaVerificationMojo is a Maven plugin that wraps https://github.com/slsa-framework/slsa-verifier.
36+
At a high level, it does the following:
37+
1: Install the slsa-verifier.
38+
2: Loop through all dependencies of a pom.xml. Resolve each dependency.
39+
3: Check if each dependency also has a provenance file.
40+
4: Run the slsa-verifier for the dependency if there is a provenance file.
41+
5: Output the results.
42+
43+
The plugin is meant to be installed and then run from the root of a given project file.
44+
A pseudo-workflow looks like this:
45+
1: git clone --depth=1 https://github.com/slsa-framework/slsa-github-generator
46+
2: cd slsa-github-generator/internal/builders/maven/plugins/verification-plugin
47+
3: mvn clean install
48+
4: cd /tmp
49+
5: git clone your repository
50+
6: cd into your repository
51+
7: mvn io.github.adamkorcz:slsa-verification-plugin:0.0.1:verify
52+
*/
53+
@Mojo(name = "verify", defaultPhase = LifecyclePhase.VALIDATE)
54+
public class SlsaVerificationMojo extends AbstractMojo {
55+
@Parameter(defaultValue = "${project}", required = true, readonly = true)
56+
private MavenProject project;
57+
58+
/**
59+
* Custom path of GOHOME, default value is $HOME/go
60+
**/
61+
@Parameter(property = "slsa.verifier.path", required = true)
62+
private String verifierPath;
63+
64+
@Component
65+
private MavenSession mavenSession;
66+
67+
@Component
68+
private BuildPluginManager pluginManager;
69+
70+
71+
public void execute() throws MojoExecutionException, MojoFailureException {
72+
// Verify the slsa of each dependency
73+
Set<Artifact> dependencyArtifacts = project.getDependencyArtifacts();
74+
for (Artifact artifact : dependencyArtifacts ) {
75+
// Retrieve the dependency jar and its slsa file
76+
String artifactStr = artifact.getGroupId() + ":" + artifact.getArtifactId() + ":" + artifact.getVersion();
77+
try {
78+
// Retrieve the slsa file of the artifact
79+
executeMojo(
80+
plugin(
81+
groupId("com.googlecode.maven-download-plugin"),
82+
artifactId("download-maven-plugin"),
83+
version("1.7.0")
84+
),
85+
goal("artifact"),
86+
configuration(
87+
element(name("outputDirectory"), "${project.build.directory}/slsa"),
88+
element(name("groupId"), artifact.getGroupId()),
89+
element(name("artifactId"), artifact.getArtifactId()),
90+
element(name("version"), artifact.getVersion()),
91+
element(name("type"), "intoto.build.slsa"),
92+
element(name("classifier"), "jar")
93+
),
94+
executionEnvironment(
95+
project,
96+
mavenSession,
97+
pluginManager
98+
)
99+
);
100+
101+
// Retrieve the dependency jar if slsa file does exists for this artifact
102+
executeMojo(
103+
plugin(
104+
groupId("org.apache.maven.plugins"),
105+
artifactId("maven-dependency-plugin"),
106+
version("3.6.0")
107+
),
108+
goal("copy"),
109+
configuration(
110+
element(name("outputDirectory"), "${project.build.directory}/slsa"),
111+
element(name("artifact"), artifactStr)
112+
),
113+
executionEnvironment(
114+
project,
115+
mavenSession,
116+
pluginManager
117+
)
118+
);
119+
} catch(MojoExecutionException e) {
120+
getLog().info("Skipping slsa verification for " + artifactStr + ": No slsa file found.");
121+
continue;
122+
}
123+
124+
// Verify slsa file
125+
try {
126+
// Run slsa verification on the artifact and print the result
127+
// It will never fail the build process
128+
// This might be prone to command-injections. TODO: Secure against that.
129+
String arguments = "verify-artifact --provenance-path ";
130+
arguments += "${project.build.directory}/slsa/" + artifact.getArtifactId() + "-" + artifact.getVersion() + "-jar.intoto.build.slsa ";
131+
arguments += " --source-uri ./ ${project.build.directory}/slsa/" + artifact.getArtifactId() + "-" + artifact.getVersion() + ".jar";
132+
executeMojo(
133+
plugin(
134+
groupId("org.codehaus.mojo"),
135+
artifactId("exec-maven-plugin"),
136+
version("3.1.0")
137+
),
138+
goal("exec"),
139+
configuration(
140+
element(name("executable"), verifierPath),
141+
element(name("commandlineArgs"), arguments),
142+
element(name("useMavenLogger"), "true")
143+
),
144+
executionEnvironment(
145+
project,
146+
mavenSession,
147+
pluginManager
148+
)
149+
);
150+
} catch(MojoExecutionException e) {
151+
// TODO: Properly interpret the output based on the verification plugin.
152+
getLog().info("Skipping slsa verification: Fail to run slsa verifier.");
153+
return;
154+
}
155+
}
156+
}
157+
}

0 commit comments

Comments
 (0)