From 1f0d6290c33c95d5f213cc409a0ff6a53a2c888e Mon Sep 17 00:00:00 2001 From: Juan Ariza Toledano Date: Wed, 27 Dec 2023 08:54:56 +0100 Subject: [PATCH] feat(vuln): include pkg identifier on detected vulnerabilities (#5439) Signed-off-by: juan131 Signed-off-by: knqyf263 Co-authored-by: DmitriyLewen Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Co-authored-by: Nikita Pivkin Co-authored-by: knqyf263 --- integration/client_server_test.go | 2 +- integration/sbom_test.go | 54 +- integration/testdata/almalinux-8.json.golden | 3 + .../testdata/alpine-310-registry.json.golden | 12 + integration/testdata/alpine-310.json.golden | 12 + .../alpine-39-high-critical.json.golden | 6 + .../alpine-39-ignore-cveids.json.golden | 6 + integration/testdata/alpine-39.json.golden | 18 + .../testdata/alpine-distroless.json.golden | 3 + integration/testdata/amazon-1.json.golden | 3 + integration/testdata/amazon-2.json.golden | 6 + .../amazonlinux2-gp2-x86-vm.json.golden | 3 + .../busybox-with-lockfile.json.golden | 6 + integration/testdata/centos-6.json.golden | 6 + .../centos-7-ignore-unfixed.json.golden | 6 + .../testdata/centos-7-medium.json.golden | 3 + integration/testdata/centos-7.json.golden | 9 + integration/testdata/cocoapods.json.golden | 6 + .../testdata/composer.lock.json.golden | 9 + integration/testdata/conan.json.golden | 24 + integration/testdata/conda-spdx.json.golden | 28 +- .../debian-buster-ignore-unfixed.json.golden | 3 + .../testdata/debian-buster.json.golden | 6 + .../testdata/debian-stretch.json.golden | 15 + .../testdata/distroless-base.json.golden | 12 + .../testdata/distroless-python27.json.golden | 12 + integration/testdata/dotnet.json.golden | 6 + integration/testdata/fluentd-gems.json.golden | 6 + .../fluentd-multiple-lockfiles.json.golden | 9 + integration/testdata/gomod-skip.json.golden | 12 + integration/testdata/gomod.json.golden | 15 + integration/testdata/gradle.json.golden | 6 + integration/testdata/mariner-1.0.json.golden | 6 + .../testdata/minikube-kbom.json.golden | 3 + integration/testdata/mix.lock.json.golden | 33 + integration/testdata/npm-with-dev.json.golden | 42 + integration/testdata/npm.json.golden | 39 + integration/testdata/nuget.json.golden | 9 + .../testdata/opensuse-leap-151.json.golden | 6 + .../testdata/oraclelinux-8.json.golden | 6 + .../testdata/packagesprops.json.golden | 6 + integration/testdata/photon-30.json.golden | 9 + integration/testdata/pip.json.golden | 27 + integration/testdata/pipenv.json.golden | 9 + integration/testdata/pnpm.json.golden | 6 + integration/testdata/poetry.json.golden | 12 + .../testdata/pom-cyclonedx.json.golden | 156 +-- integration/testdata/pom.json.golden | 6 + integration/testdata/pubspec.lock.json.golden | 9 + integration/testdata/rockylinux-8.json.golden | 3 + .../testdata/spring4shell-jre11.json.golden | 3 + .../testdata/spring4shell-jre8.json.golden | 3 + integration/testdata/swift.json.golden | 9 + integration/testdata/test-repo.json.golden | 6 + integration/testdata/ubi-7.json.golden | 3 + .../ubuntu-1804-ignore-unfixed.json.golden | 12 + integration/testdata/ubuntu-1804.json.golden | 15 + .../testdata/ubuntu-gp2-x86-vm.json.golden | 3 + integration/testdata/yarn.json.golden | 6 + pkg/detector/library/detect.go | 1 + pkg/detector/ospkg/alma/alma.go | 2 +- pkg/detector/ospkg/alpine/alpine.go | 1 + pkg/detector/ospkg/amazon/amazon.go | 1 + pkg/detector/ospkg/chainguard/chainguard.go | 1 + pkg/detector/ospkg/debian/debian.go | 1 + pkg/detector/ospkg/mariner/mariner.go | 1 + pkg/detector/ospkg/oracle/oracle.go | 1 + pkg/detector/ospkg/photon/photon.go | 1 + pkg/detector/ospkg/redhat/redhat.go | 1 + pkg/detector/ospkg/rocky/rocky.go | 1 + pkg/detector/ospkg/suse/suse.go | 1 + pkg/detector/ospkg/ubuntu/ubuntu.go | 1 + pkg/detector/ospkg/wolfi/wolfi.go | 1 + pkg/fanal/analyzer/imgconf/apk/apk.go | 12 +- pkg/fanal/analyzer/imgconf/apk/apk_test.go | 4 +- pkg/fanal/analyzer/language/analyze.go | 6 +- pkg/fanal/analyzer/pkg/dpkg/dpkg_test.go | 5 +- pkg/fanal/analyzer/pkg/rpm/rpm_test.go | 7 +- pkg/fanal/analyzer/pkg/rpm/rpmqa.go | 5 +- pkg/fanal/analyzer/sbom/sbom.go | 6 +- pkg/fanal/analyzer/sbom/sbom_test.go | 114 ++ pkg/fanal/applier/applier_test.go | 174 +++ pkg/fanal/applier/docker.go | 83 +- pkg/fanal/applier/docker_test.go | 169 +++ pkg/fanal/artifact/image/remote_sbom_test.go | 58 +- pkg/fanal/artifact/local/fs_test.go | 20 +- pkg/fanal/artifact/sbom/sbom_test.go | 161 ++- pkg/fanal/artifact/vm/vm_test.go | 8 +- pkg/fanal/cache/fs_test.go | 4 + pkg/fanal/cache/mock_artifact_cache.go | 5 +- pkg/fanal/handler/sysfile/filter_test.go | 2 +- .../handler/unpackaged/unpackaged_test.go | 11 + pkg/fanal/test/integration/library_test.go | 8 + .../goldens/packages/alpine-310.json.golden | 42 + .../goldens/packages/vulnimage.json.golden | 174 +++ .../vuln-image1.2.3.expectedlibs.golden | 630 +++++++++ ...uln-image1.2.3.expectedpkgsfromcmds.golden | 1158 +++++------------ pkg/fanal/types/artifact.go | 47 +- pkg/fanal/types/handler.go | 3 +- pkg/fanal/types/purl.go | 78 ++ pkg/k8s/scanner/scanner.go | 8 +- pkg/k8s/scanner/scanner_test.go | 11 +- pkg/module/serialize/types_easyjson.go | 197 ++- pkg/purl/purl.go | 152 +-- pkg/purl/purl_test.go | 169 ++- pkg/report/github/github.go | 2 +- pkg/result/filter_test.go | 57 +- pkg/rpc/convert.go | 32 + pkg/sbom/cyclonedx/core/cyclonedx.go | 6 +- pkg/sbom/cyclonedx/core/cyclonedx_test.go | 8 +- pkg/sbom/cyclonedx/marshal.go | 11 +- pkg/sbom/cyclonedx/marshal_test.go | 315 ++++- pkg/sbom/cyclonedx/unmarshal.go | 51 +- pkg/sbom/cyclonedx/unmarshal_test.go | 339 ++++- pkg/sbom/spdx/marshal.go | 11 +- pkg/sbom/spdx/marshal_test.go | 142 +- pkg/sbom/spdx/unmarshal.go | 13 +- pkg/sbom/spdx/unmarshal_test.go | 167 ++- pkg/types/vulnerability.go | 26 +- pkg/vex/testdata/cyclonedx.json | 2 +- pkg/vex/testdata/openvex-multiple.json | 8 +- pkg/vex/testdata/openvex.json | 4 +- pkg/vex/vex.go | 21 +- pkg/vex/vex_test.go | 100 +- rpc/common/service.pb.go | 1035 ++++++++------- rpc/common/service.proto | 21 +- 126 files changed, 4728 insertions(+), 1963 deletions(-) create mode 100644 pkg/fanal/types/purl.go diff --git a/integration/client_server_test.go b/integration/client_server_test.go index 0fd0d0522ed9..c4274eb77a80 100644 --- a/integration/client_server_test.go +++ b/integration/client_server_test.go @@ -539,7 +539,7 @@ func TestClientServerWithRedis(t *testing.T) { // Run Trivy client err := execute(osArgs) require.Error(t, err) - assert.Contains(t, err.Error(), "connect: connection refused") + assert.Contains(t, err.Error(), "unable to store cache") }) } diff --git a/integration/sbom_test.go b/integration/sbom_test.go index c195e23d43df..5b657335d316 100644 --- a/integration/sbom_test.go +++ b/integration/sbom_test.go @@ -41,9 +41,15 @@ func TestSBOM(t *testing.T) { { Target: "testdata/fixtures/sbom/centos-7-cyclonedx.json (centos 7.6.1810)", Vulnerabilities: []types.DetectedVulnerability{ - {PkgRef: "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810"}, - {PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810"}, - {PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810"}, + { + PkgRef: "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810", + }, + { + PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810", + }, + { + PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810", + }, }, }, }, @@ -82,9 +88,15 @@ func TestSBOM(t *testing.T) { { Target: "testdata/fixtures/sbom/centos-7-cyclonedx.intoto.jsonl (centos 7.6.1810)", Vulnerabilities: []types.DetectedVulnerability{ - {PkgRef: "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810"}, - {PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810"}, - {PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810"}, + { + PkgRef: "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810", + }, + { + PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810", + }, + { + PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810", + }, }, }, }, @@ -105,9 +117,15 @@ func TestSBOM(t *testing.T) { { Target: "testdata/fixtures/sbom/centos-7-spdx.txt (centos 7.6.1810)", Vulnerabilities: []types.DetectedVulnerability{ - {PkgRef: "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810"}, - {PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810"}, - {PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810"}, + { + PkgRef: "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810", + }, + { + PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810", + }, + { + PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810", + }, }, }, }, @@ -128,9 +146,15 @@ func TestSBOM(t *testing.T) { { Target: "testdata/fixtures/sbom/centos-7-spdx.json (centos 7.6.1810)", Vulnerabilities: []types.DetectedVulnerability{ - {PkgRef: "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810"}, - {PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810"}, - {PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810"}, + { + PkgRef: "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810", + }, + { + PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810", + }, + { + PkgRef: "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810", + }, }, }, }, @@ -200,6 +224,12 @@ func compareSBOMReports(t *testing.T, wantFile, gotFile string, overrideWant typ want.Results[i].Target = result.Target for j, vuln := range result.Vulnerabilities { want.Results[i].Vulnerabilities[j].PkgRef = vuln.PkgRef + if vuln.PkgIdentifier.Empty() { + continue + } + want.Results[i].Vulnerabilities[j].PkgIdentifier = ftypes.PkgIdentifier{ + PURL: vuln.PkgIdentifier.PURL, + } } } diff --git a/integration/testdata/almalinux-8.json.golden b/integration/testdata/almalinux-8.json.golden index c2ae9382f4b4..409e02d6e9bd 100644 --- a/integration/testdata/almalinux-8.json.golden +++ b/integration/testdata/almalinux-8.json.golden @@ -56,6 +56,9 @@ "VulnerabilityID": "CVE-2021-3712", "PkgID": "openssl-libs@1.1.1k-4.el8.x86_64", "PkgName": "openssl-libs", + "PkgIdentifier": { + "PURL": "pkg:rpm/alma/openssl-libs@1.1.1k-4.el8?arch=x86_64\u0026distro=alma-8.5\u0026epoch=1" + }, "InstalledVersion": "1:1.1.1k-4.el8", "FixedVersion": "1:1.1.1k-5.el8_5", "Status": "fixed", diff --git a/integration/testdata/alpine-310-registry.json.golden b/integration/testdata/alpine-310-registry.json.golden index df64131304b2..cf451bbd7bfb 100644 --- a/integration/testdata/alpine-310-registry.json.golden +++ b/integration/testdata/alpine-310-registry.json.golden @@ -64,6 +64,9 @@ "VulnerabilityID": "CVE-2019-1549", "PkgID": "libcrypto1.1@1.1.1c-r0", "PkgName": "libcrypto1.1", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/libcrypto1.1@1.1.1c-r0?arch=x86_64\u0026distro=3.10.2" + }, "InstalledVersion": "1.1.1c-r0", "FixedVersion": "1.1.1d-r0", "Status": "fixed", @@ -133,6 +136,9 @@ "VulnerabilityID": "CVE-2019-1551", "PkgID": "libcrypto1.1@1.1.1c-r0", "PkgName": "libcrypto1.1", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/libcrypto1.1@1.1.1c-r0?arch=x86_64\u0026distro=3.10.2" + }, "InstalledVersion": "1.1.1c-r0", "FixedVersion": "1.1.1d-r2", "Status": "fixed", @@ -212,6 +218,9 @@ "VulnerabilityID": "CVE-2019-1549", "PkgID": "libssl1.1@1.1.1c-r0", "PkgName": "libssl1.1", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/libssl1.1@1.1.1c-r0?arch=x86_64\u0026distro=3.10.2" + }, "InstalledVersion": "1.1.1c-r0", "FixedVersion": "1.1.1d-r0", "Status": "fixed", @@ -281,6 +290,9 @@ "VulnerabilityID": "CVE-2019-1551", "PkgID": "libssl1.1@1.1.1c-r0", "PkgName": "libssl1.1", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/libssl1.1@1.1.1c-r0?arch=x86_64\u0026distro=3.10.2" + }, "InstalledVersion": "1.1.1c-r0", "FixedVersion": "1.1.1d-r2", "Status": "fixed", diff --git a/integration/testdata/alpine-310.json.golden b/integration/testdata/alpine-310.json.golden index 8c591c26815c..d6b4a7884027 100644 --- a/integration/testdata/alpine-310.json.golden +++ b/integration/testdata/alpine-310.json.golden @@ -58,6 +58,9 @@ "VulnerabilityID": "CVE-2019-1549", "PkgID": "libcrypto1.1@1.1.1c-r0", "PkgName": "libcrypto1.1", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/libcrypto1.1@1.1.1c-r0?arch=x86_64\u0026distro=3.10.2" + }, "InstalledVersion": "1.1.1c-r0", "FixedVersion": "1.1.1d-r0", "Status": "fixed", @@ -127,6 +130,9 @@ "VulnerabilityID": "CVE-2019-1551", "PkgID": "libcrypto1.1@1.1.1c-r0", "PkgName": "libcrypto1.1", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/libcrypto1.1@1.1.1c-r0?arch=x86_64\u0026distro=3.10.2" + }, "InstalledVersion": "1.1.1c-r0", "FixedVersion": "1.1.1d-r2", "Status": "fixed", @@ -206,6 +212,9 @@ "VulnerabilityID": "CVE-2019-1549", "PkgID": "libssl1.1@1.1.1c-r0", "PkgName": "libssl1.1", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/libssl1.1@1.1.1c-r0?arch=x86_64\u0026distro=3.10.2" + }, "InstalledVersion": "1.1.1c-r0", "FixedVersion": "1.1.1d-r0", "Status": "fixed", @@ -275,6 +284,9 @@ "VulnerabilityID": "CVE-2019-1551", "PkgID": "libssl1.1@1.1.1c-r0", "PkgName": "libssl1.1", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/libssl1.1@1.1.1c-r0?arch=x86_64\u0026distro=3.10.2" + }, "InstalledVersion": "1.1.1c-r0", "FixedVersion": "1.1.1d-r2", "Status": "fixed", diff --git a/integration/testdata/alpine-39-high-critical.json.golden b/integration/testdata/alpine-39-high-critical.json.golden index fc61f908f444..73288f579caa 100644 --- a/integration/testdata/alpine-39-high-critical.json.golden +++ b/integration/testdata/alpine-39-high-critical.json.golden @@ -58,6 +58,9 @@ "VulnerabilityID": "CVE-2019-14697", "PkgID": "musl@1.1.20-r4", "PkgName": "musl", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/musl@1.1.20-r4?arch=x86_64\u0026distro=3.9.4" + }, "InstalledVersion": "1.1.20-r4", "FixedVersion": "1.1.20-r5", "Status": "fixed", @@ -100,6 +103,9 @@ "VulnerabilityID": "CVE-2019-14697", "PkgID": "musl-utils@1.1.20-r4", "PkgName": "musl-utils", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/musl-utils@1.1.20-r4?arch=x86_64\u0026distro=3.9.4" + }, "InstalledVersion": "1.1.20-r4", "FixedVersion": "1.1.20-r5", "Status": "fixed", diff --git a/integration/testdata/alpine-39-ignore-cveids.json.golden b/integration/testdata/alpine-39-ignore-cveids.json.golden index e620ebe42066..f11198c2364e 100644 --- a/integration/testdata/alpine-39-ignore-cveids.json.golden +++ b/integration/testdata/alpine-39-ignore-cveids.json.golden @@ -58,6 +58,9 @@ "VulnerabilityID": "CVE-2019-1551", "PkgID": "libcrypto1.1@1.1.1b-r1", "PkgName": "libcrypto1.1", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/libcrypto1.1@1.1.1b-r1?arch=x86_64\u0026distro=3.9.4" + }, "InstalledVersion": "1.1.1b-r1", "FixedVersion": "1.1.1d-r2", "Status": "fixed", @@ -137,6 +140,9 @@ "VulnerabilityID": "CVE-2019-1551", "PkgID": "libssl1.1@1.1.1b-r1", "PkgName": "libssl1.1", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/libssl1.1@1.1.1b-r1?arch=x86_64\u0026distro=3.9.4" + }, "InstalledVersion": "1.1.1b-r1", "FixedVersion": "1.1.1d-r2", "Status": "fixed", diff --git a/integration/testdata/alpine-39.json.golden b/integration/testdata/alpine-39.json.golden index 7781ccc44c21..303f7a3c7277 100644 --- a/integration/testdata/alpine-39.json.golden +++ b/integration/testdata/alpine-39.json.golden @@ -58,6 +58,9 @@ "VulnerabilityID": "CVE-2019-1549", "PkgID": "libcrypto1.1@1.1.1b-r1", "PkgName": "libcrypto1.1", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/libcrypto1.1@1.1.1b-r1?arch=x86_64\u0026distro=3.9.4" + }, "InstalledVersion": "1.1.1b-r1", "FixedVersion": "1.1.1d-r0", "Status": "fixed", @@ -127,6 +130,9 @@ "VulnerabilityID": "CVE-2019-1551", "PkgID": "libcrypto1.1@1.1.1b-r1", "PkgName": "libcrypto1.1", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/libcrypto1.1@1.1.1b-r1?arch=x86_64\u0026distro=3.9.4" + }, "InstalledVersion": "1.1.1b-r1", "FixedVersion": "1.1.1d-r2", "Status": "fixed", @@ -206,6 +212,9 @@ "VulnerabilityID": "CVE-2019-1549", "PkgID": "libssl1.1@1.1.1b-r1", "PkgName": "libssl1.1", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/libssl1.1@1.1.1b-r1?arch=x86_64\u0026distro=3.9.4" + }, "InstalledVersion": "1.1.1b-r1", "FixedVersion": "1.1.1d-r0", "Status": "fixed", @@ -275,6 +284,9 @@ "VulnerabilityID": "CVE-2019-1551", "PkgID": "libssl1.1@1.1.1b-r1", "PkgName": "libssl1.1", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/libssl1.1@1.1.1b-r1?arch=x86_64\u0026distro=3.9.4" + }, "InstalledVersion": "1.1.1b-r1", "FixedVersion": "1.1.1d-r2", "Status": "fixed", @@ -354,6 +366,9 @@ "VulnerabilityID": "CVE-2019-14697", "PkgID": "musl@1.1.20-r4", "PkgName": "musl", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/musl@1.1.20-r4?arch=x86_64\u0026distro=3.9.4" + }, "InstalledVersion": "1.1.20-r4", "FixedVersion": "1.1.20-r5", "Status": "fixed", @@ -396,6 +411,9 @@ "VulnerabilityID": "CVE-2019-14697", "PkgID": "musl-utils@1.1.20-r4", "PkgName": "musl-utils", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/musl-utils@1.1.20-r4?arch=x86_64\u0026distro=3.9.4" + }, "InstalledVersion": "1.1.20-r4", "FixedVersion": "1.1.20-r5", "Status": "fixed", diff --git a/integration/testdata/alpine-distroless.json.golden b/integration/testdata/alpine-distroless.json.golden index 6896e3c56053..8f79cba7610c 100644 --- a/integration/testdata/alpine-distroless.json.golden +++ b/integration/testdata/alpine-distroless.json.golden @@ -53,6 +53,9 @@ "VulnerabilityID": "CVE-2022-24765", "PkgID": "git@2.35.1-r2", "PkgName": "git", + "PkgIdentifier": { + "PURL": "pkg:apk/alpine/git@2.35.1-r2?arch=x86_64\u0026distro=3.16" + }, "InstalledVersion": "2.35.1-r2", "FixedVersion": "2.35.2-r0", "Status": "fixed", diff --git a/integration/testdata/amazon-1.json.golden b/integration/testdata/amazon-1.json.golden index dde37a90724c..6be4b41ffe3b 100644 --- a/integration/testdata/amazon-1.json.golden +++ b/integration/testdata/amazon-1.json.golden @@ -57,6 +57,9 @@ "VulnerabilityID": "CVE-2019-5481", "PkgID": "curl@7.61.1-11.91.amzn1.x86_64", "PkgName": "curl", + "PkgIdentifier": { + "PURL": "pkg:rpm/amazon/curl@7.61.1-11.91.amzn1?arch=x86_64\u0026distro=amazon-AMI+release+2018.03" + }, "InstalledVersion": "7.61.1-11.91.amzn1", "FixedVersion": "7.61.1-12.93.amzn1", "Status": "fixed", diff --git a/integration/testdata/amazon-2.json.golden b/integration/testdata/amazon-2.json.golden index ba19b615dfd7..1f20d8d37b68 100644 --- a/integration/testdata/amazon-2.json.golden +++ b/integration/testdata/amazon-2.json.golden @@ -57,6 +57,9 @@ "VulnerabilityID": "CVE-2019-5481", "PkgID": "curl@7.61.1-9.amzn2.0.1.x86_64", "PkgName": "curl", + "PkgIdentifier": { + "PURL": "pkg:rpm/amazon/curl@7.61.1-9.amzn2.0.1?arch=x86_64\u0026distro=amazon-2+%28Karoo%29" + }, "InstalledVersion": "7.61.1-9.amzn2.0.1", "FixedVersion": "7.61.1-12.amzn2.0.1", "Status": "fixed", @@ -125,6 +128,9 @@ "VulnerabilityID": "CVE-2019-5436", "PkgID": "curl@7.61.1-9.amzn2.0.1.x86_64", "PkgName": "curl", + "PkgIdentifier": { + "PURL": "pkg:rpm/amazon/curl@7.61.1-9.amzn2.0.1?arch=x86_64\u0026distro=amazon-2+%28Karoo%29" + }, "InstalledVersion": "7.61.1-9.amzn2.0.1", "FixedVersion": "7.61.1-11.amzn2.0.2", "Status": "fixed", diff --git a/integration/testdata/amazonlinux2-gp2-x86-vm.json.golden b/integration/testdata/amazonlinux2-gp2-x86-vm.json.golden index fe220cabad2e..27cda6c2b6e7 100644 --- a/integration/testdata/amazonlinux2-gp2-x86-vm.json.golden +++ b/integration/testdata/amazonlinux2-gp2-x86-vm.json.golden @@ -29,6 +29,9 @@ "VulnerabilityID": "CVE-2022-38177", "PkgID": "bind-export-libs@9.11.4-26.P2.amzn2.5.2.x86_64", "PkgName": "bind-export-libs", + "PkgIdentifier": { + "PURL": "pkg:rpm/amazon/bind-export-libs@9.11.4-26.P2.amzn2.5.2?arch=x86_64\u0026distro=amazon-2+%28Karoo%29\u0026epoch=32" + }, "InstalledVersion": "32:9.11.4-26.P2.amzn2.5.2", "FixedVersion": "99:9.11.4-26.P2.amzn2.13", "Status": "fixed", diff --git a/integration/testdata/busybox-with-lockfile.json.golden b/integration/testdata/busybox-with-lockfile.json.golden index 8c02e02b4d6f..520afe2de928 100644 --- a/integration/testdata/busybox-with-lockfile.json.golden +++ b/integration/testdata/busybox-with-lockfile.json.golden @@ -57,6 +57,9 @@ "VulnerabilityID": "CVE-2019-15542", "PkgID": "ammonia@1.9.0", "PkgName": "ammonia", + "PkgIdentifier": { + "PURL": "pkg:cargo/ammonia@1.9.0" + }, "InstalledVersion": "1.9.0", "FixedVersion": "\u003e= 2.1.0", "Status": "fixed", @@ -99,6 +102,9 @@ "VulnerabilityID": "CVE-2021-38193", "PkgID": "ammonia@1.9.0", "PkgName": "ammonia", + "PkgIdentifier": { + "PURL": "pkg:cargo/ammonia@1.9.0" + }, "InstalledVersion": "1.9.0", "FixedVersion": "\u003e= 3.1.0, \u003e= 2.1.3, \u003c 3.0.0", "Status": "fixed", diff --git a/integration/testdata/centos-6.json.golden b/integration/testdata/centos-6.json.golden index d8cb95553e79..c1791c58a486 100644 --- a/integration/testdata/centos-6.json.golden +++ b/integration/testdata/centos-6.json.golden @@ -79,6 +79,9 @@ "VulnerabilityID": "CVE-2020-29573", "PkgID": "glibc@2.12-1.212.el6.x86_64", "PkgName": "glibc", + "PkgIdentifier": { + "PURL": "pkg:rpm/centos/glibc@2.12-1.212.el6?arch=x86_64\u0026distro=centos-6.10" + }, "InstalledVersion": "2.12-1.212.el6", "Status": "end_of_life", "Layer": { @@ -132,6 +135,9 @@ ], "PkgID": "openssl@1.0.1e-57.el6.x86_64", "PkgName": "openssl", + "PkgIdentifier": { + "PURL": "pkg:rpm/centos/openssl@1.0.1e-57.el6?arch=x86_64\u0026distro=centos-6.10" + }, "InstalledVersion": "1.0.1e-57.el6", "FixedVersion": "1.0.1e-58.el6_10", "Status": "fixed", diff --git a/integration/testdata/centos-7-ignore-unfixed.json.golden b/integration/testdata/centos-7-ignore-unfixed.json.golden index 49777f004005..ad8379a5d80e 100644 --- a/integration/testdata/centos-7-ignore-unfixed.json.golden +++ b/integration/testdata/centos-7-ignore-unfixed.json.golden @@ -72,6 +72,9 @@ ], "PkgID": "openssl-libs@1.0.2k-16.el7.x86_64", "PkgName": "openssl-libs", + "PkgIdentifier": { + "PURL": "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64\u0026distro=centos-7.6.1810\u0026epoch=1" + }, "InstalledVersion": "1:1.0.2k-16.el7", "FixedVersion": "1:1.0.2k-19.el7", "Status": "fixed", @@ -162,6 +165,9 @@ ], "PkgID": "openssl-libs@1.0.2k-16.el7.x86_64", "PkgName": "openssl-libs", + "PkgIdentifier": { + "PURL": "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64\u0026distro=centos-7.6.1810\u0026epoch=1" + }, "InstalledVersion": "1:1.0.2k-16.el7", "FixedVersion": "1:1.0.2k-19.el7", "Status": "fixed", diff --git a/integration/testdata/centos-7-medium.json.golden b/integration/testdata/centos-7-medium.json.golden index eb54be5b1315..ef4a44d2bbe5 100644 --- a/integration/testdata/centos-7-medium.json.golden +++ b/integration/testdata/centos-7-medium.json.golden @@ -72,6 +72,9 @@ ], "PkgID": "openssl-libs@1.0.2k-16.el7.x86_64", "PkgName": "openssl-libs", + "PkgIdentifier": { + "PURL": "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64\u0026distro=centos-7.6.1810\u0026epoch=1" + }, "InstalledVersion": "1:1.0.2k-16.el7", "FixedVersion": "1:1.0.2k-19.el7", "Status": "fixed", diff --git a/integration/testdata/centos-7.json.golden b/integration/testdata/centos-7.json.golden index 333ce10d4e5f..55ea768c99a8 100644 --- a/integration/testdata/centos-7.json.golden +++ b/integration/testdata/centos-7.json.golden @@ -69,6 +69,9 @@ "VulnerabilityID": "CVE-2019-18276", "PkgID": "bash@4.2.46-31.el7.x86_64", "PkgName": "bash", + "PkgIdentifier": { + "PURL": "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64\u0026distro=centos-7.6.1810" + }, "InstalledVersion": "4.2.46-31.el7", "Status": "will_not_fix", "Layer": { @@ -126,6 +129,9 @@ ], "PkgID": "openssl-libs@1.0.2k-16.el7.x86_64", "PkgName": "openssl-libs", + "PkgIdentifier": { + "PURL": "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64\u0026distro=centos-7.6.1810\u0026epoch=1" + }, "InstalledVersion": "1:1.0.2k-16.el7", "FixedVersion": "1:1.0.2k-19.el7", "Status": "fixed", @@ -216,6 +222,9 @@ ], "PkgID": "openssl-libs@1.0.2k-16.el7.x86_64", "PkgName": "openssl-libs", + "PkgIdentifier": { + "PURL": "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64\u0026distro=centos-7.6.1810\u0026epoch=1" + }, "InstalledVersion": "1:1.0.2k-16.el7", "FixedVersion": "1:1.0.2k-19.el7", "Status": "fixed", diff --git a/integration/testdata/cocoapods.json.golden b/integration/testdata/cocoapods.json.golden index 71c4651e8158..9553f0624286 100644 --- a/integration/testdata/cocoapods.json.golden +++ b/integration/testdata/cocoapods.json.golden @@ -24,6 +24,9 @@ { "ID": "_NIODataStructures@2.41.0", "Name": "_NIODataStructures", + "Identifier": { + "PURL": "pkg:cocoapods/_NIODataStructures@2.41.0" + }, "Version": "2.41.0", "Layer": {} } @@ -33,6 +36,9 @@ "VulnerabilityID": "CVE-2022-3215", "PkgID": "_NIODataStructures@2.41.0", "PkgName": "_NIODataStructures", + "PkgIdentifier": { + "PURL": "pkg:cocoapods/_NIODataStructures@2.41.0" + }, "InstalledVersion": "2.41.0", "FixedVersion": "2.29.1, 2.39.1, 2.42.0", "Status": "fixed", diff --git a/integration/testdata/composer.lock.json.golden b/integration/testdata/composer.lock.json.golden index 02718c7cab3d..a3bdf13f9ece 100644 --- a/integration/testdata/composer.lock.json.golden +++ b/integration/testdata/composer.lock.json.golden @@ -24,6 +24,9 @@ { "ID": "guzzlehttp/guzzle@7.4.4", "Name": "guzzlehttp/guzzle", + "Identifier": { + "PURL": "pkg:composer/guzzlehttp/guzzle@7.4.4" + }, "Version": "7.4.4", "Licenses": [ "MIT" @@ -42,6 +45,9 @@ { "ID": "guzzlehttp/psr7@1.8.3", "Name": "guzzlehttp/psr7", + "Identifier": { + "PURL": "pkg:composer/guzzlehttp/psr7@1.8.3" + }, "Version": "1.8.3", "Licenses": [ "MIT" @@ -61,6 +67,9 @@ "VulnerabilityID": "CVE-2022-24775", "PkgID": "guzzlehttp/psr7@1.8.3", "PkgName": "guzzlehttp/psr7", + "PkgIdentifier": { + "PURL": "pkg:composer/guzzlehttp/psr7@1.8.3" + }, "InstalledVersion": "1.8.3", "FixedVersion": "1.8.4", "Status": "fixed", diff --git a/integration/testdata/conan.json.golden b/integration/testdata/conan.json.golden index 3b0d8d4f4e0d..ee60780c1d5f 100644 --- a/integration/testdata/conan.json.golden +++ b/integration/testdata/conan.json.golden @@ -24,6 +24,9 @@ { "ID": "bzip2/1.0.8", "Name": "bzip2", + "Identifier": { + "PURL": "pkg:conan/bzip2@1.0.8" + }, "Version": "1.0.8", "Indirect": true, "Layer": {}, @@ -37,6 +40,9 @@ { "ID": "expat/2.4.8", "Name": "expat", + "Identifier": { + "PURL": "pkg:conan/expat@2.4.8" + }, "Version": "2.4.8", "Indirect": true, "Layer": {}, @@ -50,6 +56,9 @@ { "ID": "openssl/1.1.1q", "Name": "openssl", + "Identifier": { + "PURL": "pkg:conan/openssl@1.1.1q" + }, "Version": "1.1.1q", "Indirect": true, "Layer": {}, @@ -63,6 +72,9 @@ { "ID": "pcre/8.43", "Name": "pcre", + "Identifier": { + "PURL": "pkg:conan/pcre@8.43" + }, "Version": "8.43", "Indirect": true, "DependsOn": [ @@ -80,6 +92,9 @@ { "ID": "poco/1.9.4", "Name": "poco", + "Identifier": { + "PURL": "pkg:conan/poco@1.9.4" + }, "Version": "1.9.4", "DependsOn": [ "pcre/8.43", @@ -99,6 +114,9 @@ { "ID": "sqlite3/3.39.2", "Name": "sqlite3", + "Identifier": { + "PURL": "pkg:conan/sqlite3@3.39.2" + }, "Version": "3.39.2", "Indirect": true, "Layer": {}, @@ -112,6 +130,9 @@ { "ID": "zlib/1.2.12", "Name": "zlib", + "Identifier": { + "PURL": "pkg:conan/zlib@1.2.12" + }, "Version": "1.2.12", "Indirect": true, "Layer": {}, @@ -128,6 +149,9 @@ "VulnerabilityID": "CVE-2020-14155", "PkgID": "pcre/8.43", "PkgName": "pcre", + "PkgIdentifier": { + "PURL": "pkg:conan/pcre@8.43" + }, "InstalledVersion": "8.43", "FixedVersion": "8.45", "Status": "fixed", diff --git a/integration/testdata/conda-spdx.json.golden b/integration/testdata/conda-spdx.json.golden index 73b3394e6697..4803da139d8c 100644 --- a/integration/testdata/conda-spdx.json.golden +++ b/integration/testdata/conda-spdx.json.golden @@ -22,7 +22,7 @@ }, { "name": "openssl", - "SPDXID": "SPDXRef-Package-c75d9dc75200186f", + "SPDXID": "SPDXRef-Package-a4bad823866cc210", "versionInfo": "1.1.1q", "supplier": "NOASSERTION", "downloadLocation": "NONE", @@ -43,7 +43,7 @@ }, { "name": "pip", - "SPDXID": "SPDXRef-Package-195557cddf18e4a9", + "SPDXID": "SPDXRef-Package-e8a0eb2c9979a021", "versionInfo": "22.2.2", "supplier": "NOASSERTION", "downloadLocation": "NONE", @@ -75,23 +75,23 @@ ], "files": [ { - "fileName": "miniconda3/envs/testenv/conda-meta/pip-22.2.2-py38h06a4308_0.json", - "SPDXID": "SPDXRef-File-7eb62e2a3edddc0a", + "fileName": "miniconda3/envs/testenv/conda-meta/openssl-1.1.1q-h7f8727e_0.json", + "SPDXID": "SPDXRef-File-600e5e0110a84891", "checksums": [ { "algorithm": "SHA1", - "checksumValue": "a6a2db7668f1ad541d704369fc66c96a4415aa24" + "checksumValue": "237db0da53131e4548cb1181337fa0f420299e1f" } ], "copyrightText": "" }, { - "fileName": "miniconda3/envs/testenv/conda-meta/openssl-1.1.1q-h7f8727e_0.json", - "SPDXID": "SPDXRef-File-600e5e0110a84891", + "fileName": "miniconda3/envs/testenv/conda-meta/pip-22.2.2-py38h06a4308_0.json", + "SPDXID": "SPDXRef-File-7eb62e2a3edddc0a", "checksums": [ { "algorithm": "SHA1", - "checksumValue": "237db0da53131e4548cb1181337fa0f420299e1f" + "checksumValue": "a6a2db7668f1ad541d704369fc66c96a4415aa24" } ], "copyrightText": "" @@ -110,22 +110,22 @@ }, { "spdxElementId": "SPDXRef-Application-ee5ef1aa4ac89125", - "relatedSpdxElement": "SPDXRef-Package-195557cddf18e4a9", + "relatedSpdxElement": "SPDXRef-Package-a4bad823866cc210", "relationshipType": "CONTAINS" }, { - "spdxElementId": "SPDXRef-Package-195557cddf18e4a9", - "relatedSpdxElement": "SPDXRef-File-7eb62e2a3edddc0a", + "spdxElementId": "SPDXRef-Package-a4bad823866cc210", + "relatedSpdxElement": "SPDXRef-File-600e5e0110a84891", "relationshipType": "CONTAINS" }, { "spdxElementId": "SPDXRef-Application-ee5ef1aa4ac89125", - "relatedSpdxElement": "SPDXRef-Package-c75d9dc75200186f", + "relatedSpdxElement": "SPDXRef-Package-e8a0eb2c9979a021", "relationshipType": "CONTAINS" }, { - "spdxElementId": "SPDXRef-Package-c75d9dc75200186f", - "relatedSpdxElement": "SPDXRef-File-600e5e0110a84891", + "spdxElementId": "SPDXRef-Package-e8a0eb2c9979a021", + "relatedSpdxElement": "SPDXRef-File-7eb62e2a3edddc0a", "relationshipType": "CONTAINS" } ] diff --git a/integration/testdata/debian-buster-ignore-unfixed.json.golden b/integration/testdata/debian-buster-ignore-unfixed.json.golden index 0ef080d4a7a7..0d387db18fbf 100644 --- a/integration/testdata/debian-buster-ignore-unfixed.json.golden +++ b/integration/testdata/debian-buster-ignore-unfixed.json.golden @@ -60,6 +60,9 @@ ], "PkgID": "libidn2-0@2.0.5-1", "PkgName": "libidn2-0", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/libidn2-0@2.0.5-1?arch=amd64\u0026distro=debian-10.1" + }, "InstalledVersion": "2.0.5-1", "FixedVersion": "2.0.5-1+deb10u1", "Status": "fixed", diff --git a/integration/testdata/debian-buster.json.golden b/integration/testdata/debian-buster.json.golden index 67a40b7b5a58..739158b5fe6e 100644 --- a/integration/testdata/debian-buster.json.golden +++ b/integration/testdata/debian-buster.json.golden @@ -57,6 +57,9 @@ "VulnerabilityID": "CVE-2019-18276", "PkgID": "bash@5.0-4", "PkgName": "bash", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/bash@5.0-4?arch=amd64\u0026distro=debian-10.1" + }, "InstalledVersion": "5.0-4", "Status": "affected", "Layer": { @@ -120,6 +123,9 @@ ], "PkgID": "libidn2-0@2.0.5-1", "PkgName": "libidn2-0", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/libidn2-0@2.0.5-1?arch=amd64\u0026distro=debian-10.1" + }, "InstalledVersion": "2.0.5-1", "FixedVersion": "2.0.5-1+deb10u1", "Status": "fixed", diff --git a/integration/testdata/debian-stretch.json.golden b/integration/testdata/debian-stretch.json.golden index 7c8893cbdad7..6fd20bda1ee8 100644 --- a/integration/testdata/debian-stretch.json.golden +++ b/integration/testdata/debian-stretch.json.golden @@ -58,6 +58,9 @@ "VulnerabilityID": "CVE-2019-18276", "PkgID": "bash@4.4-5", "PkgName": "bash", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/bash@4.4-5?arch=amd64\u0026distro=debian-9.9" + }, "InstalledVersion": "4.4-5", "Status": "end_of_life", "Layer": { @@ -121,6 +124,9 @@ ], "PkgID": "e2fslibs@1.43.4-2", "PkgName": "e2fslibs", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/e2fslibs@1.43.4-2?arch=amd64\u0026distro=debian-9.9" + }, "InstalledVersion": "1.43.4-2", "FixedVersion": "1.43.4-2+deb9u1", "Status": "fixed", @@ -191,6 +197,9 @@ ], "PkgID": "e2fsprogs@1.43.4-2", "PkgName": "e2fsprogs", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/e2fsprogs@1.43.4-2?arch=amd64\u0026distro=debian-9.9" + }, "InstalledVersion": "1.43.4-2", "FixedVersion": "1.43.4-2+deb9u1", "Status": "fixed", @@ -261,6 +270,9 @@ ], "PkgID": "libcomerr2@1.43.4-2", "PkgName": "libcomerr2", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/libcomerr2@1.43.4-2?arch=amd64\u0026distro=debian-9.9" + }, "InstalledVersion": "1.43.4-2", "FixedVersion": "1.43.4-2+deb9u1", "Status": "fixed", @@ -331,6 +343,9 @@ ], "PkgID": "libss2@1.43.4-2", "PkgName": "libss2", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/libss2@1.43.4-2?arch=amd64\u0026distro=debian-9.9" + }, "InstalledVersion": "1.43.4-2", "FixedVersion": "1.43.4-2+deb9u1", "Status": "fixed", diff --git a/integration/testdata/distroless-base.json.golden b/integration/testdata/distroless-base.json.golden index b9ce4e3b400d..82de2d5368b9 100644 --- a/integration/testdata/distroless-base.json.golden +++ b/integration/testdata/distroless-base.json.golden @@ -56,6 +56,9 @@ "VulnerabilityID": "CVE-2019-1551", "PkgID": "libssl1.1@1.1.0k-1~deb9u1", "PkgName": "libssl1.1", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/libssl1.1@1.1.0k-1~deb9u1?arch=amd64\u0026distro=debian-9.9" + }, "InstalledVersion": "1.1.0k-1~deb9u1", "Status": "affected", "Layer": { @@ -137,6 +140,9 @@ ], "PkgID": "libssl1.1@1.1.0k-1~deb9u1", "PkgName": "libssl1.1", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/libssl1.1@1.1.0k-1~deb9u1?arch=amd64\u0026distro=debian-9.9" + }, "InstalledVersion": "1.1.0k-1~deb9u1", "FixedVersion": "1.1.0l-1~deb9u1", "Status": "fixed", @@ -224,6 +230,9 @@ "VulnerabilityID": "CVE-2019-1551", "PkgID": "openssl@1.1.0k-1~deb9u1", "PkgName": "openssl", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/openssl@1.1.0k-1~deb9u1?arch=amd64\u0026distro=debian-9.9" + }, "InstalledVersion": "1.1.0k-1~deb9u1", "Status": "affected", "Layer": { @@ -305,6 +314,9 @@ ], "PkgID": "openssl@1.1.0k-1~deb9u1", "PkgName": "openssl", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/openssl@1.1.0k-1~deb9u1?arch=amd64\u0026distro=debian-9.9" + }, "InstalledVersion": "1.1.0k-1~deb9u1", "FixedVersion": "1.1.0l-1~deb9u1", "Status": "fixed", diff --git a/integration/testdata/distroless-python27.json.golden b/integration/testdata/distroless-python27.json.golden index d97edd78bfed..f8d54b339867 100644 --- a/integration/testdata/distroless-python27.json.golden +++ b/integration/testdata/distroless-python27.json.golden @@ -73,6 +73,9 @@ "VulnerabilityID": "CVE-2019-1551", "PkgID": "libssl1.1@1.1.0k-1~deb9u1", "PkgName": "libssl1.1", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/libssl1.1@1.1.0k-1~deb9u1?arch=amd64\u0026distro=debian-9.9" + }, "InstalledVersion": "1.1.0k-1~deb9u1", "Status": "affected", "Layer": { @@ -154,6 +157,9 @@ ], "PkgID": "libssl1.1@1.1.0k-1~deb9u1", "PkgName": "libssl1.1", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/libssl1.1@1.1.0k-1~deb9u1?arch=amd64\u0026distro=debian-9.9" + }, "InstalledVersion": "1.1.0k-1~deb9u1", "FixedVersion": "1.1.0l-1~deb9u1", "Status": "fixed", @@ -241,6 +247,9 @@ "VulnerabilityID": "CVE-2019-1551", "PkgID": "openssl@1.1.0k-1~deb9u1", "PkgName": "openssl", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/openssl@1.1.0k-1~deb9u1?arch=amd64\u0026distro=debian-9.9" + }, "InstalledVersion": "1.1.0k-1~deb9u1", "Status": "affected", "Layer": { @@ -322,6 +331,9 @@ ], "PkgID": "openssl@1.1.0k-1~deb9u1", "PkgName": "openssl", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/openssl@1.1.0k-1~deb9u1?arch=amd64\u0026distro=debian-9.9" + }, "InstalledVersion": "1.1.0k-1~deb9u1", "FixedVersion": "1.1.0l-1~deb9u1", "Status": "fixed", diff --git a/integration/testdata/dotnet.json.golden b/integration/testdata/dotnet.json.golden index c2d51a2080aa..264b28d7534d 100644 --- a/integration/testdata/dotnet.json.golden +++ b/integration/testdata/dotnet.json.golden @@ -23,6 +23,9 @@ "Packages": [ { "Name": "Newtonsoft.Json", + "Identifier": { + "PURL": "pkg:nuget/Newtonsoft.Json@9.0.1" + }, "Version": "9.0.1", "Layer": {}, "Locations": [ @@ -37,6 +40,9 @@ { "VulnerabilityID": "GHSA-5crp-9r3c-p9vr", "PkgName": "Newtonsoft.Json", + "PkgIdentifier": { + "PURL": "pkg:nuget/Newtonsoft.Json@9.0.1" + }, "InstalledVersion": "9.0.1", "FixedVersion": "13.0.1", "Status": "fixed", diff --git a/integration/testdata/fluentd-gems.json.golden b/integration/testdata/fluentd-gems.json.golden index eb24957e0a13..2072e0c4bf8d 100644 --- a/integration/testdata/fluentd-gems.json.golden +++ b/integration/testdata/fluentd-gems.json.golden @@ -113,6 +113,9 @@ ], "PkgID": "libidn2-0@2.0.5-1", "PkgName": "libidn2-0", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/libidn2-0@2.0.5-1?arch=amd64\u0026distro=debian-10.2" + }, "InstalledVersion": "2.0.5-1", "FixedVersion": "2.0.5-1+deb10u1", "Status": "fixed", @@ -181,6 +184,9 @@ "VulnerabilityID": "CVE-2020-8165", "PkgName": "activesupport", "PkgPath": "var/lib/gems/2.5.0/specifications/activesupport-6.0.2.1.gemspec", + "PkgIdentifier": { + "PURL": "pkg:gem/activesupport@6.0.2.1" + }, "InstalledVersion": "6.0.2.1", "FixedVersion": "6.0.3.1, 5.2.4.3", "Status": "fixed", diff --git a/integration/testdata/fluentd-multiple-lockfiles.json.golden b/integration/testdata/fluentd-multiple-lockfiles.json.golden index c067638c8dd1..784f9f1a0339 100644 --- a/integration/testdata/fluentd-multiple-lockfiles.json.golden +++ b/integration/testdata/fluentd-multiple-lockfiles.json.golden @@ -28,6 +28,9 @@ { "VulnerabilityID": "CVE-2019-18276", "PkgName": "bash", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/bash@5.0-4?distro=debian-10.2" + }, "InstalledVersion": "5.0-4", "Status": "affected", "Layer": {}, @@ -88,6 +91,9 @@ "DSA-4613-1" ], "PkgName": "libidn2-0", + "PkgIdentifier": { + "PURL": "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2" + }, "InstalledVersion": "2.0.5-1", "FixedVersion": "2.0.5-1+deb10u1", "Status": "fixed", @@ -154,6 +160,9 @@ "VulnerabilityID": "CVE-2020-8165", "PkgName": "activesupport", "PkgPath": "var/lib/gems/2.5.0/specifications/activesupport-6.0.2.1.gemspec", + "PkgIdentifier": { + "PURL": "pkg:gem/activesupport@6.0.2.1" + }, "InstalledVersion": "6.0.2.1", "FixedVersion": "6.0.3.1, 5.2.4.3", "Status": "fixed", diff --git a/integration/testdata/gomod-skip.json.golden b/integration/testdata/gomod-skip.json.golden index 8f1e4f643cdc..ce748cc19823 100644 --- a/integration/testdata/gomod-skip.json.golden +++ b/integration/testdata/gomod-skip.json.golden @@ -25,6 +25,9 @@ "VulnerabilityID": "GMS-2022-20", "PkgID": "github.com/docker/distribution@v2.7.1+incompatible", "PkgName": "github.com/docker/distribution", + "PkgIdentifier": { + "PURL": "pkg:golang/github.com/docker/distribution@2.7.1%2Bincompatible" + }, "InstalledVersion": "2.7.1+incompatible", "FixedVersion": "v2.8.0", "Status": "fixed", @@ -48,6 +51,9 @@ "VulnerabilityID": "CVE-2022-23628", "PkgID": "github.com/open-policy-agent/opa@v0.35.0", "PkgName": "github.com/open-policy-agent/opa", + "PkgIdentifier": { + "PURL": "pkg:golang/github.com/open-policy-agent/opa@0.35.0" + }, "InstalledVersion": "0.35.0", "FixedVersion": "0.37.0", "Status": "fixed", @@ -91,6 +97,9 @@ "VulnerabilityID": "CVE-2021-38561", "PkgID": "golang.org/x/text@v0.3.6", "PkgName": "golang.org/x/text", + "PkgIdentifier": { + "PURL": "pkg:golang/golang.org/x/text@0.3.6" + }, "InstalledVersion": "0.3.6", "FixedVersion": "0.3.7", "Status": "fixed", @@ -120,6 +129,9 @@ "VulnerabilityID": "GMS-2022-20", "PkgID": "github.com/docker/distribution@v2.7.1+incompatible", "PkgName": "github.com/docker/distribution", + "PkgIdentifier": { + "PURL": "pkg:golang/github.com/docker/distribution@2.7.1%2Bincompatible" + }, "InstalledVersion": "2.7.1+incompatible", "FixedVersion": "v2.8.0", "Status": "fixed", diff --git a/integration/testdata/gomod.json.golden b/integration/testdata/gomod.json.golden index 4d553e7ca2c7..5009b9d3bf81 100644 --- a/integration/testdata/gomod.json.golden +++ b/integration/testdata/gomod.json.golden @@ -25,6 +25,9 @@ "VulnerabilityID": "GMS-2022-20", "PkgID": "github.com/docker/distribution@v2.7.1+incompatible", "PkgName": "github.com/docker/distribution", + "PkgIdentifier": { + "PURL": "pkg:golang/github.com/docker/distribution@2.7.1%2Bincompatible" + }, "InstalledVersion": "2.7.1+incompatible", "FixedVersion": "v2.8.0", "Status": "fixed", @@ -48,6 +51,9 @@ "VulnerabilityID": "CVE-2022-23628", "PkgID": "github.com/open-policy-agent/opa@v0.35.0", "PkgName": "github.com/open-policy-agent/opa", + "PkgIdentifier": { + "PURL": "pkg:golang/github.com/open-policy-agent/opa@0.35.0" + }, "InstalledVersion": "0.35.0", "FixedVersion": "0.37.0", "Status": "fixed", @@ -91,6 +97,9 @@ "VulnerabilityID": "CVE-2021-38561", "PkgID": "golang.org/x/text@v0.3.6", "PkgName": "golang.org/x/text", + "PkgIdentifier": { + "PURL": "pkg:golang/golang.org/x/text@0.3.6" + }, "InstalledVersion": "0.3.6", "FixedVersion": "0.3.7", "Status": "fixed", @@ -120,6 +129,9 @@ "VulnerabilityID": "GMS-2022-20", "PkgID": "github.com/docker/distribution@v2.7.1+incompatible", "PkgName": "github.com/docker/distribution", + "PkgIdentifier": { + "PURL": "pkg:golang/github.com/docker/distribution@2.7.1%2Bincompatible" + }, "InstalledVersion": "2.7.1+incompatible", "FixedVersion": "v2.8.0", "Status": "fixed", @@ -150,6 +162,9 @@ "VulnerabilityID": "GMS-2022-20", "PkgID": "github.com/docker/distribution@v2.7.1+incompatible", "PkgName": "github.com/docker/distribution", + "PkgIdentifier": { + "PURL": "pkg:golang/github.com/docker/distribution@2.7.1%2Bincompatible" + }, "InstalledVersion": "2.7.1+incompatible", "FixedVersion": "v2.8.0", "Status": "fixed", diff --git a/integration/testdata/gradle.json.golden b/integration/testdata/gradle.json.golden index 9ff2b02aeb8d..4979b31fbedf 100644 --- a/integration/testdata/gradle.json.golden +++ b/integration/testdata/gradle.json.golden @@ -24,6 +24,9 @@ { "VulnerabilityID": "CVE-2020-9548", "PkgName": "com.fasterxml.jackson.core:jackson-databind", + "PkgIdentifier": { + "PURL": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.1" + }, "InstalledVersion": "2.9.1", "FixedVersion": "2.9.10.4", "Status": "fixed", @@ -85,6 +88,9 @@ { "VulnerabilityID": "CVE-2021-20190", "PkgName": "com.fasterxml.jackson.core:jackson-databind", + "PkgIdentifier": { + "PURL": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.1" + }, "InstalledVersion": "2.9.1", "FixedVersion": "2.9.10.7", "Status": "fixed", diff --git a/integration/testdata/mariner-1.0.json.golden b/integration/testdata/mariner-1.0.json.golden index 4b5ac7b7363d..435dd5bdf7a6 100644 --- a/integration/testdata/mariner-1.0.json.golden +++ b/integration/testdata/mariner-1.0.json.golden @@ -41,6 +41,9 @@ { "VulnerabilityID": "CVE-2022-0261", "PkgName": "vim", + "PkgIdentifier": { + "PURL": "pkg:cbl-mariner/vim@8.2.4081-1.cm1?arch=x86_64" + }, "InstalledVersion": "8.2.4081-1.cm1", "Status": "affected", "Layer": { @@ -74,6 +77,9 @@ { "VulnerabilityID": "CVE-2022-0158", "PkgName": "vim", + "PkgIdentifier": { + "PURL": "pkg:cbl-mariner/vim@8.2.4081-1.cm1?arch=x86_64" + }, "InstalledVersion": "8.2.4081-1.cm1", "FixedVersion": "8.2.4082-1.cm1", "Status": "fixed", diff --git a/integration/testdata/minikube-kbom.json.golden b/integration/testdata/minikube-kbom.json.golden index e144904828e4..5a4ee8ed2949 100644 --- a/integration/testdata/minikube-kbom.json.golden +++ b/integration/testdata/minikube-kbom.json.golden @@ -33,6 +33,9 @@ { "VulnerabilityID": "CVE-2023-2431", "PkgName": "k8s.io/kubelet", + "PkgIdentifier": { + "PURL": "pkg:k8s/k8s.io%2Fkubelet@1.27.0" + }, "InstalledVersion": "1.27.0", "FixedVersion": "1.24.14, 1.25.9, 1.26.4, 1.27.1", "Status": "fixed", diff --git a/integration/testdata/mix.lock.json.golden b/integration/testdata/mix.lock.json.golden index 76eb19ece6a0..54445fbf9cfa 100644 --- a/integration/testdata/mix.lock.json.golden +++ b/integration/testdata/mix.lock.json.golden @@ -24,6 +24,9 @@ { "ID": "castore@0.1.18", "Name": "castore", + "Identifier": { + "PURL": "pkg:hex/castore@0.1.18" + }, "Version": "0.1.18", "Layer": {}, "Locations": [ @@ -36,6 +39,9 @@ { "ID": "jason@1.4.0", "Name": "jason", + "Identifier": { + "PURL": "pkg:hex/jason@1.4.0" + }, "Version": "1.4.0", "Layer": {}, "Locations": [ @@ -48,6 +54,9 @@ { "ID": "phoenix@1.6.13", "Name": "phoenix", + "Identifier": { + "PURL": "pkg:hex/phoenix@1.6.13" + }, "Version": "1.6.13", "Layer": {}, "Locations": [ @@ -60,6 +69,9 @@ { "ID": "phoenix_html@3.2.0", "Name": "phoenix_html", + "Identifier": { + "PURL": "pkg:hex/phoenix_html@3.2.0" + }, "Version": "3.2.0", "Layer": {}, "Locations": [ @@ -72,6 +84,9 @@ { "ID": "phoenix_pubsub@2.1.1", "Name": "phoenix_pubsub", + "Identifier": { + "PURL": "pkg:hex/phoenix_pubsub@2.1.1" + }, "Version": "2.1.1", "Layer": {}, "Locations": [ @@ -84,6 +99,9 @@ { "ID": "phoenix_template@1.0.0", "Name": "phoenix_template", + "Identifier": { + "PURL": "pkg:hex/phoenix_template@1.0.0" + }, "Version": "1.0.0", "Layer": {}, "Locations": [ @@ -96,6 +114,9 @@ { "ID": "phoenix_view@2.0.1", "Name": "phoenix_view", + "Identifier": { + "PURL": "pkg:hex/phoenix_view@2.0.1" + }, "Version": "2.0.1", "Layer": {}, "Locations": [ @@ -108,6 +129,9 @@ { "ID": "plug@1.14.0", "Name": "plug", + "Identifier": { + "PURL": "pkg:hex/plug@1.14.0" + }, "Version": "1.14.0", "Layer": {}, "Locations": [ @@ -120,6 +144,9 @@ { "ID": "plug_crypto@1.2.3", "Name": "plug_crypto", + "Identifier": { + "PURL": "pkg:hex/plug_crypto@1.2.3" + }, "Version": "1.2.3", "Layer": {}, "Locations": [ @@ -132,6 +159,9 @@ { "ID": "telemetry@1.1.0", "Name": "telemetry", + "Identifier": { + "PURL": "pkg:hex/telemetry@1.1.0" + }, "Version": "1.1.0", "Layer": {}, "Locations": [ @@ -147,6 +177,9 @@ "VulnerabilityID": "CVE-2022-42975", "PkgID": "phoenix@1.6.13", "PkgName": "phoenix", + "PkgIdentifier": { + "PURL": "pkg:hex/phoenix@1.6.13" + }, "InstalledVersion": "1.6.13", "FixedVersion": "1.6.14", "Status": "fixed", diff --git a/integration/testdata/npm-with-dev.json.golden b/integration/testdata/npm-with-dev.json.golden index 071bfd18d643..a512e5247910 100644 --- a/integration/testdata/npm-with-dev.json.golden +++ b/integration/testdata/npm-with-dev.json.golden @@ -24,6 +24,9 @@ { "ID": "asap@2.0.6", "Name": "asap", + "Identifier": { + "PURL": "pkg:npm/asap@2.0.6" + }, "Version": "2.0.6", "Indirect": true, "Layer": {}, @@ -37,6 +40,9 @@ { "ID": "jquery@3.3.9", "Name": "jquery", + "Identifier": { + "PURL": "pkg:npm/jquery@3.3.9" + }, "Version": "3.3.9", "Licenses": [ "MIT" @@ -53,6 +59,9 @@ { "ID": "js-tokens@4.0.0", "Name": "js-tokens", + "Identifier": { + "PURL": "pkg:npm/js-tokens@4.0.0" + }, "Version": "4.0.0", "Indirect": true, "Layer": {}, @@ -66,6 +75,9 @@ { "ID": "loose-envify@1.4.0", "Name": "loose-envify", + "Identifier": { + "PURL": "pkg:npm/loose-envify@1.4.0" + }, "Version": "1.4.0", "Indirect": true, "DependsOn": [ @@ -82,6 +94,9 @@ { "ID": "object-assign@4.1.1", "Name": "object-assign", + "Identifier": { + "PURL": "pkg:npm/object-assign@4.1.1" + }, "Version": "4.1.1", "Indirect": true, "Layer": {}, @@ -95,6 +110,9 @@ { "ID": "promise@8.0.3", "Name": "promise", + "Identifier": { + "PURL": "pkg:npm/promise@8.0.3" + }, "Version": "8.0.3", "Licenses": [ "MIT" @@ -114,6 +132,9 @@ { "ID": "prop-types@15.7.2", "Name": "prop-types", + "Identifier": { + "PURL": "pkg:npm/prop-types@15.7.2" + }, "Version": "15.7.2", "Indirect": true, "DependsOn": [ @@ -132,6 +153,9 @@ { "ID": "react@16.8.6", "Name": "react", + "Identifier": { + "PURL": "pkg:npm/react@16.8.6" + }, "Version": "16.8.6", "Licenses": [ "MIT" @@ -154,6 +178,9 @@ { "ID": "react-is@16.8.6", "Name": "react-is", + "Identifier": { + "PURL": "pkg:npm/react-is@16.8.6" + }, "Version": "16.8.6", "Licenses": [ "MIT" @@ -170,6 +197,9 @@ { "ID": "redux@4.0.1", "Name": "redux", + "Identifier": { + "PURL": "pkg:npm/redux@4.0.1" + }, "Version": "4.0.1", "Licenses": [ "MIT" @@ -190,6 +220,9 @@ { "ID": "scheduler@0.13.6", "Name": "scheduler", + "Identifier": { + "PURL": "pkg:npm/scheduler@0.13.6" + }, "Version": "0.13.6", "Indirect": true, "DependsOn": [ @@ -207,6 +240,9 @@ { "ID": "symbol-observable@1.2.0", "Name": "symbol-observable", + "Identifier": { + "PURL": "pkg:npm/symbol-observable@1.2.0" + }, "Version": "1.2.0", "Indirect": true, "Layer": {}, @@ -220,6 +256,9 @@ { "ID": "z-lock@1.0.0", "Name": "z-lock", + "Identifier": { + "PURL": "pkg:npm/z-lock@1.0.0" + }, "Version": "1.0.0", "Dev": true, "Licenses": [ @@ -240,6 +279,9 @@ "VulnerabilityID": "CVE-2019-11358", "PkgID": "jquery@3.3.9", "PkgName": "jquery", + "PkgIdentifier": { + "PURL": "pkg:npm/jquery@3.3.9" + }, "InstalledVersion": "3.3.9", "FixedVersion": "3.4.0", "Status": "fixed", diff --git a/integration/testdata/npm.json.golden b/integration/testdata/npm.json.golden index ec19f9d5975a..9bdb9ae37649 100644 --- a/integration/testdata/npm.json.golden +++ b/integration/testdata/npm.json.golden @@ -24,6 +24,9 @@ { "ID": "asap@2.0.6", "Name": "asap", + "Identifier": { + "PURL": "pkg:npm/asap@2.0.6" + }, "Version": "2.0.6", "Indirect": true, "Layer": {}, @@ -37,6 +40,9 @@ { "ID": "jquery@3.3.9", "Name": "jquery", + "Identifier": { + "PURL": "pkg:npm/jquery@3.3.9" + }, "Version": "3.3.9", "Licenses": [ "MIT" @@ -53,6 +59,9 @@ { "ID": "js-tokens@4.0.0", "Name": "js-tokens", + "Identifier": { + "PURL": "pkg:npm/js-tokens@4.0.0" + }, "Version": "4.0.0", "Indirect": true, "Layer": {}, @@ -66,6 +75,9 @@ { "ID": "loose-envify@1.4.0", "Name": "loose-envify", + "Identifier": { + "PURL": "pkg:npm/loose-envify@1.4.0" + }, "Version": "1.4.0", "Indirect": true, "DependsOn": [ @@ -82,6 +94,9 @@ { "ID": "object-assign@4.1.1", "Name": "object-assign", + "Identifier": { + "PURL": "pkg:npm/object-assign@4.1.1" + }, "Version": "4.1.1", "Indirect": true, "Layer": {}, @@ -95,6 +110,9 @@ { "ID": "promise@8.0.3", "Name": "promise", + "Identifier": { + "PURL": "pkg:npm/promise@8.0.3" + }, "Version": "8.0.3", "Licenses": [ "MIT" @@ -114,6 +132,9 @@ { "ID": "prop-types@15.7.2", "Name": "prop-types", + "Identifier": { + "PURL": "pkg:npm/prop-types@15.7.2" + }, "Version": "15.7.2", "Indirect": true, "DependsOn": [ @@ -132,6 +153,9 @@ { "ID": "react@16.8.6", "Name": "react", + "Identifier": { + "PURL": "pkg:npm/react@16.8.6" + }, "Version": "16.8.6", "Licenses": [ "MIT" @@ -154,6 +178,9 @@ { "ID": "react-is@16.8.6", "Name": "react-is", + "Identifier": { + "PURL": "pkg:npm/react-is@16.8.6" + }, "Version": "16.8.6", "Licenses": [ "MIT" @@ -170,6 +197,9 @@ { "ID": "redux@4.0.1", "Name": "redux", + "Identifier": { + "PURL": "pkg:npm/redux@4.0.1" + }, "Version": "4.0.1", "Licenses": [ "MIT" @@ -190,6 +220,9 @@ { "ID": "scheduler@0.13.6", "Name": "scheduler", + "Identifier": { + "PURL": "pkg:npm/scheduler@0.13.6" + }, "Version": "0.13.6", "Indirect": true, "DependsOn": [ @@ -207,6 +240,9 @@ { "ID": "symbol-observable@1.2.0", "Name": "symbol-observable", + "Identifier": { + "PURL": "pkg:npm/symbol-observable@1.2.0" + }, "Version": "1.2.0", "Indirect": true, "Layer": {}, @@ -223,6 +259,9 @@ "VulnerabilityID": "CVE-2019-11358", "PkgID": "jquery@3.3.9", "PkgName": "jquery", + "PkgIdentifier": { + "PURL": "pkg:npm/jquery@3.3.9" + }, "InstalledVersion": "3.3.9", "FixedVersion": "3.4.0", "Status": "fixed", diff --git a/integration/testdata/nuget.json.golden b/integration/testdata/nuget.json.golden index 5027f75894b4..064fb1e32d2f 100644 --- a/integration/testdata/nuget.json.golden +++ b/integration/testdata/nuget.json.golden @@ -24,6 +24,9 @@ { "ID": "Newtonsoft.Json@12.0.3", "Name": "Newtonsoft.Json", + "Identifier": { + "PURL": "pkg:nuget/Newtonsoft.Json@12.0.3" + }, "Version": "12.0.3", "Layer": {}, "Locations": [ @@ -36,6 +39,9 @@ { "ID": "NuGet.Frameworks@5.7.0", "Name": "NuGet.Frameworks", + "Identifier": { + "PURL": "pkg:nuget/NuGet.Frameworks@5.7.0" + }, "Version": "5.7.0", "DependsOn": [ "Newtonsoft.Json@12.0.3" @@ -54,6 +60,9 @@ "VulnerabilityID": "GHSA-5crp-9r3c-p9vr", "PkgID": "Newtonsoft.Json@12.0.3", "PkgName": "Newtonsoft.Json", + "PkgIdentifier": { + "PURL": "pkg:nuget/Newtonsoft.Json@12.0.3" + }, "InstalledVersion": "12.0.3", "FixedVersion": "13.0.1", "Status": "fixed", diff --git a/integration/testdata/opensuse-leap-151.json.golden b/integration/testdata/opensuse-leap-151.json.golden index ed0c29a6d890..9ca650d3dbb3 100644 --- a/integration/testdata/opensuse-leap-151.json.golden +++ b/integration/testdata/opensuse-leap-151.json.golden @@ -65,6 +65,9 @@ "VulnerabilityID": "openSUSE-SU-2020:0062-1", "PkgID": "libopenssl1_1@1.1.0i-lp151.8.3.1.x86_64", "PkgName": "libopenssl1_1", + "PkgIdentifier": { + "PURL": "pkg:rpm/opensuse.leap/libopenssl1_1@1.1.0i-lp151.8.3.1?arch=x86_64\u0026distro=opensuse.leap-15.1" + }, "InstalledVersion": "1.1.0i-lp151.8.3.1", "FixedVersion": "1.1.0i-lp151.8.6.1", "Status": "fixed", @@ -94,6 +97,9 @@ "VulnerabilityID": "openSUSE-SU-2020:0062-1", "PkgID": "openssl-1_1@1.1.0i-lp151.8.3.1.x86_64", "PkgName": "openssl-1_1", + "PkgIdentifier": { + "PURL": "pkg:rpm/opensuse.leap/openssl-1_1@1.1.0i-lp151.8.3.1?arch=x86_64\u0026distro=opensuse.leap-15.1" + }, "InstalledVersion": "1.1.0i-lp151.8.3.1", "FixedVersion": "1.1.0i-lp151.8.6.1", "Status": "fixed", diff --git a/integration/testdata/oraclelinux-8.json.golden b/integration/testdata/oraclelinux-8.json.golden index b00634c1079f..6629e7fe0e55 100644 --- a/integration/testdata/oraclelinux-8.json.golden +++ b/integration/testdata/oraclelinux-8.json.golden @@ -66,6 +66,9 @@ "VulnerabilityID": "CVE-2019-3823", "PkgID": "curl@7.61.1-8.el8.x86_64", "PkgName": "curl", + "PkgIdentifier": { + "PURL": "pkg:rpm/oracle/curl@7.61.1-8.el8?arch=x86_64\u0026distro=oracle-8.0" + }, "InstalledVersion": "7.61.1-8.el8", "FixedVersion": "7.61.1-11.el8", "Status": "fixed", @@ -133,6 +136,9 @@ "VulnerabilityID": "CVE-2019-5436", "PkgID": "curl@7.61.1-8.el8.x86_64", "PkgName": "curl", + "PkgIdentifier": { + "PURL": "pkg:rpm/oracle/curl@7.61.1-8.el8?arch=x86_64\u0026distro=oracle-8.0" + }, "InstalledVersion": "7.61.1-8.el8", "FixedVersion": "7.61.1-12.el8", "Status": "fixed", diff --git a/integration/testdata/packagesprops.json.golden b/integration/testdata/packagesprops.json.golden index 77a6cb03c51e..5cce23a7c754 100644 --- a/integration/testdata/packagesprops.json.golden +++ b/integration/testdata/packagesprops.json.golden @@ -24,6 +24,9 @@ { "ID": "Newtonsoft.Json@9.0.1", "Name": "Newtonsoft.Json", + "Identifier": { + "PURL": "pkg:nuget/Newtonsoft.Json@9.0.1" + }, "Version": "9.0.1", "Layer": {} } @@ -33,6 +36,9 @@ "VulnerabilityID": "GHSA-5crp-9r3c-p9vr", "PkgID": "Newtonsoft.Json@9.0.1", "PkgName": "Newtonsoft.Json", + "PkgIdentifier": { + "PURL": "pkg:nuget/Newtonsoft.Json@9.0.1" + }, "InstalledVersion": "9.0.1", "FixedVersion": "13.0.1", "Status": "fixed", diff --git a/integration/testdata/photon-30.json.golden b/integration/testdata/photon-30.json.golden index 5a97889fd3d6..4e4c8d793faa 100644 --- a/integration/testdata/photon-30.json.golden +++ b/integration/testdata/photon-30.json.golden @@ -67,6 +67,9 @@ "VulnerabilityID": "CVE-2019-18276", "PkgID": "bash@4.4.18-1.ph3.x86_64", "PkgName": "bash", + "PkgIdentifier": { + "PURL": "pkg:rpm/photon/bash@4.4.18-1.ph3?arch=x86_64\u0026distro=photon-3.0" + }, "InstalledVersion": "4.4.18-1.ph3", "FixedVersion": "4.4.18-2.ph3", "Status": "fixed", @@ -127,6 +130,9 @@ "VulnerabilityID": "CVE-2019-5481", "PkgID": "curl@7.61.1-4.ph3.x86_64", "PkgName": "curl", + "PkgIdentifier": { + "PURL": "pkg:rpm/photon/curl@7.61.1-4.ph3?arch=x86_64\u0026distro=photon-3.0" + }, "InstalledVersion": "7.61.1-4.ph3", "FixedVersion": "7.61.1-5.ph3", "Status": "fixed", @@ -195,6 +201,9 @@ "VulnerabilityID": "CVE-2019-5481", "PkgID": "curl-libs@7.61.1-4.ph3.x86_64", "PkgName": "curl-libs", + "PkgIdentifier": { + "PURL": "pkg:rpm/photon/curl-libs@7.61.1-4.ph3?arch=x86_64\u0026distro=photon-3.0" + }, "InstalledVersion": "7.61.1-4.ph3", "FixedVersion": "7.61.1-5.ph3", "Status": "fixed", diff --git a/integration/testdata/pip.json.golden b/integration/testdata/pip.json.golden index 60590d12ea05..29873d943d55 100644 --- a/integration/testdata/pip.json.golden +++ b/integration/testdata/pip.json.golden @@ -23,36 +23,57 @@ "Packages": [ { "Name": "Flask", + "Identifier": { + "PURL": "pkg:pypi/flask@2.0.0" + }, "Version": "2.0.0", "Layer": {} }, { "Name": "Jinja2", + "Identifier": { + "PURL": "pkg:pypi/jinja2@3.0.0" + }, "Version": "3.0.0", "Layer": {} }, { "Name": "Werkzeug", + "Identifier": { + "PURL": "pkg:pypi/werkzeug@0.11" + }, "Version": "0.11", "Layer": {} }, { "Name": "click", + "Identifier": { + "PURL": "pkg:pypi/click@8.0.0" + }, "Version": "8.0.0", "Layer": {} }, { "Name": "itsdangerous", + "Identifier": { + "PURL": "pkg:pypi/itsdangerous@2.0.0" + }, "Version": "2.0.0", "Layer": {} }, { "Name": "oauth2-client", + "Identifier": { + "PURL": "pkg:pypi/oauth2-client@4.0.0" + }, "Version": "4.0.0", "Layer": {} }, { "Name": "python-gitlab", + "Identifier": { + "PURL": "pkg:pypi/python-gitlab@2.0.0" + }, "Version": "2.0.0", "Layer": {} } @@ -61,6 +82,9 @@ { "VulnerabilityID": "CVE-2019-14806", "PkgName": "Werkzeug", + "PkgIdentifier": { + "PURL": "pkg:pypi/werkzeug@0.11" + }, "InstalledVersion": "0.11", "FixedVersion": "0.15.3", "Status": "fixed", @@ -114,6 +138,9 @@ { "VulnerabilityID": "CVE-2020-28724", "PkgName": "Werkzeug", + "PkgIdentifier": { + "PURL": "pkg:pypi/werkzeug@0.11" + }, "InstalledVersion": "0.11", "FixedVersion": "0.11.6", "Status": "fixed", diff --git a/integration/testdata/pipenv.json.golden b/integration/testdata/pipenv.json.golden index f77722278843..e5076aa4571b 100644 --- a/integration/testdata/pipenv.json.golden +++ b/integration/testdata/pipenv.json.golden @@ -23,6 +23,9 @@ "Packages": [ { "Name": "werkzeug", + "Identifier": { + "PURL": "pkg:pypi/werkzeug@0.11.1" + }, "Version": "0.11.1", "Layer": {}, "Locations": [ @@ -37,6 +40,9 @@ { "VulnerabilityID": "CVE-2019-14806", "PkgName": "werkzeug", + "PkgIdentifier": { + "PURL": "pkg:pypi/werkzeug@0.11.1" + }, "InstalledVersion": "0.11.1", "FixedVersion": "0.15.3", "Status": "fixed", @@ -90,6 +96,9 @@ { "VulnerabilityID": "CVE-2020-28724", "PkgName": "werkzeug", + "PkgIdentifier": { + "PURL": "pkg:pypi/werkzeug@0.11.1" + }, "InstalledVersion": "0.11.1", "FixedVersion": "0.11.6", "Status": "fixed", diff --git a/integration/testdata/pnpm.json.golden b/integration/testdata/pnpm.json.golden index 2f69244be160..305552bf1f2a 100644 --- a/integration/testdata/pnpm.json.golden +++ b/integration/testdata/pnpm.json.golden @@ -25,6 +25,9 @@ "VulnerabilityID": "CVE-2019-11358", "PkgID": "jquery@3.3.9", "PkgName": "jquery", + "PkgIdentifier": { + "PURL": "pkg:npm/jquery@3.3.9" + }, "InstalledVersion": "3.3.9", "FixedVersion": "3.4.0", "Status": "fixed", @@ -154,6 +157,9 @@ "VulnerabilityID": "CVE-2019-10744", "PkgID": "lodash@4.17.4", "PkgName": "lodash", + "PkgIdentifier": { + "PURL": "pkg:npm/lodash@4.17.4" + }, "InstalledVersion": "4.17.4", "FixedVersion": "4.17.12", "Status": "fixed", diff --git a/integration/testdata/poetry.json.golden b/integration/testdata/poetry.json.golden index 26f4085bf95b..394977d3ea02 100644 --- a/integration/testdata/poetry.json.golden +++ b/integration/testdata/poetry.json.golden @@ -24,6 +24,9 @@ { "ID": "click@8.1.3", "Name": "click", + "Identifier": { + "PURL": "pkg:pypi/click@8.1.3" + }, "Version": "8.1.3", "DependsOn": [ "colorama@0.4.6" @@ -33,6 +36,9 @@ { "ID": "colorama@0.4.6", "Name": "colorama", + "Identifier": { + "PURL": "pkg:pypi/colorama@0.4.6" + }, "Version": "0.4.6", "Indirect": true, "Layer": {} @@ -40,6 +46,9 @@ { "ID": "werkzeug@0.14", "Name": "werkzeug", + "Identifier": { + "PURL": "pkg:pypi/werkzeug@0.14" + }, "Version": "0.14", "Layer": {} } @@ -49,6 +58,9 @@ "VulnerabilityID": "CVE-2019-14806", "PkgID": "werkzeug@0.14", "PkgName": "werkzeug", + "PkgIdentifier": { + "PURL": "pkg:pypi/werkzeug@0.14" + }, "InstalledVersion": "0.14", "FixedVersion": "0.15.3", "Status": "fixed", diff --git a/integration/testdata/pom-cyclonedx.json.golden b/integration/testdata/pom-cyclonedx.json.golden index b5e7f17e14f3..ac245de144ce 100644 --- a/integration/testdata/pom-cyclonedx.json.golden +++ b/integration/testdata/pom-cyclonedx.json.golden @@ -103,35 +103,35 @@ ], "vulnerabilities": [ { - "id": "CVE-2021-20190", + "id": "CVE-2020-9548", "source": { - "name": "glad", - "url": "https://gitlab.com/gitlab-org/advisories-community" + "name": "ghsa", + "url": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Amaven" }, "ratings": [ { "source": { "name": "ghsa" }, - "severity": "high" + "severity": "critical" }, { "source": { "name": "nvd" }, - "score": 8.3, - "severity": "high", + "score": 6.8, + "severity": "medium", "method": "CVSSv2", - "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:C" + "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:P" }, { "source": { "name": "nvd" }, - "score": 8.1, - "severity": "high", + "score": 9.8, + "severity": "critical", "method": "CVSSv31", - "vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H" + "vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" }, { "source": { @@ -146,42 +146,72 @@ "cwes": [ 502 ], - "description": "A flaw was found in jackson-databind before 2.9.10.7. FasterXML mishandles the interaction between serialization gadgets and typing. The highest threat from this vulnerability is to data confidentiality and integrity as well as system availability.", - "recommendation": "Upgrade com.fasterxml.jackson.core:jackson-databind to version 2.9.10.7", + "description": "FasterXML jackson-databind 2.x before 2.9.10.4 mishandles the interaction between serialization gadgets and typing, related to br.com.anteros.dbcp.AnterosDBCPConfig (aka anteros-core).", + "recommendation": "Upgrade com.fasterxml.jackson.core:jackson-databind to version 2.9.10.4", "advisories": [ { - "url": "https://avd.aquasec.com/nvd/cve-2021-20190" + "url": "https://avd.aquasec.com/nvd/cve-2020-9548" }, { - "url": "https://access.redhat.com/security/cve/CVE-2021-20190" + "url": "https://access.redhat.com/security/cve/CVE-2020-9548" }, { - "url": "https://bugzilla.redhat.com/show_bug.cgi?id=1916633" + "url": "https://github.com/FasterXML/jackson-databind/issues/2634" }, { - "url": "https://github.com/FasterXML/jackson-databind/commit/7dbf51bf78d157098074a20bd9da39bd48c18e4a" + "url": "https://github.com/advisories/GHSA-p43x-xfjf-5jhr" }, { - "url": "https://github.com/FasterXML/jackson-databind/issues/2854" + "url": "https://lists.apache.org/thread.html/r35d30db00440ef63b791c4b7f7acb036e14d4a23afa2a249cb66c0fd@%3Cissues.zookeeper.apache.org%3E" }, { - "url": "https://github.com/advisories/GHSA-5949-rw7g-wx7w" + "url": "https://lists.apache.org/thread.html/r9464a40d25c3ba1a55622db72f113eb494a889656962d098c70c5bb1@%3Cdev.zookeeper.apache.org%3E" }, { - "url": "https://lists.apache.org/thread.html/r380e9257bacb8551ee6fcf2c59890ae9477b2c78e553fa9ea08e9d9a@%3Ccommits.nifi.apache.org%3E" + "url": "https://lists.apache.org/thread.html/r98c9b6e4c9e17792e2cd1ec3e4aa20b61a791939046d3f10888176bb@%3Cissues.zookeeper.apache.org%3E" }, { - "url": "https://lists.debian.org/debian-lts-announce/2021/04/msg00025.html" + "url": "https://lists.apache.org/thread.html/rb6fecb5e96a6d61e175ff49f33f2713798dd05cf03067c169d195596@%3Cissues.zookeeper.apache.org%3E" }, { - "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-20190" + "url": "https://lists.apache.org/thread.html/rd5a4457be4623038c3989294429bc063eec433a2e55995d81591e2ca@%3Cissues.zookeeper.apache.org%3E" }, { - "url": "https://security.netapp.com/advisory/ntap-20210219-0008/" + "url": "https://lists.apache.org/thread.html/rdd49ab9565bec436a896bc00c4b9fc9dce1598e106c318524fbdfec6@%3Cissues.zookeeper.apache.org%3E" + }, + { + "url": "https://lists.apache.org/thread.html/rdd4df698d5d8e635144d2994922bf0842e933809eae259521f3b5097@%3Cissues.zookeeper.apache.org%3E" + }, + { + "url": "https://lists.apache.org/thread.html/rf1bbc0ea4a9f014cf94df9a12a6477d24a27f52741dbc87f2fd52ff2@%3Cissues.geode.apache.org%3E" + }, + { + "url": "https://lists.debian.org/debian-lts-announce/2020/03/msg00008.html" + }, + { + "url": "https://medium.com/@cowtowncoder/on-jackson-cves-dont-panic-here-is-what-you-need-to-know-54cd0d6e8062" + }, + { + "url": "https://nvd.nist.gov/vuln/detail/CVE-2020-9548" + }, + { + "url": "https://security.netapp.com/advisory/ntap-20200904-0006/" + }, + { + "url": "https://www.oracle.com/security-alerts/cpujan2021.html" + }, + { + "url": "https://www.oracle.com/security-alerts/cpujul2020.html" + }, + { + "url": "https://www.oracle.com/security-alerts/cpuoct2020.html" + }, + { + "url": "https://www.oracle.com/security-alerts/cpuoct2021.html" } ], - "published": "2021-01-19T17:15:00+00:00", - "updated": "2021-07-20T23:15:00+00:00", + "published": "2020-03-02T04:15:00+00:00", + "updated": "2021-12-02T21:23:00+00:00", "affects": [ { "ref": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.1", @@ -195,35 +225,35 @@ ] }, { - "id": "CVE-2020-9548", + "id": "CVE-2021-20190", "source": { - "name": "ghsa", - "url": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Amaven" + "name": "glad", + "url": "https://gitlab.com/gitlab-org/advisories-community" }, "ratings": [ { "source": { "name": "ghsa" }, - "severity": "critical" + "severity": "high" }, { "source": { "name": "nvd" }, - "score": 6.8, - "severity": "medium", + "score": 8.3, + "severity": "high", "method": "CVSSv2", - "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:P" + "vector": "AV:N/AC:M/Au:N/C:P/I:P/A:C" }, { "source": { "name": "nvd" }, - "score": 9.8, - "severity": "critical", + "score": 8.1, + "severity": "high", "method": "CVSSv31", - "vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + "vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H" }, { "source": { @@ -238,72 +268,42 @@ "cwes": [ 502 ], - "description": "FasterXML jackson-databind 2.x before 2.9.10.4 mishandles the interaction between serialization gadgets and typing, related to br.com.anteros.dbcp.AnterosDBCPConfig (aka anteros-core).", - "recommendation": "Upgrade com.fasterxml.jackson.core:jackson-databind to version 2.9.10.4", + "description": "A flaw was found in jackson-databind before 2.9.10.7. FasterXML mishandles the interaction between serialization gadgets and typing. The highest threat from this vulnerability is to data confidentiality and integrity as well as system availability.", + "recommendation": "Upgrade com.fasterxml.jackson.core:jackson-databind to version 2.9.10.7", "advisories": [ { - "url": "https://avd.aquasec.com/nvd/cve-2020-9548" - }, - { - "url": "https://access.redhat.com/security/cve/CVE-2020-9548" - }, - { - "url": "https://github.com/FasterXML/jackson-databind/issues/2634" - }, - { - "url": "https://github.com/advisories/GHSA-p43x-xfjf-5jhr" - }, - { - "url": "https://lists.apache.org/thread.html/r35d30db00440ef63b791c4b7f7acb036e14d4a23afa2a249cb66c0fd@%3Cissues.zookeeper.apache.org%3E" - }, - { - "url": "https://lists.apache.org/thread.html/r9464a40d25c3ba1a55622db72f113eb494a889656962d098c70c5bb1@%3Cdev.zookeeper.apache.org%3E" - }, - { - "url": "https://lists.apache.org/thread.html/r98c9b6e4c9e17792e2cd1ec3e4aa20b61a791939046d3f10888176bb@%3Cissues.zookeeper.apache.org%3E" - }, - { - "url": "https://lists.apache.org/thread.html/rb6fecb5e96a6d61e175ff49f33f2713798dd05cf03067c169d195596@%3Cissues.zookeeper.apache.org%3E" - }, - { - "url": "https://lists.apache.org/thread.html/rd5a4457be4623038c3989294429bc063eec433a2e55995d81591e2ca@%3Cissues.zookeeper.apache.org%3E" - }, - { - "url": "https://lists.apache.org/thread.html/rdd49ab9565bec436a896bc00c4b9fc9dce1598e106c318524fbdfec6@%3Cissues.zookeeper.apache.org%3E" - }, - { - "url": "https://lists.apache.org/thread.html/rdd4df698d5d8e635144d2994922bf0842e933809eae259521f3b5097@%3Cissues.zookeeper.apache.org%3E" + "url": "https://avd.aquasec.com/nvd/cve-2021-20190" }, { - "url": "https://lists.apache.org/thread.html/rf1bbc0ea4a9f014cf94df9a12a6477d24a27f52741dbc87f2fd52ff2@%3Cissues.geode.apache.org%3E" + "url": "https://access.redhat.com/security/cve/CVE-2021-20190" }, { - "url": "https://lists.debian.org/debian-lts-announce/2020/03/msg00008.html" + "url": "https://bugzilla.redhat.com/show_bug.cgi?id=1916633" }, { - "url": "https://medium.com/@cowtowncoder/on-jackson-cves-dont-panic-here-is-what-you-need-to-know-54cd0d6e8062" + "url": "https://github.com/FasterXML/jackson-databind/commit/7dbf51bf78d157098074a20bd9da39bd48c18e4a" }, { - "url": "https://nvd.nist.gov/vuln/detail/CVE-2020-9548" + "url": "https://github.com/FasterXML/jackson-databind/issues/2854" }, { - "url": "https://security.netapp.com/advisory/ntap-20200904-0006/" + "url": "https://github.com/advisories/GHSA-5949-rw7g-wx7w" }, { - "url": "https://www.oracle.com/security-alerts/cpujan2021.html" + "url": "https://lists.apache.org/thread.html/r380e9257bacb8551ee6fcf2c59890ae9477b2c78e553fa9ea08e9d9a@%3Ccommits.nifi.apache.org%3E" }, { - "url": "https://www.oracle.com/security-alerts/cpujul2020.html" + "url": "https://lists.debian.org/debian-lts-announce/2021/04/msg00025.html" }, { - "url": "https://www.oracle.com/security-alerts/cpuoct2020.html" + "url": "https://nvd.nist.gov/vuln/detail/CVE-2021-20190" }, { - "url": "https://www.oracle.com/security-alerts/cpuoct2021.html" + "url": "https://security.netapp.com/advisory/ntap-20210219-0008/" } ], - "published": "2020-03-02T04:15:00+00:00", - "updated": "2021-12-02T21:23:00+00:00", + "published": "2021-01-19T17:15:00+00:00", + "updated": "2021-07-20T23:15:00+00:00", "affects": [ { "ref": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.1", diff --git a/integration/testdata/pom.json.golden b/integration/testdata/pom.json.golden index bf8d69f4125c..244817f1e4c7 100644 --- a/integration/testdata/pom.json.golden +++ b/integration/testdata/pom.json.golden @@ -25,6 +25,9 @@ "VulnerabilityID": "CVE-2020-9548", "PkgID": "com.fasterxml.jackson.core:jackson-databind:2.9.1", "PkgName": "com.fasterxml.jackson.core:jackson-databind", + "PkgIdentifier": { + "PURL": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.1" + }, "InstalledVersion": "2.9.1", "FixedVersion": "2.9.10.4", "Status": "fixed", @@ -87,6 +90,9 @@ "VulnerabilityID": "CVE-2021-20190", "PkgID": "com.fasterxml.jackson.core:jackson-databind:2.9.1", "PkgName": "com.fasterxml.jackson.core:jackson-databind", + "PkgIdentifier": { + "PURL": "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.9.1" + }, "InstalledVersion": "2.9.1", "FixedVersion": "2.9.10.7", "Status": "fixed", diff --git a/integration/testdata/pubspec.lock.json.golden b/integration/testdata/pubspec.lock.json.golden index a7e76e3153b8..7a101cd02eca 100644 --- a/integration/testdata/pubspec.lock.json.golden +++ b/integration/testdata/pubspec.lock.json.golden @@ -24,12 +24,18 @@ { "ID": "http@0.13.2", "Name": "http", + "Identifier": { + "PURL": "pkg:pub/http@0.13.2" + }, "Version": "0.13.2", "Layer": {} }, { "ID": "shelf@1.3.1", "Name": "shelf", + "Identifier": { + "PURL": "pkg:pub/shelf@1.3.1" + }, "Version": "1.3.1", "Indirect": true, "Layer": {} @@ -40,6 +46,9 @@ "VulnerabilityID": "CVE-2020-35669", "PkgID": "http@0.13.2", "PkgName": "http", + "PkgIdentifier": { + "PURL": "pkg:pub/http@0.13.2" + }, "InstalledVersion": "0.13.2", "FixedVersion": "0.13.3", "Status": "fixed", diff --git a/integration/testdata/rockylinux-8.json.golden b/integration/testdata/rockylinux-8.json.golden index c47d69455875..6d8b3b7a29a8 100644 --- a/integration/testdata/rockylinux-8.json.golden +++ b/integration/testdata/rockylinux-8.json.golden @@ -56,6 +56,9 @@ "VulnerabilityID": "CVE-2021-3712", "PkgID": "openssl-libs@1.1.1k-4.el8.x86_64", "PkgName": "openssl-libs", + "PkgIdentifier": { + "PURL": "pkg:rpm/rocky/openssl-libs@1.1.1k-4.el8?arch=x86_64\u0026distro=rocky-8.5\u0026epoch=1" + }, "InstalledVersion": "1:1.1.1k-4.el8", "FixedVersion": "1:1.1.1k-5.el8_5", "Status": "fixed", diff --git a/integration/testdata/spring4shell-jre11.json.golden b/integration/testdata/spring4shell-jre11.json.golden index b6ad22e931dd..7db6bae72bfa 100644 --- a/integration/testdata/spring4shell-jre11.json.golden +++ b/integration/testdata/spring4shell-jre11.json.golden @@ -198,6 +198,9 @@ "VulnerabilityID": "CVE-2022-22965", "PkgName": "org.springframework:spring-beans", "PkgPath": "usr/local/tomcat/webapps/helloworld.war/WEB-INF/lib/spring-beans-5.3.15.jar", + "PkgIdentifier": { + "PURL": "pkg:maven/org.springframework/spring-beans@5.3.15" + }, "InstalledVersion": "5.3.15", "FixedVersion": "5.3.18", "Status": "fixed", diff --git a/integration/testdata/spring4shell-jre8.json.golden b/integration/testdata/spring4shell-jre8.json.golden index f894c07d659c..e1a0e9ee0457 100644 --- a/integration/testdata/spring4shell-jre8.json.golden +++ b/integration/testdata/spring4shell-jre8.json.golden @@ -198,6 +198,9 @@ "VulnerabilityID": "CVE-2022-22965", "PkgName": "org.springframework:spring-beans", "PkgPath": "usr/local/tomcat/webapps/helloworld.war/WEB-INF/lib/spring-beans-5.3.15.jar", + "PkgIdentifier": { + "PURL": "pkg:maven/org.springframework/spring-beans@5.3.15" + }, "InstalledVersion": "5.3.15", "FixedVersion": "5.3.18", "Status": "fixed", diff --git a/integration/testdata/swift.json.golden b/integration/testdata/swift.json.golden index 47d1d2850470..0a9d1ebffb21 100644 --- a/integration/testdata/swift.json.golden +++ b/integration/testdata/swift.json.golden @@ -24,6 +24,9 @@ { "ID": "github.com/apple/swift-atomics@1.1.0", "Name": "github.com/apple/swift-atomics", + "Identifier": { + "PURL": "pkg:swift/github.com/apple/swift-atomics@1.1.0" + }, "Version": "1.1.0", "Layer": {}, "Locations": [ @@ -36,6 +39,9 @@ { "ID": "github.com/apple/swift-nio@2.41.0", "Name": "github.com/apple/swift-nio", + "Identifier": { + "PURL": "pkg:swift/github.com/apple/swift-nio@2.41.0" + }, "Version": "2.41.0", "Layer": {}, "Locations": [ @@ -51,6 +57,9 @@ "VulnerabilityID": "CVE-2022-3215", "PkgID": "github.com/apple/swift-nio@2.41.0", "PkgName": "github.com/apple/swift-nio", + "PkgIdentifier": { + "PURL": "pkg:swift/github.com/apple/swift-nio@2.41.0" + }, "InstalledVersion": "2.41.0", "FixedVersion": "2.29.1, 2.39.1, 2.42.0", "Status": "fixed", diff --git a/integration/testdata/test-repo.json.golden b/integration/testdata/test-repo.json.golden index b98f0e94f0d1..e1ebd91418f7 100644 --- a/integration/testdata/test-repo.json.golden +++ b/integration/testdata/test-repo.json.golden @@ -25,6 +25,9 @@ "VulnerabilityID": "CVE-2019-15542", "PkgID": "ammonia@1.9.0", "PkgName": "ammonia", + "PkgIdentifier": { + "PURL": "pkg:cargo/ammonia@1.9.0" + }, "InstalledVersion": "1.9.0", "FixedVersion": "\u003e= 2.1.0", "Status": "fixed", @@ -64,6 +67,9 @@ "VulnerabilityID": "CVE-2021-38193", "PkgID": "ammonia@1.9.0", "PkgName": "ammonia", + "PkgIdentifier": { + "PURL": "pkg:cargo/ammonia@1.9.0" + }, "InstalledVersion": "1.9.0", "FixedVersion": "\u003e= 3.1.0, \u003e= 2.1.3, \u003c 3.0.0", "Status": "fixed", diff --git a/integration/testdata/ubi-7.json.golden b/integration/testdata/ubi-7.json.golden index 2b382d42ed04..36062495c5a9 100644 --- a/integration/testdata/ubi-7.json.golden +++ b/integration/testdata/ubi-7.json.golden @@ -80,6 +80,9 @@ "VulnerabilityID": "CVE-2019-18276", "PkgID": "bash@4.2.46-33.el7.x86_64", "PkgName": "bash", + "PkgIdentifier": { + "PURL": "pkg:rpm/redhat/bash@4.2.46-33.el7?arch=x86_64\u0026distro=redhat-7.7" + }, "InstalledVersion": "4.2.46-33.el7", "Status": "will_not_fix", "Layer": { diff --git a/integration/testdata/ubuntu-1804-ignore-unfixed.json.golden b/integration/testdata/ubuntu-1804-ignore-unfixed.json.golden index 8020b35f5982..fbc7dafbdbb7 100644 --- a/integration/testdata/ubuntu-1804-ignore-unfixed.json.golden +++ b/integration/testdata/ubuntu-1804-ignore-unfixed.json.golden @@ -76,6 +76,9 @@ "VulnerabilityID": "CVE-2019-5094", "PkgID": "e2fsprogs@1.44.1-1ubuntu1.1", "PkgName": "e2fsprogs", + "PkgIdentifier": { + "PURL": "pkg:deb/ubuntu/e2fsprogs@1.44.1-1ubuntu1.1?arch=amd64\u0026distro=ubuntu-18.04" + }, "InstalledVersion": "1.44.1-1ubuntu1.1", "FixedVersion": "1.44.1-1ubuntu1.2", "Status": "fixed", @@ -143,6 +146,9 @@ "VulnerabilityID": "CVE-2019-5094", "PkgID": "libcom-err2@1.44.1-1ubuntu1.1", "PkgName": "libcom-err2", + "PkgIdentifier": { + "PURL": "pkg:deb/ubuntu/libcom-err2@1.44.1-1ubuntu1.1?arch=amd64\u0026distro=ubuntu-18.04" + }, "InstalledVersion": "1.44.1-1ubuntu1.1", "FixedVersion": "1.44.1-1ubuntu1.2", "Status": "fixed", @@ -210,6 +216,9 @@ "VulnerabilityID": "CVE-2019-5094", "PkgID": "libext2fs2@1.44.1-1ubuntu1.1", "PkgName": "libext2fs2", + "PkgIdentifier": { + "PURL": "pkg:deb/ubuntu/libext2fs2@1.44.1-1ubuntu1.1?arch=amd64\u0026distro=ubuntu-18.04" + }, "InstalledVersion": "1.44.1-1ubuntu1.1", "FixedVersion": "1.44.1-1ubuntu1.2", "Status": "fixed", @@ -277,6 +286,9 @@ "VulnerabilityID": "CVE-2019-5094", "PkgID": "libss2@1.44.1-1ubuntu1.1", "PkgName": "libss2", + "PkgIdentifier": { + "PURL": "pkg:deb/ubuntu/libss2@1.44.1-1ubuntu1.1?arch=amd64\u0026distro=ubuntu-18.04" + }, "InstalledVersion": "1.44.1-1ubuntu1.1", "FixedVersion": "1.44.1-1ubuntu1.2", "Status": "fixed", diff --git a/integration/testdata/ubuntu-1804.json.golden b/integration/testdata/ubuntu-1804.json.golden index bbca0359b3f5..93abad738729 100644 --- a/integration/testdata/ubuntu-1804.json.golden +++ b/integration/testdata/ubuntu-1804.json.golden @@ -76,6 +76,9 @@ "VulnerabilityID": "CVE-2019-18276", "PkgID": "bash@4.4.18-2ubuntu1.2", "PkgName": "bash", + "PkgIdentifier": { + "PURL": "pkg:deb/ubuntu/bash@4.4.18-2ubuntu1.2?arch=amd64\u0026distro=ubuntu-18.04" + }, "InstalledVersion": "4.4.18-2ubuntu1.2", "Status": "affected", "Layer": { @@ -135,6 +138,9 @@ "VulnerabilityID": "CVE-2019-5094", "PkgID": "e2fsprogs@1.44.1-1ubuntu1.1", "PkgName": "e2fsprogs", + "PkgIdentifier": { + "PURL": "pkg:deb/ubuntu/e2fsprogs@1.44.1-1ubuntu1.1?arch=amd64\u0026distro=ubuntu-18.04" + }, "InstalledVersion": "1.44.1-1ubuntu1.1", "FixedVersion": "1.44.1-1ubuntu1.2", "Status": "fixed", @@ -202,6 +208,9 @@ "VulnerabilityID": "CVE-2019-5094", "PkgID": "libcom-err2@1.44.1-1ubuntu1.1", "PkgName": "libcom-err2", + "PkgIdentifier": { + "PURL": "pkg:deb/ubuntu/libcom-err2@1.44.1-1ubuntu1.1?arch=amd64\u0026distro=ubuntu-18.04" + }, "InstalledVersion": "1.44.1-1ubuntu1.1", "FixedVersion": "1.44.1-1ubuntu1.2", "Status": "fixed", @@ -269,6 +278,9 @@ "VulnerabilityID": "CVE-2019-5094", "PkgID": "libext2fs2@1.44.1-1ubuntu1.1", "PkgName": "libext2fs2", + "PkgIdentifier": { + "PURL": "pkg:deb/ubuntu/libext2fs2@1.44.1-1ubuntu1.1?arch=amd64\u0026distro=ubuntu-18.04" + }, "InstalledVersion": "1.44.1-1ubuntu1.1", "FixedVersion": "1.44.1-1ubuntu1.2", "Status": "fixed", @@ -336,6 +348,9 @@ "VulnerabilityID": "CVE-2019-5094", "PkgID": "libss2@1.44.1-1ubuntu1.1", "PkgName": "libss2", + "PkgIdentifier": { + "PURL": "pkg:deb/ubuntu/libss2@1.44.1-1ubuntu1.1?arch=amd64\u0026distro=ubuntu-18.04" + }, "InstalledVersion": "1.44.1-1ubuntu1.1", "FixedVersion": "1.44.1-1ubuntu1.2", "Status": "fixed", diff --git a/integration/testdata/ubuntu-gp2-x86-vm.json.golden b/integration/testdata/ubuntu-gp2-x86-vm.json.golden index 485dc3712542..0c62f5aab4e2 100644 --- a/integration/testdata/ubuntu-gp2-x86-vm.json.golden +++ b/integration/testdata/ubuntu-gp2-x86-vm.json.golden @@ -29,6 +29,9 @@ "VulnerabilityID": "CVE-2022-3715", "PkgID": "bash@5.1-6ubuntu1", "PkgName": "bash", + "PkgIdentifier": { + "PURL": "pkg:deb/ubuntu/bash@5.1-6ubuntu1?arch=amd64\u0026distro=ubuntu-22.04" + }, "InstalledVersion": "5.1-6ubuntu1", "Status": "affected", "Layer": {}, diff --git a/integration/testdata/yarn.json.golden b/integration/testdata/yarn.json.golden index 3002b9f9b992..1e5cd3da24b3 100644 --- a/integration/testdata/yarn.json.golden +++ b/integration/testdata/yarn.json.golden @@ -24,6 +24,9 @@ { "ID": "jquery@3.2.1", "Name": "jquery", + "Identifier": { + "PURL": "pkg:npm/jquery@3.2.1" + }, "Version": "3.2.1", "Licenses": [ "MIT" @@ -42,6 +45,9 @@ "VulnerabilityID": "CVE-2019-11358", "PkgID": "jquery@3.2.1", "PkgName": "jquery", + "PkgIdentifier": { + "PURL": "pkg:npm/jquery@3.2.1" + }, "InstalledVersion": "3.2.1", "FixedVersion": "3.4.0", "Status": "fixed", diff --git a/pkg/detector/library/detect.go b/pkg/detector/library/detect.go index 121f33284e1a..14674be8d1a8 100644 --- a/pkg/detector/library/detect.go +++ b/pkg/detector/library/detect.go @@ -34,6 +34,7 @@ func detect(driver Driver, libs []ftypes.Package) ([]types.DetectedVulnerability vulns[i].Layer = lib.Layer vulns[i].PkgPath = lib.FilePath vulns[i].PkgRef = lib.Ref + vulns[i].PkgIdentifier = lib.Identifier } vulnerabilities = append(vulnerabilities, vulns...) } diff --git a/pkg/detector/ospkg/alma/alma.go b/pkg/detector/ospkg/alma/alma.go index 2c52fea3deb7..a3c3a546f8f4 100644 --- a/pkg/detector/ospkg/alma/alma.go +++ b/pkg/detector/ospkg/alma/alma.go @@ -81,7 +81,6 @@ func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Packa installed := utils.FormatVersion(pkg) installedVersion := version.NewVersion(installed) - for _, adv := range advisories { fixedVersion := version.NewVersion(adv.FixedVersion) if installedVersion.LessThan(fixedVersion) { @@ -92,6 +91,7 @@ func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Packa InstalledVersion: installed, FixedVersion: fixedVersion.String(), PkgRef: pkg.Ref, + PkgIdentifier: pkg.Identifier, Layer: pkg.Layer, DataSource: adv.DataSource, Custom: adv.Custom, diff --git a/pkg/detector/ospkg/alpine/alpine.go b/pkg/detector/ospkg/alpine/alpine.go index 45be59c1ea6a..aa50ef35ba1e 100644 --- a/pkg/detector/ospkg/alpine/alpine.go +++ b/pkg/detector/ospkg/alpine/alpine.go @@ -131,6 +131,7 @@ func (s *Scanner) Detect(osVer string, repo *ftypes.Repository, pkgs []ftypes.Pa FixedVersion: adv.FixedVersion, Layer: pkg.Layer, PkgRef: pkg.Ref, + PkgIdentifier: pkg.Identifier, Custom: adv.Custom, DataSource: adv.DataSource, }) diff --git a/pkg/detector/ospkg/amazon/amazon.go b/pkg/detector/ospkg/amazon/amazon.go index 5d28dce0a17e..4be7ab8080ae 100644 --- a/pkg/detector/ospkg/amazon/amazon.go +++ b/pkg/detector/ospkg/amazon/amazon.go @@ -104,6 +104,7 @@ func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Packa InstalledVersion: installed, FixedVersion: adv.FixedVersion, PkgRef: pkg.Ref, + PkgIdentifier: pkg.Identifier, Layer: pkg.Layer, Custom: adv.Custom, DataSource: adv.DataSource, diff --git a/pkg/detector/ospkg/chainguard/chainguard.go b/pkg/detector/ospkg/chainguard/chainguard.go index 9a6d5e752f4b..a818de11cbfe 100644 --- a/pkg/detector/ospkg/chainguard/chainguard.go +++ b/pkg/detector/ospkg/chainguard/chainguard.go @@ -82,6 +82,7 @@ func (s *Scanner) Detect(_ string, _ *ftypes.Repository, pkgs []ftypes.Package) FixedVersion: adv.FixedVersion, Layer: pkg.Layer, PkgRef: pkg.Ref, + PkgIdentifier: pkg.Identifier, Custom: adv.Custom, DataSource: adv.DataSource, }) diff --git a/pkg/detector/ospkg/debian/debian.go b/pkg/detector/ospkg/debian/debian.go index 32526e9bbffe..90a91af42b27 100644 --- a/pkg/detector/ospkg/debian/debian.go +++ b/pkg/detector/ospkg/debian/debian.go @@ -104,6 +104,7 @@ func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Packa InstalledVersion: utils.FormatVersion(pkg), FixedVersion: adv.FixedVersion, PkgRef: pkg.Ref, + PkgIdentifier: pkg.Identifier, Status: adv.Status, Layer: pkg.Layer, Custom: adv.Custom, diff --git a/pkg/detector/ospkg/mariner/mariner.go b/pkg/detector/ospkg/mariner/mariner.go index 6d88f3a3320e..0b780b9f2d71 100644 --- a/pkg/detector/ospkg/mariner/mariner.go +++ b/pkg/detector/ospkg/mariner/mariner.go @@ -50,6 +50,7 @@ func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Packa PkgName: pkg.Name, InstalledVersion: utils.FormatVersion(pkg), PkgRef: pkg.Ref, + PkgIdentifier: pkg.Identifier, Layer: pkg.Layer, DataSource: adv.DataSource, } diff --git a/pkg/detector/ospkg/oracle/oracle.go b/pkg/detector/ospkg/oracle/oracle.go index ccffc56eb1f5..0f07d9873526 100644 --- a/pkg/detector/ospkg/oracle/oracle.go +++ b/pkg/detector/ospkg/oracle/oracle.go @@ -87,6 +87,7 @@ func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Packa PkgName: pkg.Name, InstalledVersion: installed, PkgRef: pkg.Ref, + PkgIdentifier: pkg.Identifier, Layer: pkg.Layer, Custom: adv.Custom, DataSource: adv.DataSource, diff --git a/pkg/detector/ospkg/photon/photon.go b/pkg/detector/ospkg/photon/photon.go index df9822dd5b3e..ac7eb501f102 100644 --- a/pkg/detector/ospkg/photon/photon.go +++ b/pkg/detector/ospkg/photon/photon.go @@ -82,6 +82,7 @@ func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Packa PkgName: pkg.Name, InstalledVersion: installed, PkgRef: pkg.Ref, + PkgIdentifier: pkg.Identifier, Layer: pkg.Layer, Custom: adv.Custom, DataSource: adv.DataSource, diff --git a/pkg/detector/ospkg/redhat/redhat.go b/pkg/detector/ospkg/redhat/redhat.go index 8e419c93a45e..9420e9cdbb1c 100644 --- a/pkg/detector/ospkg/redhat/redhat.go +++ b/pkg/detector/ospkg/redhat/redhat.go @@ -158,6 +158,7 @@ func (s *Scanner) detect(osVer string, pkg ftypes.Package) ([]types.DetectedVuln PkgName: pkg.Name, InstalledVersion: utils.FormatVersion(pkg), PkgRef: pkg.Ref, + PkgIdentifier: pkg.Identifier, Status: adv.Status, Layer: pkg.Layer, SeveritySource: vulnerability.RedHat, diff --git a/pkg/detector/ospkg/rocky/rocky.go b/pkg/detector/ospkg/rocky/rocky.go index 25efce4cb865..9a57cf7974cf 100644 --- a/pkg/detector/ospkg/rocky/rocky.go +++ b/pkg/detector/ospkg/rocky/rocky.go @@ -91,6 +91,7 @@ func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Packa InstalledVersion: installed, FixedVersion: fixedVersion.String(), PkgRef: pkg.Ref, + PkgIdentifier: pkg.Identifier, Layer: pkg.Layer, DataSource: adv.DataSource, Custom: adv.Custom, diff --git a/pkg/detector/ospkg/suse/suse.go b/pkg/detector/ospkg/suse/suse.go index c846867d73ca..267c8940ef0b 100644 --- a/pkg/detector/ospkg/suse/suse.go +++ b/pkg/detector/ospkg/suse/suse.go @@ -134,6 +134,7 @@ func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Packa PkgName: pkg.Name, InstalledVersion: installed, PkgRef: pkg.Ref, + PkgIdentifier: pkg.Identifier, Layer: pkg.Layer, Custom: adv.Custom, DataSource: adv.DataSource, diff --git a/pkg/detector/ospkg/ubuntu/ubuntu.go b/pkg/detector/ospkg/ubuntu/ubuntu.go index 836f26999077..d2f76a2e67d0 100644 --- a/pkg/detector/ospkg/ubuntu/ubuntu.go +++ b/pkg/detector/ospkg/ubuntu/ubuntu.go @@ -124,6 +124,7 @@ func (s *Scanner) Detect(osVer string, _ *ftypes.Repository, pkgs []ftypes.Packa InstalledVersion: utils.FormatVersion(pkg), FixedVersion: adv.FixedVersion, PkgRef: pkg.Ref, + PkgIdentifier: pkg.Identifier, Layer: pkg.Layer, Custom: adv.Custom, DataSource: adv.DataSource, diff --git a/pkg/detector/ospkg/wolfi/wolfi.go b/pkg/detector/ospkg/wolfi/wolfi.go index 466ea20e5049..c7d4ca1a1c4f 100644 --- a/pkg/detector/ospkg/wolfi/wolfi.go +++ b/pkg/detector/ospkg/wolfi/wolfi.go @@ -82,6 +82,7 @@ func (s *Scanner) Detect(_ string, _ *ftypes.Repository, pkgs []ftypes.Package) FixedVersion: adv.FixedVersion, Layer: pkg.Layer, PkgRef: pkg.Ref, + PkgIdentifier: pkg.Identifier, Custom: adv.Custom, DataSource: adv.DataSource, }) diff --git a/pkg/fanal/analyzer/imgconf/apk/apk.go b/pkg/fanal/analyzer/imgconf/apk/apk.go index 7d2a88e84bff..43f6cc278023 100644 --- a/pkg/fanal/analyzer/imgconf/apk/apk.go +++ b/pkg/fanal/analyzer/imgconf/apk/apk.go @@ -13,6 +13,7 @@ import ( "time" v1 "github.com/google/go-containerregistry/pkg/v1" + "golang.org/x/exp/maps" "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" @@ -56,11 +57,11 @@ type archive struct { } type provide struct { - SO map[string]pkg // package which provides the shared object - Package map[string]pkg // package which provides the package + SO map[string]apk // package which provides the shared object + Package map[string]apk // package which provides the package } -type pkg struct { +type apk struct { Package string Versions version } @@ -135,11 +136,8 @@ func (a alpineCmdAnalyzer) parseConfig(apkIndexArchive *apkIndex, config *v1.Con uniqPkgs[result.Name] = result } } - for _, pkg := range uniqPkgs { - packages = append(packages, pkg) - } - return packages + return maps.Values(uniqPkgs) } func (a alpineCmdAnalyzer) parseCommand(command string, envs map[string]string) (pkgs []string) { diff --git a/pkg/fanal/analyzer/imgconf/apk/apk_test.go b/pkg/fanal/analyzer/imgconf/apk/apk_test.go index 1cb0e10064da..8f3856e2fde4 100644 --- a/pkg/fanal/analyzer/imgconf/apk/apk_test.go +++ b/pkg/fanal/analyzer/imgconf/apk/apk_test.go @@ -1070,11 +1070,11 @@ func TestAnalyze(t *testing.T) { args: args{ targetOS: types.OS{ Family: "alpine", - Name: "", + Name: "3.9.1", }, config: alpineConfig, }, - apkIndexArchivePath: testServer.URL + "%v", + apkIndexArchivePath: testServer.URL + "/%v", want: wantPkgs, }, } diff --git a/pkg/fanal/analyzer/language/analyze.go b/pkg/fanal/analyzer/language/analyze.go index 61d9492aa68c..8c0499b26ef6 100644 --- a/pkg/fanal/analyzer/language/analyze.go +++ b/pkg/fanal/analyzer/language/analyze.go @@ -116,7 +116,8 @@ func toApplication(fileType types.LangType, filePath, libFilePath string, r dio. if lib.FilePath != "" { libPath = lib.FilePath } - pkgs = append(pkgs, types.Package{ + + newPkg := types.Package{ ID: lib.ID, Name: lib.Name, Version: lib.Version, @@ -127,7 +128,8 @@ func toApplication(fileType types.LangType, filePath, libFilePath string, r dio. DependsOn: deps[lib.ID], Locations: locs, Digest: d, - }) + } + pkgs = append(pkgs, newPkg) } return &types.Application{ diff --git a/pkg/fanal/analyzer/pkg/dpkg/dpkg_test.go b/pkg/fanal/analyzer/pkg/dpkg/dpkg_test.go index 0a1ae4e10f54..4dc627823200 100644 --- a/pkg/fanal/analyzer/pkg/dpkg/dpkg_test.go +++ b/pkg/fanal/analyzer/pkg/dpkg/dpkg_test.go @@ -623,8 +623,9 @@ func Test_dpkgAnalyzer_Analyze(t *testing.T) { Arch: "amd64", }, { - ID: "libgpg-error0@1.27-6", - Name: "libgpg-error0", + ID: "libgpg-error0@1.27-6", + Name: "libgpg-error0", + Version: "1.27", Release: "6", SrcName: "libgpg-error", diff --git a/pkg/fanal/analyzer/pkg/rpm/rpm_test.go b/pkg/fanal/analyzer/pkg/rpm/rpm_test.go index aebb70928fb1..7e99cc601d61 100644 --- a/pkg/fanal/analyzer/pkg/rpm/rpm_test.go +++ b/pkg/fanal/analyzer/pkg/rpm/rpm_test.go @@ -3,14 +3,15 @@ package rpm import ( "context" "errors" + "os" + "strings" + "testing" + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/types" rpmdb "github.com/knqyf263/go-rpmdb/pkg" "github.com/samber/lo" "github.com/stretchr/testify/require" - "os" - "strings" - "testing" "github.com/stretchr/testify/assert" ) diff --git a/pkg/fanal/analyzer/pkg/rpm/rpmqa.go b/pkg/fanal/analyzer/pkg/rpm/rpmqa.go index 4c96ab4fb9ef..4a312961c2c2 100644 --- a/pkg/fanal/analyzer/pkg/rpm/rpmqa.go +++ b/pkg/fanal/analyzer/pkg/rpm/rpmqa.go @@ -68,7 +68,7 @@ func (a rpmqaPkgAnalyzer) parseRpmqaManifest(r io.ReadSeekerAt) ([]types.Package if err != nil { return nil, xerrors.Errorf("failed to split source rpm: %w", err) } - pkg := types.Package{ + pkgs = append(pkgs, types.Package{ Name: name, Version: ver, Release: rel, @@ -76,8 +76,7 @@ func (a rpmqaPkgAnalyzer) parseRpmqaManifest(r io.ReadSeekerAt) ([]types.Package SrcName: srcName, SrcVersion: srcVer, SrcRelease: srcRel, - } - pkgs = append(pkgs, pkg) + }) } return pkgs, nil } diff --git a/pkg/fanal/analyzer/sbom/sbom.go b/pkg/fanal/analyzer/sbom/sbom.go index 1f8b62af2fd6..51b5178c781c 100644 --- a/pkg/fanal/analyzer/sbom/sbom.go +++ b/pkg/fanal/analyzer/sbom/sbom.go @@ -86,7 +86,11 @@ func handleBitnamiImages(componentPath string, bom types.SBOM) { // e.g. modules/apm/elastic-apm-agent-1.36.0.jar // => opt/bitnami/elasticsearch/modules/apm/elastic-apm-agent-1.36.0.jar // If the file path is empty, the file path will be set to the component dir path. - bom.Applications[i].Libraries[j].FilePath = path.Join(componentPath, pkg.FilePath) + filePath := path.Join(componentPath, pkg.FilePath) + bom.Applications[i].Libraries[j].FilePath = filePath + if pkg.Identifier.PURL != nil && pkg.Identifier.PURL.FilePath != "" { + bom.Applications[i].Libraries[j].Identifier.PURL.FilePath = filePath + } } } } diff --git a/pkg/fanal/analyzer/sbom/sbom_test.go b/pkg/fanal/analyzer/sbom/sbom_test.go index fe00d31a6ae7..e475e1b363bb 100644 --- a/pkg/fanal/analyzer/sbom/sbom_test.go +++ b/pkg/fanal/analyzer/sbom/sbom_test.go @@ -2,6 +2,7 @@ package sbom import ( "context" + "github.com/package-url/packageurl-go" "os" "testing" @@ -34,24 +35,64 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) { Version: "1.36.0", Ref: "pkg:maven/co.elastic.apm/apm-agent@1.36.0", FilePath: "opt/bitnami/elasticsearch", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "co.elastic.apm", + Name: "apm-agent", + Version: "1.36.0", + }, + }, + }, }, { Name: "co.elastic.apm:apm-agent-cached-lookup-key", Version: "1.36.0", Ref: "pkg:maven/co.elastic.apm/apm-agent-cached-lookup-key@1.36.0", FilePath: "opt/bitnami/elasticsearch", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "co.elastic.apm", + Name: "apm-agent-cached-lookup-key", + Version: "1.36.0", + }, + }, + }, }, { Name: "co.elastic.apm:apm-agent-common", Version: "1.36.0", Ref: "pkg:maven/co.elastic.apm/apm-agent-common@1.36.0", FilePath: "opt/bitnami/elasticsearch", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "co.elastic.apm", + Name: "apm-agent-common", + Version: "1.36.0", + }, + }, + }, }, { Name: "co.elastic.apm:apm-agent-core", Version: "1.36.0", Ref: "pkg:maven/co.elastic.apm/apm-agent-core@1.36.0", FilePath: "opt/bitnami/elasticsearch", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "co.elastic.apm", + Name: "apm-agent-core", + Version: "1.36.0", + }, + }, + }, }, }, }, @@ -65,6 +106,21 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) { Ref: "pkg:bitnami/elasticsearch@8.9.1?arch=arm64", Arch: "arm64", Licenses: []string{"Elastic-2.0"}, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeBitnami, + Name: "elasticsearch", + Version: "8.9.1", + Qualifiers: packageurl.Qualifiers{ + { + Key: "arch", + Value: "arm64", + }, + }, + }, + }, + }, }, }, }, @@ -86,12 +142,34 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) { Name: "co.elastic.apm:apm-agent", Version: "1.36.0", Ref: "pkg:maven/co.elastic.apm/apm-agent@1.36.0", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "co.elastic.apm", + Name: "apm-agent", + Version: "1.36.0", + }, + FilePath: "opt/bitnami/elasticsearch/modules/apm/elastic-apm-agent-1.36.0.jar", + }, + }, }, { FilePath: "opt/bitnami/elasticsearch/modules/apm/elastic-apm-agent-1.36.0.jar", Name: "co.elastic.apm:apm-agent-cached-lookup-key", Version: "1.36.0", Ref: "pkg:maven/co.elastic.apm/apm-agent-cached-lookup-key@1.36.0", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "co.elastic.apm", + Name: "apm-agent-cached-lookup-key", + Version: "1.36.0", + }, + FilePath: "opt/bitnami/elasticsearch/modules/apm/elastic-apm-agent-1.36.0.jar", + }, + }, }, }, }, @@ -114,24 +192,60 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) { Version: "3.7.1", Ref: "pkg:bitnami/gdal@3.7.1", Licenses: []string{"MIT"}, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeBitnami, + Name: "gdal", + Version: "3.7.1", + }, + }, + }, }, { Name: "geos", Version: "3.8.3", Ref: "pkg:bitnami/geos@3.8.3", Licenses: []string{"LGPL-2.1-only"}, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeBitnami, + Name: "geos", + Version: "3.8.3", + }, + }, + }, }, { Name: "postgresql", Version: "15.3.0", Ref: "pkg:bitnami/postgresql@15.3.0", Licenses: []string{"PostgreSQL"}, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeBitnami, + Name: "postgresql", + Version: "15.3.0", + }, + }, + }, }, { Name: "proj", Version: "6.3.2", Ref: "pkg:bitnami/proj@6.3.2", Licenses: []string{"MIT"}, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeBitnami, + Name: "proj", + Version: "6.3.2", + }, + }, + }, }, }, }, diff --git a/pkg/fanal/applier/applier_test.go b/pkg/fanal/applier/applier_test.go index 315a042cb279..0994d46bfc39 100644 --- a/pkg/fanal/applier/applier_test.go +++ b/pkg/fanal/applier/applier_test.go @@ -1,6 +1,7 @@ package applier_test import ( + "github.com/package-url/packageurl-go" "sort" "testing" @@ -149,6 +150,22 @@ func TestApplier_ApplyLayers(t *testing.T) { Version: "2.24-11+deb9u4", SrcName: "glibc", SrcVersion: "2.24-11+deb9u4", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeDebian, + Namespace: "debian", + Name: "libc6", + Version: "2.24-11+deb9u4", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "debian-9.9", + }, + }, + }, + }, + }, Layer: types.Layer{ Digest: "sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5", DiffID: "sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819", @@ -159,6 +176,22 @@ func TestApplier_ApplyLayers(t *testing.T) { Version: "2019a-0+deb9u1", SrcName: "tzdata", SrcVersion: "2019a-0+deb9u1", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeDebian, + Namespace: "debian", + Name: "tzdata", + Version: "2019a-0+deb9u1", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "debian-9.9", + }, + }, + }, + }, + }, Layer: types.Layer{ Digest: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02", DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", @@ -177,6 +210,16 @@ func TestApplier_ApplyLayers(t *testing.T) { Digest: "sha256:beee9f30bc1f711043e78d4a2be0668955d4b761d587d6f60c2c8dc081efb203", DiffID: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7", }, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "guzzlehttp", + Name: "guzzle", + Version: "6.2.0", + }, + }, + }, }, { Name: "symfony/process", @@ -185,6 +228,16 @@ func TestApplier_ApplyLayers(t *testing.T) { Digest: "sha256:beee9f30bc1f711043e78d4a2be0668955d4b761d587d6f60c2c8dc081efb203", DiffID: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7", }, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "symfony", + Name: "process", + Version: "v4.2.7", + }, + }, + }, }, }, }, @@ -299,6 +352,22 @@ func TestApplier_ApplyLayers(t *testing.T) { { Name: "busybox", Version: "1.30.1-r3", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeApk, + Namespace: "alpine", + Name: "busybox", + Version: "1.30.1-r3", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "3.10.4", + }, + }, + }, + }, + }, Layer: types.Layer{ Digest: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", DiffID: "sha256:531743b7098cb2aaf615641007a129173f63ed86ca32fe7b5a246a1c47286028", @@ -307,6 +376,22 @@ func TestApplier_ApplyLayers(t *testing.T) { { Name: "libcrypto1.1", Version: "1.1.1d-r2", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeApk, + Namespace: "alpine", + Name: "libcrypto1.1", + Version: "1.1.1d-r2", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "3.10.4", + }, + }, + }, + }, + }, Layer: types.Layer{ Digest: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", DiffID: "sha256:531743b7098cb2aaf615641007a129173f63ed86ca32fe7b5a246a1c47286028", @@ -315,6 +400,22 @@ func TestApplier_ApplyLayers(t *testing.T) { { Name: "libssl1.1", Version: "1.1.1d-r2", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeApk, + Namespace: "alpine", + Name: "libssl1.1", + Version: "1.1.1d-r2", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "3.10.4", + }, + }, + }, + }, + }, Layer: types.Layer{ Digest: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", DiffID: "sha256:531743b7098cb2aaf615641007a129173f63ed86ca32fe7b5a246a1c47286028", @@ -323,6 +424,22 @@ func TestApplier_ApplyLayers(t *testing.T) { { Name: "musl", Version: "1.1.22-r3", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeApk, + Namespace: "alpine", + Name: "musl", + Version: "1.1.22-r3", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "3.10.4", + }, + }, + }, + }, + }, Layer: types.Layer{ Digest: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", DiffID: "sha256:531743b7098cb2aaf615641007a129173f63ed86ca32fe7b5a246a1c47286028", @@ -331,6 +448,23 @@ func TestApplier_ApplyLayers(t *testing.T) { { Name: "openssl", Version: "1.1.1d-r2", + Identifier: types.PkgIdentifier{ + //PURL: "pkg:apk/alpine/openssl@1.1.1d-r2?distro=3.10.4", + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeApk, + Namespace: "alpine", + Name: "openssl", + Version: "1.1.1d-r2", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "3.10.4", + }, + }, + }, + }, + }, Layer: types.Layer{ Digest: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", DiffID: "sha256:531743b7098cb2aaf615641007a129173f63ed86ca32fe7b5a246a1c47286028", @@ -549,6 +683,16 @@ func TestApplier_ApplyLayers(t *testing.T) { Digest: "sha256:beee9f30bc1f711043e78d4a2be0668955d4b761d587d6f60c2c8dc081efb203", DiffID: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7", }, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "guzzlehttp", + Name: "guzzle", + Version: "6.2.0", + }, + }, + }, }, { Name: "symfony/process", @@ -557,6 +701,16 @@ func TestApplier_ApplyLayers(t *testing.T) { Digest: "sha256:beee9f30bc1f711043e78d4a2be0668955d4b761d587d6f60c2c8dc081efb203", DiffID: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7", }, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "symfony", + Name: "process", + Version: "v4.2.7", + }, + }, + }, }, }, }, @@ -741,6 +895,16 @@ func TestApplier_ApplyLayers(t *testing.T) { Digest: "sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5", DiffID: "sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819", }, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "guzzlehttp", + Name: "guzzle", + Version: "6.2.0", + }, + }, + }, }, { Name: "symfony/process", @@ -749,6 +913,16 @@ func TestApplier_ApplyLayers(t *testing.T) { Digest: "sha256:dffd9992ca398466a663c87c92cfea2a2db0ae0cf33fcb99da60eec52addbfc5", DiffID: "sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819", }, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "symfony", + Name: "process", + Version: "v4.2.7", + }, + }, + }, }, }, }, diff --git a/pkg/fanal/applier/docker.go b/pkg/fanal/applier/docker.go index b0f42d957eec..68de804c89b1 100644 --- a/pkg/fanal/applier/docker.go +++ b/pkg/fanal/applier/docker.go @@ -8,7 +8,10 @@ import ( "github.com/knqyf263/nested" "github.com/samber/lo" - "github.com/aquasecurity/trivy/pkg/fanal/types" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/log" + "github.com/aquasecurity/trivy/pkg/purl" + "github.com/aquasecurity/trivy/pkg/types" ) type Config struct { @@ -25,7 +28,7 @@ type History struct { CreatedBy string `json:"created_by"` } -func containsPackage(e types.Package, s []types.Package) bool { +func containsPackage(e ftypes.Package, s []ftypes.Package) bool { for _, a := range s { if a.Name == e.Name && a.Version == e.Version && a.Release == e.Release { return true @@ -34,7 +37,7 @@ func containsPackage(e types.Package, s []types.Package) bool { return false } -func lookupOriginLayerForPkg(pkg types.Package, layers []types.BlobInfo) (string, string, *types.BuildInfo) { +func lookupOriginLayerForPkg(pkg ftypes.Package, layers []ftypes.BlobInfo) (string, string, *ftypes.BuildInfo) { for i, layer := range layers { for _, info := range layer.PackageInfos { if containsPackage(pkg, info.Packages) { @@ -46,7 +49,7 @@ func lookupOriginLayerForPkg(pkg types.Package, layers []types.BlobInfo) (string } // lookupBuildInfo looks up Red Hat content sets from all layers -func lookupBuildInfo(index int, layers []types.BlobInfo) *types.BuildInfo { +func lookupBuildInfo(index int, layers []ftypes.BlobInfo) *ftypes.BuildInfo { if layers[index].BuildInfo != nil { return layers[index].BuildInfo } @@ -70,7 +73,7 @@ func lookupBuildInfo(index int, layers []types.BlobInfo) *types.BuildInfo { return nil } -func lookupOriginLayerForLib(filePath string, lib types.Package, layers []types.BlobInfo) (string, string) { +func lookupOriginLayerForLib(filePath string, lib ftypes.Package, layers []ftypes.BlobInfo) (string, string) { for _, layer := range layers { for _, layerApp := range layer.Applications { if filePath != layerApp.FilePath { @@ -86,11 +89,11 @@ func lookupOriginLayerForLib(filePath string, lib types.Package, layers []types. // ApplyLayers returns the merged layer // nolint: gocyclo -func ApplyLayers(layers []types.BlobInfo) types.ArtifactDetail { +func ApplyLayers(layers []ftypes.BlobInfo) ftypes.ArtifactDetail { sep := "/" nestedMap := nested.Nested{} - secretsMap := make(map[string]types.Secret) - var mergedLayer types.ArtifactDetail + secretsMap := make(map[string]ftypes.Secret) + var mergedLayer ftypes.ArtifactDetail for _, layer := range layers { for _, opqDir := range layer.OpaqueDirs { @@ -121,7 +124,7 @@ func ApplyLayers(layers []types.BlobInfo) types.ArtifactDetail { // Apply misconfigurations for _, config := range layer.Misconfigurations { - config.Layer = types.Layer{ + config.Layer = ftypes.Layer{ Digest: layer.Digest, DiffID: layer.DiffID, } @@ -131,7 +134,7 @@ func ApplyLayers(layers []types.BlobInfo) types.ArtifactDetail { // Apply secrets for _, secret := range layer.Secrets { - l := types.Layer{ + l := ftypes.Layer{ Digest: layer.Digest, DiffID: layer.DiffID, CreatedBy: layer.CreatedBy, @@ -141,7 +144,7 @@ func ApplyLayers(layers []types.BlobInfo) types.ArtifactDetail { // Apply license files for _, license := range layer.Licenses { - license.Layer = types.Layer{ + license.Layer = ftypes.Layer{ Digest: layer.Digest, DiffID: layer.DiffID, } @@ -152,7 +155,7 @@ func ApplyLayers(layers []types.BlobInfo) types.ArtifactDetail { // Apply custom resources for _, customResource := range layer.CustomResources { key := fmt.Sprintf("%s/custom:%s", customResource.FilePath, customResource.Type) - customResource.Layer = types.Layer{ + customResource.Layer = ftypes.Layer{ Digest: layer.Digest, DiffID: layer.DiffID, } @@ -163,15 +166,15 @@ func ApplyLayers(layers []types.BlobInfo) types.ArtifactDetail { // nolint _ = nestedMap.Walk(func(keys []string, value interface{}) error { switch v := value.(type) { - case types.PackageInfo: + case ftypes.PackageInfo: mergedLayer.Packages = append(mergedLayer.Packages, v.Packages...) - case types.Application: + case ftypes.Application: mergedLayer.Applications = append(mergedLayer.Applications, v) - case types.Misconfiguration: + case ftypes.Misconfiguration: mergedLayer.Misconfigurations = append(mergedLayer.Misconfigurations, v) - case types.LicenseFile: + case ftypes.LicenseFile: mergedLayer.Licenses = append(mergedLayer.Licenses, v) - case types.CustomResource: + case ftypes.CustomResource: mergedLayer.CustomResources = append(mergedLayer.CustomResources, v) } return nil @@ -185,14 +188,14 @@ func ApplyLayers(layers []types.BlobInfo) types.ArtifactDetail { // The license information is not stored in the dpkg database and in a separate file, // so we have to merge the license information into the package. dpkgLicenses := make(map[string][]string) - mergedLayer.Licenses = lo.Reject(mergedLayer.Licenses, func(license types.LicenseFile, _ int) bool { - if license.Type != types.LicenseTypeDpkg { + mergedLayer.Licenses = lo.Reject(mergedLayer.Licenses, func(license ftypes.LicenseFile, _ int) bool { + if license.Type != ftypes.LicenseTypeDpkg { return false } // e.g. // "adduser" => {"GPL-2"} // "openssl" => {"MIT", "BSD"} - dpkgLicenses[license.PkgName] = lo.Map(license.Findings, func(finding types.LicenseFinding, _ int) string { + dpkgLicenses[license.PkgName] = lo.Map(license.Findings, func(finding ftypes.LicenseFinding, _ int) string { return finding.Name }) // Remove this license in the merged result as it is merged into the package information. @@ -208,11 +211,14 @@ func ApplyLayers(layers []types.BlobInfo) types.ArtifactDetail { continue } originLayerDigest, originLayerDiffID, buildInfo := lookupOriginLayerForPkg(pkg, layers) - mergedLayer.Packages[i].Layer = types.Layer{ + mergedLayer.Packages[i].Layer = ftypes.Layer{ Digest: originLayerDigest, DiffID: originLayerDiffID, } mergedLayer.Packages[i].BuildInfo = buildInfo + if mergedLayer.OS.Family != "" { + mergedLayer.Packages[i].Identifier.PURL = newPURL(mergedLayer.OS.Family, types.Metadata{OS: &mergedLayer.OS}, pkg) + } // Only debian packages if licenses, ok := dpkgLicenses[pkg.Name]; ok { @@ -227,10 +233,13 @@ func ApplyLayers(layers []types.BlobInfo) types.ArtifactDetail { continue } originLayerDigest, originLayerDiffID := lookupOriginLayerForLib(app.FilePath, lib, layers) - app.Libraries[i].Layer = types.Layer{ + app.Libraries[i].Layer = ftypes.Layer{ Digest: originLayerDigest, DiffID: originLayerDiffID, } + if lib.Identifier.PURL == nil { + app.Libraries[i].Identifier.PURL = newPURL(app.Type, types.Metadata{}, lib) + } } } @@ -240,16 +249,24 @@ func ApplyLayers(layers []types.BlobInfo) types.ArtifactDetail { return mergedLayer } +func newPURL(pkgType ftypes.TargetType, metadata types.Metadata, pkg ftypes.Package) *ftypes.PackageURL { + p, err := purl.New(pkgType, metadata, pkg) + if err != nil { + log.Logger.Errorf("Failed to create PackageURL: %s", err) + } + return p +} + // aggregate merges all packages installed by pip/gem/npm/jar/conda into each application -func aggregate(detail *types.ArtifactDetail) { - var apps []types.Application - - aggregatedApps := map[types.LangType]*types.Application{ - types.PythonPkg: {Type: types.PythonPkg}, - types.CondaPkg: {Type: types.CondaPkg}, - types.GemSpec: {Type: types.GemSpec}, - types.NodePkg: {Type: types.NodePkg}, - types.Jar: {Type: types.Jar}, +func aggregate(detail *ftypes.ArtifactDetail) { + var apps []ftypes.Application + + aggregatedApps := map[ftypes.LangType]*ftypes.Application{ + ftypes.PythonPkg: {Type: ftypes.PythonPkg}, + ftypes.CondaPkg: {Type: ftypes.CondaPkg}, + ftypes.GemSpec: {Type: ftypes.GemSpec}, + ftypes.NodePkg: {Type: ftypes.NodePkg}, + ftypes.Jar: {Type: ftypes.Jar}, } for _, app := range detail.Applications { @@ -273,7 +290,7 @@ func aggregate(detail *types.ArtifactDetail) { // We must save secrets from all layers even though they are removed in the uppler layer. // If the secret was changed at the top level, we need to overwrite it. -func mergeSecrets(secretsMap map[string]types.Secret, newSecret types.Secret, layer types.Layer) map[string]types.Secret { +func mergeSecrets(secretsMap map[string]ftypes.Secret, newSecret ftypes.Secret, layer ftypes.Layer) map[string]ftypes.Secret { for i := range newSecret.Findings { // add layer to the Findings from the new secret newSecret.Findings[i].Layer = layer } @@ -294,7 +311,7 @@ func mergeSecrets(secretsMap map[string]types.Secret, newSecret types.Secret, la return secretsMap } -func secretFindingsContains(findings []types.SecretFinding, finding types.SecretFinding) bool { +func secretFindingsContains(findings []ftypes.SecretFinding, finding ftypes.SecretFinding) bool { for _, f := range findings { if f.RuleID == finding.RuleID { return true diff --git a/pkg/fanal/applier/docker_test.go b/pkg/fanal/applier/docker_test.go index dbd2c3c4a9fb..fc04b7654070 100644 --- a/pkg/fanal/applier/docker_test.go +++ b/pkg/fanal/applier/docker_test.go @@ -1,6 +1,7 @@ package applier_test import ( + "github.com/package-url/packageurl-go" "sort" "testing" @@ -143,6 +144,22 @@ func TestApplyLayers(t *testing.T) { Name: "musl", Version: "1.2.4", Release: "4.5.8", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeApk, + Namespace: "alpine", + Name: "musl", + Version: "1.2.4-4.5.8", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "3.10", + }, + }, + }, + }, + }, Layer: types.Layer{ Digest: "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4", DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", @@ -152,6 +169,22 @@ func TestApplyLayers(t *testing.T) { Name: "openssl", Version: "1.2.3", Release: "4.5.6", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeApk, + Namespace: "alpine", + Name: "openssl", + Version: "1.2.3-4.5.6", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "3.10", + }, + }, + }, + }, + }, Layer: types.Layer{ Digest: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02", DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", @@ -170,6 +203,16 @@ func TestApplyLayers(t *testing.T) { Digest: "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4", DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", }, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "activesupport", + Version: "6.0.2.1", + }, + FilePath: "var/lib/gems/2.5.0/specifications/activesupport-6.0.2.1.gemspec", + }, + }, }, { Name: "gon", @@ -179,6 +222,16 @@ func TestApplyLayers(t *testing.T) { Digest: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02", DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", }, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "gon", + Version: "6.3.2", + }, + FilePath: "usr/local/bundle/specifications/gon-6.3.2.gemspec", + }, + }, }, }, }, @@ -193,6 +246,15 @@ func TestApplyLayers(t *testing.T) { Digest: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02", DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", }, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "gemlibrary1", + Version: "1.2.3", + }, + }, + }, }, }, }, @@ -413,6 +475,15 @@ func TestApplyLayers(t *testing.T) { Digest: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02", DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", }, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "rack", + Version: "4.0.0", + }, + }, + }, }, { Name: "rails", @@ -421,6 +492,15 @@ func TestApplyLayers(t *testing.T) { Digest: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7", DiffID: "sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819", }, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "rails", + Version: "6.0.0", + }, + }, + }, }, }, }, @@ -435,6 +515,15 @@ func TestApplyLayers(t *testing.T) { Digest: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7", DiffID: "sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819", }, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Name: "phplibrary1", + Version: "6.6.6", + }, + }, + }, }, }, }, @@ -691,6 +780,22 @@ func TestApplyLayers(t *testing.T) { Version: "1.2.4", Release: "4.5.7", Licenses: []string{"GPL-2"}, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeDebian, + Namespace: "debian", + Name: "libc", + Version: "1.2.4-4.5.7", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "debian-8", + }, + }, + }, + }, + }, Layer: types.Layer{ Digest: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02", DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", @@ -701,6 +806,22 @@ func TestApplyLayers(t *testing.T) { Version: "1.2.3", Release: "4.5.6", Licenses: []string{"OpenSSL"}, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeDebian, + Namespace: "debian", + Name: "openssl", + Version: "1.2.3-4.5.6", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "debian-8", + }, + }, + }, + }, + }, Layer: types.Layer{ Digest: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7", DiffID: "sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819", @@ -837,6 +958,22 @@ func TestApplyLayers(t *testing.T) { Name: "bash", Version: "5.6.7", Release: "8", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeRPM, + Namespace: "redhat", + Name: "bash", + Version: "5.6.7-8", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "redhat-8", + }, + }, + }, + }, + }, Layer: types.Layer{ Digest: "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4", DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", @@ -850,6 +987,22 @@ func TestApplyLayers(t *testing.T) { Name: "libc", Version: "1.2.4", Release: "5", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeRPM, + Namespace: "redhat", + Name: "libc", + Version: "1.2.4-5", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "redhat-8", + }, + }, + }, + }, + }, Layer: types.Layer{ Digest: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02", DiffID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", @@ -865,6 +1018,22 @@ func TestApplyLayers(t *testing.T) { Name: "openssl", Version: "1.2.3", Release: "4", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeRPM, + Namespace: "redhat", + Name: "openssl", + Version: "1.2.3-4", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "redhat-8", + }, + }, + }, + }, + }, Layer: types.Layer{ Digest: "sha256:24df0d4e20c0f42d3703bf1f1db2bdd77346c7956f74f423603d651e8e5ae8a7", DiffID: "sha256:aad63a9339440e7c3e1fff2b988991b9bfb81280042fa7f39a5e327023056819", diff --git a/pkg/fanal/artifact/image/remote_sbom_test.go b/pkg/fanal/artifact/image/remote_sbom_test.go index 07f1a3829e8e..b924a6efa6a3 100644 --- a/pkg/fanal/artifact/image/remote_sbom_test.go +++ b/pkg/fanal/artifact/image/remote_sbom_test.go @@ -2,6 +2,7 @@ package image_test import ( "context" + "github.com/package-url/packageurl-go" "net/http" "net/http/httptest" "net/url" @@ -69,7 +70,7 @@ func TestArtifact_InspectRekorAttestation(t *testing.T) { putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{ { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:9c23872047046e145f49fb5533b63ace0cbf819f5b68e33f69f4e9bbab4c517e", + BlobID: "sha256:754c66ef82bae2e07dc6e7a7bc42f078e1f48cbbc5b9124d18f1c18a48e1ad31", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, OS: types.OS{ @@ -80,8 +81,24 @@ func TestArtifact_InspectRekorAttestation(t *testing.T) { { Packages: types.Packages{ { - Name: "musl", - Version: "1.2.3-r0", + Name: "musl", + Version: "1.2.3-r0", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeApk, + Namespace: "alpine", + Name: "musl", + Version: "1.2.3-r0", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "3.16.2", + }, + }, + }, + }, + }, SrcName: "musl", SrcVersion: "1.2.3-r0", Licenses: []string{"MIT"}, @@ -104,9 +121,9 @@ func TestArtifact_InspectRekorAttestation(t *testing.T) { want: types.ArtifactReference{ Name: "test/image:10", Type: types.ArtifactCycloneDX, - ID: "sha256:9c23872047046e145f49fb5533b63ace0cbf819f5b68e33f69f4e9bbab4c517e", + ID: "sha256:754c66ef82bae2e07dc6e7a7bc42f078e1f48cbbc5b9124d18f1c18a48e1ad31", BlobIDs: []string{ - "sha256:9c23872047046e145f49fb5533b63ace0cbf819f5b68e33f69f4e9bbab4c517e", + "sha256:754c66ef82bae2e07dc6e7a7bc42f078e1f48cbbc5b9124d18f1c18a48e1ad31", }, }, }, @@ -173,7 +190,6 @@ func TestArtifact_inspectOCIReferrerSBOM(t *testing.T) { case "/v2/test/image/blobs/sha256:9e05dda2a2dcdd526c9204be8645ae48742861c27f093bf496a6397834acecf2": http.ServeFile(w, r, "testdata/cyclonedx.json") } - return })) defer ts.Close() @@ -208,7 +224,7 @@ func TestArtifact_inspectOCIReferrerSBOM(t *testing.T) { putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{ { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:d07a1894bfd283b4ac26682ab48f12ad22cdc4fef9cf8b4c09056f631d3667a5", + BlobID: "sha256:c4e3bd56d4b5f9634c918d0953f7667928c2410e23bdacb299bfe5802217809a", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Applications: []types.Application{ @@ -218,12 +234,32 @@ func TestArtifact_inspectOCIReferrerSBOM(t *testing.T) { { Name: "github.com/opencontainers/go-digest", Version: "v1.0.0", - Ref: "pkg:golang/github.com/opencontainers/go-digest@v1.0.0", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "github.com/opencontainers", + Name: "go-digest", + Version: "v1.0.0", + }, + }, + }, + Ref: "pkg:golang/github.com/opencontainers/go-digest@v1.0.0", }, { Name: "golang.org/x/sync", Version: "v0.1.0", - Ref: "pkg:golang/golang.org/x/sync@v0.1.0", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "golang.org/x", + Name: "sync", + Version: "v0.1.0", + }, + }, + }, + Ref: "pkg:golang/golang.org/x/sync@v0.1.0", }, }, }, @@ -235,9 +271,9 @@ func TestArtifact_inspectOCIReferrerSBOM(t *testing.T) { want: types.ArtifactReference{ Name: registry + "/test/image:10", Type: types.ArtifactCycloneDX, - ID: "sha256:d07a1894bfd283b4ac26682ab48f12ad22cdc4fef9cf8b4c09056f631d3667a5", + ID: "sha256:c4e3bd56d4b5f9634c918d0953f7667928c2410e23bdacb299bfe5802217809a", BlobIDs: []string{ - "sha256:d07a1894bfd283b4ac26682ab48f12ad22cdc4fef9cf8b4c09056f631d3667a5", + "sha256:c4e3bd56d4b5f9634c918d0953f7667928c2410e23bdacb299bfe5802217809a", }, }, }, diff --git a/pkg/fanal/artifact/local/fs_test.go b/pkg/fanal/artifact/local/fs_test.go index 21049d566f2a..200aa970bfb9 100644 --- a/pkg/fanal/artifact/local/fs_test.go +++ b/pkg/fanal/artifact/local/fs_test.go @@ -47,7 +47,7 @@ func TestArtifact_Inspect(t *testing.T) { }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:bb194ca778e3ecfa4b2addeae7b2c6b22ed10ab054b9d23e601c54e332913055", + BlobID: "sha256:ff28bff7756fb32d0a060b3b474b31a781a2d365dcd2789f47b4ae556a34947e", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, OS: types.OS{ @@ -82,9 +82,9 @@ func TestArtifact_Inspect(t *testing.T) { want: types.ArtifactReference{ Name: "host", Type: types.ArtifactFilesystem, - ID: "sha256:bb194ca778e3ecfa4b2addeae7b2c6b22ed10ab054b9d23e601c54e332913055", + ID: "sha256:ff28bff7756fb32d0a060b3b474b31a781a2d365dcd2789f47b4ae556a34947e", BlobIDs: []string{ - "sha256:bb194ca778e3ecfa4b2addeae7b2c6b22ed10ab054b9d23e601c54e332913055", + "sha256:ff28bff7756fb32d0a060b3b474b31a781a2d365dcd2789f47b4ae556a34947e", }, }, }, @@ -125,7 +125,7 @@ func TestArtifact_Inspect(t *testing.T) { }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:bb194ca778e3ecfa4b2addeae7b2c6b22ed10ab054b9d23e601c54e332913055", + BlobID: "sha256:ff28bff7756fb32d0a060b3b474b31a781a2d365dcd2789f47b4ae556a34947e", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, OS: types.OS{ @@ -175,7 +175,7 @@ func TestArtifact_Inspect(t *testing.T) { }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:0e0d362332d8928f71ac2c11e0813e2ec251dca9bdf1a66bd69cad8f2ef66ca1", + BlobID: "sha256:09aa251b64e824d0ec71a8c469619e57c9bd91d885f26e4a840de94209acbe4f", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Applications: []types.Application{ @@ -197,9 +197,9 @@ func TestArtifact_Inspect(t *testing.T) { want: types.ArtifactReference{ Name: "testdata/requirements.txt", Type: types.ArtifactFilesystem, - ID: "sha256:0e0d362332d8928f71ac2c11e0813e2ec251dca9bdf1a66bd69cad8f2ef66ca1", + ID: "sha256:09aa251b64e824d0ec71a8c469619e57c9bd91d885f26e4a840de94209acbe4f", BlobIDs: []string{ - "sha256:0e0d362332d8928f71ac2c11e0813e2ec251dca9bdf1a66bd69cad8f2ef66ca1", + "sha256:09aa251b64e824d0ec71a8c469619e57c9bd91d885f26e4a840de94209acbe4f", }, }, }, @@ -210,7 +210,7 @@ func TestArtifact_Inspect(t *testing.T) { }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:0e0d362332d8928f71ac2c11e0813e2ec251dca9bdf1a66bd69cad8f2ef66ca1", + BlobID: "sha256:09aa251b64e824d0ec71a8c469619e57c9bd91d885f26e4a840de94209acbe4f", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Applications: []types.Application{ @@ -232,9 +232,9 @@ func TestArtifact_Inspect(t *testing.T) { want: types.ArtifactReference{ Name: "testdata/requirements.txt", Type: types.ArtifactFilesystem, - ID: "sha256:0e0d362332d8928f71ac2c11e0813e2ec251dca9bdf1a66bd69cad8f2ef66ca1", + ID: "sha256:09aa251b64e824d0ec71a8c469619e57c9bd91d885f26e4a840de94209acbe4f", BlobIDs: []string{ - "sha256:0e0d362332d8928f71ac2c11e0813e2ec251dca9bdf1a66bd69cad8f2ef66ca1", + "sha256:09aa251b64e824d0ec71a8c469619e57c9bd91d885f26e4a840de94209acbe4f", }, }, }, diff --git a/pkg/fanal/artifact/sbom/sbom_test.go b/pkg/fanal/artifact/sbom/sbom_test.go index 9817c1a845fc..036574b63d13 100644 --- a/pkg/fanal/artifact/sbom/sbom_test.go +++ b/pkg/fanal/artifact/sbom/sbom_test.go @@ -3,6 +3,7 @@ package sbom_test import ( "context" "errors" + "github.com/package-url/packageurl-go" "path/filepath" "strings" "testing" @@ -29,7 +30,7 @@ func TestArtifact_Inspect(t *testing.T) { filePath: filepath.Join("testdata", "bom.json"), putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:3dca5f9082ac4e9669b5e461ae54ffe70db4ea275a09506014b17e012687e855", + BlobID: "sha256:c1cc58e08422fd7606a8e9ee2b42bf722b7af8b703b895461c23b83956f33227", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, OS: types.OS{ @@ -49,6 +50,22 @@ func TestArtifact_Inspect(t *testing.T) { Layer: types.Layer{ DiffID: "sha256:dd565ff850e7003356e2b252758f9bdc1ff2803f61e995e24c7844f6297f8fc3", }, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeApk, + Namespace: "alpine", + Name: "musl", + Version: "1.2.3-r0", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "3.16.0", + }, + }, + }, + }, + }, }, }, }, @@ -65,6 +82,16 @@ func TestArtifact_Inspect(t *testing.T) { Layer: types.Layer{ DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", }, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "log", + Version: "1.13.1", + }, + }, + }, }, { @@ -74,6 +101,16 @@ func TestArtifact_Inspect(t *testing.T) { Layer: types.Layer{ DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", }, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "pear_exception", + Version: "v1.0.0", + }, + }, + }, }, }, }, @@ -88,6 +125,16 @@ func TestArtifact_Inspect(t *testing.T) { Layer: types.Layer{ DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", }, + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "github.com/package-url", + Name: "packageurl-go", + Version: "v0.1.1-0.20220203205134-d70459300c8a", + }, + }, + }, }, }, }, @@ -103,6 +150,17 @@ func TestArtifact_Inspect(t *testing.T) { DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", }, FilePath: "app/maven/target/child-project-1.0.jar", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.codehaus.mojo", + Name: "child-project", + Version: "1.0", + }, + FilePath: "app/maven/target/child-project-1.0.jar", + }, + }, }, }, }, @@ -119,6 +177,16 @@ func TestArtifact_Inspect(t *testing.T) { DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", }, FilePath: "app/app/package.json", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeNPM, + Name: "bootstrap", + Version: "5.0.2", + }, + FilePath: "app/app/package.json", + }, + }, }, }, }, @@ -130,9 +198,9 @@ func TestArtifact_Inspect(t *testing.T) { want: types.ArtifactReference{ Name: filepath.Join("testdata", "bom.json"), Type: types.ArtifactCycloneDX, - ID: "sha256:3dca5f9082ac4e9669b5e461ae54ffe70db4ea275a09506014b17e012687e855", + ID: "sha256:c1cc58e08422fd7606a8e9ee2b42bf722b7af8b703b895461c23b83956f33227", BlobIDs: []string{ - "sha256:3dca5f9082ac4e9669b5e461ae54ffe70db4ea275a09506014b17e012687e855", + "sha256:c1cc58e08422fd7606a8e9ee2b42bf722b7af8b703b895461c23b83956f33227", }, }, }, @@ -141,7 +209,7 @@ func TestArtifact_Inspect(t *testing.T) { filePath: filepath.Join("testdata", "sbom.cdx.intoto.jsonl"), putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:3dca5f9082ac4e9669b5e461ae54ffe70db4ea275a09506014b17e012687e855", + BlobID: "sha256:c1cc58e08422fd7606a8e9ee2b42bf722b7af8b703b895461c23b83956f33227", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, OS: types.OS{ @@ -157,7 +225,23 @@ func TestArtifact_Inspect(t *testing.T) { SrcName: "musl", SrcVersion: "1.2.3-r0", Licenses: []string{"MIT"}, - Ref: "pkg:apk/alpine/musl@1.2.3-r0?distro=3.16.0", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeApk, + Namespace: "alpine", + Name: "musl", + Version: "1.2.3-r0", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "3.16.0", + }, + }, + }, + }, + }, + Ref: "pkg:apk/alpine/musl@1.2.3-r0?distro=3.16.0", Layer: types.Layer{ DiffID: "sha256:dd565ff850e7003356e2b252758f9bdc1ff2803f61e995e24c7844f6297f8fc3", }, @@ -173,7 +257,17 @@ func TestArtifact_Inspect(t *testing.T) { { Name: "pear/log", Version: "1.13.1", - Ref: "pkg:composer/pear/log@1.13.1", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "log", + Version: "1.13.1", + }, + }, + }, + Ref: "pkg:composer/pear/log@1.13.1", Layer: types.Layer{ DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", }, @@ -182,7 +276,17 @@ func TestArtifact_Inspect(t *testing.T) { Name: "pear/pear_exception", Version: "v1.0.0", - Ref: "pkg:composer/pear/pear_exception@v1.0.0", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "pear_exception", + Version: "v1.0.0", + }, + }, + }, + Ref: "pkg:composer/pear/pear_exception@v1.0.0", Layer: types.Layer{ DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", }, @@ -196,7 +300,17 @@ func TestArtifact_Inspect(t *testing.T) { { Name: "github.com/package-url/packageurl-go", Version: "v0.1.1-0.20220203205134-d70459300c8a", - Ref: "pkg:golang/github.com/package-url/packageurl-go@v0.1.1-0.20220203205134-d70459300c8a", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "github.com/package-url", + Name: "packageurl-go", + Version: "v0.1.1-0.20220203205134-d70459300c8a", + }, + }, + }, + Ref: "pkg:golang/github.com/package-url/packageurl-go@v0.1.1-0.20220203205134-d70459300c8a", Layer: types.Layer{ DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", }, @@ -209,8 +323,19 @@ func TestArtifact_Inspect(t *testing.T) { Libraries: types.Packages{ { Name: "org.codehaus.mojo:child-project", - Ref: "pkg:maven/org.codehaus.mojo/child-project@1.0?file_path=app%2Fmaven%2Ftarget%2Fchild-project-1.0.jar", Version: "1.0", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.codehaus.mojo", + Name: "child-project", + Version: "1.0", + }, + FilePath: "app/maven/target/child-project-1.0.jar", + }, + }, + Ref: "pkg:maven/org.codehaus.mojo/child-project@1.0?file_path=app%2Fmaven%2Ftarget%2Fchild-project-1.0.jar", Layer: types.Layer{ DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", }, @@ -223,8 +348,18 @@ func TestArtifact_Inspect(t *testing.T) { FilePath: "", Libraries: types.Packages{ { - Name: "bootstrap", - Version: "5.0.2", + Name: "bootstrap", + Version: "5.0.2", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeNPM, + Name: "bootstrap", + Version: "5.0.2", + }, + FilePath: "app/app/package.json", + }, + }, Ref: "pkg:npm/bootstrap@5.0.2?file_path=app%2Fapp%2Fpackage.json", Licenses: []string{"MIT"}, Layer: types.Layer{ @@ -242,9 +377,9 @@ func TestArtifact_Inspect(t *testing.T) { want: types.ArtifactReference{ Name: filepath.Join("testdata", "sbom.cdx.intoto.jsonl"), Type: types.ArtifactCycloneDX, - ID: "sha256:3dca5f9082ac4e9669b5e461ae54ffe70db4ea275a09506014b17e012687e855", + ID: "sha256:c1cc58e08422fd7606a8e9ee2b42bf722b7af8b703b895461c23b83956f33227", BlobIDs: []string{ - "sha256:3dca5f9082ac4e9669b5e461ae54ffe70db4ea275a09506014b17e012687e855", + "sha256:c1cc58e08422fd7606a8e9ee2b42bf722b7af8b703b895461c23b83956f33227", }, }, }, diff --git a/pkg/fanal/artifact/vm/vm_test.go b/pkg/fanal/artifact/vm/vm_test.go index 42ec47c07973..891b23797746 100644 --- a/pkg/fanal/artifact/vm/vm_test.go +++ b/pkg/fanal/artifact/vm/vm_test.go @@ -121,7 +121,7 @@ func TestArtifact_Inspect(t *testing.T) { rootDir: "testdata/alpine", putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:aeadb167e49ab2616738bc1d8b39f742968bef78baed984cf5801c678d6750ce", + BlobID: "sha256:84a726d23c36d0e1857101969b257c1199de5432489d44581750d54ea8eff8cd", BlobInfo: expectedBlobInfo, }, Returns: cache.ArtifactCachePutBlobReturns{}, @@ -129,7 +129,7 @@ func TestArtifact_Inspect(t *testing.T) { putArtifactExpectations: []cache.ArtifactCachePutArtifactExpectation{ { Args: cache.ArtifactCachePutArtifactArgs{ - ArtifactID: "sha256:aeadb167e49ab2616738bc1d8b39f742968bef78baed984cf5801c678d6750ce", + ArtifactID: "sha256:84a726d23c36d0e1857101969b257c1199de5432489d44581750d54ea8eff8cd", ArtifactInfo: types.ArtifactInfo{ SchemaVersion: types.ArtifactJSONSchemaVersion, }, @@ -139,9 +139,9 @@ func TestArtifact_Inspect(t *testing.T) { want: types.ArtifactReference{ Name: "rawdata.img", Type: types.ArtifactVM, - ID: "sha256:aeadb167e49ab2616738bc1d8b39f742968bef78baed984cf5801c678d6750ce", + ID: "sha256:84a726d23c36d0e1857101969b257c1199de5432489d44581750d54ea8eff8cd", BlobIDs: []string{ - "sha256:aeadb167e49ab2616738bc1d8b39f742968bef78baed984cf5801c678d6750ce", + "sha256:84a726d23c36d0e1857101969b257c1199de5432489d44581750d54ea8eff8cd", }, }, }, diff --git a/pkg/fanal/cache/fs_test.go b/pkg/fanal/cache/fs_test.go index fe93adb41f55..eaa050096d24 100644 --- a/pkg/fanal/cache/fs_test.go +++ b/pkg/fanal/cache/fs_test.go @@ -225,6 +225,7 @@ func TestFSCache_PutBlob(t *testing.T) { { "Name": "musl", "Version": "1.1.22-r3", + "Identifier": {}, "Layer": {} } ] @@ -238,11 +239,13 @@ func TestFSCache_PutBlob(t *testing.T) { { "Name":"guzzlehttp/guzzle", "Version":"6.2.0", + "Identifier": {}, "Layer": {} }, { "Name":"guzzlehttp/promises", "Version":"v1.3.1", + "Identifier": {}, "Layer": {} } ] @@ -341,6 +344,7 @@ func TestFSCache_PutArtifact(t *testing.T) { { "Name": "musl", "Version": "1.2.3", + "Identifier": {}, "Layer": {} } ] diff --git a/pkg/fanal/cache/mock_artifact_cache.go b/pkg/fanal/cache/mock_artifact_cache.go index 39fb5525c710..c73786021a58 100644 --- a/pkg/fanal/cache/mock_artifact_cache.go +++ b/pkg/fanal/cache/mock_artifact_cache.go @@ -193,7 +193,7 @@ type ArtifactCachePutBlobExpectation struct { Returns ArtifactCachePutBlobReturns } -func (_m *MockArtifactCache) ApplyPutBlobExpectation(e ArtifactCachePutBlobExpectation) { +func (_m *MockArtifactCache) ApplyPutBlobExpectation(e ArtifactCachePutBlobExpectation) *mock.Call{ var args []interface{} if e.Args.BlobIDAnything { args = append(args, mock.Anything) @@ -205,7 +205,8 @@ func (_m *MockArtifactCache) ApplyPutBlobExpectation(e ArtifactCachePutBlobExpec } else { args = append(args, e.Args.BlobInfo) } - _m.On("PutBlob", args...).Return(e.Returns.Err) + return _m.On("PutBlob", args...).Return(e.Returns.Err) + //return _m.On("PutBlob", mock.AnythingOfType("string"), mock.Anything).Return(e.Returns.Err) } func (_m *MockArtifactCache) ApplyPutBlobExpectations(expectations []ArtifactCachePutBlobExpectation) { diff --git a/pkg/fanal/handler/sysfile/filter_test.go b/pkg/fanal/handler/sysfile/filter_test.go index 6dc8d5af7b03..1b987fd5823f 100644 --- a/pkg/fanal/handler/sysfile/filter_test.go +++ b/pkg/fanal/handler/sysfile/filter_test.go @@ -178,7 +178,7 @@ func Test_systemFileFilterHook_Hook(t *testing.T) { }, }, { - name: "distoless", + name: "distroless", result: &analyzer.AnalysisResult{}, blob: &types.BlobInfo{ Applications: []types.Application{ diff --git a/pkg/fanal/handler/unpackaged/unpackaged_test.go b/pkg/fanal/handler/unpackaged/unpackaged_test.go index 8813e0eb3558..483e45b81b71 100644 --- a/pkg/fanal/handler/unpackaged/unpackaged_test.go +++ b/pkg/fanal/handler/unpackaged/unpackaged_test.go @@ -2,6 +2,7 @@ package unpackaged_test import ( "context" + "github.com/package-url/packageurl-go" "testing" "github.com/stretchr/testify/assert" @@ -45,6 +46,16 @@ func Test_unpackagedHook_Handle(t *testing.T) { Name: "github.com/spf13/cobra", Version: "1.5.0", Ref: "pkg:golang/github.com/spf13/cobra@1.5.0", + Identifier: types.PkgIdentifier{ + PURL: &types.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "github.com/spf13", + Name: "cobra", + Version: "1.5.0", + }, + }, + }, }, }, }, diff --git a/pkg/fanal/test/integration/library_test.go b/pkg/fanal/test/integration/library_test.go index e8be494a57d5..b802084ba314 100644 --- a/pkg/fanal/test/integration/library_test.go +++ b/pkg/fanal/test/integration/library_test.go @@ -362,6 +362,14 @@ func checkLangPkgs(detail types.ArtifactDetail, t *testing.T, tc testCase) { func checkPackageFromCommands(t *testing.T, detail types.ArtifactDetail, tc testCase) { if tc.wantPkgsFromCmds != "" { + if *update { + sort.Sort(types.Packages(detail.ImageConfig.Packages)) + b, err := json.MarshalIndent(detail.ImageConfig.Packages, "", " ") + require.NoError(t, err) + err = os.WriteFile(tc.wantPkgsFromCmds, b, 0666) + require.NoError(t, err) + return + } data, _ := os.ReadFile(tc.wantPkgsFromCmds) var expectedPkgsFromCmds []types.Package diff --git a/pkg/fanal/test/integration/testdata/goldens/packages/alpine-310.json.golden b/pkg/fanal/test/integration/testdata/goldens/packages/alpine-310.json.golden index 801661d8deed..ff6de7ec239e 100644 --- a/pkg/fanal/test/integration/testdata/goldens/packages/alpine-310.json.golden +++ b/pkg/fanal/test/integration/testdata/goldens/packages/alpine-310.json.golden @@ -2,6 +2,9 @@ { "ID": "alpine-baselayout@3.1.2-r0", "Name": "alpine-baselayout", + "Identifier": { + "PURL": "pkg:apk/alpine/alpine-baselayout@3.1.2-r0?arch=x86_64\u0026distro=3.10.2" + }, "Version": "3.1.2-r0", "Arch": "x86_64", "SrcName": "alpine-baselayout", @@ -49,6 +52,9 @@ { "ID": "alpine-keys@2.1-r2", "Name": "alpine-keys", + "Identifier": { + "PURL": "pkg:apk/alpine/alpine-keys@2.1-r2?arch=x86_64\u0026distro=3.10.2" + }, "Version": "2.1-r2", "Arch": "x86_64", "SrcName": "alpine-keys", @@ -85,6 +91,9 @@ { "ID": "apk-tools@2.10.4-r2", "Name": "apk-tools", + "Identifier": { + "PURL": "pkg:apk/alpine/apk-tools@2.10.4-r2?arch=x86_64\u0026distro=3.10.2" + }, "Version": "2.10.4-r2", "Arch": "x86_64", "SrcName": "apk-tools", @@ -110,6 +119,9 @@ { "ID": "busybox@1.30.1-r2", "Name": "busybox", + "Identifier": { + "PURL": "pkg:apk/alpine/busybox@1.30.1-r2?arch=x86_64\u0026distro=3.10.2" + }, "Version": "1.30.1-r2", "Arch": "x86_64", "SrcName": "busybox", @@ -137,6 +149,9 @@ { "ID": "ca-certificates-cacert@20190108-r0", "Name": "ca-certificates-cacert", + "Identifier": { + "PURL": "pkg:apk/alpine/ca-certificates-cacert@20190108-r0?arch=x86_64\u0026distro=3.10.2" + }, "Version": "20190108-r0", "Arch": "x86_64", "SrcName": "ca-certificates", @@ -157,6 +172,9 @@ { "ID": "libc-utils@0.7.1-r0", "Name": "libc-utils", + "Identifier": { + "PURL": "pkg:apk/alpine/libc-utils@0.7.1-r0?arch=x86_64\u0026distro=3.10.2" + }, "Version": "0.7.1-r0", "Arch": "x86_64", "SrcName": "libc-dev", @@ -176,6 +194,9 @@ { "ID": "libcrypto1.1@1.1.1c-r0", "Name": "libcrypto1.1", + "Identifier": { + "PURL": "pkg:apk/alpine/libcrypto1.1@1.1.1c-r0?arch=x86_64\u0026distro=3.10.2" + }, "Version": "1.1.1c-r0", "Arch": "x86_64", "SrcName": "openssl", @@ -209,6 +230,9 @@ { "ID": "libssl1.1@1.1.1c-r0", "Name": "libssl1.1", + "Identifier": { + "PURL": "pkg:apk/alpine/libssl1.1@1.1.1c-r0?arch=x86_64\u0026distro=3.10.2" + }, "Version": "1.1.1c-r0", "Arch": "x86_64", "SrcName": "openssl", @@ -233,6 +257,9 @@ { "ID": "libtls-standalone@2.9.1-r0", "Name": "libtls-standalone", + "Identifier": { + "PURL": "pkg:apk/alpine/libtls-standalone@2.9.1-r0?arch=x86_64\u0026distro=3.10.2" + }, "Version": "2.9.1-r0", "Arch": "x86_64", "SrcName": "libtls-standalone", @@ -259,6 +286,9 @@ { "ID": "musl@1.1.22-r3", "Name": "musl", + "Identifier": { + "PURL": "pkg:apk/alpine/musl@1.1.22-r3?arch=x86_64\u0026distro=3.10.2" + }, "Version": "1.1.22-r3", "Arch": "x86_64", "SrcName": "musl", @@ -279,6 +309,9 @@ { "ID": "musl-utils@1.1.22-r3", "Name": "musl-utils", + "Identifier": { + "PURL": "pkg:apk/alpine/musl-utils@1.1.22-r3?arch=x86_64\u0026distro=3.10.2" + }, "Version": "1.1.22-r3", "Arch": "x86_64", "SrcName": "musl", @@ -308,6 +341,9 @@ { "ID": "scanelf@1.2.3-r0", "Name": "scanelf", + "Identifier": { + "PURL": "pkg:apk/alpine/scanelf@1.2.3-r0?arch=x86_64\u0026distro=3.10.2" + }, "Version": "1.2.3-r0", "Arch": "x86_64", "SrcName": "pax-utils", @@ -330,6 +366,9 @@ { "ID": "ssl_client@1.30.1-r2", "Name": "ssl_client", + "Identifier": { + "PURL": "pkg:apk/alpine/ssl_client@1.30.1-r2?arch=x86_64\u0026distro=3.10.2" + }, "Version": "1.30.1-r2", "Arch": "x86_64", "SrcName": "busybox", @@ -353,6 +392,9 @@ { "ID": "zlib@1.2.11-r1", "Name": "zlib", + "Identifier": { + "PURL": "pkg:apk/alpine/zlib@1.2.11-r1?arch=x86_64\u0026distro=3.10.2" + }, "Version": "1.2.11-r1", "Arch": "x86_64", "SrcName": "zlib", diff --git a/pkg/fanal/test/integration/testdata/goldens/packages/vulnimage.json.golden b/pkg/fanal/test/integration/testdata/goldens/packages/vulnimage.json.golden index a4ca8c82c17d..d6e7df5676d6 100644 --- a/pkg/fanal/test/integration/testdata/goldens/packages/vulnimage.json.golden +++ b/pkg/fanal/test/integration/testdata/goldens/packages/vulnimage.json.golden @@ -2,6 +2,9 @@ { "ID": ".composer-phpext-rundeps@0", "Name": ".composer-phpext-rundeps", + "Identifier": { + "PURL": "pkg:apk/alpine/.composer-phpext-rundeps@0?arch=noarch\u0026distro=3.7.1" + }, "Version": "0", "Arch": "noarch", "DependsOn": [ @@ -18,6 +21,9 @@ { "ID": ".persistent-deps@0", "Name": ".persistent-deps", + "Identifier": { + "PURL": "pkg:apk/alpine/.persistent-deps@0?arch=noarch\u0026distro=3.7.1" + }, "Version": "0", "Arch": "noarch", "DependsOn": [ @@ -36,6 +42,9 @@ { "ID": ".php-rundeps@0", "Name": ".php-rundeps", + "Identifier": { + "PURL": "pkg:apk/alpine/.php-rundeps@0?arch=noarch\u0026distro=3.7.1" + }, "Version": "0", "Arch": "noarch", "DependsOn": [ @@ -57,6 +66,9 @@ { "ID": "alpine-baselayout@3.0.5-r2", "Name": "alpine-baselayout", + "Identifier": { + "PURL": "pkg:apk/alpine/alpine-baselayout@3.0.5-r2?arch=x86_64\u0026distro=3.7.1" + }, "Version": "3.0.5-r2", "Arch": "x86_64", "SrcName": "alpine-baselayout", @@ -105,6 +117,9 @@ { "ID": "alpine-keys@2.1-r1", "Name": "alpine-keys", + "Identifier": { + "PURL": "pkg:apk/alpine/alpine-keys@2.1-r1?arch=x86_64\u0026distro=3.7.1" + }, "Version": "2.1-r1", "Arch": "x86_64", "SrcName": "alpine-keys", @@ -141,6 +156,9 @@ { "ID": "apk-tools@2.10.1-r0", "Name": "apk-tools", + "Identifier": { + "PURL": "pkg:apk/alpine/apk-tools@2.10.1-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "2.10.1-r0", "Arch": "x86_64", "SrcName": "apk-tools", @@ -166,6 +184,9 @@ { "ID": "apr@1.6.3-r0", "Name": "apr", + "Identifier": { + "PURL": "pkg:apk/alpine/apr@1.6.3-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "1.6.3-r0", "Arch": "x86_64", "SrcName": "apr", @@ -191,6 +212,9 @@ { "ID": "apr-util@1.6.1-r1", "Name": "apr-util", + "Identifier": { + "PURL": "pkg:apk/alpine/apr-util@1.6.1-r1?arch=x86_64\u0026distro=3.7.1" + }, "Version": "1.6.1-r1", "Arch": "x86_64", "SrcName": "apr-util", @@ -219,6 +243,9 @@ { "ID": "bash@4.4.19-r1", "Name": "bash", + "Identifier": { + "PURL": "pkg:apk/alpine/bash@4.4.19-r1?arch=x86_64\u0026distro=3.7.1" + }, "Version": "4.4.19-r1", "Arch": "x86_64", "SrcName": "bash", @@ -330,6 +357,9 @@ { "ID": "busybox@1.27.2-r11", "Name": "busybox", + "Identifier": { + "PURL": "pkg:apk/alpine/busybox@1.27.2-r11?arch=x86_64\u0026distro=3.7.1" + }, "Version": "1.27.2-r11", "Arch": "x86_64", "SrcName": "busybox", @@ -357,6 +387,9 @@ { "ID": "ca-certificates@20171114-r0", "Name": "ca-certificates", + "Identifier": { + "PURL": "pkg:apk/alpine/ca-certificates@20171114-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "20171114-r0", "Arch": "x86_64", "SrcName": "ca-certificates", @@ -537,6 +570,9 @@ { "ID": "curl@7.61.0-r0", "Name": "curl", + "Identifier": { + "PURL": "pkg:apk/alpine/curl@7.61.0-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "7.61.0-r0", "Arch": "x86_64", "SrcName": "curl", @@ -562,6 +598,9 @@ { "ID": "db@5.3.28-r0", "Name": "db", + "Identifier": { + "PURL": "pkg:apk/alpine/db@5.3.28-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "5.3.28-r0", "Arch": "x86_64", "SrcName": "db", @@ -584,6 +623,9 @@ { "ID": "expat@2.2.5-r0", "Name": "expat", + "Identifier": { + "PURL": "pkg:apk/alpine/expat@2.2.5-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "2.2.5-r0", "Arch": "x86_64", "SrcName": "expat", @@ -608,6 +650,9 @@ { "ID": "gdbm@1.13-r1", "Name": "gdbm", + "Identifier": { + "PURL": "pkg:apk/alpine/gdbm@1.13-r1?arch=x86_64\u0026distro=3.7.1" + }, "Version": "1.13-r1", "Arch": "x86_64", "SrcName": "gdbm", @@ -636,6 +681,9 @@ { "ID": "git@2.15.2-r0", "Name": "git", + "Identifier": { + "PURL": "pkg:apk/alpine/git@2.15.2-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "2.15.2-r0", "Arch": "x86_64", "SrcName": "git", @@ -852,6 +900,9 @@ { "ID": "libbz2@1.0.6-r6", "Name": "libbz2", + "Identifier": { + "PURL": "pkg:apk/alpine/libbz2@1.0.6-r6?arch=x86_64\u0026distro=3.7.1" + }, "Version": "1.0.6-r6", "Arch": "x86_64", "SrcName": "bzip2", @@ -875,6 +926,9 @@ { "ID": "libc-utils@0.7.1-r0", "Name": "libc-utils", + "Identifier": { + "PURL": "pkg:apk/alpine/libc-utils@0.7.1-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "0.7.1-r0", "Arch": "x86_64", "SrcName": "libc-dev", @@ -894,6 +948,9 @@ { "ID": "libcurl@7.61.1-r0", "Name": "libcurl", + "Identifier": { + "PURL": "pkg:apk/alpine/libcurl@7.61.1-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "7.61.1-r0", "Arch": "x86_64", "SrcName": "curl", @@ -922,6 +979,9 @@ { "ID": "libedit@20170329.3.1-r3", "Name": "libedit", + "Identifier": { + "PURL": "pkg:apk/alpine/libedit@20170329.3.1-r3?arch=x86_64\u0026distro=3.7.1" + }, "Version": "20170329.3.1-r3", "Arch": "x86_64", "SrcName": "libedit", @@ -946,6 +1006,9 @@ { "ID": "libffi@3.2.1-r4", "Name": "libffi", + "Identifier": { + "PURL": "pkg:apk/alpine/libffi@3.2.1-r4?arch=x86_64\u0026distro=3.7.1" + }, "Version": "3.2.1-r4", "Arch": "x86_64", "SrcName": "libffi", @@ -969,6 +1032,9 @@ { "ID": "libressl@2.6.5-r0", "Name": "libressl", + "Identifier": { + "PURL": "pkg:apk/alpine/libressl@2.6.5-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "2.6.5-r0", "Arch": "x86_64", "SrcName": "libressl", @@ -995,6 +1061,9 @@ { "ID": "libressl2.6-libcrypto@2.6.5-r0", "Name": "libressl2.6-libcrypto", + "Identifier": { + "PURL": "pkg:apk/alpine/libressl2.6-libcrypto@2.6.5-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "2.6.5-r0", "Arch": "x86_64", "SrcName": "libressl", @@ -1023,6 +1092,9 @@ { "ID": "libressl2.6-libssl@2.6.5-r0", "Name": "libressl2.6-libssl", + "Identifier": { + "PURL": "pkg:apk/alpine/libressl2.6-libssl@2.6.5-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "2.6.5-r0", "Arch": "x86_64", "SrcName": "libressl", @@ -1049,6 +1121,9 @@ { "ID": "libressl2.6-libtls@2.6.5-r0", "Name": "libressl2.6-libtls", + "Identifier": { + "PURL": "pkg:apk/alpine/libressl2.6-libtls@2.6.5-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "2.6.5-r0", "Arch": "x86_64", "SrcName": "libressl", @@ -1076,6 +1151,9 @@ { "ID": "libsasl@2.1.26-r11", "Name": "libsasl", + "Identifier": { + "PURL": "pkg:apk/alpine/libsasl@2.1.26-r11?arch=x86_64\u0026distro=3.7.1" + }, "Version": "2.1.26-r11", "Arch": "x86_64", "SrcName": "cyrus-sasl", @@ -1109,6 +1187,9 @@ { "ID": "libsodium@1.0.15-r0", "Name": "libsodium", + "Identifier": { + "PURL": "pkg:apk/alpine/libsodium@1.0.15-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "1.0.15-r0", "Arch": "x86_64", "SrcName": "libsodium", @@ -1132,6 +1213,9 @@ { "ID": "libssh2@1.8.0-r2", "Name": "libssh2", + "Identifier": { + "PURL": "pkg:apk/alpine/libssh2@1.8.0-r2?arch=x86_64\u0026distro=3.7.1" + }, "Version": "1.8.0-r2", "Arch": "x86_64", "SrcName": "libssh2", @@ -1157,6 +1241,9 @@ { "ID": "libuuid@2.31-r0", "Name": "libuuid", + "Identifier": { + "PURL": "pkg:apk/alpine/libuuid@2.31-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "2.31-r0", "Arch": "x86_64", "SrcName": "util-linux", @@ -1185,6 +1272,9 @@ { "ID": "libxml2@2.9.7-r0", "Name": "libxml2", + "Identifier": { + "PURL": "pkg:apk/alpine/libxml2@2.9.7-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "2.9.7-r0", "Arch": "x86_64", "SrcName": "libxml2", @@ -1209,6 +1299,9 @@ { "ID": "mercurial@4.5.2-r0", "Name": "mercurial", + "Identifier": { + "PURL": "pkg:apk/alpine/mercurial@4.5.2-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "4.5.2-r0", "Arch": "x86_64", "SrcName": "mercurial", @@ -1950,6 +2043,9 @@ { "ID": "musl@1.1.18-r3", "Name": "musl", + "Identifier": { + "PURL": "pkg:apk/alpine/musl@1.1.18-r3?arch=x86_64\u0026distro=3.7.1" + }, "Version": "1.1.18-r3", "Arch": "x86_64", "SrcName": "musl", @@ -1970,6 +2066,9 @@ { "ID": "musl-utils@1.1.18-r3", "Name": "musl-utils", + "Identifier": { + "PURL": "pkg:apk/alpine/musl-utils@1.1.18-r3?arch=x86_64\u0026distro=3.7.1" + }, "Version": "1.1.18-r3", "Arch": "x86_64", "SrcName": "musl", @@ -1999,6 +2098,9 @@ { "ID": "ncurses-libs@6.0_p20171125-r1", "Name": "ncurses-libs", + "Identifier": { + "PURL": "pkg:apk/alpine/ncurses-libs@6.0_p20171125-r1?arch=x86_64\u0026distro=3.7.1" + }, "Version": "6.0_p20171125-r1", "Arch": "x86_64", "SrcName": "ncurses", @@ -2031,6 +2133,9 @@ { "ID": "ncurses-terminfo@6.0_p20171125-r1", "Name": "ncurses-terminfo", + "Identifier": { + "PURL": "pkg:apk/alpine/ncurses-terminfo@6.0_p20171125-r1?arch=x86_64\u0026distro=3.7.1" + }, "Version": "6.0_p20171125-r1", "Arch": "x86_64", "SrcName": "ncurses", @@ -4781,6 +4886,9 @@ { "ID": "ncurses-terminfo-base@6.0_p20171125-r1", "Name": "ncurses-terminfo-base", + "Identifier": { + "PURL": "pkg:apk/alpine/ncurses-terminfo-base@6.0_p20171125-r1?arch=x86_64\u0026distro=3.7.1" + }, "Version": "6.0_p20171125-r1", "Arch": "x86_64", "SrcName": "ncurses", @@ -4813,6 +4921,9 @@ { "ID": "openssh@7.5_p1-r9", "Name": "openssh", + "Identifier": { + "PURL": "pkg:apk/alpine/openssh@7.5_p1-r9?arch=x86_64\u0026distro=3.7.1" + }, "Version": "7.5_p1-r9", "Arch": "x86_64", "SrcName": "openssh", @@ -4839,6 +4950,9 @@ { "ID": "openssh-client@7.5_p1-r9", "Name": "openssh-client", + "Identifier": { + "PURL": "pkg:apk/alpine/openssh-client@7.5_p1-r9?arch=x86_64\u0026distro=3.7.1" + }, "Version": "7.5_p1-r9", "Arch": "x86_64", "SrcName": "openssh", @@ -4874,6 +4988,9 @@ { "ID": "openssh-keygen@7.5_p1-r9", "Name": "openssh-keygen", + "Identifier": { + "PURL": "pkg:apk/alpine/openssh-keygen@7.5_p1-r9?arch=x86_64\u0026distro=3.7.1" + }, "Version": "7.5_p1-r9", "Arch": "x86_64", "SrcName": "openssh", @@ -4897,6 +5014,9 @@ { "ID": "openssh-server@7.5_p1-r9", "Name": "openssh-server", + "Identifier": { + "PURL": "pkg:apk/alpine/openssh-server@7.5_p1-r9?arch=x86_64\u0026distro=3.7.1" + }, "Version": "7.5_p1-r9", "Arch": "x86_64", "SrcName": "openssh", @@ -4923,6 +5043,9 @@ { "ID": "openssh-server-common@7.5_p1-r9", "Name": "openssh-server-common", + "Identifier": { + "PURL": "pkg:apk/alpine/openssh-server-common@7.5_p1-r9?arch=x86_64\u0026distro=3.7.1" + }, "Version": "7.5_p1-r9", "Arch": "x86_64", "SrcName": "openssh", @@ -4944,6 +5067,9 @@ { "ID": "openssh-sftp-server@7.5_p1-r9", "Name": "openssh-sftp-server", + "Identifier": { + "PURL": "pkg:apk/alpine/openssh-sftp-server@7.5_p1-r9?arch=x86_64\u0026distro=3.7.1" + }, "Version": "7.5_p1-r9", "Arch": "x86_64", "SrcName": "openssh", @@ -4966,6 +5092,9 @@ { "ID": "patch@2.7.5-r2", "Name": "patch", + "Identifier": { + "PURL": "pkg:apk/alpine/patch@2.7.5-r2?arch=x86_64\u0026distro=3.7.1" + }, "Version": "2.7.5-r2", "Arch": "x86_64", "SrcName": "patch", @@ -4988,6 +5117,9 @@ { "ID": "pcre2@10.30-r0", "Name": "pcre2", + "Identifier": { + "PURL": "pkg:apk/alpine/pcre2@10.30-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "10.30-r0", "Arch": "x86_64", "SrcName": "pcre2", @@ -5013,6 +5145,9 @@ { "ID": "pkgconf@1.3.10-r0", "Name": "pkgconf", + "Identifier": { + "PURL": "pkg:apk/alpine/pkgconf@1.3.10-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "1.3.10-r0", "Arch": "x86_64", "SrcName": "pkgconf", @@ -5039,6 +5174,9 @@ { "ID": "python2@2.7.15-r2", "Name": "python2", + "Identifier": { + "PURL": "pkg:apk/alpine/python2@2.7.15-r2?arch=x86_64\u0026distro=3.7.1" + }, "Version": "2.7.15-r2", "Arch": "x86_64", "SrcName": "python2", @@ -7481,6 +7619,9 @@ { "ID": "readline@7.0.003-r0", "Name": "readline", + "Identifier": { + "PURL": "pkg:apk/alpine/readline@7.0.003-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "7.0.003-r0", "Arch": "x86_64", "SrcName": "readline", @@ -7505,6 +7646,9 @@ { "ID": "scanelf@1.2.2-r1", "Name": "scanelf", + "Identifier": { + "PURL": "pkg:apk/alpine/scanelf@1.2.2-r1?arch=x86_64\u0026distro=3.7.1" + }, "Version": "1.2.2-r1", "Arch": "x86_64", "SrcName": "pax-utils", @@ -7527,6 +7671,9 @@ { "ID": "serf@1.3.9-r3", "Name": "serf", + "Identifier": { + "PURL": "pkg:apk/alpine/serf@1.3.9-r3?arch=x86_64\u0026distro=3.7.1" + }, "Version": "1.3.9-r3", "Arch": "x86_64", "SrcName": "serf", @@ -7555,6 +7702,9 @@ { "ID": "sqlite-libs@3.21.0-r1", "Name": "sqlite-libs", + "Identifier": { + "PURL": "pkg:apk/alpine/sqlite-libs@3.21.0-r1?arch=x86_64\u0026distro=3.7.1" + }, "Version": "3.21.0-r1", "Arch": "x86_64", "SrcName": "sqlite", @@ -7578,6 +7728,9 @@ { "ID": "ssl_client@1.27.2-r11", "Name": "ssl_client", + "Identifier": { + "PURL": "pkg:apk/alpine/ssl_client@1.27.2-r11?arch=x86_64\u0026distro=3.7.1" + }, "Version": "1.27.2-r11", "Arch": "x86_64", "SrcName": "busybox", @@ -7601,6 +7754,9 @@ { "ID": "subversion@1.9.7-r0", "Name": "subversion", + "Identifier": { + "PURL": "pkg:apk/alpine/subversion@1.9.7-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "1.9.7-r0", "Arch": "x86_64", "SrcName": "subversion", @@ -7656,6 +7812,9 @@ { "ID": "subversion-libs@1.9.7-r0", "Name": "subversion-libs", + "Identifier": { + "PURL": "pkg:apk/alpine/subversion-libs@1.9.7-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "1.9.7-r0", "Arch": "x86_64", "SrcName": "subversion", @@ -7716,6 +7875,9 @@ { "ID": "tar@1.29-r1", "Name": "tar", + "Identifier": { + "PURL": "pkg:apk/alpine/tar@1.29-r1?arch=x86_64\u0026distro=3.7.1" + }, "Version": "1.29-r1", "Arch": "x86_64", "SrcName": "tar", @@ -7740,6 +7902,9 @@ { "ID": "tini@0.16.1-r0", "Name": "tini", + "Identifier": { + "PURL": "pkg:apk/alpine/tini@0.16.1-r0?arch=x86_64\u0026distro=3.7.1" + }, "Version": "0.16.1-r0", "Arch": "x86_64", "SrcName": "tini", @@ -7762,6 +7927,9 @@ { "ID": "xz@5.2.3-r1", "Name": "xz", + "Identifier": { + "PURL": "pkg:apk/alpine/xz@5.2.3-r1?arch=x86_64\u0026distro=3.7.1" + }, "Version": "5.2.3-r1", "Arch": "x86_64", "SrcName": "xz", @@ -7807,6 +7975,9 @@ { "ID": "xz-libs@5.2.3-r1", "Name": "xz-libs", + "Identifier": { + "PURL": "pkg:apk/alpine/xz-libs@5.2.3-r1?arch=x86_64\u0026distro=3.7.1" + }, "Version": "5.2.3-r1", "Arch": "x86_64", "SrcName": "xz", @@ -7830,6 +8001,9 @@ { "ID": "zlib@1.2.11-r1", "Name": "zlib", + "Identifier": { + "PURL": "pkg:apk/alpine/zlib@1.2.11-r1?arch=x86_64\u0026distro=3.7.1" + }, "Version": "1.2.11-r1", "Arch": "x86_64", "SrcName": "zlib", diff --git a/pkg/fanal/test/integration/testdata/goldens/vuln-image1.2.3.expectedlibs.golden b/pkg/fanal/test/integration/testdata/goldens/vuln-image1.2.3.expectedlibs.golden index f1c30482504e..fdd72301280c 100644 --- a/pkg/fanal/test/integration/testdata/goldens/vuln-image1.2.3.expectedlibs.golden +++ b/pkg/fanal/test/integration/testdata/goldens/vuln-image1.2.3.expectedlibs.golden @@ -6,6 +6,9 @@ { "ID": "actioncable@5.2.3", "Name": "actioncable", + "Identifier": { + "PURL": "pkg:gem/actioncable@5.2.3" + }, "Version": "5.2.3", "Indirect": true, "DependsOn": [ @@ -24,6 +27,9 @@ { "ID": "actionmailer@5.2.3", "Name": "actionmailer", + "Identifier": { + "PURL": "pkg:gem/actionmailer@5.2.3" + }, "Version": "5.2.3", "Indirect": true, "DependsOn": [ @@ -44,6 +50,9 @@ { "ID": "actionpack@5.2.3", "Name": "actionpack", + "Identifier": { + "PURL": "pkg:gem/actionpack@5.2.3" + }, "Version": "5.2.3", "Indirect": true, "DependsOn": [ @@ -65,6 +74,9 @@ { "ID": "actionview@5.2.3", "Name": "actionview", + "Identifier": { + "PURL": "pkg:gem/actionview@5.2.3" + }, "Version": "5.2.3", "Indirect": true, "DependsOn": [ @@ -85,6 +97,9 @@ { "ID": "activejob@5.2.3", "Name": "activejob", + "Identifier": { + "PURL": "pkg:gem/activejob@5.2.3" + }, "Version": "5.2.3", "Indirect": true, "DependsOn": [ @@ -102,6 +117,9 @@ { "ID": "activemodel@5.2.3", "Name": "activemodel", + "Identifier": { + "PURL": "pkg:gem/activemodel@5.2.3" + }, "Version": "5.2.3", "Indirect": true, "DependsOn": [ @@ -118,6 +136,9 @@ { "ID": "activerecord@5.2.3", "Name": "activerecord", + "Identifier": { + "PURL": "pkg:gem/activerecord@5.2.3" + }, "Version": "5.2.3", "Indirect": true, "DependsOn": [ @@ -136,6 +157,9 @@ { "ID": "activestorage@5.2.3", "Name": "activestorage", + "Identifier": { + "PURL": "pkg:gem/activestorage@5.2.3" + }, "Version": "5.2.3", "Indirect": true, "DependsOn": [ @@ -154,6 +178,9 @@ { "ID": "activesupport@5.2.3", "Name": "activesupport", + "Identifier": { + "PURL": "pkg:gem/activesupport@5.2.3" + }, "Version": "5.2.3", "Indirect": true, "DependsOn": [ @@ -173,6 +200,9 @@ { "ID": "arel@9.0.0", "Name": "arel", + "Identifier": { + "PURL": "pkg:gem/arel@9.0.0" + }, "Version": "9.0.0", "Indirect": true, "Layer": {}, @@ -186,6 +216,9 @@ { "ID": "ast@2.4.0", "Name": "ast", + "Identifier": { + "PURL": "pkg:gem/ast@2.4.0" + }, "Version": "2.4.0", "Indirect": true, "Layer": {}, @@ -199,6 +232,9 @@ { "ID": "builder@3.2.3", "Name": "builder", + "Identifier": { + "PURL": "pkg:gem/builder@3.2.3" + }, "Version": "3.2.3", "Indirect": true, "Layer": {}, @@ -212,6 +248,9 @@ { "ID": "coderay@1.1.2", "Name": "coderay", + "Identifier": { + "PURL": "pkg:gem/coderay@1.1.2" + }, "Version": "1.1.2", "Indirect": true, "Layer": {}, @@ -225,6 +264,9 @@ { "ID": "concurrent-ruby@1.1.5", "Name": "concurrent-ruby", + "Identifier": { + "PURL": "pkg:gem/concurrent-ruby@1.1.5" + }, "Version": "1.1.5", "Indirect": true, "Layer": {}, @@ -238,6 +280,9 @@ { "ID": "crass@1.0.4", "Name": "crass", + "Identifier": { + "PURL": "pkg:gem/crass@1.0.4" + }, "Version": "1.0.4", "Indirect": true, "Layer": {}, @@ -251,6 +296,9 @@ { "ID": "dotenv@2.7.2", "Name": "dotenv", + "Identifier": { + "PURL": "pkg:gem/dotenv@2.7.2" + }, "Version": "2.7.2", "Layer": {}, "Locations": [ @@ -263,6 +311,9 @@ { "ID": "erubi@1.8.0", "Name": "erubi", + "Identifier": { + "PURL": "pkg:gem/erubi@1.8.0" + }, "Version": "1.8.0", "Indirect": true, "Layer": {}, @@ -276,6 +327,9 @@ { "ID": "faker@1.9.3", "Name": "faker", + "Identifier": { + "PURL": "pkg:gem/faker@1.9.3" + }, "Version": "1.9.3", "DependsOn": [ "i18n@1.6.0" @@ -291,6 +345,9 @@ { "ID": "globalid@0.4.2", "Name": "globalid", + "Identifier": { + "PURL": "pkg:gem/globalid@0.4.2" + }, "Version": "0.4.2", "Indirect": true, "DependsOn": [ @@ -307,6 +364,9 @@ { "ID": "i18n@1.6.0", "Name": "i18n", + "Identifier": { + "PURL": "pkg:gem/i18n@1.6.0" + }, "Version": "1.6.0", "Indirect": true, "DependsOn": [ @@ -323,6 +383,9 @@ { "ID": "jaro_winkler@1.5.2", "Name": "jaro_winkler", + "Identifier": { + "PURL": "pkg:gem/jaro_winkler@1.5.2" + }, "Version": "1.5.2", "Indirect": true, "Layer": {}, @@ -336,6 +399,9 @@ { "ID": "json@2.2.0", "Name": "json", + "Identifier": { + "PURL": "pkg:gem/json@2.2.0" + }, "Version": "2.2.0", "Layer": {}, "Locations": [ @@ -348,6 +414,9 @@ { "ID": "loofah@2.2.3", "Name": "loofah", + "Identifier": { + "PURL": "pkg:gem/loofah@2.2.3" + }, "Version": "2.2.3", "Indirect": true, "DependsOn": [ @@ -365,6 +434,9 @@ { "ID": "mail@2.7.1", "Name": "mail", + "Identifier": { + "PURL": "pkg:gem/mail@2.7.1" + }, "Version": "2.7.1", "Indirect": true, "DependsOn": [ @@ -381,6 +453,9 @@ { "ID": "marcel@0.3.3", "Name": "marcel", + "Identifier": { + "PURL": "pkg:gem/marcel@0.3.3" + }, "Version": "0.3.3", "Indirect": true, "DependsOn": [ @@ -397,6 +472,9 @@ { "ID": "method_source@0.9.2", "Name": "method_source", + "Identifier": { + "PURL": "pkg:gem/method_source@0.9.2" + }, "Version": "0.9.2", "Indirect": true, "Layer": {}, @@ -410,6 +488,9 @@ { "ID": "mimemagic@0.3.3", "Name": "mimemagic", + "Identifier": { + "PURL": "pkg:gem/mimemagic@0.3.3" + }, "Version": "0.3.3", "Indirect": true, "Layer": {}, @@ -423,6 +504,9 @@ { "ID": "mini_mime@1.0.1", "Name": "mini_mime", + "Identifier": { + "PURL": "pkg:gem/mini_mime@1.0.1" + }, "Version": "1.0.1", "Indirect": true, "Layer": {}, @@ -436,6 +520,9 @@ { "ID": "mini_portile2@2.4.0", "Name": "mini_portile2", + "Identifier": { + "PURL": "pkg:gem/mini_portile2@2.4.0" + }, "Version": "2.4.0", "Indirect": true, "Layer": {}, @@ -449,6 +536,9 @@ { "ID": "minitest@5.11.3", "Name": "minitest", + "Identifier": { + "PURL": "pkg:gem/minitest@5.11.3" + }, "Version": "5.11.3", "Indirect": true, "Layer": {}, @@ -462,6 +552,9 @@ { "ID": "nio4r@2.3.1", "Name": "nio4r", + "Identifier": { + "PURL": "pkg:gem/nio4r@2.3.1" + }, "Version": "2.3.1", "Indirect": true, "Layer": {}, @@ -475,6 +568,9 @@ { "ID": "nokogiri@1.10.3", "Name": "nokogiri", + "Identifier": { + "PURL": "pkg:gem/nokogiri@1.10.3" + }, "Version": "1.10.3", "Indirect": true, "DependsOn": [ @@ -491,6 +587,9 @@ { "ID": "parallel@1.17.0", "Name": "parallel", + "Identifier": { + "PURL": "pkg:gem/parallel@1.17.0" + }, "Version": "1.17.0", "Indirect": true, "Layer": {}, @@ -504,6 +603,9 @@ { "ID": "parser@2.6.3.0", "Name": "parser", + "Identifier": { + "PURL": "pkg:gem/parser@2.6.3.0" + }, "Version": "2.6.3.0", "Indirect": true, "DependsOn": [ @@ -520,6 +622,9 @@ { "ID": "pry@0.12.2", "Name": "pry", + "Identifier": { + "PURL": "pkg:gem/pry@0.12.2" + }, "Version": "0.12.2", "DependsOn": [ "coderay@1.1.2", @@ -536,6 +641,9 @@ { "ID": "psych@3.1.0", "Name": "psych", + "Identifier": { + "PURL": "pkg:gem/psych@3.1.0" + }, "Version": "3.1.0", "Indirect": true, "Layer": {}, @@ -549,6 +657,9 @@ { "ID": "rack@2.0.7", "Name": "rack", + "Identifier": { + "PURL": "pkg:gem/rack@2.0.7" + }, "Version": "2.0.7", "Indirect": true, "Layer": {}, @@ -562,6 +673,9 @@ { "ID": "rack-test@1.1.0", "Name": "rack-test", + "Identifier": { + "PURL": "pkg:gem/rack-test@1.1.0" + }, "Version": "1.1.0", "Indirect": true, "DependsOn": [ @@ -578,6 +692,9 @@ { "ID": "rails@5.2.0", "Name": "rails", + "Identifier": { + "PURL": "pkg:gem/rails@5.2.0" + }, "Version": "5.2.0", "DependsOn": [ "actioncable@5.2.3", @@ -603,6 +720,9 @@ { "ID": "rails-dom-testing@2.0.3", "Name": "rails-dom-testing", + "Identifier": { + "PURL": "pkg:gem/rails-dom-testing@2.0.3" + }, "Version": "2.0.3", "Indirect": true, "DependsOn": [ @@ -620,6 +740,9 @@ { "ID": "rails-html-sanitizer@1.0.3", "Name": "rails-html-sanitizer", + "Identifier": { + "PURL": "pkg:gem/rails-html-sanitizer@1.0.3" + }, "Version": "1.0.3", "Indirect": true, "DependsOn": [ @@ -636,6 +759,9 @@ { "ID": "railties@5.2.3", "Name": "railties", + "Identifier": { + "PURL": "pkg:gem/railties@5.2.3" + }, "Version": "5.2.3", "Indirect": true, "DependsOn": [ @@ -656,6 +782,9 @@ { "ID": "rainbow@3.0.0", "Name": "rainbow", + "Identifier": { + "PURL": "pkg:gem/rainbow@3.0.0" + }, "Version": "3.0.0", "Indirect": true, "Layer": {}, @@ -669,6 +798,9 @@ { "ID": "rake@12.3.2", "Name": "rake", + "Identifier": { + "PURL": "pkg:gem/rake@12.3.2" + }, "Version": "12.3.2", "Indirect": true, "Layer": {}, @@ -682,6 +814,9 @@ { "ID": "rubocop@0.67.2", "Name": "rubocop", + "Identifier": { + "PURL": "pkg:gem/rubocop@0.67.2" + }, "Version": "0.67.2", "DependsOn": [ "jaro_winkler@1.5.2", @@ -703,6 +838,9 @@ { "ID": "ruby-progressbar@1.10.0", "Name": "ruby-progressbar", + "Identifier": { + "PURL": "pkg:gem/ruby-progressbar@1.10.0" + }, "Version": "1.10.0", "Indirect": true, "Layer": {}, @@ -716,6 +854,9 @@ { "ID": "sprockets@3.7.2", "Name": "sprockets", + "Identifier": { + "PURL": "pkg:gem/sprockets@3.7.2" + }, "Version": "3.7.2", "Indirect": true, "DependsOn": [ @@ -733,6 +874,9 @@ { "ID": "sprockets-rails@3.2.1", "Name": "sprockets-rails", + "Identifier": { + "PURL": "pkg:gem/sprockets-rails@3.2.1" + }, "Version": "3.2.1", "Indirect": true, "DependsOn": [ @@ -751,6 +895,9 @@ { "ID": "thor@0.20.3", "Name": "thor", + "Identifier": { + "PURL": "pkg:gem/thor@0.20.3" + }, "Version": "0.20.3", "Indirect": true, "Layer": {}, @@ -764,6 +911,9 @@ { "ID": "thread_safe@0.3.6", "Name": "thread_safe", + "Identifier": { + "PURL": "pkg:gem/thread_safe@0.3.6" + }, "Version": "0.3.6", "Indirect": true, "Layer": {}, @@ -777,6 +927,9 @@ { "ID": "tzinfo@1.2.5", "Name": "tzinfo", + "Identifier": { + "PURL": "pkg:gem/tzinfo@1.2.5" + }, "Version": "1.2.5", "Indirect": true, "DependsOn": [ @@ -793,6 +946,9 @@ { "ID": "unicode-display_width@1.5.0", "Name": "unicode-display_width", + "Identifier": { + "PURL": "pkg:gem/unicode-display_width@1.5.0" + }, "Version": "1.5.0", "Indirect": true, "Layer": {}, @@ -806,6 +962,9 @@ { "ID": "websocket-driver@0.7.0", "Name": "websocket-driver", + "Identifier": { + "PURL": "pkg:gem/websocket-driver@0.7.0" + }, "Version": "0.7.0", "Indirect": true, "DependsOn": [ @@ -822,6 +981,9 @@ { "ID": "websocket-extensions@0.1.3", "Name": "websocket-extensions", + "Identifier": { + "PURL": "pkg:gem/websocket-extensions@0.1.3" + }, "Version": "0.1.3", "Indirect": true, "Layer": {}, @@ -841,6 +1003,9 @@ { "ID": "ammonia@1.9.0", "Name": "ammonia", + "Identifier": { + "PURL": "pkg:cargo/ammonia@1.9.0" + }, "Version": "1.9.0", "DependsOn": [ "html5ever@0.23.0", @@ -861,6 +1026,9 @@ { "ID": "autocfg@0.1.2", "Name": "autocfg", + "Identifier": { + "PURL": "pkg:cargo/autocfg@0.1.2" + }, "Version": "0.1.2", "Layer": {}, "Locations": [ @@ -873,6 +1041,9 @@ { "ID": "bitflags@0.7.0", "Name": "bitflags", + "Identifier": { + "PURL": "pkg:cargo/bitflags@0.7.0" + }, "Version": "0.7.0", "Layer": {}, "Locations": [ @@ -885,6 +1056,9 @@ { "ID": "bitflags@1.0.4", "Name": "bitflags", + "Identifier": { + "PURL": "pkg:cargo/bitflags@1.0.4" + }, "Version": "1.0.4", "Layer": {}, "Locations": [ @@ -897,6 +1071,9 @@ { "ID": "cfg-if@0.1.7", "Name": "cfg-if", + "Identifier": { + "PURL": "pkg:cargo/cfg-if@0.1.7" + }, "Version": "0.1.7", "Layer": {}, "Locations": [ @@ -909,6 +1086,9 @@ { "ID": "cloudabi@0.0.3", "Name": "cloudabi", + "Identifier": { + "PURL": "pkg:cargo/cloudabi@0.0.3" + }, "Version": "0.0.3", "DependsOn": [ "bitflags@1.0.4" @@ -924,6 +1104,9 @@ { "ID": "fuchsia-cprng@0.1.1", "Name": "fuchsia-cprng", + "Identifier": { + "PURL": "pkg:cargo/fuchsia-cprng@0.1.1" + }, "Version": "0.1.1", "Layer": {}, "Locations": [ @@ -936,6 +1119,9 @@ { "ID": "futf@0.1.4", "Name": "futf", + "Identifier": { + "PURL": "pkg:cargo/futf@0.1.4" + }, "Version": "0.1.4", "DependsOn": [ "mac@0.1.1", @@ -952,6 +1138,9 @@ { "ID": "gdi32-sys@0.2.0", "Name": "gdi32-sys", + "Identifier": { + "PURL": "pkg:cargo/gdi32-sys@0.2.0" + }, "Version": "0.2.0", "DependsOn": [ "winapi-build@0.1.1", @@ -968,6 +1157,9 @@ { "ID": "html5ever@0.23.0", "Name": "html5ever", + "Identifier": { + "PURL": "pkg:cargo/html5ever@0.23.0" + }, "Version": "0.23.0", "DependsOn": [ "log@0.4.6", @@ -988,6 +1180,9 @@ { "ID": "idna@0.1.5", "Name": "idna", + "Identifier": { + "PURL": "pkg:cargo/idna@0.1.5" + }, "Version": "0.1.5", "DependsOn": [ "matches@0.1.8", @@ -1005,6 +1200,9 @@ { "ID": "itoa@0.4.4", "Name": "itoa", + "Identifier": { + "PURL": "pkg:cargo/itoa@0.4.4" + }, "Version": "0.4.4", "Layer": {}, "Locations": [ @@ -1017,6 +1215,9 @@ { "ID": "kernel32-sys@0.2.2", "Name": "kernel32-sys", + "Identifier": { + "PURL": "pkg:cargo/kernel32-sys@0.2.2" + }, "Version": "0.2.2", "DependsOn": [ "winapi-build@0.1.1", @@ -1033,6 +1234,9 @@ { "ID": "lazy_static@0.2.11", "Name": "lazy_static", + "Identifier": { + "PURL": "pkg:cargo/lazy_static@0.2.11" + }, "Version": "0.2.11", "Layer": {}, "Locations": [ @@ -1045,6 +1249,9 @@ { "ID": "lazy_static@1.3.0", "Name": "lazy_static", + "Identifier": { + "PURL": "pkg:cargo/lazy_static@1.3.0" + }, "Version": "1.3.0", "Layer": {}, "Locations": [ @@ -1057,6 +1264,9 @@ { "ID": "libc@0.2.54", "Name": "libc", + "Identifier": { + "PURL": "pkg:cargo/libc@0.2.54" + }, "Version": "0.2.54", "Layer": {}, "Locations": [ @@ -1069,6 +1279,9 @@ { "ID": "libressl-pnacl-sys@2.1.6", "Name": "libressl-pnacl-sys", + "Identifier": { + "PURL": "pkg:cargo/libressl-pnacl-sys@2.1.6" + }, "Version": "2.1.6", "DependsOn": [ "pnacl-build-helper@1.4.11" @@ -1084,6 +1297,9 @@ { "ID": "log@0.4.6", "Name": "log", + "Identifier": { + "PURL": "pkg:cargo/log@0.4.6" + }, "Version": "0.4.6", "DependsOn": [ "cfg-if@0.1.7" @@ -1099,6 +1315,9 @@ { "ID": "mac@0.1.1", "Name": "mac", + "Identifier": { + "PURL": "pkg:cargo/mac@0.1.1" + }, "Version": "0.1.1", "Layer": {}, "Locations": [ @@ -1111,6 +1330,9 @@ { "ID": "maplit@1.0.1", "Name": "maplit", + "Identifier": { + "PURL": "pkg:cargo/maplit@1.0.1" + }, "Version": "1.0.1", "Layer": {}, "Locations": [ @@ -1123,6 +1345,9 @@ { "ID": "markup5ever@0.8.1", "Name": "markup5ever", + "Identifier": { + "PURL": "pkg:cargo/markup5ever@0.8.1" + }, "Version": "0.8.1", "DependsOn": [ "log@0.4.6", @@ -1146,6 +1371,9 @@ { "ID": "matches@0.1.8", "Name": "matches", + "Identifier": { + "PURL": "pkg:cargo/matches@0.1.8" + }, "Version": "0.1.8", "Layer": {}, "Locations": [ @@ -1158,6 +1386,9 @@ { "ID": "new_debug_unreachable@1.0.3", "Name": "new_debug_unreachable", + "Identifier": { + "PURL": "pkg:cargo/new_debug_unreachable@1.0.3" + }, "Version": "1.0.3", "Layer": {}, "Locations": [ @@ -1170,6 +1401,9 @@ { "ID": "normal@0.1.0", "Name": "normal", + "Identifier": { + "PURL": "pkg:cargo/normal@0.1.0" + }, "Version": "0.1.0", "DependsOn": [ "ammonia@2.0.0", @@ -1187,6 +1421,9 @@ { "ID": "openssl@0.8.3", "Name": "openssl", + "Identifier": { + "PURL": "pkg:cargo/openssl@0.8.3" + }, "Version": "0.8.3", "DependsOn": [ "bitflags@0.7.0", @@ -1205,6 +1442,9 @@ { "ID": "openssl-sys@0.7.17", "Name": "openssl-sys", + "Identifier": { + "PURL": "pkg:cargo/openssl-sys@0.7.17" + }, "Version": "0.7.17", "DependsOn": [ "gdi32-sys@0.2.0", @@ -1224,6 +1464,9 @@ { "ID": "percent-encoding@1.0.1", "Name": "percent-encoding", + "Identifier": { + "PURL": "pkg:cargo/percent-encoding@1.0.1" + }, "Version": "1.0.1", "Layer": {}, "Locations": [ @@ -1236,6 +1479,9 @@ { "ID": "phf@0.7.24", "Name": "phf", + "Identifier": { + "PURL": "pkg:cargo/phf@0.7.24" + }, "Version": "0.7.24", "DependsOn": [ "phf_shared@0.7.24" @@ -1251,6 +1497,9 @@ { "ID": "phf_codegen@0.7.24", "Name": "phf_codegen", + "Identifier": { + "PURL": "pkg:cargo/phf_codegen@0.7.24" + }, "Version": "0.7.24", "DependsOn": [ "phf_generator@0.7.24", @@ -1267,6 +1516,9 @@ { "ID": "phf_generator@0.7.24", "Name": "phf_generator", + "Identifier": { + "PURL": "pkg:cargo/phf_generator@0.7.24" + }, "Version": "0.7.24", "DependsOn": [ "phf_shared@0.7.24", @@ -1283,6 +1535,9 @@ { "ID": "phf_shared@0.7.24", "Name": "phf_shared", + "Identifier": { + "PURL": "pkg:cargo/phf_shared@0.7.24" + }, "Version": "0.7.24", "DependsOn": [ "siphasher@0.2.3" @@ -1298,6 +1553,9 @@ { "ID": "pkg-config@0.3.14", "Name": "pkg-config", + "Identifier": { + "PURL": "pkg:cargo/pkg-config@0.3.14" + }, "Version": "0.3.14", "Layer": {}, "Locations": [ @@ -1310,6 +1568,9 @@ { "ID": "pnacl-build-helper@1.4.11", "Name": "pnacl-build-helper", + "Identifier": { + "PURL": "pkg:cargo/pnacl-build-helper@1.4.11" + }, "Version": "1.4.11", "DependsOn": [ "tempdir@0.3.7", @@ -1326,6 +1587,9 @@ { "ID": "precomputed-hash@0.1.1", "Name": "precomputed-hash", + "Identifier": { + "PURL": "pkg:cargo/precomputed-hash@0.1.1" + }, "Version": "0.1.1", "Layer": {}, "Locations": [ @@ -1338,6 +1602,9 @@ { "ID": "proc-macro2@0.4.30", "Name": "proc-macro2", + "Identifier": { + "PURL": "pkg:cargo/proc-macro2@0.4.30" + }, "Version": "0.4.30", "DependsOn": [ "unicode-xid@0.1.0" @@ -1353,6 +1620,9 @@ { "ID": "quote@0.6.12", "Name": "quote", + "Identifier": { + "PURL": "pkg:cargo/quote@0.6.12" + }, "Version": "0.6.12", "DependsOn": [ "proc-macro2@0.4.30" @@ -1368,6 +1638,9 @@ { "ID": "rand@0.4.6", "Name": "rand", + "Identifier": { + "PURL": "pkg:cargo/rand@0.4.6" + }, "Version": "0.4.6", "DependsOn": [ "fuchsia-cprng@0.1.1", @@ -1387,6 +1660,9 @@ { "ID": "rand@0.6.5", "Name": "rand", + "Identifier": { + "PURL": "pkg:cargo/rand@0.6.5" + }, "Version": "0.6.5", "DependsOn": [ "autocfg@0.1.2", @@ -1412,6 +1688,9 @@ { "ID": "rand_chacha@0.1.1", "Name": "rand_chacha", + "Identifier": { + "PURL": "pkg:cargo/rand_chacha@0.1.1" + }, "Version": "0.1.1", "DependsOn": [ "autocfg@0.1.2", @@ -1428,6 +1707,9 @@ { "ID": "rand_core@0.3.1", "Name": "rand_core", + "Identifier": { + "PURL": "pkg:cargo/rand_core@0.3.1" + }, "Version": "0.3.1", "DependsOn": [ "rand_core@0.4.0" @@ -1443,6 +1725,9 @@ { "ID": "rand_core@0.4.0", "Name": "rand_core", + "Identifier": { + "PURL": "pkg:cargo/rand_core@0.4.0" + }, "Version": "0.4.0", "Layer": {}, "Locations": [ @@ -1455,6 +1740,9 @@ { "ID": "rand_hc@0.1.0", "Name": "rand_hc", + "Identifier": { + "PURL": "pkg:cargo/rand_hc@0.1.0" + }, "Version": "0.1.0", "DependsOn": [ "rand_core@0.3.1" @@ -1470,6 +1758,9 @@ { "ID": "rand_isaac@0.1.1", "Name": "rand_isaac", + "Identifier": { + "PURL": "pkg:cargo/rand_isaac@0.1.1" + }, "Version": "0.1.1", "DependsOn": [ "rand_core@0.3.1" @@ -1485,6 +1776,9 @@ { "ID": "rand_jitter@0.1.4", "Name": "rand_jitter", + "Identifier": { + "PURL": "pkg:cargo/rand_jitter@0.1.4" + }, "Version": "0.1.4", "DependsOn": [ "libc@0.2.54", @@ -1502,6 +1796,9 @@ { "ID": "rand_os@0.1.3", "Name": "rand_os", + "Identifier": { + "PURL": "pkg:cargo/rand_os@0.1.3" + }, "Version": "0.1.3", "DependsOn": [ "cloudabi@0.0.3", @@ -1522,6 +1819,9 @@ { "ID": "rand_pcg@0.1.2", "Name": "rand_pcg", + "Identifier": { + "PURL": "pkg:cargo/rand_pcg@0.1.2" + }, "Version": "0.1.2", "DependsOn": [ "autocfg@0.1.2", @@ -1538,6 +1838,9 @@ { "ID": "rand_xorshift@0.1.1", "Name": "rand_xorshift", + "Identifier": { + "PURL": "pkg:cargo/rand_xorshift@0.1.1" + }, "Version": "0.1.1", "DependsOn": [ "rand_core@0.3.1" @@ -1553,6 +1856,9 @@ { "ID": "rdrand@0.4.0", "Name": "rdrand", + "Identifier": { + "PURL": "pkg:cargo/rdrand@0.4.0" + }, "Version": "0.4.0", "DependsOn": [ "rand_core@0.3.1" @@ -1568,6 +1874,9 @@ { "ID": "remove_dir_all@0.5.1", "Name": "remove_dir_all", + "Identifier": { + "PURL": "pkg:cargo/remove_dir_all@0.5.1" + }, "Version": "0.5.1", "DependsOn": [ "winapi@0.3.7" @@ -1583,6 +1892,9 @@ { "ID": "ryu@0.2.8", "Name": "ryu", + "Identifier": { + "PURL": "pkg:cargo/ryu@0.2.8" + }, "Version": "0.2.8", "Layer": {}, "Locations": [ @@ -1595,6 +1907,9 @@ { "ID": "same-file@0.1.3", "Name": "same-file", + "Identifier": { + "PURL": "pkg:cargo/same-file@0.1.3" + }, "Version": "0.1.3", "DependsOn": [ "kernel32-sys@0.2.2", @@ -1611,6 +1926,9 @@ { "ID": "serde@1.0.91", "Name": "serde", + "Identifier": { + "PURL": "pkg:cargo/serde@1.0.91" + }, "Version": "1.0.91", "Layer": {}, "Locations": [ @@ -1623,6 +1941,9 @@ { "ID": "serde_derive@1.0.91", "Name": "serde_derive", + "Identifier": { + "PURL": "pkg:cargo/serde_derive@1.0.91" + }, "Version": "1.0.91", "DependsOn": [ "proc-macro2@0.4.30", @@ -1640,6 +1961,9 @@ { "ID": "serde_json@1.0.39", "Name": "serde_json", + "Identifier": { + "PURL": "pkg:cargo/serde_json@1.0.39" + }, "Version": "1.0.39", "DependsOn": [ "itoa@0.4.4", @@ -1657,6 +1981,9 @@ { "ID": "siphasher@0.2.3", "Name": "siphasher", + "Identifier": { + "PURL": "pkg:cargo/siphasher@0.2.3" + }, "Version": "0.2.3", "Layer": {}, "Locations": [ @@ -1669,6 +1996,9 @@ { "ID": "smallvec@0.6.9", "Name": "smallvec", + "Identifier": { + "PURL": "pkg:cargo/smallvec@0.6.9" + }, "Version": "0.6.9", "Layer": {}, "Locations": [ @@ -1681,6 +2011,9 @@ { "ID": "string_cache@0.7.3", "Name": "string_cache", + "Identifier": { + "PURL": "pkg:cargo/string_cache@0.7.3" + }, "Version": "0.7.3", "DependsOn": [ "lazy_static@1.3.0", @@ -1702,6 +2035,9 @@ { "ID": "string_cache_codegen@0.4.2", "Name": "string_cache_codegen", + "Identifier": { + "PURL": "pkg:cargo/string_cache_codegen@0.4.2" + }, "Version": "0.4.2", "DependsOn": [ "phf_generator@0.7.24", @@ -1721,6 +2057,9 @@ { "ID": "string_cache_shared@0.3.0", "Name": "string_cache_shared", + "Identifier": { + "PURL": "pkg:cargo/string_cache_shared@0.3.0" + }, "Version": "0.3.0", "Layer": {}, "Locations": [ @@ -1733,6 +2072,9 @@ { "ID": "syn@0.15.34", "Name": "syn", + "Identifier": { + "PURL": "pkg:cargo/syn@0.15.34" + }, "Version": "0.15.34", "DependsOn": [ "proc-macro2@0.4.30", @@ -1750,6 +2092,9 @@ { "ID": "tempdir@0.3.7", "Name": "tempdir", + "Identifier": { + "PURL": "pkg:cargo/tempdir@0.3.7" + }, "Version": "0.3.7", "DependsOn": [ "rand@0.4.6", @@ -1766,6 +2111,9 @@ { "ID": "tendril@0.4.1", "Name": "tendril", + "Identifier": { + "PURL": "pkg:cargo/tendril@0.4.1" + }, "Version": "0.4.1", "DependsOn": [ "futf@0.1.4", @@ -1783,6 +2131,9 @@ { "ID": "unicode-bidi@0.3.4", "Name": "unicode-bidi", + "Identifier": { + "PURL": "pkg:cargo/unicode-bidi@0.3.4" + }, "Version": "0.3.4", "DependsOn": [ "matches@0.1.8" @@ -1798,6 +2149,9 @@ { "ID": "unicode-normalization@0.1.8", "Name": "unicode-normalization", + "Identifier": { + "PURL": "pkg:cargo/unicode-normalization@0.1.8" + }, "Version": "0.1.8", "DependsOn": [ "smallvec@0.6.9" @@ -1813,6 +2167,9 @@ { "ID": "unicode-xid@0.1.0", "Name": "unicode-xid", + "Identifier": { + "PURL": "pkg:cargo/unicode-xid@0.1.0" + }, "Version": "0.1.0", "Layer": {}, "Locations": [ @@ -1825,6 +2182,9 @@ { "ID": "url@1.7.2", "Name": "url", + "Identifier": { + "PURL": "pkg:cargo/url@1.7.2" + }, "Version": "1.7.2", "DependsOn": [ "idna@0.1.5", @@ -1842,6 +2202,9 @@ { "ID": "user32-sys@0.2.0", "Name": "user32-sys", + "Identifier": { + "PURL": "pkg:cargo/user32-sys@0.2.0" + }, "Version": "0.2.0", "DependsOn": [ "winapi-build@0.1.1", @@ -1858,6 +2221,9 @@ { "ID": "utf-8@0.7.5", "Name": "utf-8", + "Identifier": { + "PURL": "pkg:cargo/utf-8@0.7.5" + }, "Version": "0.7.5", "Layer": {}, "Locations": [ @@ -1870,6 +2236,9 @@ { "ID": "walkdir@1.0.7", "Name": "walkdir", + "Identifier": { + "PURL": "pkg:cargo/walkdir@1.0.7" + }, "Version": "1.0.7", "DependsOn": [ "kernel32-sys@0.2.2", @@ -1887,6 +2256,9 @@ { "ID": "winapi@0.2.8", "Name": "winapi", + "Identifier": { + "PURL": "pkg:cargo/winapi@0.2.8" + }, "Version": "0.2.8", "Layer": {}, "Locations": [ @@ -1899,6 +2271,9 @@ { "ID": "winapi@0.3.7", "Name": "winapi", + "Identifier": { + "PURL": "pkg:cargo/winapi@0.3.7" + }, "Version": "0.3.7", "DependsOn": [ "winapi-i686-pc-windows-gnu@0.4.0", @@ -1915,6 +2290,9 @@ { "ID": "winapi-build@0.1.1", "Name": "winapi-build", + "Identifier": { + "PURL": "pkg:cargo/winapi-build@0.1.1" + }, "Version": "0.1.1", "Layer": {}, "Locations": [ @@ -1927,6 +2305,9 @@ { "ID": "winapi-i686-pc-windows-gnu@0.4.0", "Name": "winapi-i686-pc-windows-gnu", + "Identifier": { + "PURL": "pkg:cargo/winapi-i686-pc-windows-gnu@0.4.0" + }, "Version": "0.4.0", "Layer": {}, "Locations": [ @@ -1939,6 +2320,9 @@ { "ID": "winapi-x86_64-pc-windows-gnu@0.4.0", "Name": "winapi-x86_64-pc-windows-gnu", + "Identifier": { + "PURL": "pkg:cargo/winapi-x86_64-pc-windows-gnu@0.4.0" + }, "Version": "0.4.0", "Layer": {}, "Locations": [ @@ -1957,6 +2341,9 @@ { "ID": "guzzlehttp/guzzle@6.2.0", "Name": "guzzlehttp/guzzle", + "Identifier": { + "PURL": "pkg:composer/guzzlehttp/guzzle@6.2.0" + }, "Version": "6.2.0", "Licenses": [ "MIT" @@ -1976,6 +2363,9 @@ { "ID": "guzzlehttp/promises@v1.3.1", "Name": "guzzlehttp/promises", + "Identifier": { + "PURL": "pkg:composer/guzzlehttp/promises@v1.3.1" + }, "Version": "v1.3.1", "Licenses": [ "MIT" @@ -1991,6 +2381,9 @@ { "ID": "guzzlehttp/psr7@1.5.2", "Name": "guzzlehttp/psr7", + "Identifier": { + "PURL": "pkg:composer/guzzlehttp/psr7@1.5.2" + }, "Version": "1.5.2", "Licenses": [ "MIT" @@ -2010,6 +2403,9 @@ { "ID": "laravel/installer@v2.0.1", "Name": "laravel/installer", + "Identifier": { + "PURL": "pkg:composer/laravel/installer@v2.0.1" + }, "Version": "v2.0.1", "Licenses": [ "MIT" @@ -2031,6 +2427,9 @@ { "ID": "pear/log@1.13.1", "Name": "pear/log", + "Identifier": { + "PURL": "pkg:composer/pear/log@1.13.1" + }, "Version": "1.13.1", "Licenses": [ "MIT" @@ -2049,6 +2448,9 @@ { "ID": "pear/pear_exception@v1.0.0", "Name": "pear/pear_exception", + "Identifier": { + "PURL": "pkg:composer/pear/pear_exception@v1.0.0" + }, "Version": "v1.0.0", "Licenses": [ "BSD-2-Clause" @@ -2064,6 +2466,9 @@ { "ID": "psr/http-message@1.0.1", "Name": "psr/http-message", + "Identifier": { + "PURL": "pkg:composer/psr/http-message@1.0.1" + }, "Version": "1.0.1", "Licenses": [ "MIT" @@ -2079,6 +2484,9 @@ { "ID": "ralouphie/getallheaders@2.0.5", "Name": "ralouphie/getallheaders", + "Identifier": { + "PURL": "pkg:composer/ralouphie/getallheaders@2.0.5" + }, "Version": "2.0.5", "Licenses": [ "MIT" @@ -2094,6 +2502,9 @@ { "ID": "symfony/console@v4.2.7", "Name": "symfony/console", + "Identifier": { + "PURL": "pkg:composer/symfony/console@v4.2.7" + }, "Version": "v4.2.7", "Licenses": [ "MIT" @@ -2113,6 +2524,9 @@ { "ID": "symfony/contracts@v1.0.2", "Name": "symfony/contracts", + "Identifier": { + "PURL": "pkg:composer/symfony/contracts@v1.0.2" + }, "Version": "v1.0.2", "Licenses": [ "MIT" @@ -2128,6 +2542,9 @@ { "ID": "symfony/filesystem@v4.2.7", "Name": "symfony/filesystem", + "Identifier": { + "PURL": "pkg:composer/symfony/filesystem@v4.2.7" + }, "Version": "v4.2.7", "Licenses": [ "MIT" @@ -2146,6 +2563,9 @@ { "ID": "symfony/polyfill-ctype@v1.11.0", "Name": "symfony/polyfill-ctype", + "Identifier": { + "PURL": "pkg:composer/symfony/polyfill-ctype@v1.11.0" + }, "Version": "v1.11.0", "Licenses": [ "MIT" @@ -2161,6 +2581,9 @@ { "ID": "symfony/polyfill-mbstring@v1.11.0", "Name": "symfony/polyfill-mbstring", + "Identifier": { + "PURL": "pkg:composer/symfony/polyfill-mbstring@v1.11.0" + }, "Version": "v1.11.0", "Licenses": [ "MIT" @@ -2176,6 +2599,9 @@ { "ID": "symfony/process@v4.2.7", "Name": "symfony/process", + "Identifier": { + "PURL": "pkg:composer/symfony/process@v4.2.7" + }, "Version": "v4.2.7", "Licenses": [ "MIT" @@ -2197,6 +2623,9 @@ { "ID": "asap@2.0.6", "Name": "asap", + "Identifier": { + "PURL": "pkg:npm/asap@2.0.6" + }, "Version": "2.0.6", "Indirect": true, "Layer": {}, @@ -2210,6 +2639,9 @@ { "ID": "jquery@3.3.9", "Name": "jquery", + "Identifier": { + "PURL": "pkg:npm/jquery@3.3.9" + }, "Version": "3.3.9", "Indirect": true, "Layer": {}, @@ -2223,6 +2655,9 @@ { "ID": "js-tokens@4.0.0", "Name": "js-tokens", + "Identifier": { + "PURL": "pkg:npm/js-tokens@4.0.0" + }, "Version": "4.0.0", "Indirect": true, "Layer": {}, @@ -2236,6 +2671,9 @@ { "ID": "lodash@4.17.4", "Name": "lodash", + "Identifier": { + "PURL": "pkg:npm/lodash@4.17.4" + }, "Version": "4.17.4", "Indirect": true, "Layer": {}, @@ -2249,6 +2687,9 @@ { "ID": "loose-envify@1.4.0", "Name": "loose-envify", + "Identifier": { + "PURL": "pkg:npm/loose-envify@1.4.0" + }, "Version": "1.4.0", "Indirect": true, "DependsOn": [ @@ -2265,6 +2706,9 @@ { "ID": "object-assign@4.1.1", "Name": "object-assign", + "Identifier": { + "PURL": "pkg:npm/object-assign@4.1.1" + }, "Version": "4.1.1", "Indirect": true, "Layer": {}, @@ -2278,6 +2722,9 @@ { "ID": "promise@8.0.3", "Name": "promise", + "Identifier": { + "PURL": "pkg:npm/promise@8.0.3" + }, "Version": "8.0.3", "Indirect": true, "DependsOn": [ @@ -2294,6 +2741,9 @@ { "ID": "prop-types@15.7.2", "Name": "prop-types", + "Identifier": { + "PURL": "pkg:npm/prop-types@15.7.2" + }, "Version": "15.7.2", "Indirect": true, "DependsOn": [ @@ -2312,6 +2762,9 @@ { "ID": "react@16.8.6", "Name": "react", + "Identifier": { + "PURL": "pkg:npm/react@16.8.6" + }, "Version": "16.8.6", "Indirect": true, "DependsOn": [ @@ -2331,6 +2784,9 @@ { "ID": "react-is@16.8.6", "Name": "react-is", + "Identifier": { + "PURL": "pkg:npm/react-is@16.8.6" + }, "Version": "16.8.6", "Indirect": true, "Layer": {}, @@ -2344,6 +2800,9 @@ { "ID": "redux@4.0.1", "Name": "redux", + "Identifier": { + "PURL": "pkg:npm/redux@4.0.1" + }, "Version": "4.0.1", "Indirect": true, "DependsOn": [ @@ -2361,6 +2820,9 @@ { "ID": "scheduler@0.13.6", "Name": "scheduler", + "Identifier": { + "PURL": "pkg:npm/scheduler@0.13.6" + }, "Version": "0.13.6", "Indirect": true, "DependsOn": [ @@ -2378,6 +2840,9 @@ { "ID": "symbol-observable@1.2.0", "Name": "symbol-observable", + "Identifier": { + "PURL": "pkg:npm/symbol-observable@1.2.0" + }, "Version": "1.2.0", "Indirect": true, "Layer": {}, @@ -2396,6 +2861,9 @@ "Libraries": [ { "Name": "amqp", + "Identifier": { + "PURL": "pkg:pypi/amqp@2.4.2" + }, "Version": "2.4.2", "Layer": {}, "Locations": [ @@ -2407,6 +2875,9 @@ }, { "Name": "autopep8", + "Identifier": { + "PURL": "pkg:pypi/autopep8@1.4.3" + }, "Version": "1.4.3", "Layer": {}, "Locations": [ @@ -2418,6 +2889,9 @@ }, { "Name": "babel", + "Identifier": { + "PURL": "pkg:pypi/babel@2.6.0" + }, "Version": "2.6.0", "Layer": {}, "Locations": [ @@ -2429,6 +2903,9 @@ }, { "Name": "billiard", + "Identifier": { + "PURL": "pkg:pypi/billiard@3.6.0.0" + }, "Version": "3.6.0.0", "Layer": {}, "Locations": [ @@ -2440,6 +2917,9 @@ }, { "Name": "boto3", + "Identifier": { + "PURL": "pkg:pypi/boto3@1.9.130" + }, "Version": "1.9.130", "Layer": {}, "Locations": [ @@ -2451,6 +2931,9 @@ }, { "Name": "botocore", + "Identifier": { + "PURL": "pkg:pypi/botocore@1.12.130" + }, "Version": "1.12.130", "Layer": {}, "Locations": [ @@ -2462,6 +2945,9 @@ }, { "Name": "celery", + "Identifier": { + "PURL": "pkg:pypi/celery@4.3.0" + }, "Version": "4.3.0", "Layer": {}, "Locations": [ @@ -2473,6 +2959,9 @@ }, { "Name": "certifi", + "Identifier": { + "PURL": "pkg:pypi/certifi@2019.3.9" + }, "Version": "2019.3.9", "Layer": {}, "Locations": [ @@ -2484,6 +2973,9 @@ }, { "Name": "chardet", + "Identifier": { + "PURL": "pkg:pypi/chardet@3.0.4" + }, "Version": "3.0.4", "Layer": {}, "Locations": [ @@ -2495,6 +2987,9 @@ }, { "Name": "decorator", + "Identifier": { + "PURL": "pkg:pypi/decorator@4.4.0" + }, "Version": "4.4.0", "Layer": {}, "Locations": [ @@ -2506,6 +3001,9 @@ }, { "Name": "django", + "Identifier": { + "PURL": "pkg:pypi/django@2.0.9" + }, "Version": "2.0.9", "Layer": {}, "Locations": [ @@ -2517,6 +3015,9 @@ }, { "Name": "django-celery-beat", + "Identifier": { + "PURL": "pkg:pypi/django-celery-beat@1.4.0" + }, "Version": "1.4.0", "Layer": {}, "Locations": [ @@ -2528,6 +3029,9 @@ }, { "Name": "django-cors-headers", + "Identifier": { + "PURL": "pkg:pypi/django-cors-headers@2.5.2" + }, "Version": "2.5.2", "Layer": {}, "Locations": [ @@ -2539,6 +3043,9 @@ }, { "Name": "django-extensions", + "Identifier": { + "PURL": "pkg:pypi/django-extensions@2.1.6" + }, "Version": "2.1.6", "Layer": {}, "Locations": [ @@ -2550,6 +3057,9 @@ }, { "Name": "django-postgres-extra", + "Identifier": { + "PURL": "pkg:pypi/django-postgres-extra" + }, "Layer": {}, "Locations": [ { @@ -2560,6 +3070,9 @@ }, { "Name": "django-redis-cache", + "Identifier": { + "PURL": "pkg:pypi/django-redis-cache@2.0.0" + }, "Version": "2.0.0", "Layer": {}, "Locations": [ @@ -2571,6 +3084,9 @@ }, { "Name": "django-silk", + "Identifier": { + "PURL": "pkg:pypi/django-silk@3.0.1" + }, "Version": "3.0.1", "Layer": {}, "Locations": [ @@ -2582,6 +3098,9 @@ }, { "Name": "django-timezone-field", + "Identifier": { + "PURL": "pkg:pypi/django-timezone-field@3.0" + }, "Version": "3.0", "Layer": {}, "Locations": [ @@ -2593,6 +3112,9 @@ }, { "Name": "djangorestframework", + "Identifier": { + "PURL": "pkg:pypi/djangorestframework@3.9.2" + }, "Version": "3.9.2", "Layer": {}, "Locations": [ @@ -2604,6 +3126,9 @@ }, { "Name": "djangorestframework-jwt", + "Identifier": { + "PURL": "pkg:pypi/djangorestframework-jwt@1.11.0" + }, "Version": "1.11.0", "Layer": {}, "Locations": [ @@ -2615,6 +3140,9 @@ }, { "Name": "docutils", + "Identifier": { + "PURL": "pkg:pypi/docutils@0.14" + }, "Version": "0.14", "Layer": {}, "Locations": [ @@ -2626,6 +3154,9 @@ }, { "Name": "flower", + "Identifier": { + "PURL": "pkg:pypi/flower@0.9.3" + }, "Version": "0.9.3", "Layer": {}, "Locations": [ @@ -2637,6 +3168,9 @@ }, { "Name": "gprof2dot", + "Identifier": { + "PURL": "pkg:pypi/gprof2dot@2016.10.13" + }, "Version": "2016.10.13", "Layer": {}, "Locations": [ @@ -2648,6 +3182,9 @@ }, { "Name": "gunicorn", + "Identifier": { + "PURL": "pkg:pypi/gunicorn@19.9.0" + }, "Version": "19.9.0", "Layer": {}, "Locations": [ @@ -2659,6 +3196,9 @@ }, { "Name": "hiredis", + "Identifier": { + "PURL": "pkg:pypi/hiredis@1.0.0" + }, "Version": "1.0.0", "Layer": {}, "Locations": [ @@ -2670,6 +3210,9 @@ }, { "Name": "httplib2", + "Identifier": { + "PURL": "pkg:pypi/httplib2@0.12.1" + }, "Version": "0.12.1", "Layer": {}, "Locations": [ @@ -2681,6 +3224,9 @@ }, { "Name": "idna", + "Identifier": { + "PURL": "pkg:pypi/idna@2.8" + }, "Version": "2.8", "Layer": {}, "Locations": [ @@ -2692,6 +3238,9 @@ }, { "Name": "jinja2", + "Identifier": { + "PURL": "pkg:pypi/jinja2@2.10.1" + }, "Version": "2.10.1", "Layer": {}, "Locations": [ @@ -2703,6 +3252,9 @@ }, { "Name": "jmespath", + "Identifier": { + "PURL": "pkg:pypi/jmespath@0.9.4" + }, "Version": "0.9.4", "Layer": {}, "Locations": [ @@ -2714,6 +3266,9 @@ }, { "Name": "kombu", + "Identifier": { + "PURL": "pkg:pypi/kombu@4.5.0" + }, "Version": "4.5.0", "Layer": {}, "Locations": [ @@ -2725,6 +3280,9 @@ }, { "Name": "markupsafe", + "Identifier": { + "PURL": "pkg:pypi/markupsafe@1.1.1" + }, "Version": "1.1.1", "Layer": {}, "Locations": [ @@ -2736,6 +3294,9 @@ }, { "Name": "oauth2", + "Identifier": { + "PURL": "pkg:pypi/oauth2@1.9.0.post1" + }, "Version": "1.9.0.post1", "Layer": {}, "Locations": [ @@ -2747,6 +3308,9 @@ }, { "Name": "psycopg2-binary", + "Identifier": { + "PURL": "pkg:pypi/psycopg2-binary@2.8.1" + }, "Version": "2.8.1", "Layer": {}, "Locations": [ @@ -2758,6 +3322,9 @@ }, { "Name": "py", + "Identifier": { + "PURL": "pkg:pypi/py@1.8.0" + }, "Version": "1.8.0", "Layer": {}, "Locations": [ @@ -2769,6 +3336,9 @@ }, { "Name": "pycodestyle", + "Identifier": { + "PURL": "pkg:pypi/pycodestyle@2.5.0" + }, "Version": "2.5.0", "Layer": {}, "Locations": [ @@ -2780,6 +3350,9 @@ }, { "Name": "pycurl", + "Identifier": { + "PURL": "pkg:pypi/pycurl@7.43.0.2" + }, "Version": "7.43.0.2", "Layer": {}, "Locations": [ @@ -2791,6 +3364,9 @@ }, { "Name": "pygments", + "Identifier": { + "PURL": "pkg:pypi/pygments@2.3.1" + }, "Version": "2.3.1", "Layer": {}, "Locations": [ @@ -2802,6 +3378,9 @@ }, { "Name": "pyjwt", + "Identifier": { + "PURL": "pkg:pypi/pyjwt@1.7.1" + }, "Version": "1.7.1", "Layer": {}, "Locations": [ @@ -2813,6 +3392,9 @@ }, { "Name": "python-crontab", + "Identifier": { + "PURL": "pkg:pypi/python-crontab@2.3.6" + }, "Version": "2.3.6", "Layer": {}, "Locations": [ @@ -2824,6 +3406,9 @@ }, { "Name": "python-dateutil", + "Identifier": { + "PURL": "pkg:pypi/python-dateutil@2.8.0" + }, "Version": "2.8.0", "Layer": {}, "Locations": [ @@ -2835,6 +3420,9 @@ }, { "Name": "python-http-client", + "Identifier": { + "PURL": "pkg:pypi/python-http-client@3.1.0" + }, "Version": "3.1.0", "Layer": {}, "Locations": [ @@ -2846,6 +3434,9 @@ }, { "Name": "pytz", + "Identifier": { + "PURL": "pkg:pypi/pytz@2019.1" + }, "Version": "2019.1", "Layer": {}, "Locations": [ @@ -2857,6 +3448,9 @@ }, { "Name": "pyyaml", + "Identifier": { + "PURL": "pkg:pypi/pyyaml@5.1" + }, "Version": "5.1", "Layer": {}, "Locations": [ @@ -2868,6 +3462,9 @@ }, { "Name": "redis", + "Identifier": { + "PURL": "pkg:pypi/redis@3.2.1" + }, "Version": "3.2.1", "Layer": {}, "Locations": [ @@ -2879,6 +3476,9 @@ }, { "Name": "requests", + "Identifier": { + "PURL": "pkg:pypi/requests@2.21.0" + }, "Version": "2.21.0", "Layer": {}, "Locations": [ @@ -2890,6 +3490,9 @@ }, { "Name": "retry", + "Identifier": { + "PURL": "pkg:pypi/retry@0.9.2" + }, "Version": "0.9.2", "Layer": {}, "Locations": [ @@ -2901,6 +3504,9 @@ }, { "Name": "s3transfer", + "Identifier": { + "PURL": "pkg:pypi/s3transfer@0.2.0" + }, "Version": "0.2.0", "Layer": {}, "Locations": [ @@ -2912,6 +3518,9 @@ }, { "Name": "sendgrid", + "Identifier": { + "PURL": "pkg:pypi/sendgrid@6.0.4" + }, "Version": "6.0.4", "Layer": {}, "Locations": [ @@ -2923,6 +3532,9 @@ }, { "Name": "sentry-sdk", + "Identifier": { + "PURL": "pkg:pypi/sentry-sdk@0.7.10" + }, "Version": "0.7.10", "Layer": {}, "Locations": [ @@ -2934,6 +3546,9 @@ }, { "Name": "six", + "Identifier": { + "PURL": "pkg:pypi/six@1.12.0" + }, "Version": "1.12.0", "Layer": {}, "Locations": [ @@ -2945,6 +3560,9 @@ }, { "Name": "sqlparse", + "Identifier": { + "PURL": "pkg:pypi/sqlparse@0.3.0" + }, "Version": "0.3.0", "Layer": {}, "Locations": [ @@ -2956,6 +3574,9 @@ }, { "Name": "tornado", + "Identifier": { + "PURL": "pkg:pypi/tornado@5.1.1" + }, "Version": "5.1.1", "Layer": {}, "Locations": [ @@ -2967,6 +3588,9 @@ }, { "Name": "urllib3", + "Identifier": { + "PURL": "pkg:pypi/urllib3@1.24.1" + }, "Version": "1.24.1", "Layer": {}, "Locations": [ @@ -2978,6 +3602,9 @@ }, { "Name": "vine", + "Identifier": { + "PURL": "pkg:pypi/vine@1.3.0" + }, "Version": "1.3.0", "Layer": {}, "Locations": [ @@ -2989,6 +3616,9 @@ }, { "Name": "xmltodict", + "Identifier": { + "PURL": "pkg:pypi/xmltodict@0.12.0" + }, "Version": "0.12.0", "Layer": {}, "Locations": [ diff --git a/pkg/fanal/test/integration/testdata/goldens/vuln-image1.2.3.expectedpkgsfromcmds.golden b/pkg/fanal/test/integration/testdata/goldens/vuln-image1.2.3.expectedpkgsfromcmds.golden index 2f2b554c38ee..818db8d5c29d 100644 --- a/pkg/fanal/test/integration/testdata/goldens/vuln-image1.2.3.expectedpkgsfromcmds.golden +++ b/pkg/fanal/test/integration/testdata/goldens/vuln-image1.2.3.expectedpkgsfromcmds.golden @@ -1,998 +1,500 @@ [ { - "Name": "m4", - "Version": "1.4.18-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" - }, - { - "Name": "binutils-libs", - "Version": "2.30-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "acl", + "Identifier": {}, + "Version": "2.2.52-r3", + "Layer": {} }, { - "Name": "ncurses-dev", - "Version": "6.0_p20171125-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "apr", + "Identifier": {}, + "Version": "1.6.3-r0", + "Layer": {} }, { - "Name": "python2", - "Version": "2.7.15-r2", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "apr-util", + "Identifier": {}, + "Version": "1.6.1-r1", + "Layer": {} }, { - "Name": "libressl2.6-libcrypto", - "Version": "2.6.5-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "attr", + "Identifier": {}, + "Version": "2.4.47-r6", + "Layer": {} }, { - "Name": "cyrus-sasl", - "Version": "2.1.26-r11", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "autoconf", + "Identifier": {}, + "Version": "2.69-r0", + "Layer": {} }, { - "Name": "libgcc", - "Version": "6.4.0-r5", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "bash", + "Identifier": {}, + "Version": "4.4.19-r1", + "Layer": {} }, { - "Name": "dpkg-dev", - "Version": "1.18.24-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "binutils", + "Identifier": {}, + "Version": "2.30-r1", + "Layer": {} }, { - "Name": "mpc1", - "Version": "1.0.3-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "binutils-libs", + "Identifier": {}, + "Version": "2.30-r1", + "Layer": {} }, { - "Name": "dpkg", - "Version": "1.18.24-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "busybox", + "Identifier": {}, + "Version": "1.27.2-r11", + "Layer": {} }, { - "Name": "libacl", - "Version": "2.2.52-r3", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "bzip2", + "Identifier": {}, + "Version": "1.0.6-r6", + "Layer": {} }, { - "Name": "musl-dev", - "Version": "1.1.18-r3", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "ca-certificates", + "Identifier": {}, + "Version": "20171114-r0", + "Layer": {} }, { - "Name": "ncurses-terminfo", - "Version": "6.0_p20171125-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "coreutils", + "Identifier": {}, + "Version": "8.28-r0", + "Layer": {} }, { - "Name": "libunistring", - "Version": "0.9.7-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "cyrus-sasl", + "Identifier": {}, + "Version": "2.1.26-r11", + "Layer": {} }, { "Name": "db", + "Identifier": {}, "Version": "5.3.28-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" - }, - { - "Name": "libressl-dev", - "Version": "2.6.5-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Layer": {} }, { - "Name": "npth", - "Version": "1.5-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "dpkg", + "Identifier": {}, + "Version": "1.18.24-r0", + "Layer": {} }, { - "Name": "pcre2", - "Version": "10.30-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "dpkg-dev", + "Identifier": {}, + "Version": "1.18.24-r0", + "Layer": {} }, { - "Name": "zlib", - "Version": "1.2.11-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "expat", + "Identifier": {}, + "Version": "2.2.5-r0", + "Layer": {} }, { - "Name": "busybox", - "Version": "1.27.2-r11", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "file", + "Identifier": {}, + "Version": "5.32-r0", + "Layer": {} }, { - "Name": "nettle", - "Version": "3.3-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "g++", + "Identifier": {}, + "Version": "6.4.0-r5", + "Layer": {} }, { - "Name": "libtasn1", - "Version": "4.12-r3", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "gcc", + "Identifier": {}, + "Version": "6.4.0-r5", + "Layer": {} }, { - "Name": "libstdc++", - "Version": "6.4.0-r5", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "gdbm", + "Identifier": {}, + "Version": "1.13-r1", + "Layer": {} }, { - "Name": "libressl2.6-libssl", - "Version": "2.6.5-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "gmp", + "Identifier": {}, + "Version": "6.1.2-r1", + "Layer": {} }, { - "Name": "xz", - "Version": "5.2.3-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "gnupg", + "Identifier": {}, + "Version": "2.2.3-r1", + "Layer": {} }, { "Name": "gnutls", + "Identifier": {}, "Version": "3.6.1-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" - }, - { - "Name": "file", - "Version": "5.32-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Layer": {} }, { - "Name": "libffi", - "Version": "3.2.1-r4", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "isl", + "Identifier": {}, + "Version": "0.18-r0", + "Layer": {} }, { - "Name": "ncurses-libs", - "Version": "6.0_p20171125-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libacl", + "Identifier": {}, + "Version": "2.2.52-r3", + "Layer": {} }, { - "Name": "gdbm", - "Version": "1.13-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libassuan", + "Identifier": {}, + "Version": "2.4.4-r0", + "Layer": {} }, { - "Name": "libgcrypt", - "Version": "1.8.3-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libatomic", + "Identifier": {}, + "Version": "6.4.0-r5", + "Layer": {} }, { - "Name": "g++", - "Version": "6.4.0-r5", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libattr", + "Identifier": {}, + "Version": "2.4.47-r6", + "Layer": {} }, { - "Name": "mercurial", - "Version": "4.5.2-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libbz2", + "Identifier": {}, + "Version": "1.0.6-r6", + "Layer": {} }, { - "Name": "zlib-dev", - "Version": "1.2.11-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libc-dev", + "Identifier": {}, + "Version": "0.7.1-r0", + "Layer": {} }, { - "Name": "pkgconf", - "Version": "1.3.10-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libcap", + "Identifier": {}, + "Version": "2.25-r1", + "Layer": {} }, { - "Name": "isl", - "Version": "0.18-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libedit", + "Identifier": {}, + "Version": "20170329.3.1-r3", + "Layer": {} }, { - "Name": "libmagic", - "Version": "5.32-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libedit-dev", + "Identifier": {}, + "Version": "20170329.3.1-r3", + "Layer": {} }, { - "Name": "xz-libs", - "Version": "5.2.3-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libffi", + "Identifier": {}, + "Version": "3.2.1-r4", + "Layer": {} }, { - "Name": "ncurses", - "Version": "6.0_p20171125-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libgcc", + "Identifier": {}, + "Version": "6.4.0-r5", + "Layer": {} }, { - "Name": "ncurses-terminfo-base", - "Version": "6.0_p20171125-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libgcrypt", + "Identifier": {}, + "Version": "1.8.3-r0", + "Layer": {} }, { - "Name": "libassuan", - "Version": "2.4.4-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libgomp", + "Identifier": {}, + "Version": "6.4.0-r5", + "Layer": {} }, { - "Name": "subversion-libs", - "Version": "1.9.7-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libgpg-error", + "Identifier": {}, + "Version": "1.27-r1", + "Layer": {} }, { - "Name": "libressl2.6-libtls", - "Version": "2.6.5-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libksba", + "Identifier": {}, + "Version": "1.3.5-r0", + "Layer": {} }, { "Name": "libldap", + "Identifier": {}, "Version": "2.4.45-r3", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Layer": {} }, { - "Name": "gmp", - "Version": "6.1.2-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libmagic", + "Identifier": {}, + "Version": "5.32-r0", + "Layer": {} }, { - "Name": "libbz2", - "Version": "1.0.6-r6", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libressl", + "Identifier": {}, + "Version": "2.6.5-r0", + "Layer": {} }, { - "Name": "libc-dev", - "Version": "0.7.1-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libressl-dev", + "Identifier": {}, + "Version": "2.6.5-r0", + "Layer": {} }, { - "Name": "binutils", - "Version": "2.30-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libressl2.6-libcrypto", + "Identifier": {}, + "Version": "2.6.5-r0", + "Layer": {} }, { - "Name": "libsodium-dev", - "Version": "1.0.15-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libressl2.6-libssl", + "Identifier": {}, + "Version": "2.6.5-r0", + "Layer": {} }, { - "Name": "musl", - "Version": "1.1.18-r3", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libressl2.6-libtls", + "Identifier": {}, + "Version": "2.6.5-r0", + "Layer": {} }, { - "Name": "pinentry", - "Version": "1.0.0-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libsasl", + "Identifier": {}, + "Version": "2.1.26-r11", + "Layer": {} }, { - "Name": "openldap", - "Version": "2.4.45-r3", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libsodium", + "Identifier": {}, + "Version": "1.0.15-r0", + "Layer": {} }, { - "Name": "libedit-dev", - "Version": "20170329.3.1-r3", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libsodium-dev", + "Identifier": {}, + "Version": "1.0.15-r0", + "Layer": {} }, { - "Name": "bash", - "Version": "4.4.19-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libstdc++", + "Identifier": {}, + "Version": "6.4.0-r5", + "Layer": {} }, { - "Name": "apr", - "Version": "1.6.3-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libtasn1", + "Identifier": {}, + "Version": "4.12-r3", + "Layer": {} }, { - "Name": "ca-certificates", - "Version": "20171114-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "libunistring", + "Identifier": {}, + "Version": "0.9.7-r0", + "Layer": {} }, { - "Name": "libcap", - "Version": "2.25-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "m4", + "Identifier": {}, + "Version": "1.4.18-r0", + "Layer": {} }, { - "Name": "libedit", - "Version": "20170329.3.1-r3", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "make", + "Identifier": {}, + "Version": "4.2.1-r0", + "Layer": {} }, { - "Name": "acl", - "Version": "2.2.52-r3", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "mercurial", + "Identifier": {}, + "Version": "4.5.2-r0", + "Layer": {} }, { - "Name": "libsasl", - "Version": "2.1.26-r11", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "mpc1", + "Identifier": {}, + "Version": "1.0.3-r1", + "Layer": {} }, { - "Name": "gnupg", - "Version": "2.2.3-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "mpfr3", + "Identifier": {}, + "Version": "3.1.5-r1", + "Layer": {} }, { - "Name": "readline", - "Version": "7.0.003-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "musl", + "Identifier": {}, + "Version": "1.1.18-r3", + "Layer": {} }, { - "Name": "apr-util", - "Version": "1.6.1-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "musl-dev", + "Identifier": {}, + "Version": "1.1.18-r3", + "Layer": {} }, { - "Name": "patch", - "Version": "2.7.5-r2", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "ncurses", + "Identifier": {}, + "Version": "6.0_p20171125-r1", + "Layer": {} }, { - "Name": "libsodium", - "Version": "1.0.15-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "ncurses-dev", + "Identifier": {}, + "Version": "6.0_p20171125-r1", + "Layer": {} }, { - "Name": "mpfr3", - "Version": "3.1.5-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "ncurses-libs", + "Identifier": {}, + "Version": "6.0_p20171125-r1", + "Layer": {} }, { - "Name": "libattr", - "Version": "2.4.47-r6", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "ncurses-terminfo", + "Identifier": {}, + "Version": "6.0_p20171125-r1", + "Layer": {} }, { - "Name": "attr", - "Version": "2.4.47-r6", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "ncurses-terminfo-base", + "Identifier": {}, + "Version": "6.0_p20171125-r1", + "Layer": {} }, { - "Name": "make", - "Version": "4.2.1-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "nettle", + "Identifier": {}, + "Version": "3.3-r0", + "Layer": {} }, { - "Name": "serf", - "Version": "1.3.9-r3", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "npth", + "Identifier": {}, + "Version": "1.5-r1", + "Layer": {} }, { - "Name": "libressl", - "Version": "2.6.5-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "openldap", + "Identifier": {}, + "Version": "2.4.45-r3", + "Layer": {} }, { - "Name": "libksba", - "Version": "1.3.5-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "p11-kit", + "Identifier": {}, + "Version": "0.23.2-r2", + "Layer": {} }, { - "Name": "bzip2", - "Version": "1.0.6-r6", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "patch", + "Identifier": {}, + "Version": "2.7.5-r2", + "Layer": {} }, { - "Name": "libgomp", - "Version": "6.4.0-r5", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "pcre2", + "Identifier": {}, + "Version": "10.30-r0", + "Layer": {} }, { - "Name": "libatomic", - "Version": "6.4.0-r5", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "pinentry", + "Identifier": {}, + "Version": "1.0.0-r0", + "Layer": {} + }, + { + "Name": "pkgconf", + "Identifier": {}, + "Version": "1.3.10-r0", + "Layer": {} + }, + { + "Name": "python2", + "Identifier": {}, + "Version": "2.7.15-r2", + "Layer": {} }, { "Name": "re2c", + "Identifier": {}, "Version": "1.0.2-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Layer": {} }, { - "Name": "coreutils", - "Version": "8.28-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "readline", + "Identifier": {}, + "Version": "7.0.003-r0", + "Layer": {} }, { - "Name": "expat", - "Version": "2.2.5-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "serf", + "Identifier": {}, + "Version": "1.3.9-r3", + "Layer": {} }, { - "Name": "libgpg-error", - "Version": "1.27-r1", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "subversion", + "Identifier": {}, + "Version": "1.9.7-r0", + "Layer": {} }, { - "Name": "p11-kit", - "Version": "0.23.2-r2", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "subversion-libs", + "Identifier": {}, + "Version": "1.9.7-r0", + "Layer": {} }, { - "Name": "gcc", - "Version": "6.4.0-r5", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "xz", + "Identifier": {}, + "Version": "5.2.3-r1", + "Layer": {} }, { - "Name": "autoconf", - "Version": "2.69-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "xz-libs", + "Identifier": {}, + "Version": "5.2.3-r1", + "Layer": {} }, { - "Name": "subversion", - "Version": "1.9.7-r0", - "Release": "", - "Epoch": 0, - "Arch": "", - "SrcName": "", - "SrcVersion": "", - "SrcRelease": "", - "SrcEpoch":0, - "LayerID":"" + "Name": "zlib", + "Identifier": {}, + "Version": "1.2.11-r1", + "Layer": {} + }, + { + "Name": "zlib-dev", + "Identifier": {}, + "Version": "1.2.11-r1", + "Layer": {} } ] \ No newline at end of file diff --git a/pkg/fanal/types/artifact.go b/pkg/fanal/types/artifact.go index 7db2cdbf1949..a6d9e5372a95 100644 --- a/pkg/fanal/types/artifact.go +++ b/pkg/fanal/types/artifact.go @@ -62,25 +62,32 @@ type Layer struct { } type Package struct { - ID string `json:",omitempty"` - Name string `json:",omitempty"` - Version string `json:",omitempty"` - Release string `json:",omitempty"` - Epoch int `json:",omitempty"` - Arch string `json:",omitempty"` - Dev bool `json:",omitempty"` - SrcName string `json:",omitempty"` - SrcVersion string `json:",omitempty"` - SrcRelease string `json:",omitempty"` - SrcEpoch int `json:",omitempty"` - Licenses []string `json:",omitempty"` - Maintainer string `json:",omitempty"` + ID string `json:",omitempty"` + Name string `json:",omitempty"` + Identifier PkgIdentifier `json:",omitempty"` + Version string `json:",omitempty"` + Release string `json:",omitempty"` + Epoch int `json:",omitempty"` + Arch string `json:",omitempty"` + Dev bool `json:",omitempty"` + SrcName string `json:",omitempty"` + SrcVersion string `json:",omitempty"` + SrcRelease string `json:",omitempty"` + SrcEpoch int `json:",omitempty"` + Licenses []string `json:",omitempty"` + Maintainer string `json:",omitempty"` Modularitylabel string `json:",omitempty"` // only for Red Hat based distributions BuildInfo *BuildInfo `json:",omitempty"` // only for Red Hat + Indirect bool `json:",omitempty"` // this package is direct dependency of the project or not - Ref string `json:",omitempty"` // identifier which can be used to reference the component elsewhere - Indirect bool `json:",omitempty"` // this package is direct dependency of the project or not + // TO BE DEPRECATED - use Identifier instead + // Only used when scanning SBOM and contains the reference ID used in it. + // It could be PURL, UUID, etc. + // e.g. + // - pkg:npm/acme/component@1.0.0 + // - b2a46a4b-8367-4bae-9820-95557cfe03a8 + Ref string `json:",omitempty"` // Dependencies of this package // Note: it may have interdependencies, which may lead to infinite loops. @@ -101,6 +108,16 @@ type Package struct { InstalledFiles []string `json:",omitempty"` } +// PkgIdentifier represents a software identifiers in one of more of the supported formats. +type PkgIdentifier struct { + // PURL is a package URL + PURL *PackageURL `json:",omitempty"` +} + +func (id *PkgIdentifier) Empty() bool { + return id.PURL == nil +} + type Location struct { StartLine int `json:",omitempty"` EndLine int `json:",omitempty"` diff --git a/pkg/fanal/types/handler.go b/pkg/fanal/types/handler.go index 7d60d1d68dd0..d53847c896c4 100644 --- a/pkg/fanal/types/handler.go +++ b/pkg/fanal/types/handler.go @@ -9,6 +9,5 @@ const ( // SystemFileFilteringPostHandlerPriority should be higher than other handlers. // Otherwise, other handlers need to process unnecessary files. SystemFileFilteringPostHandlerPriority = 100 - - UnpackagedPostHandlerPriority = 50 + UnpackagedPostHandlerPriority = 50 ) diff --git a/pkg/fanal/types/purl.go b/pkg/fanal/types/purl.go new file mode 100644 index 000000000000..53ad1cbdc0ec --- /dev/null +++ b/pkg/fanal/types/purl.go @@ -0,0 +1,78 @@ +package types + +import ( + "encoding/json" + + "github.com/package-url/packageurl-go" + "golang.org/x/xerrors" +) + +type PackageURL struct { + packageurl.PackageURL + FilePath string +} + +func (p *PackageURL) BOMRef() string { + // 'bom-ref' must be unique within BOM, but PURLs may conflict + // when the same packages are installed in an artifact. + // In that case, we prefer to make PURLs unique by adding file paths, + // rather than using UUIDs, even if it is not PURL technically. + // ref. https://cyclonedx.org/use-cases/#dependency-graph + purl := p.PackageURL // so that it will not override the qualifiers below + if p.FilePath != "" { + purl.Qualifiers = append(purl.Qualifiers, + packageurl.Qualifier{ + Key: "file_path", + Value: p.FilePath, + }, + ) + } + return purl.String() +} + +func (p *PackageURL) MarshalJSON() ([]byte, error) { + if p == nil { + return nil, nil + } + return json.Marshal(p.String()) +} + +func (p *PackageURL) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); err != nil { + return err + } + purl, err := NewPackageURL(s) + if err != nil { + return xerrors.Errorf("failed to parse purl(%s): %w", string(b), err) + } + *p = *purl + return nil +} + +func NewPackageURL(s string) (*PackageURL, error) { + p, err := packageurl.FromString(s) + if err != nil { + return nil, xerrors.Errorf("failed to parse purl(%s): %w", s, err) + } + + // Take out and delete the file path from qualifiers + var filePath string + for i, q := range p.Qualifiers { + if q.Key != "file_path" { + continue + } + filePath = q.Value + p.Qualifiers = append(p.Qualifiers[:i], p.Qualifiers[i+1:]...) + break + } + + if len(p.Qualifiers) == 0 { + p.Qualifiers = nil + } + + return &PackageURL{ + PackageURL: p, + FilePath: filePath, + }, nil +} diff --git a/pkg/k8s/scanner/scanner.go b/pkg/k8s/scanner/scanner.go index 8e624dd4a9a6..bbc7913ae745 100644 --- a/pkg/k8s/scanner/scanner.go +++ b/pkg/k8s/scanner/scanner.go @@ -394,7 +394,7 @@ func clusterInfoToReportResources(allArtifact []*artifacts.Artifact) (*core.Comp } ver := sanitizedVersion(c.Version) - imagePURL, err := purl.NewPackageURL(purl.TypeOCI, types.Metadata{ + imagePURL, err := purl.New(purl.TypeOCI, types.Metadata{ RepoDigests: []string{ fmt.Sprintf("%s@%s", name, cDigest), }, @@ -577,7 +577,7 @@ func nodeComponent(nf bom.NodeInfo) *core.Component { Namespace: k8sCoreComponentNamespace, }, }, - PackageURL: &purl.PackageURL{ + PackageURL: &ftypes.PackageURL{ PackageURL: *packageurl.NewPackageURL(golang, "", runtimeName, runtimeVersion, packageurl.Qualifiers{}, ""), }, }, @@ -601,7 +601,7 @@ func toProperties(props map[string]string, namespace string) []core.Property { return properties } -func generatePURL(name, ver, nodeName string) *purl.PackageURL { +func generatePURL(name, ver, nodeName string) *ftypes.PackageURL { var namespace string // Identify k8s distribution. An empty namespace means upstream. @@ -611,7 +611,7 @@ func generatePURL(name, ver, nodeName string) *purl.PackageURL { namespace = "" } - return &purl.PackageURL{ + return &ftypes.PackageURL{ PackageURL: *packageurl.NewPackageURL(purl.TypeK8s, namespace, name, ver, nil, ""), } } diff --git a/pkg/k8s/scanner/scanner_test.go b/pkg/k8s/scanner/scanner_test.go index ec6d78f73c05..5f70facd3cf6 100644 --- a/pkg/k8s/scanner/scanner_test.go +++ b/pkg/k8s/scanner/scanner_test.go @@ -2,6 +2,7 @@ package scanner import ( "context" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "sort" "testing" @@ -97,7 +98,7 @@ func TestScanner_Scan(t *testing.T) { Namespace: k8sCoreComponentNamespace, }, }, - PackageURL: &purl.PackageURL{ + PackageURL: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: purl.TypeK8s, Name: "k8s.io/kubernetes", @@ -109,7 +110,7 @@ func TestScanner_Scan(t *testing.T) { Type: cdx.ComponentTypeApplication, Name: "k8s.io/apiserver", Version: "1.21.1", - PackageURL: &purl.PackageURL{ + PackageURL: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: purl.TypeK8s, Name: "k8s.io/apiserver", @@ -122,7 +123,7 @@ func TestScanner_Scan(t *testing.T) { Type: cdx.ComponentTypeContainer, Name: "k8s.gcr.io/kube-apiserver", Version: "sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f", - PackageURL: &purl.PackageURL{ + PackageURL: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: "oci", Name: "kube-apiserver", @@ -233,7 +234,7 @@ func TestScanner_Scan(t *testing.T) { Namespace: k8sCoreComponentNamespace, }, }, - PackageURL: &purl.PackageURL{ + PackageURL: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: "k8s", Name: "k8s.io/kubelet", @@ -257,7 +258,7 @@ func TestScanner_Scan(t *testing.T) { Namespace: k8sCoreComponentNamespace, }, }, - PackageURL: &purl.PackageURL{ + PackageURL: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: "golang", Name: "github.com/containerd/containerd", diff --git a/pkg/module/serialize/types_easyjson.go b/pkg/module/serialize/types_easyjson.go index bbbc0290de1e..fc28d5e0f758 100644 --- a/pkg/module/serialize/types_easyjson.go +++ b/pkg/module/serialize/types_easyjson.go @@ -1616,6 +1616,8 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgTypes(in *jlexer.Lexer, out.PkgName = string(in.String()) case "PkgPath": out.PkgPath = string(in.String()) + case "PkgIdentifier": + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in, &out.PkgIdentifier) case "InstalledVersion": out.InstalledVersion = string(in.String()) case "FixedVersion": @@ -1835,6 +1837,16 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgTypes(out *jwriter.Write } out.String(string(in.PkgPath)) } + if true { + const prefix string = ",\"PkgIdentifier\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes9(out, in.PkgIdentifier) + } if in.InstalledVersion != "" { const prefix string = ",\"InstalledVersion\":" if first { @@ -2215,6 +2227,59 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyDbPkgTypes(out *jwriter.Wri } out.RawByte('}') } +func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in *jlexer.Lexer, out *types1.PkgIdentifier) { + isTopLevel := in.IsStart() + if in.IsNull() { + if isTopLevel { + in.Consumed() + } + in.Skip() + return + } + in.Delim('{') + for !in.IsDelim('}') { + key := in.UnsafeFieldName(false) + in.WantColon() + if in.IsNull() { + in.Skip() + in.WantComma() + continue + } + switch key { + case "PURL": + if in.IsNull() { + in.Skip() + out.PURL = nil + } else { + if out.PURL == nil { + out.PURL = new(types1.PackageURL) + } + if data := in.Raw(); in.Ok() { + in.AddError((*out.PURL).UnmarshalJSON(data)) + } + } + default: + in.SkipRecursive() + } + in.WantComma() + } + in.Delim('}') + if isTopLevel { + in.Consumed() + } +} +func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes9(out *jwriter.Writer, in types1.PkgIdentifier) { + out.RawByte('{') + first := true + _ = first + if in.PURL != nil { + const prefix string = ",\"PURL\":" + first = false + out.RawString(prefix[1:]) + out.Raw((*in.PURL).MarshalJSON()) + } + out.RawByte('}') +} func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes(in *jlexer.Lexer, out *types1.Package) { isTopLevel := in.IsStart() if in.IsNull() { @@ -2238,6 +2303,8 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes(in *jlexer.Le out.ID = string(in.String()) case "Name": out.Name = string(in.String()) + case "Identifier": + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in, &out.Identifier) case "Version": out.Version = string(in.String()) case "Release": @@ -2291,12 +2358,12 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes(in *jlexer.Le if out.BuildInfo == nil { out.BuildInfo = new(types1.BuildInfo) } - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in, out.BuildInfo) + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes10(in, out.BuildInfo) } - case "Ref": - out.Ref = string(in.String()) case "Indirect": out.Indirect = bool(in.Bool()) + case "Ref": + out.Ref = string(in.String()) case "DependsOn": if in.IsNull() { in.Skip() @@ -2349,6 +2416,29 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes(in *jlexer.Le } in.Delim(']') } + case "InstalledFiles": + if in.IsNull() { + in.Skip() + out.InstalledFiles = nil + } else { + in.Delim('[') + if out.InstalledFiles == nil { + if !in.IsDelim(']') { + out.InstalledFiles = make([]string, 0, 4) + } else { + out.InstalledFiles = []string{} + } + } else { + out.InstalledFiles = (out.InstalledFiles)[:0] + } + for !in.IsDelim(']') { + var v53 string + v53 = string(in.String()) + out.InstalledFiles = append(out.InstalledFiles, v53) + in.WantComma() + } + in.Delim(']') + } default: in.SkipRecursive() } @@ -2379,6 +2469,16 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes(out *jwriter. } out.String(string(in.Name)) } + if true { + const prefix string = ",\"Identifier\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes9(out, in.Identifier) + } if in.Version != "" { const prefix string = ",\"Version\":" if first { @@ -2479,11 +2579,11 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes(out *jwriter. } { out.RawByte('[') - for v53, v54 := range in.Licenses { - if v53 > 0 { + for v54, v55 := range in.Licenses { + if v54 > 0 { out.RawByte(',') } - out.String(string(v54)) + out.String(string(v55)) } out.RawByte(']') } @@ -2516,27 +2616,27 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes(out *jwriter. } else { out.RawString(prefix) } - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes9(out, *in.BuildInfo) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes10(out, *in.BuildInfo) } - if in.Ref != "" { - const prefix string = ",\"Ref\":" + if in.Indirect { + const prefix string = ",\"Indirect\":" if first { first = false out.RawString(prefix[1:]) } else { out.RawString(prefix) } - out.String(string(in.Ref)) + out.Bool(bool(in.Indirect)) } - if in.Indirect { - const prefix string = ",\"Indirect\":" + if in.Ref != "" { + const prefix string = ",\"Ref\":" if first { first = false out.RawString(prefix[1:]) } else { out.RawString(prefix) } - out.Bool(bool(in.Indirect)) + out.String(string(in.Ref)) } if len(in.DependsOn) != 0 { const prefix string = ",\"DependsOn\":" @@ -2548,11 +2648,11 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes(out *jwriter. } { out.RawByte('[') - for v55, v56 := range in.DependsOn { - if v55 > 0 { + for v56, v57 := range in.DependsOn { + if v56 > 0 { out.RawByte(',') } - out.String(string(v56)) + out.String(string(v57)) } out.RawByte(']') } @@ -2597,18 +2697,37 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes(out *jwriter. } { out.RawByte('[') - for v57, v58 := range in.Locations { - if v57 > 0 { + for v58, v59 := range in.Locations { + if v58 > 0 { out.RawByte(',') } - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes8(out, v58) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes8(out, v59) + } + out.RawByte(']') + } + } + if len(in.InstalledFiles) != 0 { + const prefix string = ",\"InstalledFiles\":" + if first { + first = false + out.RawString(prefix[1:]) + } else { + out.RawString(prefix) + } + { + out.RawByte('[') + for v60, v61 := range in.InstalledFiles { + if v60 > 0 { + out.RawByte(',') + } + out.String(string(v61)) } out.RawByte(']') } } out.RawByte('}') } -func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in *jlexer.Lexer, out *types1.BuildInfo) { +func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes10(in *jlexer.Lexer, out *types1.BuildInfo) { isTopLevel := in.IsStart() if in.IsNull() { if isTopLevel { @@ -2643,9 +2762,9 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in *jlexer.L out.ContentSets = (out.ContentSets)[:0] } for !in.IsDelim(']') { - var v59 string - v59 = string(in.String()) - out.ContentSets = append(out.ContentSets, v59) + var v62 string + v62 = string(in.String()) + out.ContentSets = append(out.ContentSets, v62) in.WantComma() } in.Delim(']') @@ -2664,7 +2783,7 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgFanalTypes9(in *jlexer.L in.Consumed() } } -func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes9(out *jwriter.Writer, in types1.BuildInfo) { +func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes10(out *jwriter.Writer, in types1.BuildInfo) { out.RawByte('{') first := true _ = first @@ -2674,11 +2793,11 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgFanalTypes9(out *jwriter out.RawString(prefix[1:]) { out.RawByte('[') - for v60, v61 := range in.ContentSets { - if v60 > 0 { + for v63, v64 := range in.ContentSets { + if v63 > 0 { out.RawByte(',') } - out.String(string(v61)) + out.String(string(v64)) } out.RawByte(']') } @@ -2742,9 +2861,9 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgModuleSerialize3(in *jle out.IDs = (out.IDs)[:0] } for !in.IsDelim(']') { - var v62 string - v62 = string(in.String()) - out.IDs = append(out.IDs, v62) + var v65 string + v65 = string(in.String()) + out.IDs = append(out.IDs, v65) in.WantComma() } in.Delim(']') @@ -2775,11 +2894,11 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgModuleSerialize3(out *jw out.RawString("null") } else { out.RawByte('[') - for v63, v64 := range in.IDs { - if v63 > 0 { + for v66, v67 := range in.IDs { + if v66 > 0 { out.RawByte(',') } - out.String(string(v64)) + out.String(string(v67)) } out.RawByte(']') } @@ -2845,9 +2964,9 @@ func easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgModuleSerialize4(in *jle out.CustomResources = (out.CustomResources)[:0] } for !in.IsDelim(']') { - var v65 CustomResource - easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgModuleSerialize5(in, &v65) - out.CustomResources = append(out.CustomResources, v65) + var v68 CustomResource + easyjson6601e8cdDecodeGithubComAquasecurityTrivyPkgModuleSerialize5(in, &v68) + out.CustomResources = append(out.CustomResources, v68) in.WantComma() } in.Delim(']') @@ -2873,11 +2992,11 @@ func easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgModuleSerialize4(out *jw out.RawString("null") } else { out.RawByte('[') - for v66, v67 := range in.CustomResources { - if v66 > 0 { + for v69, v70 := range in.CustomResources { + if v69 > 0 { out.RawByte(',') } - easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgModuleSerialize5(out, v67) + easyjson6601e8cdEncodeGithubComAquasecurityTrivyPkgModuleSerialize5(out, v70) } out.RawByte(']') } diff --git a/pkg/purl/purl.go b/pkg/purl/purl.go index 582647166ab2..c63c4fbb849f 100644 --- a/pkg/purl/purl.go +++ b/pkg/purl/purl.go @@ -43,76 +43,13 @@ const ( TypeUnknown = "unknown" ) -type PackageURL struct { - packageurl.PackageURL - FilePath string -} - -func FromString(purl string) (*PackageURL, error) { - p, err := packageurl.FromString(purl) - if err != nil { - return nil, xerrors.Errorf("failed to parse purl(%s): %w", purl, err) - } - - return &PackageURL{ - PackageURL: p, - }, nil -} - -func (p *PackageURL) Package() *ftypes.Package { - pkg := &ftypes.Package{ - Name: p.Name, - Version: p.Version, - } - for _, q := range p.Qualifiers { - switch q.Key { - case "arch": - pkg.Arch = q.Value - case "modularitylabel": - pkg.Modularitylabel = q.Value - case "epoch": - epoch, err := strconv.Atoi(q.Value) - if err == nil { - pkg.Epoch = epoch - } - } - } - - // CocoaPods purl has no namespace, but has subpath - // https://github.com/package-url/purl-spec/blob/a748c36ad415c8aeffe2b8a4a5d8a50d16d6d85f/PURL-TYPES.rst#cocoapods - if p.Type == packageurl.TypeCocoapods && p.Subpath != "" { - // CocoaPods uses / format for package name - // e.g. `pkg:cocoapods/GoogleUtilities@7.5.2#NSData+zlib` => `GoogleUtilities/NSData+zlib` - pkg.Name = p.Name + "/" + p.Subpath - } - - if p.Type == packageurl.TypeRPM { - rpmVer := version.NewVersion(p.Version) - pkg.Release = rpmVer.Release() - pkg.Version = rpmVer.Version() - } - - // Return packages without namespace. - // OS packages are not supposed to have namespace. - if p.Namespace == "" || p.Class() == types.ClassOSPkg { - return pkg - } - - // TODO: replace with packageurl.TypeGradle once they add it. - if p.Type == packageurl.TypeMaven || p.Type == string(ftypes.Gradle) { - // Maven and Gradle packages separate ":" - // e.g. org.springframework:spring-core - pkg.Name = p.Namespace + ":" + p.Name - } else { - pkg.Name = p.Namespace + "/" + p.Name - } - - return pkg +func FromString(s string) (*ftypes.PackageURL, error) { + return ftypes.NewPackageURL(s) } // LangType returns an application type in Trivy // nolint: gocyclo -func (p *PackageURL) LangType() ftypes.LangType { +func LangType(p *ftypes.PackageURL) ftypes.LangType { switch p.Type { case packageurl.TypeComposer: return ftypes.Composer @@ -165,13 +102,13 @@ func (p *PackageURL) LangType() ftypes.LangType { } } -func (p *PackageURL) Class() types.ResultClass { +func Class(p *ftypes.PackageURL) types.ResultClass { switch p.Type { case packageurl.TypeApk, packageurl.TypeDebian, packageurl.TypeRPM: // OS packages return types.ClassOSPkg default: - if p.LangType() == TypeUnknown { + if LangType(p) == TypeUnknown { return types.ClassUnknown } // Language-specific packages @@ -179,31 +116,61 @@ func (p *PackageURL) Class() types.ResultClass { } } -func (p *PackageURL) BOMRef() string { - // 'bom-ref' must be unique within BOM, but PURLs may conflict - // when the same packages are installed in an artifact. - // In that case, we prefer to make PURLs unique by adding file paths, - // rather than using UUIDs, even if it is not PURL technically. - // ref. https://cyclonedx.org/use-cases/#dependency-graph - purl := p.PackageURL // so that it will not override the qualifiers below - if p.FilePath != "" { - purl.Qualifiers = append(purl.Qualifiers, - packageurl.Qualifier{ - Key: "file_path", - Value: p.FilePath, - }, - ) +func ToPackage(p *ftypes.PackageURL) *ftypes.Package { + pkg := &ftypes.Package{ + Name: p.Name, + Version: p.Version, + } + for _, q := range p.Qualifiers { + switch q.Key { + case "arch": + pkg.Arch = q.Value + case "modularitylabel": + pkg.Modularitylabel = q.Value + case "epoch": + epoch, err := strconv.Atoi(q.Value) + if err == nil { + pkg.Epoch = epoch + } + } + } + + // CocoaPods purl has no namespace, but has subpath + // https://github.com/package-url/purl-spec/blob/a748c36ad415c8aeffe2b8a4a5d8a50d16d6d85f/PURL-TYPES.rst#cocoapods + if p.Type == packageurl.TypeCocoapods && p.Subpath != "" { + // CocoaPods uses / format for package name + // e.g. `pkg:cocoapods/GoogleUtilities@7.5.2#NSData+zlib` => `GoogleUtilities/NSData+zlib` + pkg.Name = p.Name + "/" + p.Subpath } - return purl.String() + + if p.Type == packageurl.TypeRPM { + rpmVer := version.NewVersion(p.Version) + pkg.Release = rpmVer.Release() + pkg.Version = rpmVer.Version() + } + + // Return packages without namespace. + // OS packages are not supposed to have namespace. + if p.Namespace == "" || Class(p) == types.ClassOSPkg { + return pkg + } + + // TODO: replace with packageurl.TypeGradle once they add it. + if p.Type == packageurl.TypeMaven || p.Type == packageurl.TypeGradle { + // Maven and Gradle packages separate ":" + // e.g. org.springframework:spring-core + pkg.Name = p.Namespace + ":" + p.Name + } else { + pkg.Name = p.Namespace + "/" + p.Name + } + + return pkg } // nolint: gocyclo -func NewPackageURL(t ftypes.TargetType, metadata types.Metadata, pkg ftypes.Package) (*PackageURL, error) { - var qualifiers packageurl.Qualifiers - if metadata.OS != nil { - qualifiers = parseQualifier(pkg) - pkg.Epoch = 0 // we moved Epoch to qualifiers so we don't need it in version - } +func New(t ftypes.TargetType, metadata types.Metadata, pkg ftypes.Package) (*ftypes.PackageURL, error) { + qualifiers := parseQualifier(pkg) + pkg.Epoch = 0 // we moved Epoch to qualifiers so we don't need it in version ptype := purlType(t) name := pkg.Name @@ -250,10 +217,10 @@ func NewPackageURL(t ftypes.TargetType, metadata types.Metadata, pkg ftypes.Pack if purl.Type == "" { return nil, nil } - return &PackageURL{PackageURL: purl}, nil + return &ftypes.PackageURL{PackageURL: purl}, nil } - return &PackageURL{ + return &ftypes.PackageURL{ PackageURL: *packageurl.NewPackageURL(ptype, namespace, name, ver, qualifiers, subpath), FilePath: pkg.FilePath, }, nil @@ -449,7 +416,7 @@ func purlType(t ftypes.TargetType) string { } func parseQualifier(pkg ftypes.Package) packageurl.Qualifiers { - qualifiers := packageurl.Qualifiers{} + var qualifiers packageurl.Qualifiers if pkg.Arch != "" { qualifiers = append(qualifiers, packageurl.Qualifier{ Key: "arch", @@ -462,6 +429,7 @@ func parseQualifier(pkg ftypes.Package) packageurl.Qualifiers { Value: strconv.Itoa(pkg.Epoch), }) } + return qualifiers } diff --git a/pkg/purl/purl_test.go b/pkg/purl/purl_test.go index 9847ff57d5ce..16c32cdf056c 100644 --- a/pkg/purl/purl_test.go +++ b/pkg/purl/purl_test.go @@ -20,7 +20,7 @@ func TestNewPackageURL(t *testing.T) { typ ftypes.TargetType pkg ftypes.Package metadata types.Metadata - want *purl.PackageURL + want *ftypes.PackageURL wantErr string }{ { @@ -30,7 +30,7 @@ func TestNewPackageURL(t *testing.T) { Name: "org.springframework:spring-core", Version: "5.3.14", }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven, Namespace: "org.springframework", @@ -46,7 +46,7 @@ func TestNewPackageURL(t *testing.T) { Name: "org.springframework:spring-core", Version: "5.3.14", }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeMaven, Namespace: "org.springframework", @@ -62,7 +62,7 @@ func TestNewPackageURL(t *testing.T) { Name: "@xtuc/ieee754", Version: "1.2.0", }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeNPM, Namespace: "@xtuc", @@ -78,7 +78,7 @@ func TestNewPackageURL(t *testing.T) { Name: "lodash", Version: "4.17.21", }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeNPM, Name: "lodash", @@ -93,7 +93,7 @@ func TestNewPackageURL(t *testing.T) { Name: "@xtuc/ieee754", Version: "1.2.0", }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeNPM, Namespace: "@xtuc", @@ -109,7 +109,7 @@ func TestNewPackageURL(t *testing.T) { Name: "lodash", Version: "4.17.21", }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeNPM, Name: "lodash", @@ -124,7 +124,7 @@ func TestNewPackageURL(t *testing.T) { Name: "Django_test", Version: "1.2.0", }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypePyPi, Name: "django-test", @@ -139,7 +139,7 @@ func TestNewPackageURL(t *testing.T) { Name: "absl-py", Version: "0.4.1", }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeConda, Name: "absl-py", @@ -154,7 +154,7 @@ func TestNewPackageURL(t *testing.T) { Name: "symfony/contracts", Version: "v1.0.2", }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer, Namespace: "symfony", @@ -170,7 +170,7 @@ func TestNewPackageURL(t *testing.T) { Name: "github.com/go-sql-driver/Mysql", Version: "v1.5.0", }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeGolang, Namespace: "github.com/go-sql-driver", @@ -202,7 +202,7 @@ func TestNewPackageURL(t *testing.T) { }, }, }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeHex, Name: "bunt", @@ -217,7 +217,7 @@ func TestNewPackageURL(t *testing.T) { Name: "http", Version: "0.13.2", }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypePub, Name: "http", @@ -233,7 +233,7 @@ func TestNewPackageURL(t *testing.T) { Name: "github.com/apple/swift-atomics", Version: "1.1.0", }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeSwift, Namespace: "github.com/apple", @@ -250,7 +250,7 @@ func TestNewPackageURL(t *testing.T) { Name: "GoogleUtilities/NSData+zlib", Version: "7.5.2", }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeCocoapods, Name: "GoogleUtilities", @@ -267,7 +267,7 @@ func TestNewPackageURL(t *testing.T) { Name: "abomination", Version: "0.7.3", }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeCargo, Name: "abomination", @@ -283,7 +283,7 @@ func TestNewPackageURL(t *testing.T) { Name: "Newtonsoft.Json", Version: "9.0.1", }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeNuget, Name: "Newtonsoft.Json", @@ -313,7 +313,7 @@ func TestNewPackageURL(t *testing.T) { Name: "8", }, }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeRPM, Namespace: "redhat", @@ -351,7 +351,7 @@ func TestNewPackageURL(t *testing.T) { Architecture: "amd64", }, }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeOCI, Namespace: "", @@ -399,7 +399,7 @@ func TestNewPackageURL(t *testing.T) { Architecture: "amd64", }, }, - want: &purl.PackageURL{ + want: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeOCI, Namespace: "", @@ -435,7 +435,7 @@ func TestNewPackageURL(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - packageURL, err := purl.NewPackageURL(tc.typ, tc.metadata, tc.pkg) + packageURL, err := purl.New(tc.typ, tc.metadata, tc.pkg) if tc.wantErr != "" { require.Error(t, err) assert.Contains(t, err.Error(), tc.wantErr) @@ -451,19 +451,18 @@ func TestFromString(t *testing.T) { testCases := []struct { name string purl string - want purl.PackageURL + want ftypes.PackageURL wantErr string }{ { name: "happy path for maven", purl: "pkg:maven/org.springframework/spring-core@5.0.4.RELEASE", - want: purl.PackageURL{ + want: ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ - Type: packageurl.TypeMaven, - Namespace: "org.springframework", - Version: "5.0.4.RELEASE", - Name: "spring-core", - Qualifiers: packageurl.Qualifiers{}, + Type: packageurl.TypeMaven, + Namespace: "org.springframework", + Version: "5.0.4.RELEASE", + Name: "spring-core", }, FilePath: "", }, @@ -471,61 +470,53 @@ func TestFromString(t *testing.T) { { name: "happy path for npm", purl: "pkg:npm/bootstrap@5.0.2?file_path=app%2Fapp%2Fpackage.json", - want: purl.PackageURL{ + want: ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeNPM, Name: "bootstrap", Version: "5.0.2", - Qualifiers: packageurl.Qualifiers{ - { - Key: "file_path", - Value: "app/app/package.json", - }, - }, }, + FilePath: "app/app/package.json", }, }, { name: "happy path for coocapods", purl: "pkg:cocoapods/GoogleUtilities@7.5.2#NSData+zlib", - want: purl.PackageURL{ + want: ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ - Type: packageurl.TypeCocoapods, - Name: "GoogleUtilities", - Version: "7.5.2", - Subpath: "NSData+zlib", - Qualifiers: packageurl.Qualifiers{}, + Type: packageurl.TypeCocoapods, + Name: "GoogleUtilities", + Version: "7.5.2", + Subpath: "NSData+zlib", }, }, }, { name: "happy path for hex", purl: "pkg:hex/plug@1.14.0", - want: purl.PackageURL{ + want: ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ - Type: packageurl.TypeHex, - Name: "plug", - Version: "1.14.0", - Qualifiers: packageurl.Qualifiers{}, + Type: packageurl.TypeHex, + Name: "plug", + Version: "1.14.0", }, }, }, { name: "happy path for dart", purl: "pkg:pub/http@0.13.2", - want: purl.PackageURL{ + want: ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ - Type: packageurl.TypePub, - Name: "http", - Version: "0.13.2", - Qualifiers: packageurl.Qualifiers{}, + Type: packageurl.TypePub, + Name: "http", + Version: "0.13.2", }, }, }, { name: "happy path for apk", purl: "pkg:apk/alpine/alpine-baselayout@3.2.0-r16?distro=3.14.2&epoch=1", - want: purl.PackageURL{ + want: ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: string(analyzer.TypeApk), Namespace: "alpine", @@ -547,38 +538,35 @@ func TestFromString(t *testing.T) { { name: "happy path for rpm", purl: "pkg:rpm/redhat/containers-common@0.1.14", - want: purl.PackageURL{ + want: ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ - Type: packageurl.TypeRPM, - Namespace: "redhat", - Name: "containers-common", - Version: "0.1.14", - Qualifiers: packageurl.Qualifiers{}, + Type: packageurl.TypeRPM, + Namespace: "redhat", + Name: "containers-common", + Version: "0.1.14", }, }, }, { name: "happy path for conda", purl: "pkg:conda/absl-py@0.4.1", - want: purl.PackageURL{ + want: ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ - Type: packageurl.TypeConda, - Name: "absl-py", - Version: "0.4.1", - Qualifiers: packageurl.Qualifiers{}, + Type: packageurl.TypeConda, + Name: "absl-py", + Version: "0.4.1", }, }, }, { name: "bad rpm", purl: "pkg:rpm/redhat/a--@1.0.0", - want: purl.PackageURL{ + want: ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ - Type: packageurl.TypeRPM, - Namespace: "redhat", - Name: "a--", - Version: "1.0.0", - Qualifiers: packageurl.Qualifiers{}, + Type: packageurl.TypeRPM, + Namespace: "redhat", + Name: "a--", + Version: "1.0.0", }, }, }, @@ -588,8 +576,7 @@ func TestFromString(t *testing.T) { t.Run(tc.name, func(t *testing.T) { pkg, err := purl.FromString(tc.purl) if tc.wantErr != "" { - require.Error(t, err) - assert.Contains(t, err.Error(), tc.wantErr) + assert.ErrorContains(t, err, tc.wantErr) return } assert.NoError(t, err) @@ -598,15 +585,15 @@ func TestFromString(t *testing.T) { } } -func TestPackage(t *testing.T) { +func TestToPackage(t *testing.T) { tests := []struct { name string - pkgURL *purl.PackageURL + pkgURL *ftypes.PackageURL wantPkg *ftypes.Package }{ { name: "rpm + Qualifiers", - pkgURL: &purl.PackageURL{ + pkgURL: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeRPM, Namespace: "redhat", @@ -643,7 +630,7 @@ func TestPackage(t *testing.T) { }, { name: "composer with namespace", - pkgURL: &purl.PackageURL{ + pkgURL: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeComposer, Namespace: "symfony", @@ -658,13 +645,12 @@ func TestPackage(t *testing.T) { }, { name: "maven with namespace", - pkgURL: &purl.PackageURL{ + pkgURL: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ - Type: packageurl.TypeMaven, - Namespace: "org.springframework", - Name: "spring-core", - Version: "5.0.4.RELEASE", - Qualifiers: packageurl.Qualifiers{}, + Type: packageurl.TypeMaven, + Namespace: "org.springframework", + Name: "spring-core", + Version: "5.0.4.RELEASE", }, }, wantPkg: &ftypes.Package{ @@ -674,13 +660,12 @@ func TestPackage(t *testing.T) { }, { name: "cocoapods with subpath", - pkgURL: &purl.PackageURL{ + pkgURL: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ - Type: packageurl.TypeCocoapods, - Version: "4.2.0", - Name: "AppCenter", - Subpath: "Analytics", - Qualifiers: packageurl.Qualifiers{}, + Type: packageurl.TypeCocoapods, + Version: "4.2.0", + Name: "AppCenter", + Subpath: "Analytics", }, }, wantPkg: &ftypes.Package{ @@ -690,7 +675,7 @@ func TestPackage(t *testing.T) { }, { name: "wrong epoch", - pkgURL: &purl.PackageURL{ + pkgURL: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: packageurl.TypeRPM, Namespace: "redhat", @@ -714,13 +699,13 @@ func TestPackage(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := tt.pkgURL.Package() + got := purl.ToPackage(tt.pkgURL) assert.Equal(t, tt.wantPkg, got) }) } } -func TestPackageURL_LangType(t *testing.T) { +func TestLangType(t *testing.T) { tests := []struct { name string purl packageurl.PackageURL @@ -758,8 +743,8 @@ func TestPackageURL_LangType(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - p := &purl.PackageURL{PackageURL: tt.purl} - assert.Equalf(t, tt.want, p.LangType(), "LangType()") + p := &ftypes.PackageURL{PackageURL: tt.purl} + assert.Equalf(t, tt.want, purl.LangType(p), "LangType()") }) } } diff --git a/pkg/report/github/github.go b/pkg/report/github/github.go index 9476c5020709..8384f27b0e74 100644 --- a/pkg/report/github/github.go +++ b/pkg/report/github/github.go @@ -161,7 +161,7 @@ func getPkgRelationshipType(pkg ftypes.Package) string { } func buildPurl(t ftypes.TargetType, metadata types.Metadata, pkg ftypes.Package) (string, error) { - packageUrl, err := purl.NewPackageURL(t, metadata, pkg) + packageUrl, err := purl.New(t, metadata, pkg) if err != nil { return "", xerrors.Errorf("purl error: %w", err) } diff --git a/pkg/result/filter_test.go b/pkg/result/filter_test.go index afe32726aa43..7392a4779861 100644 --- a/pkg/result/filter_test.go +++ b/pkg/result/filter_test.go @@ -2,6 +2,7 @@ package result_test import ( "context" + "github.com/package-url/packageurl-go" "testing" "time" @@ -150,9 +151,18 @@ func TestFilter(t *testing.T) { types.Result{ Vulnerabilities: []types.DetectedVulnerability{ { - VulnerabilityID: "CVE-2019-0001", - PkgName: "foo", - PkgRef: "pkg:golang/github.com/aquasecurity/foo@1.2.3", + VulnerabilityID: "CVE-2019-0001", + PkgName: "foo", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "github.com/aquasecurity", + Name: "foo", + Version: "1.2.3", + }, + }, + }, InstalledVersion: "1.2.3", FixedVersion: "1.2.4", Vulnerability: dbTypes.Vulnerability{ @@ -160,11 +170,20 @@ func TestFilter(t *testing.T) { }, }, { - VulnerabilityID: "CVE-2019-0001", - PkgName: "bar", - PkgRef: "pkg:golang/github.com/aquasecurity/bar@1.2.3", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", + VulnerabilityID: "CVE-2019-0001", + PkgName: "bar", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "github.com/aquasecurity", + Name: "bar", + Version: "4.5.6", + }, + }, + }, + InstalledVersion: "4.5.6", + FixedVersion: "4.5.7", Vulnerability: dbTypes.Vulnerability{ Severity: dbTypes.SeverityCritical.String(), }, @@ -187,11 +206,20 @@ func TestFilter(t *testing.T) { types.Result{ Vulnerabilities: []types.DetectedVulnerability{ { - VulnerabilityID: "CVE-2019-0001", - PkgName: "bar", - PkgRef: "pkg:golang/github.com/aquasecurity/bar@1.2.3", - InstalledVersion: "1.2.3", - FixedVersion: "1.2.4", + VulnerabilityID: "CVE-2019-0001", + PkgName: "bar", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "github.com/aquasecurity", + Name: "bar", + Version: "4.5.6", + }, + }, + }, + InstalledVersion: "4.5.6", + FixedVersion: "4.5.7", Vulnerability: dbTypes.Vulnerability{ Severity: dbTypes.SeverityCritical.String(), }, @@ -713,7 +741,8 @@ func TestFilter(t *testing.T) { Severity: dbTypes.SeverityHigh.String(), Status: types.StatusPassed, }, - { // this misconf is ignored + { + // this misconf is ignored ID: "AVD-TEST-0003", AVDID: "AVD-TEST-0003", Title: "test-0003", diff --git a/pkg/rpc/convert.go b/pkg/rpc/convert.go index d3bc29425a4b..d828533c596e 100644 --- a/pkg/rpc/convert.go +++ b/pkg/rpc/convert.go @@ -11,6 +11,7 @@ import ( "github.com/aquasecurity/trivy/pkg/digest" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" + "github.com/aquasecurity/trivy/pkg/purl" "github.com/aquasecurity/trivy/pkg/types" "github.com/aquasecurity/trivy/rpc/cache" "github.com/aquasecurity/trivy/rpc/common" @@ -57,6 +58,7 @@ func ConvertToRPCPkgs(pkgs []ftypes.Package) []*common.Package { Release: pkg.Release, Epoch: int32(pkg.Epoch), Arch: pkg.Arch, + Identifier: ConvertToRPCPkgIdentifier(pkg.Identifier), Dev: pkg.Dev, SrcName: pkg.SrcName, SrcVersion: pkg.SrcVersion, @@ -73,6 +75,20 @@ func ConvertToRPCPkgs(pkgs []ftypes.Package) []*common.Package { return rpcPkgs } +func ConvertToRPCPkgIdentifier(pkg ftypes.PkgIdentifier) *common.PkgIdentifier { + if pkg.Empty() { + return nil + } + + var p string + if pkg.PURL != nil { + p = pkg.PURL.BOMRef() // Use BOMRef() instead of String() so that we won't lose file_path + } + return &common.PkgIdentifier{ + Purl: p, + } +} + func ConvertToRPCCustomResources(resources []ftypes.CustomResource) []*common.CustomResource { var rpcResources []*common.CustomResource for _, r := range resources { @@ -183,6 +199,7 @@ func ConvertFromRPCPkgs(rpcPkgs []*common.Package) []ftypes.Package { Release: pkg.Release, Epoch: int(pkg.Epoch), Arch: pkg.Arch, + Identifier: ConvertFromRPCPkgIdentifier(pkg.Identifier), Dev: pkg.Dev, SrcName: pkg.SrcName, SrcVersion: pkg.SrcVersion, @@ -199,6 +216,19 @@ func ConvertFromRPCPkgs(rpcPkgs []*common.Package) []ftypes.Package { return pkgs } +func ConvertFromRPCPkgIdentifier(pkg *common.PkgIdentifier) ftypes.PkgIdentifier { + if pkg == nil || pkg.Purl == "" { + return ftypes.PkgIdentifier{} + } + pu, err := purl.FromString(pkg.Purl) + if err != nil { + log.Logger.Error("Failed to parse PURL (%s): %s", pkg.Purl, err) + } + return ftypes.PkgIdentifier{ + PURL: pu, + } +} + // ConvertToRPCVulns returns common.Vulnerability func ConvertToRPCVulns(vulns []types.DetectedVulnerability) []*common.Vulnerability { var rpcVulns []*common.Vulnerability @@ -246,6 +276,7 @@ func ConvertToRPCVulns(vulns []types.DetectedVulnerability) []*common.Vulnerabil PkgPath: vuln.PkgPath, InstalledVersion: vuln.InstalledVersion, FixedVersion: vuln.FixedVersion, + PkgIdentifier: ConvertToRPCPkgIdentifier(vuln.PkgIdentifier), Status: int32(vuln.Status), Title: vuln.Title, Description: vuln.Description, @@ -521,6 +552,7 @@ func ConvertFromRPCVulns(rpcVulns []*common.Vulnerability) []types.DetectedVulne PkgPath: vuln.PkgPath, InstalledVersion: vuln.InstalledVersion, FixedVersion: vuln.FixedVersion, + PkgIdentifier: ConvertFromRPCPkgIdentifier(vuln.PkgIdentifier), Status: dbTypes.Status(vuln.Status), Vulnerability: dbTypes.Vulnerability{ Title: vuln.Title, diff --git a/pkg/sbom/cyclonedx/core/cyclonedx.go b/pkg/sbom/cyclonedx/core/cyclonedx.go index dad245b5239c..5d61f2993f72 100644 --- a/pkg/sbom/cyclonedx/core/cyclonedx.go +++ b/pkg/sbom/cyclonedx/core/cyclonedx.go @@ -14,8 +14,8 @@ import ( "github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability" "github.com/aquasecurity/trivy/pkg/clock" "github.com/aquasecurity/trivy/pkg/digest" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" - "github.com/aquasecurity/trivy/pkg/purl" "github.com/aquasecurity/trivy/pkg/types" "github.com/aquasecurity/trivy/pkg/uuid" ) @@ -38,7 +38,7 @@ type Component struct { Name string Group string Version string - PackageURL *purl.PackageURL + PackageURL *ftypes.PackageURL Licenses []string Hashes []digest.Digest Supplier string @@ -231,7 +231,7 @@ func (c *CycloneDX) Vulnerabilities(uniq map[string]*cdx.Vulnerability) *[]cdx.V return &vulns } -func (c *CycloneDX) PackageURL(p *purl.PackageURL) string { +func (c *CycloneDX) PackageURL(p *ftypes.PackageURL) string { if p == nil { return "" } diff --git a/pkg/sbom/cyclonedx/core/cyclonedx_test.go b/pkg/sbom/cyclonedx/core/cyclonedx_test.go index c147b74247df..2685a56ef733 100644 --- a/pkg/sbom/cyclonedx/core/cyclonedx_test.go +++ b/pkg/sbom/cyclonedx/core/cyclonedx_test.go @@ -10,7 +10,7 @@ import ( "github.com/aquasecurity/trivy/pkg/clock" "github.com/aquasecurity/trivy/pkg/digest" - "github.com/aquasecurity/trivy/pkg/purl" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/sbom/cyclonedx/core" "github.com/aquasecurity/trivy/pkg/uuid" ) @@ -42,7 +42,7 @@ func TestMarshaler_CoreComponent(t *testing.T) { Type: cdx.ComponentTypeContainer, Name: "k8s.gcr.io/kube-apiserver", Version: "sha256:18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f", - PackageURL: &purl.PackageURL{ + PackageURL: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: "oci", Name: "kube-apiserver", @@ -137,7 +137,7 @@ func TestMarshaler_CoreComponent(t *testing.T) { Value: "golang", }, }, - PackageURL: &purl.PackageURL{ + PackageURL: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: "golang", Name: "kubelet", @@ -156,7 +156,7 @@ func TestMarshaler_CoreComponent(t *testing.T) { Value: "golang", }, }, - PackageURL: &purl.PackageURL{ + PackageURL: &ftypes.PackageURL{ PackageURL: packageurl.PackageURL{ Type: "golang", Name: "containerd", diff --git a/pkg/sbom/cyclonedx/marshal.go b/pkg/sbom/cyclonedx/marshal.go index c6934571c0a0..586b82d3ee39 100644 --- a/pkg/sbom/cyclonedx/marshal.go +++ b/pkg/sbom/cyclonedx/marshal.go @@ -236,7 +236,7 @@ func (e *Marshaler) rootComponent(r types.Report) (*core.Component, error) { Value: r.Metadata.ImageID, }) - p, err := purl.NewPackageURL(purl.TypeOCI, r.Metadata, ftypes.Package{}) + p, err := purl.New(purl.TypeOCI, r.Metadata, ftypes.Package{}) if err != nil { return nil, xerrors.Errorf("failed to new package url for oci: %w", err) } @@ -315,17 +315,12 @@ func (e *Marshaler) resultComponent(r types.Result, osFound *ftypes.OS) *core.Co } func pkgComponent(pkg Package) (*core.Component, error) { - pu, err := purl.NewPackageURL(pkg.Type, pkg.Metadata, pkg.Package) - if err != nil { - return nil, xerrors.Errorf("failed to new package purl: %w", err) - } - name := pkg.Name version := pkg.Version var group string // there are cases when we can't build purl // e.g. local Go packages - if pu != nil { + if pu := pkg.Identifier.PURL; pu != nil { version = pu.Version // use `group` field for GroupID and `name` for ArtifactID for jar files if pkg.Type == ftypes.Jar { @@ -382,7 +377,7 @@ func pkgComponent(pkg Package) (*core.Component, error) { Name: name, Group: group, Version: version, - PackageURL: pu, + PackageURL: pkg.Identifier.PURL, Supplier: pkg.Maintainer, Licenses: pkg.Licenses, Hashes: lo.Ternary(pkg.Digest == "", nil, []digest.Digest{pkg.Digest}), diff --git a/pkg/sbom/cyclonedx/marshal_test.go b/pkg/sbom/cyclonedx/marshal_test.go index 59f77a24ad63..234f2b9d0ae5 100644 --- a/pkg/sbom/cyclonedx/marshal_test.go +++ b/pkg/sbom/cyclonedx/marshal_test.go @@ -1,6 +1,7 @@ package cyclonedx_test import ( + "github.com/package-url/packageurl-go" "testing" "time" @@ -54,12 +55,32 @@ func TestMarshaler_Marshal(t *testing.T) { Type: ftypes.CentOS, Packages: []ftypes.Package{ { - ID: "binutils@2.30-93.el8", - Name: "binutils", - Version: "2.30", - Release: "93.el8", - Epoch: 0, - Arch: "aarch64", + ID: "binutils@2.30-93.el8", + Name: "binutils", + Version: "2.30", + Release: "93.el8", + Epoch: 0, + Arch: "aarch64", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeRPM, + Namespace: "centos", + Name: "binutils", + Version: "2.30-93.el8", + Qualifiers: packageurl.Qualifiers{ + { + Key: "arch", + Value: "aarch64", + }, + { + Key: "distro", + Value: "centos-8.3.2011", + }, + }, + }, + }, + }, SrcName: "binutils", SrcVersion: "2.30", SrcRelease: "93.el8", @@ -119,15 +140,33 @@ func TestMarshaler_Marshal(t *testing.T) { Type: ftypes.Bundler, Packages: []ftypes.Package{ { - ID: "actionpack@7.0.0", - Name: "actionpack", - Version: "7.0.0", + ID: "actionpack@7.0.0", + Name: "actionpack", + Version: "7.0.0", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "actionpack", + Version: "7.0.0", + }, + }, + }, Indirect: false, }, { - ID: "actioncontroller@7.0.0", - Name: "actioncontroller", - Version: "7.0.0", + ID: "actioncontroller@7.0.0", + Name: "actioncontroller", + Version: "7.0.0", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "actioncontroller", + Version: "7.0.0", + }, + }, + }, Indirect: false, DependsOn: []string{ "actionpack@7.0.0", @@ -144,6 +183,15 @@ func TestMarshaler_Marshal(t *testing.T) { ID: "actionpack@7.0.0", Name: "actionpack", Version: "7.0.0", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "actionpack", + Version: "7.0.0", + }, + }, + }, }, }, }, @@ -156,6 +204,15 @@ func TestMarshaler_Marshal(t *testing.T) { ID: "Newtonsoft.Json@9.0.1", Name: "Newtonsoft.Json", Version: "9.0.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeNuget, + Name: "Newtonsoft.Json", + Version: "9.0.1", + }, + }, + }, }, }, }, @@ -167,6 +224,16 @@ func TestMarshaler_Marshal(t *testing.T) { { Name: "golang.org/x/crypto", Version: "v0.0.0-20210421170649-83a5a9bb288b", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "golang.org/x", + Name: "crypto", + Version: "v0.0.0-20210421170649-83a5a9bb288b", + }, + }, + }, }, // dependency has been replaced with local directory { @@ -592,12 +659,36 @@ func TestMarshaler_Marshal(t *testing.T) { Type: ftypes.CentOS, Packages: []ftypes.Package{ { - ID: "acl@2.2.53-1.el8", - Name: "acl", - Version: "2.2.53", - Release: "1.el8", - Epoch: 1, - Arch: "aarch64", + ID: "acl@2.2.53-1.el8", + Name: "acl", + Version: "2.2.53", + Release: "1.el8", + Epoch: 1, + Arch: "aarch64", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeRPM, + Namespace: "centos", + Name: "acl", + Version: "2.2.53-1.el8", + Qualifiers: packageurl.Qualifiers{ + { + Key: "arch", + Value: "aarch64", + }, + { + Key: "distro", + Value: "centos-8.3.2011", + }, + { + Key: "epoch", + Value: "1", + }, + }, + }, + }, + }, SrcName: "acl", SrcVersion: "2.2.53", SrcRelease: "1.el8", @@ -610,12 +701,32 @@ func TestMarshaler_Marshal(t *testing.T) { Digest: "md5:483792b8b5f9eb8be7dc4407733118d0", }, { - ID: "glibc@2.28-151.el8", - Name: "glibc", - Version: "2.28", - Release: "151.el8", - Epoch: 0, - Arch: "aarch64", + ID: "glibc@2.28-151.el8", + Name: "glibc", + Version: "2.28", + Release: "151.el8", + Epoch: 0, + Arch: "aarch64", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeRPM, + Namespace: "centos", + Name: "glibc", + Version: "2.28-151.el8", + Qualifiers: packageurl.Qualifiers{ + { + Key: "arch", + Value: "aarch64", + }, + { + Key: "distro", + Value: "centos-8.3.2011", + }, + }, + }, + }, + }, SrcName: "glibc", SrcVersion: "2.28", SrcRelease: "151.el8", @@ -635,6 +746,16 @@ func TestMarshaler_Marshal(t *testing.T) { ID: "actionpack@7.0.0", Name: "actionpack", Version: "7.0.0", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "actionpack", + Version: "7.0.0", + }, + FilePath: "tools/project-john/specifications/actionpack.gemspec", + }, + }, Layer: ftypes.Layer{ DiffID: "sha256:ccb64cf0b7ba2e50741d0b64cae324eb5de3b1e2f580bbf177e721b67df38488", }, @@ -644,6 +765,16 @@ func TestMarshaler_Marshal(t *testing.T) { ID: "actionpack@7.0.1", Name: "actionpack", Version: "7.0.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "actionpack", + Version: "7.0.1", + }, + FilePath: "tools/project-doe/specifications/actionpack.gemspec", + }, + }, Layer: ftypes.Layer{ DiffID: "sha256:ccb64cf0b7ba2e50741d0b64cae324eb5de3b1e2f580bbf177e721b67df38488", }, @@ -652,10 +783,19 @@ func TestMarshaler_Marshal(t *testing.T) { }, Vulnerabilities: []types.DetectedVulnerability{ { - VulnerabilityID: "CVE-2022-23633", - PkgID: "actionpack@7.0.0", - PkgName: "actionpack", - PkgPath: "tools/project-john/specifications/actionpack.gemspec", + VulnerabilityID: "CVE-2022-23633", + PkgID: "actionpack@7.0.0", + PkgName: "actionpack", + PkgPath: "tools/project-john/specifications/actionpack.gemspec", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "actionpack", + Version: "7.0.0", + }, + }, + }, InstalledVersion: "7.0.0", FixedVersion: "~> 5.2.6, >= 5.2.6.2, ~> 6.0.4, >= 6.0.4.6, ~> 6.1.4, >= 6.1.4.6, >= 7.0.2.2", SeveritySource: vulnerability.RubySec, @@ -695,10 +835,19 @@ func TestMarshaler_Marshal(t *testing.T) { }, }, { - VulnerabilityID: "CVE-2022-23633", - PkgID: "actionpack@7.0.1", - PkgName: "actionpack", - PkgPath: "tools/project-doe/specifications/actionpack.gemspec", + VulnerabilityID: "CVE-2022-23633", + PkgID: "actionpack@7.0.1", + PkgName: "actionpack", + PkgPath: "tools/project-doe/specifications/actionpack.gemspec", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "actionpack", + Version: "7.0.1", + }, + }, + }, InstalledVersion: "7.0.1", FixedVersion: "~> 5.2.6, >= 5.2.6.2, ~> 6.0.4, >= 6.0.4.6, ~> 6.1.4, >= 6.1.4.6, >= 7.0.2.2", SeveritySource: vulnerability.RubySec, @@ -1070,6 +1219,15 @@ func TestMarshaler_Marshal(t *testing.T) { { Name: "actioncable", Version: "6.1.4.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "actioncable", + Version: "6.1.4.1", + }, + }, + }, }, }, }, @@ -1079,8 +1237,19 @@ func TestMarshaler_Marshal(t *testing.T) { Type: ftypes.Jar, Packages: []ftypes.Package{ { - Name: "org.springframework:spring-web", - Version: "5.3.22", + Name: "org.springframework:spring-web", + Version: "5.3.22", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.springframework", + Name: "spring-web", + Version: "5.3.22", + }, + FilePath: "spring-web-5.3.22.jar", + }, + }, FilePath: "spring-web-5.3.22.jar", }, }, @@ -1202,21 +1371,53 @@ func TestMarshaler_Marshal(t *testing.T) { Type: ftypes.Jar, Packages: []ftypes.Package{ { - Name: "org.apache.nifi:nifi-dbcp-base", - Version: "1.20.0", + Name: "org.apache.nifi:nifi-dbcp-base", + Version: "1.20.0", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.apache.nifi", + Name: "nifi-dbcp-base", + Version: "1.20.0", + }, + FilePath: "nifi-dbcp-base-1.20.0.jar", + }, + }, FilePath: "nifi-dbcp-base-1.20.0.jar", }, { - Name: "org.apache.nifi:nifi-hikari-dbcp-service", - Version: "1.20.0", + Name: "org.apache.nifi:nifi-hikari-dbcp-service", + Version: "1.20.0", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.apache.nifi", + Name: "nifi-hikari-dbcp-service", + Version: "1.20.0", + }, + FilePath: "nifi-hikari-dbcp-service-1.20.0.jar", + }, + }, FilePath: "nifi-hikari-dbcp-service-1.20.0.jar", }, }, Vulnerabilities: []types.DetectedVulnerability{ { - VulnerabilityID: "CVE-2023-34468", - PkgName: "org.apache.nifi:nifi-dbcp-base", - PkgPath: "nifi-dbcp-base-1.20.0.jar", + VulnerabilityID: "CVE-2023-34468", + PkgName: "org.apache.nifi:nifi-dbcp-base", + PkgPath: "nifi-dbcp-base-1.20.0.jar", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.apache.nifi", + Name: "nifi-dbcp-base", + Version: "1.20.0", + }, + }, + }, InstalledVersion: "1.20.0", FixedVersion: "1.22.0", SeveritySource: vulnerability.GHSA, @@ -1256,9 +1457,19 @@ func TestMarshaler_Marshal(t *testing.T) { }, }, { - VulnerabilityID: "CVE-2023-34468", - PkgName: "org.apache.nifi:nifi-hikari-dbcp-service", - PkgPath: "nifi-hikari-dbcp-service-1.20.0.jar", + VulnerabilityID: "CVE-2023-34468", + PkgName: "org.apache.nifi:nifi-hikari-dbcp-service", + PkgPath: "nifi-hikari-dbcp-service-1.20.0.jar", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.apache.nifi", + Name: "nifi-hikari-dbcp-service", + Version: "1.20.0", + }, + }, + }, InstalledVersion: "1.20.0", FixedVersion: "1.22.0", SeveritySource: vulnerability.GHSA, @@ -1464,9 +1675,19 @@ func TestMarshaler_Marshal(t *testing.T) { Type: ftypes.NodePkg, Packages: []ftypes.Package{ { - ID: "ruby-typeprof@0.20.1", - Name: "ruby-typeprof", - Version: "0.20.1", + ID: "ruby-typeprof@0.20.1", + Name: "ruby-typeprof", + Version: "0.20.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeNPM, + Name: "ruby-typeprof", + Version: "0.20.1", + }, + FilePath: "usr/local/lib/ruby/gems/3.1.0/gems/typeprof-0.21.1/vscode/package.json", + }, + }, Licenses: []string{"MIT"}, Layer: ftypes.Layer{ DiffID: "sha256:661c3fd3cc16b34c070f3620ca6b03b6adac150f9a7e5d0e3c707a159990f88e", diff --git a/pkg/sbom/cyclonedx/unmarshal.go b/pkg/sbom/cyclonedx/unmarshal.go index 97c24cf2797a..be08c280ed13 100644 --- a/pkg/sbom/cyclonedx/unmarshal.go +++ b/pkg/sbom/cyclonedx/unmarshal.go @@ -202,7 +202,7 @@ func parsePkgs(components []cdx.Component, seen map[string]struct{}) ([]ftypes.P } // Skip unsupported package types - if pkgURL.Class() == types.ClassUnknown { + if purl.Class(pkgURL) == types.ClassUnknown { continue } pkgs = append(pkgs, *pkg) @@ -290,11 +290,11 @@ func aggregatePkgs(libs []cdx.Component) ([]ftypes.PackageInfo, []ftypes.Applica return nil, nil, xerrors.Errorf("failed to parse the component: %w", err) } - switch pkgURL.Class() { + switch purl.Class(pkgURL) { case types.ClassOSPkg: osPkgMap[pkgURL.Type] = append(osPkgMap[pkgURL.Type], *pkg) case types.ClassLangPkg: - langType := pkgURL.LangType() + langType := purl.LangType(pkgURL) langPkgMap[langType] = append(langPkgMap[langType], *pkg) } } @@ -337,7 +337,7 @@ func toApplication(component cdx.Component) *ftypes.Application { } } -func toPackage(component cdx.Component) (*purl.PackageURL, *ftypes.Package, error) { +func toPackage(component cdx.Component) (*ftypes.PackageURL, *ftypes.Package, error) { if component.PackageURL == "" { log.Logger.Warnf("Skip the component (BOM-Ref: %s) as the PURL is empty", component.BOMRef) return nil, nil, ErrPURLEmpty @@ -347,10 +347,10 @@ func toPackage(component cdx.Component) (*purl.PackageURL, *ftypes.Package, erro return nil, nil, xerrors.Errorf("failed to parse purl: %w", err) } - pkg := p.Package() + pkg := purl.ToPackage(p) // Trivy's marshall loses case-sensitivity in PURL used in SBOM for packages (Go, Npm, PyPI), // so we have to use an original package name - pkg.Name = getPackageName(p.Type, pkg.Name, component) + pkg.Name = packageName(p.Type, pkg.Name, component) pkg.Ref = component.BOMRef for _, license := range lo.FromPtr(component.Licenses) { @@ -383,25 +383,34 @@ func toPackage(component cdx.Component) (*purl.PackageURL, *ftypes.Package, erro } } - if p.Class() == types.ClassOSPkg { - // Fill source package information for components in third-party SBOMs . - if pkg.SrcName == "" { - pkg.SrcName = pkg.Name - } - if pkg.SrcVersion == "" { - pkg.SrcVersion = pkg.Version - } - if pkg.SrcRelease == "" { - pkg.SrcRelease = pkg.Release - } - if pkg.SrcEpoch == 0 { - pkg.SrcEpoch = pkg.Epoch - } + if pkg.FilePath != "" { + p.FilePath = pkg.FilePath + } + pkg.Identifier = ftypes.PkgIdentifier{PURL: p} + + if purl.Class(p) == types.ClassOSPkg { + fillSrcPkg(pkg) } return p, pkg, nil } +func fillSrcPkg(pkg *ftypes.Package) { + // Fill source package information for components in third-party SBOMs . + if pkg.SrcName == "" { + pkg.SrcName = pkg.Name + } + if pkg.SrcVersion == "" { + pkg.SrcVersion = pkg.Version + } + if pkg.SrcRelease == "" { + pkg.SrcRelease = pkg.Release + } + if pkg.SrcEpoch == 0 { + pkg.SrcEpoch = pkg.Epoch + } +} + func toTrivyCdxComponent(component cdx.Component) ftypes.Component { return ftypes.Component{ BOMRef: component.BOMRef, @@ -413,7 +422,7 @@ func toTrivyCdxComponent(component cdx.Component) ftypes.Component { } } -func getPackageName(typ, pkgNameFromPurl string, component cdx.Component) string { +func packageName(typ, pkgNameFromPurl string, component cdx.Component) string { if typ == packageurl.TypeMaven { // Jar uses `Group` field for `GroupID` if component.Group != "" { diff --git a/pkg/sbom/cyclonedx/unmarshal_test.go b/pkg/sbom/cyclonedx/unmarshal_test.go index 26c5e5d7ff49..0af6121b4ea1 100644 --- a/pkg/sbom/cyclonedx/unmarshal_test.go +++ b/pkg/sbom/cyclonedx/unmarshal_test.go @@ -2,6 +2,8 @@ package cyclonedx_test import ( "encoding/json" + "github.com/aquasecurity/trivy/pkg/purl" + "github.com/package-url/packageurl-go" "os" "testing" @@ -37,7 +39,23 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { SrcName: "musl", SrcVersion: "1.2.3-r0", Licenses: []string{"MIT"}, - Ref: "pkg:apk/alpine/musl@1.2.3-r0?distro=3.16.0", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeApk, + Namespace: "alpine", + Name: "musl", + Version: "1.2.3-r0", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "3.16.0", + }, + }, + }, + }, + }, + Ref: "pkg:apk/alpine/musl@1.2.3-r0?distro=3.16.0", Layer: ftypes.Layer{ DiffID: "sha256:dd565ff850e7003356e2b252758f9bdc1ff2803f61e995e24c7844f6297f8fc3", }, @@ -53,7 +71,17 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Name: "pear/log", Version: "1.13.1", - Ref: "pkg:composer/pear/log@1.13.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "log", + Version: "1.13.1", + }, + }, + }, + Ref: "pkg:composer/pear/log@1.13.1", Layer: ftypes.Layer{ DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", }, @@ -62,7 +90,17 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { Name: "pear/pear_exception", Version: "v1.0.0", - Ref: "pkg:composer/pear/pear_exception@v1.0.0", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "pear_exception", + Version: "v1.0.0", + }, + }, + }, + Ref: "pkg:composer/pear/pear_exception@v1.0.0", Layer: ftypes.Layer{ DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", }, @@ -76,7 +114,17 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Name: "github.com/package-url/packageurl-go", Version: "v0.1.1-0.20220203205134-d70459300c8a", - Ref: "pkg:golang/github.com/package-url/packageurl-go@v0.1.1-0.20220203205134-d70459300c8a", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "github.com/package-url", + Name: "packageurl-go", + Version: "v0.1.1-0.20220203205134-d70459300c8a", + }, + }, + }, + Ref: "pkg:golang/github.com/package-url/packageurl-go@v0.1.1-0.20220203205134-d70459300c8a", Layer: ftypes.Layer{ DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", }, @@ -88,7 +136,17 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { FilePath: "app/gradle/target/gradle.lockfile", Libraries: ftypes.Packages{ { - Name: "com.example:example", + Name: "com.example:example", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "com.example", + Name: "example", + Version: "0.0.1", + }, + }, + }, Ref: "pkg:maven/com.example/example@0.0.1", Version: "0.0.1", Layer: ftypes.Layer{ @@ -101,7 +159,18 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { Type: ftypes.Jar, Libraries: ftypes.Packages{ { - Name: "org.codehaus.mojo:child-project", + Name: "org.codehaus.mojo:child-project", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.codehaus.mojo", + Name: "child-project", + Version: "1.0", + }, + FilePath: "app/maven/target/child-project-1.0.jar", + }, + }, Ref: "pkg:maven/org.codehaus.mojo/child-project@1.0?file_path=app%2Fmaven%2Ftarget%2Fchild-project-1.0.jar", Version: "1.0", Layer: ftypes.Layer{ @@ -116,8 +185,18 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { FilePath: "", Libraries: ftypes.Packages{ { - Name: "bootstrap", - Version: "5.0.2", + Name: "bootstrap", + Version: "5.0.2", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeNPM, + Name: "bootstrap", + Version: "5.0.2", + }, + FilePath: "app/app/package.json", + }, + }, Ref: "pkg:npm/bootstrap@5.0.2?file_path=app%2Fapp%2Fpackage.json", Licenses: []string{"MIT"}, Layer: ftypes.Layer{ @@ -150,7 +229,16 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Name: "docker", Version: "24.0.4", - Ref: "pkg:golang/docker@24.0.4", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Name: "docker", + Version: "24.0.4", + }, + }, + }, + Ref: "pkg:golang/docker@24.0.4", }, }, }, @@ -164,32 +252,86 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Name: "k8s.io/apiserver", Version: "1.27.4", - Ref: "pkg:k8s/k8s.io%2Fapiserver@1.27.4", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: purl.TypeK8s, + Name: "k8s.io/apiserver", + Version: "1.27.4", + }, + }, + }, + Ref: "pkg:k8s/k8s.io%2Fapiserver@1.27.4", }, { Name: "k8s.io/controller-manager", Version: "1.27.4", - Ref: "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.4", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: purl.TypeK8s, + Name: "k8s.io/controller-manager", + Version: "1.27.4", + }, + }, + }, + Ref: "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.4", }, { Name: "k8s.io/kube-proxy", Version: "1.27.4", - Ref: "pkg:k8s/k8s.io%2Fkube-proxy@1.27.4", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: purl.TypeK8s, + Name: "k8s.io/kube-proxy", + Version: "1.27.4", + }, + }, + }, + Ref: "pkg:k8s/k8s.io%2Fkube-proxy@1.27.4", }, { Name: "k8s.io/kube-scheduler", Version: "1.27.4", - Ref: "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.4", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: purl.TypeK8s, + Name: "k8s.io/kube-scheduler", + Version: "1.27.4", + }, + }, + }, + Ref: "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.4", }, { Name: "k8s.io/kubelet", Version: "1.27.4", - Ref: "pkg:k8s/k8s.io%2Fkubelet@1.27.4", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: purl.TypeK8s, + Name: "k8s.io/kubelet", + Version: "1.27.4", + }, + }, + }, + Ref: "pkg:k8s/k8s.io%2Fkubelet@1.27.4", }, { Name: "k8s.io/kubernetes", Version: "1.27.4", - Ref: "pkg:k8s/k8s.io%2Fkubernetes@1.27.4", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: purl.TypeK8s, + Name: "k8s.io/kubernetes", + Version: "1.27.4", + }, + }, + }, + Ref: "pkg:k8s/k8s.io%2Fkubernetes@1.27.4", }, }, }, @@ -219,6 +361,22 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { "GPL-2.0", "GFDL-1.3", }, + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeDebian, + Namespace: "ubuntu", + Name: "libc6", + Version: "2.35-0ubuntu3.1", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "ubuntu-22.04", + }, + }, + }, + }, + }, Ref: "pkg:deb/ubuntu/libc6@2.35-0ubuntu3.1?distro=ubuntu-22.04", Layer: ftypes.Layer{ Digest: "sha256:74ac377868f863e123f24c409f79709f7563fa464557c36a09cf6f85c8b92b7f", @@ -234,7 +392,27 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { SrcVersion: "4.4.27", SrcRelease: "1", SrcEpoch: 1, - Ref: "pkg:deb/ubuntu/libcrypt1@4.4.27-1?epoch=1&distro=ubuntu-22.04", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeDebian, + Namespace: "ubuntu", + Name: "libcrypt1", + Version: "4.4.27-1", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "ubuntu-22.04", + }, + { + Key: "epoch", + Value: "1", + }, + }, + }, + }, + }, + Ref: "pkg:deb/ubuntu/libcrypt1@4.4.27-1?epoch=1&distro=ubuntu-22.04", Layer: ftypes.Layer{ Digest: "sha256:74ac377868f863e123f24c409f79709f7563fa464557c36a09cf6f85c8b92b7f", DiffID: "sha256:b93c1bd012ab8fda60f5b4f5906bf244586e0e3292d84571d3abb56472248466", @@ -262,7 +440,23 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { SrcName: "musl", SrcVersion: "1.2.3-r0", Licenses: []string{"MIT"}, - Ref: "pkg:apk/alpine/musl@1.2.3-r0?distro=3.16.0", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeApk, + Namespace: "alpine", + Name: "musl", + Version: "1.2.3-r0", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "3.16.0", + }, + }, + }, + }, + }, + Ref: "pkg:apk/alpine/musl@1.2.3-r0?distro=3.16.0", }, }, }, @@ -275,13 +469,33 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Name: "pear/log", Version: "1.13.1", - Ref: "pkg:composer/pear/log@1.13.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "log", + Version: "1.13.1", + }, + }, + }, + Ref: "pkg:composer/pear/log@1.13.1", }, { Name: "pear/pear_exception", Version: "v1.0.0", - Ref: "pkg:composer/pear/pear_exception@v1.0.0", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "pear_exception", + Version: "v1.0.0", + }, + }, + }, + Ref: "pkg:composer/pear/pear_exception@v1.0.0", }, }, }, @@ -300,7 +514,17 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Name: "pear/log", Version: "1.13.1", - Ref: "pkg:composer/pear/log@1.13.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "log", + Version: "1.13.1", + }, + }, + }, + Ref: "pkg:composer/pear/log@1.13.1", }, }, }, @@ -319,13 +543,33 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Name: "pear/log", Version: "1.13.1", - Ref: "pkg:composer/pear/log@1.13.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "log", + Version: "1.13.1", + }, + }, + }, + Ref: "pkg:composer/pear/log@1.13.1", }, { Name: "pear/pear_exception", Version: "v1.0.0", - Ref: "pkg:composer/pear/pear_exception@v1.0.0", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "pear_exception", + Version: "v1.0.0", + }, + }, + }, + Ref: "pkg:composer/pear/pear_exception@v1.0.0", }, }, }, @@ -344,18 +588,48 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Name: "pear/core", Version: "1.13.1", - Ref: "pkg:composer/pear/core@1.13.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "core", + Version: "1.13.1", + }, + }, + }, + Ref: "pkg:composer/pear/core@1.13.1", }, { Name: "pear/log", Version: "1.13.1", - Ref: "pkg:composer/pear/log@1.13.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "log", + Version: "1.13.1", + }, + }, + }, + Ref: "pkg:composer/pear/log@1.13.1", }, { Name: "pear/pear_exception", Version: "v1.0.0", - Ref: "pkg:composer/pear/pear_exception@v1.0.0", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "pear_exception", + Version: "v1.0.0", + }, + }, + }, + Ref: "pkg:composer/pear/pear_exception@v1.0.0", }, }, }, @@ -371,8 +645,19 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { Type: "jar", Libraries: ftypes.Packages{ { - Name: "org.springframework:spring-web", - Version: "5.3.22", + Name: "org.springframework:spring-web", + Version: "5.3.22", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.springframework", + Name: "spring-web", + Version: "5.3.22", + }, + FilePath: "spring-web-5.3.22.jar", + }, + }, Ref: "pkg:maven/org.springframework/spring-web@5.3.22?file_path=spring-web-5.3.22.jar", FilePath: "spring-web-5.3.22.jar", }, diff --git a/pkg/sbom/spdx/marshal.go b/pkg/sbom/spdx/marshal.go index 69544d850548..642e7d7629ab 100644 --- a/pkg/sbom/spdx/marshal.go +++ b/pkg/sbom/spdx/marshal.go @@ -243,7 +243,7 @@ func (m *Marshaler) rootPackage(r types.Report, pkgDownloadLocation string) (*sp attributionTexts := []string{attributionText(PropertySchemaVersion, strconv.Itoa(r.SchemaVersion))} // When the target is a container image, add PURL to the external references of the root package. - if p, err := purl.NewPackageURL(purl.TypeOCI, r.Metadata, ftypes.Package{}); err != nil { + if p, err := purl.New(purl.TypeOCI, r.Metadata, ftypes.Package{}); err != nil { return nil, xerrors.Errorf("failed to new package url for oci: %w", err) } else if p != nil { externalReferences = append(externalReferences, purlExternalReference(p.ToString())) @@ -333,14 +333,9 @@ func (m *Marshaler) pkgToSpdxPackage(t ftypes.TargetType, pkgDownloadLocation st pkgSrcInfo = fmt.Sprintf("%s: %s %s", SourcePackagePrefix, pkg.SrcName, utils.FormatSrcVersion(pkg)) } - packageURL, err := purl.NewPackageURL(t, metadata, pkg) - if err != nil { - return spdx.Package{}, xerrors.Errorf("failed to parse purl (%s): %w", pkg.Name, err) - } - var pkgExtRefs []*spdx.PackageExternalReference - if packageURL != nil { - pkgExtRefs = []*spdx.PackageExternalReference{purlExternalReference(packageURL.String())} + if pkg.Identifier.PURL != nil { + pkgExtRefs = []*spdx.PackageExternalReference{purlExternalReference(pkg.Identifier.PURL.String())} } var attrTexts []string diff --git a/pkg/sbom/spdx/marshal_test.go b/pkg/sbom/spdx/marshal_test.go index b173958a0164..eb73274bbc30 100644 --- a/pkg/sbom/spdx/marshal_test.go +++ b/pkg/sbom/spdx/marshal_test.go @@ -1,6 +1,7 @@ package spdx_test import ( + "github.com/package-url/packageurl-go" "hash/fnv" "testing" "time" @@ -54,11 +55,31 @@ func TestMarshaler_Marshal(t *testing.T) { Type: ftypes.CentOS, Packages: []ftypes.Package{ { - Name: "binutils", - Version: "2.30", - Release: "93.el8", - Epoch: 0, - Arch: "aarch64", + Name: "binutils", + Version: "2.30", + Release: "93.el8", + Epoch: 0, + Arch: "aarch64", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeRPM, + Namespace: "centos", + Name: "binutils", + Version: "2.30-93.el8", + Qualifiers: packageurl.Qualifiers{ + { + Key: "arch", + Value: "aarch64", + }, + { + Key: "distro", + Value: "centos-8.3.2011", + }, + }, + }, + }, + }, SrcName: "binutils", SrcVersion: "2.30", SrcRelease: "93.el8", @@ -78,10 +99,28 @@ func TestMarshaler_Marshal(t *testing.T) { { Name: "actionpack", Version: "7.0.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "actionpack", + Version: "7.0.1", + }, + }, + }, }, { Name: "actioncontroller", Version: "7.0.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "actioncontroller", + Version: "7.0.1", + }, + }, + }, }, }, }, @@ -93,6 +132,15 @@ func TestMarshaler_Marshal(t *testing.T) { { Name: "actionpack", Version: "7.0.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "actionpack", + Version: "7.0.1", + }, + }, + }, }, }, }, @@ -296,11 +344,35 @@ func TestMarshaler_Marshal(t *testing.T) { Type: ftypes.CentOS, Packages: []ftypes.Package{ { - Name: "acl", - Version: "2.2.53", - Release: "1.el8", - Epoch: 1, - Arch: "aarch64", + Name: "acl", + Version: "2.2.53", + Release: "1.el8", + Epoch: 1, + Arch: "aarch64", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeRPM, + Namespace: "centos", + Name: "acl", + Version: "2.2.53-1.el8", + Qualifiers: packageurl.Qualifiers{ + { + Key: "arch", + Value: "aarch64", + }, + { + Key: "distro", + Value: "centos-8.3.2011", + }, + { + Key: "epoch", + Value: "1", + }, + }, + }, + }, + }, SrcName: "acl", SrcVersion: "2.2.53", SrcRelease: "1.el8", @@ -319,6 +391,15 @@ func TestMarshaler_Marshal(t *testing.T) { { Name: "actionpack", Version: "7.0.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "actionpack", + Version: "7.0.1", + }, + }, + }, Layer: ftypes.Layer{ DiffID: "sha256:ccb64cf0b7ba2e50741d0b64cae324eb5de3b1e2f580bbf177e721b67df38488", }, @@ -328,6 +409,15 @@ func TestMarshaler_Marshal(t *testing.T) { { Name: "actionpack", Version: "7.0.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "actionpack", + Version: "7.0.1", + }, + }, + }, Layer: ftypes.Layer{ DiffID: "sha256:ccb64cf0b7ba2e50741d0b64cae324eb5de3b1e2f580bbf177e721b67df38488", }, @@ -542,6 +632,15 @@ func TestMarshaler_Marshal(t *testing.T) { { Name: "actioncable", Version: "6.1.4.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGem, + Name: "actioncable", + Version: "6.1.4.1", + }, + }, + }, }, }, }, @@ -633,8 +732,17 @@ func TestMarshaler_Marshal(t *testing.T) { Type: ftypes.NodePkg, Packages: []ftypes.Package{ { - Name: "ruby-typeprof", - Version: "0.20.1", + Name: "ruby-typeprof", + Version: "0.20.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeNPM, + Name: "ruby-typeprof", + Version: "0.20.1", + }, + }, + }, Licenses: []string{"MIT"}, Layer: ftypes.Layer{ DiffID: "sha256:661c3fd3cc16b34c070f3620ca6b03b6adac150f9a7e5d0e3c707a159990f88e", @@ -866,6 +974,16 @@ func TestMarshaler_Marshal(t *testing.T) { { Name: "golang.org/x/crypto", Version: "v0.0.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "golang.org/x", + Name: "crypto", + Version: "v0.0.1", + }, + }, + }, }, }, }, diff --git a/pkg/sbom/spdx/unmarshal.go b/pkg/sbom/spdx/unmarshal.go index e603e646be9b..9ff8586c45d9 100644 --- a/pkg/sbom/spdx/unmarshal.go +++ b/pkg/sbom/spdx/unmarshal.go @@ -177,12 +177,12 @@ func (s *SPDX) parsePackages(pkgs map[common.ElementID]*spdx.Package) error { } else if err != nil { return xerrors.Errorf("failed to parse package: %w", err) } - switch pkgURL.Class() { + switch purl.Class(pkgURL) { case types.ClassOSPkg: osPkgs = append(osPkgs, *pkg) case types.ClassLangPkg: // Language-specific packages - pkgType := pkgURL.LangType() + pkgType := purl.LangType(pkgURL) app, ok := apps[pkgType] if !ok { app.Type = pkgType @@ -246,7 +246,7 @@ func parseOS(pkg spdx.Package) ftypes.OS { } } -func parsePkg(spdxPkg spdx.Package, packageFilePaths map[string]string) (*ftypes.Package, *purl.PackageURL, error) { +func parsePkg(spdxPkg spdx.Package, packageFilePaths map[string]string) (*ftypes.Package, *ftypes.PackageURL, error) { pkg, pkgURL, err := parseExternalReferences(spdxPkg.PackageExternalReferences) if err != nil { return nil, nil, xerrors.Errorf("external references error: %w", err) @@ -278,7 +278,7 @@ func parsePkg(spdxPkg spdx.Package, packageFilePaths map[string]string) (*ftypes return pkg, pkgURL, nil } -func parseExternalReferences(refs []*spdx.PackageExternalReference) (*ftypes.Package, *purl.PackageURL, error) { +func parseExternalReferences(refs []*spdx.PackageExternalReference) (*ftypes.Package, *ftypes.PackageURL, error) { for _, ref := range refs { // Extract the package information from PURL if ref.RefType != RefTypePurl || ref.Category != CategoryPackageManager { @@ -289,8 +289,11 @@ func parseExternalReferences(refs []*spdx.PackageExternalReference) (*ftypes.Pac if err != nil { return nil, nil, xerrors.Errorf("failed to parse purl from string: %w", err) } - pkg := packageURL.Package() + pkg := purl.ToPackage(packageURL) pkg.Ref = ref.Locator + pkg.Identifier = ftypes.PkgIdentifier{ + PURL: packageURL, + } return pkg, packageURL, nil } return nil, nil, errUnknownPackageFormat diff --git a/pkg/sbom/spdx/unmarshal_test.go b/pkg/sbom/spdx/unmarshal_test.go index 5b72fb9e0d05..d7ebdad3922d 100644 --- a/pkg/sbom/spdx/unmarshal_test.go +++ b/pkg/sbom/spdx/unmarshal_test.go @@ -2,6 +2,7 @@ package spdx_test import ( "encoding/json" + "github.com/package-url/packageurl-go" "os" "sort" "testing" @@ -38,7 +39,23 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { SrcName: "musl", SrcVersion: "1.2.3-r0", Licenses: []string{"MIT"}, - Ref: "pkg:apk/alpine/musl@1.2.3-r0?distro=3.16.0", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeApk, + Namespace: "alpine", + Name: "musl", + Version: "1.2.3-r0", + Qualifiers: packageurl.Qualifiers{ + { + Key: "distro", + Value: "3.16.0", + }, + }, + }, + }, + }, + Ref: "pkg:apk/alpine/musl@1.2.3-r0?distro=3.16.0", Layer: ftypes.Layer{ DiffID: "sha256:dd565ff850e7003356e2b252758f9bdc1ff2803f61e995e24c7844f6297f8fc3", }, @@ -54,7 +71,17 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Name: "pear/log", Version: "1.13.1", - Ref: "pkg:composer/pear/log@1.13.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "log", + Version: "1.13.1", + }, + }, + }, + Ref: "pkg:composer/pear/log@1.13.1", Layer: ftypes.Layer{ DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", }, @@ -63,7 +90,17 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { Name: "pear/pear_exception", Version: "v1.0.0", - Ref: "pkg:composer/pear/pear_exception@v1.0.0", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "pear_exception", + Version: "v1.0.0", + }, + }, + }, + Ref: "pkg:composer/pear/pear_exception@v1.0.0", Layer: ftypes.Layer{ DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", }, @@ -77,7 +114,17 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Name: "github.com/package-url/packageurl-go", Version: "v0.1.1-0.20220203205134-d70459300c8a", - Ref: "pkg:golang/github.com/package-url/packageurl-go@v0.1.1-0.20220203205134-d70459300c8a", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeGolang, + Namespace: "github.com/package-url", + Name: "packageurl-go", + Version: "v0.1.1-0.20220203205134-d70459300c8a", + }, + }, + }, + Ref: "pkg:golang/github.com/package-url/packageurl-go@v0.1.1-0.20220203205134-d70459300c8a", Layer: ftypes.Layer{ DiffID: "sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", }, @@ -88,7 +135,17 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { Type: "jar", Libraries: ftypes.Packages{ { - Name: "org.codehaus.mojo:child-project", + Name: "org.codehaus.mojo:child-project", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.codehaus.mojo", + Name: "child-project", + Version: "1.0", + }, + }, + }, Ref: "pkg:maven/org.codehaus.mojo/child-project@1.0", Version: "1.0", Layer: ftypes.Layer{ @@ -101,8 +158,17 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { Type: "node-pkg", Libraries: ftypes.Packages{ { - Name: "bootstrap", - Version: "5.0.2", + Name: "bootstrap", + Version: "5.0.2", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeNPM, + Name: "bootstrap", + Version: "5.0.2", + }, + }, + }, Ref: "pkg:npm/bootstrap@5.0.2", Licenses: []string{"MIT"}, Layer: ftypes.Layer{ @@ -127,27 +193,15 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { Name: "yargs-parser", Version: "21.1.1", Licenses: []string{"ISC"}, - Ref: "pkg:npm/yargs-parser@21.1.1", - FilePath: "node_modules/yargs-parser/package.json", - }, - }, - }, - }, - }, - }, - { - name: "happy path for bom with hasFiles field", - inputFile: "testdata/happy/with-hasfiles-bom.json", - want: types.SBOM{ - Applications: []ftypes.Application{ - { - Type: "node-pkg", - Libraries: ftypes.Packages{ - { - ID: "yargs-parser@21.1.1", - Name: "yargs-parser", - Version: "21.1.1", - Licenses: []string{"ISC"}, + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeNPM, + Name: "yargs-parser", + Version: "21.1.1", + }, + }, + }, Ref: "pkg:npm/yargs-parser@21.1.1", FilePath: "node_modules/yargs-parser/package.json", }, @@ -169,6 +223,15 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { Name: "yargs-parser", Version: "21.1.1", Licenses: []string{"ISC"}, + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeNPM, + Name: "yargs-parser", + Version: "21.1.1", + }, + }, + }, Ref: "pkg:npm/yargs-parser@21.1.1", FilePath: "node_modules/yargs-parser/package.json", }, @@ -189,13 +252,33 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { { Name: "pear/log", Version: "1.13.1", - Ref: "pkg:composer/pear/log@1.13.1", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "log", + Version: "1.13.1", + }, + }, + }, + Ref: "pkg:composer/pear/log@1.13.1", }, { Name: "pear/pear_exception", Version: "v1.0.0", - Ref: "pkg:composer/pear/pear_exception@v1.0.0", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeComposer, + Namespace: "pear", + Name: "pear_exception", + Version: "v1.0.0", + }, + }, + }, + Ref: "pkg:composer/pear/pear_exception@v1.0.0", }, }, }, @@ -214,13 +297,33 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { FilePath: "modules/apm/elastic-apm-agent-1.36.0.jar", Name: "co.elastic.apm:apm-agent", Version: "1.36.0", - Ref: "pkg:maven/co.elastic.apm/apm-agent@1.36.0", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "co.elastic.apm", + Name: "apm-agent", + Version: "1.36.0", + }, + }, + }, + Ref: "pkg:maven/co.elastic.apm/apm-agent@1.36.0", }, { FilePath: "modules/apm/elastic-apm-agent-1.36.0.jar", Name: "co.elastic.apm:apm-agent-cached-lookup-key", Version: "1.36.0", - Ref: "pkg:maven/co.elastic.apm/apm-agent-cached-lookup-key@1.36.0", + Identifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "co.elastic.apm", + Name: "apm-agent-cached-lookup-key", + Version: "1.36.0", + }, + }, + }, + Ref: "pkg:maven/co.elastic.apm/apm-agent-cached-lookup-key@1.36.0", }, }, }, diff --git a/pkg/types/vulnerability.go b/pkg/types/vulnerability.go index 488a7d635184..4727d5009083 100644 --- a/pkg/types/vulnerability.go +++ b/pkg/types/vulnerability.go @@ -7,19 +7,21 @@ import ( // DetectedVulnerability holds the information of detected vulnerabilities type DetectedVulnerability struct { - VulnerabilityID string `json:",omitempty"` - VendorIDs []string `json:",omitempty"` - PkgID string `json:",omitempty"` // It is used to construct dependency graph. - PkgName string `json:",omitempty"` - PkgPath string `json:",omitempty"` // This field is populated in the case of language-specific packages such as egg/wheel and gemspec - InstalledVersion string `json:",omitempty"` - FixedVersion string `json:",omitempty"` - Status types.Status `json:",omitempty"` - Layer ftypes.Layer `json:",omitempty"` - SeveritySource types.SourceID `json:",omitempty"` - PrimaryURL string `json:",omitempty"` + VulnerabilityID string `json:",omitempty"` + VendorIDs []string `json:",omitempty"` + PkgID string `json:",omitempty"` // It is used to construct dependency graph. + PkgName string `json:",omitempty"` + PkgPath string `json:",omitempty"` // This field is populated in the case of language-specific packages such as egg/wheel and gemspec + PkgIdentifier ftypes.PkgIdentifier `json:",omitempty"` + InstalledVersion string `json:",omitempty"` + FixedVersion string `json:",omitempty"` + Status types.Status `json:",omitempty"` + Layer ftypes.Layer `json:",omitempty"` + SeveritySource types.SourceID `json:",omitempty"` + PrimaryURL string `json:",omitempty"` - // PkgRef is populated only when scanning SBOM and contains the reference ID used in the SBOM. + // TO BE DEPRECATED - use PkgIdentifier instead + // Only used when scanning SBOM and contains the reference ID used in it. // It could be PURL, UUID, etc. // e.g. // - pkg:npm/acme/component@1.0.0 diff --git a/pkg/vex/testdata/cyclonedx.json b/pkg/vex/testdata/cyclonedx.json index 61b97de17ada..a85d430dbc69 100644 --- a/pkg/vex/testdata/cyclonedx.json +++ b/pkg/vex/testdata/cyclonedx.json @@ -15,7 +15,7 @@ }, "affects": [ { - "ref": "urn:cdx:3e671687-395b-41f5-a30f-a58921a69b79/1#jackson-databind-2.8.0" + "ref": "urn:cdx:3e671687-395b-41f5-a30f-a58921a69b79/1#pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.8.0" } ] } diff --git a/pkg/vex/testdata/openvex-multiple.json b/pkg/vex/testdata/openvex-multiple.json index acb027dc343e..11c9ac5d192e 100644 --- a/pkg/vex/testdata/openvex-multiple.json +++ b/pkg/vex/testdata/openvex-multiple.json @@ -11,7 +11,9 @@ "name": "CVE-2021-44228" }, "products": [ - {"@id": "pkg:maven/org.springframework.boot/spring-boot@2.6.0"} + { + "@id": "pkg:maven/org.springframework.boot/spring-boot@2.6.0" + } ], "status": "affected" }, @@ -20,7 +22,9 @@ "name": "CVE-2021-44228" }, "products": [ - {"@id": "pkg:maven/org.springframework.boot/spring-boot@2.6.0"} + { + "@id": "pkg:maven/org.springframework.boot/spring-boot@2.6.0" + } ], "status": "not_affected", "justification": "vulnerable_code_not_in_execute_path" diff --git a/pkg/vex/testdata/openvex.json b/pkg/vex/testdata/openvex.json index e1dd960bfb1f..4acaf3aff95e 100644 --- a/pkg/vex/testdata/openvex.json +++ b/pkg/vex/testdata/openvex.json @@ -10,7 +10,9 @@ "name": "CVE-2021-44228" }, "products": [ - {"@id": "pkg:maven/org.springframework.boot/spring-boot@2.6.0"} + { + "@id": "pkg:maven/org.springframework.boot/spring-boot@2.6.0" + } ], "status": "not_affected", "justification": "vulnerable_code_not_in_execute_path" diff --git a/pkg/vex/vex.go b/pkg/vex/vex.go index 05786d90dc14..fb64984bda6e 100644 --- a/pkg/vex/vex.go +++ b/pkg/vex/vex.go @@ -50,7 +50,13 @@ func newOpenVEX(vex openvex.VEX) VEX { func (v *OpenVEX) Filter(vulns []types.DetectedVulnerability) []types.DetectedVulnerability { return lo.Filter(vulns, func(vuln types.DetectedVulnerability, _ int) bool { - stmts := v.vex.Matches(vuln.VulnerabilityID, vuln.PkgRef, nil) + var stmts []openvex.Statement + if vuln.PkgIdentifier.PURL != nil { + matchedStmts := v.vex.Matches(vuln.VulnerabilityID, vuln.PkgIdentifier.PURL.String(), nil) + if len(matchedStmts) > 0 { + stmts = append(stmts, matchedStmts...) + } + } if len(stmts) == 0 { return true } @@ -122,8 +128,7 @@ func (v *CycloneDX) affected(vuln types.DetectedVulnerability, stmt Statement) b zap.Int("version", link.Version())) continue } - if vuln.PkgRef == link.Reference() && - (stmt.Status == StatusNotAffected || stmt.Status == StatusFixed) { + if v.matchRef(vuln, link.Reference()) && (stmt.Status == StatusNotAffected || stmt.Status == StatusFixed) { v.logger.Infow("Filtered out the detected vulnerability", zap.String("vulnerability-id", vuln.VulnerabilityID), zap.String("status", string(stmt.Status)), zap.String("justification", stmt.Justification)) return false @@ -132,6 +137,16 @@ func (v *CycloneDX) affected(vuln types.DetectedVulnerability, stmt Statement) b return true } +func (v *CycloneDX) matchRef(vuln types.DetectedVulnerability, ref string) bool { + switch { + case vuln.PkgRef == ref: // BOM-Ref + return true + case vuln.PkgIdentifier.PURL != nil && vuln.PkgIdentifier.PURL.String() == ref: // PURL + return true + } + return false +} + func cdxStatus(s cdx.ImpactAnalysisState) Status { switch s { case cdx.IASResolved, cdx.IASResolvedWithPedigree: diff --git a/pkg/vex/vex_test.go b/pkg/vex/vex_test.go index 45f8f7a5cf37..16abcf2a7ffa 100644 --- a/pkg/vex/vex_test.go +++ b/pkg/vex/vex_test.go @@ -1,6 +1,7 @@ package vex_test import ( + "github.com/package-url/packageurl-go" "os" "testing" @@ -43,7 +44,16 @@ func TestVEX_Filter(t *testing.T) { VulnerabilityID: "CVE-2021-44228", PkgName: "spring-boot", InstalledVersion: "2.6.0", - PkgRef: "pkg:maven/org.springframework.boot/spring-boot@2.6.0?type=pom", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.springframework.boot", + Name: "spring-boot", + Version: "2.6.0", + }, + }, + }, }, }, }, @@ -60,13 +70,31 @@ func TestVEX_Filter(t *testing.T) { VulnerabilityID: "CVE-2021-44228", PkgName: "spring-boot", InstalledVersion: "2.6.0", - PkgRef: "pkg:maven/org.springframework.boot/spring-boot@2.6.0?type=pom", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.springframework.boot", + Name: "spring-boot", + Version: "2.6.0", + }, + }, + }, }, { VulnerabilityID: "CVE-2021-0001", PkgName: "spring-boot", InstalledVersion: "2.6.0", - PkgRef: "pkg:maven/org.springframework.boot/spring-boot@2.6.0?type=pom", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.springframework.boot", + Name: "spring-boot", + Version: "2.6.0", + }, + }, + }, }, }, }, @@ -75,7 +103,16 @@ func TestVEX_Filter(t *testing.T) { VulnerabilityID: "CVE-2021-0001", PkgName: "spring-boot", InstalledVersion: "2.6.0", - PkgRef: "pkg:maven/org.springframework.boot/spring-boot@2.6.0?type=pom", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.springframework.boot", + Name: "spring-boot", + Version: "2.6.0", + }, + }, + }, }, }, }, @@ -96,13 +133,31 @@ func TestVEX_Filter(t *testing.T) { VulnerabilityID: "CVE-2018-7489", PkgName: "jackson-databind", InstalledVersion: "2.8.0", - PkgRef: "jackson-databind-2.8.0", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "com.fasterxml.jackson.core", + Name: "jackson-databind", + Version: "2.8.0", + }, + }, + }, }, { VulnerabilityID: "CVE-2018-7490", PkgName: "jackson-databind", InstalledVersion: "2.8.0", - PkgRef: "jackson-databind-2.8.0", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "com.fasterxml.jackson.core", + Name: "jackson-databind", + Version: "2.8.0", + }, + }, + }, }, }, }, @@ -111,7 +166,16 @@ func TestVEX_Filter(t *testing.T) { VulnerabilityID: "CVE-2018-7490", PkgName: "jackson-databind", InstalledVersion: "2.8.0", - PkgRef: "jackson-databind-2.8.0", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "com.fasterxml.jackson.core", + Name: "jackson-databind", + Version: "2.8.0", + }, + }, + }, }, }, }, @@ -132,7 +196,16 @@ func TestVEX_Filter(t *testing.T) { VulnerabilityID: "CVE-2018-7489", PkgName: "jackson-databind", InstalledVersion: "2.8.0", - PkgRef: "jackson-databind-2.8.0", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "com.fasterxml.jackson.core", + Name: "jackson-databind", + Version: "2.8.0", + }, + }, + }, }, }, }, @@ -141,7 +214,16 @@ func TestVEX_Filter(t *testing.T) { VulnerabilityID: "CVE-2018-7489", PkgName: "jackson-databind", InstalledVersion: "2.8.0", - PkgRef: "jackson-databind-2.8.0", + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &ftypes.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "com.fasterxml.jackson.core", + Name: "jackson-databind", + Version: "2.8.0", + }, + }, + }, }, }, }, diff --git a/rpc/common/service.pb.go b/rpc/common/service.pb.go index 7183f59f6a24..fcae12028a0f 100644 --- a/rpc/common/service.pb.go +++ b/rpc/common/service.pb.go @@ -138,7 +138,7 @@ func (x LicenseCategory_Enum) Number() protoreflect.EnumNumber { // Deprecated: Use LicenseCategory_Enum.Descriptor instead. func (LicenseCategory_Enum) EnumDescriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{22, 0} + return file_rpc_common_service_proto_rawDescGZIP(), []int{23, 0} } type LicenseType_Enum int32 @@ -190,7 +190,7 @@ func (x LicenseType_Enum) Number() protoreflect.EnumNumber { // Deprecated: Use LicenseType_Enum.Descriptor instead. func (LicenseType_Enum) EnumDescriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{23, 0} + return file_rpc_common_service_proto_rawDescGZIP(), []int{24, 0} } type OS struct { @@ -444,12 +444,13 @@ type Package struct { // binary package // e.g. bind-utils - Id string `protobuf:"bytes,13,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` - Release string `protobuf:"bytes,3,opt,name=release,proto3" json:"release,omitempty"` - Epoch int32 `protobuf:"varint,4,opt,name=epoch,proto3" json:"epoch,omitempty"` - Arch string `protobuf:"bytes,5,opt,name=arch,proto3" json:"arch,omitempty"` + Id string `protobuf:"bytes,13,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"` + Release string `protobuf:"bytes,3,opt,name=release,proto3" json:"release,omitempty"` + Epoch int32 `protobuf:"varint,4,opt,name=epoch,proto3" json:"epoch,omitempty"` + Identifier *PkgIdentifier `protobuf:"bytes,19,opt,name=identifier,proto3" json:"identifier,omitempty"` + Arch string `protobuf:"bytes,5,opt,name=arch,proto3" json:"arch,omitempty"` // src package containing some binary packages // e.g. bind SrcName string `protobuf:"bytes,6,opt,name=src_name,json=srcName,proto3" json:"src_name,omitempty"` @@ -532,6 +533,13 @@ func (x *Package) GetEpoch() int32 { return 0 } +func (x *Package) GetIdentifier() *PkgIdentifier { + if x != nil { + return x.Identifier + } + return nil +} + func (x *Package) GetArch() string { if x != nil { return x.Arch @@ -616,6 +624,61 @@ func (x *Package) GetIndirect() bool { return false } +type PkgIdentifier struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Purl string `protobuf:"bytes,1,opt,name=purl,proto3" json:"purl,omitempty"` + Cpe string `protobuf:"bytes,2,opt,name=cpe,proto3" json:"cpe,omitempty"` +} + +func (x *PkgIdentifier) Reset() { + *x = PkgIdentifier{} + if protoimpl.UnsafeEnabled { + mi := &file_rpc_common_service_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PkgIdentifier) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PkgIdentifier) ProtoMessage() {} + +func (x *PkgIdentifier) ProtoReflect() protoreflect.Message { + mi := &file_rpc_common_service_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PkgIdentifier.ProtoReflect.Descriptor instead. +func (*PkgIdentifier) Descriptor() ([]byte, []int) { + return file_rpc_common_service_proto_rawDescGZIP(), []int{5} +} + +func (x *PkgIdentifier) GetPurl() string { + if x != nil { + return x.Purl + } + return "" +} + +func (x *PkgIdentifier) GetCpe() string { + if x != nil { + return x.Cpe + } + return "" +} + type Misconfiguration struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -632,7 +695,7 @@ type Misconfiguration struct { func (x *Misconfiguration) Reset() { *x = Misconfiguration{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[5] + mi := &file_rpc_common_service_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -645,7 +708,7 @@ func (x *Misconfiguration) String() string { func (*Misconfiguration) ProtoMessage() {} func (x *Misconfiguration) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[5] + mi := &file_rpc_common_service_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -658,7 +721,7 @@ func (x *Misconfiguration) ProtoReflect() protoreflect.Message { // Deprecated: Use Misconfiguration.ProtoReflect.Descriptor instead. func (*Misconfiguration) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{5} + return file_rpc_common_service_proto_rawDescGZIP(), []int{6} } func (x *Misconfiguration) GetFileType() string { @@ -717,7 +780,7 @@ type MisconfResult struct { func (x *MisconfResult) Reset() { *x = MisconfResult{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[6] + mi := &file_rpc_common_service_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -730,7 +793,7 @@ func (x *MisconfResult) String() string { func (*MisconfResult) ProtoMessage() {} func (x *MisconfResult) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[6] + mi := &file_rpc_common_service_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -743,7 +806,7 @@ func (x *MisconfResult) ProtoReflect() protoreflect.Message { // Deprecated: Use MisconfResult.ProtoReflect.Descriptor instead. func (*MisconfResult) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{6} + return file_rpc_common_service_proto_rawDescGZIP(), []int{7} } func (x *MisconfResult) GetNamespace() string { @@ -792,7 +855,7 @@ type PolicyMetadata struct { func (x *PolicyMetadata) Reset() { *x = PolicyMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[7] + mi := &file_rpc_common_service_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -805,7 +868,7 @@ func (x *PolicyMetadata) String() string { func (*PolicyMetadata) ProtoMessage() {} func (x *PolicyMetadata) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[7] + mi := &file_rpc_common_service_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -818,7 +881,7 @@ func (x *PolicyMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use PolicyMetadata.ProtoReflect.Descriptor instead. func (*PolicyMetadata) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{7} + return file_rpc_common_service_proto_rawDescGZIP(), []int{8} } func (x *PolicyMetadata) GetId() string { @@ -902,7 +965,7 @@ type DetectedMisconfiguration struct { func (x *DetectedMisconfiguration) Reset() { *x = DetectedMisconfiguration{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[8] + mi := &file_rpc_common_service_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -915,7 +978,7 @@ func (x *DetectedMisconfiguration) String() string { func (*DetectedMisconfiguration) ProtoMessage() {} func (x *DetectedMisconfiguration) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[8] + mi := &file_rpc_common_service_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -928,7 +991,7 @@ func (x *DetectedMisconfiguration) ProtoReflect() protoreflect.Message { // Deprecated: Use DetectedMisconfiguration.ProtoReflect.Descriptor instead. func (*DetectedMisconfiguration) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{8} + return file_rpc_common_service_proto_rawDescGZIP(), []int{9} } func (x *DetectedMisconfiguration) GetType() string { @@ -1049,6 +1112,7 @@ type Vulnerability struct { Description string `protobuf:"bytes,6,opt,name=description,proto3" json:"description,omitempty"` Severity Severity `protobuf:"varint,7,opt,name=severity,proto3,enum=trivy.common.Severity" json:"severity,omitempty"` References []string `protobuf:"bytes,8,rep,name=references,proto3" json:"references,omitempty"` + PkgIdentifier *PkgIdentifier `protobuf:"bytes,25,opt,name=pkg_identifier,json=pkgIdentifier,proto3" json:"pkg_identifier,omitempty"` Layer *Layer `protobuf:"bytes,10,opt,name=layer,proto3" json:"layer,omitempty"` SeveritySource string `protobuf:"bytes,11,opt,name=severity_source,json=severitySource,proto3" json:"severity_source,omitempty"` Cvss map[string]*CVSS `protobuf:"bytes,12,rep,name=cvss,proto3" json:"cvss,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` @@ -1069,7 +1133,7 @@ type Vulnerability struct { func (x *Vulnerability) Reset() { *x = Vulnerability{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[9] + mi := &file_rpc_common_service_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1082,7 +1146,7 @@ func (x *Vulnerability) String() string { func (*Vulnerability) ProtoMessage() {} func (x *Vulnerability) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[9] + mi := &file_rpc_common_service_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1095,7 +1159,7 @@ func (x *Vulnerability) ProtoReflect() protoreflect.Message { // Deprecated: Use Vulnerability.ProtoReflect.Descriptor instead. func (*Vulnerability) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{9} + return file_rpc_common_service_proto_rawDescGZIP(), []int{10} } func (x *Vulnerability) GetVulnerabilityId() string { @@ -1154,6 +1218,13 @@ func (x *Vulnerability) GetReferences() []string { return nil } +func (x *Vulnerability) GetPkgIdentifier() *PkgIdentifier { + if x != nil { + return x.PkgIdentifier + } + return nil +} + func (x *Vulnerability) GetLayer() *Layer { if x != nil { return x.Layer @@ -1272,7 +1343,7 @@ type DataSource struct { func (x *DataSource) Reset() { *x = DataSource{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[10] + mi := &file_rpc_common_service_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1285,7 +1356,7 @@ func (x *DataSource) String() string { func (*DataSource) ProtoMessage() {} func (x *DataSource) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[10] + mi := &file_rpc_common_service_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1298,7 +1369,7 @@ func (x *DataSource) ProtoReflect() protoreflect.Message { // Deprecated: Use DataSource.ProtoReflect.Descriptor instead. func (*DataSource) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{10} + return file_rpc_common_service_proto_rawDescGZIP(), []int{11} } func (x *DataSource) GetId() string { @@ -1335,7 +1406,7 @@ type Layer struct { func (x *Layer) Reset() { *x = Layer{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[11] + mi := &file_rpc_common_service_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1348,7 +1419,7 @@ func (x *Layer) String() string { func (*Layer) ProtoMessage() {} func (x *Layer) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[11] + mi := &file_rpc_common_service_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1361,7 +1432,7 @@ func (x *Layer) ProtoReflect() protoreflect.Message { // Deprecated: Use Layer.ProtoReflect.Descriptor instead. func (*Layer) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{11} + return file_rpc_common_service_proto_rawDescGZIP(), []int{12} } func (x *Layer) GetDigest() string { @@ -1401,7 +1472,7 @@ type CauseMetadata struct { func (x *CauseMetadata) Reset() { *x = CauseMetadata{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[12] + mi := &file_rpc_common_service_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1414,7 +1485,7 @@ func (x *CauseMetadata) String() string { func (*CauseMetadata) ProtoMessage() {} func (x *CauseMetadata) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[12] + mi := &file_rpc_common_service_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1427,7 +1498,7 @@ func (x *CauseMetadata) ProtoReflect() protoreflect.Message { // Deprecated: Use CauseMetadata.ProtoReflect.Descriptor instead. func (*CauseMetadata) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{12} + return file_rpc_common_service_proto_rawDescGZIP(), []int{13} } func (x *CauseMetadata) GetResource() string { @@ -1486,7 +1557,7 @@ type CVSS struct { func (x *CVSS) Reset() { *x = CVSS{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[13] + mi := &file_rpc_common_service_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1499,7 +1570,7 @@ func (x *CVSS) String() string { func (*CVSS) ProtoMessage() {} func (x *CVSS) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[13] + mi := &file_rpc_common_service_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1512,7 +1583,7 @@ func (x *CVSS) ProtoReflect() protoreflect.Message { // Deprecated: Use CVSS.ProtoReflect.Descriptor instead. func (*CVSS) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{13} + return file_rpc_common_service_proto_rawDescGZIP(), []int{14} } func (x *CVSS) GetV2Vector() string { @@ -1557,7 +1628,7 @@ type CustomResource struct { func (x *CustomResource) Reset() { *x = CustomResource{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[14] + mi := &file_rpc_common_service_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1570,7 +1641,7 @@ func (x *CustomResource) String() string { func (*CustomResource) ProtoMessage() {} func (x *CustomResource) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[14] + mi := &file_rpc_common_service_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1583,7 +1654,7 @@ func (x *CustomResource) ProtoReflect() protoreflect.Message { // Deprecated: Use CustomResource.ProtoReflect.Descriptor instead. func (*CustomResource) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{14} + return file_rpc_common_service_proto_rawDescGZIP(), []int{15} } func (x *CustomResource) GetType() string { @@ -1632,7 +1703,7 @@ type Line struct { func (x *Line) Reset() { *x = Line{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[15] + mi := &file_rpc_common_service_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1645,7 +1716,7 @@ func (x *Line) String() string { func (*Line) ProtoMessage() {} func (x *Line) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[15] + mi := &file_rpc_common_service_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1658,7 +1729,7 @@ func (x *Line) ProtoReflect() protoreflect.Message { // Deprecated: Use Line.ProtoReflect.Descriptor instead. func (*Line) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{15} + return file_rpc_common_service_proto_rawDescGZIP(), []int{16} } func (x *Line) GetNumber() int32 { @@ -1728,7 +1799,7 @@ type Code struct { func (x *Code) Reset() { *x = Code{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[16] + mi := &file_rpc_common_service_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1741,7 +1812,7 @@ func (x *Code) String() string { func (*Code) ProtoMessage() {} func (x *Code) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[16] + mi := &file_rpc_common_service_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1754,7 +1825,7 @@ func (x *Code) ProtoReflect() protoreflect.Message { // Deprecated: Use Code.ProtoReflect.Descriptor instead. func (*Code) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{16} + return file_rpc_common_service_proto_rawDescGZIP(), []int{17} } func (x *Code) GetLines() []*Line { @@ -1783,7 +1854,7 @@ type SecretFinding struct { func (x *SecretFinding) Reset() { *x = SecretFinding{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[17] + mi := &file_rpc_common_service_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1796,7 +1867,7 @@ func (x *SecretFinding) String() string { func (*SecretFinding) ProtoMessage() {} func (x *SecretFinding) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[17] + mi := &file_rpc_common_service_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1809,7 +1880,7 @@ func (x *SecretFinding) ProtoReflect() protoreflect.Message { // Deprecated: Use SecretFinding.ProtoReflect.Descriptor instead. func (*SecretFinding) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{17} + return file_rpc_common_service_proto_rawDescGZIP(), []int{18} } func (x *SecretFinding) GetRuleId() string { @@ -1887,7 +1958,7 @@ type Secret struct { func (x *Secret) Reset() { *x = Secret{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[18] + mi := &file_rpc_common_service_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1900,7 +1971,7 @@ func (x *Secret) String() string { func (*Secret) ProtoMessage() {} func (x *Secret) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[18] + mi := &file_rpc_common_service_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1913,7 +1984,7 @@ func (x *Secret) ProtoReflect() protoreflect.Message { // Deprecated: Use Secret.ProtoReflect.Descriptor instead. func (*Secret) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{18} + return file_rpc_common_service_proto_rawDescGZIP(), []int{19} } func (x *Secret) GetFilepath() string { @@ -1947,7 +2018,7 @@ type DetectedLicense struct { func (x *DetectedLicense) Reset() { *x = DetectedLicense{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[19] + mi := &file_rpc_common_service_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1960,7 +2031,7 @@ func (x *DetectedLicense) String() string { func (*DetectedLicense) ProtoMessage() {} func (x *DetectedLicense) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[19] + mi := &file_rpc_common_service_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1973,7 +2044,7 @@ func (x *DetectedLicense) ProtoReflect() protoreflect.Message { // Deprecated: Use DetectedLicense.ProtoReflect.Descriptor instead. func (*DetectedLicense) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{19} + return file_rpc_common_service_proto_rawDescGZIP(), []int{20} } func (x *DetectedLicense) GetSeverity() Severity { @@ -2040,7 +2111,7 @@ type LicenseFile struct { func (x *LicenseFile) Reset() { *x = LicenseFile{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[20] + mi := &file_rpc_common_service_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2053,7 +2124,7 @@ func (x *LicenseFile) String() string { func (*LicenseFile) ProtoMessage() {} func (x *LicenseFile) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[20] + mi := &file_rpc_common_service_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2066,7 +2137,7 @@ func (x *LicenseFile) ProtoReflect() protoreflect.Message { // Deprecated: Use LicenseFile.ProtoReflect.Descriptor instead. func (*LicenseFile) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{20} + return file_rpc_common_service_proto_rawDescGZIP(), []int{21} } func (x *LicenseFile) GetLicenseType() LicenseType_Enum { @@ -2118,7 +2189,7 @@ type LicenseFinding struct { func (x *LicenseFinding) Reset() { *x = LicenseFinding{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[21] + mi := &file_rpc_common_service_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2131,7 +2202,7 @@ func (x *LicenseFinding) String() string { func (*LicenseFinding) ProtoMessage() {} func (x *LicenseFinding) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[21] + mi := &file_rpc_common_service_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2144,7 +2215,7 @@ func (x *LicenseFinding) ProtoReflect() protoreflect.Message { // Deprecated: Use LicenseFinding.ProtoReflect.Descriptor instead. func (*LicenseFinding) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{21} + return file_rpc_common_service_proto_rawDescGZIP(), []int{22} } func (x *LicenseFinding) GetCategory() LicenseCategory_Enum { @@ -2187,7 +2258,7 @@ type LicenseCategory struct { func (x *LicenseCategory) Reset() { *x = LicenseCategory{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[22] + mi := &file_rpc_common_service_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2200,7 +2271,7 @@ func (x *LicenseCategory) String() string { func (*LicenseCategory) ProtoMessage() {} func (x *LicenseCategory) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[22] + mi := &file_rpc_common_service_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2213,7 +2284,7 @@ func (x *LicenseCategory) ProtoReflect() protoreflect.Message { // Deprecated: Use LicenseCategory.ProtoReflect.Descriptor instead. func (*LicenseCategory) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{22} + return file_rpc_common_service_proto_rawDescGZIP(), []int{23} } type LicenseType struct { @@ -2225,7 +2296,7 @@ type LicenseType struct { func (x *LicenseType) Reset() { *x = LicenseType{} if protoimpl.UnsafeEnabled { - mi := &file_rpc_common_service_proto_msgTypes[23] + mi := &file_rpc_common_service_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2238,7 +2309,7 @@ func (x *LicenseType) String() string { func (*LicenseType) ProtoMessage() {} func (x *LicenseType) ProtoReflect() protoreflect.Message { - mi := &file_rpc_common_service_proto_msgTypes[23] + mi := &file_rpc_common_service_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2251,7 +2322,7 @@ func (x *LicenseType) ProtoReflect() protoreflect.Message { // Deprecated: Use LicenseType.ProtoReflect.Descriptor instead. func (*LicenseType) Descriptor() ([]byte, []int) { - return file_rpc_common_service_proto_rawDescGZIP(), []int{23} + return file_rpc_common_service_proto_rawDescGZIP(), []int{24} } var File_rpc_common_service_proto protoreflect.FileDescriptor @@ -2286,7 +2357,7 @@ var file_rpc_common_service_proto_rawDesc = []byte{ 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x33, 0x0a, 0x09, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x61, 0x63, 0x6b, 0x61, - 0x67, 0x65, 0x52, 0x09, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x22, 0xce, 0x03, + 0x67, 0x65, 0x52, 0x09, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x69, 0x65, 0x73, 0x22, 0x8b, 0x04, 0x0a, 0x07, 0x50, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, @@ -2294,332 +2365,343 @@ var file_rpc_common_service_proto_rawDesc = []byte{ 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x63, 0x68, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x63, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x73, - 0x72, 0x63, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, - 0x72, 0x63, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x72, 0x63, 0x5f, 0x76, 0x65, - 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x72, 0x63, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x72, 0x63, 0x5f, 0x72, - 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x72, - 0x63, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x72, 0x63, 0x5f, - 0x65, 0x70, 0x6f, 0x63, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x73, 0x72, 0x63, - 0x45, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, - 0x73, 0x18, 0x0f, 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, - 0x73, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, - 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x65, 0x70, - 0x65, 0x6e, 0x64, 0x73, 0x5f, 0x6f, 0x6e, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, - 0x65, 0x70, 0x65, 0x6e, 0x64, 0x73, 0x4f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, - 0x73, 0x74, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, - 0x12, 0x10, 0x0a, 0x03, 0x64, 0x65, 0x76, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x64, - 0x65, 0x76, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x18, 0x12, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x22, 0xb6, - 0x02, 0x0a, 0x10, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x39, 0x0a, - 0x09, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x09, 0x73, - 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x08, 0x77, 0x61, 0x72, 0x6e, - 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, - 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, - 0x66, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x08, 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, - 0x73, 0x12, 0x37, 0x0a, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x18, 0x05, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x0a, 0x65, 0x78, - 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, - 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x69, - 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x63, - 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xf3, 0x01, 0x0a, 0x0d, 0x4d, 0x69, 0x73, 0x63, - 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, - 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x45, 0x0a, 0x0f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x6d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x72, 0x69, - 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x42, 0x0a, 0x0e, 0x63, 0x61, 0x75, 0x73, - 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x43, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x63, - 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4a, 0x04, 0x08, 0x03, - 0x10, 0x07, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x52, 0x02, 0x69, 0x64, 0x52, 0x05, 0x74, 0x69, - 0x74, 0x6c, 0x65, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x22, 0xf0, 0x01, - 0x0a, 0x0e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, - 0x12, 0x15, 0x0a, 0x06, 0x61, 0x64, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x61, 0x64, 0x76, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, - 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, - 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, - 0x2f, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x61, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, - 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x08, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, - 0x22, 0xf7, 0x03, 0x0a, 0x18, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4d, 0x69, 0x73, - 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x08, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, 0x76, - 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, - 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6d, - 0x61, 0x72, 0x79, 0x55, 0x72, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, - 0x6e, 0x63, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x66, 0x65, - 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, - 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x52, 0x05, 0x65, 0x70, 0x6f, 0x63, 0x68, 0x12, 0x3b, 0x0a, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x13, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, + 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x6b, 0x67, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0a, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x61, 0x72, 0x63, 0x68, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x61, 0x72, 0x63, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x72, 0x63, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x72, 0x63, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x72, 0x63, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x72, 0x63, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x72, 0x63, 0x5f, 0x72, 0x65, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x72, 0x63, 0x52, 0x65, + 0x6c, 0x65, 0x61, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x72, 0x63, 0x5f, 0x65, 0x70, 0x6f, + 0x63, 0x68, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x73, 0x72, 0x63, 0x45, 0x70, 0x6f, + 0x63, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x18, 0x0f, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x12, 0x29, + 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, - 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x42, 0x0a, 0x0e, 0x63, 0x61, 0x75, - 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0d, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x43, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, - 0x63, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x15, 0x0a, - 0x06, 0x61, 0x76, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, - 0x76, 0x64, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x0f, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0xbb, 0x09, 0x0a, 0x0d, 0x56, - 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x29, 0x0a, 0x10, - 0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, - 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x6e, - 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x5f, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x23, 0x0a, 0x0d, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x69, 0x78, 0x65, 0x64, 0x56, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x08, - 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, - 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, - 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, - 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x08, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, - 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, - 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x27, 0x0a, 0x0f, 0x73, - 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x0b, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x53, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x12, 0x39, 0x0a, 0x04, 0x63, 0x76, 0x73, 0x73, 0x18, 0x0c, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2e, - 0x43, 0x76, 0x73, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x63, 0x76, 0x73, 0x73, 0x12, - 0x17, 0x0a, 0x07, 0x63, 0x77, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, - 0x52, 0x06, 0x63, 0x77, 0x65, 0x49, 0x64, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x6d, - 0x61, 0x72, 0x79, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, - 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x55, 0x72, 0x6c, 0x12, 0x41, 0x0a, 0x0e, 0x70, 0x75, 0x62, - 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x70, - 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x12, 0x48, 0x0a, 0x12, - 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x61, - 0x74, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, - 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, - 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x12, 0x48, 0x0a, 0x14, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, - 0x5f, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x79, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x11, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x63, 0x75, - 0x73, 0x74, 0x6f, 0x6d, 0x41, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x79, 0x44, 0x61, 0x74, 0x61, - 0x12, 0x40, 0x0a, 0x10, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x76, 0x75, 0x6c, 0x6e, 0x5f, - 0x64, 0x61, 0x74, 0x61, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x52, 0x0e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x56, 0x75, 0x6c, 0x6e, 0x44, 0x61, - 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x73, - 0x18, 0x13, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x49, 0x64, - 0x73, 0x12, 0x39, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x0f, - 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, - 0x15, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, - 0x74, 0x79, 0x2e, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, - 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x53, 0x65, - 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x70, 0x61, - 0x74, 0x68, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, 0x67, 0x50, 0x61, 0x74, - 0x68, 0x12, 0x15, 0x0a, 0x06, 0x70, 0x6b, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x17, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x70, 0x6b, 0x67, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x18, 0x18, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x1a, 0x4b, 0x0a, 0x09, 0x43, 0x76, 0x73, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x28, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, - 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x56, - 0x53, 0x53, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x59, 0x0a, - 0x13, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x42, 0x0a, 0x0a, 0x44, 0x61, 0x74, 0x61, - 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, - 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x57, 0x0a, 0x05, - 0x4c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, - 0x07, 0x64, 0x69, 0x66, 0x66, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, - 0x64, 0x69, 0x66, 0x66, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x5f, 0x62, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, - 0x74, 0x65, 0x64, 0x42, 0x79, 0x22, 0xc3, 0x01, 0x0a, 0x0d, 0x43, 0x61, 0x75, 0x73, 0x65, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, - 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, - 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, - 0x74, 0x61, 0x72, 0x74, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, - 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x4c, - 0x69, 0x6e, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x76, 0x0a, 0x04, 0x43, - 0x56, 0x53, 0x53, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x32, 0x5f, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x32, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, - 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x33, 0x5f, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x33, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x19, 0x0a, - 0x08, 0x76, 0x32, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, - 0x07, 0x76, 0x32, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x33, 0x5f, 0x73, - 0x63, 0x6f, 0x72, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x76, 0x33, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x22, 0x98, 0x01, 0x0a, 0x0e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, - 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, - 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, - 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xf3, - 0x01, 0x0a, 0x04, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, - 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, - 0x63, 0x61, 0x75, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x43, - 0x61, 0x75, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, - 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, - 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x65, - 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x69, 0x67, - 0x68, 0x74, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x63, 0x61, - 0x75, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, - 0x43, 0x61, 0x75, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x61, - 0x75, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x43, - 0x61, 0x75, 0x73, 0x65, 0x22, 0x30, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x28, 0x0a, 0x05, - 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x72, - 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x6e, 0x65, 0x52, - 0x05, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x22, 0x9f, 0x02, 0x0a, 0x0d, 0x53, 0x65, 0x63, 0x72, 0x65, - 0x74, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x75, 0x6c, 0x65, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x75, 0x6c, 0x65, 0x49, - 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x1a, 0x0a, - 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, - 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, - 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x19, - 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x07, 0x65, 0x6e, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x63, 0x6f, 0x64, - 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, - 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, - 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, - 0x65, 0x72, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x22, 0x5d, 0x0a, 0x06, 0x53, 0x65, 0x63, 0x72, - 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x12, 0x37, - 0x0a, 0x08, 0x66, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x08, 0x66, - 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x85, 0x02, 0x0a, 0x0f, 0x44, 0x65, 0x74, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x08, 0x73, - 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, + 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, + 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, + 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, + 0x73, 0x5f, 0x6f, 0x6e, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x70, 0x65, + 0x6e, 0x64, 0x73, 0x4f, 0x6e, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, + 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, + 0x03, 0x64, 0x65, 0x76, 0x18, 0x11, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x64, 0x65, 0x76, 0x12, + 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x18, 0x12, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x08, 0x69, 0x6e, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x22, 0x35, 0x0a, 0x0d, 0x50, + 0x6b, 0x67, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, + 0x70, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x75, 0x72, 0x6c, + 0x12, 0x10, 0x0a, 0x03, 0x63, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x63, + 0x70, 0x65, 0x22, 0xb6, 0x02, 0x0a, 0x10, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, + 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, + 0x68, 0x12, 0x39, 0x0a, 0x09, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x52, 0x09, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x12, 0x37, 0x0a, 0x08, + 0x77, 0x61, 0x72, 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, + 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x69, + 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x08, 0x77, 0x61, 0x72, + 0x6e, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x37, 0x0a, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, + 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, 0x73, 0x12, 0x3b, + 0x0a, 0x0a, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x06, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, + 0x0a, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xf3, 0x01, 0x0a, 0x0d, + 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1c, 0x0a, + 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x45, 0x0a, 0x0f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, + 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0e, 0x70, 0x6f, + 0x6c, 0x69, 0x63, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x42, 0x0a, 0x0e, + 0x63, 0x61, 0x75, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x52, 0x0d, 0x63, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x4a, 0x04, 0x08, 0x03, 0x10, 0x07, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x52, 0x02, 0x69, 0x64, + 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, + 0x79, 0x22, 0xf0, 0x01, 0x0a, 0x0e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x02, 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x64, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x64, 0x76, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, + 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, + 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, + 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, + 0x69, 0x74, 0x79, 0x12, 0x2f, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, + 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x12, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x41, 0x63, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x73, 0x22, 0xf7, 0x03, 0x0a, 0x18, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, + 0x64, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, + 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x6c, + 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, + 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, + 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, + 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, + 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x55, 0x72, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, + 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, + 0x75, 0x73, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x42, 0x0a, + 0x0e, 0x63, 0x61, 0x75, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, + 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x52, 0x0d, 0x63, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x76, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x05, 0x61, 0x76, 0x64, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, + 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0xff, + 0x09, 0x0a, 0x0d, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, + 0x12, 0x29, 0x0a, 0x10, 0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, + 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x76, 0x75, 0x6c, 0x6e, + 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x70, + 0x6b, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, + 0x6b, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, + 0x6c, 0x65, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x10, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x76, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x69, 0x78, 0x65, + 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, + 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x32, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, + 0x72, 0x69, 0x74, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0e, 0x70, 0x6b, 0x67, 0x5f, 0x69, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, + 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x6b, 0x67, 0x49, + 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0d, 0x70, 0x6b, 0x67, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, + 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, + 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, + 0x79, 0x65, 0x72, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x5f, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, + 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x39, 0x0a, 0x04, + 0x63, 0x76, 0x73, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x74, 0x72, 0x69, + 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, + 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x43, 0x76, 0x73, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x52, 0x04, 0x63, 0x76, 0x73, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x63, 0x77, 0x65, 0x5f, 0x69, + 0x64, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x63, 0x77, 0x65, 0x49, 0x64, 0x73, + 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x75, 0x72, 0x6c, 0x18, + 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x55, 0x72, + 0x6c, 0x12, 0x41, 0x0a, 0x0e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x64, + 0x61, 0x74, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, + 0x44, 0x61, 0x74, 0x65, 0x12, 0x48, 0x0a, 0x12, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6d, 0x6f, 0x64, + 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x6c, 0x61, + 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x12, 0x48, + 0x0a, 0x14, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, + 0x79, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x41, 0x64, 0x76, 0x69, + 0x73, 0x6f, 0x72, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x40, 0x0a, 0x10, 0x63, 0x75, 0x73, 0x74, + 0x6f, 0x6d, 0x5f, 0x76, 0x75, 0x6c, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x12, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x63, 0x75, 0x73, 0x74, + 0x6f, 0x6d, 0x56, 0x75, 0x6c, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x76, 0x65, + 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, + 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x0b, 0x64, 0x61, 0x74, + 0x61, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, + 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x61, + 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x0f, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x73, + 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x15, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, + 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x56, 0x75, 0x6c, + 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x56, 0x65, 0x6e, 0x64, 0x6f, + 0x72, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, + 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x19, + 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x70, 0x6b, 0x67, 0x50, 0x61, 0x74, 0x68, 0x12, 0x15, 0x0a, 0x06, 0x70, 0x6b, 0x67, + 0x5f, 0x69, 0x64, 0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x6b, 0x67, 0x49, 0x64, + 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x18, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0x4b, 0x0a, 0x09, 0x43, 0x76, 0x73, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x28, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x56, 0x53, 0x53, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x59, 0x0a, 0x13, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x53, + 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x76, - 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, - 0x3e, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0e, 0x32, 0x22, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, - 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, - 0x19, 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, - 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, - 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x52, - 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, - 0x69, 0x6e, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x22, - 0xed, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, - 0x41, 0x0a, 0x0c, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x0b, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, + 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, + 0x22, 0x42, 0x0a, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x75, 0x72, 0x6c, 0x22, 0x57, 0x0a, 0x05, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x16, 0x0a, + 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, + 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x69, 0x66, 0x66, 0x5f, 0x69, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x66, 0x66, 0x49, 0x64, 0x12, 0x1d, + 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x22, 0xc3, 0x01, + 0x0a, 0x0d, 0x43, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, + 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x69, 0x6e, 0x65, + 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x63, + 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x72, 0x69, 0x76, + 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, + 0x6f, 0x64, 0x65, 0x22, 0x76, 0x0a, 0x04, 0x43, 0x56, 0x53, 0x53, 0x12, 0x1b, 0x0a, 0x09, 0x76, + 0x32, 0x5f, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, + 0x76, 0x32, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x33, 0x5f, 0x76, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x33, 0x56, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x32, 0x5f, 0x73, 0x63, 0x6f, 0x72, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x76, 0x32, 0x53, 0x63, 0x6f, 0x72, 0x65, + 0x12, 0x19, 0x0a, 0x08, 0x76, 0x33, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x01, 0x52, 0x07, 0x76, 0x33, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x98, 0x01, 0x0a, 0x0e, + 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, - 0x19, 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x69, - 0x6e, 0x67, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, + 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, + 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, + 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x04, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xf3, 0x01, 0x0a, 0x04, 0x4c, 0x69, 0x6e, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, + 0x74, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x63, 0x61, 0x75, 0x73, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x43, 0x61, 0x75, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, + 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, + 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x09, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, + 0x67, 0x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, + 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x75, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, 0x43, 0x61, 0x75, 0x73, 0x65, 0x12, 0x1d, 0x0a, + 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x75, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x08, 0x52, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x43, 0x61, 0x75, 0x73, 0x65, 0x22, 0x30, 0x0a, 0x04, + 0x43, 0x6f, 0x64, 0x65, 0x12, 0x28, 0x0a, 0x05, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x01, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x6e, 0x65, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x22, 0x9f, + 0x02, 0x0a, 0x0d, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, + 0x12, 0x17, 0x0a, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x72, 0x75, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x74, + 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, 0x74, + 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, + 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, + 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x74, 0x61, + 0x72, 0x74, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x6c, 0x69, + 0x6e, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x4c, 0x69, 0x6e, + 0x65, 0x12, 0x26, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x12, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, + 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, 0x74, + 0x63, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x12, + 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, + 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, + 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, + 0x22, 0x5d, 0x0a, 0x06, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, + 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, + 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x12, 0x37, 0x0a, 0x08, 0x66, 0x69, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x46, 0x69, + 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x08, 0x66, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x22, + 0x85, 0x02, 0x0a, 0x0f, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4c, 0x69, 0x63, 0x65, + 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, + 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x3e, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, + 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x74, 0x72, 0x69, 0x76, + 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, + 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x08, 0x63, + 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, + 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0xed, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x63, 0x65, + 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x6c, 0x69, 0x63, 0x65, 0x6e, + 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, + 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, + 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x0b, 0x6c, + 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, + 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, + 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x69, 0x6e, 0x67, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x52, 0x08, 0x66, 0x69, 0x6e, 0x67, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x29, 0x0a, 0x05, + 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, + 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, + 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x22, 0x98, 0x01, 0x0a, 0x0e, 0x4c, 0x69, 0x63, 0x65, + 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x3e, 0x0a, 0x08, 0x63, 0x61, + 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, - 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x08, 0x66, 0x69, 0x6e, 0x67, - 0x69, 0x6e, 0x67, 0x73, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x22, - 0x98, 0x01, 0x0a, 0x0e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6e, 0x64, 0x69, - 0x6e, 0x67, 0x12, 0x3e, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, - 0x6f, 0x72, 0x79, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, - 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, - 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0x95, 0x01, 0x0a, 0x0f, 0x4c, - 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, 0x81, - 0x01, 0x0a, 0x04, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, - 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x42, - 0x49, 0x44, 0x44, 0x45, 0x4e, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x53, 0x54, 0x52, - 0x49, 0x43, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x43, 0x49, 0x50, - 0x52, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x54, 0x49, 0x43, - 0x45, 0x10, 0x04, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x56, - 0x45, 0x10, 0x05, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x45, 0x4e, 0x43, 0x55, 0x4d, 0x42, 0x45, - 0x52, 0x45, 0x44, 0x10, 0x06, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, - 0x10, 0x07, 0x22, 0x4e, 0x0a, 0x0b, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x22, 0x3f, 0x0a, 0x04, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, - 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x50, - 0x4b, 0x47, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x10, 0x02, - 0x12, 0x10, 0x0a, 0x0c, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x5f, 0x46, 0x49, 0x4c, 0x45, - 0x10, 0x03, 0x2a, 0x44, 0x0a, 0x08, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x0b, - 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4c, - 0x4f, 0x57, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x45, 0x44, 0x49, 0x55, 0x4d, 0x10, 0x02, - 0x12, 0x08, 0x0a, 0x04, 0x48, 0x49, 0x47, 0x48, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x52, - 0x49, 0x54, 0x49, 0x43, 0x41, 0x4c, 0x10, 0x04, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x71, 0x75, 0x61, 0x73, 0x65, 0x63, 0x75, 0x72, - 0x69, 0x74, 0x79, 0x2f, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x33, + 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x2e, 0x45, 0x6e, 0x75, 0x6d, + 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, + 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x02, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, + 0x6e, 0x6b, 0x22, 0x95, 0x01, 0x0a, 0x0f, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, + 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, 0x81, 0x01, 0x0a, 0x04, 0x45, 0x6e, 0x75, 0x6d, 0x12, + 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x42, 0x49, 0x44, 0x44, 0x45, 0x4e, 0x10, 0x01, 0x12, + 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x53, 0x54, 0x52, 0x49, 0x43, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, + 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x43, 0x49, 0x50, 0x52, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x03, 0x12, + 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x54, 0x49, 0x43, 0x45, 0x10, 0x04, 0x12, 0x0e, 0x0a, 0x0a, 0x50, + 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x56, 0x45, 0x10, 0x05, 0x12, 0x10, 0x0a, 0x0c, 0x55, + 0x4e, 0x45, 0x4e, 0x43, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x45, 0x44, 0x10, 0x06, 0x12, 0x0b, 0x0a, + 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x07, 0x22, 0x4e, 0x0a, 0x0b, 0x4c, 0x69, + 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3f, 0x0a, 0x04, 0x45, 0x6e, 0x75, + 0x6d, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x50, 0x4b, 0x47, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, + 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x4c, 0x49, 0x43, 0x45, + 0x4e, 0x53, 0x45, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x03, 0x2a, 0x44, 0x0a, 0x08, 0x53, 0x65, + 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, + 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4c, 0x4f, 0x57, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, + 0x4d, 0x45, 0x44, 0x49, 0x55, 0x4d, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x49, 0x47, 0x48, + 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x52, 0x49, 0x54, 0x49, 0x43, 0x41, 0x4c, 0x10, 0x04, + 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, + 0x71, 0x75, 0x61, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x72, 0x69, 0x76, + 0x79, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x3b, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2635,7 +2717,7 @@ func file_rpc_common_service_proto_rawDescGZIP() []byte { } var file_rpc_common_service_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_rpc_common_service_proto_msgTypes = make([]protoimpl.MessageInfo, 26) +var file_rpc_common_service_proto_msgTypes = make([]protoimpl.MessageInfo, 27) var file_rpc_common_service_proto_goTypes = []interface{}{ (Severity)(0), // 0: trivy.common.Severity (LicenseCategory_Enum)(0), // 1: trivy.common.LicenseCategory.Enum @@ -2645,72 +2727,75 @@ var file_rpc_common_service_proto_goTypes = []interface{}{ (*PackageInfo)(nil), // 5: trivy.common.PackageInfo (*Application)(nil), // 6: trivy.common.Application (*Package)(nil), // 7: trivy.common.Package - (*Misconfiguration)(nil), // 8: trivy.common.Misconfiguration - (*MisconfResult)(nil), // 9: trivy.common.MisconfResult - (*PolicyMetadata)(nil), // 10: trivy.common.PolicyMetadata - (*DetectedMisconfiguration)(nil), // 11: trivy.common.DetectedMisconfiguration - (*Vulnerability)(nil), // 12: trivy.common.Vulnerability - (*DataSource)(nil), // 13: trivy.common.DataSource - (*Layer)(nil), // 14: trivy.common.Layer - (*CauseMetadata)(nil), // 15: trivy.common.CauseMetadata - (*CVSS)(nil), // 16: trivy.common.CVSS - (*CustomResource)(nil), // 17: trivy.common.CustomResource - (*Line)(nil), // 18: trivy.common.Line - (*Code)(nil), // 19: trivy.common.Code - (*SecretFinding)(nil), // 20: trivy.common.SecretFinding - (*Secret)(nil), // 21: trivy.common.Secret - (*DetectedLicense)(nil), // 22: trivy.common.DetectedLicense - (*LicenseFile)(nil), // 23: trivy.common.LicenseFile - (*LicenseFinding)(nil), // 24: trivy.common.LicenseFinding - (*LicenseCategory)(nil), // 25: trivy.common.LicenseCategory - (*LicenseType)(nil), // 26: trivy.common.LicenseType - nil, // 27: trivy.common.Vulnerability.CvssEntry - nil, // 28: trivy.common.Vulnerability.VendorSeverityEntry - (*timestamppb.Timestamp)(nil), // 29: google.protobuf.Timestamp - (*structpb.Value)(nil), // 30: google.protobuf.Value + (*PkgIdentifier)(nil), // 8: trivy.common.PkgIdentifier + (*Misconfiguration)(nil), // 9: trivy.common.Misconfiguration + (*MisconfResult)(nil), // 10: trivy.common.MisconfResult + (*PolicyMetadata)(nil), // 11: trivy.common.PolicyMetadata + (*DetectedMisconfiguration)(nil), // 12: trivy.common.DetectedMisconfiguration + (*Vulnerability)(nil), // 13: trivy.common.Vulnerability + (*DataSource)(nil), // 14: trivy.common.DataSource + (*Layer)(nil), // 15: trivy.common.Layer + (*CauseMetadata)(nil), // 16: trivy.common.CauseMetadata + (*CVSS)(nil), // 17: trivy.common.CVSS + (*CustomResource)(nil), // 18: trivy.common.CustomResource + (*Line)(nil), // 19: trivy.common.Line + (*Code)(nil), // 20: trivy.common.Code + (*SecretFinding)(nil), // 21: trivy.common.SecretFinding + (*Secret)(nil), // 22: trivy.common.Secret + (*DetectedLicense)(nil), // 23: trivy.common.DetectedLicense + (*LicenseFile)(nil), // 24: trivy.common.LicenseFile + (*LicenseFinding)(nil), // 25: trivy.common.LicenseFinding + (*LicenseCategory)(nil), // 26: trivy.common.LicenseCategory + (*LicenseType)(nil), // 27: trivy.common.LicenseType + nil, // 28: trivy.common.Vulnerability.CvssEntry + nil, // 29: trivy.common.Vulnerability.VendorSeverityEntry + (*timestamppb.Timestamp)(nil), // 30: google.protobuf.Timestamp + (*structpb.Value)(nil), // 31: google.protobuf.Value } var file_rpc_common_service_proto_depIdxs = []int32{ 7, // 0: trivy.common.PackageInfo.packages:type_name -> trivy.common.Package 7, // 1: trivy.common.Application.libraries:type_name -> trivy.common.Package - 14, // 2: trivy.common.Package.layer:type_name -> trivy.common.Layer - 9, // 3: trivy.common.Misconfiguration.successes:type_name -> trivy.common.MisconfResult - 9, // 4: trivy.common.Misconfiguration.warnings:type_name -> trivy.common.MisconfResult - 9, // 5: trivy.common.Misconfiguration.failures:type_name -> trivy.common.MisconfResult - 9, // 6: trivy.common.Misconfiguration.exceptions:type_name -> trivy.common.MisconfResult - 10, // 7: trivy.common.MisconfResult.policy_metadata:type_name -> trivy.common.PolicyMetadata - 15, // 8: trivy.common.MisconfResult.cause_metadata:type_name -> trivy.common.CauseMetadata - 0, // 9: trivy.common.DetectedMisconfiguration.severity:type_name -> trivy.common.Severity - 14, // 10: trivy.common.DetectedMisconfiguration.layer:type_name -> trivy.common.Layer - 15, // 11: trivy.common.DetectedMisconfiguration.cause_metadata:type_name -> trivy.common.CauseMetadata - 0, // 12: trivy.common.Vulnerability.severity:type_name -> trivy.common.Severity - 14, // 13: trivy.common.Vulnerability.layer:type_name -> trivy.common.Layer - 27, // 14: trivy.common.Vulnerability.cvss:type_name -> trivy.common.Vulnerability.CvssEntry - 29, // 15: trivy.common.Vulnerability.published_date:type_name -> google.protobuf.Timestamp - 29, // 16: trivy.common.Vulnerability.last_modified_date:type_name -> google.protobuf.Timestamp - 30, // 17: trivy.common.Vulnerability.custom_advisory_data:type_name -> google.protobuf.Value - 30, // 18: trivy.common.Vulnerability.custom_vuln_data:type_name -> google.protobuf.Value - 13, // 19: trivy.common.Vulnerability.data_source:type_name -> trivy.common.DataSource - 28, // 20: trivy.common.Vulnerability.vendor_severity:type_name -> trivy.common.Vulnerability.VendorSeverityEntry - 19, // 21: trivy.common.CauseMetadata.code:type_name -> trivy.common.Code - 14, // 22: trivy.common.CustomResource.layer:type_name -> trivy.common.Layer - 30, // 23: trivy.common.CustomResource.data:type_name -> google.protobuf.Value - 18, // 24: trivy.common.Code.lines:type_name -> trivy.common.Line - 19, // 25: trivy.common.SecretFinding.code:type_name -> trivy.common.Code - 14, // 26: trivy.common.SecretFinding.layer:type_name -> trivy.common.Layer - 20, // 27: trivy.common.Secret.findings:type_name -> trivy.common.SecretFinding - 0, // 28: trivy.common.DetectedLicense.severity:type_name -> trivy.common.Severity - 1, // 29: trivy.common.DetectedLicense.category:type_name -> trivy.common.LicenseCategory.Enum - 2, // 30: trivy.common.LicenseFile.license_type:type_name -> trivy.common.LicenseType.Enum - 24, // 31: trivy.common.LicenseFile.fingings:type_name -> trivy.common.LicenseFinding - 14, // 32: trivy.common.LicenseFile.layer:type_name -> trivy.common.Layer - 1, // 33: trivy.common.LicenseFinding.category:type_name -> trivy.common.LicenseCategory.Enum - 16, // 34: trivy.common.Vulnerability.CvssEntry.value:type_name -> trivy.common.CVSS - 0, // 35: trivy.common.Vulnerability.VendorSeverityEntry.value:type_name -> trivy.common.Severity - 36, // [36:36] is the sub-list for method output_type - 36, // [36:36] is the sub-list for method input_type - 36, // [36:36] is the sub-list for extension type_name - 36, // [36:36] is the sub-list for extension extendee - 0, // [0:36] is the sub-list for field type_name + 8, // 2: trivy.common.Package.identifier:type_name -> trivy.common.PkgIdentifier + 15, // 3: trivy.common.Package.layer:type_name -> trivy.common.Layer + 10, // 4: trivy.common.Misconfiguration.successes:type_name -> trivy.common.MisconfResult + 10, // 5: trivy.common.Misconfiguration.warnings:type_name -> trivy.common.MisconfResult + 10, // 6: trivy.common.Misconfiguration.failures:type_name -> trivy.common.MisconfResult + 10, // 7: trivy.common.Misconfiguration.exceptions:type_name -> trivy.common.MisconfResult + 11, // 8: trivy.common.MisconfResult.policy_metadata:type_name -> trivy.common.PolicyMetadata + 16, // 9: trivy.common.MisconfResult.cause_metadata:type_name -> trivy.common.CauseMetadata + 0, // 10: trivy.common.DetectedMisconfiguration.severity:type_name -> trivy.common.Severity + 15, // 11: trivy.common.DetectedMisconfiguration.layer:type_name -> trivy.common.Layer + 16, // 12: trivy.common.DetectedMisconfiguration.cause_metadata:type_name -> trivy.common.CauseMetadata + 0, // 13: trivy.common.Vulnerability.severity:type_name -> trivy.common.Severity + 8, // 14: trivy.common.Vulnerability.pkg_identifier:type_name -> trivy.common.PkgIdentifier + 15, // 15: trivy.common.Vulnerability.layer:type_name -> trivy.common.Layer + 28, // 16: trivy.common.Vulnerability.cvss:type_name -> trivy.common.Vulnerability.CvssEntry + 30, // 17: trivy.common.Vulnerability.published_date:type_name -> google.protobuf.Timestamp + 30, // 18: trivy.common.Vulnerability.last_modified_date:type_name -> google.protobuf.Timestamp + 31, // 19: trivy.common.Vulnerability.custom_advisory_data:type_name -> google.protobuf.Value + 31, // 20: trivy.common.Vulnerability.custom_vuln_data:type_name -> google.protobuf.Value + 14, // 21: trivy.common.Vulnerability.data_source:type_name -> trivy.common.DataSource + 29, // 22: trivy.common.Vulnerability.vendor_severity:type_name -> trivy.common.Vulnerability.VendorSeverityEntry + 20, // 23: trivy.common.CauseMetadata.code:type_name -> trivy.common.Code + 15, // 24: trivy.common.CustomResource.layer:type_name -> trivy.common.Layer + 31, // 25: trivy.common.CustomResource.data:type_name -> google.protobuf.Value + 19, // 26: trivy.common.Code.lines:type_name -> trivy.common.Line + 20, // 27: trivy.common.SecretFinding.code:type_name -> trivy.common.Code + 15, // 28: trivy.common.SecretFinding.layer:type_name -> trivy.common.Layer + 21, // 29: trivy.common.Secret.findings:type_name -> trivy.common.SecretFinding + 0, // 30: trivy.common.DetectedLicense.severity:type_name -> trivy.common.Severity + 1, // 31: trivy.common.DetectedLicense.category:type_name -> trivy.common.LicenseCategory.Enum + 2, // 32: trivy.common.LicenseFile.license_type:type_name -> trivy.common.LicenseType.Enum + 25, // 33: trivy.common.LicenseFile.fingings:type_name -> trivy.common.LicenseFinding + 15, // 34: trivy.common.LicenseFile.layer:type_name -> trivy.common.Layer + 1, // 35: trivy.common.LicenseFinding.category:type_name -> trivy.common.LicenseCategory.Enum + 17, // 36: trivy.common.Vulnerability.CvssEntry.value:type_name -> trivy.common.CVSS + 0, // 37: trivy.common.Vulnerability.VendorSeverityEntry.value:type_name -> trivy.common.Severity + 38, // [38:38] is the sub-list for method output_type + 38, // [38:38] is the sub-list for method input_type + 38, // [38:38] is the sub-list for extension type_name + 38, // [38:38] is the sub-list for extension extendee + 0, // [0:38] is the sub-list for field type_name } func init() { file_rpc_common_service_proto_init() } @@ -2780,7 +2865,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Misconfiguration); i { + switch v := v.(*PkgIdentifier); i { case 0: return &v.state case 1: @@ -2792,7 +2877,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MisconfResult); i { + switch v := v.(*Misconfiguration); i { case 0: return &v.state case 1: @@ -2804,7 +2889,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PolicyMetadata); i { + switch v := v.(*MisconfResult); i { case 0: return &v.state case 1: @@ -2816,7 +2901,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DetectedMisconfiguration); i { + switch v := v.(*PolicyMetadata); i { case 0: return &v.state case 1: @@ -2828,7 +2913,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Vulnerability); i { + switch v := v.(*DetectedMisconfiguration); i { case 0: return &v.state case 1: @@ -2840,7 +2925,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DataSource); i { + switch v := v.(*Vulnerability); i { case 0: return &v.state case 1: @@ -2852,7 +2937,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Layer); i { + switch v := v.(*DataSource); i { case 0: return &v.state case 1: @@ -2864,7 +2949,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CauseMetadata); i { + switch v := v.(*Layer); i { case 0: return &v.state case 1: @@ -2876,7 +2961,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CVSS); i { + switch v := v.(*CauseMetadata); i { case 0: return &v.state case 1: @@ -2888,7 +2973,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CustomResource); i { + switch v := v.(*CVSS); i { case 0: return &v.state case 1: @@ -2900,7 +2985,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Line); i { + switch v := v.(*CustomResource); i { case 0: return &v.state case 1: @@ -2912,7 +2997,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Code); i { + switch v := v.(*Line); i { case 0: return &v.state case 1: @@ -2924,7 +3009,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SecretFinding); i { + switch v := v.(*Code); i { case 0: return &v.state case 1: @@ -2936,7 +3021,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Secret); i { + switch v := v.(*SecretFinding); i { case 0: return &v.state case 1: @@ -2948,7 +3033,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DetectedLicense); i { + switch v := v.(*Secret); i { case 0: return &v.state case 1: @@ -2960,7 +3045,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LicenseFile); i { + switch v := v.(*DetectedLicense); i { case 0: return &v.state case 1: @@ -2972,7 +3057,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LicenseFinding); i { + switch v := v.(*LicenseFile); i { case 0: return &v.state case 1: @@ -2984,7 +3069,7 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LicenseCategory); i { + switch v := v.(*LicenseFinding); i { case 0: return &v.state case 1: @@ -2996,6 +3081,18 @@ func file_rpc_common_service_proto_init() { } } file_rpc_common_service_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LicenseCategory); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_rpc_common_service_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*LicenseType); i { case 0: return &v.state @@ -3014,7 +3111,7 @@ func file_rpc_common_service_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_rpc_common_service_proto_rawDesc, NumEnums: 3, - NumMessages: 26, + NumMessages: 27, NumExtensions: 0, NumServices: 0, }, diff --git a/rpc/common/service.proto b/rpc/common/service.proto index ee8aaea697d3..375b17684809 100644 --- a/rpc/common/service.proto +++ b/rpc/common/service.proto @@ -33,12 +33,13 @@ message Application { message Package { // binary package // e.g. bind-utils - string id = 13; - string name = 1; - string version = 2; - string release = 3; - int32 epoch = 4; - string arch = 5; + string id = 13; + string name = 1; + string version = 2; + string release = 3; + int32 epoch = 4; + PkgIdentifier identifier = 19; + string arch = 5; // src package containing some binary packages // e.g. bind string src_name = 6; @@ -54,6 +55,11 @@ message Package { bool indirect = 18; } +message PkgIdentifier { + string purl = 1; + string cpe = 2; +} + message Misconfiguration { string file_type = 1; string file_path = 2; @@ -110,6 +116,7 @@ message Vulnerability { string description = 6; Severity severity = 7; repeated string references = 8; + PkgIdentifier pkg_identifier = 25; Layer layer = 10; string severity_source = 11; map cvss = 12; @@ -252,4 +259,4 @@ message LicenseType { HEADER = 2; LICENSE_FILE = 3; } -} \ No newline at end of file +}