This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ant-antlibs-cyclonedx.git
The following commit(s) were added to refs/heads/main by this push:
new 159b309 tweaks
159b309 is described below
commit 159b3096753ce55143498c8eb3ef589d53dc38f4
Author: Stefan Bodewig <[email protected]>
AuthorDate: Sat May 16 13:22:24 2026 +0200
tweaks
---
docs/component.html | 2 +-
src/main/org/apache/ant/cyclonedx/Component.java | 106 +++++++++++++----------
src/tests/antunit/component-test.xml | 33 +++++++
3 files changed, 93 insertions(+), 48 deletions(-)
diff --git a/docs/component.html b/docs/component.html
index c5ad4d9..fbb402a 100644
--- a/docs/component.html
+++ b/docs/component.html
@@ -73,7 +73,7 @@ <h3>Attributes</h3>
(purl)</a> of the component.</td>
<td>No - if not set but <code>name</code>, <code>group</code>
and <code>version</code> are present an implicit purl is
- calculated as <code>pkg:maven</code> purl from these
+ calculated as <code>pkg:maven</code> jar purl from these
values.</td>
</tr>
<tr>
diff --git a/src/main/org/apache/ant/cyclonedx/Component.java
b/src/main/org/apache/ant/cyclonedx/Component.java
index 0e123f2..8445ac3 100644
--- a/src/main/org/apache/ant/cyclonedx/Component.java
+++ b/src/main/org/apache/ant/cyclonedx/Component.java
@@ -308,6 +308,7 @@ public class Component extends DataType {
public void addComponent(Component c) {
checkChildrenAllowed();
nestedComponents.add(c);
+ // the newly added component may cause a circular dependency
setChecked(false);
}
@@ -415,6 +416,10 @@ public class Component extends DataType {
return result;
}
+ /**
+ * Whether this component links to an external SBOM and wants to
+ * read data from it.
+ */
public boolean hasSbomLink() {
if (isReference()) {
return getRef().hasSbomLink();
@@ -423,13 +428,22 @@ public class Component extends DataType {
return sbomLink != null;
}
- public Collection<Component> resolve() throws IOException {
+ /**
+ * Read the linked SBOM (if any) and merge its content with the
+ * one already defined for this component.
+ *
+ * @return the "addtional" components defined in the linked SBOM
+ * that are dependencies of this component.
+ */
+ public synchronized Collection<Component> resolve() throws IOException {
if (isReference()) {
return getRef().resolve();
}
dieOnCircularReference();
if (sbomLink != null && !sbomLinkResolved) {
+ sbomLinkResolved = true;
+
Bom bom = readLinkedSbom();
if (bom.getMetadata() == null) {
throw new BuildException("referenced SBOM file lacks
metadata");
@@ -439,23 +453,14 @@ public class Component extends DataType {
throw new BuildException("referenced SBOM file lacks
component");
}
List<org.cyclonedx.model.Dependency> allDependencies =
bom.getDependencies();
- fillFrom(real, allDependencies);
-
- List<org.cyclonedx.model.Component> additionalComponents =
bom.getComponents();
- if (additionalComponents != null && !areDependenciesUnknown()) {
- List<Component> toReturn = new ArrayList<>();
- for (org.cyclonedx.model.Component c : additionalComponents) {
- Component dep = from(c, Collections.emptyList());
- if (dependencies.stream().anyMatch(d ->
Objects.equals(dep.getBomRef(), d.getBomRef()))) {
- // only include "additional components" this component
depends on directly.
- // we don't want to resolve transitive dependencies
automatically
- dep.setUnknownDependencies(true);
- toReturn.add(dep);
- }
+ fillFromBomLink(real, allDependencies);
+
+ if (!areDependenciesUnknown() && !dependencies.isEmpty()) {
+ List<org.cyclonedx.model.Component> additionalComponents =
bom.getComponents();
+ if (additionalComponents != null) {
+ return
extractComponentsThatAreDirectDependencies(additionalComponents);
}
- return toReturn;
}
- sbomLinkResolved = true;
}
return Collections.emptyList();
@@ -484,16 +489,10 @@ public class Component extends DataType {
if (scope != null) {
component.setScope(scope);
}
+ // add isExternal once VERSION_17 is supported by cyclonedx-java-core
return component;
}
- private static Component from(org.cyclonedx.model.Component real,
- List<org.cyclonedx.model.Dependency>
dependencies) {
- Component c = new Component();
- c.fillFrom(real, dependencies);
- return c;
- }
-
private org.cyclonedx.model.Component toCycloneDxComponent(Version
bomVersion)
throws IOException {
dieOnCircularReference();
@@ -548,20 +547,6 @@ public class Component extends DataType {
if (supplier != null) {
component.setSupplier(supplier.toOrganizationalEntity());
}
- if (!authors.isEmpty()) {
- component.setAuthors(authors);
- }
- if (!properties.isEmpty()) {
- component.setProperties(properties);
- }
- if (!tags.isEmpty()) {
- component.setTags(new
Tags(tags.stream().sorted().collect(Collectors.toList())));
- }
- if (!licenses.isEmpty()) {
- LicenseChoice lc = new LicenseChoice();
- lc.setLicenses(licenses);
- component.setLicenses(lc);
- }
String purl = getPurl();
if (purl != null) {
component.setPurl(purl);
@@ -572,19 +557,45 @@ public class Component extends DataType {
} else if (!dependencies.isEmpty()) {
throw new BuildException("a component with dependencies must
provide a bomRef");
}
- if (!externalReferences.isEmpty()) {
- component.setExternalReferences(externalReferences);
- }
+ component.setAuthors(authors);
+ component.setProperties(properties);
+ component.setTags(new
Tags(tags.stream().sorted().collect(Collectors.toList())));
+ LicenseChoice lc = new LicenseChoice();
+ lc.setLicenses(licenses);
+ component.setLicenses(lc);
+ component.setExternalReferences(externalReferences);
for (Component c : nestedComponents) {
component.addComponent(c.toAdditionalCycloneDxComponent(bomVersion));
}
- // add isExternal once VERSION_17 is supported by cyclonedx-java-core
addHashes(component, bomVersion);
return component;
}
- private void fillFrom(org.cyclonedx.model.Component real,
- List<org.cyclonedx.model.Dependency>
allDependencies) {
+ private List<Component>
extractComponentsThatAreDirectDependencies(List<org.cyclonedx.model.Component>
cs) {
+ List<Component> toReturn = new ArrayList<>();
+ for (org.cyclonedx.model.Component c : cs) {
+ Component dep = from(c, Collections.emptyList());
+ if (dependencies.stream().anyMatch(d ->
Objects.equals(dep.getBomRef(), d.getBomRef()))) {
+ // only include "additional components" this component depends
on directly.
+ // we don't want to resolve transitive dependencies
automatically
+ dep.setUnknownDependencies(true);
+ toReturn.add(dep);
+ }
+ }
+ return toReturn;
+ }
+
+ private static Component from(
+ org.cyclonedx.model.Component real,
+ List<org.cyclonedx.model.Dependency> dependencies) {
+ Component c = new Component();
+ c.fillFromBomLink(real, dependencies);
+ return c;
+ }
+
+ private void fillFromBomLink(
+ org.cyclonedx.model.Component real,
+ List<org.cyclonedx.model.Dependency> allDependencies) {
if (type == null) {
setType(ComponentType.from(real.getType()));
}
@@ -668,11 +679,11 @@ public class Component extends DataType {
}
}
if (dependencies.isEmpty() && allDependencies != null) {
- fillDependencies(allDependencies);
+ fillDependenciesFromBomLink(allDependencies);
}
}
- private void fillDependencies(List<org.cyclonedx.model.Dependency>
allDependencies) {
+ private void
fillDependenciesFromBomLink(List<org.cyclonedx.model.Dependency>
allDependencies) {
setUnknownDependencies(true);
org.cyclonedx.model.Dependency myDependencies = allDependencies
.stream()
@@ -766,15 +777,16 @@ public class Component extends DataType {
return bomRef;
}
+ String refid = componentRef.getRefId();
Object component = componentRef.getReferencedObject();
if (component instanceof Component) {
String b = ((Component) component).getBomRef();
if (b == null) {
- throw new BuildException("component with id '" +
componentRef.getRefId() + "' doesn't provide a bomRef");
+ throw new BuildException("component with id '" + refid +
"' doesn't provide a bomRef");
}
return b;
}
- throw new BuildException("componentRef '" +
componentRef.getRefId() + "' doesn't refer to a component");
+ throw new BuildException("componentRef '" + refid + "' doesn't
refer to a component");
}
static Dependency from(org.cyclonedx.model.Dependency dependency) {
diff --git a/src/tests/antunit/component-test.xml
b/src/tests/antunit/component-test.xml
index be612d6..8bc47c4 100644
--- a/src/tests/antunit/component-test.xml
+++ b/src/tests/antunit/component-test.xml
@@ -913,6 +913,39 @@
value='<hash alg="SHA-256">${ant.file.sha256}</hash>'/>
</target>
+ <target
+ name="testSbomLinkDoesNotUseLinkedSupplierIfManufacturerIsSupplier"
+ depends="createMaximalComponentData">
+ <cdx:componentbom
+ bomName="merged"
+ outputdirectory="${output}"
+ format="xml"
+ xmlns:cdx="antlib:org.apache.ant.cyclonedx">
+ <component manufacturerIsSupplier="true">
+ <sbomLink>
+ <file file="${output}/bom.json"/>
+ </sbomLink>
+ </component>
+ </cdx:componentbom>
+ <xmlproperty file="${output}/merged.xml"/>
+ <au:assertPropertyEquals
+ xmlns:au="antlib:org.apache.ant.antunit"
+ name="bom.metadata.component.manufacturer.name"
+ value="Example"/>
+ <au:assertPropertyEquals
+ xmlns:au="antlib:org.apache.ant.antunit"
+ name="bom.metadata.component.manufacturer.url"
+ value="https://example.org/"/>
+ <au:assertPropertyEquals
+ xmlns:au="antlib:org.apache.ant.antunit"
+ name="bom.metadata.component.supplier.name"
+ value="Example"/>
+ <au:assertPropertyEquals
+ xmlns:au="antlib:org.apache.ant.antunit"
+ name="bom.metadata.component.supplier.url"
+ value="https://example.org/"/>
+ </target>
+
<target
name="testDataFromLinkedSbomCanBeOverwerittenOrMerged"
depends="createMaximalComponentData">