From 3df829eb11992fce0daffa6999993b3d6f6e433c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Volkan=20Yaz=C4=B1c=C4=B1?= Date: Fri, 5 Jan 2024 13:22:19 +0100 Subject: [PATCH] Avoid `$.components[].externalReferences` enrichment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Volkan Yazıcı --- .../cyclonedx/maven/BaseCycloneDxMojo.java | 24 ++-- .../maven/DefaultModelConverter.java | 118 ++++-------------- .../org/cyclonedx/maven/ModelConverter.java | 10 +- .../maven/ExternalReferenceTest.java | 6 - 4 files changed, 38 insertions(+), 120 deletions(-) diff --git a/src/main/java/org/cyclonedx/maven/BaseCycloneDxMojo.java b/src/main/java/org/cyclonedx/maven/BaseCycloneDxMojo.java index 4ce1eafe..c9845107 100644 --- a/src/main/java/org/cyclonedx/maven/BaseCycloneDxMojo.java +++ b/src/main/java/org/cyclonedx/maven/BaseCycloneDxMojo.java @@ -24,7 +24,6 @@ import org.apache.maven.model.Plugin; import org.apache.maven.model.PluginExecution; import org.apache.maven.plugin.AbstractMojo; -import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.project.MavenProject; @@ -37,7 +36,12 @@ import org.cyclonedx.generators.json.BomJsonGenerator; import org.cyclonedx.generators.xml.BomXmlGenerator; import org.cyclonedx.maven.ProjectDependenciesConverter.BomDependencies; -import org.cyclonedx.model.*; +import org.cyclonedx.model.Bom; +import org.cyclonedx.model.Component; +import org.cyclonedx.model.Dependency; +import org.cyclonedx.model.ExternalReference; +import org.cyclonedx.model.Metadata; +import org.cyclonedx.model.Property; import org.cyclonedx.parsers.JsonParser; import org.cyclonedx.parsers.Parser; import org.cyclonedx.parsers.XmlParser; @@ -215,21 +219,11 @@ public abstract class BaseCycloneDxMojo extends AbstractMojo { private String outputTimestamp; /** - * External references to be added. - *

- * They will be injected in two locations: - *

- *
    - *
  1. $.metadata.component.externalReferences[]
  2. - *
  3. $.components[].externalReferences[] (only for $.components[] provided by the project)
  4. - *
+ * External references to be added to $.metadata.component.externalReferences[]. */ @Parameter private ExternalReference[] externalReferences; - @Parameter(defaultValue = "${mojoExecution}", readonly = true, required = true) - private MojoExecution execution; - @org.apache.maven.plugins.annotations.Component private MavenProjectHelper mavenProjectHelper; @@ -270,7 +264,7 @@ protected String generatePackageUrl(final Artifact artifact) { } protected Component convert(Artifact artifact) { - return modelConverter.convert(execution, artifact, schemaVersion(), includeLicenseText); + return modelConverter.convert(artifact, schemaVersion(), includeLicenseText, externalReferences); } /** @@ -314,7 +308,7 @@ public void execute() throws MojoExecutionException { String analysis = extractComponentsAndDependencies(topLevelComponents, componentMap, dependencyMap); if (analysis != null) { - final Metadata metadata = modelConverter.convert(project, projectType, execution, schemaVersion(), includeLicenseText); + final Metadata metadata = modelConverter.convert(project, projectType, schemaVersion(), includeLicenseText, externalReferences); if (schemaVersion().getVersion() >= 1.3) { metadata.addProperty(newProperty("maven.goal", analysis)); diff --git a/src/main/java/org/cyclonedx/maven/DefaultModelConverter.java b/src/main/java/org/cyclonedx/maven/DefaultModelConverter.java index 62b9dc12..692468f5 100644 --- a/src/main/java/org/cyclonedx/maven/DefaultModelConverter.java +++ b/src/main/java/org/cyclonedx/maven/DefaultModelConverter.java @@ -18,42 +18,20 @@ */ package org.cyclonedx.maven; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.net.URISyntaxException; -import java.util.ArrayList; -import java.util.List; -import java.util.Properties; -import java.util.TreeMap; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import javax.annotation.Nullable; -import javax.inject.Inject; -import javax.inject.Named; -import javax.inject.Singleton; - -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.MapperFeature; -import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.github.packageurl.MalformedPackageURLException; +import com.github.packageurl.PackageURL; import org.apache.commons.lang3.StringUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.DefaultArtifact; import org.apache.maven.artifact.handler.DefaultArtifactHandler; import org.apache.maven.execution.MavenSession; import org.apache.maven.model.MailingList; -import org.apache.maven.model.Plugin; import org.apache.maven.model.building.ModelBuildingRequest; -import org.apache.maven.plugin.MojoExecution; import org.apache.maven.project.MavenProject; import org.apache.maven.project.ProjectBuilder; import org.apache.maven.project.ProjectBuildingException; import org.apache.maven.project.ProjectBuildingResult; import org.apache.maven.repository.RepositorySystem; -import org.codehaus.plexus.util.xml.Xpp3Dom; import org.cyclonedx.CycloneDxSchema; import org.cyclonedx.model.Component; import org.cyclonedx.model.ExternalReference; @@ -67,8 +45,18 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.github.packageurl.MalformedPackageURLException; -import com.github.packageurl.PackageURL; +import javax.inject.Inject; +import javax.inject.Named; +import javax.inject.Singleton; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; +import java.util.TreeMap; +import java.util.stream.Collectors; @Singleton @Named @@ -165,7 +153,7 @@ private String generatePackageUrl(String groupId, String artifactId, String vers } @Override - public Component convert(MojoExecution execution, Artifact artifact, CycloneDxSchema.Version schemaVersion, boolean includeLicenseText) { + public Component convert(Artifact artifact, CycloneDxSchema.Version schemaVersion, boolean includeLicenseText, ExternalReference[] externalReferences) { // Populate basic fields from the `Artifact` instance final Component component = new Component(); @@ -202,8 +190,7 @@ public Component convert(MojoExecution execution, Artifact artifact, CycloneDxSc if (project != null) { // Populate external references - List externalReferences = extractExternalReferences(project, execution); - component.setExternalReferences(externalReferences); + setExternalReferences(component, externalReferences); // Extract the rest of the metadata for JARs, i.e., *described* artifacts if (isDescribedArtifact(artifact)) { @@ -217,68 +204,13 @@ public Component convert(MojoExecution execution, Artifact artifact, CycloneDxSc } - private List extractExternalReferences(MavenProject project, MojoExecution activeExecution) { - Plugin activePlugin = activeExecution.getPlugin(); - return project - .getBuild() - .getPlugins() - .stream() - .filter(plugin -> activePlugin.getGroupId().equals(plugin.getGroupId()) && activePlugin.getArtifactId().equals(plugin.getArtifactId())) - .findFirst() - .map(plugin -> extractExternalReferences(plugin, activeExecution)) - .orElseGet(ArrayList::new); - } - - private static List extractExternalReferences(Plugin plugin, MojoExecution activeExecution) { - - // Collect external references from the execution configuration - List executionExternalReferences = plugin - .getExecutions() - .stream() - .filter(execution -> activeExecution.getExecutionId().equals(execution.getId())) - .flatMap(execution -> { - Xpp3Dom executionConfig = (Xpp3Dom) execution.getConfiguration(); - return ExternalReferenceConfigDto.parseDom(executionConfig).stream(); - }) - .collect(Collectors.toList()); - - // Collect external references from the plugin configuration - Xpp3Dom pluginConfig = (Xpp3Dom) plugin.getConfiguration(); - List pluginExternalReferences = ExternalReferenceConfigDto.parseDom(pluginConfig); - - // Combine collected external references - return Stream - .concat(executionExternalReferences.stream(), pluginExternalReferences.stream()) - .distinct() - .collect(Collectors.toList()); - - } - - private static final class ExternalReferenceConfigDto { - - private static final XmlMapper MAPPER = XmlMapper - .builder() - .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) - .enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS) - .build(); - - private static List parseDom(@Nullable Xpp3Dom dom) { - if (dom == null) { - return new ArrayList<>(); - } - String xml = dom.toString(); - try { - ExternalReferenceConfigDto dto = MAPPER.readValue(xml, ExternalReferenceConfigDto.class); - @Nullable List externalReferences = dto.externalReferences; - return externalReferences != null ? externalReferences : new ArrayList<>(); - } catch (JsonProcessingException error) { - throw new RuntimeException(error); - } + private static void setExternalReferences(Component component, ExternalReference[] externalReferences) { + if (externalReferences == null || externalReferences.length == 0) { + return; } - - @JsonProperty - private List externalReferences; - + // We need a mutable `List`, hence `Arrays.asList()` won't work. + List externalReferences_ = Arrays.stream(externalReferences).collect(Collectors.toList()); + component.setExternalReferences(externalReferences_); } private boolean isModified(Artifact artifact) { @@ -433,7 +365,7 @@ else if (licenseChoiceToResolve.getExpression() != null && CycloneDxSchema.Versi } @Override - public Metadata convert(final MavenProject project, String projectType, MojoExecution execution, CycloneDxSchema.Version schemaVersion, boolean includeLicenseText) { + public Metadata convert(final MavenProject project, String projectType, CycloneDxSchema.Version schemaVersion, boolean includeLicenseText, ExternalReference[] externalReferences) { final Tool tool = new Tool(); final Properties properties = readPluginProperties(); tool.setVendor(properties.getProperty("vendor")); @@ -459,9 +391,7 @@ public Metadata convert(final MavenProject project, String projectType, MojoExec component.setType(resolveProjectType(projectType)); component.setPurl(generatePackageUrl(project.getArtifact())); component.setBomRef(component.getPurl()); - - List externalReferences = extractExternalReferences(project, execution); - component.setExternalReferences(externalReferences); + setExternalReferences(component, externalReferences); extractComponentMetadata(project, component, schemaVersion, includeLicenseText); final Metadata metadata = new Metadata(); diff --git a/src/main/java/org/cyclonedx/maven/ModelConverter.java b/src/main/java/org/cyclonedx/maven/ModelConverter.java index d3ae77f8..5493162a 100644 --- a/src/main/java/org/cyclonedx/maven/ModelConverter.java +++ b/src/main/java/org/cyclonedx/maven/ModelConverter.java @@ -19,10 +19,10 @@ package org.cyclonedx.maven; import org.apache.maven.artifact.Artifact; -import org.apache.maven.plugin.MojoExecution; import org.apache.maven.project.MavenProject; import org.cyclonedx.CycloneDxSchema; import org.cyclonedx.model.Component; +import org.cyclonedx.model.ExternalReference; import org.cyclonedx.model.Metadata; /** @@ -44,24 +44,24 @@ public interface ModelConverter { * Converts a Maven artifact (dependency or transitive dependency) into a * CycloneDX component. * - * @param execution the associated execution * @param artifact the artifact to convert * @param schemaVersion the target CycloneDX schema version * @param includeLicenseText should license text be included in bom? + * @param externalReferences the external references * @return a CycloneDX component */ - Component convert(MojoExecution execution, Artifact artifact, CycloneDxSchema.Version schemaVersion, boolean includeLicenseText); + Component convert(Artifact artifact, CycloneDxSchema.Version schemaVersion, boolean includeLicenseText, ExternalReference[] externalReferences); /** * Converts a MavenProject into a Metadata object. * * @param project the MavenProject to convert * @param projectType the target CycloneDX component type - * @param execution the associated execution * @param schemaVersion the target CycloneDX schema version * @param includeLicenseText should license text be included in bom? + * @param externalReferences the external references * @return a CycloneDX Metadata object */ - Metadata convert(MavenProject project, String projectType, MojoExecution execution, CycloneDxSchema.Version schemaVersion, boolean includeLicenseText); + Metadata convert(MavenProject project, String projectType, CycloneDxSchema.Version schemaVersion, boolean includeLicenseText, ExternalReference[] externalReferences); } diff --git a/src/test/java/org/cyclonedx/maven/ExternalReferenceTest.java b/src/test/java/org/cyclonedx/maven/ExternalReferenceTest.java index 2d082b72..d725fbd7 100644 --- a/src/test/java/org/cyclonedx/maven/ExternalReferenceTest.java +++ b/src/test/java/org/cyclonedx/maven/ExternalReferenceTest.java @@ -45,12 +45,6 @@ public void testAddedExternalReferences() throws Exception { "$.metadata.component.externalReferences[?(@.type=='chat')].url", Collections.singleton("https://acme.com/parent")); - // Verify parent components - assertExternalReferences( - new File(projDir, "target/bom.json"), - "$.components[?(@.name=='child')].externalReferences[?(@.type=='chat')].url", - Arrays.asList("https://acme.com/parent", "https://acme.com/child")); - // Verify child metadata assertExternalReferences( new File(projDir, "child/target/bom.json"),