BREAKING: migrate the sarif template to Go code (#1437)

Co-authored-by: knqyf263 <knqyf263@gmail.com>
This commit is contained in:
afdesk
2022-01-12 12:49:47 +06:00
committed by GitHub
parent 714b5ca246
commit 8da20c8c92
21 changed files with 624 additions and 369 deletions

View File

@@ -1,100 +0,0 @@
{
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
"version": "2.1.0",
{{- $rules := makeRuleMap }}
"runs": [
{
"tool": {
"driver": {
"name": "Trivy",
"informationUri": "https://github.com/aquasecurity/trivy",
"fullName": "Trivy Vulnerability Scanner",
"version": "0.15.0",
"rules": [
{{- $t_first := true }}
{{- range $result := . }}
{{- $vulnerabilityType := .Type }}
{{- range .Vulnerabilities -}}
{{- if indexRule $rules .VulnerabilityID -}}
{{- if $t_first -}}
{{- $t_first = false -}}
{{ else -}}
,
{{- end }}
{
"id": {{ .VulnerabilityID | toJson }},
"name": "{{ toSarifRuleName $vulnerabilityType }}",
"shortDescription": {
"text": {{ .VulnerabilityID | toJson }}
},
"fullDescription": {
"text": {{ endWithPeriod (escapeString .Title) | printf "%q" }}
},
"defaultConfiguration": {
"level": "{{ toSarifErrorLevel .Vulnerability.Severity }}"
}
{{- with $help_uri := .PrimaryURL -}}
,
{{ $help_uri | printf "\"helpUri\": %q," -}}
{{- else -}}
,
{{- end }}
"help": {
"text": {{ printf "Vulnerability %v\n%v\nSeverity: %v\nPackage: %v\nFixed Version: %v\nLink: [%v](%v)" .VulnerabilityID .Vulnerability.Description .Vulnerability.Severity .PkgName .FixedVersion .VulnerabilityID .PrimaryURL | printf "%q"}},
"markdown": {{ printf "**Vulnerability %v**\n%v\n| Severity | Package | Fixed Version | Link |\n| --- | --- | --- | --- |\n|%v|%v|%v|[%v](%v)|\n" .VulnerabilityID .Vulnerability.Description .Vulnerability.Severity .PkgName .FixedVersion .VulnerabilityID .PrimaryURL | printf "%q"}}
},
"properties": {
"tags": [
"vulnerability",
"{{ .Vulnerability.Severity }}"
],
"precision": "very-high"
}
}
{{- end -}}
{{- end -}}
{{- end -}}
]
}
},
"results": [
{{- $t_first := true }}
{{- range $result := . }}
{{- $filePath := .Target }}
{{- range $index, $vulnerability := .Vulnerabilities -}}
{{- if $t_first -}}
{{- $t_first = false -}}
{{ else -}}
,
{{- end }}
{
"ruleId": {{ .VulnerabilityID | toJson }},
"ruleIndex": {{ index $rules .VulnerabilityID }},
"level": "{{ toSarifErrorLevel $vulnerability.Vulnerability.Severity }}",
"message": {
"text": {{ printf "Package: %v\nInstalled Version: %v\nVulnerability %v\nSeverity: %v\nFixed Version: %v\nLink: [%v](%v)" .PkgName .InstalledVersion .VulnerabilityID .Vulnerability.Severity .FixedVersion .VulnerabilityID .PrimaryURL | printf "%q"}}
},
"locations": [{
"physicalLocation": {
"artifactLocation": {
"uri": "{{ toPathUri $filePath }}",
"uriBaseId": "ROOTPATH"
},
"region" : {
"startLine": 1
}
}
}]
}
{{- end -}}
{{- end -}}
],
"columnKind": "utf16CodeUnits",
"originalUriBaseIds": {
"ROOTPATH": {
"uri": "file:///"
}
}
}
]
}

View File

@@ -9,7 +9,7 @@ USAGE:
OPTIONS:
--template value, -t value output template [$TRIVY_TEMPLATE]
--format value, -f value format (table, json, template) (default: "table") [$TRIVY_FORMAT]
--format value, -f value format (table, json, sarif, template) (default: "table") [$TRIVY_FORMAT]
--input value, -i value input file path instead of image name [$TRIVY_INPUT]
--severity value, -s value severities of vulnerabilities to be displayed (comma separated) (default: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL") [$TRIVY_SEVERITY]
--output value, -o value output file name [$TRIVY_OUTPUT]

View File

@@ -9,7 +9,7 @@ USAGE:
OPTIONS:
--template value, -t value output template [$TRIVY_TEMPLATE]
--format value, -f value format (table, json, template) (default: "table") [$TRIVY_FORMAT]
--format value, -f value format (table, json, sarif, template) (default: "table") [$TRIVY_FORMAT]
--severity value, -s value severities of vulnerabilities to be displayed (comma separated) (default: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL") [$TRIVY_SEVERITY]
--output value, -o value output file name [$TRIVY_OUTPUT]
--exit-code value Exit code when vulnerabilities were found (default: 0) [$TRIVY_EXIT_CODE]

View File

@@ -9,7 +9,7 @@ USAGE:
OPTIONS:
--template value, -t value output template [$TRIVY_TEMPLATE]
--format value, -f value format (table, json, template) (default: "table") [$TRIVY_FORMAT]
--format value, -f value format (table, json, sarif, template) (default: "table") [$TRIVY_FORMAT]
--severity value, -s value severities of vulnerabilities to be displayed (comma separated) (default: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL") [$TRIVY_SEVERITY]
--output value, -o value output file name [$TRIVY_OUTPUT]
--exit-code value Exit code when vulnerabilities were found (default: 0) [$TRIVY_EXIT_CODE]

View File

@@ -9,7 +9,7 @@ USAGE:
OPTIONS:
--template value, -t value output template [$TRIVY_TEMPLATE]
--format value, -f value format (table, json, template) (default: "table") [$TRIVY_FORMAT]
--format value, -f value format (table, json, sarif, template) (default: "table") [$TRIVY_FORMAT]
--input value, -i value input file path instead of image name [$TRIVY_INPUT]
--severity value, -s value severities of vulnerabilities to be displayed (comma separated) (default: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL") [$TRIVY_SEVERITY]
--output value, -o value output file name [$TRIVY_OUTPUT]

View File

@@ -9,7 +9,7 @@ USAGE:
OPTIONS:
--template value, -t value output template [$TRIVY_TEMPLATE]
--format value, -f value format (table, json, template) (default: "table") [$TRIVY_FORMAT]
--format value, -f value format (table, json, sarif, template) (default: "table") [$TRIVY_FORMAT]
--input value, -i value input file path instead of image name [$TRIVY_INPUT]
--severity value, -s value severities of vulnerabilities to be displayed (comma separated) (default: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL") [$TRIVY_SEVERITY]
--output value, -o value output file name [$TRIVY_OUTPUT]

View File

@@ -9,7 +9,7 @@ USAGE:
OPTIONS:
--template value, -t value output template [$TRIVY_TEMPLATE]
--format value, -f value format (table, json, template) (default: "table") [$TRIVY_FORMAT]
--format value, -f value format (table, json, sarif, template) (default: "table") [$TRIVY_FORMAT]
--severity value, -s value severities of vulnerabilities to be displayed (comma separated) (default: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL") [$TRIVY_SEVERITY]
--output value, -o value output file name [$TRIVY_OUTPUT]
--exit-code value Exit code when vulnerabilities were found (default: 0) [$TRIVY_EXIT_CODE]

View File

@@ -3,4 +3,4 @@
See [Reports Formats](../../vulnerability/examples/report.md) in Vulnerability section.
!!! caution
Misconfiguration scanning doesn't support default templates such as XML and SARIF for now.
Misconfiguration scanning doesn't support default templates such as XML for now.

View File

@@ -136,6 +136,15 @@ $ trivy image -f json -o results.json golang:1.12-alpine
`VulnerabilityID`, `PkgName`, `InstalledVersion`, and `Severity` in `Vulnerabilities` are always filled with values, but other fields might be empty.
## SARIF
[Sarif][sarif] can be generated with the `--format sarif` option.
```
$ trivy image --format sarif -o report.sarif golang:1.12-alpine
```
This SARIF file can be uploaded to GitHub code scanning results, and there is a [Trivy GitHub Action][action] for automating this process.
## Template
### Custom Template
@@ -192,13 +201,7 @@ In the following example using the template `junit.tpl` XML can be generated.
$ trivy image --format template --template "@contrib/junit.tpl" -o junit-report.xml golang:1.12-alpine
```
#### SARIF
In the following example using the template `sarif.tpl` [Sarif][sarif] can be generated.
```
$ trivy image --format template --template "@contrib/sarif.tpl" -o report.sarif golang:1.12-alpine
```
This SARIF format can be uploaded to GitHub code scanning results, and there is a [Trivy GitHub Action][action] for automating this process.
#### ASFF
Trivy also supports an [ASFF template for reporting findings to AWS Security Hub][asff]
#### HTML

1
go.mod
View File

@@ -35,6 +35,7 @@ require (
github.com/mitchellh/copystructure v1.1.1 // indirect
github.com/olekukonko/tablewriter v0.0.5
github.com/open-policy-agent/opa v0.34.0
github.com/owenrumney/go-sarif/v2 v2.0.17
github.com/spf13/afero v1.6.0
github.com/stretchr/objx v0.3.0 // indirect
github.com/stretchr/testify v1.7.0

4
go.sum
View File

@@ -1246,6 +1246,10 @@ github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnh
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/owenrumney/go-sarif v1.0.10/go.mod h1:sgJM0ZaZ28jT8t8Iq3/mUCFBW9cX09EobIBXYOhiYBc=
github.com/owenrumney/go-sarif v1.0.12/go.mod h1:Jk5smXU9QuCqTdh4N3PehnG+azzrf0XcQ267ZwAG8Ho=
github.com/owenrumney/go-sarif v1.1.1 h1:QNObu6YX1igyFKhdzd7vgzmw7XsWN3/6NMGuDzBgXmE=
github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U=
github.com/owenrumney/go-sarif/v2 v2.0.17 h1:F3V0IQYMjOqBtfnQQWC+yv5dTISkcZuG/9YBv0mIEBE=
github.com/owenrumney/go-sarif/v2 v2.0.17/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w=
github.com/owenrumney/squealer v0.2.28 h1:LYsqUHal+5QlANjbZ+h44SN5kIZSfHCWKUzBAS1KwB0=
github.com/owenrumney/squealer v0.2.28/go.mod h1:wwVPzhjiUBILIdDtnzGSEcapXczIj/tONP+ZJ49IhPY=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=

View File

@@ -246,10 +246,9 @@ func TestClientServerWithTemplate(t *testing.T) {
golden: "testdata/alpine-310.gitlab-codequality.golden",
},
{
name: "alpine 3.10 with sarif template",
name: "alpine 3.10 with sarif format",
args: csArgs{
Format: "template",
TemplatePath: "@../contrib/sarif.tpl",
Format: "sarif",
Input: "testdata/fixtures/images/alpine-310.tar.gz",
},
golden: "testdata/alpine-310.sarif.golden",

View File

@@ -1,14 +1,13 @@
{
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
"version": "2.1.0",
"$schema": "https://json.schemastore.org/sarif-2.1.0-rtm.5.json",
"runs": [
{
"tool": {
"driver": {
"name": "Trivy",
"informationUri": "https://github.com/aquasecurity/trivy",
"fullName": "Trivy Vulnerability Scanner",
"version": "0.15.0",
"informationUri": "https://github.com/aquasecurity/trivy",
"name": "Trivy",
"rules": [
{
"id": "CVE-2019-1549",
@@ -17,22 +16,24 @@
"text": "CVE-2019-1549"
},
"fullDescription": {
"text": "openssl: information disclosure in fork()."
"text": "OpenSSL 1.1.1 introduced a rewritten random number generator (RNG). This was intended to include protection in the event of a fork() system call in order to ensure that the parent and child processes did not share the same RNG state. However this protection was not being used in the default case. A partial mitigation for this issue is that the output from a high precision timer is mixed into the RNG state so the likelihood of a parent and child process sharing state is significantly reduced. If an application already calls OPENSSL_init_crypto() explicitly using OPENSSL_INIT_ATFORK then this problem does not occur at all. Fixed in OpenSSL 1.1.1d (Affected 1.1.1-1.1.1c)."
},
"defaultConfiguration": {
"level": "warning"
},
"helpUri": "https://avd.aquasec.com/nvd/cve-2019-1549",
"help": {
"text": "Vulnerability CVE-2019-1549\nOpenSSL 1.1.1 introduced a rewritten random number generator (RNG). This was intended to include protection in the event of a fork() system call in order to ensure that the parent and child processes did not share the same RNG state. However this protection was not being used in the default case. A partial mitigation for this issue is that the output from a high precision timer is mixed into the RNG state so the likelihood of a parent and child process sharing state is significantly reduced. If an application already calls OPENSSL_init_crypto() explicitly using OPENSSL_INIT_ATFORK then this problem does not occur at all. Fixed in OpenSSL 1.1.1d (Affected 1.1.1-1.1.1c).\nSeverity: MEDIUM\nPackage: libcrypto1.1\nFixed Version: 1.1.1d-r0\nLink: [CVE-2019-1549](https://avd.aquasec.com/nvd/cve-2019-1549)",
"markdown": "**Vulnerability CVE-2019-1549**\nOpenSSL 1.1.1 introduced a rewritten random number generator (RNG). This was intended to include protection in the event of a fork() system call in order to ensure that the parent and child processes did not share the same RNG state. However this protection was not being used in the default case. A partial mitigation for this issue is that the output from a high precision timer is mixed into the RNG state so the likelihood of a parent and child process sharing state is significantly reduced. If an application already calls OPENSSL_init_crypto() explicitly using OPENSSL_INIT_ATFORK then this problem does not occur at all. Fixed in OpenSSL 1.1.1d (Affected 1.1.1-1.1.1c).\n| Severity | Package | Fixed Version | Link |\n| --- | --- | --- | --- |\n|MEDIUM|libcrypto1.1|1.1.1d-r0|[CVE-2019-1549](https://avd.aquasec.com/nvd/cve-2019-1549)|\n"
"text": "Vulnerability CVE-2019-1549\nSeverity: MEDIUM\nPackage: libssl1.1\nFixed Version: 1.1.1d-r0\nLink: [CVE-2019-1549](https://avd.aquasec.com/nvd/cve-2019-1549)\nOpenSSL 1.1.1 introduced a rewritten random number generator (RNG). This was intended to include protection in the event of a fork() system call in order to ensure that the parent and child processes did not share the same RNG state. However this protection was not being used in the default case. A partial mitigation for this issue is that the output from a high precision timer is mixed into the RNG state so the likelihood of a parent and child process sharing state is significantly reduced. If an application already calls OPENSSL_init_crypto() explicitly using OPENSSL_INIT_ATFORK then this problem does not occur at all. Fixed in OpenSSL 1.1.1d (Affected 1.1.1-1.1.1c).",
"markdown": "**Vulnerability CVE-2019-1549**\n| Severity | Package | Fixed Version | Link |\n| --- | --- | --- | --- |\n|MEDIUM|libssl1.1|1.1.1d-r0|[CVE-2019-1549](https://avd.aquasec.com/nvd/cve-2019-1549)|\n\nOpenSSL 1.1.1 introduced a rewritten random number generator (RNG). This was intended to include protection in the event of a fork() system call in order to ensure that the parent and child processes did not share the same RNG state. However this protection was not being used in the default case. A partial mitigation for this issue is that the output from a high precision timer is mixed into the RNG state so the likelihood of a parent and child process sharing state is significantly reduced. If an application already calls OPENSSL_init_crypto() explicitly using OPENSSL_INIT_ATFORK then this problem does not occur at all. Fixed in OpenSSL 1.1.1d (Affected 1.1.1-1.1.1c)."
},
"properties": {
"precision": "very-high",
"security-severity": "5.3",
"tags": [
"vulnerability",
"security",
"MEDIUM"
],
"precision": "very-high"
]
}
},
{
@@ -42,24 +43,28 @@
"text": "CVE-2019-1551"
},
"fullDescription": {
"text": "openssl: Integer overflow in RSAZ modular exponentiation on x86_64."
"text": "There is an overflow bug in the x64_64 Montgomery squaring procedure used in exponentiation with 512-bit moduli. No EC algorithms are affected. Analysis suggests that attacks against 2-prime RSA1024, 3-prime RSA1536, and DSA1024 as a result of this defect would be very difficult to perform and are not believed likely. Attacks against DH512 are considered just feasible. However, for an attack the target would have to re-use the DH512 private key, which is not recommended anyway. Also applications directly using the low level API BN_mod_exp may be affected if they use BN_FLG_CONSTTIME. Fixed in OpenSSL 1.1.1e (Affected 1.1.1-1.1.1d). Fixed in OpenSSL 1.0.2u (Affected 1.0.2-1.0.2t)."
},
"defaultConfiguration": {
"level": "warning"
},
"helpUri": "https://avd.aquasec.com/nvd/cve-2019-1551",
"help": {
"text": "Vulnerability CVE-2019-1551\nThere is an overflow bug in the x64_64 Montgomery squaring procedure used in exponentiation with 512-bit moduli. No EC algorithms are affected. Analysis suggests that attacks against 2-prime RSA1024, 3-prime RSA1536, and DSA1024 as a result of this defect would be very difficult to perform and are not believed likely. Attacks against DH512 are considered just feasible. However, for an attack the target would have to re-use the DH512 private key, which is not recommended anyway. Also applications directly using the low level API BN_mod_exp may be affected if they use BN_FLG_CONSTTIME. Fixed in OpenSSL 1.1.1e (Affected 1.1.1-1.1.1d). Fixed in OpenSSL 1.0.2u (Affected 1.0.2-1.0.2t).\nSeverity: MEDIUM\nPackage: libcrypto1.1\nFixed Version: 1.1.1d-r2\nLink: [CVE-2019-1551](https://avd.aquasec.com/nvd/cve-2019-1551)",
"markdown": "**Vulnerability CVE-2019-1551**\nThere is an overflow bug in the x64_64 Montgomery squaring procedure used in exponentiation with 512-bit moduli. No EC algorithms are affected. Analysis suggests that attacks against 2-prime RSA1024, 3-prime RSA1536, and DSA1024 as a result of this defect would be very difficult to perform and are not believed likely. Attacks against DH512 are considered just feasible. However, for an attack the target would have to re-use the DH512 private key, which is not recommended anyway. Also applications directly using the low level API BN_mod_exp may be affected if they use BN_FLG_CONSTTIME. Fixed in OpenSSL 1.1.1e (Affected 1.1.1-1.1.1d). Fixed in OpenSSL 1.0.2u (Affected 1.0.2-1.0.2t).\n| Severity | Package | Fixed Version | Link |\n| --- | --- | --- | --- |\n|MEDIUM|libcrypto1.1|1.1.1d-r2|[CVE-2019-1551](https://avd.aquasec.com/nvd/cve-2019-1551)|\n"
"text": "Vulnerability CVE-2019-1551\nSeverity: MEDIUM\nPackage: libssl1.1\nFixed Version: 1.1.1d-r2\nLink: [CVE-2019-1551](https://avd.aquasec.com/nvd/cve-2019-1551)\nThere is an overflow bug in the x64_64 Montgomery squaring procedure used in exponentiation with 512-bit moduli. No EC algorithms are affected. Analysis suggests that attacks against 2-prime RSA1024, 3-prime RSA1536, and DSA1024 as a result of this defect would be very difficult to perform and are not believed likely. Attacks against DH512 are considered just feasible. However, for an attack the target would have to re-use the DH512 private key, which is not recommended anyway. Also applications directly using the low level API BN_mod_exp may be affected if they use BN_FLG_CONSTTIME. Fixed in OpenSSL 1.1.1e (Affected 1.1.1-1.1.1d). Fixed in OpenSSL 1.0.2u (Affected 1.0.2-1.0.2t).",
"markdown": "**Vulnerability CVE-2019-1551**\n| Severity | Package | Fixed Version | Link |\n| --- | --- | --- | --- |\n|MEDIUM|libssl1.1|1.1.1d-r2|[CVE-2019-1551](https://avd.aquasec.com/nvd/cve-2019-1551)|\n\nThere is an overflow bug in the x64_64 Montgomery squaring procedure used in exponentiation with 512-bit moduli. No EC algorithms are affected. Analysis suggests that attacks against 2-prime RSA1024, 3-prime RSA1536, and DSA1024 as a result of this defect would be very difficult to perform and are not believed likely. Attacks against DH512 are considered just feasible. However, for an attack the target would have to re-use the DH512 private key, which is not recommended anyway. Also applications directly using the low level API BN_mod_exp may be affected if they use BN_FLG_CONSTTIME. Fixed in OpenSSL 1.1.1e (Affected 1.1.1-1.1.1d). Fixed in OpenSSL 1.0.2u (Affected 1.0.2-1.0.2t)."
},
"properties": {
"precision": "very-high",
"security-severity": "5.3",
"tags": [
"vulnerability",
"security",
"MEDIUM"
],
"precision": "very-high"
]
}
}]
}
],
"version": "dev"
}
},
"results": [
@@ -70,17 +75,19 @@
"message": {
"text": "Package: libcrypto1.1\nInstalled Version: 1.1.1c-r0\nVulnerability CVE-2019-1549\nSeverity: MEDIUM\nFixed Version: 1.1.1d-r0\nLink: [CVE-2019-1549](https://avd.aquasec.com/nvd/cve-2019-1549)"
},
"locations": [{
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "testdata/fixtures/images/alpine-310.tar.gz",
"uriBaseId": "ROOTPATH"
},
"region" : {
"region": {
"startLine": 1
}
}
}]
}
]
},
{
"ruleId": "CVE-2019-1551",
@@ -89,17 +96,19 @@
"message": {
"text": "Package: libcrypto1.1\nInstalled Version: 1.1.1c-r0\nVulnerability CVE-2019-1551\nSeverity: MEDIUM\nFixed Version: 1.1.1d-r2\nLink: [CVE-2019-1551](https://avd.aquasec.com/nvd/cve-2019-1551)"
},
"locations": [{
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "testdata/fixtures/images/alpine-310.tar.gz",
"uriBaseId": "ROOTPATH"
},
"region" : {
"region": {
"startLine": 1
}
}
}]
}
]
},
{
"ruleId": "CVE-2019-1549",
@@ -108,17 +117,19 @@
"message": {
"text": "Package: libssl1.1\nInstalled Version: 1.1.1c-r0\nVulnerability CVE-2019-1549\nSeverity: MEDIUM\nFixed Version: 1.1.1d-r0\nLink: [CVE-2019-1549](https://avd.aquasec.com/nvd/cve-2019-1549)"
},
"locations": [{
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "testdata/fixtures/images/alpine-310.tar.gz",
"uriBaseId": "ROOTPATH"
},
"region" : {
"region": {
"startLine": 1
}
}
}]
}
]
},
{
"ruleId": "CVE-2019-1551",
@@ -127,18 +138,21 @@
"message": {
"text": "Package: libssl1.1\nInstalled Version: 1.1.1c-r0\nVulnerability CVE-2019-1551\nSeverity: MEDIUM\nFixed Version: 1.1.1d-r2\nLink: [CVE-2019-1551](https://avd.aquasec.com/nvd/cve-2019-1551)"
},
"locations": [{
"locations": [
{
"physicalLocation": {
"artifactLocation": {
"uri": "testdata/fixtures/images/alpine-310.tar.gz",
"uriBaseId": "ROOTPATH"
},
"region" : {
"region": {
"startLine": 1
}
}
}]
}],
}
]
}
],
"columnKind": "utf16CodeUnits",
"originalUriBaseIds": {
"ROOTPATH": {

View File

@@ -41,7 +41,7 @@ var (
Name: "format",
Aliases: []string{"f"},
Value: "table",
Usage: "format (table, json, template)",
Usage: "format (table, json, sarif, template)",
EnvVars: []string{"TRIVY_FORMAT"},
}

View File

@@ -77,6 +77,7 @@ func runWithTimeout(ctx context.Context, opt Option, initializeScanner Initializ
}
if err = pkgReport.Write(report, pkgReport.Option{
AppVersion: opt.GlobalOption.AppVersion,
Format: opt.Format,
Output: opt.Output,
Severities: opt.Severities,

View File

@@ -85,6 +85,7 @@ func runWithTimeout(ctx context.Context, opt Option) error {
}
if err = pkgReport.Write(report, pkgReport.Option{
AppVersion: opt.GlobalOption.AppVersion,
Format: opt.Format,
Output: opt.Output,
Severities: opt.Severities,

232
pkg/report/sarif.go Normal file
View File

@@ -0,0 +1,232 @@
package report
import (
"fmt"
"html"
"io"
"regexp"
"strings"
"github.com/owenrumney/go-sarif/v2/sarif"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy/pkg/types"
)
const (
sarifOsPackageVulnerability = "OsPackageVulnerability"
sarifLanguageSpecificVulnerability = "LanguageSpecificPackageVulnerability"
sarifConfigFiles = "Misconfiguration"
sarifUnknownIssue = "UnknownIssue"
sarifError = "error"
sarifWarning = "warning"
sarifNote = "note"
sarifNone = "none"
columnKind = "utf16CodeUnits"
)
var (
rootPath = "file:///"
// pathRegex to extract file path in case string includes (distro:version)
pathRegex = regexp.MustCompile(`(?P<path>.+?)(?:\s*\((?:.*?)\).*?)?$`)
)
// SarifWriter implements result Writer
type SarifWriter struct {
Output io.Writer
Version string
run *sarif.Run
}
type sarifData struct {
title string
vulnerabilityId string
fullDescription string
helpText string
helpMarkdown string
resourceClass string
severity string
url string
resultIndex int
artifactLocation string
message string
cvssScore string
}
func (sw *SarifWriter) addSarifRule(data *sarifData) {
r := sw.run.AddRule(data.vulnerabilityId).
WithName(toSarifRuleName(data.resourceClass)).
WithDescription(data.vulnerabilityId).
WithFullDescription(&sarif.MultiformatMessageString{Text: &data.fullDescription}).
WithHelp(&sarif.MultiformatMessageString{
Text: &data.helpText,
Markdown: &data.helpMarkdown,
}).
WithDefaultConfiguration(&sarif.ReportingConfiguration{
Level: toSarifErrorLevel(data.severity),
}).
WithProperties(sarif.Properties{
"tags": []string{
data.title,
"security",
data.severity,
},
"precision": "very-high",
"security-severity": data.cvssScore,
})
if data.url != "" {
r.WithHelpURI(data.url)
}
}
func (sw *SarifWriter) addSarifResult(data *sarifData) {
sw.addSarifRule(data)
location := sarif.NewPhysicalLocation().
WithArtifactLocation(sarif.NewSimpleArtifactLocation(data.artifactLocation).WithUriBaseId("ROOTPATH")).
WithRegion(sarif.NewRegion().WithStartLine(1))
result := sarif.NewRuleResult(data.vulnerabilityId).
WithRuleIndex(data.resultIndex).
WithMessage(sarif.NewTextMessage(data.message)).
WithLevel(toSarifErrorLevel(data.severity)).
WithLocations([]*sarif.Location{sarif.NewLocation().WithPhysicalLocation(location)})
sw.run.AddResult(result)
}
func getRuleIndex(id string, indexes map[string]int) int {
if i, ok := indexes[id]; ok {
return i
} else {
l := len(indexes)
indexes[id] = l
return l
}
}
func (sw SarifWriter) Write(report Report) error {
sarifReport, err := sarif.New(sarif.Version210)
if err != nil {
return xerrors.Errorf("error creating a new sarif template: %w", err)
}
sw.run = sarif.NewRunWithInformationURI("Trivy", "https://github.com/aquasecurity/trivy")
sw.run.Tool.Driver.WithVersion(sw.Version)
sw.run.Tool.Driver.WithFullName("Trivy Vulnerability Scanner")
ruleIndexes := map[string]int{}
for _, res := range report.Results {
for _, vuln := range res.Vulnerabilities {
fullDescription := vuln.Description
if fullDescription == "" {
fullDescription = vuln.Title
}
path := vuln.PkgPath
if path == "" {
path = res.Target
}
sw.addSarifResult(&sarifData{
title: "vulnerability",
vulnerabilityId: vuln.VulnerabilityID,
severity: vuln.Severity,
cvssScore: getCVSSScore(vuln),
url: vuln.PrimaryURL,
resourceClass: string(res.Class),
artifactLocation: toPathUri(path),
resultIndex: getRuleIndex(vuln.VulnerabilityID, ruleIndexes),
fullDescription: html.EscapeString(fullDescription),
helpText: fmt.Sprintf("Vulnerability %v\nSeverity: %v\nPackage: %v\nFixed Version: %v\nLink: [%v](%v)\n%v",
vuln.VulnerabilityID, vuln.Severity, vuln.PkgName, vuln.FixedVersion, vuln.VulnerabilityID, vuln.PrimaryURL, vuln.Description),
helpMarkdown: fmt.Sprintf("**Vulnerability %v**\n| Severity | Package | Fixed Version | Link |\n| --- | --- | --- | --- |\n|%v|%v|%v|[%v](%v)|\n\n%v",
vuln.VulnerabilityID, vuln.Severity, vuln.PkgName, vuln.FixedVersion, vuln.VulnerabilityID, vuln.PrimaryURL, vuln.Description),
message: fmt.Sprintf("Package: %v\nInstalled Version: %v\nVulnerability %v\nSeverity: %v\nFixed Version: %v\nLink: [%v](%v)",
vuln.PkgName, vuln.InstalledVersion, vuln.VulnerabilityID, vuln.Severity, vuln.FixedVersion, vuln.VulnerabilityID, vuln.PrimaryURL),
})
}
for _, misconf := range res.Misconfigurations {
sw.addSarifResult(&sarifData{
title: "misconfiguration",
vulnerabilityId: misconf.ID,
severity: misconf.Severity,
cvssScore: severityToScore(misconf.Severity),
url: misconf.PrimaryURL,
resourceClass: string(res.Class),
artifactLocation: toPathUri(res.Target),
resultIndex: getRuleIndex(misconf.ID, ruleIndexes),
fullDescription: html.EscapeString(misconf.Description),
helpText: fmt.Sprintf("Misconfiguration %v\nType: %s\nSeverity: %v\nCheck: %v\nMessage: %v\nLink: [%v](%v)\n%s",
misconf.ID, misconf.Type, misconf.Severity, misconf.Title, misconf.Message, misconf.ID, misconf.PrimaryURL, misconf.Description),
helpMarkdown: fmt.Sprintf("**Misconfiguration %v**\n| Type | Severity | Check | Message | Link |\n| --- | --- | --- | --- | --- |\n|%v|%v|%v|%s|[%v](%v)|\n\n%v",
misconf.ID, misconf.Type, misconf.Severity, misconf.Title, misconf.Message, misconf.ID, misconf.PrimaryURL, misconf.Description),
message: fmt.Sprintf("Artifact: %v\nType: %v\nVulnerability %v\nSeverity: %v\nMessage: %v\nLink: [%v](%v)",
res.Target, res.Type, misconf.ID, misconf.Severity, misconf.Message, misconf.ID, misconf.PrimaryURL),
})
}
}
sw.run.ColumnKind = columnKind
sw.run.OriginalUriBaseIDs = map[string]*sarif.ArtifactLocation{
"ROOTPATH": {URI: &rootPath},
}
sarifReport.AddRun(sw.run)
return sarifReport.PrettyWrite(sw.Output)
}
func toSarifRuleName(class string) string {
switch class {
case ClassOSPkg:
return sarifOsPackageVulnerability
case ClassLangPkg:
return sarifLanguageSpecificVulnerability
case ClassConfig:
return sarifConfigFiles
default:
return sarifUnknownIssue
}
}
func toSarifErrorLevel(severity string) string {
switch severity {
case "CRITICAL", "HIGH":
return sarifError
case "MEDIUM":
return sarifWarning
case "LOW", "UNKNOWN":
return sarifNote
default:
return sarifNone
}
}
func toPathUri(input string) string {
var matches = pathRegex.FindStringSubmatch(input)
if matches != nil {
input = matches[pathRegex.SubexpIndex("path")]
}
return strings.ReplaceAll(input, "\\", "/")
}
func getCVSSScore(vuln types.DetectedVulnerability) string {
// Take the vendor score
if cvss, ok := vuln.CVSS[vuln.SeveritySource]; ok {
return fmt.Sprintf("%.1f", cvss.V3Score)
}
// Converts severity to score
return severityToScore(vuln.Severity)
}
func severityToScore(severity string) string {
switch severity {
case "CRITICAL":
return "9.5"
case "HIGH":
return "8.0"
case "MEDIUM":
return "5.5"
case "LOW":
return "2.0"
default:
return "0.0"
}
}

246
pkg/report/sarif_test.go Normal file
View File

@@ -0,0 +1,246 @@
package report_test
import (
"bytes"
"encoding/json"
"testing"
"github.com/owenrumney/go-sarif/v2/sarif"
"github.com/stretchr/testify/assert"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/report"
"github.com/aquasecurity/trivy/pkg/types"
)
func getStringPointer(s string) *string {
return &s
}
func getUintPointer(i uint) *uint {
return &i
}
func getIntPointer(i int) *int {
return &i
}
func TestReportWriter_Sarif(t *testing.T) {
tests := []struct {
name string
input report.Results
wantRules []*sarif.ReportingDescriptor
wantResults []*sarif.Result
}{
{
name: "report with vulnerabilities",
input: report.Results{
{
Target: "test",
Class: report.ClassOSPkg,
Vulnerabilities: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2020-0001",
PkgName: "foo",
InstalledVersion: "1.2.3",
FixedVersion: "3.4.5",
PrimaryURL: "https://avd.aquasec.com/nvd/cve-2020-0001",
SeveritySource: "redhat",
Vulnerability: dbTypes.Vulnerability{
Title: "foobar",
Description: "baz",
Severity: "HIGH",
CVSS: map[string]dbTypes.CVSS{
"nvd": {
V3Vector: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
V3Score: 9.8,
},
"redhat": {
V3Vector: "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
V3Score: 7.5,
},
},
},
},
},
},
},
wantRules: []*sarif.ReportingDescriptor{
{
ID: "CVE-2020-0001",
Name: getStringPointer("OsPackageVulnerability"),
ShortDescription: &sarif.MultiformatMessageString{Text: getStringPointer("CVE-2020-0001")},
FullDescription: &sarif.MultiformatMessageString{Text: getStringPointer("baz")},
DefaultConfiguration: &sarif.ReportingConfiguration{
Level: "error",
},
HelpURI: getStringPointer("https://avd.aquasec.com/nvd/cve-2020-0001"),
Properties: map[string]interface{}{
"tags": []interface{}{
"vulnerability",
"security",
"HIGH",
},
"precision": "very-high",
"security-severity": "7.5",
},
Help: &sarif.MultiformatMessageString{
Text: getStringPointer("Vulnerability CVE-2020-0001\nSeverity: HIGH\nPackage: foo\nFixed Version: 3.4.5\nLink: [CVE-2020-0001](https://avd.aquasec.com/nvd/cve-2020-0001)\nbaz"),
Markdown: getStringPointer("**Vulnerability CVE-2020-0001**\n| Severity | Package | Fixed Version | Link |\n| --- | --- | --- | --- |\n|HIGH|foo|3.4.5|[CVE-2020-0001](https://avd.aquasec.com/nvd/cve-2020-0001)|\n\nbaz"),
},
},
},
wantResults: []*sarif.Result{
{
RuleID: getStringPointer("CVE-2020-0001"),
RuleIndex: getUintPointer(0),
Level: getStringPointer("error"),
Message: sarif.Message{Text: getStringPointer("Package: foo\nInstalled Version: 1.2.3\nVulnerability CVE-2020-0001\nSeverity: HIGH\nFixed Version: 3.4.5\nLink: [CVE-2020-0001](https://avd.aquasec.com/nvd/cve-2020-0001)")},
Locations: []*sarif.Location{
{
PhysicalLocation: &sarif.PhysicalLocation{
ArtifactLocation: &sarif.ArtifactLocation{
URI: getStringPointer("test"),
URIBaseId: getStringPointer("ROOTPATH"),
},
Region: &sarif.Region{StartLine: getIntPointer(1)},
},
},
},
},
},
},
{
name: "report with misconfigurations",
input: report.Results{
{
Target: "test",
Class: report.ClassConfig,
Misconfigurations: []types.DetectedMisconfiguration{
{
Type: "Kubernetes Security Check",
ID: "KSV001",
Title: "Image tag ':latest' used",
Message: "Message",
Severity: "HIGH",
PrimaryURL: "https://avd.aquasec.com/appshield/ksv001",
Status: types.StatusFailure,
},
{
Type: "Kubernetes Security Check",
ID: "KSV002",
Title: "SYS_ADMIN capability added",
Message: "Message",
Severity: "CRITICAL",
PrimaryURL: "https://avd.aquasec.com/appshield/ksv002",
Status: types.StatusPassed,
},
},
},
},
wantResults: []*sarif.Result{
{
RuleID: getStringPointer("KSV001"),
RuleIndex: getUintPointer(0),
Level: getStringPointer("error"),
Message: sarif.Message{Text: getStringPointer("Artifact: test\nType: \nVulnerability KSV001\nSeverity: HIGH\nMessage: Message\nLink: [KSV001](https://avd.aquasec.com/appshield/ksv001)")},
Locations: []*sarif.Location{
{
PhysicalLocation: &sarif.PhysicalLocation{
ArtifactLocation: &sarif.ArtifactLocation{
URI: getStringPointer("test"),
URIBaseId: getStringPointer("ROOTPATH"),
},
Region: &sarif.Region{StartLine: getIntPointer(1)},
},
},
},
},
{
RuleID: getStringPointer("KSV002"),
RuleIndex: getUintPointer(1),
Level: getStringPointer("error"),
Message: sarif.Message{Text: getStringPointer("Artifact: test\nType: \nVulnerability KSV002\nSeverity: CRITICAL\nMessage: Message\nLink: [KSV002](https://avd.aquasec.com/appshield/ksv002)")},
Locations: []*sarif.Location{
{
PhysicalLocation: &sarif.PhysicalLocation{
ArtifactLocation: &sarif.ArtifactLocation{
URI: getStringPointer("test"),
URIBaseId: getStringPointer("ROOTPATH"),
},
Region: &sarif.Region{StartLine: getIntPointer(1)},
},
},
},
},
},
wantRules: []*sarif.ReportingDescriptor{
{
ID: "KSV001",
Name: getStringPointer("Misconfiguration"),
ShortDescription: &sarif.MultiformatMessageString{Text: getStringPointer("KSV001")},
FullDescription: &sarif.MultiformatMessageString{Text: getStringPointer("")},
DefaultConfiguration: &sarif.ReportingConfiguration{
Level: "error",
},
HelpURI: getStringPointer("https://avd.aquasec.com/appshield/ksv001"),
Properties: map[string]interface{}{
"tags": []interface{}{
"misconfiguration",
"security",
"HIGH",
},
"precision": "very-high",
"security-severity": "8.0",
},
Help: &sarif.MultiformatMessageString{
Text: getStringPointer("Misconfiguration KSV001\nType: Kubernetes Security Check\nSeverity: HIGH\nCheck: Image tag ':latest' used\nMessage: Message\nLink: [KSV001](https://avd.aquasec.com/appshield/ksv001)\n"),
Markdown: getStringPointer("**Misconfiguration KSV001**\n| Type | Severity | Check | Message | Link |\n| --- | --- | --- | --- | --- |\n|Kubernetes Security Check|HIGH|Image tag ':latest' used|Message|[KSV001](https://avd.aquasec.com/appshield/ksv001)|\n\n"),
},
},
{
ID: "KSV002",
Name: getStringPointer("Misconfiguration"),
ShortDescription: &sarif.MultiformatMessageString{Text: getStringPointer("KSV002")},
FullDescription: &sarif.MultiformatMessageString{Text: getStringPointer("")},
DefaultConfiguration: &sarif.ReportingConfiguration{
Level: "error",
},
HelpURI: getStringPointer("https://avd.aquasec.com/appshield/ksv002"),
Properties: map[string]interface{}{
"tags": []interface{}{
"misconfiguration",
"security",
"CRITICAL",
},
"precision": "very-high",
"security-severity": "9.5",
},
Help: &sarif.MultiformatMessageString{
Text: getStringPointer("Misconfiguration KSV002\nType: Kubernetes Security Check\nSeverity: CRITICAL\nCheck: SYS_ADMIN capability added\nMessage: Message\nLink: [KSV002](https://avd.aquasec.com/appshield/ksv002)\n"),
Markdown: getStringPointer("**Misconfiguration KSV002**\n| Type | Severity | Check | Message | Link |\n| --- | --- | --- | --- | --- |\n|Kubernetes Security Check|CRITICAL|SYS_ADMIN capability added|Message|[KSV002](https://avd.aquasec.com/appshield/ksv002)|\n\n"),
},
},
},
},
{
name: "no vulns",
wantResults: []*sarif.Result{},
wantRules: []*sarif.ReportingDescriptor{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sarifWritten := bytes.Buffer{}
err := report.Write(report.Report{Results: tt.input}, report.Option{
Format: "sarif",
Output: &sarifWritten,
})
assert.NoError(t, err)
result := &sarif.Report{}
err = json.Unmarshal(sarifWritten.Bytes(), result)
assert.NoError(t, err)
assert.Equal(t, tt.wantRules, result.Runs[0].Tool.Driver.Rules, tt.name)
assert.Equal(t, tt.wantResults, result.Runs[0].Results, tt.name)
})
}
}

View File

@@ -7,20 +7,14 @@ import (
"html"
"io"
"os"
"regexp"
"strings"
"text/template"
"time"
"github.com/Masterminds/sprig"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
)
// regex to extract file path in case string includes (distro:version)
var re = regexp.MustCompile(`(?P<path>.+?)(?:\s*\((?:.*?)\).*?)?$`)
// TemplateWriter write result in custom format defined by user's template
type TemplateWriter struct {
Output io.Writer
@@ -46,18 +40,6 @@ func NewTemplateWriter(output io.Writer, outputTemplate string) (*TemplateWriter
}
return escaped.String()
}
templateFuncMap["makeRuleMap"] = func() map[string]int {
return make(map[string]int)
}
templateFuncMap["indexRule"] = func(rules map[string]int, vulnerabilityID string) bool {
if _, ok := rules[vulnerabilityID]; !ok {
rules[vulnerabilityID] = len(rules)
return true
}
return false
}
templateFuncMap["toSarifErrorLevel"] = toSarifErrorLevel
templateFuncMap["toSarifRuleName"] = toSarifRuleName
templateFuncMap["endWithPeriod"] = func(input string) string {
if !strings.HasSuffix(input, ".") {
input += "."
@@ -70,14 +52,6 @@ func NewTemplateWriter(output io.Writer, outputTemplate string) (*TemplateWriter
templateFuncMap["escapeString"] = func(input string) string {
return html.EscapeString(input)
}
templateFuncMap["toPathUri"] = func(input string) string {
var matches = re.FindStringSubmatch(input)
if matches != nil {
input = matches[re.SubexpIndex("path")]
}
input = strings.ReplaceAll(input, "\\", "/")
return input
}
templateFuncMap["getEnv"] = func(key string) string {
return os.Getenv(key)
}
@@ -99,30 +73,3 @@ func (tw TemplateWriter) Write(report Report) error {
}
return nil
}
func toSarifRuleName(vulnerabilityType string) string {
switch vulnerabilityType {
case vulnerability.Ubuntu, vulnerability.Alpine, vulnerability.RedHat, vulnerability.RedHatOVAL,
vulnerability.Debian, vulnerability.DebianOVAL, vulnerability.Fedora, vulnerability.Amazon,
vulnerability.OracleOVAL, vulnerability.SuseCVRF, vulnerability.OpenSuseCVRF, vulnerability.Photon,
vulnerability.CentOS, vulnerability.Alma:
return "OsPackageVulnerability"
case "npm", "yarn", "nuget", "pipenv", "poetry", "bundler", "cargo", "composer":
return "ProgrammingLanguageVulnerability"
default:
return "OtherVulnerability"
}
}
func toSarifErrorLevel(severity string) string {
switch severity {
case "CRITICAL", "HIGH":
return "error"
case "MEDIUM":
return "warning"
case "LOW", "UNKNOWN":
return "note"
default:
return "none"
}
}

View File

@@ -2,6 +2,8 @@ package report
import (
"io"
"path/filepath"
"strings"
"time"
v1 "github.com/google/go-containerregistry/pkg/v1"
@@ -9,6 +11,7 @@ import (
ftypes "github.com/aquasecurity/fanal/types"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
"github.com/aquasecurity/trivy/pkg/log"
"github.com/aquasecurity/trivy/pkg/types"
)
@@ -93,6 +96,8 @@ type Option struct {
Output io.Writer
Severities []dbTypes.Severity
OutputTemplate string
Light bool
AppVersion string
// For misconfigurations
IncludeNonFailures bool
@@ -113,10 +118,18 @@ func Write(report Report, option Option) error {
case "json":
writer = &JSONWriter{Output: option.Output}
case "template":
// We keep `sarif.tpl` template working for backward compatibility for a while.
if strings.HasPrefix(option.OutputTemplate, "@") && filepath.Base(option.OutputTemplate) == "sarif.tpl" {
log.Logger.Warn("Using `--template sarif.tpl` is deprecated. Please migrate to `--report sarif`. See https://github.com/aquasecurity/trivy/discussions/1571")
writer = SarifWriter{Output: option.Output, Version: option.AppVersion}
break
}
var err error
if writer, err = NewTemplateWriter(option.Output, option.OutputTemplate); err != nil {
return xerrors.Errorf("failed to initialize template writer: %w", err)
}
case "sarif":
writer = SarifWriter{Output: option.Output, Version: option.AppVersion}
default:
return xerrors.Errorf("unknown format: %v", option.Format)
}

View File

@@ -3,115 +3,9 @@ package report
import (
"testing"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
"github.com/stretchr/testify/assert"
)
func TestReportWriter_toSarifRuleName(t *testing.T) {
tests := []struct {
vulnerabilityType string
sarifRuleName string
}{
{
vulnerabilityType: vulnerability.Ubuntu,
sarifRuleName: "OsPackageVulnerability",
},
{
vulnerabilityType: vulnerability.Alpine,
sarifRuleName: "OsPackageVulnerability",
},
{
vulnerabilityType: vulnerability.RedHat,
sarifRuleName: "OsPackageVulnerability",
},
{
vulnerabilityType: vulnerability.RedHatOVAL,
sarifRuleName: "OsPackageVulnerability",
},
{
vulnerabilityType: vulnerability.Debian,
sarifRuleName: "OsPackageVulnerability",
},
{
vulnerabilityType: vulnerability.DebianOVAL,
sarifRuleName: "OsPackageVulnerability",
},
{
vulnerabilityType: vulnerability.Fedora,
sarifRuleName: "OsPackageVulnerability",
},
{
vulnerabilityType: vulnerability.Amazon,
sarifRuleName: "OsPackageVulnerability",
},
{
vulnerabilityType: vulnerability.OracleOVAL,
sarifRuleName: "OsPackageVulnerability",
},
{
vulnerabilityType: vulnerability.SuseCVRF,
sarifRuleName: "OsPackageVulnerability",
},
{
vulnerabilityType: vulnerability.OpenSuseCVRF,
sarifRuleName: "OsPackageVulnerability",
},
{
vulnerabilityType: vulnerability.Photon,
sarifRuleName: "OsPackageVulnerability",
},
{
vulnerabilityType: vulnerability.CentOS,
sarifRuleName: "OsPackageVulnerability",
},
{
vulnerabilityType: vulnerability.Alma,
sarifRuleName: "OsPackageVulnerability",
},
{
vulnerabilityType: "npm",
sarifRuleName: "ProgrammingLanguageVulnerability",
},
{
vulnerabilityType: "yarn",
sarifRuleName: "ProgrammingLanguageVulnerability",
},
{
vulnerabilityType: "nuget",
sarifRuleName: "ProgrammingLanguageVulnerability",
},
{
vulnerabilityType: "pipenv",
sarifRuleName: "ProgrammingLanguageVulnerability",
},
{
vulnerabilityType: "poetry",
sarifRuleName: "ProgrammingLanguageVulnerability",
},
{
vulnerabilityType: "bundler",
sarifRuleName: "ProgrammingLanguageVulnerability",
},
{
vulnerabilityType: "cargo",
sarifRuleName: "ProgrammingLanguageVulnerability",
},
{
vulnerabilityType: "composer",
sarifRuleName: "ProgrammingLanguageVulnerability",
},
{
vulnerabilityType: "redis",
sarifRuleName: "OtherVulnerability",
},
}
for _, tc := range tests {
t.Run(tc.vulnerabilityType, func(t *testing.T) {
assert.Equal(t, tc.sarifRuleName, toSarifRuleName(tc.vulnerabilityType), tc.vulnerabilityType)
})
}
}
func TestReportWriter_toSarifErrorLevel(t *testing.T) {
tests := []struct {
severity string