Compare commits

...

11 Commits

Author SHA1 Message Date
Igor Adulyan
718ec29ec6 docs: update binary signature verification for sigstore bundles (#9929) 2025-12-12 06:56:26 +00:00
DmitriyLewen
d528250a1d chore(deps): bump alpine from 3.22.1 to 3.23.0 (#9935) 2025-12-12 06:55:39 +00:00
DmitriyLewen
f50b96a815 chore(alpine): add EOL date for alpine 3.23 (#9934) 2025-12-12 06:55:09 +00:00
Nikita Pivkin
d65b504cb2 feat(cloudformation): add support for Fn::ForEach (#9508)
Signed-off-by: nikpivkin <nikita.pivkin@smartforce.io>
2025-12-11 18:53:03 +00:00
DmitriyLewen
1a901e5c75 ci: enable check-latest for setup-go (#9931) 2025-12-11 08:17:40 +00:00
Teppei Fukuda
effc1c0d4d feat(debian): detect third-party packages using maintainer list (#9917) 2025-12-11 05:18:31 +00:00
DmitriyLewen
335cc993fa fix(vex): add CVE-2025-66564 as not_affected into Trivy VEX file (#9924) 2025-12-10 12:16:31 +00:00
Kélian Saint-Bonnet
879e4fca12 feat(helm): add sslCertDir parameter (#9697) 2025-12-09 23:15:31 +00:00
Nikita Pivkin
18ecf75176 fix(misconf): respect .yml files when Helm charts are detected (#9912)
Signed-off-by: nikpivkin <nikita.pivkin@smartforce.io>
2025-12-09 23:07:39 +00:00
Teppei Fukuda
56b59e8abb feat(php): add support for dev dependencies in Composer (#9910) 2025-12-09 12:40:05 +00:00
dependabot[bot]
f58826fb2a chore(deps): bump the common group across 1 directory with 9 updates (#9903)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-09 05:35:08 +00:00
39 changed files with 1148 additions and 192 deletions

View File

@@ -65,6 +65,7 @@ jobs:
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version-file: go.mod
check-latest: true # Ensure we use the latest Go patch version
cache: false
# Ensure the base commit exists locally for go-apidiff to compare against.

View File

@@ -18,6 +18,7 @@ jobs:
with:
go-version-file: go.mod
cache: false
check-latest: true # Ensure we use the latest Go patch version
- name: Install Go tools
run: go install tool # GOBIN is added to the PATH by the setup-go action

View File

@@ -22,6 +22,7 @@ jobs:
with:
go-version-file: go.mod
cache: false
check-latest: true # Ensure we use the latest Go patch version
- name: Install Go tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
@@ -55,6 +56,7 @@ jobs:
with:
go-version-file: go.mod
cache: false
check-latest: true # Ensure we use the latest Go patch version
- name: Install Go tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
@@ -88,6 +90,7 @@ jobs:
with:
go-version-file: go.mod
cache: false
check-latest: true # Ensure we use the latest Go patch version
- name: Run golangci-lint for caching
uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0

View File

@@ -74,6 +74,7 @@ jobs:
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version-file: go.mod
check-latest: true # Ensure we use the latest Go patch version
cache: false
- name: Install Go tools

View File

@@ -69,6 +69,7 @@ jobs:
with:
go-version-file: go.mod
cache: false # Disable cache to avoid free space issues during `Post Setup Go` step.
check-latest: true # Ensure we use the latest Go patch version
- name: Generate SBOM
uses: CycloneDX/gh-gomod-generate-sbom@efc74245d6802c8cefd925620515442756c70d8f # v2.0.0

View File

@@ -16,6 +16,8 @@ jobs:
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
with:
go-version-file: go.mod
cache: false
check-latest: true # Ensure we use the latest Go patch version
- name: Install Go tools
run: go install tool # GOBIN is added to the PATH by the setup-go action

View File

@@ -26,6 +26,7 @@ jobs:
with:
go-version-file: go.mod
cache: false
check-latest: true # Ensure we use the latest Go patch version
- name: go mod tidy
run: |
@@ -80,6 +81,7 @@ jobs:
with:
go-version-file: go.mod
cache: false
check-latest: true # Ensure we use the latest Go patch version
- name: Install Go tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
@@ -113,6 +115,7 @@ jobs:
with:
go-version-file: go.mod
cache: false
check-latest: true # Ensure we use the latest Go patch version
- name: Install Go tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
@@ -132,6 +135,7 @@ jobs:
with:
go-version-file: go.mod
cache: false
check-latest: true # Ensure we use the latest Go patch version
- name: Install tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
@@ -167,6 +171,7 @@ jobs:
with:
go-version-file: go.mod
cache: false
check-latest: true # Ensure we use the latest Go patch version
- name: Install Go tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
@@ -201,6 +206,7 @@ jobs:
with:
go-version-file: go.mod
cache: false
check-latest: true # Ensure we use the latest Go patch version
- name: Install Go tools
run: go install tool # GOBIN is added to the PATH by the setup-go action
@@ -236,6 +242,7 @@ jobs:
with:
go-version-file: go.mod
cache: false
check-latest: true # Ensure we use the latest Go patch version
- name: Determine GoReleaser ID
id: goreleaser_id

View File

@@ -599,6 +599,36 @@
"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-2025-4192",
"name": "GO-2025-4192",
"description": "Sigstore Timestamp Authority allocates excessive memory during request parsing in github.com/sigstore/timestamp-authority",
"aliases": [
"CVE-2025-66564",
"GHSA-4qg8-fj49-pxjh"
]
},
"products": [
{
"@id": "pkg:golang/github.com/aquasecurity/trivy",
"identifiers": {
"purl": "pkg:golang/github.com/aquasecurity/trivy"
},
"subcomponents": [
{
"@id": "pkg:golang/github.com/sigstore/timestamp-authority@v1.2.2",
"identifiers": {
"purl": "pkg:golang/github.com/sigstore/timestamp-authority@v1.2.2"
}
}
]
}
],
"status": "not_affected",
"justification": "vulnerable_code_not_present",
"impact_statement": "Govulncheck determined that the vulnerable code isn't called"
}
]
}

View File

@@ -1,4 +1,4 @@
FROM alpine:3.22.1
FROM alpine:3.23.0
RUN apk --no-cache add ca-certificates git
COPY trivy /usr/local/bin/trivy
COPY contrib/*.tpl contrib/

View File

@@ -1,4 +1,4 @@
FROM alpine:3.22.1
FROM alpine:3.23.0
RUN apk --no-cache add ca-certificates git
# binaries were created with GoReleaser

View File

@@ -26,16 +26,26 @@ The following checks were performed on each of these signatures:
## Verifying binary
Download the required tarball, associated signature and certificate files from the [GitHub Release](https://github.com/aquasecurity/trivy/releases).
Since Trivy v0.68.1, GitHub Releases provide [sigstore signature bundles](https://docs.sigstore.dev/cosign/bundle/). Separate `.sig` and certificate (`.pem`) files are no longer published.
Download the required tarball and its associated `.sigstore.json` bundle file from the [GitHub Release](https://github.com/aquasecurity/trivy/releases).
Use the following command for keyless verification:
```shell
cosign verify-blob <path to binary> \
--certificate <path to cert> \
--signature <path to sig> \
--certificate-identity-regexp 'https://github\.com/aquasecurity/trivy/\.github/workflows/.+' \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"
cosign verify-blob-attestation <path to tarball> \
--bundle <path to tarball>.sigstore.json \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
--certificate-identity 'https://github.com/aquasecurity/trivy/.github/workflows/reusable-release.yaml@refs/tags/<release tag>'
```
Example for `trivy_0.68.1_Linux-64bit.tar.gz`:
```shell
cosign verify-blob-attestation trivy_0.68.1_Linux-64bit.tar.gz \
--bundle trivy_0.68.1_Linux-64bit.tar.gz.sigstore.json \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com \
--certificate-identity 'https://github.com/aquasecurity/trivy/.github/workflows/reusable-release.yaml@refs/tags/v0.68.1'
```
You should get the following output

View File

@@ -16,7 +16,7 @@ Trivy scans Infrastructure as Code (IaC) files for
| [Terraform Plan](terraform.md) | tfplan, \*.tfplan, \*.json |
| [CloudFormation](cloudformation.md) | \*.yml, \*.yaml, \*.json |
| [Azure ARM Template](azure-arm.md) | \*.json |
| [Helm](helm.md) | \*.yaml, \*.tpl, \*.tar.gz, etc. |
| [Helm](helm.md) | \*.yml, \*.yaml, \*.tpl, \*.tar.gz, etc. |
| [YAML][json-and-yaml] | \*.yaml, \*.yml |
| [JSON][json-and-yaml] | \*.json |
| [Ansible](ansible.md) | \*.yml, \*.yaml, \*.json, \*.ini, without extension |

View File

@@ -11,10 +11,10 @@ The following scanners are supported.
The following table provides an outline of the features Trivy offers.
| Package manager | File | Transitive dependencies | Dev dependencies | [Dependency graph][dependency-graph] | Position |
|-----------------|----------------|:-----------------------:|:----------------:|:------------------------------------:|:--------:|
| Composer | composer.lock | ✓ | Excluded | ✓ | ✓ |
| Composer | installed.json | ✓ | Excluded | - | ✓ |
| Package manager | File | Transitive dependencies | Dev dependencies | [Dependency graph][dependency-graph] | Position |
|-----------------|----------------|:-----------------------:|:----------------------------------:|:------------------------------------:|:--------:|
| Composer | composer.lock | ✓ | [Excluded](#development-dependencies) | ✓ | ✓ |
| Composer | installed.json | ✓ | Excluded | - | ✓ |
## composer.lock
In order to detect dependencies, Trivy searches for `composer.lock`.
@@ -23,6 +23,12 @@ Trivy also supports dependency trees; however, to display an accurate tree, it n
Since this information is not included in `composer.lock`, Trivy parses `composer.json`, which should be located next to `composer.lock`.
If you want to see the dependency tree, please ensure that `composer.json` is present.
### Development dependencies
By default, Trivy doesn't report development dependencies (`packages-dev` in `composer.lock`).
Use the `--include-dev-deps` flag to include them.
To correctly identify direct development dependencies, Trivy parses `require-dev` from `composer.json`, which should be located next to `composer.lock`.
## installed.json
Trivy also supports dependency detection for `installed.json` files. By default, you can find this file at `path_to_app/vendor/composer/installed.json`.

30
go.mod
View File

@@ -46,12 +46,12 @@ require (
github.com/docker/go-connections v0.6.0
github.com/docker/go-units v0.5.0
github.com/fatih/color v1.18.0
github.com/go-git/go-git/v5 v5.16.3
github.com/go-git/go-git/v5 v5.16.4
github.com/go-redis/redis/v8 v8.11.5
github.com/go-viper/mapstructure/v2 v2.4.0
github.com/gocsaf/csaf/v3 v3.4.0
github.com/gocsaf/csaf/v3 v3.5.0
github.com/golang-jwt/jwt/v5 v5.3.0
github.com/google/go-containerregistry v0.20.6
github.com/google/go-containerregistry v0.20.7
github.com/google/go-github/v62 v62.0.0
github.com/google/licenseclassifier/v2 v2.0.0
github.com/google/uuid v1.6.0
@@ -59,7 +59,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1
github.com/hashicorp/go-retryablehttp v0.7.8
github.com/hashicorp/go-uuid v1.0.3
github.com/hashicorp/go-version v1.7.0
github.com/hashicorp/go-version v1.8.0
github.com/hashicorp/golang-lru/v2 v2.0.7
github.com/hashicorp/hc-install v0.9.2
github.com/hashicorp/hcl/v2 v2.24.0
@@ -84,7 +84,7 @@ require (
github.com/moby/buildkit v0.26.2
github.com/moby/docker-image-spec v1.3.1
github.com/moby/moby/client v0.2.1 // indirect
github.com/open-policy-agent/opa v1.10.1
github.com/open-policy-agent/opa v1.11.0
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.1
github.com/openvex/discovery v0.1.1-0.20240802171711-7c54efc57553
@@ -102,7 +102,7 @@ require (
github.com/sosedoff/gitkit v0.4.0
github.com/spdx/tools-golang v0.5.5 // v0.5.3 with necessary changes. Can be upgraded to version 0.5.4 after release.
github.com/spf13/cast v1.10.0
github.com/spf13/cobra v1.10.1
github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.10
github.com/spf13/viper v1.21.0
github.com/stretchr/testify v1.11.1
@@ -119,10 +119,10 @@ require (
golang.org/x/crypto v0.45.0
golang.org/x/mod v0.30.0
golang.org/x/net v0.47.0
golang.org/x/sync v0.18.0
golang.org/x/sync v0.19.0
golang.org/x/term v0.37.0
golang.org/x/text v0.31.0
golang.org/x/tools v0.38.0
golang.org/x/tools v0.39.0
golang.org/x/vuln v1.1.4
golang.org/x/xerrors v0.0.0-20240716161551-93cc26a95ae9
google.golang.org/protobuf v1.36.10
@@ -135,7 +135,7 @@ require (
require (
github.com/go-ini/ini v1.67.0
github.com/nikolalohinski/gonja/v2 v2.3.5
github.com/nikolalohinski/gonja/v2 v2.4.2
)
require (
@@ -225,7 +225,7 @@ require (
github.com/containerd/fifo v1.1.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/plugin v1.0.0 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.17.0 // indirect
github.com/containerd/stargz-snapshotter/estargz v0.18.1 // indirect
github.com/containerd/ttrpc v1.2.7 // indirect
github.com/containerd/typeurl/v2 v2.2.3 // indirect
github.com/cpuguy83/dockercfg v0.3.2 // indirect
@@ -331,7 +331,7 @@ require (
github.com/lestrrat-go/dsig-secp256k1 v1.0.0 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/httprc/v3 v3.0.1 // indirect
github.com/lestrrat-go/jwx/v3 v3.0.11 // indirect
github.com/lestrrat-go/jwx/v3 v3.0.12 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/lestrrat-go/option/v2 v2.0.0 // indirect
github.com/letsencrypt/boulder v0.0.0-20240620165639-de9c06129bec // indirect
@@ -398,7 +398,7 @@ require (
github.com/samber/oops v1.18.1 // indirect
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
github.com/sassoftware/relic v7.2.1+incompatible // indirect
github.com/segmentio/asm v1.2.0 // indirect
github.com/segmentio/asm v1.2.1 // indirect
github.com/segmentio/encoding v0.5.3 // indirect
github.com/sergi/go-diff v1.4.0 // indirect
github.com/shibumi/go-pathspec v1.3.0 // indirect
@@ -428,7 +428,7 @@ require (
github.com/ulikunitz/xz v0.5.15 // indirect
github.com/valyala/fastjson v1.6.4 // indirect
github.com/vbatts/tar-split v0.12.2 // indirect
github.com/vektah/gqlparser/v2 v2.5.30 // indirect
github.com/vektah/gqlparser/v2 v2.5.31 // indirect
github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
@@ -465,9 +465,9 @@ require (
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/exp v0.0.0-20250911091902-df9299821621 // indirect
golang.org/x/oauth2 v0.32.0 // indirect
golang.org/x/oauth2 v0.33.0 // indirect
golang.org/x/sys v0.38.0 // indirect
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 // indirect
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 // indirect
golang.org/x/time v0.14.0 // indirect
golang.org/x/tools/gopls v0.0.0-20251008221726-a22b5e8a9b8d // indirect
google.golang.org/api v0.254.0 // indirect

64
go.sum
View File

@@ -316,8 +316,8 @@ github.com/buildkite/go-pipeline v0.3.2 h1:SW4EaXNwfjow7xDRPGgX0Rcx+dPj5C1kV9LKC
github.com/buildkite/go-pipeline v0.3.2/go.mod h1:iY5jzs3Afc8yHg6KDUcu3EJVkfaUkd9x/v/OH98qyUA=
github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251 h1:k6UDF1uPYOs0iy1HPeotNa155qXRWrzKnqAaGXHLZCE=
github.com/buildkite/interpolate v0.0.0-20200526001904-07f35b4ae251/go.mod h1:gbPR1gPu9dB96mucYIR7T3B7p/78hRVSOuzIWLHK2Y4=
github.com/bytecodealliance/wasmtime-go/v37 v37.0.0 h1:DPjdn2V3JhXHMoZ2ymRqGK+y1bDyr9wgpyYCvhjMky8=
github.com/bytecodealliance/wasmtime-go/v37 v37.0.0/go.mod h1:Pf1l2JCTUFMnOqDIwkjzx1qfVJ09xbaXETKgRVE4jZ0=
github.com/bytecodealliance/wasmtime-go/v39 v39.0.1 h1:RibaT47yiyCRxMOj/l2cvL8cWiWBSqDXHyqsa9sGcCE=
github.com/bytecodealliance/wasmtime-go/v39 v39.0.1/go.mod h1:miR4NYIEBXeDNamZIzpskhJ0z/p8al+lwMWylQ/ZJb4=
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM=
@@ -370,8 +370,8 @@ github.com/containerd/platforms v1.0.0-rc.2 h1:0SPgaNZPVWGEi4grZdV8VRYQn78y+nm6a
github.com/containerd/platforms v1.0.0-rc.2/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4=
github.com/containerd/plugin v1.0.0 h1:c8Kf1TNl6+e2TtMHZt+39yAPDbouRH9WAToRjex483Y=
github.com/containerd/plugin v1.0.0/go.mod h1:hQfJe5nmWfImiqT1q8Si3jLv3ynMUIBB47bQ+KexvO8=
github.com/containerd/stargz-snapshotter/estargz v0.17.0 h1:+TyQIsR/zSFI1Rm31EQBwpAA1ovYgIKHy7kctL3sLcE=
github.com/containerd/stargz-snapshotter/estargz v0.17.0/go.mod h1:s06tWAiJcXQo9/8AReBCIo/QxcXFZ2n4qfsRnpl71SM=
github.com/containerd/stargz-snapshotter/estargz v0.18.1 h1:cy2/lpgBXDA3cDKSyEfNOFMA/c10O1axL69EU7iirO8=
github.com/containerd/stargz-snapshotter/estargz v0.18.1/go.mod h1:ALIEqa7B6oVDsrF37GkGN20SuvG/pIMm7FwP7ZmRb0Q=
github.com/containerd/ttrpc v1.2.7 h1:qIrroQvuOL9HQ1X6KHe2ohc7p+HP/0VE6XPU7elJRqQ=
github.com/containerd/ttrpc v1.2.7/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o=
github.com/containerd/typeurl/v2 v2.2.3 h1:yNA/94zxWdvYACdYO8zofhrTVuQY73fFU1y++dYSw40=
@@ -508,8 +508,8 @@ github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UN
github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.16.3 h1:Z8BtvxZ09bYm/yYNgPKCzgWtaRqDTgIKRgIRHBfU6Z8=
github.com/go-git/go-git/v5 v5.16.3/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
github.com/go-git/go-git/v5 v5.16.4 h1:7ajIEZHZJULcyJebDLo99bGgS0jRrOxzZG4uCk2Yb2Y=
github.com/go-git/go-git/v5 v5.16.4/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A=
@@ -600,8 +600,8 @@ github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PU
github.com/goccy/go-yaml v1.8.1/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y=
github.com/goccy/go-yaml v1.15.23 h1:WS0GAX1uNPDLUvLkNU2vXq6oTnsmfVFocjQ/4qA48qo=
github.com/goccy/go-yaml v1.15.23/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/gocsaf/csaf/v3 v3.4.0 h1:rzVTiA5WmzTHumgGfK/823h0zQ0y4WAS+Rorhcm2LDE=
github.com/gocsaf/csaf/v3 v3.4.0/go.mod h1:MmKPoT9IhckqbC590XvKbCkRstuba9vbL+HT3bsuQLk=
github.com/gocsaf/csaf/v3 v3.5.0 h1:tj8l1vK2V8GwjCh3axwKF/yJ9d28xuFn3NsZDdPSkJ8=
github.com/gocsaf/csaf/v3 v3.5.0/go.mod h1:JKOjRGPvEFalUm5u2vP1itqqgUaojWTpBtGlhEUI7g0=
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw=
@@ -662,8 +662,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-containerregistry v0.20.6 h1:cvWX87UxxLgaH76b4hIvya6Dzz9qHB31qAwjAohdSTU=
github.com/google/go-containerregistry v0.20.6/go.mod h1:T0x8MuoAoKX/873bkeSfLD2FAkwCDf9/HZgsFJ02E2Y=
github.com/google/go-containerregistry v0.20.7 h1:24VGNpS0IwrOZ2ms2P1QE3Xa5X9p4phx0aUgzYzHW6I=
github.com/google/go-containerregistry v0.20.7/go.mod h1:Lx5LCZQjLH1QBaMPeGwsME9biPeo1lPx6lbGj/UmzgM=
github.com/google/go-github/v31 v31.0.0 h1:JJUxlP9lFK+ziXKimTCprajMApV1ecWD4NB6CCb0plo=
github.com/google/go-github/v31 v31.0.0/go.mod h1:NQPZol8/1sMoWYGN2yaALIBytu17gAWfhbweiEed3pM=
github.com/google/go-github/v55 v55.0.0 h1:4pp/1tNMB9X/LuAhs5i0KQAE40NmiR/y6prLNb9x9cg=
@@ -737,8 +737,8 @@ github.com/hashicorp/go-sockaddr v1.0.5 h1:dvk7TIXCZpmfOlM+9mlcrWmWjw/wlKT+VDq2w
github.com/hashicorp/go-sockaddr v1.0.5/go.mod h1:uoUUmtwU7n9Dv3O4SNLeFvg0SxQ3lyjsj6+CCykpaxI=
github.com/hashicorp/go-uuid v1.0.3 h1:2gKiV6YVmrJ1i2CKKa9obLvRieoRGviZFL26PcT/Co8=
github.com/hashicorp/go-uuid v1.0.3/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go-version v1.8.0 h1:KAkNb1HAiZd1ukkxDFGmokVZe1Xy9HG6NUp+bPle2i4=
github.com/hashicorp/go-version v1.8.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru/arc/v2 v2.0.5 h1:l2zaLDubNhW4XO3LnliVj0GXO3+/CGNJAg1dcN2Fpfw=
github.com/hashicorp/golang-lru/arc/v2 v2.0.5/go.mod h1:ny6zBSQZi2JxIeYcv7kt2sH2PXJtirBN7RDhRpxPkxU=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
@@ -834,8 +834,8 @@ github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZ
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
github.com/lestrrat-go/httprc/v3 v3.0.1 h1:3n7Es68YYGZb2Jf+k//llA4FTZMl3yCwIjFIk4ubevI=
github.com/lestrrat-go/httprc/v3 v3.0.1/go.mod h1:2uAvmbXE4Xq8kAUjVrZOq1tZVYYYs5iP62Cmtru00xk=
github.com/lestrrat-go/jwx/v3 v3.0.11 h1:yEeUGNUuNjcez/Voxvr7XPTYNraSQTENJgtVTfwvG/w=
github.com/lestrrat-go/jwx/v3 v3.0.11/go.mod h1:XSOAh2SiXm0QgRe3DulLZLyt+wUuEdFo81zuKTLcvgQ=
github.com/lestrrat-go/jwx/v3 v3.0.12 h1:p25r68Y4KrbBdYjIsQweYxq794CtGCzcrc5dGzJIRjg=
github.com/lestrrat-go/jwx/v3 v3.0.12/go.mod h1:HiUSaNmMLXgZ08OmGBaPVvoZQgJVOQphSrGr5zMamS8=
github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss=
@@ -949,8 +949,8 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nikolalohinski/gonja/v2 v2.3.5 h1:7ukCnsokmOIGXOjgW/WrM+xqgwjsQcU0ejFrrz4HQXk=
github.com/nikolalohinski/gonja/v2 v2.3.5/go.mod h1:UIzXPVuOsr5h7dZ5DUbqk3/Z7oFA/NLGQGMjqT4L2aU=
github.com/nikolalohinski/gonja/v2 v2.4.2 h1:1tmj/ICrskH8/9dtuQ9MNnQsyId4AkUe9qlCFmVQ9eI=
github.com/nikolalohinski/gonja/v2 v2.4.2/go.mod h1:UIzXPVuOsr5h7dZ5DUbqk3/Z7oFA/NLGQGMjqT4L2aU=
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 h1:Up6+btDp321ZG5/zdSLo48H9Iaq0UQGthrhWC6pCxzE=
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481/go.mod h1:yKZQO8QE2bHlgozqWDiRVqTFlLQSj30K/6SAK8EeYFw=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
@@ -977,8 +977,8 @@ github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAl
github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
github.com/open-policy-agent/opa v1.10.1 h1:haIvxZSPky8HLjRrvQwWAjCPLg8JDFSZMbbG4yyUHgY=
github.com/open-policy-agent/opa v1.10.1/go.mod h1:7uPI3iRpOalJ0BhK6s1JALWPU9HvaV1XeBSSMZnr/PM=
github.com/open-policy-agent/opa v1.11.0 h1:eOd/jJrbavakiX477yT4LrXZfUWViAot/AsKsjsfe7o=
github.com/open-policy-agent/opa v1.11.0/go.mod h1:QimuJO4T3KYxWzrmAymqlFvsIanCjKrGjmmC8GgAdgE=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
@@ -1087,8 +1087,8 @@ github.com/sassoftware/relic/v7 v7.6.2 h1:rS44Lbv9G9eXsukknS4mSjIAuuX+lMq/FnStgm
github.com/sassoftware/relic/v7 v7.6.2/go.mod h1:kjmP0IBVkJZ6gXeAu35/KCEfca//+PKM6vTAsyDPY+k=
github.com/secure-systems-lab/go-securesystemslib v0.9.1 h1:nZZaNz4DiERIQguNy0cL5qTdn9lR8XKHf4RUyG1Sx3g=
github.com/secure-systems-lab/go-securesystemslib v0.9.1/go.mod h1:np53YzT0zXGMv6x4iEWc9Z59uR+x+ndLwCLqPYpLXVU=
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/segmentio/encoding v0.5.3 h1:OjMgICtcSFuNvQCdwqMCv9Tg7lEOXGwm1J5RPQccx6w=
github.com/segmentio/encoding v0.5.3/go.mod h1:HS1ZKa3kSN32ZHVZ7ZLPLXWvOVIiZtyJnO1gPH1sKt0=
github.com/segmentio/ksuid v1.0.4 h1:sBo2BdShXjmcugAMwjugoGUdUV0pcxY5mW4xKRn3v4c=
@@ -1144,8 +1144,8 @@ github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
github.com/spf13/cobra v0.0.0-20170130214531-35136c09d8da/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
@@ -1228,8 +1228,8 @@ github.com/valyala/fastjson v1.6.4 h1:uAUNq9Z6ymTgGhcm0UynUAB6tlbakBrz6CQFax3BXV
github.com/valyala/fastjson v1.6.4/go.mod h1:CLCAqky6SMuOcxStkYQvblddUtoRxhYMGLrsQns1aXY=
github.com/vbatts/tar-split v0.12.2 h1:w/Y6tjxpeiFMR47yzZPlPj/FcPLpXbTUi/9H7d3CPa4=
github.com/vbatts/tar-split v0.12.2/go.mod h1:eF6B6i6ftWQcDqEn3/iGFRFRo8cBIMSJVOpnNdfTMFA=
github.com/vektah/gqlparser/v2 v2.5.30 h1:EqLwGAFLIzt1wpx1IPpY67DwUujF1OfzgEyDsLrN6kE=
github.com/vektah/gqlparser/v2 v2.5.30/go.mod h1:D1/VCZtV3LPnQrcPBeR/q5jkSQIPti0uYCP/RI0gIeo=
github.com/vektah/gqlparser/v2 v2.5.31 h1:YhWGA1mfTjID7qJhd1+Vxhpk5HTgydrGU9IgkWBTJ7k=
github.com/vektah/gqlparser/v2 v2.5.31/go.mod h1:c1I28gSOVNzlfc4WuDlqU7voQnsqI6OG2amkBAFmgts=
github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4=
github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
@@ -1391,15 +1391,15 @@ golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo=
golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1435,8 +1435,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8 h1:LvzTn0GQhWuvKH/kVRS3R3bVAsdQWI7hvfLHGgh9+lU=
golang.org/x/telemetry v0.0.0-20251008203120-078029d740a8/go.mod h1:Pi4ztBfryZoJEkyFTI5/Ocsu2jXyDr6iSdgJiYE/uwE=
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54 h1:E2/AqCUMZGgd73TQkxUMcMla25GB9i/5HOdLr+uH7Vo=
golang.org/x/telemetry v0.0.0-20251111182119-bc8e575c7b54/go.mod h1:hKdjCMrbv9skySur+Nek8Hd0uJ0GuxJIoIX2payrIdQ=
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.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU=
@@ -1460,8 +1460,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ=
golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs=
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM=
golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM=

View File

@@ -78,6 +78,7 @@ The following table lists the configurable parameters of the Trivy chart and the
| `trivy.existingSecret` | existingSecret if an existing secret has been created outside the chart. Overrides gitHubToken, registryUsername, registryPassword, serverToken | `` |
| `trivy.podAnnotations` | Annotations for pods created by statefulset | `{}` |
| `trivy.extraEnvVars` | extraEnvVars to be set on the container | `{}` |
| `trivy.sslCertDir` | Can be used to override the system default locations for SSL certificate files directory, example: `/ssl/certs` | `` |
| `service.name` | If specified, the name used for the Trivy service | |
| `service.type` | Kubernetes service type | `ClusterIP` |
| `service.port` | Kubernetes service port | `4954` |

View File

@@ -27,3 +27,6 @@ data:
{{- with .Values.trivy.extraEnvVars }}
{{- . | toYaml | nindent 2 }}
{{- end }}
{{- if .Values.trivy.sslCertDir }}
SSL_CERT_DIR: {{ .Values.trivy.sslCertDir | quote }}
{{- end }}

View File

@@ -125,6 +125,11 @@ spec:
- mountPath: /home/scanner/.cache
name: data
readOnly: false
{{- with .Values.trivy.sslCertDir }}
- mountPath: {{ . }}
name: ssl-cert-dir
readOnly: true
{{- end }}
{{- if .Values.resources }}
resources:
{{ toYaml .Values.resources | indent 12 }}
@@ -136,3 +141,8 @@ spec:
- name: data
emptyDir: {}
{{- end }}
{{- with .Values.trivy.sslCertDir }}
- name: ssl-cert-dir
hostPath:
path: {{ . }}
{{- end }}

View File

@@ -128,6 +128,8 @@ trivy:
existingSecret: ""
# extraEnvVars to be set on the container
extraEnvVars: {}
# sslCertDir can be used to override the system default locations for SSL certificate files directory, example: /ssl/certs
sslCertDir: ""
service:
# If specified, the name used for the Trivy service.

View File

@@ -17,7 +17,8 @@ import (
)
type LockFile struct {
Packages []packageInfo `json:"packages"`
Packages []packageInfo `json:"packages"`
PackagesDev []packageInfo `json:"packages-dev"`
}
type packageInfo struct {
Name string `json:"name"`
@@ -45,30 +46,11 @@ func (p *Parser) Parse(_ context.Context, r xio.ReadSeekerAt) ([]ftypes.Package,
pkgs := make(map[string]ftypes.Package)
foundDeps := make(map[string][]string)
for _, lpkg := range lockFile.Packages {
pkg := ftypes.Package{
ID: dependency.ID(ftypes.Composer, lpkg.Name, lpkg.Version),
Name: lpkg.Name,
Version: lpkg.Version,
Relationship: ftypes.RelationshipUnknown, // composer.lock file doesn't have info about direct/indirect dependencies
Licenses: licenses(lpkg.License),
Locations: []ftypes.Location{ftypes.Location(lpkg.Location)},
}
pkgs[pkg.Name] = pkg
var dependsOn []string
for depName := range lpkg.Require {
// Require field includes required php version, skip this
// Also skip PHP extensions
if depName == "php" || strings.HasPrefix(depName, "ext") {
continue
}
dependsOn = append(dependsOn, depName) // field uses range of versions, so later we will fill in the versions from the packages
}
if len(dependsOn) > 0 {
foundDeps[pkg.ID] = dependsOn
}
}
// Production packages are parsed first to ensure they take precedence
// when the same package exists in both "packages" and "packages-dev".
p.parseProdPackages(lockFile, pkgs, foundDeps)
p.parseDevPackages(lockFile, pkgs, foundDeps)
// fill deps versions
var deps ftypes.Dependencies
@@ -95,6 +77,50 @@ func (p *Parser) Parse(_ context.Context, r xio.ReadSeekerAt) ([]ftypes.Package,
return pkgSlice, deps, nil
}
// parseProdPackages parses packages from the "packages" field in composer.lock.
func (p *Parser) parseProdPackages(lockFile LockFile, pkgs map[string]ftypes.Package, foundDeps map[string][]string) {
p.parsePackages(lockFile.Packages, false, pkgs, foundDeps)
}
// parseDevPackages parses packages from the "packages-dev" field in composer.lock.
// Packages already present in pkgs (i.e., production packages) are skipped.
func (p *Parser) parseDevPackages(lockFile LockFile, pkgs map[string]ftypes.Package, foundDeps map[string][]string) {
p.parsePackages(lockFile.PackagesDev, true, pkgs, foundDeps)
}
func (p *Parser) parsePackages(lockPkgs []packageInfo, isDev bool, pkgs map[string]ftypes.Package, foundDeps map[string][]string) {
for _, lpkg := range lockPkgs {
// Skip if the package already exists (production packages take precedence over dev packages)
if _, ok := pkgs[lpkg.Name]; ok {
continue
}
pkg := ftypes.Package{
ID: dependency.ID(ftypes.Composer, lpkg.Name, lpkg.Version),
Name: lpkg.Name,
Version: lpkg.Version,
Relationship: ftypes.RelationshipUnknown, // composer.lock file doesn't have info about direct/indirect dependencies
Licenses: licenses(lpkg.License),
Locations: []ftypes.Location{ftypes.Location(lpkg.Location)},
Dev: isDev,
}
pkgs[pkg.Name] = pkg
var dependsOn []string
for depName := range lpkg.Require {
// Require field includes required php version, skip this
// Also skip PHP extensions
if depName == "php" || strings.HasPrefix(depName, "ext") {
continue
}
dependsOn = append(dependsOn, depName) // field uses range of versions, so later we will fill in the versions from the packages
}
if len(dependsOn) > 0 {
foundDeps[pkg.ID] = dependsOn
}
}
}
// licenses returns slice of licenses from string, string with separators (`or`, `and`, etc.) or string array
// cf. https://getcomposer.org/doc/04-schema.md#license
func licenses(val any) []string {

View File

@@ -54,6 +54,32 @@ var (
},
},
},
{
ID: "pear/log@1.13.3",
Name: "pear/log",
Version: "1.13.3",
Dev: true,
Licenses: []string{"MIT"},
Locations: []ftypes.Location{
{
StartLine: 660,
EndLine: 719,
},
},
},
{
ID: "pear/pear_exception@v1.0.2",
Name: "pear/pear_exception",
Version: "v1.0.2",
Dev: true,
Licenses: []string{"BSD-2-Clause"},
Locations: []ftypes.Location{
{
StartLine: 720,
EndLine: 778,
},
},
},
{
ID: "psr/http-message@1.0.1",
Name: "psr/http-message",
@@ -132,6 +158,12 @@ var (
"ralouphie/getallheaders@3.0.3",
},
},
{
ID: "pear/log@1.13.3",
DependsOn: []string{
"pear/pear_exception@v1.0.2",
},
},
{
ID: "symfony/polyfill-intl-idn@v1.27.0",
DependsOn: []string{

View File

@@ -50,6 +50,7 @@ var eolDates = map[string]time.Time{
"3.20": time.Date(2026, 4, 1, 23, 59, 59, 0, time.UTC),
"3.21": time.Date(2026, 12, 5, 23, 59, 59, 0, time.UTC),
"3.22": time.Date(2027, 4, 30, 23, 59, 59, 0, time.UTC),
"3.23": time.Date(2027, 11, 1, 23, 59, 59, 0, time.UTC),
"edge": time.Date(9999, 1, 1, 0, 0, 0, 0, time.UTC),
}

View File

@@ -676,7 +676,7 @@ func TestAnalyzerGroup_AnalyzerVersions(t *testing.T) {
"ubuntu-esm": 1,
},
PostAnalyzers: map[string]int{
"dpkg": 5,
"dpkg": 6,
"jar": 1,
"poetry": 1,
},

View File

@@ -106,7 +106,7 @@ func (a composerAnalyzer) parseComposerLock(ctx context.Context, path string, r
func (a composerAnalyzer) mergeComposerJson(fsys fs.FS, dir string, app *types.Application) error {
// Parse composer.json to identify the direct dependencies
path := filepath.Join(dir, types.ComposerJson)
p, err := a.parseComposerJson(fsys, path)
cj, err := a.parseComposerJson(fsys, path)
if errors.Is(err, fs.ErrNotExist) {
// Assume all the packages are direct dependencies as it cannot identify them from composer.lock
log.Debug("Unable to determine the direct dependencies, composer.json not found", log.FilePath(path))
@@ -117,7 +117,9 @@ func (a composerAnalyzer) mergeComposerJson(fsys fs.FS, dir string, app *types.A
for i, pkg := range app.Packages {
// Identify the direct/transitive dependencies
if _, ok := p[pkg.Name]; ok {
if _, ok := cj.Require[pkg.Name]; ok {
app.Packages[i].Relationship = types.RelationshipDirect
} else if _, ok := cj.RequireDev[pkg.Name]; ok {
app.Packages[i].Relationship = types.RelationshipDirect
} else {
app.Packages[i].Indirect = true
@@ -129,21 +131,22 @@ func (a composerAnalyzer) mergeComposerJson(fsys fs.FS, dir string, app *types.A
}
type composerJson struct {
Require map[string]string `json:"require"`
Require map[string]string `json:"require"`
RequireDev map[string]string `json:"require-dev"`
}
func (a composerAnalyzer) parseComposerJson(fsys fs.FS, path string) (map[string]string, error) {
func (a composerAnalyzer) parseComposerJson(fsys fs.FS, path string) (composerJson, error) {
// Parse composer.json
f, err := fsys.Open(path)
if err != nil {
return nil, xerrors.Errorf("file open error: %w", err)
return composerJson{}, xerrors.Errorf("file open error: %w", err)
}
defer func() { _ = f.Close() }()
jsonFile := composerJson{}
var jsonFile composerJson
err = json.NewDecoder(f).Decode(&jsonFile)
if err != nil {
return nil, xerrors.Errorf("json decode error: %w", err)
return composerJson{}, xerrors.Errorf("json decode error: %w", err)
}
return jsonFile.Require, nil
return jsonFile, nil
}

View File

@@ -151,6 +151,65 @@ func Test_composerAnalyzer_PostAnalyze(t *testing.T) {
dir: "testdata/composer/sad",
want: &analyzer.AnalysisResult{},
},
{
name: "with dev dependencies",
dir: "testdata/composer/with-dev",
want: &analyzer.AnalysisResult{
Applications: []types.Application{
{
Type: types.Composer,
FilePath: "composer.lock",
Packages: types.Packages{
{
ID: "pear/log@1.14.6",
Name: "pear/log",
Version: "1.14.6",
Dev: true,
Indirect: false,
Relationship: types.RelationshipDirect,
Licenses: []string{"MIT"},
Locations: []types.Location{
{
StartLine: 61,
EndLine: 121,
},
},
DependsOn: []string{"pear/pear_exception@v1.0.2"},
},
{
ID: "psr/log@1.1.4",
Name: "psr/log",
Version: "1.1.4",
Indirect: false,
Relationship: types.RelationshipDirect,
Licenses: []string{"MIT"},
Locations: []types.Location{
{
StartLine: 9,
EndLine: 58,
},
},
},
{
ID: "pear/pear_exception@v1.0.2",
Name: "pear/pear_exception",
Version: "v1.0.2",
Dev: true,
Indirect: true,
Relationship: types.RelationshipIndirect,
Licenses: []string{"BSD-2-Clause"},
Locations: []types.Location{
{
StartLine: 122,
EndLine: 180,
},
},
},
},
},
},
},
},
}
for _, tt := range tests {

View File

@@ -0,0 +1,8 @@
{
"require": {
"psr/log": "^1.0"
},
"require-dev": {
"pear/log": "^1.13"
}
}

View File

@@ -0,0 +1,190 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "2c9e13a2460669ca09226814c0aefb51",
"packages": [
{
"name": "psr/log",
"version": "1.1.4",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"support": {
"source": "https://github.com/php-fig/log/tree/1.1.4"
},
"time": "2021-05-03T11:20:27+00:00"
}
],
"packages-dev": [
{
"name": "pear/log",
"version": "1.14.6",
"source": {
"type": "git",
"url": "https://github.com/pear/Log.git",
"reference": "e136d31ff6d5991e9707862f5fbfb97d40cd37a3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pear/Log/zipball/e136d31ff6d5991e9707862f5fbfb97d40cd37a3",
"reference": "e136d31ff6d5991e9707862f5fbfb97d40cd37a3",
"shasum": ""
},
"require": {
"pear/pear_exception": "1.0.1 || 1.0.2",
"php": ">=7.4"
},
"require-dev": {
"phpunit/phpunit": "*",
"rector/rector": "*"
},
"suggest": {
"pear/db": "Install optionally via your project's composer.json"
},
"type": "library",
"autoload": {
"psr-0": {
"Log": "./"
},
"exclude-from-classmap": [
"/examples/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
""
],
"license": [
"MIT"
],
"authors": [
{
"name": "Jon Parise",
"email": "jon@php.net",
"homepage": "https://www.indelible.org/",
"role": "Developer"
}
],
"description": "PEAR Logging Framework",
"homepage": "https://pear.github.io/Log/",
"keywords": [
"log",
"logging"
],
"support": {
"issues": "https://github.com/pear/Log/issues",
"source": "https://github.com/pear/Log"
},
"time": "2025-07-27T00:25:20+00:00"
},
{
"name": "pear/pear_exception",
"version": "v1.0.2",
"source": {
"type": "git",
"url": "https://github.com/pear/PEAR_Exception.git",
"reference": "b14fbe2ddb0b9f94f5b24cf08783d599f776fff0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/pear/PEAR_Exception/zipball/b14fbe2ddb0b9f94f5b24cf08783d599f776fff0",
"reference": "b14fbe2ddb0b9f94f5b24cf08783d599f776fff0",
"shasum": ""
},
"require": {
"php": ">=5.2.0"
},
"require-dev": {
"phpunit/phpunit": "<9"
},
"type": "class",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"classmap": [
"PEAR/"
]
},
"notification-url": "https://packagist.org/downloads/",
"include-path": [
"."
],
"license": [
"BSD-2-Clause"
],
"authors": [
{
"name": "Helgi Thormar",
"email": "dufuz@php.net"
},
{
"name": "Greg Beaver",
"email": "cellog@php.net"
}
],
"description": "The PEAR Exception base class.",
"homepage": "https://github.com/pear/PEAR_Exception",
"keywords": [
"exception"
],
"support": {
"issues": "http://pear.php.net/bugs/search.php?cmd=display&package_name[]=PEAR_Exception",
"source": "https://github.com/pear/PEAR_Exception"
},
"time": "2021-03-21T15:43:46+00:00"
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {},
"platform-dev": {},
"plugin-api-version": "2.9.0"
}

View File

@@ -41,7 +41,7 @@ func newDpkgAnalyzer(_ analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error)
}
const (
analyzerVersion = 5
analyzerVersion = 6
statusFile = "var/lib/dpkg/status"
statusDir = "var/lib/dpkg/status.d/"
@@ -54,6 +54,56 @@ const (
var (
dpkgSrcCaptureRegexp = regexp.MustCompile(`(?P<name>[^\s]*)( \((?P<version>.*)\))?`)
dpkgSrcCaptureRegexpNames = dpkgSrcCaptureRegexp.SubexpNames()
// thirdPartyMaintainerPatterns contains patterns that indicate a package is from a third-party repository.
// Packages with maintainers matching these patterns will NOT have their InstalledFiles tracked,
// allowing language scanners to properly analyze files installed by those packages.
// See https://github.com/aquasecurity/trivy/issues/9916 for more details.
thirdPartyMaintainerPatterns = []string{
// Container & orchestration
"support@docker.com", // Docker
// Cloud providers & infrastructure
"@nvidia.com", // NVIDIA CUDA
"Google Cloud CLI Authors", // Google Cloud SDK
"sapmachine@sap.com", // SAP Machine JDK
"@hashicorp.com", // HashiCorp (Terraform, Vault, Consul, etc.)
"@microsoft.com", // Microsoft (VS Code, Azure CLI, .NET, etc.)
// Databases
"@mongodb.com", // MongoDB
"developers@lists.mariadb.org", // MariaDB
"dev@couchdb.apache.org", // Apache CouchDB
"info@elastic.co", // Elastic (Elasticsearch, Kibana, etc.)
// Web servers & API gateways
"nginx-packaging@f5.com", // NGINX (from nginx.org, not Debian)
"@konghq.com", // Kong
"@cloudflare.com", // Cloudflare (cloudflared, WARP)
// Monitoring & observability
"support@influxdb.com", // InfluxData (InfluxDB, Telegraf)
"support@gitlab.com", // GitLab
"contact@grafana.com", // Grafana Labs
"@datadoghq.com", // Datadog
// Language runtimes (third-party repos)
"@nodesource.com", // NodeSource (Node.js)
// Networking & VPN
"info@tailscale.com", // Tailscale
// Robotics
"@openrobotics.org", // ROS (Robot Operating System)
"@osrfoundation.org", // ROS (Robot Operating System)
}
// thirdPartyMaintainerExact contains maintainer strings that require exact match.
// These are too short or generic for substring matching.
thirdPartyMaintainerExact = []string{
"GitHub", // GitHub CLI
"HashiCorp", // HashiCorp (Terraform, Vault, Consul, etc.)
}
)
func (a dpkgAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysisInput) (*analyzer.AnalysisResult, error) {
@@ -82,7 +132,7 @@ func (a dpkgAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysis
return xerrors.Errorf("failed to parse %s file: %w", path, err)
}
packageFiles[strings.TrimSuffix(filepath.Base(path), md5sumsExtension)] = systemFiles
systemInstalledFiles = append(systemInstalledFiles, systemFiles...)
// Note: systemInstalledFiles will be populated later based on maintainer check
return nil
}
// parse status files
@@ -97,14 +147,26 @@ func (a dpkgAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAnalysis
return nil, xerrors.Errorf("dpkg walk error: %w", err)
}
// map the packages to their respective files
// Map packages to their respective files.
// Third-party packages will NOT have their InstalledFiles populated to avoid filtering out
// language packages (npm, pip, etc.) installed by those third-party OS packages.
for i, pkgInfo := range packageInfos {
for j, pkg := range pkgInfo.Packages {
installedFiles, found := packageFiles[pkg.Name]
if !found {
installedFiles = packageFiles[pkg.Name+":"+pkg.Arch]
}
// Skip InstalledFiles for third-party packages
if isThirdPartyPackage(pkg.Maintainer) {
a.logger.Debug("Third-party package detected",
log.String("package", pkg.Name),
log.String("maintainer", pkg.Maintainer))
continue
}
packageInfos[i].Packages[j].InstalledFiles = installedFiles
systemInstalledFiles = append(systemInstalledFiles, installedFiles...)
}
}
@@ -349,6 +411,21 @@ func (a dpkgAnalyzer) isMd5SumsFile(dir, fileName string) bool {
return strings.HasSuffix(fileName, md5sumsExtension)
}
// isThirdPartyPackage checks if a package is from a third-party repository
// by examining the Maintainer field against known third-party patterns.
//
// Unlike RPM which has a dedicated "Vendor" field, dpkg packages don't have a reliable
// way to identify their origin. We use a heuristic approach based on maintainer patterns.
// See https://github.com/aquasecurity/trivy/issues/9916 for more details.
func isThirdPartyPackage(maintainer string) bool {
if slices.Contains(thirdPartyMaintainerExact, maintainer) {
return true
}
return slices.ContainsFunc(thirdPartyMaintainerPatterns, func(pattern string) bool {
return strings.Contains(maintainer, pattern)
})
}
func (a dpkgAnalyzer) Type() analyzer.Type {
return analyzer.TypeDpkg
}

View File

@@ -1420,9 +1420,45 @@ func Test_dpkgAnalyzer_Analyze(t *testing.T) {
},
},
{
name: "md5sums",
testFiles: map[string]string{"./testdata/tar.md5sums": "var/lib/dpkg/info/tar.md5sums"},
name: "md5sums",
testFiles: map[string]string{
"./testdata/tar-status": "var/lib/dpkg/status",
"./testdata/tar.md5sums": "var/lib/dpkg/info/tar.md5sums",
},
want: &analyzer.AnalysisResult{
PackageInfos: []types.PackageInfo{
{
FilePath: "var/lib/dpkg/status",
Packages: types.Packages{
{
ID: "tar@1.29b-2",
Name: "tar",
Version: "1.29b",
Release: "2",
Arch: "amd64",
SrcName: "tar",
SrcVersion: "1.29b",
SrcRelease: "2",
Maintainer: "Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>",
InstalledFiles: []string{
"/usr/bin/tar",
"/usr/lib/mime/packages/tar",
"/usr/sbin/rmt-tar",
"/usr/sbin/tarcat",
"/usr/share/doc/tar/AUTHORS",
"/usr/share/doc/tar/NEWS.gz",
"/usr/share/doc/tar/README.Debian",
"/usr/share/doc/tar/THANKS.gz",
"/usr/share/doc/tar/changelog.Debian.gz",
"/usr/share/doc/tar/copyright",
"/usr/share/man/man1/tar.1.gz",
"/usr/share/man/man1/tarcat.1.gz",
"/usr/share/man/man8/rmt-tar.8.gz",
},
},
},
},
},
SystemInstalledFiles: []string{
"/usr/bin/tar",
"/usr/lib/mime/packages/tar",
@@ -1470,6 +1506,23 @@ func Test_dpkgAnalyzer_Analyze(t *testing.T) {
}
}
func Test_isThirdPartyPackage(t *testing.T) {
tests := []struct {
name string
maintainer string
want bool
}{
{"third-party (Docker)", "Docker <support@docker.com>", true},
{"third-party (GitHub - exact match)", "GitHub", true},
{"official (Ubuntu)", "Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, isThirdPartyPackage(tt.maintainer))
})
}
}
func Test_dpkgAnalyzer_Required(t *testing.T) {
tests := []struct {
name string

View File

@@ -0,0 +1,17 @@
Package: tar
Essential: yes
Status: install ok installed
Priority: required
Section: utils
Installed-Size: 864
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Architecture: amd64
Multi-Arch: foreign
Version: 1.29b-2
Replaces: cpio (<< 2.4.2-39)
Pre-Depends: libacl1 (>= 2.2.51-8), libc6 (>= 2.17), libselinux1 (>= 1.32)
Suggests: bzip2, ncompress, xz-utils, tar-scripts, tar-doc
Breaks: dpkg-dev (<< 1.14.26)
Conflicts: cpio (<= 2.4.2-38)
Description: GNU version of the tar archiving utility

View File

@@ -36,7 +36,7 @@ import (
// Common blob IDs used across multiple test cases to reduce duplication
const (
alpineBaseLayerID = "sha256:5fa8e7300cfe1b8f70c304e3b04f9b1f022942a0dc57d3fc0d4d3f04327e6d2a"
alpineBaseLayerID = "sha256:6c42077a82b21707f581759b12a99cc9a593ce35a0d7be4c19c01eb48bd5ba33"
alpineBaseLayerDiffID = "sha256:beee9f30bc1f711043e78d4a2be0668955d4b761d587d6f60c2c8dc081efb203"
alpineArtifactID = "sha256:3c709d2a158be3a97051e10cd0e30f047225cb9505101feb3fadcd395c2e0408"
composerImageID = "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72"
@@ -510,7 +510,7 @@ func TestArtifact_Inspect(t *testing.T) {
},
wantBlobs: []cachetest.WantBlob{
{
ID: "sha256:5b61242ed7786d642c7037c5d42c97ef4eb77e79b5cee7d47c3a2476bdd37e54",
ID: "sha256:75a461ca76eecc6cea981889d69aa1c2dd78c436108be8be1bbc29295520c7d4",
BlobInfo: types.BlobInfo{
SchemaVersion: types.BlobJSONSchemaVersion,
Size: 3061760,
@@ -598,7 +598,7 @@ func TestArtifact_Inspect(t *testing.T) {
},
},
{
ID: "sha256:1a8ac8af11a039295f3fffd3e058c034dae966ac7ace649121f0559146133ee5",
ID: "sha256:81afc1747d0fdec7a606c27570313634ae331fab6f13566b23d0f6b3e498c050",
BlobInfo: types.BlobInfo{
SchemaVersion: types.BlobJSONSchemaVersion,
Size: 15441920,
@@ -693,7 +693,7 @@ func TestArtifact_Inspect(t *testing.T) {
},
},
{
ID: "sha256:a686ab4c4132800a0d67a8ddf33dd89387d750a7b3427c01b9ce7bf3219cadfb",
ID: "sha256:0778c3e388c54f736a3d6e74ed390a91fdb42c6809f8fb743d4f72acb41a5d6d",
BlobInfo: types.BlobInfo{
SchemaVersion: types.BlobJSONSchemaVersion,
Size: 29696,
@@ -900,7 +900,7 @@ func TestArtifact_Inspect(t *testing.T) {
},
},
{
ID: "sha256:789b01e58c608d3a3021ce18cf6c8bd21e701116134089d949da35a25f73d9ec",
ID: "sha256:5a3e3f25fdc97a14d69d99c63dd640cd2d38af5b987b7a95084cce3d835970fb",
BlobInfo: types.BlobInfo{
SchemaVersion: types.BlobJSONSchemaVersion,
Size: 6656,
@@ -1763,10 +1763,10 @@ func TestArtifact_Inspect(t *testing.T) {
Type: types.TypeContainerImage,
ID: "sha256:0bebf0773ffd87baa7c64fbdbdf79a24ae125e3f99a8adebe52d1ccbe6bed16b",
BlobIDs: []string{
"sha256:5b61242ed7786d642c7037c5d42c97ef4eb77e79b5cee7d47c3a2476bdd37e54",
"sha256:1a8ac8af11a039295f3fffd3e058c034dae966ac7ace649121f0559146133ee5",
"sha256:a686ab4c4132800a0d67a8ddf33dd89387d750a7b3427c01b9ce7bf3219cadfb",
"sha256:789b01e58c608d3a3021ce18cf6c8bd21e701116134089d949da35a25f73d9ec",
"sha256:75a461ca76eecc6cea981889d69aa1c2dd78c436108be8be1bbc29295520c7d4",
"sha256:81afc1747d0fdec7a606c27570313634ae331fab6f13566b23d0f6b3e498c050",
"sha256:0778c3e388c54f736a3d6e74ed390a91fdb42c6809f8fb743d4f72acb41a5d6d",
"sha256:5a3e3f25fdc97a14d69d99c63dd640cd2d38af5b987b7a95084cce3d835970fb",
},
ImageMetadata: artifact.ImageMetadata{
ID: "sha256:58701fd185bda36cab0557bb6438661831267aa4a9e0b54211c4d5317a48aff4",

View File

@@ -193,7 +193,7 @@ func init() {
return true
}
}
helmFileExtensions := []string{".yaml", ".tpl"}
helmFileExtensions := []string{".yml", ".yaml", ".tpl"}
ext := filepath.Ext(filepath.Base(name))
for _, expected := range helmFileExtensions {
if strings.EqualFold(ext, expected) {

View File

@@ -246,6 +246,7 @@ Resources:
r: nil,
expected: []FileType{
FileTypeYAML,
FileTypeHelm,
FileTypeAnsible,
},
},
@@ -276,6 +277,7 @@ spec:
expected: []FileType{
FileTypeKubernetes,
FileTypeYAML,
FileTypeHelm,
FileTypeAnsible,
},
},
@@ -342,6 +344,7 @@ spec:
r: nil,
expected: []FileType{
FileTypeYAML,
FileTypeHelm,
FileTypeAnsible,
},
},
@@ -351,6 +354,7 @@ spec:
r: nil,
expected: []FileType{
FileTypeYAML,
FileTypeHelm,
},
},
{
@@ -384,6 +388,7 @@ data:
expected: []FileType{
FileTypeKubernetes,
FileTypeYAML,
FileTypeHelm,
FileTypeAnsible,
},
},
@@ -413,6 +418,7 @@ rules:
expected: []FileType{
FileTypeKubernetes,
FileTypeYAML,
FileTypeHelm,
FileTypeAnsible,
},
},

View File

@@ -1,6 +1,11 @@
package parser
import (
"fmt"
"maps"
"regexp"
"strings"
"github.com/samber/lo"
"github.com/aquasecurity/trivy/pkg/iac/ignore"
@@ -12,6 +17,8 @@ type SourceFormat string
const (
YamlSourceFormat SourceFormat = "yaml"
JsonSourceFormat SourceFormat = "json"
ForEachPrefix = "Fn::ForEach::"
)
type FileContexts []*FileContext
@@ -81,3 +88,168 @@ func (t *FileContext) stripNullProperties() {
})
}
}
func (t *FileContext) expandTransforms() error {
resources := make(map[string]*Resource, len(t.Resources))
for name, r := range t.Resources {
if r.raw == nil {
resources[name] = r
continue
}
instances, err := t.expandTransform(r.raw, name)
if err != nil {
return err
}
for logicalID, rawProp := range instances {
instance, err := newExpandedResource(r, logicalID, rawProp)
if err != nil {
return err
}
resources[logicalID] = instance
}
}
t.Resources = resources
return nil
}
func newExpandedResource(base *Resource, logicalID string, raw *Property) (*Resource, error) {
rawMap := raw.AsMap()
typProp, ok := rawMap["Type"]
if !ok {
return nil, fmt.Errorf("missing 'Type' in expanded resource %q", logicalID)
}
propsProp, ok := rawMap["Properties"]
if !ok {
return nil, fmt.Errorf("missing 'Properties' in expanded resource %q", logicalID)
}
instance := base.clone()
instance.typ = typProp.AsString()
instance.properties = propsProp.AsMap()
instance.setId(logicalID)
return instance, nil
}
func (t *FileContext) expandTransform(prop *Property, logicalName string) (map[string]*Property, error) {
if strings.HasPrefix(logicalName, "Fn::ForEach::") {
return expandForEach(prop, nil)
}
return nil, nil
}
func expandForEach(prop *Property, parentCtx *LoopContext) (map[string]*Property, error) {
args := prop.AsList()
if len(args) != 3 {
return nil, fmt.Errorf("invalid Fn::ForEach: expected 3 arguments, got %d", len(args))
}
identifier := args[0].AsString()
coll := args[1].AsList()
templ := args[2].AsMap()
result := make(map[string]*Property)
for _, el := range coll {
loopCtx := parentCtx.Child(identifier, el)
for tmplKey, templValue := range templ {
cp := templValue.clone()
// handle nested loop
if strings.HasPrefix(tmplKey, ForEachPrefix) {
nestedResult, err := expandForEach(cp, loopCtx)
if err != nil {
return nil, err
}
maps.Copy(result, nestedResult)
continue
}
logicalID := resolveLoopPlaceholders(tmplKey, loopCtx)
cp.setLogicalResource(logicalID)
if err := expandProperties(cp, loopCtx); err != nil {
return nil, err
}
result[logicalID] = cp
}
}
return result, nil
}
var placeholderRe = regexp.MustCompile(`[$&]\{([^}]+)\}`)
func resolveLoopPlaceholders(v string, loopCtx *LoopContext) string {
return placeholderRe.ReplaceAllStringFunc(v, func(s string) string {
id := s[2 : len(s)-1]
val, found := loopCtx.Resolve(id)
if found {
return val.AsString()
}
return s
})
}
func expandProperties(prop *Property, parentCtx *LoopContext) error {
prop.loopCtx = parentCtx
switch v := prop.Value.(type) {
case string:
prop.Value = resolveLoopPlaceholders(v, parentCtx)
case map[string]*Property:
newProps := make(map[string]*Property)
for k, el := range v {
if strings.HasPrefix(k, ForEachPrefix) {
expanded, err := expandForEach(el, parentCtx)
if err != nil {
return err
}
maps.Copy(newProps, expanded)
} else {
if err := expandProperties(el, parentCtx); err != nil {
return err
}
newProps[k] = el
}
}
prop.Value = newProps
case []*Property:
for _, el := range v {
if err := expandProperties(el, parentCtx); err != nil {
return err
}
}
}
return nil
}
type LoopContext struct {
Identifier string
Value *Property
Parent *LoopContext
}
func (c *LoopContext) Child(identifier string, value *Property) *LoopContext {
return &LoopContext{
Identifier: identifier,
Value: value,
Parent: c,
}
}
func (c *LoopContext) Resolve(name string) (*Property, bool) {
if c.Identifier == name {
return c.Value, true
}
if c.Parent != nil {
return c.Parent.Resolve(name)
}
return nil, false
}

View File

@@ -4,7 +4,7 @@ import (
"github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation/cftypes"
)
func ResolveReference(property *Property) (resolved *Property, success bool) {
func ResolveReference(property *Property) (*Property, bool) {
if !property.isFunction() {
return property, true
}
@@ -19,16 +19,18 @@ func ResolveReference(property *Property) (resolved *Property, success bool) {
return property.deriveResolved(pseudo.t, pseudo.val), true
}
if property.loopCtx != nil {
v, found := property.loopCtx.Resolve(refValue)
if found {
return property.deriveResolved(v.Type, v.RawValue()), true
}
}
if property.ctx == nil {
return property, false
}
var param *Parameter
for k := range property.ctx.Parameters {
if k != refValue {
continue
}
param = property.ctx.Parameters[k]
if param, exists := property.ctx.Parameters[refValue]; exists {
resolvedType := param.Type()
switch param.Default().(type) {
@@ -40,16 +42,14 @@ func ResolveReference(property *Property) (resolved *Property, success bool) {
resolvedType = cftypes.Int
}
resolved = property.deriveResolved(resolvedType, param.Default())
resolved := property.deriveResolved(resolvedType, param.Default())
return resolved, true
}
for k := range property.ctx.Resources {
if k == refValue {
res := property.ctx.Resources[k]
resolved = property.deriveResolved(cftypes.String, res.ID())
break
}
if res, exists := property.ctx.Resources[refValue]; exists {
resolved := property.deriveResolved(cftypes.String, res.ID())
return resolved, true
}
return resolved, true
return nil, false
}

View File

@@ -163,6 +163,10 @@ func (p *Parser) ParseFile(ctx context.Context, fsys fs.FS, filePath string) (fc
r.configureResource(name, fsys, filePath, fctx)
}
if err := fctx.expandTransforms(); err != nil {
return nil, err
}
return fctx, nil
}

View File

@@ -482,3 +482,158 @@ Resources:
assert.True(t, res.GetProperty("PublicAccessBlockConfiguration.BlockPublicAcls").IsNil())
}
func Test_ExpandForEachYAML(t *testing.T) {
source := `AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::LanguageExtensions
Parameters:
TopicNamesParam:
Type: CommaDelimitedList
Default: Success,Failure
Mappings:
Success:
Properties:
DisplayName: success
FifoTopic: "true"
Failure:
Properties:
DisplayName: failure
FifoTopic: "false"
Resources:
'Fn::ForEach::Topics':
- TopicName
- !Split [",", !Ref TopicNamesParam]
- 'SnsTopic${TopicName}':
Type: 'AWS::SNS::Topic'
Properties:
TopicName: !Sub '${TopicName}.fifo'
'Fn::ForEach::Properties':
- PropertyName
- [DisplayName, FifoTopic]
- '${PropertyName}':
'Fn::FindInMap':
- Ref: 'TopicName'
- Properties
- Ref: 'PropertyName'
'Fn::ForEach::Subscriptions':
- SubName
- ['Alpha', 'Beta']
- 'SnsSubscription${TopicName}${SubName}':
Type: 'AWS::SNS::Subscription'
Properties:
TopicArn: !Ref 'SnsTopic${TopicName}'
Protocol: email
Endpoint: !Sub '${SubName}@example.com'
`
files, err := parseFile(t, source, "cf.yaml")
require.NoError(t, err)
file := files[0]
assert.Len(t, file.Resources, 6)
tests := []struct {
LogicalID string
Props map[string]any
}{
// SnsTopic
{
"SnsTopicSuccess",
map[string]any{
"TopicName": "Success.fifo",
"DisplayName": "success",
"FifoTopic": "true",
},
},
{
"SnsTopicFailure",
map[string]any{
"TopicName": "Failure.fifo",
"DisplayName": "failure",
"FifoTopic": "false",
},
},
// SnsSubscription
{
"SnsSubscriptionSuccessAlpha",
map[string]any{
"TopicArn": "SnsTopicSuccess",
"Protocol": "email",
"Endpoint": "Alpha@example.com",
},
},
{
"SnsSubscriptionSuccessBeta",
map[string]any{
"TopicArn": "SnsTopicSuccess",
"Protocol": "email",
"Endpoint": "Beta@example.com",
},
},
{
"SnsSubscriptionFailureAlpha",
map[string]any{
"TopicArn": "SnsTopicFailure",
"Protocol": "email",
"Endpoint": "Alpha@example.com",
},
},
{
"SnsSubscriptionFailureBeta",
map[string]any{
"TopicArn": "SnsTopicFailure",
"Protocol": "email",
"Endpoint": "Beta@example.com",
},
},
}
for _, tt := range tests {
t.Run(tt.LogicalID, func(t *testing.T) {
res, ok := file.Resources[tt.LogicalID]
require.True(t, ok)
for propName, expected := range tt.Props {
prop := res.GetProperty(propName)
assert.Equal(t, expected, prop.RawValue())
}
})
}
}
func Test_ExpandForEachJSON(t *testing.T) {
source := `{
"AWSTemplateFormatVersion": "2010-09-09",
"Transform": "AWS::LanguageExtensions",
"Resources": {
"Fn::ForEach::Buckets": [
"Suffix",
["A", "B"],
{
"S3Bucket${Suffix}": {
"Type": "AWS::S3::Bucket",
"Properties": {
"BucketName": { "Fn::Sub": "bucket-${Suffix}" }
}
}
}
]
}
}`
files, err := parseFile(t, source, "cf.json")
require.NoError(t, err)
require.Len(t, files, 1)
file := files[0]
require.Len(t, file.Resources, 2)
b1, ok := file.Resources["S3BucketA"]
require.True(t, ok)
assert.Equal(t, "AWS::S3::Bucket", b1.Type())
assert.Equal(t, "bucket-A", b1.GetProperty("BucketName").AsString())
b2, ok := file.Resources["S3BucketB"]
require.True(t, ok)
assert.Equal(t, "AWS::S3::Bucket", b2.Type())
assert.Equal(t, "bucket-B", b2.GetProperty("BucketName").AsString())
}

View File

@@ -33,10 +33,8 @@ type Property struct {
parentRange iacTypes.Range
logicalId string
unresolved bool
}
func (p *Property) Comment() string {
return p.comment
loopCtx *LoopContext
}
func (p *Property) setName(name string) {
@@ -52,22 +50,17 @@ func (p *Property) setName(name string) {
}
func (p *Property) setContext(ctx *FileContext) {
p.ctx = ctx
p.walk(func(prop *Property) bool {
prop.ctx = ctx
return true
})
}
if p.IsMap() {
for _, subProp := range p.AsMap() {
if subProp == nil {
continue
}
subProp.setContext(ctx)
}
}
if p.IsList() {
for _, subProp := range p.AsList() {
subProp.setContext(ctx)
}
}
func (p *Property) setLogicalResource(id string) {
p.walk(func(prop *Property) bool {
prop.logicalId = id
return !prop.isFunction()
})
}
func (p *Property) setFileAndParentRange(target fs.FS, filepath string, parentRange iacTypes.Range) {
@@ -80,18 +73,55 @@ func (p *Property) setFileAndParentRange(target fs.FS, filepath string, parentRa
if subProp == nil {
continue
}
subProp.setFileAndParentRange(target, filepath, parentRange)
subProp.setFileAndParentRange(target, filepath, p.rng)
}
case cftypes.List:
for _, subProp := range p.AsList() {
if subProp == nil {
continue
}
subProp.setFileAndParentRange(target, filepath, parentRange)
subProp.setFileAndParentRange(target, filepath, p.rng)
}
}
}
func (p *Property) clone() *Property {
if p == nil {
return nil
}
clone := &Property{
Location: p.Location,
ctx: p.ctx,
Type: p.Type,
name: p.name,
comment: p.comment,
rng: p.rng,
parentRange: p.parentRange,
logicalId: p.logicalId,
unresolved: p.unresolved,
}
switch v := p.Value.(type) {
case map[string]*Property:
m := make(map[string]*Property, len(v))
for k, el := range v {
m[k] = el.clone()
}
clone.Value = m
case []*Property:
slice := make([]*Property, len(v))
for i, el := range v {
slice[i] = el.clone()
}
clone.Value = slice
default:
clone.Value = v
}
return clone
}
func (p *Property) UnmarshalYAML(node *yaml.Node) error {
p.StartLine = node.Line
p.EndLine = calculateEndLine(node)
@@ -301,17 +331,10 @@ func (p *Property) GetProperty(path string) *Property {
}
func (p *Property) deriveResolved(propType cftypes.CfType, propValue any) *Property {
return &Property{
Location: p.Location,
Value: propValue,
Type: propType,
ctx: p.ctx,
name: p.name,
comment: p.comment,
rng: p.rng,
parentRange: p.parentRange,
logicalId: p.logicalId,
}
clone := p.clone()
clone.Type = propType
clone.Value = propValue
return clone
}
func (p *Property) ParentRange() iacTypes.Range {
@@ -363,29 +386,6 @@ func (p *Property) String() string {
return r
}
func (p *Property) setLogicalResource(id string) {
p.logicalId = id
if p.isFunction() {
return
}
if p.IsMap() {
for _, subProp := range p.AsMap() {
if subProp == nil {
continue
}
subProp.setLogicalResource(id)
}
}
if p.IsList() {
for _, subProp := range p.AsList() {
subProp.setLogicalResource(id)
}
}
}
func (p *Property) GetJsonBytes(squashList ...bool) []byte {
if p.IsNil() {
return []byte{}
@@ -458,3 +458,28 @@ func (p *Property) inferType() {
}
p.Type = typ
}
func (p *Property) walk(fn func(*Property) bool) {
if fn == nil {
return
}
if !fn(p) {
return
}
switch v := p.Value.(type) {
case map[string]*Property:
for _, child := range v {
if child != nil {
child.walk(fn)
}
}
case []*Property:
for _, child := range v {
if child != nil {
child.walk(fn)
}
}
}
}

View File

@@ -3,6 +3,7 @@ package parser
import (
"encoding/json/jsontext"
"encoding/json/v2"
"fmt"
"io/fs"
"strings"
@@ -20,6 +21,8 @@ type Resource struct {
rng iacTypes.Range
id string
comment string
raw *Property
}
func (r *Resource) configureResource(id string, target fs.FS, filepath string, ctx *FileContext) {
@@ -46,13 +49,39 @@ func (r *Resource) setFile(target fs.FS, filepath string) {
func (r *Resource) setContext(ctx *FileContext) {
r.ctx = ctx
for _, p := range r.properties {
p.setLogicalResource(r.id)
p.setContext(ctx)
if r.raw != nil {
r.raw.setContext(ctx)
} else {
for _, p := range r.properties {
p.setLogicalResource(r.id)
p.setContext(ctx)
}
}
}
func (r *Resource) clone() *Resource {
clone := &Resource{
typ: r.typ,
ctx: r.ctx,
rng: r.rng,
id: r.id,
comment: r.comment,
}
if r.properties != nil {
clone.properties = make(map[string]*Property, len(r.properties))
for k, p := range r.properties {
clone.properties[k] = p.clone()
}
}
if r.raw != nil {
clone.raw = r.raw.clone()
}
return clone
}
type resourceInner struct {
Type string `json:"Type" yaml:"Type"`
Properties map[string]*Property `json:"Properties" yaml:"Properties"`
@@ -63,22 +92,43 @@ func (r *Resource) UnmarshalYAML(node *yaml.Node) error {
r.EndLine = calculateEndLine(node)
r.comment = node.LineComment
var i resourceInner
if err := node.Decode(&i); err != nil {
return err
switch node.Kind {
case yaml.MappingNode:
var i resourceInner
if err := node.Decode(&i); err != nil {
return err
}
r.typ = i.Type
r.properties = i.Properties
return nil
case yaml.SequenceNode:
var raw Property
if err := node.Decode(&raw); err != nil {
return err
}
r.raw = &raw
return nil
default:
return fmt.Errorf("unsupported YAML node kind: %v", node.Kind)
}
r.typ = i.Type
r.properties = i.Properties
return nil
}
func (r *Resource) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
var i resourceInner
if err := json.UnmarshalDecode(dec, &i); err != nil {
return err
switch dec.PeekKind() {
case '{':
var i resourceInner
if err := json.UnmarshalDecode(dec, &i); err != nil {
return err
}
r.typ = i.Type
r.properties = i.Properties
case '[':
var raw Property
if err := json.UnmarshalDecode(dec, &raw); err != nil {
return err
}
r.raw = &raw
}
r.typ = i.Type
r.properties = i.Properties
return nil
}