diff --git a/src/main/java/com/redhat/exhort/impl/ExhortApi.java b/src/main/java/com/redhat/exhort/impl/ExhortApi.java index d823e87d..86905708 100644 --- a/src/main/java/com/redhat/exhort/impl/ExhortApi.java +++ b/src/main/java/com/redhat/exhort/impl/ExhortApi.java @@ -62,8 +62,10 @@ public String getEndpoint() { } public static final void main(String[] args) throws IOException, InterruptedException, ExecutionException { +// System.setProperty("EXHORT_DEV_MOD","true"); AnalysisReport analysisReport = new ExhortApi() - .componentAnalysis("/home/zgrinber/git/exhort-java-api/src/test/resources/tst_manifests/maven/pom_deps_with_no_ignore_common_paths/pom.xml").get(); + + .stackAnalysis("/home/zgrinber/git/exhort-java-api/src/test/resources/tst_manifests/pip/pip_requirements_txt_no_ignore/requirements.txt").get(); System.out.println(new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(analysisReport)); // AnalysisReport analysisReport = new ExhortApi() // byte[] analysisReport = new ExhortApi(). diff --git a/src/main/java/com/redhat/exhort/providers/PythonPipProvider.java b/src/main/java/com/redhat/exhort/providers/PythonPipProvider.java index eb7cf9aa..b88dc9ca 100644 --- a/src/main/java/com/redhat/exhort/providers/PythonPipProvider.java +++ b/src/main/java/com/redhat/exhort/providers/PythonPipProvider.java @@ -77,6 +77,8 @@ public Content provideStack(Path manifestPath) throws IOException { }); byte[] requirementsFile = Files.readAllBytes(manifestPath); handleIgnoredDependencies(new String(requirementsFile), sbom); + // In python' pip requirements.txt, there is no real root element, then need to remove dummy root element that was created for creating the sbom. + sbom.removeRootComponent(); return new Content(sbom.getAsJsonString().getBytes(StandardCharsets.UTF_8), Api.CYCLONEDX_MEDIA_TYPE); } @@ -119,6 +121,8 @@ public Content provideComponent(byte[] manifestContent) throws IOException { Files.delete(manifestPath); Files.delete(tempRepository); handleIgnoredDependencies(new String(manifestContent), sbom); + // In python' pip requirements.txt, there is no real root element, then need to remove dummy root element that was created for creating the sbom. + sbom.removeRootComponent(); return new Content(sbom.getAsJsonString().getBytes(StandardCharsets.UTF_8), Api.CYCLONEDX_MEDIA_TYPE); } diff --git a/src/main/java/com/redhat/exhort/sbom/CycloneDXSbom.java b/src/main/java/com/redhat/exhort/sbom/CycloneDXSbom.java index 344f06f6..8185ce30 100644 --- a/src/main/java/com/redhat/exhort/sbom/CycloneDXSbom.java +++ b/src/main/java/com/redhat/exhort/sbom/CycloneDXSbom.java @@ -21,7 +21,6 @@ import java.util.stream.Collectors; import com.github.packageurl.MalformedPackageURLException; -import com.redhat.exhort.tools.Ecosystem; import org.cyclonedx.BomGeneratorFactory; import org.cyclonedx.CycloneDxSchema.Version; import org.cyclonedx.model.Bom; @@ -286,4 +285,12 @@ public boolean checkIfPackageInsideDependsOnList(PackageURL component, String na return result; } + @Override + public void removeRootComponent() + { + bom.getComponents().removeIf( (component) -> component.getBomRef().equals(this.root.getCoordinates())); + bom.getDependencies().removeIf( (dependency) -> dependency.getRef().equals(this.root.getCoordinates())); + bom.getMetadata().setComponent(null); + } + } diff --git a/src/main/java/com/redhat/exhort/sbom/Sbom.java b/src/main/java/com/redhat/exhort/sbom/Sbom.java index 977230ae..079d94a8 100644 --- a/src/main/java/com/redhat/exhort/sbom/Sbom.java +++ b/src/main/java/com/redhat/exhort/sbom/Sbom.java @@ -16,7 +16,6 @@ package com.redhat.exhort.sbom; import java.util.Collection; -import java.util.function.Predicate; import com.github.packageurl.PackageURL; public interface Sbom { @@ -30,7 +29,9 @@ public interface Sbom { public boolean checkIfPackageInsideDependsOnList(PackageURL component, String name); - public enum BelongingCondition + void removeRootComponent(); + + public enum BelongingCondition { NAME("name"), PURL("purl"); diff --git a/src/test/java/com/redhat/exhort/providers/Python_Provider_Test.java b/src/test/java/com/redhat/exhort/providers/Python_Provider_Test.java index ae35251e..f4425ae7 100644 --- a/src/test/java/com/redhat/exhort/providers/Python_Provider_Test.java +++ b/src/test/java/com/redhat/exhort/providers/Python_Provider_Test.java @@ -112,6 +112,6 @@ void Test_The_ProvideComponent_Path_Should_Throw_Exception() { } private String dropIgnored(String s) { - return s.replaceAll("\\s+","").replaceAll("\"timestamp\":\"[a-zA-Z0-9\\-\\:]+\",", ""); + return s.replaceAll("\\s+","").replaceAll("\"timestamp\":\"[a-zA-Z0-9\\-\\:]+\"", ""); } } diff --git a/src/test/resources/tst_manifests/pip/pip_requirements_txt_ignore/expected_component_sbom.json b/src/test/resources/tst_manifests/pip/pip_requirements_txt_ignore/expected_component_sbom.json index 3aa22753..733cb95c 100644 --- a/src/test/resources/tst_manifests/pip/pip_requirements_txt_ignore/expected_component_sbom.json +++ b/src/test/resources/tst_manifests/pip/pip_requirements_txt_ignore/expected_component_sbom.json @@ -3,21 +3,9 @@ "specVersion" : "1.4", "version" : 1, "metadata" : { - "timestamp" : "2023-09-28T12:40:41Z", - "component" : { - "name" : "root", - "purl" : "pkg:pypi/root", - "type" : "application", - "bom-ref" : "pkg:pypi/root" - } + "timestamp" : "2023-09-28T12:40:41Z" }, "components" : [ - { - "name" : "root", - "purl" : "pkg:pypi/root", - "type" : "application", - "bom-ref" : "pkg:pypi/root" - }, { "name" : "anyio", "version" : "3.6.2", @@ -195,36 +183,6 @@ } ], "dependencies" : [ - { - "ref" : "pkg:pypi/root", - "dependsOn" : [ - "pkg:pypi/anyio@3.6.2", - "pkg:pypi/asgiref@3.4.1", - "pkg:pypi/beautifulsoup4@4.12.2", - "pkg:pypi/certifi@2023.7.22", - "pkg:pypi/chardet@4.0.0", - "pkg:pypi/contextlib2@21.6.0", - "pkg:pypi/fastapi@0.75.1", - "pkg:pypi/flask@2.0.3", - "pkg:pypi/h11@0.13.0", - "pkg:pypi/idna@2.10", - "pkg:pypi/immutables@0.19", - "pkg:pypi/importlib-metadata@4.8.3", - "pkg:pypi/itsdangerous@2.0.1", - "pkg:pypi/jinja2@3.0.3", - "pkg:pypi/markupsafe@2.0.1", - "pkg:pypi/requests@2.25.1", - "pkg:pypi/six@1.16.0", - "pkg:pypi/sniffio@1.2.0", - "pkg:pypi/soupsieve@2.3.2.post1", - "pkg:pypi/starlette@0.17.1", - "pkg:pypi/typing-extensions@4.1.1", - "pkg:pypi/urllib3@1.26.16", - "pkg:pypi/uvicorn@0.17.0", - "pkg:pypi/werkzeug@2.0.3", - "pkg:pypi/zipp@3.6.0" - ] - }, { "ref" : "pkg:pypi/anyio@3.6.2", "dependsOn" : [ ] diff --git a/src/test/resources/tst_manifests/pip/pip_requirements_txt_ignore/expected_stack_sbom.json b/src/test/resources/tst_manifests/pip/pip_requirements_txt_ignore/expected_stack_sbom.json index 4754d382..35844f5a 100644 --- a/src/test/resources/tst_manifests/pip/pip_requirements_txt_ignore/expected_stack_sbom.json +++ b/src/test/resources/tst_manifests/pip/pip_requirements_txt_ignore/expected_stack_sbom.json @@ -3,21 +3,9 @@ "specVersion" : "1.4", "version" : 1, "metadata" : { - "timestamp" : "2023-09-28T12:40:47Z", - "component" : { - "name" : "root", - "purl" : "pkg:pypi/root", - "type" : "application", - "bom-ref" : "pkg:pypi/root" - } + "timestamp" : "2023-09-28T12:40:47Z" }, "components" : [ - { - "name" : "root", - "purl" : "pkg:pypi/root", - "type" : "application", - "bom-ref" : "pkg:pypi/root" - }, { "name" : "anyio", "version" : "3.6.2", @@ -195,36 +183,6 @@ } ], "dependencies" : [ - { - "ref" : "pkg:pypi/root", - "dependsOn" : [ - "pkg:pypi/anyio@3.6.2", - "pkg:pypi/asgiref@3.4.1", - "pkg:pypi/beautifulsoup4@4.12.2", - "pkg:pypi/certifi@2023.7.22", - "pkg:pypi/chardet@4.0.0", - "pkg:pypi/contextlib2@21.6.0", - "pkg:pypi/fastapi@0.75.1", - "pkg:pypi/flask@2.0.3", - "pkg:pypi/h11@0.13.0", - "pkg:pypi/idna@2.10", - "pkg:pypi/immutables@0.19", - "pkg:pypi/importlib-metadata@4.8.3", - "pkg:pypi/itsdangerous@2.0.1", - "pkg:pypi/jinja2@3.0.3", - "pkg:pypi/markupsafe@2.0.1", - "pkg:pypi/requests@2.25.1", - "pkg:pypi/six@1.16.0", - "pkg:pypi/sniffio@1.2.0", - "pkg:pypi/soupsieve@2.3.2.post1", - "pkg:pypi/starlette@0.17.1", - "pkg:pypi/typing-extensions@4.1.1", - "pkg:pypi/urllib3@1.26.16", - "pkg:pypi/uvicorn@0.17.0", - "pkg:pypi/werkzeug@2.0.3", - "pkg:pypi/zipp@3.6.0" - ] - }, { "ref" : "pkg:pypi/anyio@3.6.2", "dependsOn" : [ diff --git a/src/test/resources/tst_manifests/pip/pip_requirements_txt_no_ignore/expected_component_sbom.json b/src/test/resources/tst_manifests/pip/pip_requirements_txt_no_ignore/expected_component_sbom.json index 7aa0a879..80f1df2b 100644 --- a/src/test/resources/tst_manifests/pip/pip_requirements_txt_no_ignore/expected_component_sbom.json +++ b/src/test/resources/tst_manifests/pip/pip_requirements_txt_no_ignore/expected_component_sbom.json @@ -3,20 +3,8 @@ "specVersion" : "1.4", "version" : 1, "metadata" : { - "component" : { - "name" : "root", - "purl" : "pkg:pypi/root", - "type" : "application", - "bom-ref" : "pkg:pypi/root" - } }, "components" : [ - { - "name" : "root", - "purl" : "pkg:pypi/root", - "type" : "application", - "bom-ref" : "pkg:pypi/root" - }, { "name" : "anyio", "version" : "3.6.2", @@ -208,38 +196,6 @@ } ], "dependencies" : [ - { - "ref" : "pkg:pypi/root", - "dependsOn" : [ - "pkg:pypi/anyio@3.6.2", - "pkg:pypi/asgiref@3.4.1", - "pkg:pypi/beautifulsoup4@4.12.2", - "pkg:pypi/certifi@2023.7.22", - "pkg:pypi/chardet@4.0.0", - "pkg:pypi/click@8.0.4", - "pkg:pypi/contextlib2@21.6.0", - "pkg:pypi/fastapi@0.75.1", - "pkg:pypi/flask@2.0.3", - "pkg:pypi/h11@0.13.0", - "pkg:pypi/idna@2.10", - "pkg:pypi/immutables@0.19", - "pkg:pypi/importlib-metadata@4.8.3", - "pkg:pypi/itsdangerous@2.0.1", - "pkg:pypi/jinja2@3.0.3", - "pkg:pypi/markupsafe@2.0.1", - "pkg:pypi/pydantic@1.9.2", - "pkg:pypi/requests@2.25.1", - "pkg:pypi/six@1.16.0", - "pkg:pypi/sniffio@1.2.0", - "pkg:pypi/soupsieve@2.3.2.post1", - "pkg:pypi/starlette@0.17.1", - "pkg:pypi/typing-extensions@4.1.1", - "pkg:pypi/urllib3@1.26.16", - "pkg:pypi/uvicorn@0.17.0", - "pkg:pypi/werkzeug@2.0.3", - "pkg:pypi/zipp@3.6.0" - ] - }, { "ref" : "pkg:pypi/anyio@3.6.2", "dependsOn" : [ ] diff --git a/src/test/resources/tst_manifests/pip/pip_requirements_txt_no_ignore/expected_stack_sbom.json b/src/test/resources/tst_manifests/pip/pip_requirements_txt_no_ignore/expected_stack_sbom.json index 82da5549..6a4bf126 100644 --- a/src/test/resources/tst_manifests/pip/pip_requirements_txt_no_ignore/expected_stack_sbom.json +++ b/src/test/resources/tst_manifests/pip/pip_requirements_txt_no_ignore/expected_stack_sbom.json @@ -3,21 +3,9 @@ "specVersion" : "1.4", "version" : 1, "metadata" : { - "timestamp" : "2023-09-28T12:40:44Z", - "component" : { - "name" : "root", - "purl" : "pkg:pypi/root", - "type" : "application", - "bom-ref" : "pkg:pypi/root" - } + "timestamp" : "2023-09-28T12:40:44Z" }, "components" : [ - { - "name" : "root", - "purl" : "pkg:pypi/root", - "type" : "application", - "bom-ref" : "pkg:pypi/root" - }, { "name" : "anyio", "version" : "3.6.2", @@ -209,38 +197,6 @@ } ], "dependencies" : [ - { - "ref" : "pkg:pypi/root", - "dependsOn" : [ - "pkg:pypi/anyio@3.6.2", - "pkg:pypi/asgiref@3.4.1", - "pkg:pypi/beautifulsoup4@4.12.2", - "pkg:pypi/certifi@2023.7.22", - "pkg:pypi/chardet@4.0.0", - "pkg:pypi/click@8.0.4", - "pkg:pypi/contextlib2@21.6.0", - "pkg:pypi/fastapi@0.75.1", - "pkg:pypi/flask@2.0.3", - "pkg:pypi/h11@0.13.0", - "pkg:pypi/idna@2.10", - "pkg:pypi/immutables@0.19", - "pkg:pypi/importlib-metadata@4.8.3", - "pkg:pypi/itsdangerous@2.0.1", - "pkg:pypi/jinja2@3.0.3", - "pkg:pypi/markupsafe@2.0.1", - "pkg:pypi/pydantic@1.9.2", - "pkg:pypi/requests@2.25.1", - "pkg:pypi/six@1.16.0", - "pkg:pypi/sniffio@1.2.0", - "pkg:pypi/soupsieve@2.3.2.post1", - "pkg:pypi/starlette@0.17.1", - "pkg:pypi/typing-extensions@4.1.1", - "pkg:pypi/urllib3@1.26.16", - "pkg:pypi/uvicorn@0.17.0", - "pkg:pypi/werkzeug@2.0.3", - "pkg:pypi/zipp@3.6.0" - ] - }, { "ref" : "pkg:pypi/anyio@3.6.2", "dependsOn" : [