mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-22 07:10:41 -08:00
refactor(cyclonedx): add intermediate representation (#4490)
This commit is contained in:
@@ -12,9 +12,6 @@ trivy sbom [flags] SBOM_PATH
|
|||||||
# Scan CycloneDX and show the result in tables
|
# Scan CycloneDX and show the result in tables
|
||||||
$ trivy sbom /path/to/report.cdx
|
$ trivy sbom /path/to/report.cdx
|
||||||
|
|
||||||
# Scan CycloneDX and generate a CycloneDX report
|
|
||||||
$ trivy sbom --format cyclonedx /path/to/report.cdx
|
|
||||||
|
|
||||||
# Scan CycloneDX-type attestation and show the result in tables
|
# Scan CycloneDX-type attestation and show the result in tables
|
||||||
$ trivy sbom /path/to/report.cdx.intoto.jsonl
|
$ trivy sbom /path/to/report.cdx.intoto.jsonl
|
||||||
|
|
||||||
|
|||||||
@@ -28,10 +28,6 @@ Trivy supports CycloneDX as an input.
|
|||||||
$ trivy sbom /path/to/cyclonedx.json
|
$ trivy sbom /path/to/cyclonedx.json
|
||||||
```
|
```
|
||||||
|
|
||||||
!!! note
|
|
||||||
If you want to generate a CycloneDX report from a CycloneDX input, please be aware that the output stores references to your original CycloneDX report and contains only detected vulnerabilities, not components.
|
|
||||||
The report is called [BOV](https://cyclonedx.org/capabilities/sbom/).
|
|
||||||
|
|
||||||
## SPDX
|
## SPDX
|
||||||
Trivy supports the SPDX SBOM as an input.
|
Trivy supports the SPDX SBOM as an input.
|
||||||
|
|
||||||
|
|||||||
@@ -418,7 +418,7 @@ func TestClientServerWithCycloneDX(t *testing.T) {
|
|||||||
Input: "testdata/fixtures/images/fluentd-multiple-lockfiles.tar.gz",
|
Input: "testdata/fixtures/images/fluentd-multiple-lockfiles.tar.gz",
|
||||||
},
|
},
|
||||||
wantComponentsCount: 161,
|
wantComponentsCount: 161,
|
||||||
wantDependenciesCount: 80,
|
wantDependenciesCount: 162,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,16 +30,30 @@ func TestSBOM(t *testing.T) {
|
|||||||
name: "centos7 cyclonedx",
|
name: "centos7 cyclonedx",
|
||||||
args: args{
|
args: args{
|
||||||
input: "testdata/fixtures/sbom/centos-7-cyclonedx.json",
|
input: "testdata/fixtures/sbom/centos-7-cyclonedx.json",
|
||||||
format: "cyclonedx",
|
format: "json",
|
||||||
artifactType: "cyclonedx",
|
artifactType: "cyclonedx",
|
||||||
},
|
},
|
||||||
golden: "testdata/centos-7-cyclonedx.json.golden",
|
golden: "testdata/centos-7.json.golden",
|
||||||
|
override: types.Report{
|
||||||
|
ArtifactName: "testdata/fixtures/sbom/centos-7-cyclonedx.json",
|
||||||
|
ArtifactType: ftypes.ArtifactType("cyclonedx"),
|
||||||
|
Results: types.Results{
|
||||||
|
{
|
||||||
|
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"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "fluentd-multiple-lockfiles cyclonedx",
|
name: "fluentd-multiple-lockfiles cyclonedx",
|
||||||
args: args{
|
args: args{
|
||||||
input: "testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json",
|
input: "testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json",
|
||||||
format: "cyclonedx",
|
format: "json",
|
||||||
artifactType: "cyclonedx",
|
artifactType: "cyclonedx",
|
||||||
},
|
},
|
||||||
golden: "testdata/fluentd-multiple-lockfiles-cyclonedx.json.golden",
|
golden: "testdata/fluentd-multiple-lockfiles-cyclonedx.json.golden",
|
||||||
@@ -48,10 +62,24 @@ func TestSBOM(t *testing.T) {
|
|||||||
name: "centos7 in in-toto attestation",
|
name: "centos7 in in-toto attestation",
|
||||||
args: args{
|
args: args{
|
||||||
input: "testdata/fixtures/sbom/centos-7-cyclonedx.intoto.jsonl",
|
input: "testdata/fixtures/sbom/centos-7-cyclonedx.intoto.jsonl",
|
||||||
format: "cyclonedx",
|
format: "json",
|
||||||
artifactType: "cyclonedx",
|
artifactType: "cyclonedx",
|
||||||
},
|
},
|
||||||
golden: "testdata/centos-7-cyclonedx.json.golden",
|
golden: "testdata/centos-7.json.golden",
|
||||||
|
override: types.Report{
|
||||||
|
ArtifactName: "testdata/fixtures/sbom/centos-7-cyclonedx.intoto.jsonl",
|
||||||
|
ArtifactType: ftypes.ArtifactType("cyclonedx"),
|
||||||
|
Results: types.Results{
|
||||||
|
{
|
||||||
|
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"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "centos7 spdx tag-value",
|
name: "centos7 spdx tag-value",
|
||||||
@@ -131,8 +159,6 @@ func TestSBOM(t *testing.T) {
|
|||||||
|
|
||||||
// Compare want and got
|
// Compare want and got
|
||||||
switch tt.args.format {
|
switch tt.args.format {
|
||||||
case "cyclonedx":
|
|
||||||
compareCycloneDX(t, tt.golden, outputFile)
|
|
||||||
case "json":
|
case "json":
|
||||||
compareSBOMReports(t, tt.golden, outputFile, tt.override)
|
compareSBOMReports(t, tt.golden, outputFile, tt.override)
|
||||||
default:
|
default:
|
||||||
@@ -146,8 +172,12 @@ func TestSBOM(t *testing.T) {
|
|||||||
func compareSBOMReports(t *testing.T, wantFile, gotFile string, overrideWant types.Report) {
|
func compareSBOMReports(t *testing.T, wantFile, gotFile string, overrideWant types.Report) {
|
||||||
want := readReport(t, wantFile)
|
want := readReport(t, wantFile)
|
||||||
|
|
||||||
|
if overrideWant.ArtifactName != "" {
|
||||||
want.ArtifactName = overrideWant.ArtifactName
|
want.ArtifactName = overrideWant.ArtifactName
|
||||||
|
}
|
||||||
|
if overrideWant.ArtifactType != "" {
|
||||||
want.ArtifactType = overrideWant.ArtifactType
|
want.ArtifactType = overrideWant.ArtifactType
|
||||||
|
}
|
||||||
want.Metadata.ImageID = ""
|
want.Metadata.ImageID = ""
|
||||||
want.Metadata.ImageConfig = v1.ConfigFile{}
|
want.Metadata.ImageConfig = v1.ConfigFile{}
|
||||||
want.Metadata.DiffIDs = nil
|
want.Metadata.DiffIDs = nil
|
||||||
|
|||||||
528
integration/testdata/centos-7-cyclonedx.json.golden
vendored
528
integration/testdata/centos-7-cyclonedx.json.golden
vendored
@@ -1,528 +0,0 @@
|
|||||||
{
|
|
||||||
"bomFormat": "CycloneDX",
|
|
||||||
"specVersion": "1.4",
|
|
||||||
"version": 1,
|
|
||||||
"metadata": {
|
|
||||||
"timestamp": "2023-05-19T10:38:43+00:00",
|
|
||||||
"tools": [
|
|
||||||
{
|
|
||||||
"vendor": "aquasecurity",
|
|
||||||
"name": "trivy",
|
|
||||||
"version": "dev"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"component": {
|
|
||||||
"bom-ref": "urn:uuid:1455c02d-64ca-453e-a5df-ddfb70a7c804/1",
|
|
||||||
"type": "container",
|
|
||||||
"name": "integration/testdata/fixtures/images/centos-7.tar.gz"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"vulnerabilities": [
|
|
||||||
{
|
|
||||||
"id": "CVE-2019-18276",
|
|
||||||
"ratings": [
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "cbl-mariner"
|
|
||||||
},
|
|
||||||
"severity": "high"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "nvd"
|
|
||||||
},
|
|
||||||
"score": 7.2,
|
|
||||||
"severity": "high",
|
|
||||||
"method": "CVSSv2",
|
|
||||||
"vector": "AV:L/AC:L/Au:N/C:C/I:C/A:C"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "nvd"
|
|
||||||
},
|
|
||||||
"score": 7.8,
|
|
||||||
"severity": "high",
|
|
||||||
"method": "CVSSv31",
|
|
||||||
"vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "oracle-oval"
|
|
||||||
},
|
|
||||||
"severity": "low"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "photon"
|
|
||||||
},
|
|
||||||
"severity": "high"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "redhat"
|
|
||||||
},
|
|
||||||
"score": 7.8,
|
|
||||||
"severity": "low",
|
|
||||||
"method": "CVSSv31",
|
|
||||||
"vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "ubuntu"
|
|
||||||
},
|
|
||||||
"severity": "low"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"cwes": [
|
|
||||||
273
|
|
||||||
],
|
|
||||||
"description": "An issue was discovered in disable_priv_mode in shell.c in GNU Bash through 5.0 patch 11. By default, if Bash is run with its effective UID not equal to its real UID, it will drop privileges by setting its effective UID to its real UID. However, it does so incorrectly. On Linux and other systems that support \"saved UID\" functionality, the saved UID is not dropped. An attacker with command execution in the shell can use \"enable -f\" for runtime loading of a new builtin, which can be a shared object that calls setuid() and therefore regains privileges. However, binaries running with an effective UID of 0 are unaffected.",
|
|
||||||
"advisories": [
|
|
||||||
{
|
|
||||||
"url": "http://packetstormsecurity.com/files/155498/Bash-5.0-Patch-11-Privilege-Escalation.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://access.redhat.com/security/cve/CVE-2019-18276"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18276"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/bminor/bash/commit/951bdaad7a18cc0dc1036bba86b18b90874d39ff"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://linux.oracle.com/cve/CVE-2019-18276.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://linux.oracle.com/errata/ELSA-2021-1679.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772@%3Cdev.mina.apache.org%3E"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://nvd.nist.gov/vuln/detail/CVE-2019-18276"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://security.gentoo.org/glsa/202105-34"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://security.netapp.com/advisory/ntap-20200430-0003/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.youtube.com/watch?v=-wGtxJ8opa8"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"published": "2019-11-28T01:15:00+00:00",
|
|
||||||
"updated": "2021-05-26T12:15:00+00:00",
|
|
||||||
"affects": [
|
|
||||||
{
|
|
||||||
"ref": "urn:cdx:1455c02d-64ca-453e-a5df-ddfb70a7c804/1#pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64\u0026distro=centos-7.6.1810",
|
|
||||||
"versions": [
|
|
||||||
{
|
|
||||||
"version": "4.2.46-31.el7",
|
|
||||||
"status": "affected"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "CVE-2019-1559",
|
|
||||||
"ratings": [
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "amazon"
|
|
||||||
},
|
|
||||||
"severity": "medium"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "arch-linux"
|
|
||||||
},
|
|
||||||
"severity": "medium"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "nvd"
|
|
||||||
},
|
|
||||||
"score": 4.3,
|
|
||||||
"severity": "medium",
|
|
||||||
"method": "CVSSv2",
|
|
||||||
"vector": "AV:N/AC:M/Au:N/C:P/I:N/A:N"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "nvd"
|
|
||||||
},
|
|
||||||
"score": 5.9,
|
|
||||||
"severity": "medium",
|
|
||||||
"method": "CVSSv3",
|
|
||||||
"vector": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "oracle-oval"
|
|
||||||
},
|
|
||||||
"severity": "medium"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "redhat"
|
|
||||||
},
|
|
||||||
"score": 5.9,
|
|
||||||
"severity": "medium",
|
|
||||||
"method": "CVSSv31",
|
|
||||||
"vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "ubuntu"
|
|
||||||
},
|
|
||||||
"severity": "medium"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"cwes": [
|
|
||||||
203
|
|
||||||
],
|
|
||||||
"description": "If an application encounters a fatal protocol error and then calls SSL_shutdown() twice (once to send a close_notify, and once to receive one) then OpenSSL can respond differently to the calling application if a 0 byte record is received with invalid padding compared to if a 0 byte record is received with an invalid MAC. If the application then behaves differently based on that in a way that is detectable to the remote peer, then this amounts to a padding oracle that could be used to decrypt data. In order for this to be exploitable \"non-stitched\" ciphersuites must be in use. Stitched ciphersuites are optimised implementations of certain commonly used ciphersuites. Also the application must call SSL_shutdown() twice even if a protocol error has occurred (applications should not do this but some do anyway). Fixed in OpenSSL 1.0.2r (Affected 1.0.2-1.0.2q).",
|
|
||||||
"recommendation": "Upgrade openssl-libs to version 1:1.0.2k-19.el7",
|
|
||||||
"advisories": [
|
|
||||||
{
|
|
||||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-03/msg00041.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-04/msg00019.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-04/msg00046.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-04/msg00047.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-05/msg00049.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-06/msg00080.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "http://www.securityfocus.com/bid/107174"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://access.redhat.com/errata/RHSA-2019:2304"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://access.redhat.com/errata/RHSA-2019:2437"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://access.redhat.com/errata/RHSA-2019:2439"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://access.redhat.com/errata/RHSA-2019:2471"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://access.redhat.com/errata/RHSA-2019:3929"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://access.redhat.com/errata/RHSA-2019:3931"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://access.redhat.com/security/cve/CVE-2019-1559"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1559"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=e9bbefbf0f24c57645e7ad6a5a71ae649d18ac8e"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/RUB-NDS/TLS-Padding-Oracles"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://kc.mcafee.com/corporate/index?page=content\u0026id=SB10282"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://linux.oracle.com/cve/CVE-2019-1559.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://linux.oracle.com/errata/ELSA-2019-2471.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://lists.debian.org/debian-lts-announce/2019/03/msg00003.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/EWC42UXL5GHTU5G77VKBF6JYUUNGSHOM/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/Y3IVFGSERAZLNJCK35TEM2R4726XIH3Z/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/ZBEV5QGDRFUZDMNECFXUSN5FMYOZDE4V/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://security.gentoo.org/glsa/201903-10"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://security.netapp.com/advisory/ntap-20190301-0001/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://security.netapp.com/advisory/ntap-20190301-0002/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://security.netapp.com/advisory/ntap-20190423-0002/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://support.f5.com/csp/article/K18549143"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://support.f5.com/csp/article/K18549143?utm_source=f5support\u0026amp;utm_medium=RSS"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://ubuntu.com/security/notices/USN-3899-1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://ubuntu.com/security/notices/USN-4376-2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://usn.ubuntu.com/3899-1/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://usn.ubuntu.com/4376-2/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.debian.org/security/2019/dsa-4400"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.openssl.org/news/secadv/20190226.txt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.oracle.com/security-alerts/cpujan2020.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.oracle.com/security-alerts/cpujan2021.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.oracle.com/technetwork/security-advisory/cpuapr2019-5072813.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.oracle.com/technetwork/security-advisory/cpujul2019-5072835.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.oracle.com/technetwork/security-advisory/cpuoct2019-5072832.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.tenable.com/security/tns-2019-02"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.tenable.com/security/tns-2019-03"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"published": "2019-02-27T23:29:00+00:00",
|
|
||||||
"updated": "2021-01-20T15:15:00+00:00",
|
|
||||||
"affects": [
|
|
||||||
{
|
|
||||||
"ref": "urn:cdx:1455c02d-64ca-453e-a5df-ddfb70a7c804/1#pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64\u0026epoch=1\u0026distro=centos-7.6.1810",
|
|
||||||
"versions": [
|
|
||||||
{
|
|
||||||
"version": "1:1.0.2k-16.el7",
|
|
||||||
"status": "affected"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "CVE-2018-0734",
|
|
||||||
"ratings": [
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "amazon"
|
|
||||||
},
|
|
||||||
"severity": "medium"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "arch-linux"
|
|
||||||
},
|
|
||||||
"severity": "low"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "cbl-mariner"
|
|
||||||
},
|
|
||||||
"severity": "medium"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "nvd"
|
|
||||||
},
|
|
||||||
"score": 4.3,
|
|
||||||
"severity": "medium",
|
|
||||||
"method": "CVSSv2",
|
|
||||||
"vector": "AV:N/AC:M/Au:N/C:P/I:N/A:N"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "nvd"
|
|
||||||
},
|
|
||||||
"score": 5.9,
|
|
||||||
"severity": "medium",
|
|
||||||
"method": "CVSSv3",
|
|
||||||
"vector": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "oracle-oval"
|
|
||||||
},
|
|
||||||
"severity": "low"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "photon"
|
|
||||||
},
|
|
||||||
"severity": "medium"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "redhat"
|
|
||||||
},
|
|
||||||
"score": 5.1,
|
|
||||||
"severity": "low",
|
|
||||||
"method": "CVSSv3",
|
|
||||||
"vector": "CVSS:3.0/AV:L/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "ubuntu"
|
|
||||||
},
|
|
||||||
"severity": "low"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"cwes": [
|
|
||||||
327
|
|
||||||
],
|
|
||||||
"description": "The OpenSSL DSA signature algorithm has been shown to be vulnerable to a timing side channel attack. An attacker could use variations in the signing algorithm to recover the private key. Fixed in OpenSSL 1.1.1a (Affected 1.1.1). Fixed in OpenSSL 1.1.0j (Affected 1.1.0-1.1.0i). Fixed in OpenSSL 1.0.2q (Affected 1.0.2-1.0.2p).",
|
|
||||||
"recommendation": "Upgrade openssl-libs to version 1:1.0.2k-19.el7",
|
|
||||||
"advisories": [
|
|
||||||
{
|
|
||||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-06/msg00030.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-07/msg00056.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "http://www.securityfocus.com/bid/105758"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://access.redhat.com/errata/RHSA-2019:2304"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://access.redhat.com/errata/RHSA-2019:3700"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://access.redhat.com/errata/RHSA-2019:3932"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://access.redhat.com/errata/RHSA-2019:3933"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://access.redhat.com/errata/RHSA-2019:3935"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://access.redhat.com/security/cve/CVE-2018-0734"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-0734"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=43e6a58d4991a451daf4891ff05a48735df871ac"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=8abfe72e8c1de1b95f50aa0d9134803b4d00070f"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=ef11e19d1365eea2b1851e6f540a0bf365d303e7"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://linux.oracle.com/cve/CVE-2018-0734.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://linux.oracle.com/errata/ELSA-2019-3700.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/EWC42UXL5GHTU5G77VKBF6JYUUNGSHOM/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/Y3IVFGSERAZLNJCK35TEM2R4726XIH3Z/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/ZBEV5QGDRFUZDMNECFXUSN5FMYOZDE4V/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://nodejs.org/en/blog/vulnerability/november-2018-security-releases/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://nvd.nist.gov/vuln/detail/CVE-2018-0734"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://security.netapp.com/advisory/ntap-20181105-0002/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://security.netapp.com/advisory/ntap-20190118-0002/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://security.netapp.com/advisory/ntap-20190423-0002/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://ubuntu.com/security/notices/USN-3840-1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://usn.ubuntu.com/3840-1/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.debian.org/security/2018/dsa-4348"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.debian.org/security/2018/dsa-4355"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.openssl.org/news/secadv/20181030.txt"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.oracle.com/security-alerts/cpuapr2020.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.oracle.com/security-alerts/cpujan2020.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.oracle.com/technetwork/security-advisory/cpuapr2019-5072813.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.oracle.com/technetwork/security-advisory/cpujan2019-5072801.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.oracle.com/technetwork/security-advisory/cpujul2019-5072835.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.tenable.com/security/tns-2018-16"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.tenable.com/security/tns-2018-17"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"published": "2018-10-30T12:29:00+00:00",
|
|
||||||
"updated": "2020-08-24T17:37:00+00:00",
|
|
||||||
"affects": [
|
|
||||||
{
|
|
||||||
"ref": "urn:cdx:1455c02d-64ca-453e-a5df-ddfb70a7c804/1#pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64\u0026epoch=1\u0026distro=centos-7.6.1810",
|
|
||||||
"versions": [
|
|
||||||
{
|
|
||||||
"version": "1:1.0.2k-16.el7",
|
|
||||||
"status": "affected"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -77,6 +77,12 @@
|
|||||||
"pkg:conda/openssl@1.1.1q?file_path=miniconda3%2Fenvs%2Ftestenv%2Fconda-meta%2Fopenssl-1.1.1q-h7f8727e_0.json",
|
"pkg:conda/openssl@1.1.1q?file_path=miniconda3%2Fenvs%2Ftestenv%2Fconda-meta%2Fopenssl-1.1.1q-h7f8727e_0.json",
|
||||||
"pkg:conda/pip@22.2.2?file_path=miniconda3%2Fenvs%2Ftestenv%2Fconda-meta%2Fpip-22.2.2-py38h06a4308_0.json"
|
"pkg:conda/pip@22.2.2?file_path=miniconda3%2Fenvs%2Ftestenv%2Fconda-meta%2Fpip-22.2.2-py38h06a4308_0.json"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ref": "pkg:conda/openssl@1.1.1q?file_path=miniconda3%2Fenvs%2Ftestenv%2Fconda-meta%2Fopenssl-1.1.1q-h7f8727e_0.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ref": "pkg:conda/pip@22.2.2?file_path=miniconda3%2Fenvs%2Ftestenv%2Fconda-meta%2Fpip-22.2.2-py38h06a4308_0.json"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"vulnerabilities": []
|
"vulnerabilities": []
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL2N5Y2xvbmVkeC5vcmcvYm9tIiwic3ViamVjdCI6W3sibmFtZSI6ImluZGV4LmRvY2tlci5pby9saWJyYXJ5L2NlbnRvcyIsImRpZ2VzdCI6eyJzaGEyNTYiOiJiZTY1ZjQ4OGI3NzY0YWQzNjM4ZjIzNmI3YjUxNWIzNjc4MzY5YTUxMjRjNDdiOGQzMjkxNmQ2NDg3NDE4ZWE0In19XSwicHJlZGljYXRlIjp7ImJvbUZvcm1hdCI6IkN5Y2xvbmVEWCIsImNvbXBvbmVudHMiOlt7ImJvbS1yZWYiOiJwa2c6cnBtL2NlbnRvcy9iYXNoQDQuMi40Ni0zMS5lbDc/YXJjaD14ODZfNjRcdTAwMjZkaXN0cm89Y2VudG9zLTcuNi4xODEwIiwibGljZW5zZXMiOlt7ImV4cHJlc3Npb24iOiJHUEx2MysifV0sIm5hbWUiOiJiYXNoIiwicHJvcGVydGllcyI6W3sibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpTcmNOYW1lIiwidmFsdWUiOiJiYXNoIn0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlNyY1ZlcnNpb24iLCJ2YWx1ZSI6IjQuMi40NiJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpTcmNSZWxlYXNlIiwidmFsdWUiOiIzMS5lbDcifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6TGF5ZXJEaWdlc3QiLCJ2YWx1ZSI6InNoYTI1NjphYzkyMDgyMDdhZGFhYzNhNDhlNTRhNGRjNmI0OWM2OWU3OGMzMDcyZDJiM2FkZDdlZmRhYmY4MTRkYjIxMzNiIn0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OkxheWVyRGlmZklEIiwidmFsdWUiOiJzaGEyNTY6ODkxNjlkODdkYmUyYjcyYmE0MmJmYmIzNTc5Yzk1NzMyMmJhY2EyOGUwM2ExZTU1ODA3NjU0MmExYzFiMmI0YSJ9XSwicHVybCI6InBrZzpycG0vY2VudG9zL2Jhc2hANC4yLjQ2LTMxLmVsNz9hcmNoPXg4Nl82NFx1MDAyNmRpc3Rybz1jZW50b3MtNy42LjE4MTAiLCJ0eXBlIjoibGlicmFyeSIsInZlcnNpb24iOiI0LjIuNDYtMzEuZWw3In0seyJib20tcmVmIjoicGtnOnJwbS9jZW50b3Mvb3BlbnNzbC1saWJzQDEuMC4yay0xNi5lbDc/YXJjaD14ODZfNjRcdTAwMjZlcG9jaD0xXHUwMDI2ZGlzdHJvPWNlbnRvcy03LjYuMTgxMCIsImxpY2Vuc2VzIjpbeyJleHByZXNzaW9uIjoiT3BlblNTTCJ9XSwibmFtZSI6Im9wZW5zc2wtbGlicyIsInByb3BlcnRpZXMiOlt7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6U3JjTmFtZSIsInZhbHVlIjoib3BlbnNzbCJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpTcmNWZXJzaW9uIiwidmFsdWUiOiIxLjAuMmsifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6U3JjUmVsZWFzZSIsInZhbHVlIjoiMTYuZWw3In0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlNyY0Vwb2NoIiwidmFsdWUiOiIxIn0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OkxheWVyRGlnZXN0IiwidmFsdWUiOiJzaGEyNTY6YWM5MjA4MjA3YWRhYWMzYTQ4ZTU0YTRkYzZiNDljNjllNzhjMzA3MmQyYjNhZGQ3ZWZkYWJmODE0ZGIyMTMzYiJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpMYXllckRpZmZJRCIsInZhbHVlIjoic2hhMjU2Ojg5MTY5ZDg3ZGJlMmI3MmJhNDJiZmJiMzU3OWM5NTczMjJiYWNhMjhlMDNhMWU1NTgwNzY1NDJhMWMxYjJiNGEifV0sInB1cmwiOiJwa2c6cnBtL2NlbnRvcy9vcGVuc3NsLWxpYnNAMS4wLjJrLTE2LmVsNz9hcmNoPXg4Nl82NFx1MDAyNmVwb2NoPTFcdTAwMjZkaXN0cm89Y2VudG9zLTcuNi4xODEwIiwidHlwZSI6ImxpYnJhcnkiLCJ2ZXJzaW9uIjoiMS4wLjJrLTE2LmVsNyJ9LHsiYm9tLXJlZiI6IjAxNzVmNzMyLWRmOWQtNGJiOC05ZjU2LTg3MDg5OGUzZmY4OSIsIm5hbWUiOiJjZW50b3MiLCJwcm9wZXJ0aWVzIjpbeyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlR5cGUiLCJ2YWx1ZSI6ImNlbnRvcyJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpDbGFzcyIsInZhbHVlIjoib3MtcGtncyJ9XSwidHlwZSI6Im9wZXJhdGluZy1zeXN0ZW0iLCJ2ZXJzaW9uIjoiNy42LjE4MTAifV0sImRlcGVuZGVuY2llcyI6W3siZGVwZW5kc09uIjpbInBrZzpycG0vY2VudG9zL2Jhc2hANC4yLjQ2LTMxLmVsNz9hcmNoPXg4Nl82NFx1MDAyNmRpc3Rybz1jZW50b3MtNy42LjE4MTAiLCJwa2c6cnBtL2NlbnRvcy9vcGVuc3NsLWxpYnNAMS4wLjJrLTE2LmVsNz9hcmNoPXg4Nl82NFx1MDAyNmVwb2NoPTFcdTAwMjZkaXN0cm89Y2VudG9zLTcuNi4xODEwIl0sInJlZiI6IjAxNzVmNzMyLWRmOWQtNGJiOC05ZjU2LTg3MDg5OGUzZmY4OSJ9LHsiZGVwZW5kc09uIjpbIjAxNzVmNzMyLWRmOWQtNGJiOC05ZjU2LTg3MDg5OGUzZmY4OSJdLCJyZWYiOiJkMGQ0MWUzMC05NjUwLTQ4OWQtOTQ4ZC00MjVmZjJlZDYzZDIifV0sIm1ldGFkYXRhIjp7ImNvbXBvbmVudCI6eyJib20tcmVmIjoiZDBkNDFlMzAtOTY1MC00ODlkLTk0OGQtNDI1ZmYyZWQ2M2QyIiwibmFtZSI6ImludGVncmF0aW9uL3Rlc3RkYXRhL2ZpeHR1cmVzL2ltYWdlcy9jZW50b3MtNy50YXIuZ3oiLCJwcm9wZXJ0aWVzIjpbeyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlNjaGVtYVZlcnNpb24iLCJ2YWx1ZSI6IjIifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6SW1hZ2VJRCIsInZhbHVlIjoic2hhMjU2OmYxY2I3YzdkNThiNzNlYWM4NTljMzk1ODgyZWVjNDlkNTA2NTEyNDRlMzQyY2Q2YzY4YTVjNzgwOTc4NWY0MjcifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6RGlmZklEIiwidmFsdWUiOiJzaGEyNTY6ODkxNjlkODdkYmUyYjcyYmE0MmJmYmIzNTc5Yzk1NzMyMmJhY2EyOGUwM2ExZTU1ODA3NjU0MmExYzFiMmI0YSJ9XSwidHlwZSI6ImNvbnRhaW5lciJ9LCJ0aW1lc3RhbXAiOiIyMDIyLTA2LTE0VDE1OjA4OjQ4KzAwOjAwIiwidG9vbHMiOlt7Im5hbWUiOiJ0cml2eSIsInZlbmRvciI6ImFxdWFzZWN1cml0eSIsInZlcnNpb24iOiJkZXYifV19LCJzZXJpYWxOdW1iZXIiOiJ1cm46dXVpZDoxNDU1YzAyZC02NGNhLTQ1M2UtYTVkZi1kZGZiNzBhN2M4MDQiLCJzcGVjVmVyc2lvbiI6IjEuNCIsInZlcnNpb24iOjF9fQ==","signatures":[{"keyid":"","sig":"MEUCIQCtj78dipe+yzdlIsmwjn9QeaBTAPQacwIJAWfnrtp7FwIgcViOUgPA0WFYjimrIl7vbygdSpduM+ZzY3cqrDciH1U="}]}
|
{"payloadType":"application/vnd.in-toto+json","payload":"eyJfdHlwZSI6Imh0dHBzOi8vaW4tdG90by5pby9TdGF0ZW1lbnQvdjAuMSIsInByZWRpY2F0ZVR5cGUiOiJodHRwczovL2N5Y2xvbmVkeC5vcmcvYm9tIiwic3ViamVjdCI6W3sibmFtZSI6ImluZGV4LmRvY2tlci5pby9saWJyYXJ5L2NlbnRvcyIsImRpZ2VzdCI6eyJzaGEyNTYiOiJiZTY1ZjQ4OGI3NzY0YWQzNjM4ZjIzNmI3YjUxNWIzNjc4MzY5YTUxMjRjNDdiOGQzMjkxNmQ2NDg3NDE4ZWE0In19XSwicHJlZGljYXRlIjp7ImJvbUZvcm1hdCI6IkN5Y2xvbmVEWCIsInNwZWNWZXJzaW9uIjoiMS40Iiwic2VyaWFsTnVtYmVyIjoidXJuOnV1aWQ6MTQ1NWMwMmQtNjRjYS00NTNlLWE1ZGYtZGRmYjcwYTdjODA0IiwidmVyc2lvbiI6MSwibWV0YWRhdGEiOnsidGltZXN0YW1wIjoiMjAyMi0wNi0xNFQxNTowODo0OCswMDowMCIsInRvb2xzIjpbeyJ2ZW5kb3IiOiJhcXVhc2VjdXJpdHkiLCJuYW1lIjoidHJpdnkiLCJ2ZXJzaW9uIjoiZGV2In1dLCJjb21wb25lbnQiOnsiYm9tLXJlZiI6ImQwZDQxZTMwLTk2NTAtNDg5ZC05NDhkLTQyNWZmMmVkNjNkMiIsInR5cGUiOiJjb250YWluZXIiLCJuYW1lIjoiaW50ZWdyYXRpb24vdGVzdGRhdGEvZml4dHVyZXMvaW1hZ2VzL2NlbnRvcy03LnRhci5neiIsInByb3BlcnRpZXMiOlt7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6U2NoZW1hVmVyc2lvbiIsInZhbHVlIjoiMiJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpJbWFnZUlEIiwidmFsdWUiOiJzaGEyNTY6ZjFjYjdjN2Q1OGI3M2VhYzg1OWMzOTU4ODJlZWM0OWQ1MDY1MTI0NGUzNDJjZDZjNjhhNWM3ODA5Nzg1ZjQyNyJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpEaWZmSUQiLCJ2YWx1ZSI6InNoYTI1Njo4OTE2OWQ4N2RiZTJiNzJiYTQyYmZiYjM1NzljOTU3MzIyYmFjYTI4ZTAzYTFlNTU4MDc2NTQyYTFjMWIyYjRhIn1dfX0sImNvbXBvbmVudHMiOlt7ImJvbS1yZWYiOiJwa2c6cnBtL2NlbnRvcy9iYXNoQDQuMi40Ni0zMS5lbDc/YXJjaD14ODZfNjQmZGlzdHJvPWNlbnRvcy03LjYuMTgxMCIsInR5cGUiOiJsaWJyYXJ5IiwibmFtZSI6ImJhc2giLCJ2ZXJzaW9uIjoiNC4yLjQ2LTMxLmVsNyIsImxpY2Vuc2VzIjpbeyJleHByZXNzaW9uIjoiR1BMdjMrIn1dLCJwdXJsIjoicGtnOnJwbS9jZW50b3MvYmFzaEA0LjIuNDYtMzEuZWw3P2FyY2g9eDg2XzY0JmRpc3Rybz1jZW50b3MtNy42LjE4MTAiLCJwcm9wZXJ0aWVzIjpbeyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlBrZ0lEIiwidmFsdWUiOiJiYXNoQDQuMi40Ni0zMS5lbDcueDg2XzY0In0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlNyY05hbWUiLCJ2YWx1ZSI6ImJhc2gifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6U3JjVmVyc2lvbiIsInZhbHVlIjoiNC4yLjQ2In0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlNyY1JlbGVhc2UiLCJ2YWx1ZSI6IjMxLmVsNyJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpMYXllckRpZ2VzdCIsInZhbHVlIjoic2hhMjU2OmFjOTIwODIwN2FkYWFjM2E0OGU1NGE0ZGM2YjQ5YzY5ZTc4YzMwNzJkMmIzYWRkN2VmZGFiZjgxNGRiMjEzM2IifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6TGF5ZXJEaWZmSUQiLCJ2YWx1ZSI6InNoYTI1Njo4OTE2OWQ4N2RiZTJiNzJiYTQyYmZiYjM1NzljOTU3MzIyYmFjYTI4ZTAzYTFlNTU4MDc2NTQyYTFjMWIyYjRhIn1dfSx7ImJvbS1yZWYiOiJwa2c6cnBtL2NlbnRvcy9vcGVuc3NsLWxpYnNAMS4wLjJrLTE2LmVsNz9hcmNoPXg4Nl82NCZlcG9jaD0xJmRpc3Rybz1jZW50b3MtNy42LjE4MTAiLCJ0eXBlIjoibGlicmFyeSIsIm5hbWUiOiJvcGVuc3NsLWxpYnMiLCJ2ZXJzaW9uIjoiMS4wLjJrLTE2LmVsNyIsImxpY2Vuc2VzIjpbeyJleHByZXNzaW9uIjoiT3BlblNTTCJ9XSwicHVybCI6InBrZzpycG0vY2VudG9zL29wZW5zc2wtbGlic0AxLjAuMmstMTYuZWw3P2FyY2g9eDg2XzY0JmVwb2NoPTEmZGlzdHJvPWNlbnRvcy03LjYuMTgxMCIsInByb3BlcnRpZXMiOlt7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6UGtnSUQiLCJ2YWx1ZSI6Im9wZW5zc2wtbGlic0AxLjAuMmstMTYuZWw3Lng4Nl82NCJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpTcmNOYW1lIiwidmFsdWUiOiJvcGVuc3NsIn0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OlNyY1ZlcnNpb24iLCJ2YWx1ZSI6IjEuMC4yayJ9LHsibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpTcmNSZWxlYXNlIiwidmFsdWUiOiIxNi5lbDcifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6U3JjRXBvY2giLCJ2YWx1ZSI6IjEifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6TGF5ZXJEaWdlc3QiLCJ2YWx1ZSI6InNoYTI1NjphYzkyMDgyMDdhZGFhYzNhNDhlNTRhNGRjNmI0OWM2OWU3OGMzMDcyZDJiM2FkZDdlZmRhYmY4MTRkYjIxMzNiIn0seyJuYW1lIjoiYXF1YXNlY3VyaXR5OnRyaXZ5OkxheWVyRGlmZklEIiwidmFsdWUiOiJzaGEyNTY6ODkxNjlkODdkYmUyYjcyYmE0MmJmYmIzNTc5Yzk1NzMyMmJhY2EyOGUwM2ExZTU1ODA3NjU0MmExYzFiMmI0YSJ9XX0seyJib20tcmVmIjoiMDE3NWY3MzItZGY5ZC00YmI4LTlmNTYtODcwODk4ZTNmZjg5IiwidHlwZSI6Im9wZXJhdGluZy1zeXN0ZW0iLCJuYW1lIjoiY2VudG9zIiwidmVyc2lvbiI6IjcuNi4xODEwIiwicHJvcGVydGllcyI6W3sibmFtZSI6ImFxdWFzZWN1cml0eTp0cml2eTpUeXBlIiwidmFsdWUiOiJjZW50b3MifSx7Im5hbWUiOiJhcXVhc2VjdXJpdHk6dHJpdnk6Q2xhc3MiLCJ2YWx1ZSI6Im9zLXBrZ3MifV19XSwiZGVwZW5kZW5jaWVzIjpbeyJyZWYiOiIwMTc1ZjczMi1kZjlkLTRiYjgtOWY1Ni04NzA4OThlM2ZmODkiLCJkZXBlbmRzT24iOlsicGtnOnJwbS9jZW50b3MvYmFzaEA0LjIuNDYtMzEuZWw3P2FyY2g9eDg2XzY0JmRpc3Rybz1jZW50b3MtNy42LjE4MTAiLCJwa2c6cnBtL2NlbnRvcy9vcGVuc3NsLWxpYnNAMS4wLjJrLTE2LmVsNz9hcmNoPXg4Nl82NCZlcG9jaD0xJmRpc3Rybz1jZW50b3MtNy42LjE4MTAiXX0seyJyZWYiOiJkMGQ0MWUzMC05NjUwLTQ4OWQtOTQ4ZC00MjVmZjJlZDYzZDIiLCJkZXBlbmRzT24iOlsiMDE3NWY3MzItZGY5ZC00YmI4LTlmNTYtODcwODk4ZTNmZjg5Il19XX19Cg==","signatures":[{"keyid":"","sig":"MEUCIQCtj78dipe+yzdlIsmwjn9QeaBTAPQacwIJAWfnrtp7FwIgcViOUgPA0WFYjimrIl7vbygdSpduM+ZzY3cqrDciH1U="}]}
|
||||||
|
|||||||
@@ -45,6 +45,10 @@
|
|||||||
],
|
],
|
||||||
"purl": "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810",
|
"purl": "pkg:rpm/centos/bash@4.2.46-31.el7?arch=x86_64&distro=centos-7.6.1810",
|
||||||
"properties": [
|
"properties": [
|
||||||
|
{
|
||||||
|
"name": "aquasecurity:trivy:PkgID",
|
||||||
|
"value": "bash@4.2.46-31.el7.x86_64"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "aquasecurity:trivy:SrcName",
|
"name": "aquasecurity:trivy:SrcName",
|
||||||
"value": "bash"
|
"value": "bash"
|
||||||
@@ -79,6 +83,10 @@
|
|||||||
],
|
],
|
||||||
"purl": "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810",
|
"purl": "pkg:rpm/centos/openssl-libs@1.0.2k-16.el7?arch=x86_64&epoch=1&distro=centos-7.6.1810",
|
||||||
"properties": [
|
"properties": [
|
||||||
|
{
|
||||||
|
"name": "aquasecurity:trivy:PkgID",
|
||||||
|
"value": "openssl-libs@1.0.2k-16.el7.x86_64"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "aquasecurity:trivy:SrcName",
|
"name": "aquasecurity:trivy:SrcName",
|
||||||
"value": "openssl"
|
"value": "openssl"
|
||||||
|
|||||||
@@ -1,346 +1,187 @@
|
|||||||
{
|
{
|
||||||
"bomFormat": "CycloneDX",
|
"SchemaVersion": 2,
|
||||||
"specVersion": "1.4",
|
"ArtifactName": "testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json",
|
||||||
"version": 1,
|
"ArtifactType": "cyclonedx",
|
||||||
"metadata": {
|
"Metadata": {
|
||||||
"timestamp": "2023-05-19T10:38:42+00:00",
|
"OS": {
|
||||||
"tools": [
|
"Family": "debian",
|
||||||
{
|
"Name": "10.2"
|
||||||
"vendor": "aquasecurity",
|
},
|
||||||
"name": "trivy",
|
"ImageConfig": {
|
||||||
"version": "dev"
|
"architecture": "",
|
||||||
|
"created": "0001-01-01T00:00:00Z",
|
||||||
|
"os": "",
|
||||||
|
"rootfs": {
|
||||||
|
"type": "",
|
||||||
|
"diff_ids": null
|
||||||
|
},
|
||||||
|
"config": {}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"Results": [
|
||||||
|
{
|
||||||
|
"Target": "testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json (debian 10.2)",
|
||||||
|
"Class": "os-pkgs",
|
||||||
|
"Type": "debian",
|
||||||
|
"Vulnerabilities": [
|
||||||
|
{
|
||||||
|
"VulnerabilityID": "CVE-2019-18276",
|
||||||
|
"PkgName": "bash",
|
||||||
|
"InstalledVersion": "5.0-4",
|
||||||
|
"Layer": {},
|
||||||
|
"SeveritySource": "debian",
|
||||||
|
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2019-18276",
|
||||||
|
"PkgRef": "pkg:deb/debian/bash@5.0-4?distro=debian-10.2",
|
||||||
|
"DataSource": {
|
||||||
|
"ID": "debian",
|
||||||
|
"Name": "Debian Security Tracker",
|
||||||
|
"URL": "https://salsa.debian.org/security-tracker-team/security-tracker"
|
||||||
|
},
|
||||||
|
"Title": "bash: when effective UID is not equal to its real UID the saved UID is not dropped",
|
||||||
|
"Description": "An issue was discovered in disable_priv_mode in shell.c in GNU Bash through 5.0 patch 11. By default, if Bash is run with its effective UID not equal to its real UID, it will drop privileges by setting its effective UID to its real UID. However, it does so incorrectly. On Linux and other systems that support \"saved UID\" functionality, the saved UID is not dropped. An attacker with command execution in the shell can use \"enable -f\" for runtime loading of a new builtin, which can be a shared object that calls setuid() and therefore regains privileges. However, binaries running with an effective UID of 0 are unaffected.",
|
||||||
|
"Severity": "LOW",
|
||||||
|
"CweIDs": [
|
||||||
|
"CWE-273"
|
||||||
],
|
],
|
||||||
"component": {
|
"CVSS": {
|
||||||
"bom-ref": "urn:uuid:31ee662c-480e-4f63-9765-23ea8afc754d/1",
|
"nvd": {
|
||||||
"type": "container",
|
"V2Vector": "AV:L/AC:L/Au:N/C:C/I:C/A:C",
|
||||||
"name": "integration/testdata/fixtures/images/fluentd-multiple-lockfiles.tar.gz"
|
"V3Vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
|
||||||
|
"V2Score": 7.2,
|
||||||
|
"V3Score": 7.8
|
||||||
|
},
|
||||||
|
"redhat": {
|
||||||
|
"V3Vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
|
||||||
|
"V3Score": 7.8
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"vulnerabilities": [
|
"References": [
|
||||||
{
|
"http://packetstormsecurity.com/files/155498/Bash-5.0-Patch-11-Privilege-Escalation.html",
|
||||||
"id": "CVE-2020-8165",
|
"https://access.redhat.com/security/cve/CVE-2019-18276",
|
||||||
"source": {
|
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18276",
|
||||||
"name": "ghsa",
|
"https://github.com/bminor/bash/commit/951bdaad7a18cc0dc1036bba86b18b90874d39ff",
|
||||||
"url": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Arubygems"
|
"https://linux.oracle.com/cve/CVE-2019-18276.html",
|
||||||
},
|
"https://linux.oracle.com/errata/ELSA-2021-1679.html",
|
||||||
"ratings": [
|
"https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772@%3Cdev.mina.apache.org%3E",
|
||||||
{
|
"https://nvd.nist.gov/vuln/detail/CVE-2019-18276",
|
||||||
"source": {
|
"https://security.gentoo.org/glsa/202105-34",
|
||||||
"name": "ghsa"
|
"https://security.netapp.com/advisory/ntap-20200430-0003/",
|
||||||
},
|
"https://www.youtube.com/watch?v=-wGtxJ8opa8"
|
||||||
"severity": "high"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "nvd"
|
|
||||||
},
|
|
||||||
"score": 7.5,
|
|
||||||
"severity": "high",
|
|
||||||
"method": "CVSSv2",
|
|
||||||
"vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "nvd"
|
|
||||||
},
|
|
||||||
"score": 9.8,
|
|
||||||
"severity": "critical",
|
|
||||||
"method": "CVSSv31",
|
|
||||||
"vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "redhat"
|
|
||||||
},
|
|
||||||
"score": 9.8,
|
|
||||||
"severity": "high",
|
|
||||||
"method": "CVSSv31",
|
|
||||||
"vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
"cwes": [
|
"PublishedDate": "2019-11-28T01:15:00Z",
|
||||||
502
|
"LastModifiedDate": "2021-05-26T12:15:00Z"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"VulnerabilityID": "CVE-2019-18224",
|
||||||
|
"VendorIDs": [
|
||||||
|
"DSA-4613-1"
|
||||||
],
|
],
|
||||||
"description": "A deserialization of untrusted data vulnerability exists in rails \u003c 5.2.4.3, rails \u003c 6.0.3.1 that can allow an attacker to unmarshal user-provided objects in MemCacheStore and RedisCacheStore potentially resulting in an RCE.",
|
"PkgName": "libidn2-0",
|
||||||
"recommendation": "Upgrade activesupport to version 6.0.3.1, 5.2.4.3",
|
"InstalledVersion": "2.0.5-1",
|
||||||
"advisories": [
|
"FixedVersion": "2.0.5-1+deb10u1",
|
||||||
{
|
"Layer": {},
|
||||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2020-10/msg00031.html"
|
"SeveritySource": "nvd",
|
||||||
|
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2019-18224",
|
||||||
|
"PkgRef": "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2",
|
||||||
|
"DataSource": {
|
||||||
|
"ID": "debian",
|
||||||
|
"Name": "Debian Security Tracker",
|
||||||
|
"URL": "https://salsa.debian.org/security-tracker-team/security-tracker"
|
||||||
},
|
},
|
||||||
{
|
"Title": "libidn2: heap-based buffer overflow in idn2_to_ascii_4i in lib/lookup.c",
|
||||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2020-10/msg00034.html"
|
"Description": "idn2_to_ascii_4i in lib/lookup.c in GNU libidn2 before 2.1.1 has a heap-based buffer overflow via a long domain string.",
|
||||||
},
|
"Severity": "CRITICAL",
|
||||||
{
|
"CweIDs": [
|
||||||
"url": "https://access.redhat.com/security/cve/CVE-2020-8165"
|
"CWE-787"
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/advisories/GHSA-2p68-f74v-9wc6"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/activesupport/CVE-2020-8165.yml"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://groups.google.com/forum/#!msg/rubyonrails-security/bv6fW4S0Y1c/KnkEqM7AAQAJ"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://groups.google.com/forum/#!topic/rubyonrails-security/bv6fW4S0Y1c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://groups.google.com/g/rubyonrails-security/c/bv6fW4S0Y1c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://hackerone.com/reports/413388"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://lists.debian.org/debian-lts-announce/2020/06/msg00022.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://lists.debian.org/debian-lts-announce/2020/07/msg00013.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://nvd.nist.gov/vuln/detail/CVE-2020-8165"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://weblog.rubyonrails.org/2020/5/18/Rails-5-2-4-3-and-6-0-3-1-have-been-released/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.debian.org/security/2020/dsa-4766"
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
"published": "2020-06-19T18:15:00+00:00",
|
"CVSS": {
|
||||||
"updated": "2020-10-17T12:15:00+00:00",
|
"nvd": {
|
||||||
"affects": [
|
"V2Vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P",
|
||||||
{
|
"V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||||
"ref": "urn:cdx:31ee662c-480e-4f63-9765-23ea8afc754d/1#pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec",
|
"V2Score": 7.5,
|
||||||
"versions": [
|
"V3Score": 9.8
|
||||||
{
|
},
|
||||||
"version": "6.0.2.1",
|
"redhat": {
|
||||||
"status": "affected"
|
"V3Vector": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L",
|
||||||
|
"V3Score": 5.6
|
||||||
}
|
}
|
||||||
]
|
},
|
||||||
|
"References": [
|
||||||
|
"http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00008.html",
|
||||||
|
"http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00009.html",
|
||||||
|
"https://access.redhat.com/security/cve/CVE-2019-18224",
|
||||||
|
"https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=12420",
|
||||||
|
"https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18224",
|
||||||
|
"https://github.com/libidn/libidn2/commit/e4d1558aa2c1c04a05066ee8600f37603890ba8c",
|
||||||
|
"https://github.com/libidn/libidn2/compare/libidn2-2.1.0...libidn2-2.1.1",
|
||||||
|
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/JDQVQ2XPV5BTZUFINT7AFJSKNNBVURNJ/",
|
||||||
|
"https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MINU5RKDFE6TKAFY5DRFN3WSFDS4DYVS/",
|
||||||
|
"https://seclists.org/bugtraq/2020/Feb/4",
|
||||||
|
"https://security.gentoo.org/glsa/202003-63",
|
||||||
|
"https://ubuntu.com/security/notices/USN-4168-1",
|
||||||
|
"https://usn.ubuntu.com/4168-1/",
|
||||||
|
"https://www.debian.org/security/2020/dsa-4613"
|
||||||
|
],
|
||||||
|
"PublishedDate": "2019-10-21T17:15:00Z",
|
||||||
|
"LastModifiedDate": "2019-10-29T19:15:00Z"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "CVE-2019-18276",
|
"Target": "Ruby",
|
||||||
"source": {
|
"Class": "lang-pkgs",
|
||||||
"name": "debian",
|
"Type": "gemspec",
|
||||||
"url": "https://salsa.debian.org/security-tracker-team/security-tracker"
|
"Vulnerabilities": [
|
||||||
},
|
|
||||||
"ratings": [
|
|
||||||
{
|
{
|
||||||
"source": {
|
"VulnerabilityID": "CVE-2020-8165",
|
||||||
"name": "cbl-mariner"
|
"PkgName": "activesupport",
|
||||||
|
"InstalledVersion": "6.0.2.1",
|
||||||
|
"FixedVersion": "6.0.3.1, 5.2.4.3",
|
||||||
|
"Layer": {},
|
||||||
|
"SeveritySource": "ghsa",
|
||||||
|
"PrimaryURL": "https://avd.aquasec.com/nvd/cve-2020-8165",
|
||||||
|
"PkgRef": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec",
|
||||||
|
"DataSource": {
|
||||||
|
"ID": "ghsa",
|
||||||
|
"Name": "GitHub Security Advisory RubyGems",
|
||||||
|
"URL": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Arubygems"
|
||||||
},
|
},
|
||||||
"severity": "high"
|
"Title": "rubygem-activesupport: potentially unintended unmarshalling of user-provided objects in MemCacheStore and RedisCacheStore",
|
||||||
},
|
"Description": "A deserialization of untrusted data vulnerability exists in rails \u003c 5.2.4.3, rails \u003c 6.0.3.1 that can allow an attacker to unmarshal user-provided objects in MemCacheStore and RedisCacheStore potentially resulting in an RCE.",
|
||||||
{
|
"Severity": "HIGH",
|
||||||
"source": {
|
"CweIDs": [
|
||||||
"name": "nvd"
|
"CWE-502"
|
||||||
},
|
|
||||||
"score": 7.2,
|
|
||||||
"severity": "high",
|
|
||||||
"method": "CVSSv2",
|
|
||||||
"vector": "AV:L/AC:L/Au:N/C:C/I:C/A:C"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "nvd"
|
|
||||||
},
|
|
||||||
"score": 7.8,
|
|
||||||
"severity": "high",
|
|
||||||
"method": "CVSSv31",
|
|
||||||
"vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "oracle-oval"
|
|
||||||
},
|
|
||||||
"severity": "low"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "photon"
|
|
||||||
},
|
|
||||||
"severity": "high"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "redhat"
|
|
||||||
},
|
|
||||||
"score": 7.8,
|
|
||||||
"severity": "low",
|
|
||||||
"method": "CVSSv31",
|
|
||||||
"vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "ubuntu"
|
|
||||||
},
|
|
||||||
"severity": "low"
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
"cwes": [
|
"CVSS": {
|
||||||
273
|
"nvd": {
|
||||||
|
"V2Vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P",
|
||||||
|
"V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||||
|
"V2Score": 7.5,
|
||||||
|
"V3Score": 9.8
|
||||||
|
},
|
||||||
|
"redhat": {
|
||||||
|
"V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
|
||||||
|
"V3Score": 9.8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"References": [
|
||||||
|
"http://lists.opensuse.org/opensuse-security-announce/2020-10/msg00031.html",
|
||||||
|
"http://lists.opensuse.org/opensuse-security-announce/2020-10/msg00034.html",
|
||||||
|
"https://access.redhat.com/security/cve/CVE-2020-8165",
|
||||||
|
"https://github.com/advisories/GHSA-2p68-f74v-9wc6",
|
||||||
|
"https://github.com/rubysec/ruby-advisory-db/blob/master/gems/activesupport/CVE-2020-8165.yml",
|
||||||
|
"https://groups.google.com/forum/#!msg/rubyonrails-security/bv6fW4S0Y1c/KnkEqM7AAQAJ",
|
||||||
|
"https://groups.google.com/forum/#!topic/rubyonrails-security/bv6fW4S0Y1c",
|
||||||
|
"https://groups.google.com/g/rubyonrails-security/c/bv6fW4S0Y1c",
|
||||||
|
"https://hackerone.com/reports/413388",
|
||||||
|
"https://lists.debian.org/debian-lts-announce/2020/06/msg00022.html",
|
||||||
|
"https://lists.debian.org/debian-lts-announce/2020/07/msg00013.html",
|
||||||
|
"https://nvd.nist.gov/vuln/detail/CVE-2020-8165",
|
||||||
|
"https://weblog.rubyonrails.org/2020/5/18/Rails-5-2-4-3-and-6-0-3-1-have-been-released/",
|
||||||
|
"https://www.debian.org/security/2020/dsa-4766"
|
||||||
],
|
],
|
||||||
"description": "An issue was discovered in disable_priv_mode in shell.c in GNU Bash through 5.0 patch 11. By default, if Bash is run with its effective UID not equal to its real UID, it will drop privileges by setting its effective UID to its real UID. However, it does so incorrectly. On Linux and other systems that support \"saved UID\" functionality, the saved UID is not dropped. An attacker with command execution in the shell can use \"enable -f\" for runtime loading of a new builtin, which can be a shared object that calls setuid() and therefore regains privileges. However, binaries running with an effective UID of 0 are unaffected.",
|
"PublishedDate": "2020-06-19T18:15:00Z",
|
||||||
"advisories": [
|
"LastModifiedDate": "2020-10-17T12:15:00Z"
|
||||||
{
|
|
||||||
"url": "http://packetstormsecurity.com/files/155498/Bash-5.0-Patch-11-Privilege-Escalation.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://access.redhat.com/security/cve/CVE-2019-18276"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18276"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/bminor/bash/commit/951bdaad7a18cc0dc1036bba86b18b90874d39ff"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://linux.oracle.com/cve/CVE-2019-18276.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://linux.oracle.com/errata/ELSA-2021-1679.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772@%3Cdev.mina.apache.org%3E"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://nvd.nist.gov/vuln/detail/CVE-2019-18276"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://security.gentoo.org/glsa/202105-34"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://security.netapp.com/advisory/ntap-20200430-0003/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.youtube.com/watch?v=-wGtxJ8opa8"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"published": "2019-11-28T01:15:00+00:00",
|
|
||||||
"updated": "2021-05-26T12:15:00+00:00",
|
|
||||||
"affects": [
|
|
||||||
{
|
|
||||||
"ref": "urn:cdx:31ee662c-480e-4f63-9765-23ea8afc754d/1#pkg:deb/debian/bash@5.0-4?distro=debian-10.2",
|
|
||||||
"versions": [
|
|
||||||
{
|
|
||||||
"version": "5.0-4",
|
|
||||||
"status": "affected"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "CVE-2019-18224",
|
|
||||||
"source": {
|
|
||||||
"name": "debian",
|
|
||||||
"url": "https://salsa.debian.org/security-tracker-team/security-tracker"
|
|
||||||
},
|
|
||||||
"ratings": [
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "amazon"
|
|
||||||
},
|
|
||||||
"severity": "medium"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "nvd"
|
|
||||||
},
|
|
||||||
"score": 7.5,
|
|
||||||
"severity": "high",
|
|
||||||
"method": "CVSSv2",
|
|
||||||
"vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "nvd"
|
|
||||||
},
|
|
||||||
"score": 9.8,
|
|
||||||
"severity": "critical",
|
|
||||||
"method": "CVSSv31",
|
|
||||||
"vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "redhat"
|
|
||||||
},
|
|
||||||
"score": 5.6,
|
|
||||||
"severity": "medium",
|
|
||||||
"method": "CVSSv3",
|
|
||||||
"vector": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": {
|
|
||||||
"name": "ubuntu"
|
|
||||||
},
|
|
||||||
"severity": "medium"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"cwes": [
|
|
||||||
787
|
|
||||||
],
|
|
||||||
"description": "idn2_to_ascii_4i in lib/lookup.c in GNU libidn2 before 2.1.1 has a heap-based buffer overflow via a long domain string.",
|
|
||||||
"recommendation": "Upgrade libidn2-0 to version 2.0.5-1+deb10u1",
|
|
||||||
"advisories": [
|
|
||||||
{
|
|
||||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00008.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00009.html"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://access.redhat.com/security/cve/CVE-2019-18224"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=12420"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18224"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/libidn/libidn2/commit/e4d1558aa2c1c04a05066ee8600f37603890ba8c"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/libidn/libidn2/compare/libidn2-2.1.0...libidn2-2.1.1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/JDQVQ2XPV5BTZUFINT7AFJSKNNBVURNJ/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MINU5RKDFE6TKAFY5DRFN3WSFDS4DYVS/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://seclists.org/bugtraq/2020/Feb/4"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://security.gentoo.org/glsa/202003-63"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://ubuntu.com/security/notices/USN-4168-1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://usn.ubuntu.com/4168-1/"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://www.debian.org/security/2020/dsa-4613"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"published": "2019-10-21T17:15:00+00:00",
|
|
||||||
"updated": "2019-10-29T19:15:00+00:00",
|
|
||||||
"affects": [
|
|
||||||
{
|
|
||||||
"ref": "urn:cdx:31ee662c-480e-4f63-9765-23ea8afc754d/1#pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2",
|
|
||||||
"versions": [
|
|
||||||
{
|
|
||||||
"version": "2.0.5-1",
|
|
||||||
"status": "affected"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1110,9 +1110,6 @@ func NewSBOMCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command {
|
|||||||
Example: ` # Scan CycloneDX and show the result in tables
|
Example: ` # Scan CycloneDX and show the result in tables
|
||||||
$ trivy sbom /path/to/report.cdx
|
$ trivy sbom /path/to/report.cdx
|
||||||
|
|
||||||
# Scan CycloneDX and generate a CycloneDX report
|
|
||||||
$ trivy sbom --format cyclonedx /path/to/report.cdx
|
|
||||||
|
|
||||||
# Scan CycloneDX-type attestation and show the result in tables
|
# Scan CycloneDX-type attestation and show the result in tables
|
||||||
$ trivy sbom /path/to/report.cdx.intoto.jsonl
|
$ trivy sbom /path/to/report.cdx.intoto.jsonl
|
||||||
`,
|
`,
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import (
|
|||||||
cdx "github.com/CycloneDX/cyclonedx-go"
|
cdx "github.com/CycloneDX/cyclonedx-go"
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/log"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx"
|
"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx"
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
)
|
)
|
||||||
@@ -29,18 +27,7 @@ func NewWriter(output io.Writer, appVersion string) Writer {
|
|||||||
|
|
||||||
// Write writes the results in CycloneDX format
|
// Write writes the results in CycloneDX format
|
||||||
func (w Writer) Write(report types.Report) error {
|
func (w Writer) Write(report types.Report) error {
|
||||||
var bom *cdx.BOM
|
bom, err := w.marshaler.Marshal(report)
|
||||||
var err error
|
|
||||||
|
|
||||||
// When the input is CycloneDX, only vulnerabilities will be stored in CycloneDX.
|
|
||||||
// Each vulnerability has a reference to a component in the original CycloneDX.
|
|
||||||
// e.g. "urn:cdx:3e671687-395b-41f5-a30f-a58921a69b79/1#jackson-databind-2.8.0"
|
|
||||||
if report.ArtifactType == ftypes.ArtifactCycloneDX {
|
|
||||||
log.Logger.Info("Components will not be exported in the CycloneDX report as the input is CycloneDX")
|
|
||||||
bom, err = w.marshaler.MarshalVulnerabilities(report)
|
|
||||||
} else {
|
|
||||||
bom, err = w.marshaler.Marshal(report)
|
|
||||||
}
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return xerrors.Errorf("CycloneDX marshal error: %w", err)
|
return xerrors.Errorf("CycloneDX marshal error: %w", err)
|
||||||
}
|
}
|
||||||
|
|||||||
489
pkg/sbom/cyclonedx/core/cyclonedx.go
Normal file
489
pkg/sbom/cyclonedx/core/cyclonedx.go
Normal file
@@ -0,0 +1,489 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
cdx "github.com/CycloneDX/cyclonedx-go"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/samber/lo"
|
||||||
|
"k8s.io/utils/clock"
|
||||||
|
|
||||||
|
dtypes "github.com/aquasecurity/trivy-db/pkg/types"
|
||||||
|
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/digest"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/log"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/purl"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
ToolVendor = "aquasecurity"
|
||||||
|
ToolName = "trivy"
|
||||||
|
Namespace = ToolVendor + ":" + ToolName + ":"
|
||||||
|
|
||||||
|
// https://json-schema.org/understanding-json-schema/reference/string.html#dates-and-times
|
||||||
|
timeLayout = "2006-01-02T15:04:05+00:00"
|
||||||
|
)
|
||||||
|
|
||||||
|
type NewUUID func() uuid.UUID
|
||||||
|
|
||||||
|
type Option func(dx *CycloneDX)
|
||||||
|
|
||||||
|
func WithClock(clock clock.Clock) Option {
|
||||||
|
return func(opts *CycloneDX) {
|
||||||
|
opts.clock = clock
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithNewUUID(newUUID NewUUID) Option {
|
||||||
|
return func(opts *CycloneDX) {
|
||||||
|
opts.newUUID = newUUID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type CycloneDX struct {
|
||||||
|
appVersion string
|
||||||
|
clock clock.Clock
|
||||||
|
newUUID NewUUID
|
||||||
|
}
|
||||||
|
|
||||||
|
type Component struct {
|
||||||
|
Type cdx.ComponentType
|
||||||
|
Name string
|
||||||
|
Version string
|
||||||
|
PackageURL *purl.PackageURL
|
||||||
|
Licenses []string
|
||||||
|
Hashes []digest.Digest
|
||||||
|
Supplier string
|
||||||
|
Properties map[string]string
|
||||||
|
|
||||||
|
Components []*Component
|
||||||
|
Vulnerabilities []types.DetectedVulnerability
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewCycloneDX(version string, opts ...Option) *CycloneDX {
|
||||||
|
c := &CycloneDX{
|
||||||
|
appVersion: version,
|
||||||
|
clock: clock.RealClock{},
|
||||||
|
newUUID: uuid.New,
|
||||||
|
}
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CycloneDX) Marshal(root *Component) *cdx.BOM {
|
||||||
|
bom := cdx.NewBOM()
|
||||||
|
bom.SerialNumber = c.newUUID().URN()
|
||||||
|
bom.Metadata = c.Metadata()
|
||||||
|
|
||||||
|
components := map[string]*cdx.Component{}
|
||||||
|
dependencies := map[string]*[]string{}
|
||||||
|
vulnerabilities := map[string]*cdx.Vulnerability{}
|
||||||
|
bom.Metadata.Component = c.MarshalComponent(root, components, dependencies, vulnerabilities)
|
||||||
|
|
||||||
|
// Remove metadata component
|
||||||
|
delete(components, bom.Metadata.Component.BOMRef)
|
||||||
|
|
||||||
|
bom.Components = c.Components(components)
|
||||||
|
bom.Dependencies = c.Dependencies(dependencies)
|
||||||
|
bom.Vulnerabilities = c.Vulnerabilities(vulnerabilities)
|
||||||
|
|
||||||
|
return bom
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CycloneDX) MarshalComponent(component *Component, components map[string]*cdx.Component,
|
||||||
|
deps map[string]*[]string, vulns map[string]*cdx.Vulnerability) *cdx.Component {
|
||||||
|
bomRef := c.BOMRef(component)
|
||||||
|
|
||||||
|
// When multiple lock files have the same dependency with the same name and version,
|
||||||
|
// "BOM-Ref" (PURL technically) of "Library" components may conflict.
|
||||||
|
// In that case, only one "Library" component will be added and
|
||||||
|
// some "Application" components will refer to the same component.
|
||||||
|
// e.g.
|
||||||
|
// Application component (/app1/package-lock.json)
|
||||||
|
// |
|
||||||
|
// | Application component (/app2/package-lock.json)
|
||||||
|
// | |
|
||||||
|
// └----┴----> Library component (npm package, express-4.17.3)
|
||||||
|
//
|
||||||
|
if v, ok := components[bomRef]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
cdxComponent := &cdx.Component{
|
||||||
|
BOMRef: bomRef,
|
||||||
|
Type: component.Type,
|
||||||
|
Name: component.Name,
|
||||||
|
Version: component.Version,
|
||||||
|
PackageURL: c.PackageURL(component.PackageURL),
|
||||||
|
Supplier: c.Supplier(component.Supplier),
|
||||||
|
Hashes: c.Hashes(component.Hashes),
|
||||||
|
Licenses: c.Licenses(component.Licenses),
|
||||||
|
Properties: lo.ToPtr(c.Properties(component.Properties)),
|
||||||
|
}
|
||||||
|
components[cdxComponent.BOMRef] = cdxComponent
|
||||||
|
|
||||||
|
for _, v := range component.Vulnerabilities {
|
||||||
|
// If the same vulnerability affects multiple packages, those packages will be aggregated into one vulnerability.
|
||||||
|
// Vulnerability component (CVE-2020-26247)
|
||||||
|
// -> Library component (nokogiri /srv/app1/vendor/bundle/ruby/3.0.0/specifications/nokogiri-1.10.0.gemspec)
|
||||||
|
// -> Library component (nokogiri /srv/app2/vendor/bundle/ruby/3.0.0/specifications/nokogiri-1.10.0.gemspec)
|
||||||
|
if vuln, ok := vulns[v.VulnerabilityID]; ok {
|
||||||
|
*vuln.Affects = append(*vuln.Affects, cdxAffects(bomRef, v.InstalledVersion))
|
||||||
|
} else {
|
||||||
|
vulns[v.VulnerabilityID] = c.marshalVulnerability(cdxComponent.BOMRef, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var dependencies []string
|
||||||
|
for _, child := range component.Components {
|
||||||
|
childComponent := c.MarshalComponent(child, components, deps, vulns)
|
||||||
|
dependencies = append(dependencies, childComponent.BOMRef)
|
||||||
|
}
|
||||||
|
sort.Strings(dependencies)
|
||||||
|
|
||||||
|
deps[cdxComponent.BOMRef] = &dependencies
|
||||||
|
|
||||||
|
return cdxComponent
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CycloneDX) marshalVulnerability(bomRef string, vuln types.DetectedVulnerability) *cdx.Vulnerability {
|
||||||
|
v := &cdx.Vulnerability{
|
||||||
|
ID: vuln.VulnerabilityID,
|
||||||
|
Source: cdxSource(vuln.DataSource),
|
||||||
|
Ratings: cdxRatings(vuln),
|
||||||
|
CWEs: cwes(vuln.CweIDs),
|
||||||
|
Description: vuln.Description,
|
||||||
|
Advisories: cdxAdvisories(vuln.References),
|
||||||
|
}
|
||||||
|
if vuln.FixedVersion != "" {
|
||||||
|
v.Recommendation = fmt.Sprintf("Upgrade %s to version %s", vuln.PkgName, vuln.FixedVersion)
|
||||||
|
}
|
||||||
|
if vuln.PublishedDate != nil {
|
||||||
|
v.Published = vuln.PublishedDate.Format(timeLayout)
|
||||||
|
}
|
||||||
|
if vuln.LastModifiedDate != nil {
|
||||||
|
v.Updated = vuln.LastModifiedDate.Format(timeLayout)
|
||||||
|
}
|
||||||
|
|
||||||
|
v.Affects = &[]cdx.Affects{cdxAffects(bomRef, vuln.InstalledVersion)}
|
||||||
|
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CycloneDX) BOMRef(component *Component) string {
|
||||||
|
// PURL takes precedence over UUID
|
||||||
|
if component.PackageURL == nil {
|
||||||
|
return c.newUUID().String()
|
||||||
|
}
|
||||||
|
return component.PackageURL.BOMRef()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CycloneDX) Metadata() *cdx.Metadata {
|
||||||
|
return &cdx.Metadata{
|
||||||
|
Timestamp: c.clock.Now().UTC().Format(timeLayout),
|
||||||
|
Tools: &[]cdx.Tool{
|
||||||
|
{
|
||||||
|
Vendor: ToolVendor,
|
||||||
|
Name: ToolName,
|
||||||
|
Version: c.appVersion,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CycloneDX) Components(uniq map[string]*cdx.Component) *[]cdx.Component {
|
||||||
|
// Convert components from map to slice and sort by BOM-Ref
|
||||||
|
components := lo.MapToSlice(uniq, func(_ string, value *cdx.Component) cdx.Component {
|
||||||
|
return *value
|
||||||
|
})
|
||||||
|
sort.Slice(components, func(i, j int) bool {
|
||||||
|
return components[i].BOMRef < components[j].BOMRef
|
||||||
|
})
|
||||||
|
return &components
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CycloneDX) Dependencies(uniq map[string]*[]string) *[]cdx.Dependency {
|
||||||
|
// Convert dependencies from map to slice and sort by BOM-Ref
|
||||||
|
dependencies := lo.MapToSlice(uniq, func(bomRef string, value *[]string) cdx.Dependency {
|
||||||
|
return cdx.Dependency{
|
||||||
|
Ref: bomRef,
|
||||||
|
Dependencies: value,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
sort.Slice(dependencies, func(i, j int) bool {
|
||||||
|
return dependencies[i].Ref < dependencies[j].Ref
|
||||||
|
})
|
||||||
|
return &dependencies
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CycloneDX) Vulnerabilities(uniq map[string]*cdx.Vulnerability) *[]cdx.Vulnerability {
|
||||||
|
vulns := lo.MapToSlice(uniq, func(bomRef string, value *cdx.Vulnerability) cdx.Vulnerability {
|
||||||
|
sort.Slice(*value.Affects, func(i, j int) bool {
|
||||||
|
return (*value.Affects)[i].Ref < (*value.Affects)[j].Ref
|
||||||
|
})
|
||||||
|
return *value
|
||||||
|
})
|
||||||
|
sort.Slice(vulns, func(i, j int) bool {
|
||||||
|
return vulns[i].BOMRef < vulns[j].BOMRef
|
||||||
|
})
|
||||||
|
return &vulns
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CycloneDX) PackageURL(purl *purl.PackageURL) string {
|
||||||
|
if purl == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return purl.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CycloneDX) Supplier(supplier string) *cdx.OrganizationalEntity {
|
||||||
|
if supplier == "" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &cdx.OrganizationalEntity{
|
||||||
|
Name: supplier,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CycloneDX) Hashes(hashes []digest.Digest) *[]cdx.Hash {
|
||||||
|
if len(hashes) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var cdxHashes []cdx.Hash
|
||||||
|
for _, hash := range hashes {
|
||||||
|
var alg cdx.HashAlgorithm
|
||||||
|
switch hash.Algorithm() {
|
||||||
|
case digest.SHA1:
|
||||||
|
alg = cdx.HashAlgoSHA1
|
||||||
|
case digest.SHA256:
|
||||||
|
alg = cdx.HashAlgoSHA256
|
||||||
|
case digest.MD5:
|
||||||
|
alg = cdx.HashAlgoMD5
|
||||||
|
default:
|
||||||
|
log.Logger.Debugf("Unable to convert %q algorithm to CycloneDX format", hash.Algorithm())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
cdxHashes = append(cdxHashes, cdx.Hash{
|
||||||
|
Algorithm: alg,
|
||||||
|
Value: hash.Encoded(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return &cdxHashes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CycloneDX) Licenses(licenses []string) *cdx.Licenses {
|
||||||
|
if len(licenses) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
choices := lo.Map(licenses, func(license string, i int) cdx.LicenseChoice {
|
||||||
|
return cdx.LicenseChoice{Expression: license}
|
||||||
|
})
|
||||||
|
return lo.ToPtr(cdx.Licenses(choices))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CycloneDX) Properties(props map[string]string) []cdx.Property {
|
||||||
|
properties := lo.MapToSlice(props, func(k, v string) cdx.Property {
|
||||||
|
return cdx.Property{
|
||||||
|
Name: Namespace + k,
|
||||||
|
Value: v,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
sort.Slice(properties, func(i, j int) bool {
|
||||||
|
return properties[i].Name < properties[j].Name
|
||||||
|
})
|
||||||
|
return properties
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsTrivySBOM(c *cdx.BOM) bool {
|
||||||
|
if c == nil || c.Metadata == nil || c.Metadata.Tools == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tool := range *c.Metadata.Tools {
|
||||||
|
if tool.Vendor == ToolVendor && tool.Name == ToolName {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func LookupProperty(properties *[]cdx.Property, key string) string {
|
||||||
|
for _, p := range lo.FromPtr(properties) {
|
||||||
|
if p.Name == Namespace+key {
|
||||||
|
return p.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func UnmarshalProperties(properties *[]cdx.Property) map[string]string {
|
||||||
|
props := map[string]string{}
|
||||||
|
for _, prop := range lo.FromPtr(properties) {
|
||||||
|
if !strings.HasPrefix(prop.Name, Namespace) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
props[strings.TrimPrefix(prop.Name, Namespace)] = prop.Value
|
||||||
|
}
|
||||||
|
return props
|
||||||
|
}
|
||||||
|
|
||||||
|
func cdxAdvisories(refs []string) *[]cdx.Advisory {
|
||||||
|
var advs []cdx.Advisory
|
||||||
|
for _, ref := range refs {
|
||||||
|
advs = append(advs, cdx.Advisory{
|
||||||
|
URL: ref,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return &advs
|
||||||
|
}
|
||||||
|
|
||||||
|
func cwes(cweIDs []string) *[]int {
|
||||||
|
// to skip cdx.Vulnerability.CWEs when generating json
|
||||||
|
// we should return 'clear' nil without 'type' interface part
|
||||||
|
if cweIDs == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var ret []int
|
||||||
|
for _, cweID := range cweIDs {
|
||||||
|
number, err := strconv.Atoi(strings.TrimPrefix(strings.ToLower(cweID), "cwe-"))
|
||||||
|
if err != nil {
|
||||||
|
log.Logger.Debugf("cwe id parse error: %s", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ret = append(ret, number)
|
||||||
|
}
|
||||||
|
return &ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func cdxRatings(vulnerability types.DetectedVulnerability) *[]cdx.VulnerabilityRating {
|
||||||
|
rates := make([]cdx.VulnerabilityRating, 0) // To export an empty array in JSON
|
||||||
|
for sourceID, severity := range vulnerability.VendorSeverity {
|
||||||
|
// When the vendor also provides CVSS score/vector
|
||||||
|
if cvss, ok := vulnerability.CVSS[sourceID]; ok {
|
||||||
|
if cvss.V2Score != 0 || cvss.V2Vector != "" {
|
||||||
|
rates = append(rates, cdxRatingV2(sourceID, severity, cvss))
|
||||||
|
}
|
||||||
|
if cvss.V3Score != 0 || cvss.V3Vector != "" {
|
||||||
|
rates = append(rates, cdxRatingV3(sourceID, severity, cvss))
|
||||||
|
}
|
||||||
|
} else { // When the vendor provides only severity
|
||||||
|
rate := cdx.VulnerabilityRating{
|
||||||
|
Source: &cdx.Source{
|
||||||
|
Name: string(sourceID),
|
||||||
|
},
|
||||||
|
Severity: toCDXSeverity(severity),
|
||||||
|
}
|
||||||
|
rates = append(rates, rate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For consistency
|
||||||
|
sort.Slice(rates, func(i, j int) bool {
|
||||||
|
if rates[i].Source.Name != rates[j].Source.Name {
|
||||||
|
return rates[i].Source.Name < rates[j].Source.Name
|
||||||
|
}
|
||||||
|
if rates[i].Method != rates[j].Method {
|
||||||
|
return rates[i].Method < rates[j].Method
|
||||||
|
}
|
||||||
|
if rates[i].Score != nil && rates[j].Score != nil {
|
||||||
|
return *rates[i].Score < *rates[j].Score
|
||||||
|
}
|
||||||
|
return rates[i].Vector < rates[j].Vector
|
||||||
|
})
|
||||||
|
return &rates
|
||||||
|
}
|
||||||
|
|
||||||
|
func cdxRatingV2(sourceID dtypes.SourceID, severity dtypes.Severity, cvss dtypes.CVSS) cdx.VulnerabilityRating {
|
||||||
|
cdxSeverity := toCDXSeverity(severity)
|
||||||
|
|
||||||
|
// Trivy keeps only CVSSv3 severity for NVD.
|
||||||
|
// The CVSSv2 severity must be calculated according to CVSSv2 score.
|
||||||
|
if sourceID == vulnerability.NVD {
|
||||||
|
cdxSeverity = nvdSeverityV2(cvss.V2Score)
|
||||||
|
}
|
||||||
|
return cdx.VulnerabilityRating{
|
||||||
|
Source: &cdx.Source{
|
||||||
|
Name: string(sourceID),
|
||||||
|
},
|
||||||
|
Score: &cvss.V2Score,
|
||||||
|
Method: cdx.ScoringMethodCVSSv2,
|
||||||
|
Severity: cdxSeverity,
|
||||||
|
Vector: cvss.V2Vector,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cdxRatingV3(sourceID dtypes.SourceID, severity dtypes.Severity, cvss dtypes.CVSS) cdx.VulnerabilityRating {
|
||||||
|
rate := cdx.VulnerabilityRating{
|
||||||
|
Source: &cdx.Source{
|
||||||
|
Name: string(sourceID),
|
||||||
|
},
|
||||||
|
Score: &cvss.V3Score,
|
||||||
|
Method: cdx.ScoringMethodCVSSv3,
|
||||||
|
Severity: toCDXSeverity(severity),
|
||||||
|
Vector: cvss.V3Vector,
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(cvss.V3Vector, "CVSS:3.1") {
|
||||||
|
rate.Method = cdx.ScoringMethodCVSSv31
|
||||||
|
}
|
||||||
|
return rate
|
||||||
|
}
|
||||||
|
|
||||||
|
func nvdSeverityV2(score float64) cdx.Severity {
|
||||||
|
// cf. https://nvd.nist.gov/vuln-metrics/cvss
|
||||||
|
switch {
|
||||||
|
case score < 4.0:
|
||||||
|
return cdx.SeverityInfo
|
||||||
|
case 4.0 <= score && score < 7.0:
|
||||||
|
return cdx.SeverityMedium
|
||||||
|
case 7.0 <= score:
|
||||||
|
return cdx.SeverityHigh
|
||||||
|
}
|
||||||
|
return cdx.SeverityUnknown
|
||||||
|
}
|
||||||
|
|
||||||
|
func toCDXSeverity(s dtypes.Severity) cdx.Severity {
|
||||||
|
switch s {
|
||||||
|
case dtypes.SeverityLow:
|
||||||
|
return cdx.SeverityLow
|
||||||
|
case dtypes.SeverityMedium:
|
||||||
|
return cdx.SeverityMedium
|
||||||
|
case dtypes.SeverityHigh:
|
||||||
|
return cdx.SeverityHigh
|
||||||
|
case dtypes.SeverityCritical:
|
||||||
|
return cdx.SeverityCritical
|
||||||
|
default:
|
||||||
|
return cdx.SeverityUnknown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cdxSource(source *dtypes.DataSource) *cdx.Source {
|
||||||
|
if source == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cdx.Source{
|
||||||
|
Name: string(source.ID),
|
||||||
|
URL: source.URL,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func cdxAffects(ref, version string) cdx.Affects {
|
||||||
|
return cdx.Affects{
|
||||||
|
Ref: ref,
|
||||||
|
Range: &[]cdx.AffectedVersions{
|
||||||
|
{
|
||||||
|
Version: version,
|
||||||
|
Status: cdx.VulnerabilityStatusAffected,
|
||||||
|
// "AffectedVersions.Range" is not included, because it does not exist in DetectedVulnerability.
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,32 +2,22 @@ package cyclonedx
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
cdx "github.com/CycloneDX/cyclonedx-go"
|
cdx "github.com/CycloneDX/cyclonedx-go"
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
"golang.org/x/exp/maps"
|
|
||||||
"golang.org/x/xerrors"
|
"golang.org/x/xerrors"
|
||||||
"k8s.io/utils/clock"
|
|
||||||
|
|
||||||
dtypes "github.com/aquasecurity/trivy-db/pkg/types"
|
|
||||||
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
|
|
||||||
"github.com/aquasecurity/trivy/pkg/digest"
|
"github.com/aquasecurity/trivy/pkg/digest"
|
||||||
ftypes "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/purl"
|
||||||
|
"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx/core"
|
||||||
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
"github.com/aquasecurity/trivy/pkg/scanner/utils"
|
||||||
"github.com/aquasecurity/trivy/pkg/types"
|
"github.com/aquasecurity/trivy/pkg/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ToolVendor = "aquasecurity"
|
|
||||||
ToolName = "trivy"
|
|
||||||
Namespace = ToolVendor + ":" + ToolName + ":"
|
|
||||||
|
|
||||||
PropertySchemaVersion = "SchemaVersion"
|
PropertySchemaVersion = "SchemaVersion"
|
||||||
PropertyType = "Type"
|
PropertyType = "Type"
|
||||||
PropertyClass = "Class"
|
PropertyClass = "Class"
|
||||||
@@ -50,9 +40,6 @@ const (
|
|||||||
PropertyFilePath = "FilePath"
|
PropertyFilePath = "FilePath"
|
||||||
PropertyLayerDigest = "LayerDigest"
|
PropertyLayerDigest = "LayerDigest"
|
||||||
PropertyLayerDiffID = "LayerDiffID"
|
PropertyLayerDiffID = "LayerDiffID"
|
||||||
|
|
||||||
// https://json-schema.org/understanding-json-schema/reference/string.html#dates-and-times
|
|
||||||
timeLayout = "2006-01-02T15:04:05+00:00"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -60,223 +47,44 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Marshaler struct {
|
type Marshaler struct {
|
||||||
appVersion string // Trivy version
|
core *core.CycloneDX
|
||||||
clock clock.Clock
|
|
||||||
newUUID newUUID
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type newUUID func() uuid.UUID
|
func NewMarshaler(version string, opts ...core.Option) *Marshaler {
|
||||||
|
return &Marshaler{
|
||||||
type marshalOption func(*Marshaler)
|
core: core.NewCycloneDX(version, opts...),
|
||||||
|
|
||||||
func WithClock(clock clock.Clock) marshalOption {
|
|
||||||
return func(opts *Marshaler) {
|
|
||||||
opts.clock = clock
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func WithNewUUID(newUUID newUUID) marshalOption {
|
|
||||||
return func(opts *Marshaler) {
|
|
||||||
opts.newUUID = newUUID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewMarshaler(version string, opts ...marshalOption) *Marshaler {
|
|
||||||
e := &Marshaler{
|
|
||||||
appVersion: version,
|
|
||||||
clock: clock.RealClock{},
|
|
||||||
newUUID: uuid.New,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, opt := range opts {
|
|
||||||
opt(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marshal converts the Trivy report to the CycloneDX format
|
// Marshal converts the Trivy report to the CycloneDX format
|
||||||
func (e *Marshaler) Marshal(report types.Report) (*cdx.BOM, error) {
|
func (e *Marshaler) Marshal(report types.Report) (*cdx.BOM, error) {
|
||||||
bom := cdx.NewBOM()
|
// Convert
|
||||||
bom.SerialNumber = e.newUUID().URN()
|
root, err := e.MarshalReport(report)
|
||||||
metadataComponent, err := e.reportToCdxComponent(report)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to parse metadata component: %w", err)
|
return nil, xerrors.Errorf("failed to marshal report: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bom.Metadata = e.cdxMetadata()
|
return e.core.Marshal(root), nil
|
||||||
bom.Metadata.Component = metadataComponent
|
|
||||||
|
|
||||||
bom.Components, bom.Dependencies, bom.Vulnerabilities, err = e.marshalComponents(report, bom.Metadata.Component.BOMRef)
|
|
||||||
if err != nil {
|
|
||||||
return nil, xerrors.Errorf("failed to parse components: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return bom, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalVulnerabilities converts the Trivy report to the CycloneDX format only with vulnerabilities.
|
func (e *Marshaler) MarshalReport(r types.Report) (*core.Component, error) {
|
||||||
// The output refers to another CycloneDX SBOM.
|
// Metadata component
|
||||||
func (e *Marshaler) MarshalVulnerabilities(report types.Report) (*cdx.BOM, error) {
|
root, err := e.rootComponent(r)
|
||||||
vulnMap := map[string]cdx.Vulnerability{}
|
|
||||||
for _, result := range report.Results {
|
|
||||||
for _, vuln := range result.Vulnerabilities {
|
|
||||||
ref, err := externalRef(report.CycloneDX.SerialNumber, vuln.PkgRef)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if v, ok := vulnMap[vuln.VulnerabilityID]; ok {
|
|
||||||
*v.Affects = append(*v.Affects, cdxAffects(ref, vuln.InstalledVersion))
|
|
||||||
} else {
|
|
||||||
vulnMap[vuln.VulnerabilityID] = toCdxVulnerability(ref, vuln)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vulns := maps.Values(vulnMap)
|
|
||||||
sort.Slice(vulns, func(i, j int) bool {
|
|
||||||
return vulns[i].ID > vulns[j].ID
|
|
||||||
})
|
|
||||||
|
|
||||||
bom := cdx.NewBOM()
|
|
||||||
bom.Metadata = e.cdxMetadata()
|
|
||||||
|
|
||||||
// Fill the detected vulnerabilities
|
|
||||||
bom.Vulnerabilities = &vulns
|
|
||||||
|
|
||||||
// Use the original component as is
|
|
||||||
bom.Metadata.Component = &cdx.Component{
|
|
||||||
Name: report.CycloneDX.Metadata.Component.Name,
|
|
||||||
Version: report.CycloneDX.Metadata.Component.Version,
|
|
||||||
Type: cdx.ComponentType(report.CycloneDX.Metadata.Component.Type),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Overwrite the bom ref as it must be the BOM ref of the original CycloneDX.
|
|
||||||
// e.g.
|
|
||||||
// "metadata" : {
|
|
||||||
// "timestamp" : "2022-07-02T00:00:00Z",
|
|
||||||
// "component" : {
|
|
||||||
// "name" : "Acme Product",
|
|
||||||
// "version": "2.4.0",
|
|
||||||
// "type" : "application",
|
|
||||||
// "bom-ref" : "urn:cdx:f08a6ccd-4dce-4759-bd84-c626675d60a7/1"
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
if report.CycloneDX.SerialNumber != "" { // bomRef is optional field - https://cyclonedx.org/docs/1.4/json/#metadata_component_bom-ref
|
|
||||||
bom.Metadata.Component.BOMRef = fmt.Sprintf("%s/%d", report.CycloneDX.SerialNumber, report.CycloneDX.Version)
|
|
||||||
}
|
|
||||||
return bom, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Marshaler) cdxMetadata() *cdx.Metadata {
|
|
||||||
return &cdx.Metadata{
|
|
||||||
Timestamp: e.clock.Now().UTC().Format(timeLayout),
|
|
||||||
Tools: &[]cdx.Tool{
|
|
||||||
{
|
|
||||||
Vendor: ToolVendor,
|
|
||||||
Name: ToolName,
|
|
||||||
Version: e.appVersion,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func externalRef(bomLink string, bomRef string) (string, error) {
|
|
||||||
// bomLink is optional field: https://cyclonedx.org/docs/1.4/json/#vulnerabilities_items_bom-ref
|
|
||||||
if bomLink == "" {
|
|
||||||
return bomRef, nil
|
|
||||||
}
|
|
||||||
if !strings.HasPrefix(bomLink, "urn:uuid:") {
|
|
||||||
return "", xerrors.Errorf("%q: %w", bomLink, ErrInvalidBOMLink)
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s/%d#%s", strings.Replace(bomLink, "uuid", "cdx", 1), cdx.BOMFileFormatJSON, bomRef), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *Marshaler) marshalComponents(r types.Report, bomRef string) (*[]cdx.Component, *[]cdx.Dependency, *[]cdx.Vulnerability, error) {
|
|
||||||
components := make([]cdx.Component, 0) // To export an empty array in JSON
|
|
||||||
// we use map to avoid duplicate components
|
|
||||||
dependencies := map[string]cdx.Dependency{}
|
|
||||||
metadataDependencies := make([]string, 0) // To export an empty array in JSON
|
|
||||||
libraryUniqMap := map[string]struct{}{}
|
|
||||||
vulnMap := map[string]cdx.Vulnerability{}
|
|
||||||
for _, result := range r.Results {
|
for _, result := range r.Results {
|
||||||
bomRefMap := map[string]string{}
|
components, err := e.marshalResult(r.Metadata, result)
|
||||||
pkgIDToRef := map[string]string{}
|
|
||||||
var directDepRefs []string
|
|
||||||
|
|
||||||
// Get dependency parents first
|
|
||||||
parents := ftypes.Packages(result.Packages).ParentDeps()
|
|
||||||
|
|
||||||
for _, pkg := range result.Packages {
|
|
||||||
pkgComponent, err := pkgToCdxComponent(result.Type, r.Metadata, result.Class, pkg)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, nil, xerrors.Errorf("failed to parse pkg: %w", err)
|
return nil, err
|
||||||
}
|
|
||||||
pkgID := packageID(result.Target, pkg.Name, utils.FormatVersion(pkg), pkg.FilePath)
|
|
||||||
bomRefMap[pkgID] = pkgComponent.BOMRef
|
|
||||||
if pkg.ID != "" {
|
|
||||||
pkgIDToRef[pkg.ID] = pkgComponent.BOMRef
|
|
||||||
}
|
|
||||||
// This package is a direct dependency
|
|
||||||
if !pkg.Indirect || len(parents[pkg.ID]) == 0 {
|
|
||||||
directDepRefs = append(directDepRefs, pkgComponent.BOMRef)
|
|
||||||
}
|
|
||||||
|
|
||||||
// When multiple lock files have the same dependency with the same name and version,
|
|
||||||
// "bom-ref" (PURL technically) of Library components may conflict.
|
|
||||||
// In that case, only one Library component will be added and
|
|
||||||
// some Application components will refer to the same component.
|
|
||||||
// e.g.
|
|
||||||
// Application component (/app1/package-lock.json)
|
|
||||||
// |
|
|
||||||
// | Application component (/app2/package-lock.json)
|
|
||||||
// | |
|
|
||||||
// └----┴----> Library component (npm package, express-4.17.3)
|
|
||||||
//
|
|
||||||
if _, ok := libraryUniqMap[pkgComponent.BOMRef]; !ok {
|
|
||||||
libraryUniqMap[pkgComponent.BOMRef] = struct{}{}
|
|
||||||
|
|
||||||
// For components
|
|
||||||
// ref. https://cyclonedx.org/use-cases/#inventory
|
|
||||||
components = append(components, pkgComponent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Iterate packages again to build dependency graph
|
|
||||||
for _, pkg := range result.Packages {
|
|
||||||
deps := lo.FilterMap(pkg.DependsOn, func(dep string, _ int) (string, bool) {
|
|
||||||
if ref, ok := pkgIDToRef[dep]; ok {
|
|
||||||
return ref, true
|
|
||||||
}
|
|
||||||
return "", false
|
|
||||||
})
|
|
||||||
if len(deps) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
sort.Strings(deps)
|
|
||||||
ref := pkgIDToRef[pkg.ID]
|
|
||||||
dependencies[ref] = cdx.Dependency{
|
|
||||||
Ref: ref,
|
|
||||||
Dependencies: &deps,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sort.Strings(directDepRefs)
|
|
||||||
|
|
||||||
for _, vuln := range result.Vulnerabilities {
|
|
||||||
// Take a bom-ref
|
|
||||||
pkgID := packageID(result.Target, vuln.PkgName, vuln.InstalledVersion, vuln.PkgPath)
|
|
||||||
ref := bomRefMap[pkgID]
|
|
||||||
if v, ok := vulnMap[vuln.VulnerabilityID]; ok {
|
|
||||||
// If a vulnerability depends on multiple packages,
|
|
||||||
// it will be commonised into a single vulnerability.
|
|
||||||
// Vulnerability component (CVE-2020-26247)
|
|
||||||
// -> Library component (nokogiri /srv/app1/vendor/bundle/ruby/3.0.0/specifications/nokogiri-1.10.0.gemspec)
|
|
||||||
// -> Library component (nokogiri /srv/app2/vendor/bundle/ruby/3.0.0/specifications/nokogiri-1.10.0.gemspec)
|
|
||||||
*v.Affects = append(*v.Affects, cdxAffects(ref, vuln.InstalledVersion))
|
|
||||||
} else {
|
|
||||||
vulnMap[vuln.VulnerabilityID] = toCdxVulnerability(ref, vuln)
|
|
||||||
}
|
}
|
||||||
|
root.Components = append(root.Components, components...)
|
||||||
}
|
}
|
||||||
|
return root, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Marshaler) marshalResult(metadata types.Metadata, result types.Result) ([]*core.Component, error) {
|
||||||
if result.Type == ftypes.NodePkg || result.Type == ftypes.PythonPkg ||
|
if result.Type == ftypes.NodePkg || result.Type == ftypes.PythonPkg ||
|
||||||
result.Type == ftypes.GemSpec || result.Type == ftypes.Jar || result.Type == ftypes.CondaPkg {
|
result.Type == ftypes.GemSpec || result.Type == ftypes.Jar || result.Type == ftypes.CondaPkg {
|
||||||
// If a package is language-specific package that isn't associated with a lock file,
|
// If a package is language-specific package that isn't associated with a lock file,
|
||||||
@@ -289,7 +97,11 @@ func (e *Marshaler) marshalComponents(r types.Report, bomRef string) (*[]cdx.Com
|
|||||||
// ref. https://cyclonedx.org/use-cases/#inventory
|
// ref. https://cyclonedx.org/use-cases/#inventory
|
||||||
|
|
||||||
// Dependency graph from #1 to #2
|
// Dependency graph from #1 to #2
|
||||||
metadataDependencies = append(metadataDependencies, directDepRefs...)
|
components, err := e.marshalPackages(metadata, result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return components, nil
|
||||||
} else if result.Class == types.ClassOSPkg || result.Class == types.ClassLangPkg {
|
} else if result.Class == types.ClassOSPkg || result.Class == types.ClassLangPkg {
|
||||||
// If a package is OS package, it will be a dependency of "Operating System" component.
|
// If a package is OS package, it will be a dependency of "Operating System" component.
|
||||||
// e.g.
|
// e.g.
|
||||||
@@ -308,120 +120,149 @@ func (e *Marshaler) marshalComponents(r types.Report, bomRef string) (*[]cdx.Com
|
|||||||
// -> Library component (npm package, lodash-4.17.21) --- #3
|
// -> Library component (npm package, lodash-4.17.21) --- #3
|
||||||
// -> etc.
|
// -> etc.
|
||||||
|
|
||||||
resultComponent := e.resultToCdxComponent(result, r.Metadata.OS)
|
// #2
|
||||||
components = append(components, resultComponent)
|
appComponent := e.resultComponent(result, metadata.OS)
|
||||||
|
|
||||||
|
// #3
|
||||||
|
components, err := e.marshalPackages(metadata, result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
// Dependency graph from #2 to #3
|
// Dependency graph from #2 to #3
|
||||||
dependencies[resultComponent.BOMRef] = cdx.Dependency{
|
appComponent.Components = components
|
||||||
Ref: resultComponent.BOMRef,
|
|
||||||
Dependencies: &directDepRefs,
|
|
||||||
}
|
|
||||||
// Dependency graph from #1 to #2
|
// Dependency graph from #1 to #2
|
||||||
metadataDependencies = append(metadataDependencies, resultComponent.BOMRef)
|
return []*core.Component{appComponent}, nil
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
vulns := maps.Values(vulnMap)
|
func (e *Marshaler) marshalPackages(metadata types.Metadata, result types.Result) ([]*core.Component, error) {
|
||||||
sort.Slice(vulns, func(i, j int) bool {
|
// Get dependency parents first
|
||||||
return vulns[i].ID > vulns[j].ID
|
parents := ftypes.Packages(result.Packages).ParentDeps()
|
||||||
|
|
||||||
|
// Group vulnerabilities by package ID
|
||||||
|
vulns := lo.GroupBy(result.Vulnerabilities, func(v types.DetectedVulnerability) string {
|
||||||
|
return lo.Ternary(v.PkgID == "", fmt.Sprintf("%s@%s", v.PkgName, v.InstalledVersion), v.PkgID)
|
||||||
})
|
})
|
||||||
|
|
||||||
dependencies[bomRef] = cdx.Dependency{
|
// Create package map
|
||||||
Ref: bomRef,
|
pkgs := lo.SliceToMap(result.Packages, func(pkg ftypes.Package) (string, Package) {
|
||||||
Dependencies: &metadataDependencies,
|
pkgID := lo.Ternary(pkg.ID == "", fmt.Sprintf("%s@%s", pkg.Name, utils.FormatVersion(pkg)), pkg.ID)
|
||||||
|
return pkgID, Package{
|
||||||
|
Type: result.Type,
|
||||||
|
Metadata: metadata,
|
||||||
|
Package: pkg,
|
||||||
|
Vulnerabilities: vulns[pkgID],
|
||||||
}
|
}
|
||||||
dependencyList := maps.Values(dependencies)
|
|
||||||
sort.Slice(dependencyList, func(i, j int) bool {
|
|
||||||
return dependencyList[i].Ref < dependencyList[j].Ref
|
|
||||||
})
|
})
|
||||||
return &components, &dependencyList, &vulns, nil
|
|
||||||
|
var directComponents []*core.Component
|
||||||
|
for _, pkg := range pkgs {
|
||||||
|
// Skip indirect dependencies
|
||||||
|
if pkg.Indirect && len(parents[pkg.ID]) != 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursive packages from direct dependencies
|
||||||
|
if component, err := e.marshalPackage(pkg, pkgs, map[string]*core.Component{}); err != nil {
|
||||||
|
return nil, nil
|
||||||
|
} else if component != nil {
|
||||||
|
directComponents = append(directComponents, component)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return directComponents, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func packageID(target, pkgName, pkgVersion, pkgFilePath string) string {
|
type Package struct {
|
||||||
return fmt.Sprintf("%s/%s/%s/%s", target, pkgName, pkgVersion, pkgFilePath)
|
ftypes.Package
|
||||||
|
Type string
|
||||||
|
Metadata types.Metadata
|
||||||
|
Vulnerabilities []types.DetectedVulnerability
|
||||||
}
|
}
|
||||||
|
|
||||||
func toCdxVulnerability(bomRef string, vuln types.DetectedVulnerability) cdx.Vulnerability {
|
func (e *Marshaler) marshalPackage(pkg Package, pkgs map[string]Package, components map[string]*core.Component,
|
||||||
v := cdx.Vulnerability{
|
) (*core.Component, error) {
|
||||||
ID: vuln.VulnerabilityID,
|
if c, ok := components[pkg.ID]; ok {
|
||||||
Source: cdxSource(vuln.DataSource),
|
return c, nil
|
||||||
Ratings: cdxRatings(vuln),
|
|
||||||
CWEs: cwes(vuln.CweIDs),
|
|
||||||
Description: vuln.Description,
|
|
||||||
Advisories: cdxAdvisories(vuln.References),
|
|
||||||
}
|
|
||||||
if vuln.FixedVersion != "" {
|
|
||||||
v.Recommendation = fmt.Sprintf("Upgrade %s to version %s", vuln.PkgName, vuln.FixedVersion)
|
|
||||||
}
|
|
||||||
if vuln.PublishedDate != nil {
|
|
||||||
v.Published = vuln.PublishedDate.Format(timeLayout)
|
|
||||||
}
|
|
||||||
if vuln.LastModifiedDate != nil {
|
|
||||||
v.Updated = vuln.LastModifiedDate.Format(timeLayout)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
v.Affects = &[]cdx.Affects{cdxAffects(bomRef, vuln.InstalledVersion)}
|
component, err := pkgComponent(pkg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to parse pkg: %w", err)
|
||||||
|
}
|
||||||
|
components[pkg.ID] = component
|
||||||
|
|
||||||
return v
|
// Iterate dependencies
|
||||||
|
for _, dep := range pkg.DependsOn {
|
||||||
|
childPkg, ok := pkgs[dep]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
child, err := e.marshalPackage(childPkg, pkgs, components)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("failed to parse pkg: %w", err)
|
||||||
|
}
|
||||||
|
component.Components = append(component.Components, child)
|
||||||
|
}
|
||||||
|
return component, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Marshaler) reportToCdxComponent(r types.Report) (*cdx.Component, error) {
|
func (e *Marshaler) rootComponent(r types.Report) (*core.Component, error) {
|
||||||
component := &cdx.Component{
|
root := &core.Component{
|
||||||
Name: r.ArtifactName,
|
Name: r.ArtifactName,
|
||||||
}
|
}
|
||||||
|
|
||||||
properties := []cdx.Property{
|
props := map[string]string{
|
||||||
cdxProperty(PropertySchemaVersion, strconv.Itoa(r.SchemaVersion)),
|
PropertySchemaVersion: strconv.Itoa(r.SchemaVersion),
|
||||||
}
|
|
||||||
|
|
||||||
if r.Metadata.Size != 0 {
|
|
||||||
properties = appendProperties(properties, PropertySize, strconv.FormatInt(r.Metadata.Size, 10))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch r.ArtifactType {
|
switch r.ArtifactType {
|
||||||
case ftypes.ArtifactContainerImage:
|
case ftypes.ArtifactContainerImage:
|
||||||
component.Type = cdx.ComponentTypeContainer
|
root.Type = cdx.ComponentTypeContainer
|
||||||
|
props[PropertyImageID] = r.Metadata.ImageID
|
||||||
|
|
||||||
p, err := purl.NewPackageURL(purl.TypeOCI, r.Metadata, ftypes.Package{})
|
p, err := purl.NewPackageURL(purl.TypeOCI, r.Metadata, ftypes.Package{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, xerrors.Errorf("failed to new package url for oci: %w", err)
|
return nil, xerrors.Errorf("failed to new package url for oci: %w", err)
|
||||||
|
} else if p.Type != "" {
|
||||||
|
root.PackageURL = &p
|
||||||
}
|
}
|
||||||
properties = appendProperties(properties, PropertyImageID, r.Metadata.ImageID)
|
|
||||||
|
|
||||||
if p.Type == "" {
|
|
||||||
component.BOMRef = e.newUUID().String()
|
|
||||||
} else {
|
|
||||||
component.BOMRef = p.ToString()
|
|
||||||
component.PackageURL = p.ToString()
|
|
||||||
}
|
|
||||||
case ftypes.ArtifactVM:
|
case ftypes.ArtifactVM:
|
||||||
component.Type = cdx.ComponentTypeContainer
|
root.Type = cdx.ComponentTypeContainer
|
||||||
component.BOMRef = e.newUUID().String()
|
|
||||||
case ftypes.ArtifactFilesystem, ftypes.ArtifactRemoteRepository:
|
case ftypes.ArtifactFilesystem, ftypes.ArtifactRemoteRepository:
|
||||||
component.Type = cdx.ComponentTypeApplication
|
root.Type = cdx.ComponentTypeApplication
|
||||||
component.BOMRef = e.newUUID().String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, d := range r.Metadata.RepoDigests {
|
if r.Metadata.Size != 0 {
|
||||||
properties = appendProperties(properties, PropertyRepoDigest, d)
|
props[PropertySize] = strconv.FormatInt(r.Metadata.Size, 10)
|
||||||
}
|
|
||||||
for _, d := range r.Metadata.DiffIDs {
|
|
||||||
properties = appendProperties(properties, PropertyDiffID, d)
|
|
||||||
}
|
|
||||||
for _, t := range r.Metadata.RepoTags {
|
|
||||||
properties = appendProperties(properties, PropertyRepoTag, t)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
component.Properties = &properties
|
if len(r.Metadata.RepoDigests) > 0 {
|
||||||
|
props[PropertyRepoDigest] = strings.Join(r.Metadata.RepoDigests, ",")
|
||||||
|
}
|
||||||
|
if len(r.Metadata.DiffIDs) > 0 {
|
||||||
|
props[PropertyDiffID] = strings.Join(r.Metadata.DiffIDs, ",")
|
||||||
|
}
|
||||||
|
if len(r.Metadata.RepoTags) > 0 {
|
||||||
|
props[PropertyRepoTag] = strings.Join(r.Metadata.RepoTags, ",")
|
||||||
|
}
|
||||||
|
|
||||||
return component, nil
|
root.Properties = filterProperties(props)
|
||||||
|
|
||||||
|
return root, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Marshaler) resultToCdxComponent(r types.Result, osFound *ftypes.OS) cdx.Component {
|
func (e *Marshaler) resultComponent(r types.Result, osFound *ftypes.OS) *core.Component {
|
||||||
component := cdx.Component{
|
component := &core.Component{
|
||||||
Name: r.Target,
|
Name: r.Target,
|
||||||
Properties: &[]cdx.Property{
|
Properties: map[string]string{
|
||||||
cdxProperty(PropertyType, r.Type),
|
PropertyType: r.Type,
|
||||||
cdxProperty(PropertyClass, string(r.Class)),
|
PropertyClass: string(r.Class),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,7 +270,6 @@ func (e *Marshaler) resultToCdxComponent(r types.Result, osFound *ftypes.OS) cdx
|
|||||||
case types.ClassOSPkg:
|
case types.ClassOSPkg:
|
||||||
// UUID needs to be generated since Operating System Component cannot generate PURL.
|
// UUID needs to be generated since Operating System Component cannot generate PURL.
|
||||||
// https://cyclonedx.org/use-cases/#known-vulnerabilities
|
// https://cyclonedx.org/use-cases/#known-vulnerabilities
|
||||||
component.BOMRef = e.newUUID().String()
|
|
||||||
if osFound != nil {
|
if osFound != nil {
|
||||||
component.Name = osFound.Family
|
component.Name = osFound.Family
|
||||||
component.Version = osFound.Name
|
component.Version = osFound.Name
|
||||||
@@ -438,296 +278,46 @@ func (e *Marshaler) resultToCdxComponent(r types.Result, osFound *ftypes.OS) cdx
|
|||||||
case types.ClassLangPkg:
|
case types.ClassLangPkg:
|
||||||
// UUID needs to be generated since Application Component cannot generate PURL.
|
// UUID needs to be generated since Application Component cannot generate PURL.
|
||||||
// https://cyclonedx.org/use-cases/#known-vulnerabilities
|
// https://cyclonedx.org/use-cases/#known-vulnerabilities
|
||||||
component.BOMRef = e.newUUID().String()
|
|
||||||
component.Type = cdx.ComponentTypeApplication
|
component.Type = cdx.ComponentTypeApplication
|
||||||
case types.ClassConfig:
|
|
||||||
// TODO: Config support
|
|
||||||
component.BOMRef = e.newUUID().String()
|
|
||||||
component.Type = cdx.ComponentTypeFile
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return component
|
return component
|
||||||
}
|
}
|
||||||
|
|
||||||
func pkgToCdxComponent(pkgType string, meta types.Metadata, class types.ResultClass, pkg ftypes.Package) (cdx.Component, error) {
|
func pkgComponent(pkg Package) (*core.Component, error) {
|
||||||
pu, err := purl.NewPackageURL(pkgType, meta, pkg)
|
pu, err := purl.NewPackageURL(pkg.Type, pkg.Metadata, pkg.Package)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return cdx.Component{}, xerrors.Errorf("failed to new package purl: %w", err)
|
return nil, xerrors.Errorf("failed to new package purl: %w", err)
|
||||||
}
|
|
||||||
properties := cdxProperties(pkgType, pkg)
|
|
||||||
var hashes *[]cdx.Hash
|
|
||||||
if pkg.Digest != "" && class == types.ClassOSPkg {
|
|
||||||
if alg := cdxHashAlgorithm(pkg.Digest.Algorithm()); alg != "" {
|
|
||||||
hashes = &[]cdx.Hash{
|
|
||||||
{
|
|
||||||
Algorithm: alg,
|
|
||||||
Value: pkg.Digest.Encoded(),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
properties := map[string]string{
|
||||||
|
PropertyPkgID: pkg.ID,
|
||||||
|
PropertyPkgType: pkg.Type,
|
||||||
|
PropertyFilePath: pkg.FilePath,
|
||||||
|
PropertySrcName: pkg.SrcName,
|
||||||
|
PropertySrcVersion: pkg.SrcVersion,
|
||||||
|
PropertySrcRelease: pkg.SrcRelease,
|
||||||
|
PropertySrcEpoch: strconv.Itoa(pkg.SrcEpoch),
|
||||||
|
PropertyModularitylabel: pkg.Modularitylabel,
|
||||||
|
PropertyLayerDigest: pkg.Layer.Digest,
|
||||||
|
PropertyLayerDiffID: pkg.Layer.DiffID,
|
||||||
}
|
}
|
||||||
component := cdx.Component{
|
|
||||||
|
return &core.Component{
|
||||||
Type: cdx.ComponentTypeLibrary,
|
Type: cdx.ComponentTypeLibrary,
|
||||||
Name: pkg.Name,
|
Name: pkg.Name,
|
||||||
Version: pu.Version,
|
Version: pu.Version,
|
||||||
BOMRef: pu.BOMRef(),
|
PackageURL: &pu,
|
||||||
PackageURL: pu.ToString(),
|
Supplier: pkg.Maintainer,
|
||||||
Properties: properties,
|
Licenses: pkg.Licenses,
|
||||||
Hashes: hashes,
|
Hashes: lo.Ternary(pkg.Digest == "", nil, []digest.Digest{pkg.Digest}),
|
||||||
}
|
Properties: filterProperties(properties),
|
||||||
|
Vulnerabilities: pkg.Vulnerabilities,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
if len(pkg.Licenses) != 0 {
|
func filterProperties(props map[string]string) map[string]string {
|
||||||
choices := lo.Map(pkg.Licenses, func(license string, i int) cdx.LicenseChoice {
|
return lo.OmitBy(props, func(key string, value string) bool {
|
||||||
return cdx.LicenseChoice{Expression: license}
|
return value == "" || (key == PropertySrcEpoch && value == "0")
|
||||||
})
|
})
|
||||||
component.Licenses = lo.ToPtr(cdx.Licenses(choices))
|
|
||||||
}
|
|
||||||
|
|
||||||
if pkg.Maintainer != "" {
|
|
||||||
component.Supplier = &cdx.OrganizationalEntity{
|
|
||||||
Name: pkg.Maintainer,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return component, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func cdxProperties(pkgType string, pkg ftypes.Package) *[]cdx.Property {
|
|
||||||
props := []struct {
|
|
||||||
name string
|
|
||||||
value string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
PropertyPkgID,
|
|
||||||
pkg.ID,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
PropertyPkgType,
|
|
||||||
pkgType,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
PropertyFilePath,
|
|
||||||
pkg.FilePath,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
PropertySrcName,
|
|
||||||
pkg.SrcName,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
PropertySrcVersion,
|
|
||||||
pkg.SrcVersion,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
PropertySrcRelease,
|
|
||||||
pkg.SrcRelease,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
PropertySrcEpoch,
|
|
||||||
strconv.Itoa(pkg.SrcEpoch),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
PropertyModularitylabel,
|
|
||||||
pkg.Modularitylabel,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
PropertyLayerDigest,
|
|
||||||
pkg.Layer.Digest,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
PropertyLayerDiffID,
|
|
||||||
pkg.Layer.DiffID,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
var properties []cdx.Property
|
|
||||||
for _, prop := range props {
|
|
||||||
properties = appendProperties(properties, prop.name, prop.value)
|
|
||||||
}
|
|
||||||
if len(properties) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &properties
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendProperties(properties []cdx.Property, key, value string) []cdx.Property {
|
|
||||||
if value == "" || (key == PropertySrcEpoch && value == "0") {
|
|
||||||
return properties
|
|
||||||
}
|
|
||||||
return append(properties, cdxProperty(key, value))
|
|
||||||
}
|
|
||||||
|
|
||||||
func cdxProperty(key, value string) cdx.Property {
|
|
||||||
return cdx.Property{
|
|
||||||
Name: Namespace + key,
|
|
||||||
Value: value,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func cdxAdvisories(refs []string) *[]cdx.Advisory {
|
|
||||||
var advs []cdx.Advisory
|
|
||||||
for _, ref := range refs {
|
|
||||||
advs = append(advs, cdx.Advisory{
|
|
||||||
URL: ref,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
return &advs
|
|
||||||
}
|
|
||||||
|
|
||||||
func cwes(cweIDs []string) *[]int {
|
|
||||||
// to skip cdx.Vulnerability.CWEs when generating json
|
|
||||||
// we should return 'clear' nil without 'type' interface part
|
|
||||||
if cweIDs == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
var ret []int
|
|
||||||
for _, cweID := range cweIDs {
|
|
||||||
number, err := strconv.Atoi(strings.TrimPrefix(strings.ToLower(cweID), "cwe-"))
|
|
||||||
if err != nil {
|
|
||||||
log.Logger.Debugf("cwe id parse error: %s", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
ret = append(ret, number)
|
|
||||||
}
|
|
||||||
return &ret
|
|
||||||
}
|
|
||||||
|
|
||||||
func cdxRatings(vulnerability types.DetectedVulnerability) *[]cdx.VulnerabilityRating {
|
|
||||||
rates := make([]cdx.VulnerabilityRating, 0) // To export an empty array in JSON
|
|
||||||
for sourceID, severity := range vulnerability.VendorSeverity {
|
|
||||||
// When the vendor also provides CVSS score/vector
|
|
||||||
if cvss, ok := vulnerability.CVSS[sourceID]; ok {
|
|
||||||
if cvss.V2Score != 0 || cvss.V2Vector != "" {
|
|
||||||
rates = append(rates, cdxRatingV2(sourceID, severity, cvss))
|
|
||||||
}
|
|
||||||
if cvss.V3Score != 0 || cvss.V3Vector != "" {
|
|
||||||
rates = append(rates, cdxRatingV3(sourceID, severity, cvss))
|
|
||||||
}
|
|
||||||
} else { // When the vendor provides only severity
|
|
||||||
rate := cdx.VulnerabilityRating{
|
|
||||||
Source: &cdx.Source{
|
|
||||||
Name: string(sourceID),
|
|
||||||
},
|
|
||||||
Severity: toCDXSeverity(severity),
|
|
||||||
}
|
|
||||||
rates = append(rates, rate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// For consistency
|
|
||||||
sort.Slice(rates, func(i, j int) bool {
|
|
||||||
if rates[i].Source.Name != rates[j].Source.Name {
|
|
||||||
return rates[i].Source.Name < rates[j].Source.Name
|
|
||||||
}
|
|
||||||
if rates[i].Method != rates[j].Method {
|
|
||||||
return rates[i].Method < rates[j].Method
|
|
||||||
}
|
|
||||||
if rates[i].Score != nil && rates[j].Score != nil {
|
|
||||||
return *rates[i].Score < *rates[j].Score
|
|
||||||
}
|
|
||||||
return rates[i].Vector < rates[j].Vector
|
|
||||||
})
|
|
||||||
return &rates
|
|
||||||
}
|
|
||||||
|
|
||||||
func cdxRatingV2(sourceID dtypes.SourceID, severity dtypes.Severity, cvss dtypes.CVSS) cdx.VulnerabilityRating {
|
|
||||||
cdxSeverity := toCDXSeverity(severity)
|
|
||||||
|
|
||||||
// Trivy keeps only CVSSv3 severity for NVD.
|
|
||||||
// The CVSSv2 severity must be calculated according to CVSSv2 score.
|
|
||||||
if sourceID == vulnerability.NVD {
|
|
||||||
cdxSeverity = nvdSeverityV2(cvss.V2Score)
|
|
||||||
}
|
|
||||||
return cdx.VulnerabilityRating{
|
|
||||||
Source: &cdx.Source{
|
|
||||||
Name: string(sourceID),
|
|
||||||
},
|
|
||||||
Score: &cvss.V2Score,
|
|
||||||
Method: cdx.ScoringMethodCVSSv2,
|
|
||||||
Severity: cdxSeverity,
|
|
||||||
Vector: cvss.V2Vector,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func nvdSeverityV2(score float64) cdx.Severity {
|
|
||||||
// cf. https://nvd.nist.gov/vuln-metrics/cvss
|
|
||||||
switch {
|
|
||||||
case score < 4.0:
|
|
||||||
return cdx.SeverityInfo
|
|
||||||
case 4.0 <= score && score < 7.0:
|
|
||||||
return cdx.SeverityMedium
|
|
||||||
case 7.0 <= score:
|
|
||||||
return cdx.SeverityHigh
|
|
||||||
}
|
|
||||||
return cdx.SeverityUnknown
|
|
||||||
}
|
|
||||||
|
|
||||||
func cdxRatingV3(sourceID dtypes.SourceID, severity dtypes.Severity, cvss dtypes.CVSS) cdx.VulnerabilityRating {
|
|
||||||
rate := cdx.VulnerabilityRating{
|
|
||||||
Source: &cdx.Source{
|
|
||||||
Name: string(sourceID),
|
|
||||||
},
|
|
||||||
Score: &cvss.V3Score,
|
|
||||||
Method: cdx.ScoringMethodCVSSv3,
|
|
||||||
Severity: toCDXSeverity(severity),
|
|
||||||
Vector: cvss.V3Vector,
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(cvss.V3Vector, "CVSS:3.1") {
|
|
||||||
rate.Method = cdx.ScoringMethodCVSSv31
|
|
||||||
}
|
|
||||||
return rate
|
|
||||||
}
|
|
||||||
|
|
||||||
func toCDXSeverity(s dtypes.Severity) cdx.Severity {
|
|
||||||
switch s {
|
|
||||||
case dtypes.SeverityLow:
|
|
||||||
return cdx.SeverityLow
|
|
||||||
case dtypes.SeverityMedium:
|
|
||||||
return cdx.SeverityMedium
|
|
||||||
case dtypes.SeverityHigh:
|
|
||||||
return cdx.SeverityHigh
|
|
||||||
case dtypes.SeverityCritical:
|
|
||||||
return cdx.SeverityCritical
|
|
||||||
default:
|
|
||||||
return cdx.SeverityUnknown
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func cdxSource(source *dtypes.DataSource) *cdx.Source {
|
|
||||||
if source == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &cdx.Source{
|
|
||||||
Name: string(source.ID),
|
|
||||||
URL: source.URL,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func cdxAffects(ref, version string) cdx.Affects {
|
|
||||||
return cdx.Affects{
|
|
||||||
Ref: ref,
|
|
||||||
Range: &[]cdx.AffectedVersions{
|
|
||||||
{
|
|
||||||
Version: version,
|
|
||||||
Status: cdx.VulnerabilityStatusAffected,
|
|
||||||
// "AffectedVersions.Range" is not included, because it does not exist in DetectedVulnerability.
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func cdxHashAlgorithm(algorithm digest.Algorithm) cdx.HashAlgorithm {
|
|
||||||
switch algorithm {
|
|
||||||
case digest.SHA1:
|
|
||||||
return cdx.HashAlgoSHA1
|
|
||||||
case digest.SHA256:
|
|
||||||
return cdx.HashAlgoSHA256
|
|
||||||
case digest.MD5:
|
|
||||||
return cdx.HashAlgoMD5
|
|
||||||
default:
|
|
||||||
log.Logger.Debugf("Unable to convert %q algorithm to CycloneDX format", algorithm)
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,8 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
|
"github.com/aquasecurity/trivy/pkg/sbom/cyclonedx/core"
|
||||||
|
|
||||||
cdx "github.com/CycloneDX/cyclonedx-go"
|
cdx "github.com/CycloneDX/cyclonedx-go"
|
||||||
"github.com/samber/lo"
|
"github.com/samber/lo"
|
||||||
@@ -23,7 +24,7 @@ var (
|
|||||||
ErrPURLEmpty = errors.New("purl empty error")
|
ErrPURLEmpty = errors.New("purl empty error")
|
||||||
)
|
)
|
||||||
|
|
||||||
type CycloneDX struct {
|
type BOM struct {
|
||||||
*types.SBOM
|
*types.SBOM
|
||||||
|
|
||||||
dependencies map[string][]string
|
dependencies map[string][]string
|
||||||
@@ -39,7 +40,7 @@ func DecodeJSON(r io.Reader) (*cdx.BOM, error) {
|
|||||||
return bom, nil
|
return bom, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CycloneDX) UnmarshalJSON(b []byte) error {
|
func (c *BOM) UnmarshalJSON(b []byte) error {
|
||||||
log.Logger.Debug("Unmarshaling CycloneDX JSON...")
|
log.Logger.Debug("Unmarshaling CycloneDX JSON...")
|
||||||
if c.SBOM == nil {
|
if c.SBOM == nil {
|
||||||
c.SBOM = &types.SBOM{}
|
c.SBOM = &types.SBOM{}
|
||||||
@@ -49,7 +50,7 @@ func (c *CycloneDX) UnmarshalJSON(b []byte) error {
|
|||||||
return xerrors.Errorf("CycloneDX decode error: %w", err)
|
return xerrors.Errorf("CycloneDX decode error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isTrivySBOM(bom) {
|
if !core.IsTrivySBOM(bom) {
|
||||||
log.Logger.Warnf("Third-party SBOM may lead to inaccurate vulnerability detection")
|
log.Logger.Warnf("Third-party SBOM may lead to inaccurate vulnerability detection")
|
||||||
log.Logger.Warnf("Recommend using Trivy to generate SBOMs")
|
log.Logger.Warnf("Recommend using Trivy to generate SBOMs")
|
||||||
}
|
}
|
||||||
@@ -90,7 +91,7 @@ func (c *CycloneDX) UnmarshalJSON(b []byte) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CycloneDX) parseSBOM(bom *cdx.BOM) error {
|
func (c *BOM) parseSBOM(bom *cdx.BOM) error {
|
||||||
c.dependencies = dependencyMap(bom.Dependencies)
|
c.dependencies = dependencyMap(bom.Dependencies)
|
||||||
c.components = componentMap(bom.Metadata, bom.Components)
|
c.components = componentMap(bom.Metadata, bom.Components)
|
||||||
var seen = make(map[string]struct{})
|
var seen = make(map[string]struct{})
|
||||||
@@ -106,7 +107,7 @@ func (c *CycloneDX) parseSBOM(bom *cdx.BOM) error {
|
|||||||
}
|
}
|
||||||
c.Packages = append(c.Packages, pkgInfo)
|
c.Packages = append(c.Packages, pkgInfo)
|
||||||
case cdx.ComponentTypeApplication: // It would be a lock file in a CycloneDX report generated by Trivy
|
case cdx.ComponentTypeApplication: // It would be a lock file in a CycloneDX report generated by Trivy
|
||||||
if lookupProperty(component.Properties, PropertyType) == "" {
|
if core.LookupProperty(component.Properties, PropertyType) == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
app, err := c.parseLangPkgs(component, seen)
|
app, err := c.parseLangPkgs(component, seen)
|
||||||
@@ -160,7 +161,7 @@ func (c *CycloneDX) parseSBOM(bom *cdx.BOM) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CycloneDX) parseOSPkgs(component cdx.Component, seen map[string]struct{}) (ftypes.PackageInfo, error) {
|
func (c *BOM) parseOSPkgs(component cdx.Component, seen map[string]struct{}) (ftypes.PackageInfo, error) {
|
||||||
components := c.walkDependencies(component.BOMRef, map[string]struct{}{})
|
components := c.walkDependencies(component.BOMRef, map[string]struct{}{})
|
||||||
pkgs, err := parsePkgs(components, seen)
|
pkgs, err := parsePkgs(components, seen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -172,7 +173,7 @@ func (c *CycloneDX) parseOSPkgs(component cdx.Component, seen map[string]struct{
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *CycloneDX) parseLangPkgs(component cdx.Component, seen map[string]struct{}) (*ftypes.Application, error) {
|
func (c *BOM) parseLangPkgs(component cdx.Component, seen map[string]struct{}) (*ftypes.Application, error) {
|
||||||
components := c.walkDependencies(component.BOMRef, map[string]struct{}{})
|
components := c.walkDependencies(component.BOMRef, map[string]struct{}{})
|
||||||
components = lo.UniqBy(components, func(c cdx.Component) string {
|
components = lo.UniqBy(components, func(c cdx.Component) string {
|
||||||
return c.BOMRef
|
return c.BOMRef
|
||||||
@@ -205,7 +206,7 @@ func parsePkgs(components []cdx.Component, seen map[string]struct{}) ([]ftypes.P
|
|||||||
}
|
}
|
||||||
|
|
||||||
// walkDependencies takes all nested dependencies of the root component.
|
// walkDependencies takes all nested dependencies of the root component.
|
||||||
func (c *CycloneDX) walkDependencies(rootRef string, uniqComponents map[string]struct{}) []cdx.Component {
|
func (c *BOM) walkDependencies(rootRef string, uniqComponents map[string]struct{}) []cdx.Component {
|
||||||
// e.g. Library A, B, C, D and E will be returned as dependencies of Application 1.
|
// e.g. Library A, B, C, D and E will be returned as dependencies of Application 1.
|
||||||
// type: Application 1
|
// type: Application 1
|
||||||
// - type: Library A
|
// - type: Library A
|
||||||
@@ -325,7 +326,7 @@ func toOS(component cdx.Component) ftypes.OS {
|
|||||||
|
|
||||||
func toApplication(component cdx.Component) *ftypes.Application {
|
func toApplication(component cdx.Component) *ftypes.Application {
|
||||||
return &ftypes.Application{
|
return &ftypes.Application{
|
||||||
Type: lookupProperty(component.Properties, PropertyType),
|
Type: core.LookupProperty(component.Properties, PropertyType),
|
||||||
FilePath: component.Name,
|
FilePath: component.Name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -350,27 +351,25 @@ func toPackage(component cdx.Component) (bool, string, *ftypes.Package, error) {
|
|||||||
pkg.Licenses = append(pkg.Licenses, license.Expression)
|
pkg.Licenses = append(pkg.Licenses, license.Expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, prop := range lo.FromPtr(component.Properties) {
|
for key, value := range core.UnmarshalProperties(component.Properties) {
|
||||||
if strings.HasPrefix(prop.Name, Namespace) {
|
switch key {
|
||||||
switch strings.TrimPrefix(prop.Name, Namespace) {
|
|
||||||
case PropertyPkgID:
|
case PropertyPkgID:
|
||||||
pkg.ID = prop.Value
|
pkg.ID = value
|
||||||
case PropertySrcName:
|
case PropertySrcName:
|
||||||
pkg.SrcName = prop.Value
|
pkg.SrcName = value
|
||||||
case PropertySrcVersion:
|
case PropertySrcVersion:
|
||||||
pkg.SrcVersion = prop.Value
|
pkg.SrcVersion = value
|
||||||
case PropertySrcRelease:
|
case PropertySrcRelease:
|
||||||
pkg.SrcRelease = prop.Value
|
pkg.SrcRelease = value
|
||||||
case PropertySrcEpoch:
|
case PropertySrcEpoch:
|
||||||
pkg.SrcEpoch, err = strconv.Atoi(prop.Value)
|
pkg.SrcEpoch, err = strconv.Atoi(value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, "", nil, xerrors.Errorf("failed to parse source epoch: %w", err)
|
return false, "", nil, xerrors.Errorf("failed to parse source epoch: %w", err)
|
||||||
}
|
}
|
||||||
case PropertyModularitylabel:
|
case PropertyModularitylabel:
|
||||||
pkg.Modularitylabel = prop.Value
|
pkg.Modularitylabel = value
|
||||||
case PropertyLayerDiffID:
|
case PropertyLayerDiffID:
|
||||||
pkg.Layer.DiffID = prop.Value
|
pkg.Layer.DiffID = value
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,25 +403,3 @@ func toTrivyCdxComponent(component cdx.Component) ftypes.Component {
|
|||||||
PackageURL: component.PackageURL,
|
PackageURL: component.PackageURL,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookupProperty(properties *[]cdx.Property, key string) string {
|
|
||||||
for _, p := range lo.FromPtr(properties) {
|
|
||||||
if p.Name == Namespace+key {
|
|
||||||
return p.Value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func isTrivySBOM(c *cdx.BOM) bool {
|
|
||||||
if c == nil || c.Metadata == nil || c.Metadata.Tools == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, tool := range *c.Metadata.Tools {
|
|
||||||
if tool.Vendor == ToolVendor && tool.Name == ToolName {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -315,7 +315,7 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
var cdx cyclonedx.CycloneDX
|
var cdx cyclonedx.BOM
|
||||||
err = json.NewDecoder(f).Decode(&cdx)
|
err = json.NewDecoder(f).Decode(&cdx)
|
||||||
if tt.wantErr != "" {
|
if tt.wantErr != "" {
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|||||||
@@ -187,14 +187,14 @@ func Decode(f io.Reader, format Format) (types.SBOM, error) {
|
|||||||
|
|
||||||
switch format {
|
switch format {
|
||||||
case FormatCycloneDXJSON:
|
case FormatCycloneDXJSON:
|
||||||
v = &cyclonedx.CycloneDX{SBOM: &bom}
|
v = &cyclonedx.BOM{SBOM: &bom}
|
||||||
decoder = json.NewDecoder(f)
|
decoder = json.NewDecoder(f)
|
||||||
case FormatAttestCycloneDXJSON:
|
case FormatAttestCycloneDXJSON:
|
||||||
// dsse envelope
|
// dsse envelope
|
||||||
// => in-toto attestation
|
// => in-toto attestation
|
||||||
// => CycloneDX JSON
|
// => CycloneDX JSON
|
||||||
v = &attestation.Statement{
|
v = &attestation.Statement{
|
||||||
Predicate: &cyclonedx.CycloneDX{SBOM: &bom},
|
Predicate: &cyclonedx.BOM{SBOM: &bom},
|
||||||
}
|
}
|
||||||
decoder = json.NewDecoder(f)
|
decoder = json.NewDecoder(f)
|
||||||
case FormatLegacyCosignAttestCycloneDXJSON:
|
case FormatLegacyCosignAttestCycloneDXJSON:
|
||||||
@@ -204,7 +204,7 @@ func Decode(f io.Reader, format Format) (types.SBOM, error) {
|
|||||||
// => CycloneDX JSON
|
// => CycloneDX JSON
|
||||||
v = &attestation.Statement{
|
v = &attestation.Statement{
|
||||||
Predicate: &attestation.CosignPredicate{
|
Predicate: &attestation.CosignPredicate{
|
||||||
Data: &cyclonedx.CycloneDX{SBOM: &bom},
|
Data: &cyclonedx.BOM{SBOM: &bom},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
decoder = json.NewDecoder(f)
|
decoder = json.NewDecoder(f)
|
||||||
|
|||||||
Reference in New Issue
Block a user