From a893ba6f07e4c9a14facee41a92003b4230da9be Mon Sep 17 00:00:00 2001 From: Steve Springett Date: Sat, 19 Nov 2022 17:14:59 -0600 Subject: [PATCH] Correcting bomlink generation for XML and JSON. Added unit tests. --- .../java/org/cyclonedx/util/BomUtils.java | 11 ++++++++ .../util/ExternalReferenceSerializer.java | 2 +- .../org/cyclonedx/BomJsonGeneratorTest.java | 13 +++++++++ .../org/cyclonedx/BomXmlGeneratorTest.java | 13 +++++++++ .../org/cyclonedx/parsers/JsonParserTest.java | 11 ++++++++ .../org/cyclonedx/parsers/XmlParserTest.java | 11 ++++++++ src/test/resources/bom-1.4-bomlink.json | 28 +++++++++++++++++++ src/test/resources/bom-1.4-bomlink.xml | 19 +++++++++++++ 8 files changed, 107 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/bom-1.4-bomlink.json create mode 100644 src/test/resources/bom-1.4-bomlink.xml diff --git a/src/main/java/org/cyclonedx/util/BomUtils.java b/src/main/java/org/cyclonedx/util/BomUtils.java index 58b3072ed..820ffac34 100644 --- a/src/main/java/org/cyclonedx/util/BomUtils.java +++ b/src/main/java/org/cyclonedx/util/BomUtils.java @@ -27,6 +27,7 @@ import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; +import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.nio.file.Files; @@ -95,6 +96,7 @@ private static Hash.Algorithm toAlgorithm(MessageDigest digest) { throw new IllegalArgumentException("Unable to find algorithm matching '"+digest.getAlgorithm()+"'. Known algorithms: "+ Arrays.stream(Hash.Algorithm.values()).map(Hash.Algorithm::getSpec).sorted().collect(Collectors.joining())); } + @Deprecated public static boolean validateUrlString(String url) { try { new URL(url).toURI(); @@ -103,4 +105,13 @@ public static boolean validateUrlString(String url) { return false; } } + + public static boolean validateUriString(String uri) { + try { + new URI(uri); + return true; + } catch (URISyntaxException e) { + return false; + } + } } diff --git a/src/main/java/org/cyclonedx/util/ExternalReferenceSerializer.java b/src/main/java/org/cyclonedx/util/ExternalReferenceSerializer.java index 4e2686301..119a43956 100644 --- a/src/main/java/org/cyclonedx/util/ExternalReferenceSerializer.java +++ b/src/main/java/org/cyclonedx/util/ExternalReferenceSerializer.java @@ -46,7 +46,7 @@ public ExternalReferenceSerializer(final Class t) { public void serialize( final ExternalReference extRef, final JsonGenerator gen, final SerializerProvider provider) throws IOException { - final BiPredicate validateExternalReference = (type, url) -> (type != null && url != null && BomUtils.validateUrlString(url)); + final BiPredicate validateExternalReference = (type, url) -> (type != null && url != null && BomUtils.validateUriString(url)); if (gen instanceof ToXmlGenerator) { final ToXmlGenerator toXmlGenerator = (ToXmlGenerator) gen; final XMLStreamWriter staxWriter = toXmlGenerator.getStaxWriter(); diff --git a/src/test/java/org/cyclonedx/BomJsonGeneratorTest.java b/src/test/java/org/cyclonedx/BomJsonGeneratorTest.java index 1ccd8a7a3..c5f9038ed 100644 --- a/src/test/java/org/cyclonedx/BomJsonGeneratorTest.java +++ b/src/test/java/org/cyclonedx/BomJsonGeneratorTest.java @@ -164,6 +164,19 @@ public void schema14MultipleDependenciesJsonTest() throws Exception { assertTrue(jsonParser.isValid(file, CycloneDxSchema.Version.VERSION_14)); } + @Test + public void schema14JBomLinkGenerationTest() throws Exception { + Bom bom = createCommonBom("/bom-1.4-bomlink.xml"); + BomJsonGenerator generator = BomGeneratorFactory.createJson(Version.VERSION_14, bom); + File file = writeToFile(generator.toJsonString()); + JsonParser parser = new JsonParser(); + assertTrue(parser.isValid(file, CycloneDxSchema.Version.VERSION_14)); + Bom bom2 = parser.parse(file); + assertNotNull(bom2.getComponents().get(0).getExternalReferences()); + assertEquals("bom", bom2.getComponents().get(0).getExternalReferences().get(0).getType().getTypeName()); + assertEquals("urn:cdx:f08a6ccd-4dce-4759-bd84-c626675d60a7/1", bom2.getComponents().get(0).getExternalReferences().get(0).getUrl()); + } + private File writeToFile(String jsonString) throws Exception { try (FileWriter writer = new FileWriter(tempFile.getAbsolutePath())) { writer.write(jsonString); diff --git a/src/test/java/org/cyclonedx/BomXmlGeneratorTest.java b/src/test/java/org/cyclonedx/BomXmlGeneratorTest.java index 8c10f3ddf..541106533 100644 --- a/src/test/java/org/cyclonedx/BomXmlGeneratorTest.java +++ b/src/test/java/org/cyclonedx/BomXmlGeneratorTest.java @@ -308,6 +308,19 @@ public void schema13EmptyComponentsXmlTest() throws Exception { assertTrue(parser.isValid(file, CycloneDxSchema.Version.VERSION_13)); } + @Test + public void schema14JBomLinkGenerationTest() throws Exception { + Bom bom = createCommonBom("/bom-1.4-bomlink.xml"); + BomXmlGenerator generator = BomGeneratorFactory.createXml(Version.VERSION_14, bom); + File file = writeToFile(generator.toXmlString()); + XmlParser parser = new XmlParser(); + assertTrue(parser.isValid(file, CycloneDxSchema.Version.VERSION_14)); + Bom bom2 = parser.parse(file); + assertNotNull(bom2.getComponents().get(0).getExternalReferences()); + assertEquals("bom", bom2.getComponents().get(0).getExternalReferences().get(0).getType().getTypeName()); + assertEquals("urn:cdx:f08a6ccd-4dce-4759-bd84-c626675d60a7/1", bom2.getComponents().get(0).getExternalReferences().get(0).getUrl()); + } + private File writeToFile(String xmlString) throws Exception { try (FileWriter writer = new FileWriter(tempFile.getAbsolutePath())) { writer.write(xmlString); diff --git a/src/test/java/org/cyclonedx/parsers/JsonParserTest.java b/src/test/java/org/cyclonedx/parsers/JsonParserTest.java index 4641cf38f..c907f2f1a 100644 --- a/src/test/java/org/cyclonedx/parsers/JsonParserTest.java +++ b/src/test/java/org/cyclonedx/parsers/JsonParserTest.java @@ -312,6 +312,17 @@ public void testParsedObjects13Bom() throws Exception { assertEquals("pkg:npm/acme/common@2.2.0", d22.getRef()); } + @Test + public void testValidBomLink() throws Exception { + final File file = new File(this.getClass().getResource("/bom-1.4-bomlink.json").getFile()); + final JsonParser parser = new JsonParser(); + Bom bom = parser.parse(file); + assertTrue(parser.isValid(file, CycloneDxSchema.Version.VERSION_14)); + ExternalReference ref = bom.getComponents().get(0).getExternalReferences().get(0); + assertEquals("bom", ref.getType().getTypeName()); + assertEquals("urn:cdx:f08a6ccd-4dce-4759-bd84-c626675d60a7/1", ref.getUrl()); + } + @Test public void testParsedObjects14Bom() throws Exception { final byte[] bomBytes = IOUtils.toByteArray(this.getClass().getResourceAsStream("/bom-1.4.json")); diff --git a/src/test/java/org/cyclonedx/parsers/XmlParserTest.java b/src/test/java/org/cyclonedx/parsers/XmlParserTest.java index 8b55c1020..cb035776a 100644 --- a/src/test/java/org/cyclonedx/parsers/XmlParserTest.java +++ b/src/test/java/org/cyclonedx/parsers/XmlParserTest.java @@ -92,6 +92,17 @@ public void testValid12Bom() throws Exception { assertTrue(valid); } + @Test + public void testValidBomLink() throws Exception { + final File file = new File(this.getClass().getResource("/bom-1.4-bomlink.xml").getFile()); + final XmlParser parser = new XmlParser(); + Bom bom = parser.parse(file); + assertTrue(parser.isValid(file, CycloneDxSchema.Version.VERSION_14)); + ExternalReference ref = bom.getComponents().get(0).getExternalReferences().get(0); + assertEquals("bom", ref.getType().getTypeName()); + assertEquals("urn:cdx:f08a6ccd-4dce-4759-bd84-c626675d60a7/1", ref.getUrl()); + } + @Test public void testValid12BomWithPedigree() throws Exception { final File file = new File(this.getClass().getResource("/bom-1.2-pedigree.xml").getFile()); diff --git a/src/test/resources/bom-1.4-bomlink.json b/src/test/resources/bom-1.4-bomlink.json new file mode 100644 index 000000000..a3aa1c732 --- /dev/null +++ b/src/test/resources/bom-1.4-bomlink.json @@ -0,0 +1,28 @@ +{ + "bomFormat": "CycloneDX", + "specVersion": "1.4", + "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", + "version": 1, + "components": [ + { + "type": "library", + "publisher": "Acme Inc", + "group": "org.example", + "name": "mylibrary", + "version": "1.0.0", + "externalReferences": [ + { + "type": "bom", + "url": "urn:cdx:f08a6ccd-4dce-4759-bd84-c626675d60a7/1", + "comment": "An external SBOM that describes what this component includes", + "hashes": [ + { + "alg": "SHA-256", + "content": "708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313" + } + ] + } + ] + } + ] +} diff --git a/src/test/resources/bom-1.4-bomlink.xml b/src/test/resources/bom-1.4-bomlink.xml new file mode 100644 index 000000000..d62225c04 --- /dev/null +++ b/src/test/resources/bom-1.4-bomlink.xml @@ -0,0 +1,19 @@ + + + + + org.example + mylibrary + 1.0.0 + + + urn:cdx:f08a6ccd-4dce-4759-bd84-c626675d60a7/1 + An external SBOM that describes what this component includes + + f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b + + + + + +