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
commit e2c6b23a137ba15cf034618e5ee05559cc9f434a Author: Stefan Bodewig <[email protected]> AuthorDate: Fri May 1 22:48:32 2026 +0200 NTIA Minimum Elements require bom.metadata.supplier as well --- examples/bom.json | 48 +++++++++++------- examples/bom.xml | 44 +++++++++------- src/main/org/apache/ant/cyclonedx/Component.java | 25 ---------- .../org/apache/ant/cyclonedx/ComponentBomTask.java | 41 +++++++++++++++ .../org/apache/ant/cyclonedx/Organization.java | 32 ++++++++++++ src/main/org/apache/ant/cyclonedx/ToolData.java | 2 +- src/tests/antunit/componentbom-test.xml | 58 +++++++++++++++++++++- 7 files changed, 186 insertions(+), 64 deletions(-) diff --git a/examples/bom.json b/examples/bom.json index 3887657..07879a3 100644 --- a/examples/bom.json +++ b/examples/bom.json @@ -1,10 +1,10 @@ { "bomFormat" : "CycloneDX", "specVersion" : "1.6", - "serialNumber" : "urn:uuid:9473c08b-477c-4087-9fb9-965d51f6b87b", + "serialNumber" : "urn:uuid:932573e3-25d5-4922-a5a1-eaa64e76a184", "version" : 1, "metadata" : { - "timestamp" : "2026-05-01T20:20:09Z", + "timestamp" : "2026-05-01T20:44:53Z", "lifecycles" : [ { "phase" : "build" @@ -33,35 +33,35 @@ "hashes" : [ { "alg" : "MD5", - "content" : "8f400c4cf1c0fced3eb9e0bfd5d18485" + "content" : "6802fde2fdd7103022fb9203fc8ceed2" }, { "alg" : "SHA-1", - "content" : "9d6e76799441f34d56b39aca6415a36d510b463c" + "content" : "06ff4239c338b0e9a6f6b8567a79126c957d4187" }, { "alg" : "SHA-256", - "content" : "0b12ba1c7c6ae24a49581810c7495b92df933c150eddebf94522f5fdb19902d8" + "content" : "480ace3a039d882edb028227aa8ae682cb18fe40461ad757bd04dce7ed513b3f" }, { "alg" : "SHA-512", - "content" : "7eb05a92293ead979a82953f4ac2eb560f7414b7d52a6caa651f2d71d95bee8c5deb1e85235ede013497400f005a938d7ce3647396a9f2c7859afaa5e1991102" + "content" : "e888ecde1d5bbf5b1aef63364bbcabf8f0c92e63379b0bedc085a68c117c011730f643bb9a105157c4eb529190abd3df5b16f61826df85082819b96b2b813b6a" }, { "alg" : "SHA3-256", - "content" : "18e97fdcdfb34cad170895bf01da95fdc83a77639ca32451bd7dcd3a313dbc47" + "content" : "39716ad8b6b6081eefc5a3f61095b39ec650147dbe9bd5a238ada8e732b8bd41" }, { "alg" : "SHA3-512", - "content" : "dd80e9505830bcd1381ac41b5fb68f9eec5413c9eca02740bdcd2dcdb28a3dce2480a61da1f61fe1b5e27d5f50f95f46dabbb28fa05015140a34245eafd86e3b" + "content" : "23e9d1ddc7745d71e55f912246d1cd6f23f14e9000fdeb6911b17d8c305718cb2df9f7d8219c21f89d74709a3ed8b440111b62297b67e6f6a5deb2912769a201" }, { "alg" : "SHA-384", - "content" : "e64ab7365de5350211165f5f1334d5bcd399d5e918a40791122b529f5f81b5200e83b1d62789b062a40671b45e2b7946" + "content" : "461a095ee273e71bfb09659ccf3aa548890058057b59a8d069b5f7bea9a3a437be316c1e61e3e7ca6852202d5ae1d6a6" }, { "alg" : "SHA3-384", - "content" : "9a632d33939e993910ae7eedafb383a1ac6786b72e4e36a88f5873a3be8690577becd66cddc7875e97fcc98455c11bb3" + "content" : "1b3cb728b5eaab8e62538ab986e8ccb4c1370799fbe7f1c8c60702f270a91c566e172ceed7f5fb0acb9cf53e7300f38a" } ], "licenses" : [ @@ -84,6 +84,12 @@ "component" : { "type" : "library", "bom-ref" : "pkg:maven/org.apache.ant/[email protected]?type=jar", + "supplier" : { + "name" : "Apache Ant Development Team", + "url" : [ + "https://ant.apache.org/" + ] + }, "manufacturer" : { "name" : "Apache Ant Development Team", "url" : [ @@ -97,35 +103,35 @@ "hashes" : [ { "alg" : "MD5", - "content" : "8f400c4cf1c0fced3eb9e0bfd5d18485" + "content" : "6802fde2fdd7103022fb9203fc8ceed2" }, { "alg" : "SHA-1", - "content" : "9d6e76799441f34d56b39aca6415a36d510b463c" + "content" : "06ff4239c338b0e9a6f6b8567a79126c957d4187" }, { "alg" : "SHA-256", - "content" : "0b12ba1c7c6ae24a49581810c7495b92df933c150eddebf94522f5fdb19902d8" + "content" : "480ace3a039d882edb028227aa8ae682cb18fe40461ad757bd04dce7ed513b3f" }, { "alg" : "SHA-512", - "content" : "7eb05a92293ead979a82953f4ac2eb560f7414b7d52a6caa651f2d71d95bee8c5deb1e85235ede013497400f005a938d7ce3647396a9f2c7859afaa5e1991102" + "content" : "e888ecde1d5bbf5b1aef63364bbcabf8f0c92e63379b0bedc085a68c117c011730f643bb9a105157c4eb529190abd3df5b16f61826df85082819b96b2b813b6a" }, { "alg" : "SHA3-256", - "content" : "18e97fdcdfb34cad170895bf01da95fdc83a77639ca32451bd7dcd3a313dbc47" + "content" : "39716ad8b6b6081eefc5a3f61095b39ec650147dbe9bd5a238ada8e732b8bd41" }, { "alg" : "SHA3-512", - "content" : "dd80e9505830bcd1381ac41b5fb68f9eec5413c9eca02740bdcd2dcdb28a3dce2480a61da1f61fe1b5e27d5f50f95f46dabbb28fa05015140a34245eafd86e3b" + "content" : "23e9d1ddc7745d71e55f912246d1cd6f23f14e9000fdeb6911b17d8c305718cb2df9f7d8219c21f89d74709a3ed8b440111b62297b67e6f6a5deb2912769a201" }, { "alg" : "SHA-384", - "content" : "e64ab7365de5350211165f5f1334d5bcd399d5e918a40791122b529f5f81b5200e83b1d62789b062a40671b45e2b7946" + "content" : "461a095ee273e71bfb09659ccf3aa548890058057b59a8d069b5f7bea9a3a437be316c1e61e3e7ca6852202d5ae1d6a6" }, { "alg" : "SHA3-384", - "content" : "9a632d33939e993910ae7eedafb383a1ac6786b72e4e36a88f5873a3be8690577becd66cddc7875e97fcc98455c11bb3" + "content" : "1b3cb728b5eaab8e62538ab986e8ccb4c1370799fbe7f1c8c60702f270a91c566e172ceed7f5fb0acb9cf53e7300f38a" } ], "licenses" : [ @@ -142,6 +148,12 @@ "url" : "https://github.com/apache/ant-antlibs-cyclonedx" } ] + }, + "supplier" : { + "name" : "Apache Ant Development Team", + "url" : [ + "https://ant.apache.org/" + ] } }, "components" : [ diff --git a/examples/bom.xml b/examples/bom.xml index 82404a3..b557624 100644 --- a/examples/bom.xml +++ b/examples/bom.xml @@ -1,7 +1,7 @@ <?xml version="1.0" encoding="UTF-8"?> -<bom serialNumber="urn:uuid:fdd9f10c-e0ba-4971-acdb-7dfe4f3c274d" version="1" xmlns="http://cyclonedx.org/schema/bom/1.6"> +<bom serialNumber="urn:uuid:1544955e-349c-4a57-9a24-3e7ec9bda318" version="1" xmlns="http://cyclonedx.org/schema/bom/1.6"> <metadata> - <timestamp>2026-05-01T20:20:09Z</timestamp> + <timestamp>2026-05-01T20:44:53Z</timestamp> <lifecycles> <lifecycle> <phase>build</phase> @@ -23,14 +23,14 @@ <version>0.1alpha</version> <description>Apache CycloneDX Antlib</description> <hashes> - <hash alg="MD5">8f400c4cf1c0fced3eb9e0bfd5d18485</hash> - <hash alg="SHA-1">9d6e76799441f34d56b39aca6415a36d510b463c</hash> - <hash alg="SHA-256">0b12ba1c7c6ae24a49581810c7495b92df933c150eddebf94522f5fdb19902d8</hash> - <hash alg="SHA-512">7eb05a92293ead979a82953f4ac2eb560f7414b7d52a6caa651f2d71d95bee8c5deb1e85235ede013497400f005a938d7ce3647396a9f2c7859afaa5e1991102</hash> - <hash alg="SHA3-256">18e97fdcdfb34cad170895bf01da95fdc83a77639ca32451bd7dcd3a313dbc47</hash> - <hash alg="SHA3-512">dd80e9505830bcd1381ac41b5fb68f9eec5413c9eca02740bdcd2dcdb28a3dce2480a61da1f61fe1b5e27d5f50f95f46dabbb28fa05015140a34245eafd86e3b</hash> - <hash alg="SHA-384">e64ab7365de5350211165f5f1334d5bcd399d5e918a40791122b529f5f81b5200e83b1d62789b062a40671b45e2b7946</hash> - <hash alg="SHA3-384">9a632d33939e993910ae7eedafb383a1ac6786b72e4e36a88f5873a3be8690577becd66cddc7875e97fcc98455c11bb3</hash> + <hash alg="MD5">6802fde2fdd7103022fb9203fc8ceed2</hash> + <hash alg="SHA-1">06ff4239c338b0e9a6f6b8567a79126c957d4187</hash> + <hash alg="SHA-256">480ace3a039d882edb028227aa8ae682cb18fe40461ad757bd04dce7ed513b3f</hash> + <hash alg="SHA-512">e888ecde1d5bbf5b1aef63364bbcabf8f0c92e63379b0bedc085a68c117c011730f643bb9a105157c4eb529190abd3df5b16f61826df85082819b96b2b813b6a</hash> + <hash alg="SHA3-256">39716ad8b6b6081eefc5a3f61095b39ec650147dbe9bd5a238ada8e732b8bd41</hash> + <hash alg="SHA3-512">23e9d1ddc7745d71e55f912246d1cd6f23f14e9000fdeb6911b17d8c305718cb2df9f7d8219c21f89d74709a3ed8b440111b62297b67e6f6a5deb2912769a201</hash> + <hash alg="SHA-384">461a095ee273e71bfb09659ccf3aa548890058057b59a8d069b5f7bea9a3a437be316c1e61e3e7ca6852202d5ae1d6a6</hash> + <hash alg="SHA3-384">1b3cb728b5eaab8e62538ab986e8ccb4c1370799fbe7f1c8c60702f270a91c566e172ceed7f5fb0acb9cf53e7300f38a</hash> </hashes> <licenses> <license> @@ -47,6 +47,10 @@ </components> </tools> <component type="library" bom-ref="pkg:maven/org.apache.ant/[email protected]?type=jar"> + <supplier> + <name>Apache Ant Development Team</name> + <url>https://ant.apache.org/</url> + </supplier> <manufacturer> <name>Apache Ant Development Team</name> <url>https://ant.apache.org/</url> @@ -56,14 +60,14 @@ <version>0.1alpha</version> <description>Apache CycloneDX Antlib</description> <hashes> - <hash alg="MD5">8f400c4cf1c0fced3eb9e0bfd5d18485</hash> - <hash alg="SHA-1">9d6e76799441f34d56b39aca6415a36d510b463c</hash> - <hash alg="SHA-256">0b12ba1c7c6ae24a49581810c7495b92df933c150eddebf94522f5fdb19902d8</hash> - <hash alg="SHA-512">7eb05a92293ead979a82953f4ac2eb560f7414b7d52a6caa651f2d71d95bee8c5deb1e85235ede013497400f005a938d7ce3647396a9f2c7859afaa5e1991102</hash> - <hash alg="SHA3-256">18e97fdcdfb34cad170895bf01da95fdc83a77639ca32451bd7dcd3a313dbc47</hash> - <hash alg="SHA3-512">dd80e9505830bcd1381ac41b5fb68f9eec5413c9eca02740bdcd2dcdb28a3dce2480a61da1f61fe1b5e27d5f50f95f46dabbb28fa05015140a34245eafd86e3b</hash> - <hash alg="SHA-384">e64ab7365de5350211165f5f1334d5bcd399d5e918a40791122b529f5f81b5200e83b1d62789b062a40671b45e2b7946</hash> - <hash alg="SHA3-384">9a632d33939e993910ae7eedafb383a1ac6786b72e4e36a88f5873a3be8690577becd66cddc7875e97fcc98455c11bb3</hash> + <hash alg="MD5">6802fde2fdd7103022fb9203fc8ceed2</hash> + <hash alg="SHA-1">06ff4239c338b0e9a6f6b8567a79126c957d4187</hash> + <hash alg="SHA-256">480ace3a039d882edb028227aa8ae682cb18fe40461ad757bd04dce7ed513b3f</hash> + <hash alg="SHA-512">e888ecde1d5bbf5b1aef63364bbcabf8f0c92e63379b0bedc085a68c117c011730f643bb9a105157c4eb529190abd3df5b16f61826df85082819b96b2b813b6a</hash> + <hash alg="SHA3-256">39716ad8b6b6081eefc5a3f61095b39ec650147dbe9bd5a238ada8e732b8bd41</hash> + <hash alg="SHA3-512">23e9d1ddc7745d71e55f912246d1cd6f23f14e9000fdeb6911b17d8c305718cb2df9f7d8219c21f89d74709a3ed8b440111b62297b67e6f6a5deb2912769a201</hash> + <hash alg="SHA-384">461a095ee273e71bfb09659ccf3aa548890058057b59a8d069b5f7bea9a3a437be316c1e61e3e7ca6852202d5ae1d6a6</hash> + <hash alg="SHA3-384">1b3cb728b5eaab8e62538ab986e8ccb4c1370799fbe7f1c8c60702f270a91c566e172ceed7f5fb0acb9cf53e7300f38a</hash> </hashes> <licenses> <license> @@ -77,6 +81,10 @@ </reference> </externalReferences> </component> + <supplier> + <name>Apache Ant Development Team</name> + <url>https://ant.apache.org/</url> + </supplier> </metadata> <components> <component type="library" bom-ref="pkg:maven/org.apache.ant/[email protected]?type=jar"> diff --git a/src/main/org/apache/ant/cyclonedx/Component.java b/src/main/org/apache/ant/cyclonedx/Component.java index 6813699..2f18159 100644 --- a/src/main/org/apache/ant/cyclonedx/Component.java +++ b/src/main/org/apache/ant/cyclonedx/Component.java @@ -9,7 +9,6 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.ProjectComponent; import org.apache.tools.ant.types.Resource; import org.apache.tools.ant.types.resources.FileProvider; -import org.apache.tools.ant.types.resources.URLResource; import org.cyclonedx.Version; import org.cyclonedx.model.LicenseChoice; @@ -238,30 +237,6 @@ public class Component { component.setHashes(BomUtils.calculateHashes(file, bomVersion)); } - public static class Organization { - private String name; - private List<String> urls = new ArrayList<>(); - - public void setName(String name) { - this.name = name; - } - - public void addConfiguredUrl(URLResource url) { - urls.add(url.getURL().toExternalForm()); - } - - public OrganizationalEntity toOrganizationalEntity() { - OrganizationalEntity oe = new OrganizationalEntity(); - if (name != null) { - oe.setName(name); - } - if (!urls.isEmpty()) { - oe.setUrls(urls); - } - return oe; - } - } - public static class License { private String id; private String name; diff --git a/src/main/org/apache/ant/cyclonedx/ComponentBomTask.java b/src/main/org/apache/ant/cyclonedx/ComponentBomTask.java index 8bb5528..d7d5cad 100644 --- a/src/main/org/apache/ant/cyclonedx/ComponentBomTask.java +++ b/src/main/org/apache/ant/cyclonedx/ComponentBomTask.java @@ -27,6 +27,7 @@ import org.cyclonedx.model.Dependency; import org.cyclonedx.model.LifecycleChoice; import org.cyclonedx.model.Lifecycles; import org.cyclonedx.model.Metadata; +import org.cyclonedx.model.OrganizationalEntity; /** * Task that creates CycloneDX BOM for a single component. @@ -37,6 +38,9 @@ public class ComponentBomTask extends Task { private Format format = Format.JSON; private Component component; private List<Component> additionalComponents = new ArrayList<>(); + private Organization manufacturer = null; + private Organization supplier = null; + private boolean useComponentSupplier = false; public void setBomFile(File f) { bomFile = f; @@ -58,7 +62,31 @@ public class ComponentBomTask extends Task { additionalComponents.add(c); } + public Organization createManufacturer() { + if (manufacturer != null) { + throw new BuildException("can only have one manufacturer"); + } + manufacturer = new Organization(); + return manufacturer; + } + + public Organization createSupplier() { + if (supplier != null) { + throw new BuildException("can only have one supplier"); + } + supplier = new Organization(); + return supplier; + } + + public void setUseComponentSupplier(boolean useComponentSupplier) { + this.useComponentSupplier = useComponentSupplier; + } + public void execute() { + if (supplier != null && useComponentSupplier) { + throw new BuildException("can't use component's supplier when there is an explicit supplier"); + } + try { Bom bom = createBom(); writeBom(bom, bomFile); @@ -85,6 +113,19 @@ public class ComponentBomTask extends Task { throw new BuildException("nested component element is required"); } meta.setComponent(component.toMainCycloneDxComponent(Version.VERSION_16)); + if (useComponentSupplier) { + OrganizationalEntity componentSupplier = meta.getComponent().getSupplier(); + if (componentSupplier == null) { + throw new BuildException("useComponentSupplier is true but component supplier is null"); + } + meta.setSupplier(componentSupplier); + } + if (supplier != null) { + meta.setSupplier(supplier.toOrganizationalEntity()); + } + if (manufacturer != null) { + meta.setManufacturer(manufacturer.toOrganizationalEntity()); + } bom.setMetadata(meta); diff --git a/src/main/org/apache/ant/cyclonedx/Organization.java b/src/main/org/apache/ant/cyclonedx/Organization.java new file mode 100644 index 0000000..66aa552 --- /dev/null +++ b/src/main/org/apache/ant/cyclonedx/Organization.java @@ -0,0 +1,32 @@ +package org.apache.ant.cyclonedx; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.tools.ant.types.resources.URLResource; + +import org.cyclonedx.model.OrganizationalEntity; + +public class Organization { + private String name; + private List<String> urls = new ArrayList<>(); + + public void setName(String name) { + this.name = name; + } + + public void addConfiguredUrl(URLResource url) { + urls.add(url.getURL().toExternalForm()); + } + + public OrganizationalEntity toOrganizationalEntity() { + OrganizationalEntity oe = new OrganizationalEntity(); + if (name != null) { + oe.setName(name); + } + if (!urls.isEmpty()) { + oe.setUrls(urls); + } + return oe; + } +} diff --git a/src/main/org/apache/ant/cyclonedx/ToolData.java b/src/main/org/apache/ant/cyclonedx/ToolData.java index 1894538..8698f93 100644 --- a/src/main/org/apache/ant/cyclonedx/ToolData.java +++ b/src/main/org/apache/ant/cyclonedx/ToolData.java @@ -38,7 +38,7 @@ public class ToolData { antlibComponent.setVersion(getVersion()); antlibComponent.setDescription("Apache CycloneDX Antlib"); - Component.Organization manufacturer = antlibComponent.createManufacturer(); + Organization manufacturer = antlibComponent.createManufacturer(); manufacturer.setName("Apache Ant Development Team"); manufacturer.addConfiguredUrl(new URLResource("https://ant.apache.org/")); antlibComponent.setManufacturerIsSupplier(true); diff --git a/src/tests/antunit/componentbom-test.xml b/src/tests/antunit/componentbom-test.xml index fa3559f..8fcfb10 100644 --- a/src/tests/antunit/componentbom-test.xml +++ b/src/tests/antunit/componentbom-test.xml @@ -118,6 +118,56 @@ value='<url>https://github.com/apache/ant-antlibs-cyclonedx</url>'/> </target> + <target name="testSupplierAndManufacturerInMeta"> + <mkdir dir="${output}"/> + <cdx:componentbom bomfile="${output}/bom.xml" format="XML" + xmlns:cdx="antlib:org.apache.ant.cyclonedx"> + <manufacturer name="Example"> + <url url="https://example.org/"/> + </manufacturer> + <supplier name="Example 2"> + <url url="https://example.com/"/> + </supplier> + <component name="testname"/> + </cdx:componentbom> + <xmlproperty file="${output}/bom.xml"/> + <au:assertPropertyEquals + xmlns:au="antlib:org.apache.ant.antunit" + name="bom.metadata.manufacturer.name" + value="Example"/> + <au:assertPropertyEquals + xmlns:au="antlib:org.apache.ant.antunit" + name="bom.metadata.manufacturer.url" + value="https://example.org/"/> + <au:assertPropertyEquals + xmlns:au="antlib:org.apache.ant.antunit" + name="bom.metadata.supplier.name" + value="Example 2"/> + <au:assertPropertyEquals + xmlns:au="antlib:org.apache.ant.antunit" + name="bom.metadata.supplier.url" + value="https://example.com/"/> + + <cdx:componentbom bomfile="${output}/bom.xml" format="XML" + useComponentSupplier="true" + xmlns:cdx="antlib:org.apache.ant.cyclonedx"> + <component name="testname"> + <supplier name="Example 2"> + <url url="https://example.com/"/> + </supplier> + </component> + </cdx:componentbom> + <xmlproperty file="${output}/bom.xml"/> + <au:assertPropertyEquals + xmlns:au="antlib:org.apache.ant.antunit" + name="bom.metadata.supplier.name" + value="Example 2"/> + <au:assertPropertyEquals + xmlns:au="antlib:org.apache.ant.antunit" + name="bom.metadata.supplier.url" + value="https://example.com/"/> +</target> + <target name="testComponentIsRequired"> <au:expectfailure expectedMessage="nested component element is required" xmlns:au="antlib:org.apache.ant.antunit"> @@ -329,12 +379,14 @@ <cdx:componentbom bomfile="${output}/bom.json" format="JSON" + useComponentSupplier="true" xmlns:cdx="antlib:org.apache.ant.cyclonedx"> <component name="ant-cyclonedx" group="org.apache.ant" version="${artifact.version}" - description="Apache CycloneDX Antlib"> + description="Apache CycloneDX Antlib" + manufacturerIsSupplier="true"> <file file="${antlib.location}"/> <manufacturer name="Apache Ant Development Team"> <url url="https://ant.apache.org/"/> @@ -375,12 +427,14 @@ <cdx:componentbom bomfile="${output}/bom.xml" format="XML" + useComponentSupplier="true" xmlns:cdx="antlib:org.apache.ant.cyclonedx"> <component name="ant-cyclonedx" group="org.apache.ant" version="${artifact.version}" - description="Apache CycloneDX Antlib"> + description="Apache CycloneDX Antlib" + manufacturerIsSupplier="true"> <file file="${antlib.location}"/> <manufacturer name="Apache Ant Development Team"> <url url="https://ant.apache.org/"/>
