Skip to content

Commit

Permalink
Avoid $.components[].externalReferences enrichment
Browse files Browse the repository at this point in the history
  • Loading branch information
vy committed Jan 5, 2024
1 parent a662bdb commit fb588d8
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 122 deletions.
16 changes: 3 additions & 13 deletions src/main/java/org/cyclonedx/maven/BaseCycloneDxMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -215,21 +215,11 @@ public abstract class BaseCycloneDxMojo extends AbstractMojo {
private String outputTimestamp;

/**
* External references to be added.
* <p>
* They will be injected in two locations:
* </p>
* <ol>
* <li><code>$.metadata.component.externalReferences[]</code></li>
* <li><code>$.components[].externalReferences[]</code> (only for <code>$.components[]</code> provided by the project)</li>
* </ol>
* External references to be added to <code>$.metadata.component.externalReferences[]</code>.
*/
@Parameter
private ExternalReference[] externalReferences;

@Parameter(defaultValue = "${mojoExecution}", readonly = true, required = true)
private MojoExecution execution;

@org.apache.maven.plugins.annotations.Component
private MavenProjectHelper mavenProjectHelper;

Expand Down Expand Up @@ -270,7 +260,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);
}

/**
Expand Down Expand Up @@ -314,7 +304,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));
Expand Down
120 changes: 24 additions & 96 deletions src/main/java/org/cyclonedx/maven/DefaultModelConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -165,9 +153,7 @@ private String generatePackageUrl(String groupId, String artifactId, String vers
}

@Override
public Component convert(MojoExecution execution, Artifact artifact, CycloneDxSchema.Version schemaVersion, boolean includeLicenseText) {

// Populate basic fields from the `Artifact` instance
public Component convert(Artifact artifact, CycloneDxSchema.Version schemaVersion, boolean includeLicenseText, ExternalReference[] externalReferences) {
final Component component = new Component();
component.setGroup(artifact.getGroupId());
component.setName(artifact.getArtifactId());
Expand Down Expand Up @@ -202,8 +188,7 @@ public Component convert(MojoExecution execution, Artifact artifact, CycloneDxSc
if (project != null) {

// Populate external references
List<ExternalReference> 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)) {
Expand All @@ -217,68 +202,13 @@ public Component convert(MojoExecution execution, Artifact artifact, CycloneDxSc

}

private List<ExternalReference> 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<ExternalReference> extractExternalReferences(Plugin plugin, MojoExecution activeExecution) {

// Collect external references from the execution configuration
List<ExternalReference> 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<ExternalReference> 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<ExternalReference> parseDom(@Nullable Xpp3Dom dom) {
if (dom == null) {
return new ArrayList<>();
}
String xml = dom.toString();
try {
ExternalReferenceConfigDto dto = MAPPER.readValue(xml, ExternalReferenceConfigDto.class);
@Nullable List<ExternalReference> 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<ExternalReference> externalReferences;

// We need a mutable `List`, hence `Arrays.asList()` won't work!
List<ExternalReference> externalReferences_ = Arrays.stream(externalReferences).collect(Collectors.toList());
component.setExternalReferences(externalReferences_);
}

private boolean isModified(Artifact artifact) {
Expand Down Expand Up @@ -433,7 +363,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"));
Expand All @@ -459,9 +389,7 @@ public Metadata convert(final MavenProject project, String projectType, MojoExec
component.setType(resolveProjectType(projectType));
component.setPurl(generatePackageUrl(project.getArtifact()));
component.setBomRef(component.getPurl());

List<ExternalReference> externalReferences = extractExternalReferences(project, execution);
component.setExternalReferences(externalReferences);
setExternalReferences(component, externalReferences);
extractComponentMetadata(project, component, schemaVersion, includeLicenseText);

final Metadata metadata = new Metadata();
Expand Down
11 changes: 5 additions & 6 deletions src/main/java/org/cyclonedx/maven/ModelConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand All @@ -44,24 +44,23 @@ 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);
}
7 changes: 0 additions & 7 deletions src/test/java/org/cyclonedx/maven/ExternalReferenceTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ public void testAddedExternalReferences() throws Exception {
verifier
.forProject(projDir)
.withCliOption("-Dcyclonedx-maven-plugin.version=" + getCurrentVersion())
.withCliOption("-X")
.withCliOption("-B")
.execute("clean", "verify")
.assertErrorFreeLog();
Expand All @@ -45,12 +44,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"),
Expand Down

0 comments on commit fb588d8

Please sign in to comment.