From c7bd13c3ac4bfd978ce36da6dfa3e126aa7d8d64 Mon Sep 17 00:00:00 2001 From: Jonathan Christison Date: Tue, 4 Jul 2023 23:27:31 +0100 Subject: [PATCH 1/3] Attempt to add PNC Client (Currently Broken) Hit a bug with pnc rest-easy client builder using javax rather than jakarta which means the class fails to load at runtime for some reason, i've tried various dependency inclusions and exclusions as well as using classic resteasy-client in quarkus, all either cause duplicates or give the same error ``` java.lang.RuntimeException: java.lang.ClassNotFoundException: org.glassfish.jersey.client.JerseyClientBuilder javax.ws.rs.client.ClientBuilder.newBuilder(ClientBuilder.java:86) at org.jboss.pnc.client.ClientBase.(ClientBase.java:76) at org.jboss.pnc.client.ArtifactClient.(ArtifactClient.java:22) at com.redhat.pctsec.model.api.service.PncService.(PncService.java:31) ``` --- pom.xml | 47 ++++- .../com/redhat/pctsec/model/PNCBuild.java | 30 ++- .../pctsec/model/api/service/PncService.java | 195 ++++++++++++++++++ .../rest/v1alpha1/ScanRequestsResource.java | 4 +- src/main/resources/application.properties | 6 + .../pctsec/model/test/PNCBuildTest.java | 19 ++ .../model/{osh => test}/paramMapperTest.java | 3 +- 7 files changed, 298 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/redhat/pctsec/model/api/service/PncService.java create mode 100644 src/test/java/com/redhat/pctsec/model/test/PNCBuildTest.java rename src/test/java/com/redhat/pctsec/model/{osh => test}/paramMapperTest.java (83%) 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; From 87f45b8329d6611e370393972909992bed0cbc59 Mon Sep 17 00:00:00 2001 From: Jonathan Christison Date: Wed, 5 Jul 2023 23:21:36 +0100 Subject: [PATCH 2/3] Give up on using PNC rest client for now roll our own There is incompatibility between resteasy in quarkus (6.x) to the one used in PNC (3.x), the API design has changed quite a bit and it seems impossible to have both exist on the classpath at the same time. For the one endpoint we need (Build) then our own restclient should do --- pom.xml | 33 ++----------------- .../com/redhat/pctsec/model/PNCBuild.java | 16 +++++++-- .../model/api/service/AltPncService.java | 12 +++++++ 3 files changed, 29 insertions(+), 32 deletions(-) create mode 100644 src/main/java/com/redhat/pctsec/model/api/service/AltPncService.java diff --git a/pom.xml b/pom.xml index 090d0f1..83453dc 100644 --- a/pom.xml +++ b/pom.xml @@ -96,42 +96,15 @@ org.jboss.pnc rest-client 2.5.1 - - - - - - - org.glassfish.jersey.core - jersey-client - 2.34 + io.quarkus + quarkus-rest-client-reactive - - 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 eb8c695..a6f2f88 100644 --- a/src/main/java/com/redhat/pctsec/model/PNCBuild.java +++ b/src/main/java/com/redhat/pctsec/model/PNCBuild.java @@ -1,9 +1,14 @@ package com.redhat.pctsec.model; -import com.redhat.pctsec.model.api.service.PncService; +import com.redhat.pctsec.model.api.service.AltPncService; +//import com.redhat.pctsec.model.api.service.PncService; +import io.quarkus.rest.client.reactive.QuarkusRestClientBuilder; +import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; import jakarta.persistence.Entity; import jakarta.persistence.Transient; +import org.eclipse.microprofile.config.ConfigProvider; +import org.eclipse.microprofile.config.inject.ConfigProperty; import org.jboss.pnc.dto.Build; import java.net.URI; @@ -13,8 +18,16 @@ import java.net.URL; public class PNCBuild extends BuildType{ + @Transient + public static final String apiUrl = ConfigProvider.getConfig().getValue("pnc.api-url",String.class); + @Transient + private static final AltPncService pnc = QuarkusRestClientBuilder.newBuilder().baseUri(URI.create(apiUrl)).build(AltPncService.class); + + + /* @Transient PncService pnc; + */ @Transient Build build; @@ -33,7 +46,6 @@ public class PNCBuild extends BuildType{ public PNCBuild(String buildRef) { super(buildRef); - this.pnc = new PncService(); } @Override diff --git a/src/main/java/com/redhat/pctsec/model/api/service/AltPncService.java b/src/main/java/com/redhat/pctsec/model/api/service/AltPncService.java new file mode 100644 index 0000000..2f09a58 --- /dev/null +++ b/src/main/java/com/redhat/pctsec/model/api/service/AltPncService.java @@ -0,0 +1,12 @@ +package com.redhat.pctsec.model.api.service; +import jakarta.ws.rs.*; +import org.eclipse.microprofile.rest.client.inject.RegisterRestClient; +import org.jboss.pnc.dto.Build; + +@Path("pnc-rest/v2/builds") +@RegisterRestClient +public interface AltPncService { + @GET + @Path("{id}") + Build getBuild(@PathParam("id") String id); +} From bad8b847ecb8db2ae033fa2df89e800548e2e6ad Mon Sep 17 00:00:00 2001 From: Jonathan Christison Date: Thu, 6 Jul 2023 10:53:33 +0100 Subject: [PATCH 3/3] Remove PncService for now --- .../pctsec/model/api/service/PncService.java | 195 ------------------ 1 file changed, 195 deletions(-) delete mode 100644 src/main/java/com/redhat/pctsec/model/api/service/PncService.java 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 deleted file mode 100644 index 026d95d..0000000 --- a/src/main/java/com/redhat/pctsec/model/api/service/PncService.java +++ /dev/null @@ -1,195 +0,0 @@ -/** - * 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); - } - } - -}