diff --git a/docs/docs/scanner/vulnerability.md b/docs/docs/scanner/vulnerability.md index 017d57510b65..2ebd9ec7a5f8 100644 --- a/docs/docs/scanner/vulnerability.md +++ b/docs/docs/scanner/vulnerability.md @@ -5,6 +5,7 @@ The following packages are supported. - [OS packages](#os-packages) - [Language-specific packages](#language-specific-packages) +- [Kubernetes components (control plane, node and addons)](#kubernetes-components-control-plane-node-and-addons) Trivy also detects known vulnerabilities in Kubernetes components using KBOM (Kubernetes bill of Material) scanning. To learn more, see the [documentation for Kubernetes scanning](../target/kubernetes.md#KBOM). @@ -106,9 +107,9 @@ Trivy can detect vulnerabilities in Kubernetes clusters and components. ### Data Sources -| Vendor | Source | -| ------------- | ------------------------------------------------------------ | -| Kubernetes | [Kubernetes Official CVE feed][^1] | +| Vendor | Source | +| ------------- |---------------------------------------------| +| Kubernetes | [Kubernetes Official CVE feed][k8s-cve][^1] | [^1]: Some manual triage and correction has been made. @@ -195,4 +196,4 @@ Currently, specifying a username and password is not supported. [nvd]: https://nvd.nist.gov/vuln -[Kubernetes Official CVE feed]: https://kubernetes.io/docs/reference/issues-security/official-cve-feed/ +[k8s-cve]: https://kubernetes.io/docs/reference/issues-security/official-cve-feed/ diff --git a/go.mod b/go.mod index fbb71e929c8c..b33c6003fb0f 100644 --- a/go.mod +++ b/go.mod @@ -23,9 +23,9 @@ require ( github.com/aquasecurity/table v1.8.0 github.com/aquasecurity/testdocker v0.0.0-20230111101738-e741bda259da github.com/aquasecurity/tml v0.6.1 - github.com/aquasecurity/trivy-db v0.0.0-20230831170347-f732860d4917 + github.com/aquasecurity/trivy-db v0.0.0-20231005141211-4fc651f7ac8d github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728 - github.com/aquasecurity/trivy-kubernetes v0.5.7 + github.com/aquasecurity/trivy-kubernetes v0.5.8-0.20230928134646-b414e546fe6d github.com/aws/aws-sdk-go v1.45.19 github.com/aws/aws-sdk-go-v2 v1.21.0 github.com/aws/aws-sdk-go-v2/config v1.18.38 diff --git a/go.sum b/go.sum index e23b1cb268ee..cfe2f8badc22 100644 --- a/go.sum +++ b/go.sum @@ -343,12 +343,12 @@ github.com/aquasecurity/testdocker v0.0.0-20230111101738-e741bda259da h1:pj/adfN github.com/aquasecurity/testdocker v0.0.0-20230111101738-e741bda259da/go.mod h1:852lbQLpK2nCwlR4ZLYIccxYCfoQao6q9Nl6tjz54v8= github.com/aquasecurity/tml v0.6.1 h1:y2ZlGSfrhnn7t4ZJ/0rotuH+v5Jgv6BDDO5jB6A9gwo= github.com/aquasecurity/tml v0.6.1/go.mod h1:OnYMWY5lvI9ejU7yH9LCberWaaTBW7hBFsITiIMY2yY= -github.com/aquasecurity/trivy-db v0.0.0-20230831170347-f732860d4917 h1:MQd7h7yUyA8UlUzhjNMzpUX0NpD7jfxmRfSKwp/Ji3E= -github.com/aquasecurity/trivy-db v0.0.0-20230831170347-f732860d4917/go.mod h1:WJ5Qnk5ZNGWvks07GOZe2IOsuXrPfSC5c8hYGOGfrsU= +github.com/aquasecurity/trivy-db v0.0.0-20231005141211-4fc651f7ac8d h1:fjI9mkoTUAkbGqpzt9nJsO24RAdfG+ZSiLFj0G2jO8c= +github.com/aquasecurity/trivy-db v0.0.0-20231005141211-4fc651f7ac8d/go.mod h1:cj9/QmD9N3OZnKQMp+/DvdV+ym3HyIkd4e+F0ZM3ZGs= github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728 h1:0eS+V7SXHgqoT99tV1mtMW6HL4HdoB9qGLMCb1fZp8A= github.com/aquasecurity/trivy-java-db v0.0.0-20230209231723-7cddb1406728/go.mod h1:Ldya37FLi0e/5Cjq2T5Bty7cFkzUDwTcPeQua+2M8i8= -github.com/aquasecurity/trivy-kubernetes v0.5.7 h1:+tIrSnIkvweL+cuK0SSiYxF8EvKT3Xk1iuE9EWduV+c= -github.com/aquasecurity/trivy-kubernetes v0.5.7/go.mod h1:e1RaMcs2R/C+eP1Pi7JyhDB7Qn1PNRg5rTVwuJL7AiE= +github.com/aquasecurity/trivy-kubernetes v0.5.8-0.20230928134646-b414e546fe6d h1:5urHj0NMGflp/M9Ll5QlKfo0Kf6nJ01RED1HRgl0CeE= +github.com/aquasecurity/trivy-kubernetes v0.5.8-0.20230928134646-b414e546fe6d/go.mod h1:e1RaMcs2R/C+eP1Pi7JyhDB7Qn1PNRg5rTVwuJL7AiE= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= diff --git a/integration/sbom_test.go b/integration/sbom_test.go index 6bdad20883f5..c195e23d43df 100644 --- a/integration/sbom_test.go +++ b/integration/sbom_test.go @@ -58,6 +58,15 @@ func TestSBOM(t *testing.T) { }, golden: "testdata/fluentd-multiple-lockfiles.json.golden", }, + { + name: "minikube KBOM", + args: args{ + input: "testdata/fixtures/sbom/minikube-kbom.json", + format: "json", + artifactType: "cyclonedx", + }, + golden: "testdata/minikube-kbom.json.golden", + }, { name: "centos7 in in-toto attestation", args: args{ diff --git a/integration/testdata/fixtures/db/data-source.yaml b/integration/testdata/fixtures/db/data-source.yaml index ca034600bd97..6a2570b1e977 100644 --- a/integration/testdata/fixtures/db/data-source.yaml +++ b/integration/testdata/fixtures/db/data-source.yaml @@ -144,3 +144,8 @@ ID: "cbl-mariner" Name: "CBL-Mariner Vulnerability Data" URL: "https://github.com/microsoft/CBL-MarinerVulnerabilityData" + - key: k8s::Official Kubernetes CVE Feed + value: + ID: "k8s" + Name: "Official Kubernetes CVE Feed" + URL: "https://kubernetes.io/docs/reference/issues-security/official-cve-feed/index.json" diff --git a/integration/testdata/fixtures/db/k8s.yaml b/integration/testdata/fixtures/db/k8s.yaml new file mode 100644 index 000000000000..4fa27ca07828 --- /dev/null +++ b/integration/testdata/fixtures/db/k8s.yaml @@ -0,0 +1,16 @@ +- bucket: "k8s::Official Kubernetes CVE Feed" + pairs: + - bucket: k8s.io/kubelet + pairs: + - key: CVE-2023-2431 + value: + PatchedVersions: + - 1.24.14 + - 1.25.9 + - 1.26.4 + - 1.27.1 + VulnerableVersions: + - "< 1.24.14" + - ">= 1.25.0, < 1.25.9" + - ">= 1.26.0, < 1.26.4" + - ">= 1.27.0, < 1.27.1" diff --git a/integration/testdata/fixtures/db/vulnerability.yaml b/integration/testdata/fixtures/db/vulnerability.yaml index 3165663ebf25..1cc7882214be 100644 --- a/integration/testdata/fixtures/db/vulnerability.yaml +++ b/integration/testdata/fixtures/db/vulnerability.yaml @@ -1037,6 +1037,20 @@ ghsa: 3.0 nvd: 3.0 redhat: 3.0 + - key: CVE-2023-2431 + value: + Title: "Bypass of seccomp profile enforcement " + Description: "A security issue was discovered in Kubelet that allows pods to bypass the seccomp profile enforcement..." + Severity: LOW + VendorSeverity: + k8s: 1 + CVSS: + k8s: + V3Vector: "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N" + V3Score: 3.4 + References: + - https://github.com/kubernetes/kubernetes/issues/118690 + - https://www.cve.org/cverecord?id=CVE-2023-2431 - key: CVE-2021-3712 value: CVSS: diff --git a/integration/testdata/fixtures/sbom/minikube-kbom.json b/integration/testdata/fixtures/sbom/minikube-kbom.json new file mode 100644 index 000000000000..e63c5733a816 --- /dev/null +++ b/integration/testdata/fixtures/sbom/minikube-kbom.json @@ -0,0 +1,434 @@ +{ + "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.5", + "serialNumber": "urn:uuid:e2daaea6-d96f-4b84-960c-0d72c348cd23", + "version": 1, + "metadata": { + "timestamp": "2023-09-29T06:25:00+00:00", + "tools": [ + { + "vendor": "aquasecurity", + "name": "trivy", + "version": "0.45.1-15-g7bbd0d097" + } + ], + "component": { + "bom-ref": "pkg:k8s/k8s.io%2Fkubernetes@1.27.0", + "type": "platform", + "name": "k8s.io/kubernetes", + "version": "1.27.0", + "purl": "pkg:k8s/k8s.io%2Fkubernetes@1.27.0", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "minikube" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "cluster" + } + ] + } + }, + "components": [ + { + "bom-ref": "5262e708-f1a3-4fca-a1c3-0a8384f7f4a5", + "type": "operating-system", + "name": "ubuntu", + "version": "22.04.2", + "properties": [ + { + "name": "aquasecurity:trivy:Class", + "value": "os-pkgs" + }, + { + "name": "aquasecurity:trivy:Type", + "value": "ubuntu" + } + ] + }, + { + "bom-ref": "a62abb1f-cb38-4fde-90f3-2bda3b87ddb2", + "type": "application", + "name": "node-core-components", + "properties": [ + { + "name": "aquasecurity:trivy:Class", + "value": "lang-pkgs" + }, + { + "name": "aquasecurity:trivy:Type", + "value": "golang" + } + ] + }, + { + "bom-ref": "a6350ac3-52f6-4c5f-a3e3-184b9a634bef", + "type": "platform", + "name": "minikube", + "properties": [ + { + "name": "aquasecurity:trivy:Architecture", + "value": "arm64" + }, + { + "name": "aquasecurity:trivy:HostName", + "value": "minikube" + }, + { + "name": "aquasecurity:trivy:KernelVersion", + "value": "5.15.49-linuxkit-pr" + }, + { + "name": "aquasecurity:trivy:NodeRole", + "value": "master" + }, + { + "name": "aquasecurity:trivy:OperatingSystem", + "value": "linux" + }, + { + "name": "aquasecurity:trivy:resource:Name", + "value": "minikube" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "node" + } + ] + }, + { + "bom-ref": "b19a88a3-017d-4e70-a73a-75f48696ec0f", + "type": "application", + "name": "kube-dns", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "coredns-5d78c9869d-nd92n" + } + ] + }, + { + "bom-ref": "b1c502c9-3c6e-43af-822b-1cb55c6c6ff3", + "type": "application", + "name": "go.etcd.io/etcd/v3", + "version": "3.5.7-0", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "etcd-minikube" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "controlPlane" + } + ] + }, + { + "bom-ref": "pkg:golang/docker@24.0.4", + "type": "application", + "name": "docker", + "version": "24.0.4", + "purl": "pkg:golang/docker@24.0.4", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "docker" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "node" + } + ] + }, + { + "bom-ref": "pkg:k8s/k8s.io%2Fapiserver@1.27.0", + "type": "application", + "name": "k8s.io/apiserver", + "version": "1.27.0", + "purl": "pkg:k8s/k8s.io%2Fapiserver@1.27.0", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "kube-apiserver-minikube" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "controlPlane" + } + ] + }, + { + "bom-ref": "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.0", + "type": "application", + "name": "k8s.io/controller-manager", + "version": "1.27.0", + "purl": "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.0", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "kube-controller-manager-minikube" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "controlPlane" + } + ] + }, + { + "bom-ref": "pkg:k8s/k8s.io%2Fkube-proxy@1.27.0", + "type": "application", + "name": "k8s.io/kube-proxy", + "version": "1.27.0", + "purl": "pkg:k8s/k8s.io%2Fkube-proxy@1.27.0", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "kube-proxy-4wftc" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "node" + } + ] + }, + { + "bom-ref": "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.0", + "type": "application", + "name": "k8s.io/kube-scheduler", + "version": "1.27.0", + "purl": "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.0", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "kube-scheduler-minikube" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "controlPlane" + } + ] + }, + { + "bom-ref": "pkg:k8s/k8s.io%2Fkubelet@1.27.0", + "type": "application", + "name": "k8s.io/kubelet", + "version": "1.27.0", + "purl": "pkg:k8s/k8s.io%2Fkubelet@1.27.0", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "k8s.io/kubelet" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "node" + } + ] + }, + { + "bom-ref": "pkg:oci/coredns@sha256%3Aa0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e?repository_url=registry.k8s.io%2Fcoredns%2Fcoredns", + "type": "container", + "name": "registry.k8s.io/coredns/coredns", + "version": "sha256:a0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e", + "purl": "pkg:oci/coredns@sha256%3Aa0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e?repository_url=registry.k8s.io%2Fcoredns%2Fcoredns", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "registry.k8s.io/coredns/coredns:1.10.1" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "oci" + } + ] + }, + { + "bom-ref": "pkg:oci/etcd@sha256%3A51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83?repository_url=registry.k8s.io%2Fetcd", + "type": "container", + "name": "registry.k8s.io/etcd", + "version": "sha256:51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83", + "purl": "pkg:oci/etcd@sha256%3A51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83?repository_url=registry.k8s.io%2Fetcd", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "registry.k8s.io/etcd:3.5.7-0" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "oci" + } + ] + }, + { + "bom-ref": "pkg:oci/kube-apiserver@sha256%3A697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d?repository_url=registry.k8s.io%2Fkube-apiserver", + "type": "container", + "name": "registry.k8s.io/kube-apiserver", + "version": "sha256:697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d", + "purl": "pkg:oci/kube-apiserver@sha256%3A697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d?repository_url=registry.k8s.io%2Fkube-apiserver", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "registry.k8s.io/kube-apiserver:1.27.0" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "oci" + } + ] + }, + { + "bom-ref": "pkg:oci/kube-controller-manager@sha256%3A6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265?repository_url=registry.k8s.io%2Fkube-controller-manager", + "type": "container", + "name": "registry.k8s.io/kube-controller-manager", + "version": "sha256:6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265", + "purl": "pkg:oci/kube-controller-manager@sha256%3A6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265?repository_url=registry.k8s.io%2Fkube-controller-manager", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "registry.k8s.io/kube-controller-manager:1.27.0" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "oci" + } + ] + }, + { + "bom-ref": "pkg:oci/kube-proxy@sha256%3A4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf?repository_url=registry.k8s.io%2Fkube-proxy", + "type": "container", + "name": "registry.k8s.io/kube-proxy", + "version": "sha256:4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf", + "purl": "pkg:oci/kube-proxy@sha256%3A4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf?repository_url=registry.k8s.io%2Fkube-proxy", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "registry.k8s.io/kube-proxy:1.27.0" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "oci" + } + ] + }, + { + "bom-ref": "pkg:oci/kube-scheduler@sha256%3A5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af?repository_url=registry.k8s.io%2Fkube-scheduler", + "type": "container", + "name": "registry.k8s.io/kube-scheduler", + "version": "sha256:5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af", + "purl": "pkg:oci/kube-scheduler@sha256%3A5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af?repository_url=registry.k8s.io%2Fkube-scheduler", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "registry.k8s.io/kube-scheduler:1.27.0" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "oci" + } + ] + } + ], + "dependencies": [ + { + "ref": "5262e708-f1a3-4fca-a1c3-0a8384f7f4a5", + "dependsOn": [] + }, + { + "ref": "a62abb1f-cb38-4fde-90f3-2bda3b87ddb2", + "dependsOn": [ + "pkg:golang/docker@24.0.4", + "pkg:k8s/k8s.io%2Fkubelet@1.27.0" + ] + }, + { + "ref": "a6350ac3-52f6-4c5f-a3e3-184b9a634bef", + "dependsOn": [ + "5262e708-f1a3-4fca-a1c3-0a8384f7f4a5", + "a62abb1f-cb38-4fde-90f3-2bda3b87ddb2" + ] + }, + { + "ref": "b19a88a3-017d-4e70-a73a-75f48696ec0f", + "dependsOn": [ + "pkg:oci/coredns@sha256%3Aa0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e?repository_url=registry.k8s.io%2Fcoredns%2Fcoredns" + ] + }, + { + "ref": "b1c502c9-3c6e-43af-822b-1cb55c6c6ff3", + "dependsOn": [ + "pkg:oci/etcd@sha256%3A51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83?repository_url=registry.k8s.io%2Fetcd" + ] + }, + { + "ref": "pkg:golang/docker@24.0.4", + "dependsOn": [] + }, + { + "ref": "pkg:k8s/k8s.io%2Fapiserver@1.27.0", + "dependsOn": [ + "pkg:oci/kube-apiserver@sha256%3A697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d?repository_url=registry.k8s.io%2Fkube-apiserver" + ] + }, + { + "ref": "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.0", + "dependsOn": [ + "pkg:oci/kube-controller-manager@sha256%3A6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265?repository_url=registry.k8s.io%2Fkube-controller-manager" + ] + }, + { + "ref": "pkg:k8s/k8s.io%2Fkube-proxy@1.27.0", + "dependsOn": [ + "pkg:oci/kube-proxy@sha256%3A4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf?repository_url=registry.k8s.io%2Fkube-proxy" + ] + }, + { + "ref": "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.0", + "dependsOn": [ + "pkg:oci/kube-scheduler@sha256%3A5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af?repository_url=registry.k8s.io%2Fkube-scheduler" + ] + }, + { + "ref": "pkg:k8s/k8s.io%2Fkubelet@1.27.0", + "dependsOn": [] + }, + { + "ref": "pkg:k8s/k8s.io%2Fkubernetes@1.27.0", + "dependsOn": [ + "a6350ac3-52f6-4c5f-a3e3-184b9a634bef", + "b19a88a3-017d-4e70-a73a-75f48696ec0f", + "b1c502c9-3c6e-43af-822b-1cb55c6c6ff3", + "pkg:k8s/k8s.io%2Fapiserver@1.27.0", + "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.0", + "pkg:k8s/k8s.io%2Fkube-proxy@1.27.0", + "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.0" + ] + }, + { + "ref": "pkg:oci/coredns@sha256%3Aa0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e?repository_url=registry.k8s.io%2Fcoredns%2Fcoredns", + "dependsOn": [] + }, + { + "ref": "pkg:oci/etcd@sha256%3A51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83?repository_url=registry.k8s.io%2Fetcd", + "dependsOn": [] + }, + { + "ref": "pkg:oci/kube-apiserver@sha256%3A697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d?repository_url=registry.k8s.io%2Fkube-apiserver", + "dependsOn": [] + }, + { + "ref": "pkg:oci/kube-controller-manager@sha256%3A6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265?repository_url=registry.k8s.io%2Fkube-controller-manager", + "dependsOn": [] + }, + { + "ref": "pkg:oci/kube-proxy@sha256%3A4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf?repository_url=registry.k8s.io%2Fkube-proxy", + "dependsOn": [] + }, + { + "ref": "pkg:oci/kube-scheduler@sha256%3A5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af?repository_url=registry.k8s.io%2Fkube-scheduler", + "dependsOn": [] + } + ], + "vulnerabilities": [] +} diff --git a/integration/testdata/minikube-kbom.json.golden b/integration/testdata/minikube-kbom.json.golden new file mode 100644 index 000000000000..267725173303 --- /dev/null +++ b/integration/testdata/minikube-kbom.json.golden @@ -0,0 +1,65 @@ +{ + "SchemaVersion": 2, + "ArtifactName": "testdata/fixtures/sbom/minikube-kbom.json", + "ArtifactType": "cyclonedx", + "Metadata": { + "OS": { + "Family": "ubuntu", + "Name": "22.04.2", + "EOSL": false + }, + "ImageConfig": { + "architecture": "", + "created": "0001-01-01T00:00:00Z", + "os": "", + "rootfs": { + "type": "", + "diff_ids": null + }, + "config": {} + } + }, + "Results": [ + { + "Target": "testdata/fixtures/sbom/minikube-kbom.json (ubuntu 22.04.2)", + "Class": "os-pkgs", + "Type": "ubuntu" + }, + { + "Target": "Kubernetes", + "Class": "lang-pkgs", + "Type": "kubernetes", + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2023-2431", + "PkgName": "k8s.io/kubelet", + "InstalledVersion": "1.27.0", + "FixedVersion": "1.24.14, 1.25.9, 1.26.4, 1.27.1", + "Status": "fixed", + "Layer": {}, + "SeveritySource": "k8s", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2023-2431", + "PkgRef": "pkg:k8s/k8s.io%2Fkubelet@1.27.0", + "DataSource": { + "ID": "k8s", + "Name": "Official Kubernetes CVE Feed", + "URL": "https://kubernetes.io/docs/reference/issues-security/official-cve-feed/index.json" + }, + "Title": "Bypass of seccomp profile enforcement ", + "Description": "A security issue was discovered in Kubelet that allows pods to bypass the seccomp profile enforcement...", + "Severity": "LOW", + "CVSS": { + "k8s": { + "V3Vector": "CVSS:3.1/AV:L/AC:L/PR:H/UI:N/S:U/C:L/I:L/A:N", + "V3Score": 3.4 + } + }, + "References": [ + "https://github.com/kubernetes/kubernetes/issues/118690", + "https://www.cve.org/cverecord?id=CVE-2023-2431" + ] + } + ] + } + ] +} diff --git a/pkg/detector/library/driver.go b/pkg/detector/library/driver.go index c75c22caf678..bea534ba0727 100644 --- a/pkg/detector/library/driver.go +++ b/pkg/detector/library/driver.go @@ -65,9 +65,6 @@ func NewDriver(libType ftypes.LangType) (Driver, bool) { // https://www.swift.org/package-manager/#importing-dependencies ecosystem = vulnerability.Swift comparer = compare.GenericComparer{} - case ftypes.Bitnami: - ecosystem = vulnerability.Bitnami - comparer = compare.GenericComparer{} case ftypes.Cocoapods: // CocoaPods uses RubyGems version specifiers // https://guides.cocoapods.org/making/making-a-cocoapod.html#cocoapods-versioning-specifics @@ -76,6 +73,12 @@ func NewDriver(libType ftypes.LangType) (Driver, bool) { case ftypes.CondaPkg: log.Logger.Warn("Conda package is supported for SBOM, not for vulnerability scanning") return Driver{}, false + case ftypes.Bitnami: + ecosystem = vulnerability.Bitnami + comparer = compare.GenericComparer{} + case ftypes.K8sUpstream: + ecosystem = vulnerability.Kubernetes + comparer = compare.GenericComparer{} default: log.Logger.Warnf("The %q library type is not supported for vulnerability scanning", libType) return Driver{}, false diff --git a/pkg/fanal/types/const.go b/pkg/fanal/types/const.go index e36fa92c57d9..28e11d55beb9 100644 --- a/pkg/fanal/types/const.go +++ b/pkg/fanal/types/const.go @@ -71,6 +71,13 @@ const ( Pub LangType = "pub" Hex LangType = "hex" Bitnami LangType = "bitnami" + + K8sUpstream LangType = "kubernetes" + EKS LangType = "eks" // Amazon Elastic Kubernetes Service + GKE LangType = "gke" // Google Kubernetes Engine + AKS LangType = "aks" // Azure Kubernetes Service + RKE LangType = "rke" // Rancher Kubernetes Engine + OCP LangType = "ocp" // Red Hat OpenShift Container Platform ) // Config files diff --git a/pkg/k8s/scanner/scanner.go b/pkg/k8s/scanner/scanner.go index 30796af2d48f..e4676665aeaf 100644 --- a/pkg/k8s/scanner/scanner.go +++ b/pkg/k8s/scanner/scanner.go @@ -208,6 +208,17 @@ const ( func clusterInfoToReportResources(allArtifact []*artifacts.Artifact) (*core.Component, error) { var coreComponents []*core.Component var cInfo *core.Component + + // Find the first node name to identify AKS cluster + var nodeName string + for _, artifact := range allArtifact { + if artifact.Kind != nodeInfo { + continue + } + nodeName = artifact.Name + break + } + for _, artifact := range allArtifact { switch artifact.Kind { case pod: @@ -257,6 +268,7 @@ func clusterInfoToReportResources(allArtifact []*artifacts.Artifact) (*core.Comp Type: cdx.ComponentTypeApplication, Properties: toProperties(comp.Properties, k8sCoreComponentNamespace), Components: imageComponents, + PackageURL: generatePURL(comp.Name, comp.Version, nodeName), } coreComponents = append(coreComponents, rootComponent) case nodeInfo: @@ -287,6 +299,7 @@ func clusterInfoToReportResources(allArtifact []*artifacts.Artifact) (*core.Comp Type: cdx.ComponentTypePlatform, Properties: cInfo.Properties, Components: coreComponents, + PackageURL: generatePURL(cInfo.Name, cInfo.Version, nodeName), } return rootComponent, nil } @@ -313,20 +326,20 @@ func osNameVersion(name string) (string, string) { } func runtimeNameVersion(name string) (string, string) { - parts := strings.Split(name, "://") - if len(parts) == 2 { - name := parts[0] - switch parts[0] { - case "cri-o": - name = "github.com/cri-o/cri-o" - case "containerd": - name = "github.com/containerd/containerd" - case "cri-dockerd": - name = "github.com/Mirantis/cri-dockerd" - } - return name, parts[1] + runtime, ver, ok := strings.Cut(name, "://") + if !ok { + return "", "" } - return "", "" + + switch runtime { + case "cri-o": + name = "github.com/cri-o/cri-o" + case "containerd": + name = "github.com/containerd/containerd" + case "cri-dockerd": + name = "github.com/Mirantis/cri-dockerd" + } + return name, ver } func nodeComponent(nf bom.NodeInfo) *core.Component { @@ -388,9 +401,7 @@ func nodeComponent(nf bom.NodeInfo) *core.Component { Namespace: k8sCoreComponentNamespace, }, }, - PackageURL: &purl.PackageURL{ - PackageURL: *packageurl.NewPackageURL(golang, "", kubelet, kubeletVersion, packageurl.Qualifiers{}, ""), - }, + PackageURL: generatePURL(kubelet, kubeletVersion, nf.NodeName), }, { Type: cdx.ComponentTypeApplication, @@ -431,3 +442,27 @@ func toProperties(props map[string]string, namespace string) []core.Property { }) return properties } + +func generatePURL(name, ver, nodeName string) *purl.PackageURL { + // Identify k8s distribution. An empty namespace means upstream. + var namespace string + switch { + case strings.Contains(ver, "eks"): + namespace = purl.NamespaceEKS + case strings.Contains(ver, "gke"): + namespace = purl.NamespaceGKE + case strings.Contains(ver, "rke2"): + namespace = purl.NamespaceRKE + case strings.Contains(ver, "hotfix"): + if !strings.Contains(nodeName, "aks") { + // Unknown k8s distribution + return nil + } + namespace = purl.NamespaceAKS + case strings.Contains(nodeName, "ocp"): + namespace = purl.NamespaceOCP + } + return &purl.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 bee414223ddd..7a7253a3c24b 100644 --- a/pkg/k8s/scanner/scanner_test.go +++ b/pkg/k8s/scanner/scanner_test.go @@ -17,7 +17,7 @@ import ( "github.com/aquasecurity/trivy/pkg/sbom/cyclonedx/core" ) -func TestK8sClusterInfoReport(t *testing.T) { +func TestScanner_Scan(t *testing.T) { flagOpts := flag.Options{ReportOptions: flag.ReportOptions{Format: "cyclonedx"}} tests := []struct { name string @@ -34,31 +34,31 @@ func TestK8sClusterInfoReport(t *testing.T) { Kind: "ClusterInfo", Name: "k8s.io/kubernetes", RawResource: map[string]interface{}{ + "name": "k8s.io/kubernetes", + "version": "1.21.1", + "type": "ClusterInfo", "Properties": map[string]string{ - "Name": "kube-cluster", + "Name": "kind-kind", + "Type": "cluster", }, - "Name": "kube-apiserver-kind-control-plane", - "Version": "1.21.1", }, }, { Namespace: "kube-system", Kind: "PodInfo", - Name: "kube-apiserver-kind-control-plane", + Name: "k8s.io/apiserver", RawResource: map[string]interface{}{ - "Containers": []interface{}{map[string]interface{}{ - "Digest": "18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f", - "ID": "kube-apiserver:v1.21.1", - "Registry": "k8s.gcr.io", - "Repository": "kube-apiserver", - "Version": "v1.21.1", - }, - }, - "Properties": map[string]string{ - "ControlPlaneComponents": "kube-apiserver", + "Containers": []interface{}{ + map[string]interface{}{ + "Digest": "18e61c783b41758dd391ab901366ec3546b26fae00eef7e223d1f94da808e02f", + "ID": "kube-apiserver:v1.21.1", + "Registry": "k8s.gcr.io", + "Repository": "kube-apiserver", + "Version": "v1.21.1", + }, }, - "Name": "kube-apiserver-kind-control-plane", - "Namespace": "kube-system", + "Name": "k8s.io/apiserver", + "Version": "1.21.1", }, }, { @@ -83,18 +83,40 @@ func TestK8sClusterInfoReport(t *testing.T) { }, want: &core.Component{ Type: cdx.ComponentTypePlatform, - Name: "kube-apiserver-kind-control-plane", + Name: "k8s.io/kubernetes", Version: "1.21.1", Properties: []core.Property{ - {Name: "Name", Value: "kube-cluster", Namespace: k8sCoreComponentNamespace}, + { + Name: "Name", + Value: "kind-kind", + Namespace: k8sCoreComponentNamespace, + }, + { + Name: "Type", + Value: "cluster", + Namespace: k8sCoreComponentNamespace, + }, + }, + PackageURL: &purl.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: purl.TypeK8s, + Name: "k8s.io/kubernetes", + Version: "1.21.1", + }, }, Components: []*core.Component{ { - Type: cdx.ComponentTypeApplication, - Name: "kube-apiserver-kind-control-plane", - Properties: []core.Property{ - {Name: "ControlPlaneComponents", Value: "kube-apiserver", Namespace: k8sCoreComponentNamespace}, + Type: cdx.ComponentTypeApplication, + Name: "k8s.io/apiserver", + Version: "1.21.1", + PackageURL: &purl.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: purl.TypeK8s, + Name: "k8s.io/apiserver", + Version: "1.21.1", + }, }, + Properties: []core.Property{}, Components: []*core.Component{ { Type: cdx.ComponentTypeContainer, @@ -110,15 +132,18 @@ func TestK8sClusterInfoReport(t *testing.T) { Key: "repository_url", Value: "k8s.gcr.io/kube-apiserver", }, - { - Key: "arch", - }, }, }, }, Properties: []core.Property{ - {Name: cyc.PropertyPkgID, Value: "k8s.gcr.io/kube-apiserver:1.21.1"}, - {Name: cyc.PropertyPkgType, Value: "oci"}, + { + Name: cyc.PropertyPkgID, + Value: "k8s.gcr.io/kube-apiserver:1.21.1", + }, + { + Name: cyc.PropertyPkgType, + Value: "oci", + }, }, }, }, @@ -127,13 +152,36 @@ func TestK8sClusterInfoReport(t *testing.T) { Type: cdx.ComponentTypePlatform, Name: "kind-control-plane", Properties: []core.Property{ - {Name: "Architecture", Value: "arm64"}, - {Name: "HostName", Value: "kind-control-plane"}, - {Name: "KernelVersion", Value: "6.2.15-300.fc38.aarch64"}, - {Name: "NodeRole", Value: "master"}, - {Name: "OperatingSystem", Value: "linux"}, - {Name: k8sComponentName, Value: "kind-control-plane", Namespace: k8sCoreComponentNamespace}, - {Name: k8sComponentType, Value: "node", Namespace: k8sCoreComponentNamespace}, + { + Name: "Architecture", + Value: "arm64", + }, + { + Name: "HostName", + Value: "kind-control-plane", + }, + { + Name: "KernelVersion", + Value: "6.2.15-300.fc38.aarch64", + }, + { + Name: "NodeRole", + Value: "master", + }, + { + Name: "OperatingSystem", + Value: "linux", + }, + { + Name: k8sComponentName, + Value: "kind-control-plane", + Namespace: k8sCoreComponentNamespace, + }, + { + Name: k8sComponentType, + Value: "node", + Namespace: k8sCoreComponentNamespace, + }, }, Components: []*core.Component{ { @@ -141,16 +189,32 @@ func TestK8sClusterInfoReport(t *testing.T) { Name: "ubuntu", Version: "21.04", Properties: []core.Property{ - {Name: "Class", Value: "os-pkgs", Namespace: ""}, - {Name: "Type", Value: "ubuntu", Namespace: ""}, + { + Name: "Class", + Value: "os-pkgs", + Namespace: "", + }, + { + Name: "Type", + Value: "ubuntu", + Namespace: "", + }, }, }, { Type: cdx.ComponentTypeApplication, Name: "node-core-components", Properties: []core.Property{ - {Name: "Class", Value: "lang-pkgs", Namespace: ""}, - {Name: "Type", Value: "golang", Namespace: ""}, + { + Name: "Class", + Value: "lang-pkgs", + Namespace: "", + }, + { + Name: "Type", + Value: "golang", + Namespace: "", + }, }, Components: []*core.Component{ { @@ -158,15 +222,22 @@ func TestK8sClusterInfoReport(t *testing.T) { Name: "k8s.io/kubelet", Version: "1.21.1", Properties: []core.Property{ - {Name: k8sComponentType, Value: "node", Namespace: k8sCoreComponentNamespace}, - {Name: k8sComponentName, Value: "k8s.io/kubelet", Namespace: k8sCoreComponentNamespace}, + { + Name: k8sComponentType, + Value: "node", + Namespace: k8sCoreComponentNamespace, + }, + { + Name: k8sComponentName, + Value: "k8s.io/kubelet", + Namespace: k8sCoreComponentNamespace, + }, }, PackageURL: &purl.PackageURL{ PackageURL: packageurl.PackageURL{ - Type: "golang", - Name: "k8s.io/kubelet", - Version: "1.21.1", - Qualifiers: packageurl.Qualifiers{}, + Type: "k8s", + Name: "k8s.io/kubelet", + Version: "1.21.1", }, }, }, @@ -175,8 +246,16 @@ func TestK8sClusterInfoReport(t *testing.T) { Name: "github.com/containerd/containerd", Version: "1.5.2", Properties: []core.Property{ - {Name: k8sComponentType, Value: "node", Namespace: k8sCoreComponentNamespace}, - {Name: k8sComponentName, Value: "github.com/containerd/containerd", Namespace: k8sCoreComponentNamespace}, + { + Name: k8sComponentType, + Value: "node", + Namespace: k8sCoreComponentNamespace, + }, + { + Name: k8sComponentName, + Value: "github.com/containerd/containerd", + Namespace: k8sCoreComponentNamespace, + }, }, PackageURL: &purl.PackageURL{ PackageURL: packageurl.PackageURL{ @@ -262,3 +341,63 @@ func TestTestOsNameVersion(t *testing.T) { }) } } + +func TestGeneratePURL(t *testing.T) { + tests := []struct { + name string + compName string + compVersion string + nodeName string + want string + }{ + { + name: "native k8s component", + compName: "k8s.io/kubelet", + compVersion: "1.24.10", + nodeName: "kind-kind", + want: "pkg:k8s/k8s.io%2Fkubelet@1.24.10", + }, + + { + name: "GKE", + compName: "k8s.io/kubelet", + compVersion: "1.24.10-gke.2300", + nodeName: "gke-gke1796-default-pool-768cb718-sk1d", + want: "pkg:k8s/gke/k8s.io%2Fkubelet@1.24.10-gke.2300", + }, + { + name: "AKS", + compName: "k8s.io/kubelet", + compVersion: "1.24.10-hotfix.20221110", + nodeName: "aks-default-23814474-vmss000000", + want: "pkg:k8s/aks/k8s.io%2Fkubelet@1.24.10-hotfix.20221110", + }, + { + name: "EKS", + compName: "k8s.io/kubelet", + compVersion: "1.23.17-eks-8ccc7ba", + nodeName: "eks-vmss000000", + want: "pkg:k8s/eks/k8s.io%2Fkubelet@1.23.17-eks-8ccc7ba", + }, + { + name: "Rancher", + compName: "k8s.io/kubelet", + compVersion: "1.24.11+rke2r1", + nodeName: "ip-10-0-5-23", + want: "pkg:k8s/rke/k8s.io%2Fkubelet@1.24.11%2Brke2r1", + }, + { + name: "OCP", + compName: "k8s.io/kubelet", + compVersion: "1.26.7+c7ee51f", + nodeName: "ocp413vpool14000-p8vnm-master-2", + want: "pkg:k8s/ocp/k8s.io%2Fkubelet@1.26.7%2Bc7ee51f", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := generatePURL(tt.compName, tt.compVersion, tt.nodeName) + assert.Equal(t, tt.want, got.String()) + }) + } +} diff --git a/pkg/purl/purl.go b/pkg/purl/purl.go index cb5bfeb8c2d4..a7bbbbfef6b3 100644 --- a/pkg/purl/purl.go +++ b/pkg/purl/purl.go @@ -18,6 +18,30 @@ import ( const ( TypeOCI = "oci" TypeDart = "dart" + + // TypeK8s is a custom type for Kubernetes components in PURL. + // - namespace: The service provider such as EKS or GKE. It is not case sensitive and must be lowercased. + // Known namespaces: + // - empty (upstream) + // - eks (AWS) + // - aks (GCP) + // - gke (Azure) + // - rke (Rancher) + // - name: The k8s component name and is case sensitive. + // - version: The combined version and release of a component. + // + // Examples: + // - pkg:k8s/upstream/k8s.io%2Fapiserver@1.24.1 + // - pkg:k8s/eks/k8s.io%2Fkube-proxy@1.26.2-eksbuild.1 + TypeK8s = "k8s" + + NamespaceEKS = "eks" + NamespaceAKS = "aks" + NamespaceGKE = "gke" + NamespaceRKE = "rke" + NamespaceOCP = "ocp" + + TypeUnknown = "unknown" ) type PackageURL struct { @@ -71,7 +95,7 @@ func (p *PackageURL) Package() *ftypes.Package { // Return packages without namespace. // OS packages are not supposed to have namespace. - if p.Namespace == "" || p.IsOSPkg() { + if p.Namespace == "" || p.Class() == types.ClassOSPkg { return pkg } @@ -88,6 +112,7 @@ func (p *PackageURL) Package() *ftypes.Package { } // LangType returns an application type in Trivy +// nolint: gocyclo func (p *PackageURL) LangType() ftypes.LangType { switch p.Type { case packageurl.TypeComposer: @@ -120,12 +145,39 @@ func (p *PackageURL) LangType() ftypes.LangType { return ftypes.Pub case packageurl.TypeBitnami: return ftypes.Bitnami + case TypeK8s: + switch p.Namespace { + case NamespaceEKS: + return ftypes.EKS + case NamespaceGKE: + return ftypes.GKE + case NamespaceAKS: + return ftypes.AKS + case NamespaceRKE: + return ftypes.RKE + case NamespaceOCP: + return ftypes.OCP + case "": + return ftypes.K8sUpstream + } + return TypeUnknown + default: + return TypeUnknown } - return "unknown" } -func (p *PackageURL) IsOSPkg() bool { - return p.Type == packageurl.TypeApk || p.Type == packageurl.TypeDebian || p.Type == packageurl.TypeRPM +func (p *PackageURL) Class() types.ResultClass { + switch p.Type { + case packageurl.TypeApk, packageurl.TypeDebian, packageurl.TypeRPM: + // OS packages + return types.ClassOSPkg + default: + if p.LangType() == TypeUnknown { + return types.ClassUnknown + } + // Language-specific packages + return types.ClassLangPkg + } } func (p *PackageURL) BOMRef() string { @@ -221,15 +273,19 @@ func parseOCI(metadata types.Metadata) (packageurl.PackageURL, error) { if index != -1 { name = name[index+1:] } - qualifiers := packageurl.Qualifiers{ - packageurl.Qualifier{ + + var qualifiers packageurl.Qualifiers + if repoURL := digest.Repository.Name(); repoURL != "" { + qualifiers = append(qualifiers, packageurl.Qualifier{ Key: "repository_url", - Value: digest.Repository.Name(), - }, - packageurl.Qualifier{ + Value: repoURL, + }) + } + if arch := metadata.ImageConfig.Architecture; arch != "" { + qualifiers = append(qualifiers, packageurl.Qualifier{ Key: "arch", Value: metadata.ImageConfig.Architecture, - }, + }) } return *packageurl.NewPackageURL(packageurl.TypeOCI, "", name, digest.DigestStr(), qualifiers, ""), nil diff --git a/pkg/purl/purl_test.go b/pkg/purl/purl_test.go index 4cdb3f7a2a60..dfb3bf841b28 100644 --- a/pkg/purl/purl_test.go +++ b/pkg/purl/purl_test.go @@ -717,3 +717,47 @@ func TestPackage(t *testing.T) { }) } } + +func TestPackageURL_LangType(t *testing.T) { + tests := []struct { + name string + purl packageurl.PackageURL + want ftypes.LangType + }{ + { + name: "maven", + purl: packageurl.PackageURL{ + Type: packageurl.TypeMaven, + Namespace: "org.springframework", + Name: "spring-core", + Version: "5.0.4.RELEASE", + }, + want: ftypes.Jar, + }, + { + name: "k8s", + purl: packageurl.PackageURL{ + Type: purl.TypeK8s, + Name: "kubelet", + Version: "1.21.1", + }, + want: ftypes.K8sUpstream, + }, + { + name: "eks", + purl: packageurl.PackageURL{ + Type: purl.TypeK8s, + Namespace: purl.NamespaceEKS, + Name: "kubelet", + Version: "1.21.1", + }, + want: ftypes.EKS, + }, + } + 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()") + }) + } +} diff --git a/pkg/sbom/cyclonedx/testdata/happy/kbom.json b/pkg/sbom/cyclonedx/testdata/happy/kbom.json new file mode 100644 index 000000000000..a843dbdfd212 --- /dev/null +++ b/pkg/sbom/cyclonedx/testdata/happy/kbom.json @@ -0,0 +1,434 @@ +{ + "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.5", + "serialNumber": "urn:uuid:e2daaea6-d96f-4b84-960c-0d72c348cd23", + "version": 1, + "metadata": { + "timestamp": "2023-09-29T06:25:00+00:00", + "tools": [ + { + "vendor": "aquasecurity", + "name": "trivy", + "version": "0.45.1-15-g7bbd0d097" + } + ], + "component": { + "bom-ref": "pkg:k8s/k8s.io%2Fkubernetes@1.27.4", + "type": "platform", + "name": "k8s.io/kubernetes", + "version": "1.27.4", + "purl": "pkg:k8s/k8s.io%2Fkubernetes@1.27.4", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "minikube" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "cluster" + } + ] + } + }, + "components": [ + { + "bom-ref": "5262e708-f1a3-4fca-a1c3-0a8384f7f4a5", + "type": "operating-system", + "name": "ubuntu", + "version": "22.04.2", + "properties": [ + { + "name": "aquasecurity:trivy:Class", + "value": "os-pkgs" + }, + { + "name": "aquasecurity:trivy:Type", + "value": "ubuntu" + } + ] + }, + { + "bom-ref": "a62abb1f-cb38-4fde-90f3-2bda3b87ddb2", + "type": "application", + "name": "node-core-components", + "properties": [ + { + "name": "aquasecurity:trivy:Class", + "value": "lang-pkgs" + }, + { + "name": "aquasecurity:trivy:Type", + "value": "golang" + } + ] + }, + { + "bom-ref": "a6350ac3-52f6-4c5f-a3e3-184b9a634bef", + "type": "platform", + "name": "minikube", + "properties": [ + { + "name": "aquasecurity:trivy:Architecture", + "value": "arm64" + }, + { + "name": "aquasecurity:trivy:HostName", + "value": "minikube" + }, + { + "name": "aquasecurity:trivy:KernelVersion", + "value": "5.15.49-linuxkit-pr" + }, + { + "name": "aquasecurity:trivy:NodeRole", + "value": "master" + }, + { + "name": "aquasecurity:trivy:OperatingSystem", + "value": "linux" + }, + { + "name": "aquasecurity:trivy:resource:Name", + "value": "minikube" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "node" + } + ] + }, + { + "bom-ref": "b19a88a3-017d-4e70-a73a-75f48696ec0f", + "type": "application", + "name": "kube-dns", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "coredns-5d78c9869d-nd92n" + } + ] + }, + { + "bom-ref": "b1c502c9-3c6e-43af-822b-1cb55c6c6ff3", + "type": "application", + "name": "go.etcd.io/etcd/v3", + "version": "3.5.7-0", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "etcd-minikube" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "controlPlane" + } + ] + }, + { + "bom-ref": "pkg:golang/docker@24.0.4", + "type": "application", + "name": "docker", + "version": "24.0.4", + "purl": "pkg:golang/docker@24.0.4", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "docker" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "node" + } + ] + }, + { + "bom-ref": "pkg:k8s/k8s.io%2Fapiserver@1.27.4", + "type": "application", + "name": "k8s.io/apiserver", + "version": "1.27.4", + "purl": "pkg:k8s/k8s.io%2Fapiserver@1.27.4", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "kube-apiserver-minikube" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "controlPlane" + } + ] + }, + { + "bom-ref": "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.4", + "type": "application", + "name": "k8s.io/controller-manager", + "version": "1.27.4", + "purl": "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.4", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "kube-controller-manager-minikube" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "controlPlane" + } + ] + }, + { + "bom-ref": "pkg:k8s/k8s.io%2Fkube-proxy@1.27.4", + "type": "application", + "name": "k8s.io/kube-proxy", + "version": "1.27.4", + "purl": "pkg:k8s/k8s.io%2Fkube-proxy@1.27.4", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "kube-proxy-4wftc" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "node" + } + ] + }, + { + "bom-ref": "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.4", + "type": "application", + "name": "k8s.io/kube-scheduler", + "version": "1.27.4", + "purl": "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.4", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "kube-scheduler-minikube" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "controlPlane" + } + ] + }, + { + "bom-ref": "pkg:k8s/k8s.io%2Fkubelet@1.27.4", + "type": "application", + "name": "k8s.io/kubelet", + "version": "1.27.4", + "purl": "pkg:k8s/k8s.io%2Fkubelet@1.27.4", + "properties": [ + { + "name": "aquasecurity:trivy:resource:Name", + "value": "k8s.io/kubelet" + }, + { + "name": "aquasecurity:trivy:resource:Type", + "value": "node" + } + ] + }, + { + "bom-ref": "pkg:oci/coredns@sha256%3Aa0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e?repository_url=registry.k8s.io%2Fcoredns%2Fcoredns", + "type": "container", + "name": "registry.k8s.io/coredns/coredns", + "version": "sha256:a0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e", + "purl": "pkg:oci/coredns@sha256%3Aa0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e?repository_url=registry.k8s.io%2Fcoredns%2Fcoredns", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "registry.k8s.io/coredns/coredns:1.10.1" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "oci" + } + ] + }, + { + "bom-ref": "pkg:oci/etcd@sha256%3A51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83?repository_url=registry.k8s.io%2Fetcd", + "type": "container", + "name": "registry.k8s.io/etcd", + "version": "sha256:51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83", + "purl": "pkg:oci/etcd@sha256%3A51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83?repository_url=registry.k8s.io%2Fetcd", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "registry.k8s.io/etcd:3.5.7-0" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "oci" + } + ] + }, + { + "bom-ref": "pkg:oci/kube-apiserver@sha256%3A697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d?repository_url=registry.k8s.io%2Fkube-apiserver", + "type": "container", + "name": "registry.k8s.io/kube-apiserver", + "version": "sha256:697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d", + "purl": "pkg:oci/kube-apiserver@sha256%3A697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d?repository_url=registry.k8s.io%2Fkube-apiserver", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "registry.k8s.io/kube-apiserver:1.27.4" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "oci" + } + ] + }, + { + "bom-ref": "pkg:oci/kube-controller-manager@sha256%3A6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265?repository_url=registry.k8s.io%2Fkube-controller-manager", + "type": "container", + "name": "registry.k8s.io/kube-controller-manager", + "version": "sha256:6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265", + "purl": "pkg:oci/kube-controller-manager@sha256%3A6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265?repository_url=registry.k8s.io%2Fkube-controller-manager", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "registry.k8s.io/kube-controller-manager:1.27.4" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "oci" + } + ] + }, + { + "bom-ref": "pkg:oci/kube-proxy@sha256%3A4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf?repository_url=registry.k8s.io%2Fkube-proxy", + "type": "container", + "name": "registry.k8s.io/kube-proxy", + "version": "sha256:4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf", + "purl": "pkg:oci/kube-proxy@sha256%3A4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf?repository_url=registry.k8s.io%2Fkube-proxy", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "registry.k8s.io/kube-proxy:1.27.4" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "oci" + } + ] + }, + { + "bom-ref": "pkg:oci/kube-scheduler@sha256%3A5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af?repository_url=registry.k8s.io%2Fkube-scheduler", + "type": "container", + "name": "registry.k8s.io/kube-scheduler", + "version": "sha256:5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af", + "purl": "pkg:oci/kube-scheduler@sha256%3A5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af?repository_url=registry.k8s.io%2Fkube-scheduler", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "registry.k8s.io/kube-scheduler:1.27.4" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "oci" + } + ] + } + ], + "dependencies": [ + { + "ref": "5262e708-f1a3-4fca-a1c3-0a8384f7f4a5", + "dependsOn": [] + }, + { + "ref": "a62abb1f-cb38-4fde-90f3-2bda3b87ddb2", + "dependsOn": [ + "pkg:golang/docker@24.0.4", + "pkg:k8s/k8s.io%2Fkubelet@1.27.4" + ] + }, + { + "ref": "a6350ac3-52f6-4c5f-a3e3-184b9a634bef", + "dependsOn": [ + "5262e708-f1a3-4fca-a1c3-0a8384f7f4a5", + "a62abb1f-cb38-4fde-90f3-2bda3b87ddb2" + ] + }, + { + "ref": "b19a88a3-017d-4e70-a73a-75f48696ec0f", + "dependsOn": [ + "pkg:oci/coredns@sha256%3Aa0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e?repository_url=registry.k8s.io%2Fcoredns%2Fcoredns" + ] + }, + { + "ref": "b1c502c9-3c6e-43af-822b-1cb55c6c6ff3", + "dependsOn": [ + "pkg:oci/etcd@sha256%3A51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83?repository_url=registry.k8s.io%2Fetcd" + ] + }, + { + "ref": "pkg:golang/docker@24.0.4", + "dependsOn": [] + }, + { + "ref": "pkg:k8s/k8s.io%2Fapiserver@1.27.4", + "dependsOn": [ + "pkg:oci/kube-apiserver@sha256%3A697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d?repository_url=registry.k8s.io%2Fkube-apiserver" + ] + }, + { + "ref": "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.4", + "dependsOn": [ + "pkg:oci/kube-controller-manager@sha256%3A6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265?repository_url=registry.k8s.io%2Fkube-controller-manager" + ] + }, + { + "ref": "pkg:k8s/k8s.io%2Fkube-proxy@1.27.4", + "dependsOn": [ + "pkg:oci/kube-proxy@sha256%3A4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf?repository_url=registry.k8s.io%2Fkube-proxy" + ] + }, + { + "ref": "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.4", + "dependsOn": [ + "pkg:oci/kube-scheduler@sha256%3A5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af?repository_url=registry.k8s.io%2Fkube-scheduler" + ] + }, + { + "ref": "pkg:k8s/k8s.io%2Fkubelet@1.27.4", + "dependsOn": [] + }, + { + "ref": "pkg:k8s/k8s.io%2Fkubernetes@1.27.4", + "dependsOn": [ + "a6350ac3-52f6-4c5f-a3e3-184b9a634bef", + "b19a88a3-017d-4e70-a73a-75f48696ec0f", + "b1c502c9-3c6e-43af-822b-1cb55c6c6ff3", + "pkg:k8s/k8s.io%2Fapiserver@1.27.4", + "pkg:k8s/k8s.io%2Fcontroller-manager@1.27.4", + "pkg:k8s/k8s.io%2Fkube-proxy@1.27.4", + "pkg:k8s/k8s.io%2Fkube-scheduler@1.27.4" + ] + }, + { + "ref": "pkg:oci/coredns@sha256%3Aa0ead06651cf580044aeb0a0feba63591858fb2e43ade8c9dea45a6a89ae7e5e?repository_url=registry.k8s.io%2Fcoredns%2Fcoredns", + "dependsOn": [] + }, + { + "ref": "pkg:oci/etcd@sha256%3A51eae8381dcb1078289fa7b4f3df2630cdc18d09fb56f8e56b41c40e191d6c83?repository_url=registry.k8s.io%2Fetcd", + "dependsOn": [] + }, + { + "ref": "pkg:oci/kube-apiserver@sha256%3A697cd88d94f7f2ef42144cb3072b016dcb2e9251f0e7d41a7fede557e555452d?repository_url=registry.k8s.io%2Fkube-apiserver", + "dependsOn": [] + }, + { + "ref": "pkg:oci/kube-controller-manager@sha256%3A6286e500782ad6d0b37a1b8be57fc73f597dc931dfc73ff18ce534059803b265?repository_url=registry.k8s.io%2Fkube-controller-manager", + "dependsOn": [] + }, + { + "ref": "pkg:oci/kube-proxy@sha256%3A4bcb707da9898d2625f5d4edc6d0c96519a24f16db914fc673aa8f97e41dbabf?repository_url=registry.k8s.io%2Fkube-proxy", + "dependsOn": [] + }, + { + "ref": "pkg:oci/kube-scheduler@sha256%3A5897d7a97d23dce25cbf36fcd6e919180a8ef904bf5156583ffdb6a733ab04af?repository_url=registry.k8s.io%2Fkube-scheduler", + "dependsOn": [] + } + ], + "vulnerabilities": [] +} diff --git a/pkg/sbom/cyclonedx/unmarshal.go b/pkg/sbom/cyclonedx/unmarshal.go index d8837980bd0b..8282edae2c3f 100644 --- a/pkg/sbom/cyclonedx/unmarshal.go +++ b/pkg/sbom/cyclonedx/unmarshal.go @@ -128,7 +128,7 @@ func (c *BOM) parseSBOM(bom *cdx.BOM) error { if _, ok := seen[ref]; ok { continue } - if component.Type == cdx.ComponentTypeLibrary { + if component.Type == cdx.ComponentTypeLibrary || component.PackageURL != "" { libComponents = append(libComponents, component) } @@ -194,13 +194,17 @@ func parsePkgs(components []cdx.Component, seen map[string]struct{}) ([]ftypes.P var pkgs []ftypes.Package for _, com := range components { seen[com.BOMRef] = struct{}{} - _, _, pkg, err := toPackage(com) - if err != nil { - if errors.Is(err, ErrPURLEmpty) { - continue - } + pkgURL, pkg, err := toPackage(com) + if errors.Is(err, ErrPURLEmpty) { + continue + } else if err != nil { return nil, xerrors.Errorf("failed to parse language package: %w", err) } + + // Skip unsupported package types + if pkgURL.Class() == types.ClassUnknown { + continue + } pkgs = append(pkgs, *pkg) } return pkgs, nil @@ -276,21 +280,22 @@ func dependencyMap(deps *[]cdx.Dependency) map[string][]string { } func aggregatePkgs(libs []cdx.Component) ([]ftypes.PackageInfo, []ftypes.Application, error) { - osPkgMap := make(map[ftypes.OSType]ftypes.Packages) + osPkgMap := make(map[string]ftypes.Packages) langPkgMap := make(map[ftypes.LangType]ftypes.Packages) for _, lib := range libs { - isOSPkg, pkgType, pkg, err := toPackage(lib) - if err != nil { - if errors.Is(err, ErrPURLEmpty) { - continue - } + pkgURL, pkg, err := toPackage(lib) + if errors.Is(err, ErrPURLEmpty) { + continue + } else if err != nil { return nil, nil, xerrors.Errorf("failed to parse the component: %w", err) } - if isOSPkg { - osPkgMap[pkgType] = append(osPkgMap[pkgType], *pkg) - } else { - langPkgMap[pkgType] = append(langPkgMap[pkgType], *pkg) + switch pkgURL.Class() { + case types.ClassOSPkg: + osPkgMap[pkgURL.Type] = append(osPkgMap[pkgURL.Type], *pkg) + case types.ClassLangPkg: + langType := pkgURL.LangType() + langPkgMap[langType] = append(langPkgMap[langType], *pkg) } } @@ -332,14 +337,14 @@ func toApplication(component cdx.Component) *ftypes.Application { } } -func toPackage(component cdx.Component) (bool, ftypes.TargetType, *ftypes.Package, error) { +func toPackage(component cdx.Component) (*purl.PackageURL, *ftypes.Package, error) { if component.PackageURL == "" { log.Logger.Warnf("Skip the component (BOM-Ref: %s) as the PURL is empty", component.BOMRef) - return false, "", nil, ErrPURLEmpty + return nil, nil, ErrPURLEmpty } p, err := purl.FromString(component.PackageURL) if err != nil { - return false, "", nil, xerrors.Errorf("failed to parse purl: %w", err) + return nil, nil, xerrors.Errorf("failed to parse purl: %w", err) } pkg := p.Package() @@ -365,7 +370,7 @@ func toPackage(component cdx.Component) (bool, ftypes.TargetType, *ftypes.Packag case PropertySrcEpoch: pkg.SrcEpoch, err = strconv.Atoi(value) if err != nil { - return false, "", nil, xerrors.Errorf("failed to parse source epoch: %w", err) + return nil, nil, xerrors.Errorf("failed to parse source epoch: %w", err) } case PropertyModularitylabel: pkg.Modularitylabel = value @@ -376,8 +381,7 @@ func toPackage(component cdx.Component) (bool, ftypes.TargetType, *ftypes.Packag } } - isOSPkg := p.IsOSPkg() - if isOSPkg { + if p.Class() == types.ClassOSPkg { // Fill source package information for components in third-party SBOMs . if pkg.SrcName == "" { pkg.SrcName = pkg.Name @@ -393,7 +397,7 @@ func toPackage(component cdx.Component) (bool, ftypes.TargetType, *ftypes.Packag } } - return isOSPkg, p.LangType(), pkg, nil + return p, pkg, nil } func toTrivyCdxComponent(component cdx.Component) ftypes.Component { diff --git a/pkg/sbom/cyclonedx/unmarshal_test.go b/pkg/sbom/cyclonedx/unmarshal_test.go index 4e3b4d5f01be..4ea9b17f44c1 100644 --- a/pkg/sbom/cyclonedx/unmarshal_test.go +++ b/pkg/sbom/cyclonedx/unmarshal_test.go @@ -130,6 +130,72 @@ func TestUnmarshaler_Unmarshal(t *testing.T) { }, }, }, + { + name: "happy path KBOM", + inputFile: "testdata/happy/kbom.json", + want: types.SBOM{ + OS: ftypes.OS{ + Family: "ubuntu", + Name: "22.04.2", + }, + Packages: []ftypes.PackageInfo{ + { + FilePath: "", + }, + }, + Applications: []ftypes.Application{ + { + Type: ftypes.GoBinary, + Libraries: ftypes.Packages{ + { + Name: "docker", + Version: "24.0.4", + Ref: "pkg:golang/docker@24.0.4", + }, + }, + }, + { + Type: "golang", + FilePath: "node-core-components", + }, + { + Type: ftypes.K8sUpstream, + Libraries: ftypes.Packages{ + { + 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", + }, + { + 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", + }, + { + 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", + }, + }, + }, + }, + }, + }, { name: "happy path with infinity loop", inputFile: "testdata/happy/infinite-loop-bom.json", diff --git a/pkg/sbom/spdx/unmarshal.go b/pkg/sbom/spdx/unmarshal.go index 1624d781ffdf..e603e646be9b 100644 --- a/pkg/sbom/spdx/unmarshal.go +++ b/pkg/sbom/spdx/unmarshal.go @@ -177,10 +177,10 @@ 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.Type { - case packageurl.TypeApk, packageurl.TypeDebian, packageurl.TypeRPM: + switch pkgURL.Class() { + case types.ClassOSPkg: osPkgs = append(osPkgs, *pkg) - default: + case types.ClassLangPkg: // Language-specific packages pkgType := pkgURL.LangType() app, ok := apps[pkgType] diff --git a/pkg/scanner/langpkg/scan.go b/pkg/scanner/langpkg/scan.go index 6f74f3488316..df16c0c78476 100644 --- a/pkg/scanner/langpkg/scan.go +++ b/pkg/scanner/langpkg/scan.go @@ -13,11 +13,12 @@ import ( var ( PkgTargets = map[ftypes.LangType]string{ - ftypes.PythonPkg: "Python", - ftypes.CondaPkg: "Conda", - ftypes.GemSpec: "Ruby", - ftypes.NodePkg: "Node.js", - ftypes.Jar: "Java", + ftypes.PythonPkg: "Python", + ftypes.CondaPkg: "Conda", + ftypes.GemSpec: "Ruby", + ftypes.NodePkg: "Node.js", + ftypes.Jar: "Java", + ftypes.K8sUpstream: "Kubernetes", } ) diff --git a/pkg/types/report.go b/pkg/types/report.go index 13d58646b20c..e83ce3b6c394 100644 --- a/pkg/types/report.go +++ b/pkg/types/report.go @@ -41,6 +41,7 @@ type Compliance = string type Format string const ( + ClassUnknown ResultClass = "unknown" ClassOSPkg ResultClass = "os-pkgs" // For detected packages and vulnerabilities in OS packages ClassLangPkg ResultClass = "lang-pkgs" // For detected packages and vulnerabilities in language-specific packages ClassConfig ResultClass = "config" // For detected misconfigurations