Skip to content

Commit

Permalink
Merge pull request #34 from tecarter94/add-ability-to-sign-output
Browse files Browse the repository at this point in the history
Add ability to sign artifacts via GPG
  • Loading branch information
stuartwdouglas authored May 13, 2024
2 parents 8cbce60 + 574e19b commit 29bf079
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 6 deletions.
10 changes: 9 additions & 1 deletion README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,12 @@ Sashimono is based on the following principles:
- Builds should be reproducible by default
- Sashimono should have as few dependencies as possible, ideally zero, however some functionality may required additional libraries (e.g. signing).
- All dependencies should be explicit, and referenced by hash. Alternatively trusted keys can be specified to handle the case where a rebuilt dependencies has a different hash to the original. Transient dependencies should be resolved when the Sashimono build file is generated.
- Everything should be checked into the repository, e.g. if you are doing code generation with a Maven plugin the release tag should have this checked in so Sashimono can build it without needed to run the code generator.
- Everything should be checked into the repository, e.g. if you are doing code generation with a Maven plugin the release tag should have this checked in so Sashimono can build it without needed to run the code generator.
Signature generation can be enabled when building with the system property: `-Dsign_artifacts=true`.

The following environment variables are required for signature generation:

- `GPG_EXECUTABLE_PATH` - The absolute path to your GPG executable/binary.
- `GPG_KEYNAME` - The name of the private key within your secret keyring that you wish to sign with.
- `GPG_PASSPHRASE` - The passphrase encrypting your private key.
7 changes: 7 additions & 0 deletions builder/src/main/java/dev/sashimono/builder/Sashimono.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import dev.sashimono.builder.jar.JarTask;
import dev.sashimono.builder.jar.JavadocJarTask;
import dev.sashimono.builder.jar.PomTask;
import dev.sashimono.builder.jar.SignatureTask;
import dev.sashimono.builder.jar.SourcesJarTask;
import dev.sashimono.builder.util.Task;
import dev.sashimono.builder.util.TaskRunner;
Expand Down Expand Up @@ -53,6 +54,8 @@ public void buildProject() {
runner.addResultMapper(JarResult.class, JarResult.RESOLVED_DEPENDENCY_MAPPER);
runner.addResultMapper(JarResult.class, JarResult.FILE_OUTPUT_MAPPER);
Task<Void> digestTask = runner.newTask(Void.class, new DigestTask());
Task<Void> signatureTask = runner.newTask(Void.class, new SignatureTask());
signatureTask.addDependency(digestTask);
Map<GAV, Task<FileOutput>> pomTasks = new HashMap<>();
Map<GAV, Task<FileOutput>> sourcesJarTasks = new HashMap<>();
Map<GAV, Task<FileOutput>> javadocJarTasks = new HashMap<>();
Expand Down Expand Up @@ -108,13 +111,17 @@ public void buildProject() {
Task<JarResult> jarTask = jarTasks.get(m.gav());
jarTask.addDependency(compileTask);
digestTask.addDependency(jarTask);
signatureTask.addDependency(jarTask);
Task<FileOutput> pomTask = pomTasks.get(m.gav());
digestTask.addDependency(pomTask);
signatureTask.addDependency(pomTask);
Task<FileOutput> sourcesJarTask = sourcesJarTasks.get(m.gav());
digestTask.addDependency(sourcesJarTask);
signatureTask.addDependency(sourcesJarTask);
Task<FileOutput> javadocJarTask = javadocJarTasks.get(m.gav());
javadocJarTask.addDependency(documentationTask);
digestTask.addDependency(javadocJarTask);
signatureTask.addDependency(javadocJarTask);
}
}
runner.run();
Expand Down
3 changes: 2 additions & 1 deletion builder/src/main/java/dev/sashimono/builder/jar/PomTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public FileOutput apply(final TaskMap taskMap) {
final Path parentDir = FileUtil.getOutputPath(outputDir, gav);
try {
Files.createDirectories(parentDir);
final Path targetPomPath = parentDir.resolve(sourcePomPath.getFileName());
final String pomFileName = gav.artifact() + "-" + gav.version() + ".pom";
final Path targetPomPath = parentDir.resolve(pomFileName);
Files.copy(sourcePomPath, targetPomPath, StandardCopyOption.REPLACE_EXISTING);
log.infof("copied pom to %s", targetPomPath);
return new FileOutput(targetPomPath);
Expand Down
59 changes: 59 additions & 0 deletions builder/src/main/java/dev/sashimono/builder/jar/SignatureTask.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package dev.sashimono.builder.jar;

import static java.lang.Boolean.getBoolean;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.file.Path;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Function;

import dev.sashimono.builder.util.Log;
import dev.sashimono.builder.util.TaskMap;

public class SignatureTask implements Function<TaskMap, Void> {

private static final Log log = Log.of(SignatureTask.class);

@Override
public Void apply(final TaskMap taskMap) {
if (getBoolean("sign_artifacts")) {
final Path executablePath = Path.of(System.getenv("GPG_EXECUTABLE_PATH"));
final String keyName = System.getenv("GPG_KEYNAME");
final String passPhrase = System.getenv("GPG_PASSPHRASE");

final List<FileOutput> outputs = taskMap.results(FileOutput.class);
for (final FileOutput i : outputs) {
final Path inputPath = i.file().toAbsolutePath();
final String inputFileName = inputPath.getFileName().toString();
if (inputFileName.endsWith(".jar") || inputFileName.endsWith(".pom")) {
final Path outputPath = inputPath
.resolveSibling(inputFileName + ".asc");
final ProcessBuilder processBuilder = new ProcessBuilder();
final List<String> args = List.of(executablePath.toString(), "--local-user", keyName, "--passphrase",
passPhrase, "--batch", "--no-tty", "--armor", "--detach-sign", "--pinentry-mode", "loopback",
"--output", outputPath.toString(), "--sign", inputPath.toString());
processBuilder.command(args);
final ExecutorService executorService = Executors.newFixedThreadPool(2);
try {
final Process process = processBuilder.start();
executorService.submit(() -> new BufferedReader(new InputStreamReader(process.getInputStream())).lines()
.forEach(log::info));
executorService.submit(() -> new BufferedReader(new InputStreamReader(process.getErrorStream())).lines()
.forEach(log::error));
process.waitFor();
} catch (final IOException | InterruptedException e) {
throw new RuntimeException(e);
} finally {
executorService.shutdown();
}
}
}
}
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public class BuildProjectTestCase {
public void testBuildingSimpleProject(BuildResult result) throws IOException {
Path dir = result.output().resolve("com").resolve("foo").resolve("test").resolve("1.1.0.Final");
Path jar = dir.resolve("test-1.1.0.Final.jar");
Path pom = dir.resolve("pom.xml");
Path pom = dir.resolve("test-1.1.0.Final.pom");
Path sourcesJar = dir.resolve("test-1.1.0.Final-sources.jar");
Path javadocJar = dir.resolve("test-1.1.0.Final-javadoc.jar");
Assertions.assertTrue(Files.exists(jar));
Expand Down Expand Up @@ -142,7 +142,7 @@ public static void main(String ... args) {
public void testBuildingMultiModuleProject(BuildResult result) throws IOException {
Path dir = result.output().resolve("com").resolve("acme").resolve("foo").resolve("1.0");
Path jar = dir.resolve("foo-1.0.jar");
Path pom = dir.resolve("pom.xml");
Path pom = dir.resolve("foo-1.0.pom");
Path sourcesJar = dir.resolve("foo-1.0-sources.jar");
Path javadocJar = dir.resolve("foo-1.0-javadoc.jar");
Assertions.assertTrue(Files.exists(jar));
Expand Down Expand Up @@ -221,7 +221,7 @@ public String greet() {

dir = result.output().resolve("com").resolve("acme").resolve("bar").resolve("1.0");
jar = dir.resolve("bar-1.0.jar");
pom = dir.resolve("pom.xml");
pom = dir.resolve("bar-1.0.pom");
sourcesJar = dir.resolve("bar-1.0-sources.jar");
javadocJar = dir.resolve("bar-1.0-javadoc.jar");
Assertions.assertTrue(Files.exists(jar));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public void beforeEach(ExtensionContext context) throws Exception {
//TODO: should this be in some kind of extension system that lets you apply tests to all builds?

try (Stream<Path> pathStream = Files.walk(tempDir)) {
pathStream.filter(f -> f.getFileName().toString().endsWith(".jar") || f.getFileName().toString().endsWith(".xml"))
pathStream.filter(f -> f.getFileName().toString().endsWith(".jar") || f.getFileName().toString().endsWith(".pom"))
.forEach(f -> {
try (var in = Files.newInputStream(f)) {
Path md5 = f.getParent().resolve(f.getFileName() + ".md5");
Expand Down

0 comments on commit 29bf079

Please sign in to comment.