Skip to content

Commit

Permalink
generate report of verification status
Browse files Browse the repository at this point in the history
fix: #136
  • Loading branch information
slawekjaranowski committed Jun 6, 2021
1 parent d8ca7ff commit 1ab2c2f
Show file tree
Hide file tree
Showing 17 changed files with 441 additions and 57 deletions.
8 changes: 8 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,14 @@
<groupId>io.vavr</groupId>
<artifactId>vavr</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
Expand Down
2 changes: 2 additions & 0 deletions src/it/sigOkKeysMapWithPluginDependencies/keysmap.list
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,8 @@ org.eclipse.aether = 0xBA926F64CA647B6D853A38672E2010F8A7FF4A41
org.eclipse.jetty = 0x5989BAF76217B843D66BE55B2D0E1FB8FE4B68B4
org.eclipse.sisu = 0xCF17E92C9FFA55316B5DB83901D734EE5EE9C3F8

com.fasterxml.jackson.core = 0x8A10792983023D5D14C93B488D7F1BEC1E2ECAE7

org.hamcrest:hamcrest-core:1.1 = noSig
org.hamcrest:hamcrest-library:1.3 = 0x4DB1A49729B053CAF015CEE9A6ADFC93EF34893E
org.iq80.snappy:snappy:0.4 = 0x9E93DB1192CEE3D3B581AABB37E9D58EA4598641
Expand Down
1 change: 1 addition & 0 deletions src/it/sigOkKeysMapWithPluginDependencies/pom-test.xml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
<verifyPluginDependencies>true</verifyPluginDependencies>
<verifyAtypical>true</verifyAtypical>
<verifySnapshots>true</verifySnapshots>
<reportWrite>true</reportWrite>
</configuration>
<executions>
<execution>
Expand Down
4 changes: 4 additions & 0 deletions src/it/sigOkKeysMapWithPluginDependencies/postbuild.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,7 @@ assert buildLog.matches('(?ms).*^\\[INFO\\] org.apache.httpcomponents:httpcore:j
assert buildLog.matches('(?ms).*^\\[INFO\\] com.vladsch.flexmark:flexmark-all:jar:.* PGP Signature OK$.*')
assert buildLog.matches('(?ms).*^\\[INFO\\] commons-validator:commons-validator:jar:.* PGP Signature OK$.*')
assert buildLog.contains('[INFO] BUILD SUCCESS')

def reportFile = new File(basedir, "target/pgpverify-report.json")
assert reportFile.exists()
assert reportFile.length() > 0
10 changes: 5 additions & 5 deletions src/main/java/org/simplify4u/plugins/AbstractVerifyMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
package org.simplify4u.plugins;

import java.time.Duration;
import java.util.LinkedHashSet;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -170,7 +170,7 @@ public final void executeConfiguredMojo() throws MojoExecutionException {
LOGGER.info("Resolved {} signature(s) in {}", artifactMap.size(),
Duration.ofNanos(System.nanoTime() - signatureResolutionStart));

Set<V> verificationResult;
Collection<V> verificationResult;
final long artifactValidationStart = System.nanoTime();
try {
verificationResult = processArtifactsSignatures(artifactMap);
Expand Down Expand Up @@ -206,7 +206,7 @@ public final void executeConfiguredMojo() throws MojoExecutionException {
*
* @param verificationResult a verification result
*/
protected abstract void processVerificationResult(Set<V> verificationResult);
protected abstract void processVerificationResult(Collection<V> verificationResult);

private SkipFilter prepareDependencyFilters() {
final List<SkipFilter> filters = new LinkedList<>();
Expand Down Expand Up @@ -242,10 +242,10 @@ private SkipFilter preparePluginFilters() {
return new CompositeSkipper(filters);
}

private Set<V> processArtifactsSignatures(Map<Artifact, Artifact> artifactToAsc) {
private Collection<V> processArtifactsSignatures(Map<Artifact, Artifact> artifactToAsc) {
return artifactToAsc.entrySet().stream()
.map(entry -> processArtifactSignature(entry.getKey(), entry.getValue()))
.filter(Objects::nonNull)
.collect(Collectors.toCollection(LinkedHashSet::new));
.collect(Collectors.toList());
}
}
99 changes: 83 additions & 16 deletions src/main/java/org/simplify4u/plugins/CheckMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.inject.Inject;

import io.vavr.control.Try;
import lombok.Builder;
import lombok.extern.slf4j.Slf4j;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.ArtifactUtils;
Expand All @@ -36,6 +39,7 @@
import org.simplify4u.plugins.keysmap.KeysMap;
import org.simplify4u.plugins.keysmap.KeysMapLocationConfig;
import org.simplify4u.plugins.pgp.PublicKeyUtils;
import org.simplify4u.plugins.pgp.ReportsUtils;
import org.simplify4u.plugins.pgp.SignatureCheckResult;

/**
Expand All @@ -46,15 +50,26 @@
@Slf4j
@Mojo(name = CheckMojo.MOJO_NAME, requiresDependencyResolution = ResolutionScope.TEST,
defaultPhase = LifecyclePhase.VALIDATE, threadSafe = true)
public class CheckMojo extends AbstractVerifyMojo<Boolean> {
public class CheckMojo extends AbstractVerifyMojo<CheckMojo.VerificationResult> {

/**
* Verification result item.
*/
@Builder
public static class VerificationResult {
boolean error;
SignatureCheckResult result;
}

public static final String MOJO_NAME = "check";

private static final String PGP_VERIFICATION_RESULT_FORMAT = "{} PGP Signature {}\n {} UserIds: {}";

@Inject
protected KeysMap keysMap;
private KeysMap keysMap;

@Inject
private ReportsUtils reportsUtils;

/**
* Fail the build if any dependency doesn't have a signature.
Expand Down Expand Up @@ -123,6 +138,35 @@ public class CheckMojo extends AbstractVerifyMojo<Boolean> {
@Parameter(property = "pgpverify.keysMapLocation", alias = "keysMapLocations")
private List<KeysMapLocationConfig> keysMapLocation = new ArrayList<>();

/**
* <p>
* Path to report file of verification result.
* </p>
*
* <p>
* <a href="report-format.html">Report file format</a>
* </p>
*
* @since 1.13.0
*/
@Parameter(property = "pgpverify.reportFile",
defaultValue = "${project.build.directory}/pgpverify-report.json")
private File reportFile;

/**
* <p>
* Indicate if verification report should be generated.
* </p>
*
* <p>
* <a href="report-format.html">Report file format</a>
* </p>
*
* @since 1.13.0
*/
@Parameter(property = "pgpverify.reportWrite", defaultValue = "false")
private boolean reportWrite;

@Override
protected String getMojoName() {
return MOJO_NAME;
Expand Down Expand Up @@ -186,9 +230,13 @@ protected void shouldProcess(Set<Artifact> artifacts, Runnable runnable) {
}

@Override
protected Boolean processArtifactSignature(Artifact artifact, Artifact ascArtifact) {
protected VerificationResult processArtifactSignature(Artifact artifact, Artifact ascArtifact) {

SignatureCheckResult signatureCheckResult = signatureUtils.checkSignature(artifact, ascArtifact, pgpKeysCache);

VerificationResult.VerificationResultBuilder verificationResultBuilder = VerificationResult.builder()
.result(signatureCheckResult);

switch (signatureCheckResult.getStatus()) {
case ARTIFACT_NOT_RESOLVED:
throw new PGPMojoException("Artifact not resolved: %s", artifact.getId());
Expand All @@ -198,14 +246,17 @@ protected Boolean processArtifactSignature(Artifact artifact, Artifact ascArtifa
case SIGNATURE_ERROR:
if (keysMap.isBrokenSignature(artifact)) {
logInfoWithQuiet("{} PGP Signature is broken, consistent with keys map.", artifact::getId);
return true;
verificationResultBuilder.error(false);
break;
}

LOGGER.error("Failed to process signature for artifact {} - {}",
artifact.getId(), signatureCheckResult.getErrorMessage());
return false;
verificationResultBuilder.error(true);
break;
case SIGNATURE_NOT_RESOLVED:
return verifySignatureUnavailable(artifact);
verificationResultBuilder.error(!verifySignatureUnavailable(artifact));
break;
case SIGNATURE_VALID:
verifyWeakSignature(signatureCheckResult.getSignature().getHashAlgorithm());

Expand All @@ -214,7 +265,8 @@ protected Boolean processArtifactSignature(Artifact artifact, Artifact ascArtifa
PublicKeyUtils.fingerprintForMaster(signatureCheckResult.getKey()));
LOGGER.error("Not allowed artifact {} and keyID:\n\t{}\n\t{}",
artifact.getId(), msg, signatureCheckResult.getKeyShowUrl());
return false;
verificationResultBuilder.error(true);
break;
}

LOGGER.debug("signature.KeyAlgorithm: {} signature.hashAlgorithm: {}",
Expand All @@ -225,37 +277,51 @@ protected Boolean processArtifactSignature(Artifact artifact, Artifact ascArtifa
() -> PublicKeyUtils.keyIdDescription(signatureCheckResult.getKey()),
() -> signatureCheckResult.getKey().getUids());

return true;
verificationResultBuilder.error(false);
break;
case SIGNATURE_INVALID:
if (keysMap.isBrokenSignature(artifact)) {
logInfoWithQuiet("{} PGP Signature is broken, consistent with keys map.", artifact::getId);
return true;
verificationResultBuilder.error(false);
break;
}
if (LOGGER.isErrorEnabled()) {
LOGGER.error(PGP_VERIFICATION_RESULT_FORMAT, artifact.getId(),
"INVALID", PublicKeyUtils.keyIdDescription(signatureCheckResult.getKey()),
signatureCheckResult.getKey().getUids());
}
return false;
verificationResultBuilder.error(true);
break;
case KEY_NOT_FOUND:
if (keysMap.isKeyMissing(artifact)) {
logInfoWithQuiet("{} PGP key not found on keyserver, consistent with keys map.",
artifact::getId);
return true;
verificationResultBuilder.error(false);
break;
}

LOGGER.error("PGP key {} not found on keyserver for artifact {}",
signatureCheckResult.getKeyShowUrl(), artifact.getId());
return false;

verificationResultBuilder.error(true);
break;
default:
return false;
verificationResultBuilder.error(true);
break;
}

return verificationResultBuilder.build();
}

@Override
protected void processVerificationResult(Set<Boolean> verificationResult) {
if (verificationResult.stream().anyMatch(result -> !result)) {
protected void processVerificationResult(Collection<VerificationResult> verificationResult) {

if (reportWrite) {
Try.run(() -> reportsUtils.writeReportAsJson(reportFile,
verificationResult.stream().map(v -> v.result).collect(Collectors.toList())))
.getOrElseThrow(e -> new PGPMojoException(e.getMessage(), e));
}

if (verificationResult.stream().anyMatch(result -> result.error)) {
throw new PGPMojoException("Signature errors");
}
}
Expand Down Expand Up @@ -299,4 +365,5 @@ private boolean verifySignatureUnavailable(Artifact artifact) {
}
return false;
}

}
3 changes: 2 additions & 1 deletion src/main/java/org/simplify4u/plugins/GoOfflineMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.simplify4u.plugins;

import java.util.Collection;
import java.util.Optional;
import java.util.Set;

Expand Down Expand Up @@ -62,7 +63,7 @@ protected Void processArtifactSignature(Artifact artifact, Artifact ascArtifact)
}

@Override
protected void processVerificationResult(Set<Void> verificationResult) {
protected void processVerificationResult(Collection<Void> verificationResult) {
// not used
}
}
2 changes: 2 additions & 0 deletions src/main/java/org/simplify4u/plugins/pgp/KeyFingerprint.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package org.simplify4u.plugins.pgp;

import com.fasterxml.jackson.annotation.JsonValue;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import org.simplify4u.plugins.utils.HexUtils;
Expand All @@ -36,6 +37,7 @@ public KeyFingerprint(String strFingerprint) {
fingerprint = HexUtils.stringToFingerprint(strFingerprint);
}

@JsonValue
public String toString() {
return HexUtils.fingerprintToString(fingerprint);
}
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/simplify4u/plugins/pgp/KeyId.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

import static org.simplify4u.plugins.utils.HexUtils.fingerprintToString;

import com.fasterxml.jackson.annotation.JsonValue;
import lombok.EqualsAndHashCode;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
Expand Down Expand Up @@ -63,6 +64,7 @@ public PGPPublicKeyRing getKeyRingFromRingCollection(PGPPublicKeyRingCollection
}

@Override
@JsonValue
public String toString() {
return String.format("0x%016X", keyId);
}
Expand Down Expand Up @@ -103,6 +105,8 @@ public PGPPublicKeyRing getKeyRingFromRingCollection(PGPPublicKeyRingCollection
return pgpRingCollection.getPublicKeyRing(fingerprint);
}

@Override
@JsonValue
public String toString() {
return fingerprintToString(fingerprint);
}
Expand Down
Loading

0 comments on commit 1ab2c2f

Please sign in to comment.