Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(vex): VEX Repository support #7206

Merged
merged 56 commits into from
Jul 25, 2024
Merged
Show file tree
Hide file tree
Changes from 44 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
547363a
feat: add vex subcommand
knqyf263 Jul 3, 2024
6ab7fc8
feat: adhere to VEX Repository Specification
knqyf263 Jul 4, 2024
476dcfc
fix: inherit logger options for fatal errors
knqyf263 Jul 4, 2024
d885ecf
feat: download VEX repos
knqyf263 Jul 4, 2024
8ba0871
feat: add --vex-repos to 'trivy clean'
knqyf263 Jul 4, 2024
319eb65
add 'trivy vex repo download'
knqyf263 Jul 5, 2024
2b18878
feat: cache ETag
knqyf263 Jul 5, 2024
d2ec227
TODO: refactor CycloneDX
knqyf263 Jul 5, 2024
c548e38
refactor: always create parent map
knqyf263 Jul 6, 2024
9787609
refactor: rename library to package
knqyf263 Jul 6, 2024
71b8ca3
refactor: rename FilterOption to FilterOptions
knqyf263 Jul 6, 2024
6a0533d
fix: re-use the existing UID
knqyf263 Jul 6, 2024
7b35ccc
refactor: re-define interface
knqyf263 Jul 6, 2024
abd6ab9
test: fit for new interface
knqyf263 Jul 6, 2024
7458b32
fix: re-use serial number from SBOM
knqyf263 Jul 6, 2024
1353291
fix: go-github may return nil for transport
knqyf263 Jul 8, 2024
e969bf8
feat: store cache metadata for VEX repos
knqyf263 Jul 8, 2024
d098fb6
feat: add RepositorySet
knqyf263 Jul 10, 2024
430954e
feat(csaf): support VEX source
knqyf263 Jul 10, 2024
34ade4b
test: fix sources
knqyf263 Jul 10, 2024
33f8207
test(vex): add tests for repository set
knqyf263 Jul 10, 2024
3d6e0e3
test: add more vexr tests
knqyf263 Jul 10, 2024
02e173a
feat: skip repos that hasn't been downloaded
knqyf263 Jul 10, 2024
ab19441
feat: use repository_url for OCI
knqyf263 Jul 11, 2024
0b8c2fd
feat: add "--vex repo"
knqyf263 Jul 11, 2024
03c707f
feat: add "enabled" field
knqyf263 Jul 11, 2024
82f9595
feat: add authentication
knqyf263 Jul 12, 2024
a22ad36
test(vex): add tests for vex-repo
knqyf263 Jul 13, 2024
2609053
feat: support version array
knqyf263 Jul 18, 2024
438187d
test(vex): add tests for manager
knqyf263 Jul 20, 2024
74ebecf
feat: add "vex repo list"
knqyf263 Jul 20, 2024
83d5ae0
chore: rename --vex-repos to --vex-repo
knqyf263 Jul 20, 2024
db16176
docs: add VEX Repository
knqyf263 Jul 20, 2024
2f04b6e
feat(vex): add --skip-vex-repo-update
knqyf263 Jul 20, 2024
1f4ccb9
Merge branch 'main' into feat/vexrepo
knqyf263 Jul 22, 2024
8fcd8d2
test(integration): add VEX tests
knqyf263 Jul 22, 2024
e2ce02f
fix(plugin): join plugins dir
knqyf263 Jul 22, 2024
bfb24cf
test(vex): comply with new spec
knqyf263 Jul 22, 2024
ba16b88
test(vex): show a file path
knqyf263 Jul 22, 2024
6dff269
test(vex): add enabled field
knqyf263 Jul 22, 2024
8ee2353
feat(download): support client mode
knqyf263 Jul 22, 2024
7e24dca
fix: support insecure in custom transport
knqyf263 Jul 22, 2024
aec8684
fix: lint issues
knqyf263 Jul 22, 2024
32bcd21
ci: switch to ubuntu-latest
knqyf263 Jul 23, 2024
d5cc59d
docs: auto-generate
knqyf263 Jul 23, 2024
422e03c
Update manager.go
knqyf263 Jul 23, 2024
fca16cb
fix: cli usage
knqyf263 Jul 25, 2024
71c9bf3
Update pkg/commands/operation/operation.go
knqyf263 Jul 25, 2024
642f2d9
docs(cache): add a link to vex repo
knqyf263 Jul 25, 2024
9881b0f
revert: add parents flag
knqyf263 Jul 25, 2024
19e60ba
chore: add a comment
knqyf263 Jul 25, 2024
e02af76
chore: add a long description
knqyf263 Jul 25, 2024
424759e
fix: delete unused field
knqyf263 Jul 25, 2024
07ba807
fix: delete debug code
knqyf263 Jul 25, 2024
ae853ce
docs: generate references
knqyf263 Jul 25, 2024
1479468
feat: show debug message once per package
knqyf263 Jul 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: [ubuntu-latest-m, windows-latest, macos-latest]
operating-system: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/[email protected]

