Skip to content

Commit

Permalink
initial test at signing with sigstore
Browse files Browse the repository at this point in the history
  • Loading branch information
hboutemy committed Apr 12, 2023
1 parent ffc82c2 commit df6b4f1
Show file tree
Hide file tree
Showing 3 changed files with 267 additions and 3 deletions.
37 changes: 36 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,18 @@ under the License.

<properties>
<mavenVersion>3.2.5</mavenVersion>
<javaVersion>8</javaVersion>
<javaVersion>11</javaVersion>
<maven.compiler.release>${javaVersion}</maven.compiler.release>
<project.build.outputTimestamp>2021-05-05T16:39:01Z</project.build.outputTimestamp>
<resource.delimiter>@</resource.delimiter>
</properties>

<dependencies>
<dependency>
<groupId>dev.sigstore</groupId>
<artifactId>sigstore-java</artifactId>
<version>0.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
Expand Down Expand Up @@ -282,5 +288,34 @@ under the License.
</plugins>
</build>
</profile>

<profile>
<id>apache-release</id>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>${project.version}</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<executions>
<execution>
<id>sigstore-sign-release-artifacts</id>
<goals>
<goal>sigstore</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public class GpgSignAttachedMojo
{

private static final String DEFAULT_EXCLUDES[] =
new String[] { "**/*.md5", "**/*.sha1", "**/*.sha256", "**/*.sha512", "**/*.asc" };
new String[] { "**/*.md5", "**/*.sha1", "**/*.sha256", "**/*.sha512", "**/*.asc", "**/*.sigstore" };

/**
* Skip doing the gpg signing.
Expand All @@ -60,7 +60,8 @@ public class GpgSignAttachedMojo

/**
* A list of files to exclude from being signed. Can contain Ant-style wildcards and double wildcards. The default
* excludes are <code>**&#47;*.md5 **&#47;*.sha1 **&#47;*.sha256 **&#47;*.sha512 **&#47;*.asc</code>.
* excludes are <code>**&#47;*.md5 **&#47;*.sha1 **&#47;*.sha256 **&#47;*.sha512
* **&#47;*.asc **&#47;*.sigstore</code>.
*
* @since 1.0-alpha-4
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,228 @@
package org.apache.maven.plugins.gpg;

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.
*/

import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.SelectorUtils;

import dev.sigstore.KeylessSignature;
import dev.sigstore.KeylessSigner;
import dev.sigstore.bundle.BundleFactory;

/**
* Sign project artifact, the POM, and attached artifacts with sigstore for deployment.
*
* @since 3.1.0
*/
@Mojo( name = "sigstore", defaultPhase = LifecyclePhase.VERIFY, threadSafe = true )
public class SigstoreSignAttachedMojo
extends AbstractMojo
{

private static final String DEFAULT_EXCLUDES[] =
new String[] { "**/*.md5", "**/*.sha1", "**/*.sha256", "**/*.sha512", "**/*.asc", "**/*.sigstore" };

/**
* Skip doing the gpg signing.
*/
@Parameter( property = "sigstore.skip", defaultValue = "false" )
private boolean skip;

/**
* A list of files to exclude from being signed. Can contain Ant-style wildcards and double wildcards. The default
* excludes are <code>**&#47;*.md5 **&#47;*.sha1 **&#47;*.sha256 **&#47;*.sha512
* **&#47;*.asc **&#47;*.sigstore</code>.
*/
@Parameter
private String[] excludes;

/**
* The Maven project.
*/
@Parameter( defaultValue = "${project}", readonly = true, required = true )
protected MavenProject project;

/**
* Maven ProjectHelper
*/
@Component
private MavenProjectHelper projectHelper;

@Override
public void execute()
throws MojoExecutionException, MojoFailureException
{
if ( skip )
{
// We're skipping the signing stuff
return;
}

if ( excludes == null || excludes.length == 0 )
{
excludes = DEFAULT_EXCLUDES;
}
String newExcludes[] = new String[excludes.length];
for ( int i = 0; i < excludes.length; i++ )
{
String pattern;
pattern = excludes[i].trim().replace( '/', File.separatorChar ).replace( '\\', File.separatorChar );
if ( pattern.endsWith( File.separator ) )
{
pattern += "**";
}
newExcludes[i] = pattern;
}
excludes = newExcludes;

List<SigningBundle> filesToSign = new ArrayList<>();

if ( !"pom".equals( project.getPackaging() ) )
{
// ----------------------------------------------------------------------------
// Project artifact
// ----------------------------------------------------------------------------

Artifact artifact = project.getArtifact();

File file = artifact.getFile();

if ( file != null && file.isFile() )
{
filesToSign.add( new SigningBundle( artifact.getArtifactHandler().getExtension(), file ) );
}
else if ( project.getAttachedArtifacts().isEmpty() )
{
throw new MojoFailureException( "The project artifact has not been assembled yet. "
+ "Please do not invoke this goal before the lifecycle phase \"package\"." );
}
else
{
getLog().debug( "Main artifact not assembled, skipping signature generation" );
}
}

// ----------------------------------------------------------------------------
// POM
// ----------------------------------------------------------------------------

File pomToSign = new File( project.getBuild().getDirectory(), project.getBuild().getFinalName() + ".pom" );

try
{
FileUtils.copyFile( project.getFile(), pomToSign );
}
catch ( IOException e )
{
throw new MojoExecutionException( "Error copying POM for signing.", e );
}

filesToSign.add( new SigningBundle( "pom", pomToSign ) );

// ----------------------------------------------------------------------------
// Attached artifacts
// ----------------------------------------------------------------------------

for ( Object o : project.getAttachedArtifacts() )
{
Artifact artifact = (Artifact) o;

File file = artifact.getFile();

if ( isExcluded( artifact ) )
{
getLog().debug( "Skipping generation of signature for excluded " + file );
continue;
}

filesToSign.add( new SigningBundle( artifact.getArtifactHandler().getExtension(),
artifact.getClassifier(), file ) );
}

// ----------------------------------------------------------------------------
// Sign the filesToSign and attach all the signatures
// ----------------------------------------------------------------------------

try
{
KeylessSigner signer = KeylessSigner.builder().sigstoreStagingDefaults().build();
for ( SigningBundle bundleToSign : filesToSign )
{
File fileToSign = bundleToSign.getSignature(); // reusing original GPG implementation where it's the signature: TODO change

KeylessSignature signature = signer.signFile( fileToSign.toPath() );

// sigstore signature in bundle format (json string)
String sigstoreBundle = BundleFactory.createBundle( signature );

File signatureFile = new File( fileToSign + ".sigstore" );
FileUtils.fileWrite( signatureFile, "UTF-8", sigstoreBundle );

projectHelper.attachArtifact( project, bundleToSign.getExtension() + ".sigstore",
bundleToSign.getClassifier(), signatureFile );
}
}
catch ( Exception e )
{
throw new MojoExecutionException( "Error while signing with sigstore", e );
}
}

/**
* Tests whether or not a name matches against at least one exclude pattern.
*
* @param artifact The artifact to match. Must not be <code>null</code>.
* @return <code>true</code> when the name matches against at least one exclude pattern, or <code>false</code>
* otherwise.
*/
protected boolean isExcluded( Artifact artifact )
{
final Path projectBasePath = project.getBasedir().toPath();
final Path artifactPath = artifact.getFile().toPath();
final String relativeArtifactPath = projectBasePath.relativize( artifactPath ).toString();

for ( String exclude : excludes )
{
if ( SelectorUtils.matchPath( exclude, relativeArtifactPath ) )
{
return true;
}
}

return false;
}

}

0 comments on commit df6b4f1

Please sign in to comment.