diff --git a/pom.xml b/pom.xml index a9acab6..090d0f1 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ UTF-8 quarkus-bom io.quarkus.platform - 3.1.2.Final + 3.1.3.Final true 3.0.0 @@ -87,6 +87,51 @@ io.quarkus quarkus-kubernetes-config + + org.jboss.pnc + common + 2.5.1 + + + org.jboss.pnc + rest-client + 2.5.1 + + + + + + + + + org.glassfish.jersey.core + jersey-client + 2.34 + + + io.quarkus quarkus-junit5 diff --git a/src/main/java/com/redhat/pctsec/model/PNCBuild.java b/src/main/java/com/redhat/pctsec/model/PNCBuild.java index 36f9b55..eb8c695 100644 --- a/src/main/java/com/redhat/pctsec/model/PNCBuild.java +++ b/src/main/java/com/redhat/pctsec/model/PNCBuild.java @@ -1,23 +1,47 @@ package com.redhat.pctsec.model; +import com.redhat.pctsec.model.api.service.PncService; +import jakarta.inject.Inject; import jakarta.persistence.Entity; +import jakarta.persistence.Transient; +import org.jboss.pnc.dto.Build; import java.net.URI; import java.net.URL; @Entity public class PNCBuild extends BuildType{ + + + @Transient + PncService pnc; + + @Transient + Build build; + + private URI SCMURL; + private String revision; + public PNCBuild() { super(); } + public Build getBuild() { + if(build == null) + build = pnc.getBuild(this.buildRef); + return build; + } public PNCBuild(String buildRef) { super(buildRef); + this.pnc = new PncService(); } @Override public URI SCMURL() { - return null; + if(SCMURL == null) + SCMURL = URI.create(getBuild().getScmUrl()); + + return this.SCMURL; } @Override @@ -27,7 +51,9 @@ public class PNCBuild extends BuildType{ @Override public String revision() { - return null; + if(revision == null) + revision = getBuild().getScmTag(); + return revision; } public static boolean isValidRef(String ref){ diff --git a/src/main/java/com/redhat/pctsec/model/api/service/PncService.java b/src/main/java/com/redhat/pctsec/model/api/service/PncService.java new file mode 100644 index 0000000..026d95d --- /dev/null +++ b/src/main/java/com/redhat/pctsec/model/api/service/PncService.java @@ -0,0 +1,195 @@ +/** + * Stolen from + * https://github.com/project-ncl/sbomer/blob/3b2ef857e8c0cefe9324ea401fa3fbe53499c615/cli/src/main/java/org/jboss/sbomer/cli/feature/sbom/service/PncService.java + */ +package com.redhat.pctsec.model.api.service; + +//import jakarta.annotation.PostConstruct; +//import jakarta.annotation.PreDestroy; +import jakarta.enterprise.context.ApplicationScoped; +import jakarta.ws.rs.WebApplicationException; +import org.eclipse.microprofile.config.inject.ConfigProperty; +import org.jboss.logging.Logger; +import org.jboss.pnc.client.*; +import org.jboss.pnc.dto.Artifact; +import org.jboss.pnc.dto.Build; +import org.jboss.pnc.dto.BuildConfiguration; +import org.jboss.pnc.dto.ProductVersionRef; + +import java.util.Optional; + +/** + * A service to interact with the PNC build system. + */ + +//@ApplicationScoped +public class PncService { + + private static final Logger log = Logger.getLogger(PncService.class); + + public PncService() { + artifactClient = new ArtifactClient(getConfiguration()); + buildClient = new BuildClient(getConfiguration()); + buildConfigurationClient = new BuildConfigurationClient(getConfiguration()); + } + + public String getApiUrl() { + return apiUrl; + } + + @ConfigProperty(name = "pnc.api-url") + String apiUrl; + + ArtifactClient artifactClient; + + BuildClient buildClient; + + BuildConfigurationClient buildConfigurationClient; + + /* + @PostConstruct + void init() { + artifactClient = new ArtifactClient(getConfiguration()); + buildClient = new BuildClient(getConfiguration()); + buildConfigurationClient = new BuildConfigurationClient(getConfiguration()); + } + + @PreDestroy + void cleanup() { + artifactClient.close(); + buildClient.close(); + buildConfigurationClient.close(); + } + */ + + /** + * Setup basic configuration to be able to talk to PNC. + * + * + * @return + */ + public Configuration getConfiguration() { + return Configuration.builder().host(apiUrl).protocol("http").build(); + } + + /** + *

+ * Fetch information about the PNC {@link Build} identified by the particular {@code buildId}. + *

+ * + *

+ * In case the {@link Build} with provided identifier cannot be found {@code null} is returned. + *

+ * + * @param buildId Tbe {@link Build} identifier in PNC + * @return The {@link Build} object or {@code null} in case the {@link Build} could not be found. + */ + public Build getBuild(String buildId) { + log.debugv("Fetching Build from PNC with id '{}'", buildId); + try { + return buildClient.getSpecific(buildId); + } catch (RemoteResourceNotFoundException ex) { + log.warnv("Build with id '{}' was not found in PNC", buildId); + return null; + } catch (RemoteResourceException ex) { + throw new WebApplicationException("Build could not be retrieved because PNC responded with an error", ex); + } + } + + /** + *

+ * Fetch information about the PNC {@link BuildConfiguration} identified by the particular {@code buildConfigId}. + *

+ * + *

+ * In case the {@link BuildConfiguration} with provided identifier cannot be found {@code null} is returned. + *

+ * + * @param buildId Tbe {@link BuildConfiguration} identifier in PNC + * @return The {@link BuildConfiguration} object or {@code null} in case the {@link BuildConfiguration} could not be + * found. + */ + public BuildConfiguration getBuildConfig(String buildConfigId) { + log.debugv("Fetching BuildConfig from PNC with id '{}'", buildConfigId); + try { + return buildConfigurationClient.getSpecific(buildConfigId); + } catch (RemoteResourceNotFoundException ex) { + log.warnv("BuildConfig with id '{}' was not found in PNC", buildConfigId); + return null; + } catch (RemoteResourceException ex) { + throw new WebApplicationException( + "BuildConfig could not be retrieved because PNC responded with an error", + ex); + } + } + + /** + *

+ * Obtains the {@link ProductVersionRef} for a given PNC {@link Build} identifier. + *

+ * + * @param buildId The {@link Build} identifier to get the Product Version for. + * @return The {@link ProductVersionRef} object for the related or {@code null} in case it is not possible to obtain + * it. + */ + public ProductVersionRef getProductVersion(String buildId) { + log.debugv("Fetching Product Version information from PNC for build '{}'", buildId); + + if (buildId == null) { + return null; + } + Build build = getBuild(buildId); + + if (build == null) { + log.warn("Build related to the SBOM could not be found in PNC, interrupting processing"); + return null; + } + + BuildConfiguration buildConfig = getBuildConfig(build.getBuildConfigRevision().getId()); + + if (buildConfig == null) { + log.warn("BuildConfig related to the SBOM could not be found in PNC, interrupting processing"); + return null; + } + + ProductVersionRef productVersion = buildConfig.getProductVersion(); + + if (productVersion == null) { + log.warn( + "BuildConfig related to the SBOM does not provide product version information, interrupting processing"); + return null; + } + + return productVersion; + } + + /** + * Fetch information about the PNC {@link Artifact} identified by the particular purl. + * + * @param purl + * @return The {@link Artifact} object or {@code null} if it cannot be found. + */ + public Artifact getArtifact(String purl) { + log.debugv("Fetching artifact from PNC for purl '{}'", purl); + + try { + String artifactQuery = "purl==\"" + purl + "\""; + RemoteCollection artifacts = artifactClient + .getAll(null, null, null, Optional.empty(), Optional.of(artifactQuery)); + if (artifacts.size() == 0) { + log.debugv("Artifact with purl '{}' was not found in PNC", purl); + return null; + } else if (artifacts.size() > 1) { + throw new IllegalStateException("There should exist only one artifact with purl " + purl); + } + return artifacts.iterator().next(); + } catch (RemoteResourceNotFoundException ex) { + throw new WebApplicationException("Artifact with purl" + purl + "was not found in PNC", ex); + } catch (RemoteResourceException ex) { + throw new WebApplicationException( + "Artifact with purl" + purl + "could not be retrieved because PNC responded with an error", + ex); + } + } + +} diff --git a/src/main/java/com/redhat/pctsec/rest/v1alpha1/ScanRequestsResource.java b/src/main/java/com/redhat/pctsec/rest/v1alpha1/ScanRequestsResource.java index 6b26743..5564b64 100644 --- a/src/main/java/com/redhat/pctsec/rest/v1alpha1/ScanRequestsResource.java +++ b/src/main/java/com/redhat/pctsec/rest/v1alpha1/ScanRequestsResource.java @@ -9,7 +9,7 @@ import io.quarkus.security.Authenticated; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.ws.rs.*; -import org.jboss.resteasy.reactive.common.NotImplementedYet; +//import org.jboss.resteasy.reactive.common.NotImplementedYet; import java.util.UUID; @@ -35,7 +35,7 @@ public class ScanRequestsResource { @Authenticated public ScanRequests addScanRequest(String id, ScanRequest scanRequest) { - throw new NotImplementedYet(); + throw new WebApplicationException("Not implemented"); } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index a2748bb..750c602 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -57,6 +57,7 @@ quarkus.arc.remove-unused-beans=false %stage.quarkus.openshift.route.target-port=https %stage.quarkus.openshift.route.tls.insecure-edge-termination-policy=redirect %stage.quarkus.openshift.namespace=pct-security-tooling +quarkus.openshift.namespace=pct-security-tooling ########################################## # Kerberos Specifics # @@ -80,5 +81,10 @@ tekton.pipeline.ref=osh-client-from-source tekton.task.ref=osh-scan-task tekton.service-account=${quarkus.openshift.service-account} +########################################## +# PNC Settings # +########################################## +pnc.api-url=http://orch.psi.redhat.com + diff --git a/src/test/java/com/redhat/pctsec/model/test/PNCBuildTest.java b/src/test/java/com/redhat/pctsec/model/test/PNCBuildTest.java new file mode 100644 index 0000000..76a571b --- /dev/null +++ b/src/test/java/com/redhat/pctsec/model/test/PNCBuildTest.java @@ -0,0 +1,19 @@ +package com.redhat.pctsec.model.test; + +import com.redhat.pctsec.model.PNCBuild; +import io.quarkus.test.junit.QuarkusTest; +import jakarta.inject.Inject; +import org.junit.jupiter.api.Test; + +@QuarkusTest +public class PNCBuildTest { + + + + @Test + public void testBuildFetch(){ + PNCBuild pb = new PNCBuild("AZAQZSPFDRQAA"); + System.out.println(pb.SCMURL()); + System.out.println(pb.revision()); + } +} diff --git a/src/test/java/com/redhat/pctsec/model/osh/paramMapperTest.java b/src/test/java/com/redhat/pctsec/model/test/paramMapperTest.java similarity index 83% rename from src/test/java/com/redhat/pctsec/model/osh/paramMapperTest.java rename to src/test/java/com/redhat/pctsec/model/test/paramMapperTest.java index f24ee8c..f376e8f 100644 --- a/src/test/java/com/redhat/pctsec/model/osh/paramMapperTest.java +++ b/src/test/java/com/redhat/pctsec/model/test/paramMapperTest.java @@ -1,5 +1,6 @@ -package com.redhat.pctsec.model.osh; +package com.redhat.pctsec.model.test; +import com.redhat.pctsec.model.osh.paramMapper; import io.quarkus.test.junit.QuarkusTest; import jakarta.inject.Inject; import org.junit.jupiter.api.Test;