Skip to content

Commit

Permalink
feat(sbom): add cyclonedx sbom scan (aquasecurity#2203)
Browse files Browse the repository at this point in the history
Co-authored-by: knqyf263 <[email protected]>
  • Loading branch information
masahiro331 and knqyf263 authored Jul 3, 2022
1 parent f0720f3 commit 5b821d3
Show file tree
Hide file tree
Showing 58 changed files with 3,892 additions and 101 deletions.
55 changes: 37 additions & 18 deletions docs/docs/references/cli/sbom.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,45 @@

```bash
NAME:
trivy sbom - generate SBOM for an artifact
trivy sbom - scan SBOM for vulnerabilities

USAGE:
trivy sbom [command options] ARTIFACT

DESCRIPTION:
ARTIFACT can be a container image, file path/directory, git repository or container image archive. See examples.
trivy sbom [command options] SBOM

OPTIONS:
--output value, -o value output file name [$TRIVY_OUTPUT]
--clear-cache, -c clear image caches without scanning (default: false) [$TRIVY_CLEAR_CACHE]
--ignorefile value specify .trivyignore file (default: ".trivyignore") [$TRIVY_IGNOREFILE]
--timeout value timeout (default: 5m0s) [$TRIVY_TIMEOUT]
--severity value, -s value severities of vulnerabilities to be displayed (comma separated) (default: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL") [$TRIVY_SEVERITY]
--offline-scan do not issue API requests to identify dependencies (default: false) [$TRIVY_OFFLINE_SCAN]
--db-repository value OCI repository to retrieve trivy-db from (default: "ghcr.io/aquasecurity/trivy-db") [$TRIVY_DB_REPOSITORY]
--insecure allow insecure server connections when using SSL (default: false) [$TRIVY_INSECURE]
--skip-files value specify the file paths to skip traversal (accepts multiple inputs) [$TRIVY_SKIP_FILES]
--skip-dirs value specify the directories where the traversal is skipped (accepts multiple inputs) [$TRIVY_SKIP_DIRS]
--artifact-type value, --type value input artifact type (image, fs, repo, archive) (default: "image") [$TRIVY_ARTIFACT_TYPE]
--sbom-format value, --format value SBOM format (cyclonedx, spdx, spdx-json) (default: "cyclonedx") [$TRIVY_SBOM_FORMAT]
--help, -h show help (default: false)
--cache-backend value cache backend (e.g. redis://localhost:6379) (default: "fs") [$TRIVY_CACHE_BACKEND]
--cache-ttl value cache TTL when using redis as cache backend (default: 0s) [$TRIVY_CACHE_TTL]
--clear-cache, -c clear image caches without scanning (default: false) [$TRIVY_CLEAR_CACHE]
--custom-headers value custom headers in client/server mode (accepts multiple inputs) [$TRIVY_CUSTOM_HEADERS]
--db-repository value OCI repository to retrieve trivy-db from (default: "ghcr.io/aquasecurity/trivy-db") [$TRIVY_DB_REPOSITORY]
--download-db-only download/update vulnerability database but don't run a scan (default: false) [$TRIVY_DOWNLOAD_DB_ONLY]
--exit-code value Exit code when vulnerabilities were found (default: 0) [$TRIVY_EXIT_CODE]
--format value, -f value format (table, json, sarif, template, cyclonedx, spdx, spdx-json, github) (default: "table") [$TRIVY_FORMAT]
--ignore-policy value specify the Rego file to evaluate each vulnerability [$TRIVY_IGNORE_POLICY]
--ignore-unfixed display only fixed vulnerabilities (default: false) [$TRIVY_IGNORE_UNFIXED]
--ignorefile value specify .trivyignore file (default: ".trivyignore") [$TRIVY_IGNOREFILE]
--input value, -i value input file path instead of image name [$TRIVY_INPUT]
--insecure allow insecure server connections when using SSL (default: false) [$TRIVY_INSECURE]
--list-all-pkgs enabling the option will output all packages regardless of vulnerability (default: false) [$TRIVY_LIST_ALL_PKGS]
--no-progress suppress progress bar (default: false) [$TRIVY_NO_PROGRESS]
--offline-scan do not issue API requests to identify dependencies (default: false) [$TRIVY_OFFLINE_SCAN]
--output value, -o value output file name [$TRIVY_OUTPUT]
--reset remove all caches and database (default: false) [$TRIVY_RESET]
--security-checks value comma-separated list of what security issues to detect (vuln,config,secret) (default: "vuln") [$TRIVY_SECURITY_CHECKS]
--server value server address [$TRIVY_SERVER]
--severity value, -s value severities of vulnerabilities to be displayed (comma separated) (default: "UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL") [$TRIVY_SEVERITY]
--skip-db-update, --skip-update skip updating vulnerability database (default: false) [$TRIVY_SKIP_UPDATE, $TRIVY_SKIP_DB_UPDATE]
--skip-dirs value specify the directories where the traversal is skipped (accepts multiple inputs) [$TRIVY_SKIP_DIRS]
--skip-files value specify the file paths to skip traversal (accepts multiple inputs) [$TRIVY_SKIP_FILES]
--template value, -t value output template [$TRIVY_TEMPLATE]
--timeout value timeout (default: 5m0s) [$TRIVY_TIMEOUT]
--token value for authentication in client/server mode [$TRIVY_TOKEN]
--token-header value specify a header name for token in client/server mode (default: "Trivy-Token") [$TRIVY_TOKEN_HEADER]
EXAMPLES:
- Scan CycloneDX and show the result in tables:
$ trivy sbom /path/to/report.cdx
- Scan CycloneDX and generate a CycloneDX report:
$ trivy sbom --format cyclonedx /path/to/report.cdx
```
29 changes: 29 additions & 0 deletions docs/docs/sbom/cyclonedx.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# CycloneDX

## Reporting
Trivy generates JSON reports in the [CycloneDX][cyclonedx] format.
Note that XML format is not supported at the moment.

Expand Down Expand Up @@ -230,4 +231,32 @@ $ cat result.json | jq .

</details>

## Scanning
Trivy can take CycloneDX as an input and scan for vulnerabilities.
To scan SBOM, you can use the `sbom` subcommand and pass the path to your CycloneDX report.

```bash
$ trivy sbom /path/to/cyclonedx.json

cyclonedx.json (alpine 3.7.1)
=========================
Total: 3 (CRITICAL: 3)

┌─────────────┬────────────────┬──────────┬───────────────────┬───────────────┬──────────────────────────────────────────────────────────────┐
│ Library │ Vulnerability │ Severity │ Installed Version │ Fixed Version │ Title │
├─────────────┼────────────────┼──────────┼───────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤
│ curl │ CVE-2018-14618 │ CRITICAL │ 7.61.0-r0 │ 7.61.1-r0 │ curl: NTLM password overflow via integer overflow │
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2018-14618 │
├─────────────┼────────────────┼──────────┼───────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤
│ libbz2 │ CVE-2019-12900 │ CRITICAL │ 1.0.6-r6 │ 1.0.6-r7 │ bzip2: out-of-bounds write in function BZ2_decompress
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2019-12900 │
├─────────────┼────────────────┼──────────┼───────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤
│ sqlite-libs │ CVE-2019-8457 │ CRITICAL │ 3.21.0-r1 │ 3.25.3-r1 │ sqlite: heap out-of-bound read in function rtreenode()
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2019-8457 │
└─────────────┴────────────────┴──────────┴───────────────────┴───────────────┴──────────────────────────────────────────────────────────────┘
```

!!! 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.

[cyclonedx]: https://cyclonedx.org/
35 changes: 34 additions & 1 deletion docs/docs/sbom/index.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# SBOM

Trivy currently supports the following SBOM formats.
## Reporting
Trivy can generate the following SBOM formats.

- [CycloneDX][cyclonedx]
- [SPDX][spdx]
Expand Down Expand Up @@ -175,5 +176,37 @@ $ trivy fs --format cyclonedx --output result.json /app/myproject

</details>

## Scanning
Trivy also can take the following SBOM formats as an input and scan for vulnerabilities.

- CycloneDX

To scan SBOM, you can use the `sbom` subcommand and pass the path to the SBOM.

```bash
$ trivy sbom /path/to/cyclonedx.json

cyclonedx.json (alpine 3.7.1)
=========================
Total: 3 (CRITICAL: 3)

┌─────────────┬────────────────┬──────────┬───────────────────┬───────────────┬──────────────────────────────────────────────────────────────┐
│ Library │ Vulnerability │ Severity │ Installed Version │ Fixed Version │ Title │
├─────────────┼────────────────┼──────────┼───────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤
│ curl │ CVE-2018-14618 │ CRITICAL │ 7.61.0-r0 │ 7.61.1-r0 │ curl: NTLM password overflow via integer overflow │
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2018-14618 │
├─────────────┼────────────────┼──────────┼───────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤
│ libbz2 │ CVE-2019-12900 │ CRITICAL │ 1.0.6-r6 │ 1.0.6-r7 │ bzip2: out-of-bounds write in function BZ2_decompress
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2019-12900 │
├─────────────┼────────────────┼──────────┼───────────────────┼───────────────┼──────────────────────────────────────────────────────────────┤
│ sqlite-libs │ CVE-2019-8457 │ CRITICAL │ 3.21.0-r1 │ 3.25.3-r1 │ sqlite: heap out-of-bound read in function rtreenode()
│ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2019-8457 │
└─────────────┴────────────────┴──────────┴───────────────────┴───────────────┴──────────────────────────────────────────────────────────────┘
```


!!! note
CycloneDX XML and SPDX are not supported at the moment.

[cyclonedx]: cyclonedx.md
[spdx]: spdx.md
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ require (
github.com/hashicorp/go-getter v1.6.2
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936
github.com/knqyf263/go-rpm-version v0.0.0-20220614171824-631e686d1075
github.com/kylelemons/godebug v1.1.0
github.com/mailru/easyjson v0.7.6
github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -943,8 +943,8 @@ github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f h1:GvCU5GX
github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f/go.mod h1:q59u9px8b7UTj0nIjEjvmTWekazka6xIt6Uogz5Dm+8=
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d h1:X4cedH4Kn3JPupAwwWuo4AzYp16P0OyLO9d7OnMZc/c=
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d/go.mod h1:o8sgWoz3JADecfc/cTYD92/Et1yMqMy0utV1z+VaZao=
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936 h1:HDjRqotkViMNcGMGicb7cgxklx8OwnjtCBmyWEqrRvM=
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0=
github.com/knqyf263/go-rpm-version v0.0.0-20220614171824-631e686d1075 h1:aC6MEAs3PE3lWD7lqrJfDxHd6hcced9R4JTZu85cJwU=
github.com/knqyf263/go-rpm-version v0.0.0-20220614171824-631e686d1075/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0=
github.com/knqyf263/go-rpmdb v0.0.0-20220607073645-842f01763e21 h1:3E1B04qBvkGmr6oXPSwLpuAF0wekN67CKseKGRjj6Yo=
github.com/knqyf263/go-rpmdb v0.0.0-20220607073645-842f01763e21/go.mod h1:zp6SMcRd0GB+uwNJjr+DkrNZdQZ4er2HMO6KyD0vIGU=
github.com/knqyf263/nested v0.0.1 h1:Sv26CegUMhjt19zqbBKntjwESdxe5hxVPSk0+AKjdUc=
Expand Down
96 changes: 96 additions & 0 deletions integration/sbom_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
//go:build integration
// +build integration

package integration

import (
"io"
"os"
"path/filepath"
"testing"

cdx "github.com/CycloneDX/cyclonedx-go"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/aquasecurity/trivy/pkg/commands"
)

func TestCycloneDX(t *testing.T) {
type args struct {
input string
format string
artifactType string
}
tests := []struct {
name string
args args
golden string
}{
{
name: "centos7-bom by trivy",
args: args{
input: "testdata/fixtures/sbom/centos-7-cyclonedx.json",
format: "cyclonedx",
artifactType: "cyclonedx",
},
golden: "testdata/centos-7-cyclonedx.json.golden",
},
{
name: "fluentd-multiple-lockfiles-bom by trivy",
args: args{
input: "testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json",
format: "cyclonedx",
artifactType: "cyclonedx",
},
golden: "testdata/fluentd-multiple-lockfiles-cyclonedx.json.golden",
},
}

// Set up testing DB
cacheDir := initDB(t)

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
osArgs := []string{
"trivy", "--cache-dir", cacheDir, "sbom", "--skip-db-update", "--format", tt.args.format,
}

// Setup the output file
outputFile := filepath.Join(t.TempDir(), "output.json")
if *update {
outputFile = tt.golden
}

osArgs = append(osArgs, "--output", outputFile)
osArgs = append(osArgs, tt.args.input)

// Setup CLI App
app := commands.NewApp("dev")
app.Writer = io.Discard

// Run "trivy sbom"
assert.Nil(t, app.Run(osArgs))

// Compare want and got
want := decodeCycloneDX(t, tt.golden)
got := decodeCycloneDX(t, outputFile)
assert.Equal(t, want, got)
})
}
}

func decodeCycloneDX(t *testing.T, filePath string) *cdx.BOM {
f, err := os.Open(filePath)
require.NoError(t, err)
defer f.Close()

bom := cdx.NewBOM()
decoder := cdx.NewBOMDecoder(f, cdx.BOMFileFormatJSON)
err = decoder.Decode(bom)
require.NoError(t, err)

bom.Metadata.Timestamp = ""

return bom
}
Loading

0 comments on commit 5b821d3

Please sign in to comment.