From d85cffb8acdc74a60d4beb7981bbc26c97e5fcd8 Mon Sep 17 00:00:00 2001 From: mrizzi Date: Tue, 4 Feb 2025 13:47:22 +0100 Subject: [PATCH] TC-2220 FindTopLevelPackagesRelatedToVulnerability: fix response builder Signed-off-by: mrizzi --- demo/graphql/queries-trustification.gql | 54 +++++ internal/testing/e2e-trustification/e2e | 13 +- .../expectTC_1609_FindDependentProduct.json | 32 +-- .../expectTC_2220_FindProductByCVE.json | 205 ++++++++++++++++++ .../exampledata/rhel-9.4-slimmed-down.json | 163 ++++++++++++++ pkg/assembler/backends/ent/backend/search.go | 28 ++- 6 files changed, 469 insertions(+), 26 deletions(-) create mode 100644 internal/testing/e2e-trustification/expectTC_2220_FindProductByCVE.json create mode 100644 internal/testing/testdata/exampledata/rhel-9.4-slimmed-down.json diff --git a/demo/graphql/queries-trustification.gql b/demo/graphql/queries-trustification.gql index 5f64fef7f3..f758d845d1 100644 --- a/demo/graphql/queries-trustification.gql +++ b/demo/graphql/queries-trustification.gql @@ -502,3 +502,57 @@ query TC_1928_FindVulnerabilityBySbomURI { } } } + +mutation TC_2220_OSV_GHSA_vulnerability{ + ingestVulnerability ( + vuln: { + vulnerabilityInput : { + type: "osv" + vulnerabilityID: "GHSA-2363-cqg2-863c" + } + } + ){vulnerabilityNodeID} +} + +mutation TC_2220_OSV_GHSA_certify_vuln { + ingestCertifyVuln( + pkg: { + packageInput: { + type: "maven" + namespace: "org.jdom" + name: "jdom" + version: "1.1" + } + } + vulnerability: { + vulnerabilityInput: { + type: "osv" + vulnerabilityID: "GHSA-2363-cqg2-863c" + } + } + certifyVuln: { + timeScanned: "2025-02-04T11:03:05.999999999Z" + dbUri: "test" + dbVersion: "0.0.0" + scannerUri: "test" + scannerVersion: "0.0.0" + origin: "test" + collector: "test" + documentRef: "test" + } + ) +} + +query TC_2220_find_product_by_cve { + findTopLevelPackagesRelatedToVulnerability(vulnerabilityID: "ghsa-2363-cqg2-863c") { + ... on CertifyVuln { + ...allCertifyVulnTree + } + ... on Package { + ...allPkgTree + } + ... on IsDependency { + ...allIsDependencyTree + } + } +} diff --git a/internal/testing/e2e-trustification/e2e b/internal/testing/e2e-trustification/e2e index c69b94fdf3..7657c7927e 100755 --- a/internal/testing/e2e-trustification/e2e +++ b/internal/testing/e2e-trustification/e2e @@ -113,7 +113,7 @@ time go run ./cmd/guacone collect files ${GUAC_DIR}/internal/testing/testdata/ex echo @@@@ Running TC_1609 queries and validating output -cat "$queries" | gql-cli http://localhost:8080/query -o TC_1609_FindDependentProduct | jq 'del(.. | .id?) | del(.. | .downloadLocation?) | del(.. | .origin?) | .findDependentProduct[].subject.namespaces[]?.names[]?.versions[]?.qualifiers? |= sort | .findDependentProduct' > "${GUAC_DIR}/gotTC_1609_FindDependentProduct.json" +cat "$queries" | gql-cli http://localhost:8080/query -o TC_1609_FindDependentProduct | jq 'del(.. | .id?) | del(.. | .downloadLocation?) | del(.. | .origin?) | .findDependentProduct | sort_by(.digest) | .[].subject.namespaces[]?.names[]?.versions[]?.qualifiers? |= sort | .' > "${GUAC_DIR}/gotTC_1609_FindDependentProduct.json" diff -u "${SCRIPT_DIR}/expectTC_1609_FindDependentProduct.json" "${GUAC_DIR}/gotTC_1609_FindDependentProduct.json" echo @@@@ Ingesting TC_1757_openssl-3.0.7-18.el9_2.spdx.json into server @@ -166,11 +166,20 @@ echo @@@@ Ingesting alpine-cyclonedx.json into server for TC-1842 time go run ./cmd/guacone collect files ${GUAC_DIR}/internal/testing/testdata/exampledata/alpine-cyclonedx.json; echo @@@@ Running TC-1842 queries and validating output -cat "$queries" | gql-cli http://localhost:8080/query -o TC_1842_HasMetadata | jq 'del(.. | .id?) | .HasMetadata ' > "${GUAC_DIR}/gotTC_1842_HasMetadata.json" +cat "$queries" | gql-cli http://localhost:8080/query -o TC_1842_HasMetadata | jq 'del(.. | .id?) | .HasMetadata[].subject.namespaces[]?.names[]?.versions[]?.qualifiers? |= sort | .HasMetadata ' > "${GUAC_DIR}/gotTC_1842_HasMetadata.json" diff -u "${SCRIPT_DIR}/expectTC_1842_HasMetadata.json" "${GUAC_DIR}/gotTC_1842_HasMetadata.json" echo @@@@ Running TC-1928 queries cat "$queries" | gql-cli http://localhost:8080/query -o TC_1928_FindVulnerabilityBySbomURI | jq ' .findVulnerabilityBySbomURI ' > "${GUAC_DIR}/gotTC_1928_FindVulnerabilityBySbomURI.json" diff -u "${SCRIPT_DIR}/expectTC_1928_FindVulnerabilityBySbomURI.json" "${GUAC_DIR}/gotTC_1928_FindVulnerabilityBySbomURI.json" +echo @@@@ Ingesting data for TC-2220 +time go run ./cmd/guacone collect files ${GUAC_DIR}/internal/testing/testdata/exampledata/rhel-9.4-slimmed-down.json; +cat "$queries" | gql-cli http://localhost:8080/query -o TC_2220_OSV_GHSA_vulnerability +cat "$queries" | gql-cli http://localhost:8080/query -o TC_2220_OSV_GHSA_certify_vuln + +echo @@@@ Running TC-2220 queries +cat "$queries" | gql-cli http://localhost:8080/query -o TC_2220_find_product_by_cve | jq 'del(.. | .id?) | del(.. | .origin?) | .findTopLevelPackagesRelatedToVulnerability[] ' > "${GUAC_DIR}/gotTC_2220_FindProductByCVE.json" +diff -u "${SCRIPT_DIR}/expectTC_2220_FindProductByCVE.json" "${GUAC_DIR}/gotTC_2220_FindProductByCVE.json" + # Note: graphql_playground is left running, CI will clean it up diff --git a/internal/testing/e2e-trustification/expectTC_1609_FindDependentProduct.json b/internal/testing/e2e-trustification/expectTC_1609_FindDependentProduct.json index 25c796a659..818303a3b4 100644 --- a/internal/testing/e2e-trustification/expectTC_1609_FindDependentProduct.json +++ b/internal/testing/e2e-trustification/expectTC_1609_FindDependentProduct.json @@ -5,17 +5,21 @@ "type": "maven", "namespaces": [ { - "namespace": "com.example", + "namespace": "com.redhat.quarkus.platform", "names": [ { - "name": "demo", + "name": "quarkus-bom", "versions": [ { - "version": "0.0.1-SNAPSHOT", + "version": "2.13.8.Final-redhat-00004", "qualifiers": [ + { + "key": "repository_url", + "value": "https://maven.repository.redhat.com/ga/" + }, { "key": "type", - "value": "jar" + "value": "pom" } ], "subpath": "" @@ -26,9 +30,9 @@ } ] }, - "uri": "urn:uuid:4dd9ce9a-b3f2-47c9-b670-a7884f29fd21", + "uri": "https://access.redhat.com/security/data/sbom/beta/spdx/quarkus-bom-d6ecbbd9-31bf-46fd-afda-8082120f5260", "algorithm": "sha256", - "digest": "d2d350e6a166d24530297215b415a041cef1942394528bc8b625dd123a401341", + "digest": "4087ad9b170efe11192ff2dd28ec11c3c07e0d859dba42685d2665aa4086bcf8", "collector": "FileCollector" }, { @@ -37,21 +41,17 @@ "type": "maven", "namespaces": [ { - "namespace": "com.redhat.quarkus.platform", + "namespace": "com.example", "names": [ { - "name": "quarkus-bom", + "name": "demo", "versions": [ { - "version": "2.13.8.Final-redhat-00004", + "version": "0.0.1-SNAPSHOT", "qualifiers": [ - { - "key": "repository_url", - "value": "https://maven.repository.redhat.com/ga/" - }, { "key": "type", - "value": "pom" + "value": "jar" } ], "subpath": "" @@ -62,9 +62,9 @@ } ] }, - "uri": "https://access.redhat.com/security/data/sbom/beta/spdx/quarkus-bom-d6ecbbd9-31bf-46fd-afda-8082120f5260", + "uri": "urn:uuid:4dd9ce9a-b3f2-47c9-b670-a7884f29fd21", "algorithm": "sha256", - "digest": "4087ad9b170efe11192ff2dd28ec11c3c07e0d859dba42685d2665aa4086bcf8", + "digest": "d2d350e6a166d24530297215b415a041cef1942394528bc8b625dd123a401341", "collector": "FileCollector" } ] diff --git a/internal/testing/e2e-trustification/expectTC_2220_FindProductByCVE.json b/internal/testing/e2e-trustification/expectTC_2220_FindProductByCVE.json new file mode 100644 index 0000000000..ef076e71d5 --- /dev/null +++ b/internal/testing/e2e-trustification/expectTC_2220_FindProductByCVE.json @@ -0,0 +1,205 @@ +[ + { + "package": { + "type": "maven", + "namespaces": [ + { + "namespace": "org.jdom", + "names": [ + { + "name": "jdom", + "versions": [ + { + "version": "1.1", + "qualifiers": [], + "subpath": "" + } + ] + } + ] + } + ] + }, + "vulnerability": { + "type": "osv", + "vulnerabilityIDs": [ + { + "vulnerabilityID": "ghsa-2363-cqg2-863c" + } + ] + }, + "metadata": { + "dbUri": "test", + "dbVersion": "0.0.0", + "scannerUri": "test", + "scannerVersion": "0.0.0", + "timeScanned": "2025-02-04T11:03:06Z", + "collector": "test" + } + }, + { + "type": "maven", + "namespaces": [ + { + "namespace": "org.jdom", + "names": [ + { + "name": "jdom", + "versions": [ + { + "version": "1.1", + "qualifiers": [], + "subpath": "" + } + ] + } + ] + } + ] + }, + { + "justification": "Derived from SPDX CONTAINED_BY relationship", + "versionRange": "1.1", + "package": { + "type": "rpm", + "namespaces": [ + { + "namespace": "redhat", + "names": [ + { + "name": "maven-plugin-bundle", + "versions": [ + { + "version": "5.1.1-5.el9", + "qualifiers": [ + { + "key": "arch", + "value": "src" + } + ], + "subpath": "" + } + ] + } + ] + } + ] + }, + "dependencyPackage": { + "type": "maven", + "namespaces": [ + { + "namespace": "org.jdom", + "names": [ + { + "name": "jdom", + "versions": [ + { + "version": "1.1", + "qualifiers": [], + "subpath": "" + } + ] + } + ] + } + ] + }, + "collector": "FileCollector" + }, + { + "type": "rpm", + "namespaces": [ + { + "namespace": "redhat", + "names": [ + { + "name": "maven-plugin-bundle", + "versions": [ + { + "version": "5.1.1-5.el9", + "qualifiers": [ + { + "key": "arch", + "value": "src" + } + ], + "subpath": "" + } + ] + } + ] + } + ] + }, + { + "justification": "Derived from SPDX PACKAGE_OF relationship", + "versionRange": "5.1.1-5.el9", + "package": { + "type": "guac", + "namespaces": [ + { + "namespace": "pkg", + "names": [ + { + "name": "RHEL-9.4.0.Z.MAIN+EUS", + "versions": [ + { + "version": "9.4.0", + "qualifiers": [], + "subpath": "" + } + ] + } + ] + } + ] + }, + "dependencyPackage": { + "type": "rpm", + "namespaces": [ + { + "namespace": "redhat", + "names": [ + { + "name": "maven-plugin-bundle", + "versions": [ + { + "version": "5.1.1-5.el9", + "qualifiers": [ + { + "key": "arch", + "value": "src" + } + ], + "subpath": "" + } + ] + } + ] + } + ] + }, + "collector": "FileCollector" + }, + { + "type": "guac", + "namespaces": [ + { + "namespace": "pkg", + "names": [ + { + "name": "RHEL-9.4.0.Z.MAIN+EUS", + "versions": [ + { + "version": "9.4.0", + "qualifiers": [], + "subpath": "" + } + ] + } + ] + } + ] + } +] diff --git a/internal/testing/testdata/exampledata/rhel-9.4-slimmed-down.json b/internal/testing/testdata/exampledata/rhel-9.4-slimmed-down.json new file mode 100644 index 0000000000..6026157685 --- /dev/null +++ b/internal/testing/testdata/exampledata/rhel-9.4-slimmed-down.json @@ -0,0 +1,163 @@ +{ + "SPDXID": "SPDXRef-DOCUMENT", + "comment": "Licensing information is automatically generated from the upstream package meta data and may not be accurate.", + "creationInfo": { + "created": "2025-02-03T11:17:37Z", + "creators": [ + "Organization: Red Hat Product Security (secalert@redhat.com)" + ], + "licenseListVersion": "3.22" + }, + "dataLicense": "CC0-1.0", + "name": "RHEL-9.4.0.Z.MAIN+EUS", + "spdxVersion": "SPDX-2.3", + "documentNamespace": "https://access.redhat.com/security/data/sbom/spdx/RHEL-9.4.0.Z.MAIN+EUS", + "packages": [ + { + "SPDXID": "SPDXRef-b1ac50af-1de4-48c7-850f-ddb05242561f", + "copyrightText": "NOASSERTION", + "downloadLocation": "https://repo.maven.apache.org/maven2/org/jdom/jdom/1.1", + "externalRefs": [ + { + "referenceCategory": "PACKAGE_MANAGER", + "referenceLocator": "pkg:maven/org.jdom/jdom@1.1", + "referenceType": "purl" + } + ], + "filesAnalyzed": false, + "homepage": "https://mvnrepository.com/artifact/org.jdom/jdom/1.1", + "licenseConcluded": "NOASSERTION", + "licenseDeclared": "NOASSERTION", + "name": "jdom", + "originator": "NOASSERTION", + "supplier": "Organization: Red Hat", + "versionInfo": "1.1" + }, + { + "SPDXID": "SPDXRef-98c61161-9ced-4363-b63d-4a21a93ffc31", + "copyrightText": "NOASSERTION", + "downloadLocation": "https://access.redhat.com/downloads/content/package-browser", + "externalRefs": [ + { + "referenceCategory": "PACKAGE_MANAGER", + "referenceLocator": "pkg:rpm/redhat/maven-plugin-bundle@5.1.1-5.el9?arch=src", + "referenceType": "purl" + }, + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:/a:redhat:enterprise_linux:9::crb", + "referenceType": "cpe22Type" + }, + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:/a:redhat:rhel_eus:9.0::crb", + "referenceType": "cpe22Type" + }, + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:/a:redhat:rhel_eus:9.2::crb", + "referenceType": "cpe22Type" + } + ], + "filesAnalyzed": false, + "licenseConcluded": "NOASSERTION", + "licenseDeclared": "LicenseRef-4", + "name": "maven-plugin-bundle", + "originator": "NOASSERTION", + "packageFileName": "maven-plugin-bundle-5.1.1-5.el9.src.rpm", + "supplier": "Organization: Red Hat", + "versionInfo": "5.1.1-5.el9" + }, + { + "SPDXID": "SPDXRef-56f35668-a02d-4c8a-ace9-f846159d3e61", + "copyrightText": "NOASSERTION", + "downloadLocation": "NOASSERTION", + "externalRefs": [ + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:/o:redhat:enterprise_linux:9::hypervisor", + "referenceType": "cpe22Type" + }, + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:/a:redhat:enterprise_linux:9::resilientstorage", + "referenceType": "cpe22Type" + }, + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:/a:redhat:enterprise_linux:9::sap", + "referenceType": "cpe22Type" + }, + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:/a:redhat:enterprise_linux:9::supplementary", + "referenceType": "cpe22Type" + }, + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:/a:redhat:enterprise_linux:9::crb", + "referenceType": "cpe22Type" + }, + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:/a:redhat:enterprise_linux:9::highavailability", + "referenceType": "cpe22Type" + }, + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:/a:redhat:enterprise_linux:9::appstream", + "referenceType": "cpe22Type" + }, + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:/o:redhat:enterprise_linux:9::baseos", + "referenceType": "cpe22Type" + }, + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:/a:redhat:enterprise_linux:9::sap_hana", + "referenceType": "cpe22Type" + }, + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:/a:redhat:enterprise_linux:9::realtime", + "referenceType": "cpe22Type" + }, + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:/a:redhat:enterprise_linux:9::nfv", + "referenceType": "cpe22Type" + }, + { + "referenceCategory": "SECURITY", + "referenceLocator": "cpe:/o:redhat:enterprise_linux:9::fastdatapath", + "referenceType": "cpe22Type" + } + ], + "filesAnalyzed": false, + "homepage": "https://www.redhat.com/", + "licenseConcluded": "NOASSERTION", + "licenseDeclared": "NOASSERTION", + "name": "RHEL-9.4.0.Z.MAIN+EUS", + "supplier": "Organization: Red Hat", + "versionInfo": "9.4.0" + } + ], + "relationships": [ + { + "spdxElementId": "SPDXRef-b1ac50af-1de4-48c7-850f-ddb05242561f", + "relatedSpdxElement": "SPDXRef-98c61161-9ced-4363-b63d-4a21a93ffc31", + "relationshipType": "CONTAINED_BY" + }, + { + "spdxElementId": "SPDXRef-98c61161-9ced-4363-b63d-4a21a93ffc31", + "relatedSpdxElement": "SPDXRef-56f35668-a02d-4c8a-ace9-f846159d3e61", + "relationshipType": "PACKAGE_OF" + }, + { + "spdxElementId": "SPDXRef-DOCUMENT", + "relatedSpdxElement": "SPDXRef-56f35668-a02d-4c8a-ace9-f846159d3e61", + "relationshipType": "DESCRIBES" + } + ] +} \ No newline at end of file diff --git a/pkg/assembler/backends/ent/backend/search.go b/pkg/assembler/backends/ent/backend/search.go index 13cb571e2f..9584784614 100644 --- a/pkg/assembler/backends/ent/backend/search.go +++ b/pkg/assembler/backends/ent/backend/search.go @@ -287,27 +287,39 @@ func buildDependencyPath(resultSet map[uuid.UUID][]*ent.Dependency, current *uui return result } +// this need for creating the response with a specific positional array comes from previous implementation +// of guac, i.e. 0.3.z branch, and the following integration into trustification and the willingness to not change +// trustification. +// Response array structure: +// 1. CertifyVEXStatement or CertifyVuln +// 2. Package (the affected one) +// 3. IsDependency between previous Package (the dependency) and the next Package (the dependant) +// 4. Package (dependant) +// 5. IsDependency between previous Package (the dependency) and the next Package (the dependant) +// 6. Package (dependant) +// ...[more (IsDependency - Package) pairs] +// n. Package with SBOM, i.e. Product func getResponse(certifyVexOrVuln model.Node, dependencyPaths [][]*ent.Dependency) [][]model.Node { var result [][]model.Node // each array of dependencies connects a vulnerable package with a product (i.e. package with an SBOM) the package belongs to // so looping through the dependencies will ensure all the products are listed in the response for _, dependencyPath := range dependencyPaths { + var response []model.Node + // the 1st expected element of each inner array is a CertifyVEXStatement or a CertifyVuln re to the vulnerabilityID + response = append(response, certifyVexOrVuln) + // inject the PackageVersion in order for the toModelPackage method to work + dependencyPath[0].Edges.DependentPackageVersion.Edges.Name.Edges.Versions = []*ent.PackageVersion{dependencyPath[0].Edges.DependentPackageVersion} + // the 2nd expected element of each inner array is the vulnerable Package + response = append(response, toModelPackage(dependencyPath[0].Edges.DependentPackageVersion.Edges.Name)) for _, dep := range dependencyPath { - var response []model.Node - // the 1st expected element of each inner array is a CertifyVEXStatement or a CertifyVuln re to the vulnerabilityID - response = append(response, certifyVexOrVuln) - // inject the PackageVersion in order for the toModelPackage method to work - dep.Edges.DependentPackageVersion.Edges.Name.Edges.Versions = []*ent.PackageVersion{dep.Edges.DependentPackageVersion} - // the 2nd expected element of each inner array is the vulnerable Package - response = append(response, toModelPackage(dep.Edges.DependentPackageVersion.Edges.Name)) // the 3rd expected element of each inner array is the IsDependency between the vulnerable package and its SBOM response = append(response, toModelIsDependencyWithBackrefs(dep)) // inject the PackageVersion in order for the toModelPackage method to work dep.Edges.Package.Edges.Name.Edges.Versions = []*ent.PackageVersion{dep.Edges.Package} // the 4th expected element of each inner array is the SBOM Package response = append(response, toModelPackage(dep.Edges.Package.Edges.Name)) - result = append(result, response) } + result = append(result, response) } return result }