mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 07:40:48 -08:00
chore: add VEX document and generator for Trivy (#7128)
Signed-off-by: knqyf263 <knqyf263@gmail.com> Co-authored-by: Nikita Pivkin <nikita.pivkin@smartforce.io>
This commit is contained in:
458
.vex/trivy.openvex.json
Normal file
458
.vex/trivy.openvex.json
Normal file
@@ -0,0 +1,458 @@
|
||||
{
|
||||
"@context": "https://openvex.dev/ns/v0.2.0",
|
||||
"@id": "aquasecurity/trivy:613fd55abbc2857b5ca28b07a26f3cd4c8b0ddc4c8a97c57497a2d4c4880d7fc",
|
||||
"author": "Aqua Security",
|
||||
"timestamp": "2024-07-09T11:38:00.115697+04:00",
|
||||
"version": 1,
|
||||
"tooling": "https://github.com/aquasecurity/trivy/tree/main/magefiles/vex.go",
|
||||
"statements": [
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://pkg.go.dev/vuln/GO-2024-2575",
|
||||
"name": "GO-2024-2575",
|
||||
"description": "Helm's Missing YAML Content Leads To Panic in helm.sh/helm/v3",
|
||||
"aliases": [
|
||||
"CVE-2024-26147",
|
||||
"GHSA-r53h-jv2g-vpx6"
|
||||
]
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/aquasecurity/trivy",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/aquasecurity/trivy"
|
||||
},
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/helm.sh/helm/v3",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/helm.sh/helm/v3"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"impact_statement": "Govulncheck determined that the vulnerable code isn't called"
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://pkg.go.dev/vuln/GO-2023-1765",
|
||||
"name": "GO-2023-1765",
|
||||
"description": "Leaked shared secret and weak blinding in github.com/cloudflare/circl",
|
||||
"aliases": [
|
||||
"CVE-2023-1732",
|
||||
"GHSA-2q89-485c-9j2x"
|
||||
]
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/aquasecurity/trivy",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/aquasecurity/trivy"
|
||||
},
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/cloudflare/circl",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/cloudflare/circl"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_present",
|
||||
"impact_statement": "Govulncheck determined that the vulnerable code isn't called"
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://pkg.go.dev/vuln/GO-2024-2512",
|
||||
"name": "GO-2024-2512",
|
||||
"description": "Classic builder cache poisoning in github.com/docker/docker",
|
||||
"aliases": [
|
||||
"CVE-2024-24557",
|
||||
"GHSA-xw73-rw38-6vjc"
|
||||
]
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/aquasecurity/trivy",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/aquasecurity/trivy"
|
||||
},
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/docker/docker",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/docker/docker"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_present",
|
||||
"impact_statement": "Govulncheck determined that the vulnerable code isn't called"
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://pkg.go.dev/vuln/GO-2024-2453",
|
||||
"name": "GO-2024-2453",
|
||||
"description": "Timing side channel in github.com/cloudflare/circl",
|
||||
"aliases": [
|
||||
"GHSA-9763-4f94-gfch"
|
||||
]
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/aquasecurity/trivy",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/aquasecurity/trivy"
|
||||
},
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/cloudflare/circl",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/cloudflare/circl"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_present",
|
||||
"impact_statement": "Govulncheck determined that the vulnerable code isn't called"
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://pkg.go.dev/vuln/GO-2023-2048",
|
||||
"name": "GO-2023-2048",
|
||||
"description": "Paths outside of the rootfs could be produced on Windows in github.com/cyphar/filepath-securejoin",
|
||||
"aliases": [
|
||||
"GHSA-6xv5-86q9-7xr8"
|
||||
]
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/aquasecurity/trivy",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/aquasecurity/trivy"
|
||||
},
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/cyphar/filepath-securejoin",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/cyphar/filepath-securejoin"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"impact_statement": "Govulncheck determined that the vulnerable code isn't called"
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://pkg.go.dev/vuln/GO-2024-2497",
|
||||
"name": "GO-2024-2497",
|
||||
"description": "Privilege escalation in github.com/moby/buildkit",
|
||||
"aliases": [
|
||||
"CVE-2024-23653",
|
||||
"GHSA-wr6v-9f75-vh2g"
|
||||
]
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/aquasecurity/trivy",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/aquasecurity/trivy"
|
||||
},
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/moby/buildkit",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/moby/buildkit"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_present",
|
||||
"impact_statement": "Govulncheck determined that the vulnerable code isn't called"
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://pkg.go.dev/vuln/GO-2023-2102",
|
||||
"name": "GO-2023-2102",
|
||||
"description": "HTTP/2 rapid reset can cause excessive work in net/http",
|
||||
"aliases": [
|
||||
"CVE-2023-39325",
|
||||
"GHSA-4374-p667-p6c8"
|
||||
]
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/aquasecurity/trivy",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/aquasecurity/trivy"
|
||||
},
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/golang.org/x/net",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/golang.org/x/net"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"impact_statement": "Govulncheck determined that the vulnerable code isn't called"
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://pkg.go.dev/vuln/GO-2024-2493",
|
||||
"name": "GO-2024-2493",
|
||||
"description": "Host system file access in github.com/moby/buildkit",
|
||||
"aliases": [
|
||||
"CVE-2024-23651",
|
||||
"GHSA-m3r6-h7wv-7xxv"
|
||||
]
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/aquasecurity/trivy",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/aquasecurity/trivy"
|
||||
},
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/moby/buildkit",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/moby/buildkit"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_present",
|
||||
"impact_statement": "Govulncheck determined that the vulnerable code isn't called"
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://pkg.go.dev/vuln/GO-2024-2491",
|
||||
"name": "GO-2024-2491",
|
||||
"description": "Container breakout through process.cwd trickery and leaked fds in github.com/opencontainers/runc",
|
||||
"aliases": [
|
||||
"CVE-2024-21626",
|
||||
"GHSA-xr7r-f8xq-vfvv"
|
||||
]
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/aquasecurity/trivy",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/aquasecurity/trivy"
|
||||
},
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/opencontainers/runc",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/opencontainers/runc"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_present",
|
||||
"impact_statement": "Govulncheck determined that the vulnerable code isn't called"
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://pkg.go.dev/vuln/GO-2024-2494",
|
||||
"name": "GO-2024-2494",
|
||||
"description": "Host system modification in github.com/moby/buildkit",
|
||||
"aliases": [
|
||||
"CVE-2024-23652",
|
||||
"GHSA-4v98-7qmw-rqr8"
|
||||
]
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/aquasecurity/trivy",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/aquasecurity/trivy"
|
||||
},
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/moby/buildkit",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/moby/buildkit"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_present",
|
||||
"impact_statement": "Govulncheck determined that the vulnerable code isn't called"
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://pkg.go.dev/vuln/GO-2023-2412",
|
||||
"name": "GO-2023-2412",
|
||||
"description": "RAPL accessibility in github.com/containerd/containerd",
|
||||
"aliases": [
|
||||
"GHSA-7ww5-4wqc-m92c"
|
||||
]
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/aquasecurity/trivy",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/aquasecurity/trivy"
|
||||
},
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/containerd/containerd",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/containerd/containerd"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_present",
|
||||
"impact_statement": "Govulncheck determined that the vulnerable code isn't called"
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://pkg.go.dev/vuln/GO-2023-1988",
|
||||
"name": "GO-2023-1988",
|
||||
"description": "Improper rendering of text nodes in golang.org/x/net/html",
|
||||
"aliases": [
|
||||
"CVE-2023-3978",
|
||||
"GHSA-2wrh-6pvc-2jm9"
|
||||
]
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/aquasecurity/trivy",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/aquasecurity/trivy"
|
||||
},
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/golang.org/x/net",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/golang.org/x/net"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"impact_statement": "Govulncheck determined that the vulnerable code isn't called"
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://pkg.go.dev/vuln/GO-2024-2492",
|
||||
"name": "GO-2024-2492",
|
||||
"description": "Panic in github.com/moby/buildkit",
|
||||
"aliases": [
|
||||
"CVE-2024-23650",
|
||||
"GHSA-9p26-698r-w4hx"
|
||||
]
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/aquasecurity/trivy",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/aquasecurity/trivy"
|
||||
},
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/moby/buildkit",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/moby/buildkit"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_present",
|
||||
"impact_statement": "Govulncheck determined that the vulnerable code isn't called"
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://pkg.go.dev/vuln/GO-2022-0646",
|
||||
"name": "GO-2022-0646",
|
||||
"description": "Use of risky cryptographic algorithm in github.com/aws/aws-sdk-go",
|
||||
"aliases": [
|
||||
"CVE-2020-8911",
|
||||
"CVE-2020-8912",
|
||||
"GHSA-7f33-f4f5-xwgw",
|
||||
"GHSA-f5pg-7wfw-84q9"
|
||||
]
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/aquasecurity/trivy",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/aquasecurity/trivy"
|
||||
},
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/aws/aws-sdk-go",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/aws/aws-sdk-go"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_present",
|
||||
"impact_statement": "Govulncheck determined that the vulnerable code isn't called"
|
||||
},
|
||||
{
|
||||
"vulnerability": {
|
||||
"@id": "https://pkg.go.dev/vuln/GO-2023-2153",
|
||||
"name": "GO-2023-2153",
|
||||
"description": "Denial of service from HTTP/2 Rapid Reset in google.golang.org/grpc",
|
||||
"aliases": [
|
||||
"GHSA-m425-mq94-257g"
|
||||
]
|
||||
},
|
||||
"products": [
|
||||
{
|
||||
"@id": "pkg:golang/github.com/aquasecurity/trivy",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/github.com/aquasecurity/trivy"
|
||||
},
|
||||
"subcomponents": [
|
||||
{
|
||||
"@id": "pkg:golang/google.golang.org/grpc",
|
||||
"identifiers": {
|
||||
"purl": "pkg:golang/google.golang.org/grpc"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"status": "not_affected",
|
||||
"justification": "vulnerable_code_not_in_execute_path",
|
||||
"impact_statement": "Govulncheck determined that the vulnerable code isn't called"
|
||||
}
|
||||
]
|
||||
}
|
||||
4
go.mod
4
go.mod
@@ -122,6 +122,7 @@ require (
|
||||
golang.org/x/sync v0.7.0
|
||||
golang.org/x/term v0.21.0
|
||||
golang.org/x/text v0.16.0
|
||||
golang.org/x/vuln v1.1.2
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028
|
||||
google.golang.org/protobuf v1.34.2
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
@@ -355,8 +356,9 @@ require (
|
||||
go.uber.org/zap v1.27.0 // indirect
|
||||
golang.org/x/oauth2 v0.20.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
|
||||
golang.org/x/tools v0.22.0 // indirect
|
||||
google.golang.org/api v0.172.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 // indirect
|
||||
|
||||
8
go.sum
8
go.sum
@@ -2506,6 +2506,8 @@ golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
|
||||
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 h1:FemxDzfMUcK2f3YY4H+05K9CDzbSVr2+q/JKN45pey0=
|
||||
golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -2624,8 +2626,10 @@ golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
|
||||
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
|
||||
golang.org/x/vuln v1.1.2 h1:UkLxe+kAMcrNBpGrFbU0Mc5l7cX97P2nhy21wx5+Qbk=
|
||||
golang.org/x/vuln v1.1.2/go.mod h1:2o3fRKD8Uz9AraAL3lwd/grWBv+t+SeJnPcqBUJrY24=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -469,3 +469,8 @@ type CloudActions mg.Namespace
|
||||
func (CloudActions) Generate() error {
|
||||
return sh.RunWith(ENV, "go", "run", "-tags=mage_cloudactions", "./magefiles")
|
||||
}
|
||||
|
||||
// VEX generates a VEX document for Trivy
|
||||
func VEX(_ context.Context, dir string) error {
|
||||
return sh.RunWith(ENV, "go", "run", "-tags=mage_vex", "./magefiles/vex.go", "--dir", dir)
|
||||
}
|
||||
|
||||
425
magefiles/vex.go
Normal file
425
magefiles/vex.go
Normal file
@@ -0,0 +1,425 @@
|
||||
//go:build mage_vex
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/openvex/go-vex/pkg/vex"
|
||||
"github.com/package-url/packageurl-go"
|
||||
"github.com/samber/lo"
|
||||
"golang.org/x/vuln/scan"
|
||||
|
||||
"github.com/aquasecurity/go-version/pkg/version"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
)
|
||||
|
||||
const (
|
||||
repoURL = "https://github.com/aquasecurity/trivy"
|
||||
minVersion = "0.40.0"
|
||||
)
|
||||
|
||||
var (
|
||||
minVer, _ = version.Parse(minVersion)
|
||||
|
||||
// Product ID for Trivy
|
||||
productID = &packageurl.PackageURL{
|
||||
Type: packageurl.TypeGolang,
|
||||
// According to https://github.com/package-url/purl-spec/issues/63,
|
||||
// It's probably better to leave namespace empty and put a module name into `name`.
|
||||
Namespace: "",
|
||||
Name: "github.com/aquasecurity/trivy",
|
||||
}
|
||||
)
|
||||
|
||||
// VulnerabilityFinding is for parsing govulncheck JSON output
|
||||
type VulnerabilityFinding struct {
|
||||
Finding Finding `json:"finding"`
|
||||
}
|
||||
|
||||
type Finding struct {
|
||||
OSV string `json:"osv"`
|
||||
FixedVersion string `json:"fixed_version"`
|
||||
Trace []Trace `json:"trace"`
|
||||
}
|
||||
|
||||
type Trace struct {
|
||||
Module string `json:"module"`
|
||||
Version string `json:"version"`
|
||||
Package string `json:"package"`
|
||||
}
|
||||
|
||||
// UniqueKey is used to identify unique vulnerability-subcomponent pairs
|
||||
type UniqueKey struct {
|
||||
VulnerabilityID vex.VulnerabilityID
|
||||
SubcomponentID string
|
||||
}
|
||||
|
||||
func main() {
|
||||
if err := run(); err != nil {
|
||||
log.Fatal("Fatal error", log.Err(err))
|
||||
}
|
||||
}
|
||||
|
||||
// run is the main entry point for the VEX generator
|
||||
func run() error {
|
||||
log.InitLogger(false, false)
|
||||
|
||||
// Parse command-line flags
|
||||
cloneDir := flag.String("dir", "trivy", "Directory to clone the repository")
|
||||
output := flag.String("output", ".vex/trivy.openvex.json", "Output file")
|
||||
flag.Parse()
|
||||
|
||||
ctx := context.Background()
|
||||
|
||||
// Clone or pull the Trivy repository
|
||||
if _, err := cloneOrPullRepo(ctx, *cloneDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// Ensure we are on the main branch after processing
|
||||
_, _ = checkoutMain(ctx, *cloneDir)
|
||||
}()
|
||||
|
||||
// Save the current working directory
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get current working directory: %w", err)
|
||||
}
|
||||
|
||||
// Change to the target directory as govulncheck doesn't support Dir
|
||||
// cf. https://github.com/golang/go/blob/6d89b38ed86e0bfa0ddaba08dc4071e6bb300eea/src/os/exec/exec.go#L171-L174
|
||||
if err = os.Chdir(*cloneDir); err != nil {
|
||||
return fmt.Errorf("failed to change to directory %s: %w", *cloneDir, err)
|
||||
}
|
||||
|
||||
// Get the latest tags from the repository
|
||||
tags, err := getLatestTags(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("Latest tags", log.Any("tags", tags))
|
||||
|
||||
// Maps to store "not_affected" statements across Trivy versions
|
||||
notAffectedVulns := make(map[UniqueKey][]vex.Statement)
|
||||
|
||||
// Indicate one or more Trivy versions are affected by the vulnerability.
|
||||
// This means that the version cannot be omitted later.
|
||||
affectedVulns := make(map[UniqueKey]struct{})
|
||||
|
||||
// Process each tag
|
||||
for _, tag := range tags {
|
||||
notAffected, affected, err := processTag(ctx, tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("Processed tag", log.String("tag", tag),
|
||||
log.Int("not_affected", len(notAffected)), log.Int("affected", len(affected)))
|
||||
lo.Assign(affectedVulns, affected)
|
||||
for k, v := range notAffected {
|
||||
notAffectedVulns[k] = append(notAffectedVulns[k], v)
|
||||
}
|
||||
}
|
||||
|
||||
// Change back to the original directory
|
||||
if err = os.Chdir(wd); err != nil {
|
||||
return fmt.Errorf("failed to change back to original directory: %w", err)
|
||||
}
|
||||
|
||||
// Generate the final VEX document
|
||||
if err = updateVEX(*output, combineDocs(notAffectedVulns, affectedVulns)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// cloneOrPullRepo clones the Trivy repository or pulls updates if it already exists
|
||||
func cloneOrPullRepo(ctx context.Context, dir string) ([]byte, error) {
|
||||
if _, err := os.Stat(dir); os.IsNotExist(err) {
|
||||
return runCommandWithTimeout(ctx, 20*time.Minute, "git", "clone", repoURL, dir)
|
||||
}
|
||||
|
||||
if _, err := checkoutMain(ctx, dir); err != nil {
|
||||
return nil, fmt.Errorf("failed to checkout main: %w", err)
|
||||
}
|
||||
return runCommandWithTimeout(ctx, 2*time.Minute, "git", "-C", dir, "pull", "--tags")
|
||||
}
|
||||
|
||||
// checkoutMain checks out the main branch of the repository
|
||||
func checkoutMain(ctx context.Context, dir string) ([]byte, error) {
|
||||
return runCommandWithTimeout(ctx, 1*time.Minute, "git", "-C", dir, "checkout", "main")
|
||||
}
|
||||
|
||||
// getLatestTags retrieves and sorts the latest tags from the repository
|
||||
func getLatestTags(ctx context.Context) ([]string, error) {
|
||||
output, err := runCommandWithTimeout(ctx, 1*time.Minute, "git", "tag")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get tags: %w", err)
|
||||
}
|
||||
|
||||
tags := strings.Split(strings.TrimSpace(string(output)), "\n")
|
||||
versions := make([]string, 0, len(tags))
|
||||
|
||||
for _, tag := range tags {
|
||||
v, err := version.Parse(tag)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if v.GreaterThanOrEqual(minVer) {
|
||||
versions = append(versions, tag)
|
||||
}
|
||||
}
|
||||
|
||||
return versions, nil
|
||||
}
|
||||
|
||||
// processTag processes a single tag, running govulncheck and generating VEX statements
|
||||
func processTag(ctx context.Context, tag string) (map[UniqueKey]vex.Statement, map[UniqueKey]struct{}, error) {
|
||||
log.Info("Processing tag...", log.String("tag", tag))
|
||||
if _, err := runCommandWithTimeout(ctx, 1*time.Minute, "git", "checkout", tag); err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to checkout tag %s: %w", tag, err)
|
||||
}
|
||||
|
||||
// Run govulncheck and generate VEX document
|
||||
vexDoc, err := generateVEX(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to run govulncheck: %w", err)
|
||||
}
|
||||
|
||||
// Run govulncheck and generate JSON result
|
||||
// Need to generate JSON as well as OpenVEX for the following reasons:
|
||||
// - Subcomponent
|
||||
// - OpenVEX from govulncheck doesn't fill in subcomponents.
|
||||
// - Status
|
||||
// - govulncheck uses "not_affected" for all vulnerabilities. Need to determine "fixed" vulnerabilities.
|
||||
// cf. https://github.com/golang/go/issues/68338
|
||||
findings, err := generateJSON(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to run govulncheck: %w", err)
|
||||
}
|
||||
|
||||
product := *productID // Clone Trivy PURL
|
||||
product.Version = tag
|
||||
notAffected := make(map[UniqueKey]vex.Statement)
|
||||
affected := make(map[UniqueKey]struct{})
|
||||
|
||||
// Update VEX document generated by govulncheck
|
||||
for _, stmt := range vexDoc.Statements {
|
||||
finding, ok := findings[stmt.Vulnerability.Name]
|
||||
if !ok {
|
||||
// Considered as "fixed" vulnerabilities
|
||||
// cf. https://github.com/golang/go/issues/68338
|
||||
continue
|
||||
} else if len(finding.Finding.Trace) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
namespace, name := path.Split(finding.Finding.Trace[0].Module)
|
||||
subcomponent := &packageurl.PackageURL{
|
||||
Type: packageurl.TypeGolang,
|
||||
Namespace: namespace,
|
||||
Name: name,
|
||||
}
|
||||
|
||||
key := UniqueKey{
|
||||
VulnerabilityID: stmt.Vulnerability.Name,
|
||||
SubcomponentID: subcomponent.String(),
|
||||
}
|
||||
|
||||
if stmt.Status == vex.StatusAffected {
|
||||
affected[key] = struct{}{}
|
||||
continue
|
||||
} else if stmt.Status != vex.StatusNotAffected {
|
||||
continue
|
||||
}
|
||||
|
||||
// Update the statement with product and subcomponent information
|
||||
stmt.Products = []vex.Product{
|
||||
{
|
||||
// Fill in components manually
|
||||
// cf. https://github.com/golang/go/issues/68152
|
||||
Component: vex.Component{
|
||||
ID: product.String(),
|
||||
Identifiers: map[vex.IdentifierType]string{
|
||||
vex.PURL: product.String(),
|
||||
},
|
||||
},
|
||||
Subcomponents: []vex.Subcomponent{
|
||||
{
|
||||
Component: vex.Component{
|
||||
ID: key.SubcomponentID,
|
||||
Identifiers: map[vex.IdentifierType]string{
|
||||
vex.PURL: key.SubcomponentID,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
notAffected[key] = stmt
|
||||
}
|
||||
|
||||
return notAffected, affected, nil
|
||||
}
|
||||
|
||||
// generateVEX runs govulncheck with OpenVEX format and parses the output
|
||||
func generateVEX(ctx context.Context) (*vex.VEX, error) {
|
||||
buf, err := runGovulncheck(ctx, "openvex")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to run govulncheck: %w", err)
|
||||
}
|
||||
|
||||
vexDoc, err := vex.Parse(buf.Bytes())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse govulncheck output: %w", err)
|
||||
}
|
||||
return vexDoc, nil
|
||||
}
|
||||
|
||||
// generateJSON runs govulncheck with JSON format and parses the output
|
||||
func generateJSON(ctx context.Context) (map[vex.VulnerabilityID]VulnerabilityFinding, error) {
|
||||
buf, err := runGovulncheck(ctx, "json")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to run govulncheck: %w", err)
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(buf)
|
||||
findings := make(map[vex.VulnerabilityID]VulnerabilityFinding)
|
||||
for {
|
||||
var finding VulnerabilityFinding
|
||||
if err := decoder.Decode(&finding); err == io.EOF {
|
||||
break
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode govulncheck output: %w", err)
|
||||
}
|
||||
findings[vex.VulnerabilityID(finding.Finding.OSV)] = finding
|
||||
}
|
||||
return findings, nil
|
||||
}
|
||||
|
||||
// runGovulncheck executes the govulncheck command with the specified format
|
||||
func runGovulncheck(ctx context.Context, format string) (*bytes.Buffer, error) {
|
||||
var buf bytes.Buffer
|
||||
cmd := scan.Command(ctx, "-format", format, "./...")
|
||||
cmd.Stdout = &buf
|
||||
|
||||
log.Info("Running govulncheck", log.String("format", format))
|
||||
if err := cmd.Start(); err != nil {
|
||||
return nil, fmt.Errorf("failed to start govulncheck: %w", err)
|
||||
}
|
||||
|
||||
if err := cmd.Wait(); err != nil {
|
||||
return nil, fmt.Errorf("failed to run govulncheck: %w", err)
|
||||
}
|
||||
return &buf, nil
|
||||
}
|
||||
|
||||
// combineDocs merges the VEX statements from all processed tags
|
||||
func combineDocs(notAffected map[UniqueKey][]vex.Statement, affected map[UniqueKey]struct{}) []vex.Statement {
|
||||
log.Info("Combining VEX documents")
|
||||
statements := make(map[UniqueKey]vex.Statement)
|
||||
for key, stmts := range notAffected {
|
||||
for _, stmt := range stmts {
|
||||
if _, ok := affected[key]; !ok {
|
||||
// All versions are "not_affected" or "fixed" by the vulnerability, omitting a version in PURL
|
||||
// => pkg:golang/github.com/aquasecurity/trivy
|
||||
stmt.Products[0].ID = productID.String()
|
||||
stmt.Products[0].Identifiers[vex.PURL] = productID.String()
|
||||
statements[key] = stmt
|
||||
break
|
||||
}
|
||||
|
||||
// At least one version is "affected" by the vulnerability, so we need to include the version in PURL.
|
||||
// => pkg:golang/github.com/aquasecurity/trivy@0.52.0
|
||||
if s, ok := statements[key]; ok {
|
||||
s.Products = append(s.Products, stmt.Products...)
|
||||
statements[key] = s
|
||||
} else {
|
||||
statements[key] = stmt
|
||||
}
|
||||
}
|
||||
}
|
||||
return lo.Values(statements)
|
||||
}
|
||||
|
||||
// runCommandWithTimeout executes a command with a specified timeout
|
||||
func runCommandWithTimeout(ctx context.Context, timeout time.Duration, name string, args ...string) ([]byte, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, timeout)
|
||||
defer cancel()
|
||||
|
||||
cmd := exec.CommandContext(ctx, name, args...)
|
||||
log.Info("Executing command", log.String("cmd", cmd.String()))
|
||||
|
||||
output, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
return output, fmt.Errorf("%w, output: %s", err, string(output))
|
||||
}
|
||||
|
||||
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
|
||||
return nil, fmt.Errorf("command timed out after %v", timeout)
|
||||
}
|
||||
|
||||
return output, nil
|
||||
}
|
||||
|
||||
// updateVEX updates the final VEX document with the combined statements
|
||||
func updateVEX(output string, statements []vex.Statement) error {
|
||||
doc, err := vex.Load(output)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
doc = &vex.VEX{}
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vex.SortStatements(statements, time.Now())
|
||||
d := &vex.VEX{
|
||||
Metadata: vex.Metadata{
|
||||
Context: "https://openvex.dev/ns/v0.2.0",
|
||||
Author: "Aqua Security",
|
||||
Timestamp: lo.ToPtr(time.Now()),
|
||||
Version: doc.Version + 1,
|
||||
Tooling: "https://github.com/aquasecurity/trivy/tree/main/magefiles/vex.go",
|
||||
},
|
||||
Statements: statements,
|
||||
}
|
||||
h, err := hashVEX(d)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
d.ID = "aquasecurity/trivy:" + h
|
||||
|
||||
f, err := os.Create(output)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
e := json.NewEncoder(f)
|
||||
e.SetIndent("", " ")
|
||||
if err = e.Encode(d); err != nil {
|
||||
return err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func hashVEX(d *vex.VEX) (string, error) {
|
||||
out, err := json.Marshal(d)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return fmt.Sprintf("%x", sha256.Sum256(out)), nil
|
||||
}
|
||||
Reference in New Issue
Block a user