Expand All @@ -31,15 +31,15 @@ jobs:
echo "Run 'go mod tidy' and push it"
exit 1
fi
if: matrix.operating-system == 'ubuntu-latest-m'
if: matrix.operating-system == 'ubuntu-latest'

- name: Lint
id: lint
uses: golangci/[email protected]
with:
version: v1.59
args: --verbose --out-format=line-number
if: matrix.operating-system == 'ubuntu-latest-m'
if: matrix.operating-system == 'ubuntu-latest'

- name: Check if linter failed
run: |
Expand All @@ -60,14 +60,14 @@ jobs:
echo "Run 'mage docs:generate' and push it"
exit 1
fi
if: matrix.operating-system == 'ubuntu-latest-m'
if: matrix.operating-system == 'ubuntu-latest'

- name: Run unit tests
run: mage test:unit

integration:
name: Integration Test
runs-on: ubuntu-latest-m
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/[email protected]
Expand All @@ -87,7 +87,7 @@ jobs:

k8s-integration:
name: K8s Integration Test
runs-on: ubuntu-latest-m
runs-on: ubuntu-latest
steps:
- name: Check out code into the Go module directory
uses: actions/[email protected]
Expand Down Expand Up @@ -129,7 +129,7 @@ jobs:

vm-test:
name: VM Integration Test
runs-on: ubuntu-latest-m
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/[email protected]
Expand All @@ -151,7 +151,7 @@ jobs:
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: [ubuntu-latest-m, windows-latest, macos-latest]
operating-system: [ubuntu-latest, windows-latest, macos-latest]
env:
DOCKER_CLI_EXPERIMENTAL: "enabled"
steps:
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/configuration/filtering.md
Original file line number Diff line number Diff line change
Expand Up @@ -493,7 +493,7 @@ You can find more example checks [here](https://github.com/aquasecurity/trivy/tr
| Secret | |
| License | |

Please refer to the [VEX documentation](../supply-chain/vex.md) for the details.
Please refer to the [VEX documentation](../supply-chain/vex/index.md) for the details.


[^1]: license name is used as id for `.trivyignore.yaml` files.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Vulnerability Exploitability Exchange (VEX)
# Local VEX Files

!!! warning "EXPERIMENTAL"
This feature might change without preserving backwards compatibility.

Trivy supports filtering detected vulnerabilities using [the Vulnerability Exploitability Exchange (VEX)](https://www.ntia.gov/files/ntia/publications/vex_one-page_summary.pdf), a standardized format for sharing and exchanging information about vulnerabilities.
By providing VEX during scanning, it is possible to filter vulnerabilities based on their status.
Currently, Trivy supports the following three formats:
In addition to [VEX repositories](./repo.md), Trivy also supports the use of local VEX files for vulnerability filtering.
This method is useful when you have specific VEX documents that you want to apply to your scans.
Currently, Trivy supports the following formats:

- [CycloneDX](https://cyclonedx.org/capabilities/vex/)
- [OpenVEX](https://github.com/openvex/spec)
Expand Down
33 changes: 33 additions & 0 deletions docs/docs/supply-chain/vex/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Vulnerability Exploitability Exchange (VEX)

!!! warning "EXPERIMENTAL"
This feature might change without preserving backwards compatibility.

Trivy supports filtering detected vulnerabilities using the [Vulnerability Exploitability eXchange (VEX)](https://www.ntia.gov/files/ntia/publications/vex_one-page_summary.pdf), a standardized format for sharing and exchanging information about vulnerabilities.
By providing VEX during scanning, it is possible to filter vulnerabilities based on their status.

## VEX Usage Methods

Trivy currently supports two methods for utilizing VEX:

1. [VEX Repository](./repo.md)
2. [Local VEX Files](./file.md)

### Enabling VEX
To enable VEX, use the `--vex` option.
You can specify the method to use:

- To enable the VEX Repository: `--vex repo`
- To use a local VEX file: `--vex /path/to/vex-document.json`

```bash
$ trivy image ghcr.io/aquasecurity/trivy:0.52.0 --vex repo
```

You can enable both methods simultaneously.
The order of specification determines the priority:

- `--vex repo --vex /path/to/vex-document.json`: VEX Repository has priority
- `--vex /path/to/vex-document.json --vex repo`: Local file has priority

For detailed information on each method, please refer to each page.
207 changes: 207 additions & 0 deletions docs/docs/supply-chain/vex/repo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
# VEX Repository

## Using VEX Repository

Trivy can download and utilize VEX documents from repositories that comply with [the VEX Repository Specification][vex-repo].
While it's planned to be enabled by default in the future, currently it can be activated by explicitly specifying `--vex repo`.

```
$ trivy image ghcr.io/aquasecurity/trivy:0.52.0 --vex repo
2024-07-20T11:22:58+04:00 INFO [vex] The default repository config has been created
file_path="/Users/teppei/.trivy/vex/repository.yaml"
2024-07-20T11:23:23+04:00 INFO [vex] Updating repository... repo="default" url="https://github.com/aquasecurity/vexhub"
```

During scanning, Trivy generates PURLs for discovered packages and searches for matching PURLs in the VEX Repository.
If a match is found, the corresponding VEX is utilized.

### Configuration File

#### Default Configuration

When `--vex repo` is specified for the first time, a default configuration file is created at `$HOME/.trivy/vex/repository.yaml`.
The home directory can be configured through environment variable `$XDG_DATA_HOME`.

You can also create the configuration file in advance using the `trivy vex repo init` command and edit it.

The default configuration file looks like this:

```yaml
repositories:
- name: default
url: https://github.com/aquasecurity/vexhub
enabled: true
username: ""
password: ""
token: ""
```

By default, [VEX Hub][vexhub] managed by Aqua Security is used.
VEX Hub primarily trusts VEX documents published by the package maintainers.

#### Show Configuration
You can see the config file path and the configured repositories with `trivy vex repo list`:

```bash
$ trivy vex repo list
VEX Repositories (config: /home/username/.trivy/vex/repository.yaml)

- Name: default
URL: https://github.com/aquasecurity/vexhub
Status: Enabled
```

#### Custom Repositories

If you want to trust VEX documents published by other organizations or use your own VEX repository, you can specify a custom repository that complies with [the VEX Repository Specification][vex-repo].
You can add a custom repository as below:

```yaml
- name: custom
url: https://example.com/custom-repo
enabled: true
```


#### Authentication

For private repositories:

- `username`/`password` can be used for Basic authentication
- `token` can be used for Bearer authentication

```yaml
- name: custom
url: https://example.com/custom-repo
enabled: true
token: "my-token"
```

#### Repository Priority

The priority of VEX repositories is determined by their order in the configuration file.
You can add repositories with higher priority than the default or even remove the default VEX Hub.

```yaml
- name: repo1
url: https://example.com/repo1
- name: repo2
url: https://example.com/repo2
```

In this configuration, when Trivy detects a vulnerability in a package, it generates a PURL for that package and searches for matching VEX documents in the configured repositories.
The search process follows this order:

1. Trivy first looks for a VEX document matching the package's PURL in `repo1`.
2. If no matching VEX document is found in `repo1`, Trivy then searches in `repo2`.
3. This process continues through all configured repositories until a match is found.

If a matching VEX document is found in any repository (e.g., `repo1`), the search stops, and Trivy uses that VEX document.
Subsequent repositories (e.g., `repo2`) are not checked for that specific vulnerability and package combination.

It's important to note that the first matching VEX document found determines the final status of the vulnerability.
For example, if `repo1` states that a package is "Affected" by a vulnerability, this status will be used even if `repo2` states that the same package is "Not Affected" for the same vulnerability.
The "Affected" status from the higher-priority repository (`repo1`) takes precedence, and Trivy will consider the package as affected by the vulnerability.

### Repository Updates

VEX repositories are automatically updated during scanning.
Updates are performed based on the update frequency specified by the repository.

To disable auto-update, pass `--skip-vex-repo-update`.

```shell
$ trivy image ghcr.io/aquasecurity/trivy:0.50.0 --vex repo --skip-vex-repo-update
```

To download VEX repositories in advance without scanning, use `trivy vex repo download`.

The cache can be cleared with `trivy clean --vex-repo`.
DmitriyLewen marked this conversation as resolved.
Show resolved Hide resolved

### Displaying Filtered Vulnerabilities

To see which vulnerabilities were filtered and why, use the `--show-suppressed` option:

```shell
$ trivy image ghcr.io/aquasecurity/trivy:0.50.0 --vex repo --show-suppressed
...

Suppressed Vulnerabilities (Total: 4)
=====================================
┌───────────────┬────────────────┬──────────┬──────────────┬───────────────────────────────────────────────────┬──────────────────────────────────────────┐
│ Library │ Vulnerability │ Severity │ Status │ Statement │ Source │
├───────────────┼────────────────┼──────────┼──────────────┼───────────────────────────────────────────────────┼──────────────────────────────────────────┤
│ busybox │ CVE-2023-42364 │ MEDIUM │ not_affected │ vulnerable_code_cannot_be_controlled_by_adversary │ VEX Repository: default │
│ │ │ │ │ │ (https://github.com/aquasecurity/vexhub) │
│ ├────────────────┤ │ │ │ │
│ │ CVE-2023-42365 │ │ │ │ │
│ │ │ │ │ │ │
├───────────────┼────────────────┤ │ │ │ │
│ busybox-binsh │ CVE-2023-42364 │ │ │ │ │
│ │ │ │ │ │ │
│ ├────────────────┤ │ │ │ │
│ │ CVE-2023-42365 │ │ │ │ │
│ │ │ │ │ │ │
└───────────────┴────────────────┴──────────┴──────────────┴───────────────────────────────────────────────────┴──────────────────────────────────────────┘

```

## Publishing VEX Documents

### For OSS Projects

As an OSS developer or maintainer, you may encounter vulnerabilities in the packages your project depends on.
These vulnerabilities might be discovered through your own scans or reported by third parties using your OSS project.

While Trivy strives to minimize false positives, it doesn't perform code graph analysis, which means it can't evaluate exploitability at the code level.
Consequently, Trivy may report vulnerabilities even in cases where:

1. The vulnerable function in a dependency is never called in your project.
2. The vulnerable code cannot be controlled by an attacker in the context of your project.

If you're confident that a reported vulnerability in a dependency doesn't affect your OSS project or container image, you can publish a VEX document to reduce noise in Trivy scans.
To assess exploitability, you have several options:

1. Manual assessment: As a maintainer, you can read the source code and determine if the vulnerability is exploitable in your project's context.
2. Automated assessment: You can use SAST (Static Application Security Testing) tools or similar tools to analyze the code and determine exploitability.

By publishing VEX documents in the source repository, Trivy can automatically utilize them through VEX Hub.
The main steps are:

1. Generate a VEX document
2. Commit the VEX document to the `.vex/` directory in the source repository (e.g., [Trivy's VEX][trivy-vex])
3. Register your project's [PURL][purl] in VEX Hub

Step 3 is only necessary once.
After that, updating the VEX file in your repository will automatically be fetched by VEX Hub and utilized by Trivy.
See the [VEX Hub repository][vexhub] for more information.

If you want to issue a VEX for an OSS project that you don't maintain, consider first proposing the VEX publication to the original repository.
Many OSS maintainers are open to contributions that improve the security posture of their projects.
However, if your proposal is not accepted, or if you want to issue a VEX with statements that differ from the maintainer's judgment, you may want to consider creating a [custom repository](#hosting-custom-repositories).

### For Private Projects

If you're working on private software or personal projects, you have several options:

1. [Local VEX files](./file.md): You can create local VEX files and have Trivy read them during scans. This is suitable for individual use or small teams.
2. [.trivyignore](../../configuration/filtering.md#trivyignore): For simpler cases, using a .trivyignore file might be sufficient to suppress specific vulnerabilities.
3. [Custom repositories](#hosting-custom-repositories): For large organizations wanting to share VEX information for internally used software across different departments, setting up a custom VEX repository might be the best approach.

## Hosting Custom Repositories

While the principle is to store VEX documents for OSS packages in the source repository, it's possible to create a custom repository if that's difficult.

There are various use cases for providing custom repositories:

- A Pull Request to add a VEX document upstream was not merged
- Consolidating VEX documents output by SAST tools
- Publishing vendor-specific VEX documents that differ from OSS maintainer statements
- Creating a private VEX repository to publish common VEX for your company

In these cases, you can create a repository that complies with [the VEX Repository Specification][vex-repo] to make it available for use with Trivy.

[vex-repo]: https://github.com/aquasecurity/vex-repo-spec
[vexhub]: https://github.com/aquasecurity/vexhub
[trivy-vex]: https://github.com/aquasecurity/trivy/blob/b76a7250912cfc028cfef743f0f98cd81b39f8aa/.vex/trivy.openvex.json
[purl]: https://github.com/package-url/purl-spec
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ require (
github.com/go-redis/redis/v8 v8.11.5
github.com/golang-jwt/jwt/v5 v5.2.1
github.com/google/go-containerregistry v0.20.0
github.com/google/go-github/v62 v62.0.0
github.com/google/licenseclassifier/v2 v2.0.0
github.com/google/uuid v1.6.0
github.com/google/wire v0.6.0
Expand Down Expand Up @@ -243,6 +244,7 @@ require (
github.com/google/btree v1.1.2 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1357,6 +1357,10 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI=
github.com/google/go-containerregistry v0.20.0 h1:wRqHpOeVh3DnenOrPy9xDOLdnLatiGuuNRVelR2gSbg=
github.com/google/go-containerregistry v0.20.0/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI=
github.com/google/go-github/v62 v62.0.0 h1:/6mGCaRywZz9MuHyw9gD1CwsbmBX8GWsbFkwMmHdhl4=
github.com/google/go-github/v62 v62.0.0/go.mod h1:EMxeUqGJq2xRu9DYBMwel/mr7kZrzUOfQmmpYrZn2a4=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
Expand Down
Loading
Loading