mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 15:50:15 -08:00
Compare commits
11 Commits
dependabot
...
718ec29ec6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
718ec29ec6 | ||
|
|
d528250a1d | ||
|
|
f50b96a815 | ||
|
|
d65b504cb2 | ||
|
|
1a901e5c75 | ||
|
|
effc1c0d4d | ||
|
|
335cc993fa | ||
|
|
879e4fca12 | ||
|
|
18ecf75176 | ||
|
|
56b59e8abb | ||
|
|
f58826fb2a |
1
.github/workflows/apidiff.yaml
vendored
1
.github/workflows/apidiff.yaml
vendored
@@ -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.
|
||||
|
||||
1
.github/workflows/auto-update-labels.yaml
vendored
1
.github/workflows/auto-update-labels.yaml
vendored
@@ -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
|
||||
|
||||
3
.github/workflows/cache-test-assets.yaml
vendored
3
.github/workflows/cache-test-assets.yaml
vendored
@@ -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
|
||||
|
||||
1
.github/workflows/release.yaml
vendored
1
.github/workflows/release.yaml
vendored
@@ -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
|
||||
|
||||
1
.github/workflows/reusable-release.yaml
vendored
1
.github/workflows/reusable-release.yaml
vendored
@@ -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
|
||||
|
||||
2
.github/workflows/spdx-cron.yaml
vendored
2
.github/workflows/spdx-cron.yaml
vendored
@@ -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
|
||||
|
||||
7
.github/workflows/test.yaml
vendored
7
.github/workflows/test.yaml
vendored
@@ -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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 |
|
||||
|
||||
@@ -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
30
go.mod
@@ -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
64
go.sum
@@ -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=
|
||||
|
||||
@@ -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` |
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
8
pkg/fanal/analyzer/language/php/composer/testdata/composer/with-dev/composer.json
vendored
Normal file
8
pkg/fanal/analyzer/language/php/composer/testdata/composer/with-dev/composer.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"require": {
|
||||
"psr/log": "^1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"pear/log": "^1.13"
|
||||
}
|
||||
}
|
||||
190
pkg/fanal/analyzer/language/php/composer/testdata/composer/with-dev/composer.lock
generated
vendored
Normal file
190
pkg/fanal/analyzer/language/php/composer/testdata/composer/with-dev/composer.lock
generated
vendored
Normal 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"
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
17
pkg/fanal/analyzer/pkg/dpkg/testdata/tar-status
vendored
Normal file
17
pkg/fanal/analyzer/pkg/dpkg/testdata/tar-status
vendored
Normal 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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
},
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user