From 45b3f344042bcd90ca63ab696b69bff0e9ab4e36 Mon Sep 17 00:00:00 2001 From: yusuke-koyoshi <92022336+yusuke-koyoshi@users.noreply.github.com> Date: Wed, 31 Jul 2024 16:30:20 +0900 Subject: [PATCH 001/183] feat(vm): Support direct filesystem (#7058) Signed-off-by: yusuke.koyoshi --- go.mod | 4 ++-- go.sum | 8 ++++---- pkg/fanal/walker/vm.go | 10 +++++++++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 58453c942f7d..4fe6146acb4d 100644 --- a/go.mod +++ b/go.mod @@ -76,12 +76,12 @@ require ( github.com/liamg/jfather v0.0.7 github.com/liamg/memoryfs v1.6.0 github.com/magefile/mage v1.15.0 - github.com/masahiro331/go-disk v0.0.0-20220919035250-c8da316f91ac + github.com/masahiro331/go-disk v0.0.0-20240625071113-56c933208fee github.com/masahiro331/go-ebs-file v0.0.0-20240112135404-d5fbb1d46323 github.com/masahiro331/go-ext4-filesystem v0.0.0-20231208112839-4339555a0cd4 github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 github.com/masahiro331/go-vmdk-parser v0.0.0-20221225061455-612096e4bbbd - github.com/masahiro331/go-xfs-filesystem v0.0.0-20230608043311-a335f4599b70 + github.com/masahiro331/go-xfs-filesystem v0.0.0-20231205045356-1b22259a6c44 github.com/mattn/go-shellwords v1.0.12 github.com/microsoft/go-rustaudit v0.0.0-20220808201409-204dfee52032 github.com/mitchellh/go-homedir v1.1.0 diff --git a/go.sum b/go.sum index c5c4bc01e657..2db8a06b1722 100644 --- a/go.sum +++ b/go.sum @@ -1022,8 +1022,8 @@ github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI= github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= -github.com/masahiro331/go-disk v0.0.0-20220919035250-c8da316f91ac h1:QyRucnGOLHJag1eB9CtuZwZk+/LpvTSYr5mnFLLFlgA= -github.com/masahiro331/go-disk v0.0.0-20220919035250-c8da316f91ac/go.mod h1:J7Vb0sf0JzOhT0uHTeCqO6dqP/ELVcQvQ6yQ/56ZRGw= +github.com/masahiro331/go-disk v0.0.0-20240625071113-56c933208fee h1:cgm8mE25x5XXX2oyvJDlyJ72K+rDu/4ZCYce2worNb8= +github.com/masahiro331/go-disk v0.0.0-20240625071113-56c933208fee/go.mod h1:rojbW5tVhH1cuVYFKZS+QX+VGXK45JVsRO+jW92kkKM= github.com/masahiro331/go-ebs-file v0.0.0-20240112135404-d5fbb1d46323 h1:uQubA711SeYStvStohMLrdvRTTohdPHrEPFzerLcY9I= github.com/masahiro331/go-ebs-file v0.0.0-20240112135404-d5fbb1d46323/go.mod h1:OdtzwqTtu49Gh5RFkNEU1SbcihIuVTtUipwHflqxckE= github.com/masahiro331/go-ext4-filesystem v0.0.0-20231208112839-4339555a0cd4 h1:uHO44vOunB0oEtk+r8ifBbFOD0mr6+fmoyFNCgLE66k= @@ -1032,8 +1032,8 @@ github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 h1:AevU github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08/go.mod h1:JOkBRrE1HvgTyjk6diFtNGgr8XJMtIfiBzkL5krqzVk= github.com/masahiro331/go-vmdk-parser v0.0.0-20221225061455-612096e4bbbd h1:Y30EzvuoVp97b0unb/GOFXzBUKRXZXUN2e0wYmvC+ic= github.com/masahiro331/go-vmdk-parser v0.0.0-20221225061455-612096e4bbbd/go.mod h1:5f7mCJGW9cJb8SDn3z8qodGxpMCOo8d/2nls/tiwRrw= -github.com/masahiro331/go-xfs-filesystem v0.0.0-20230608043311-a335f4599b70 h1:X6W6raTo07X0q4pvSI/68Pj/Ic4iIU2CfQU65OH0Zhc= -github.com/masahiro331/go-xfs-filesystem v0.0.0-20230608043311-a335f4599b70/go.mod h1:QKBZqdn6teT0LK3QhAf3K6xakItd1LonOShOEC44idQ= +github.com/masahiro331/go-xfs-filesystem v0.0.0-20231205045356-1b22259a6c44 h1:VmSjn0UCyfXUNdePDr7uM/uZTnGSp+mKD5+cYkEoLx4= +github.com/masahiro331/go-xfs-filesystem v0.0.0-20231205045356-1b22259a6c44/go.mod h1:QKBZqdn6teT0LK3QhAf3K6xakItd1LonOShOEC44idQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= diff --git a/pkg/fanal/walker/vm.go b/pkg/fanal/walker/vm.go index 5d7336f1623c..0bc3e87ac86d 100644 --- a/pkg/fanal/walker/vm.go +++ b/pkg/fanal/walker/vm.go @@ -9,9 +9,12 @@ import ( "strings" "github.com/masahiro331/go-disk" + diskFs "github.com/masahiro331/go-disk/fs" "github.com/masahiro331/go-disk/gpt" "github.com/masahiro331/go-disk/mbr" "github.com/masahiro331/go-disk/types" + "github.com/masahiro331/go-ext4-filesystem/ext4" + "github.com/masahiro331/go-xfs-filesystem/xfs" "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/fanal/vm/filesystem" @@ -29,6 +32,11 @@ var requiredDiskName = []string{ "3", // Common image name } +var checkFsFuncs = []diskFs.CheckFsFunc{ + ext4.Check, + xfs.Check, +} + func AppendPermitDiskName(s ...string) { requiredDiskName = append(requiredDiskName, s...) } @@ -53,7 +61,7 @@ func (w *VM) Walk(vreader *io.SectionReader, root string, opt Option, fn WalkFun // This function will be called on each file. w.analyzeFn = fn - driver, err := disk.NewDriver(vreader) + driver, err := disk.NewDriver(vreader, checkFsFuncs...) if err != nil { return xerrors.Errorf("failed to new disk driver: %w", err) } From 70245721372720027b7089bd61c693df48add865 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Wed, 31 Jul 2024 12:07:28 +0400 Subject: [PATCH 002/183] feat(cli)!: delete deprecated SBOM flags (#7266) Signed-off-by: knqyf263 --- pkg/commands/app.go | 1 - pkg/flag/options.go | 12 ----------- pkg/flag/sbom_flags.go | 49 ------------------------------------------ 3 files changed, 62 deletions(-) delete mode 100644 pkg/flag/sbom_flags.go diff --git a/pkg/commands/app.go b/pkg/commands/app.go index a3bd7b78e6f1..a3fb6df353d9 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -1146,7 +1146,6 @@ func NewSBOMCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { RemoteFlagGroup: flag.NewClientFlags(), // for client/server mode ReportFlagGroup: reportFlagGroup, ScanFlagGroup: scanFlagGroup, - SBOMFlagGroup: flag.NewSBOMFlagGroup(), VulnerabilityFlagGroup: flag.NewVulnerabilityFlagGroup(), LicenseFlagGroup: licenseFlagGroup, } diff --git a/pkg/flag/options.go b/pkg/flag/options.go index 3f48b75ac9b4..e5c46c81c64f 100644 --- a/pkg/flag/options.go +++ b/pkg/flag/options.go @@ -326,7 +326,6 @@ type Flags struct { RegoFlagGroup *RegoFlagGroup RepoFlagGroup *RepoFlagGroup ReportFlagGroup *ReportFlagGroup - SBOMFlagGroup *SBOMFlagGroup ScanFlagGroup *ScanFlagGroup SecretFlagGroup *SecretFlagGroup VulnerabilityFlagGroup *VulnerabilityFlagGroup @@ -350,7 +349,6 @@ type Options struct { RemoteOptions RepoOptions ReportOptions - SBOMOptions ScanOptions SecretOptions VulnerabilityOptions @@ -549,9 +547,6 @@ func (f *Flags) groups() []FlagGroup { if f.ImageFlagGroup != nil { groups = append(groups, f.ImageFlagGroup) } - if f.SBOMFlagGroup != nil { - groups = append(groups, f.SBOMFlagGroup) - } if f.VulnerabilityFlagGroup != nil { groups = append(groups, f.VulnerabilityFlagGroup) } @@ -760,13 +755,6 @@ func (f *Flags) ToOptions(args []string) (Options, error) { } } - if f.SBOMFlagGroup != nil { - opts.SBOMOptions, err = f.SBOMFlagGroup.ToOptions() - if err != nil { - return Options{}, xerrors.Errorf("sbom flag error: %w", err) - } - } - if f.ScanFlagGroup != nil { opts.ScanOptions, err = f.ScanFlagGroup.ToOptions(args) if err != nil { diff --git a/pkg/flag/sbom_flags.go b/pkg/flag/sbom_flags.go deleted file mode 100644 index 9af8414ed546..000000000000 --- a/pkg/flag/sbom_flags.go +++ /dev/null @@ -1,49 +0,0 @@ -package flag - -var ( - ArtifactTypeFlag = Flag[string]{ - Name: "artifact-type", - ConfigName: "sbom.artifact-type", - Usage: "deprecated", - Removed: `Use 'trivy image' or other subcommands. See also https://github.com/aquasecurity/trivy/discussions/2407`, - } - SBOMFormatFlag = Flag[string]{ - Name: "sbom-format", - ConfigName: "sbom.format", - Usage: "deprecated", - Removed: `Use 'trivy image' or other subcommands. See also https://github.com/aquasecurity/trivy/discussions/2407`, - } -) - -type SBOMFlagGroup struct { - ArtifactType *Flag[string] // deprecated - SBOMFormat *Flag[string] // deprecated -} - -type SBOMOptions struct{} - -func NewSBOMFlagGroup() *SBOMFlagGroup { - return &SBOMFlagGroup{ - ArtifactType: ArtifactTypeFlag.Clone(), - SBOMFormat: SBOMFormatFlag.Clone(), - } -} - -func (f *SBOMFlagGroup) Name() string { - return "SBOM" -} - -func (f *SBOMFlagGroup) Flags() []Flagger { - return []Flagger{ - f.ArtifactType, - f.SBOMFormat, - } -} - -func (f *SBOMFlagGroup) ToOptions() (SBOMOptions, error) { - if err := parseFlags(f); err != nil { - return SBOMOptions{}, err - } - - return SBOMOptions{}, nil -} From 35c60f030fa48de8d8e57958e5ba379814126831 Mon Sep 17 00:00:00 2001 From: Aruneko Date: Wed, 31 Jul 2024 19:49:47 +0900 Subject: [PATCH 003/183] feat(vm): support the Ext2/Ext3 filesystems (#6983) --- docs/docs/target/vm.md | 2 +- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/docs/target/vm.md b/docs/docs/target/vm.md index b0dc23e9c507..e2c2cac74467 100644 --- a/docs/docs/target/vm.md +++ b/docs/docs/target/vm.md @@ -230,7 +230,7 @@ Reference: [VMware Virtual Disk Format 1.1.pdf][vmdk] |-------------------|:-------:| | XFS | ✔ | | EXT4 | ✔ | -| EXT2/3 | | +| EXT2/3 | ✔ | | ZFS | | diff --git a/go.mod b/go.mod index 4fe6146acb4d..70277514b22a 100644 --- a/go.mod +++ b/go.mod @@ -78,7 +78,7 @@ require ( github.com/magefile/mage v1.15.0 github.com/masahiro331/go-disk v0.0.0-20240625071113-56c933208fee github.com/masahiro331/go-ebs-file v0.0.0-20240112135404-d5fbb1d46323 - github.com/masahiro331/go-ext4-filesystem v0.0.0-20231208112839-4339555a0cd4 + github.com/masahiro331/go-ext4-filesystem v0.0.0-20240620024024-ca14e6327bbd github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 github.com/masahiro331/go-vmdk-parser v0.0.0-20221225061455-612096e4bbbd github.com/masahiro331/go-xfs-filesystem v0.0.0-20231205045356-1b22259a6c44 diff --git a/go.sum b/go.sum index 2db8a06b1722..a5dde364799f 100644 --- a/go.sum +++ b/go.sum @@ -1026,8 +1026,8 @@ github.com/masahiro331/go-disk v0.0.0-20240625071113-56c933208fee h1:cgm8mE25x5X github.com/masahiro331/go-disk v0.0.0-20240625071113-56c933208fee/go.mod h1:rojbW5tVhH1cuVYFKZS+QX+VGXK45JVsRO+jW92kkKM= github.com/masahiro331/go-ebs-file v0.0.0-20240112135404-d5fbb1d46323 h1:uQubA711SeYStvStohMLrdvRTTohdPHrEPFzerLcY9I= github.com/masahiro331/go-ebs-file v0.0.0-20240112135404-d5fbb1d46323/go.mod h1:OdtzwqTtu49Gh5RFkNEU1SbcihIuVTtUipwHflqxckE= -github.com/masahiro331/go-ext4-filesystem v0.0.0-20231208112839-4339555a0cd4 h1:uHO44vOunB0oEtk+r8ifBbFOD0mr6+fmoyFNCgLE66k= -github.com/masahiro331/go-ext4-filesystem v0.0.0-20231208112839-4339555a0cd4/go.mod h1:3XMMY1M486mWGTD13WPItg6FsgflQR72ZMAkd+gsyoQ= +github.com/masahiro331/go-ext4-filesystem v0.0.0-20240620024024-ca14e6327bbd h1:JEIW94K3spsvBI5Xb9PGhKSIza9/jxO1lF30tPCAJlA= +github.com/masahiro331/go-ext4-filesystem v0.0.0-20240620024024-ca14e6327bbd/go.mod h1:3XMMY1M486mWGTD13WPItg6FsgflQR72ZMAkd+gsyoQ= github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 h1:AevUBW4cc99rAF8q8vmddIP8qd/0J5s/UyltGbp66dg= github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08/go.mod h1:JOkBRrE1HvgTyjk6diFtNGgr8XJMtIfiBzkL5krqzVk= github.com/masahiro331/go-vmdk-parser v0.0.0-20221225061455-612096e4bbbd h1:Y30EzvuoVp97b0unb/GOFXzBUKRXZXUN2e0wYmvC+ic= From b3ee6dac269bd7847674f3ce985a5ff7f8f0ba38 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Wed, 31 Jul 2024 15:16:26 +0400 Subject: [PATCH 004/183] fix(plugin): do not call GitHub content API for releases and tags (#7274) Signed-off-by: knqyf263 --- pkg/downloader/download.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkg/downloader/download.go b/pkg/downloader/download.go index 63b130a667fd..96fd3ce49008 100644 --- a/pkg/downloader/download.go +++ b/pkg/downloader/download.go @@ -154,7 +154,8 @@ func (t *CustomTransport) RoundTrip(req *http.Request) (*http.Response, error) { func NewGitHubTransport(u *url.URL, insecure bool, token string) http.RoundTripper { client := newGitHubClient(insecure, token) ss := strings.SplitN(u.Path, "/", 4) - if len(ss) < 4 || strings.HasPrefix(ss[3], "archive/") { + if len(ss) < 4 || strings.HasPrefix(ss[3], "archive/") || strings.HasPrefix(ss[3], "releases/") || + strings.HasPrefix(ss[3], "tags/") { // Use the default transport from go-github for authentication return client.Client().Transport } From 49d5270163e305f88fedcf50412973736e69dc69 Mon Sep 17 00:00:00 2001 From: Colm O hEigeartaigh Date: Wed, 31 Jul 2024 13:07:33 +0100 Subject: [PATCH 005/183] fix(java): Return error when trying to find a remote pom to avoid segfault (#7275) Co-authored-by: DmitriyLewen --- pkg/dependency/parser/java/pom/parse.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/pkg/dependency/parser/java/pom/parse.go b/pkg/dependency/parser/java/pom/parse.go index 550c5761c6ee..cbd7bf47db17 100644 --- a/pkg/dependency/parser/java/pom/parse.go +++ b/pkg/dependency/parser/java/pom/parse.go @@ -13,7 +13,7 @@ import ( "sort" "strings" - multierror "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-multierror" "github.com/samber/lo" "golang.org/x/net/html/charset" "golang.org/x/xerrors" @@ -680,18 +680,15 @@ func (p *Parser) fetchPOMFromRemoteRepositories(paths []string, snapshot bool) ( func (p *Parser) remoteRepoRequest(repo string, paths []string) (*http.Request, error) { repoURL, err := url.Parse(repo) if err != nil { - p.logger.Error("URL parse error", log.String("repo", repo)) - return nil, nil + return nil, xerrors.Errorf("unable to parse URL: %w", err) } paths = append([]string{repoURL.Path}, paths...) repoURL.Path = path.Join(paths...) - logger := p.logger.With(log.String("host", repoURL.Host), log.String("path", repoURL.Path)) req, err := http.NewRequest("GET", repoURL.String(), http.NoBody) if err != nil { - logger.Debug("HTTP request failed") - return nil, nil + return nil, xerrors.Errorf("unable to create HTTP request: %w", err) } if repoURL.User != nil { password, _ := repoURL.User.Password() @@ -709,7 +706,8 @@ func (p *Parser) fetchPomFileNameFromMavenMetadata(repo string, paths []string) req, err := p.remoteRepoRequest(repo, mavenMetadataPaths) if err != nil { - return "", xerrors.Errorf("unable to create request for maven-metadata.xml file") + p.logger.Debug("Unable to create request", log.String("repo", repo), log.Err(err)) + return "", nil } client := &http.Client{} @@ -739,7 +737,8 @@ func (p *Parser) fetchPomFileNameFromMavenMetadata(repo string, paths []string) func (p *Parser) fetchPOMFromRemoteRepository(repo string, paths []string) (*pom, error) { req, err := p.remoteRepoRequest(repo, paths) if err != nil { - return nil, xerrors.Errorf("unable to create request for pom file") + p.logger.Debug("Unable to create request", log.String("repo", repo), log.Err(err)) + return nil, nil } client := &http.Client{} From 2a0e529c36057b572119815af59c28e4790034ca Mon Sep 17 00:00:00 2001 From: afdesk Date: Wed, 31 Jul 2024 18:43:26 +0600 Subject: [PATCH 006/183] fix(flag): incorrect behavior for deprected flag `--clear-cache` (#7281) --- pkg/flag/cache_flags.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/flag/cache_flags.go b/pkg/flag/cache_flags.go index 074953c2ea44..9cf8403a1e56 100644 --- a/pkg/flag/cache_flags.go +++ b/pkg/flag/cache_flags.go @@ -80,6 +80,7 @@ type CacheOptions struct { // NewCacheFlagGroup returns a default CacheFlagGroup func NewCacheFlagGroup() *CacheFlagGroup { return &CacheFlagGroup{ + ClearCache: ClearCacheFlag.Clone(), CacheBackend: CacheBackendFlag.Clone(), CacheTTL: CacheTTLFlag.Clone(), RedisTLS: RedisTLSFlag.Clone(), From e95152f796308c25aaaa6cf75b2e7a81b3ab4388 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 2 Aug 2024 13:34:57 +0700 Subject: [PATCH 007/183] refactor(misconf): remove file filtering from parsers (#7289) Signed-off-by: nikpivkin --- pkg/iac/detection/detect.go | 11 +++- pkg/iac/detection/detect_test.go | 64 +++++++++++++++++++ pkg/iac/rego/scanner.go | 4 -- pkg/iac/scanners/azure/arm/parser/parser.go | 44 ++----------- .../scanners/azure/arm/parser/parser_test.go | 5 -- pkg/iac/scanners/azure/arm/scanner.go | 12 ++-- .../scanners/cloudformation/parser/parser.go | 29 --------- pkg/iac/scanners/cloudformation/scanner.go | 15 ++--- pkg/iac/scanners/dockerfile/parser/parser.go | 19 +----- pkg/iac/scanners/dockerfile/scanner.go | 33 +++++----- pkg/iac/scanners/helm/parser/parser.go | 21 ------ pkg/iac/scanners/helm/scanner.go | 6 +- pkg/iac/scanners/json/parser/parser.go | 20 +----- pkg/iac/scanners/json/scanner.go | 29 ++++----- pkg/iac/scanners/kubernetes/parser/parser.go | 29 +-------- pkg/iac/scanners/kubernetes/scanner.go | 29 ++++----- pkg/iac/scanners/options/parser.go | 7 -- pkg/iac/scanners/options/scanner.go | 7 -- pkg/iac/scanners/terraform/parser/parser.go | 5 -- pkg/iac/scanners/terraform/scanner.go | 12 ++-- .../scanners/terraformplan/tfjson/scanner.go | 12 ++-- pkg/iac/scanners/toml/parser/parser.go | 19 +----- pkg/iac/scanners/toml/scanner.go | 29 ++++----- pkg/iac/scanners/yaml/parser/parser.go | 19 +----- pkg/iac/scanners/yaml/scanner.go | 29 ++++----- pkg/misconf/scanner.go | 1 - 26 files changed, 173 insertions(+), 337 deletions(-) diff --git a/pkg/iac/detection/detect.go b/pkg/iac/detection/detect.go index 596d8da1851d..787b82cb0b6a 100644 --- a/pkg/iac/detection/detect.go +++ b/pkg/iac/detection/detect.go @@ -135,15 +135,20 @@ func init() { } sniff := struct { - ContentType string `json:"contentType"` - Parameters map[string]any `json:"parameters"` - Resources []any `json:"resources"` + Schema string `json:"$schema"` + Parameters map[string]any `json:"parameters"` + Resources []any `json:"resources"` }{} metadata := types.NewUnmanagedMetadata() if err := armjson.UnmarshalFromReader(r, &sniff, &metadata); err != nil { return false } + // schema is required https://learn.microsoft.com/en-us/azure/azure-resource-manager/templates/syntax + if !strings.HasPrefix(sniff.Schema, "https://schema.management.azure.com/schemas") { + return false + } + return (sniff.Parameters != nil && len(sniff.Parameters) > 0) || (sniff.Resources != nil && len(sniff.Resources) > 0) } diff --git a/pkg/iac/detection/detect_test.go b/pkg/iac/detection/detect_test.go index 5a0d9f876b16..20998427d99d 100644 --- a/pkg/iac/detection/detect_test.go +++ b/pkg/iac/detection/detect_test.go @@ -355,6 +355,70 @@ rules: FileTypeYAML, }, }, + { + name: "Azure ARM template with resources", + path: "test.json", + r: strings.NewReader(` +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [ + { + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2021-09-01", + "name": "{provide-unique-name}", + "location": "eastus", + "sku": { + "name": "Standard_LRS" + }, + "kind": "StorageV2", + "properties": { + "supportsHttpsTrafficOnly": true + } + } + ] +} +`), + expected: []FileType{ + FileTypeJSON, + FileTypeAzureARM, + }, + }, + { + name: "Azure ARM template with parameters", + path: "test.json", + r: strings.NewReader(` +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "storageName": { + "type": "string", + "minLength": 3, + "maxLength": 24 + } + } +} +`), + expected: []FileType{ + FileTypeJSON, + FileTypeAzureARM, + }, + }, + { + name: "empty Azure ARM template", + path: "test.json", + r: strings.NewReader(` +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [] +} +`), + expected: []FileType{ + FileTypeJSON, + }, + }, } for _, test := range tests { diff --git a/pkg/iac/rego/scanner.go b/pkg/iac/rego/scanner.go index 2e0516761a02..f7293c46a0c5 100644 --- a/pkg/iac/rego/scanner.go +++ b/pkg/iac/rego/scanner.go @@ -138,10 +138,6 @@ func (s *Scanner) SetPolicyNamespaces(namespaces ...string) { } } -func (s *Scanner) SetSkipRequiredCheck(_ bool) { - // NOTE: Skip required option not applicable for rego. -} - func (s *Scanner) SetRegoErrorLimit(limit int) { s.regoErrorLimit = limit } diff --git a/pkg/iac/scanners/azure/arm/parser/parser.go b/pkg/iac/scanners/azure/arm/parser/parser.go index e5e171914b42..9fbf7b7019a8 100644 --- a/pkg/iac/scanners/azure/arm/parser/parser.go +++ b/pkg/iac/scanners/azure/arm/parser/parser.go @@ -5,8 +5,6 @@ import ( "fmt" "io" "io/fs" - "path/filepath" - "strings" "github.com/aquasecurity/trivy/pkg/iac/debug" azure2 "github.com/aquasecurity/trivy/pkg/iac/scanners/azure" @@ -17,19 +15,14 @@ import ( ) type Parser struct { - targetFS fs.FS - skipRequired bool - debug debug.Logger + targetFS fs.FS + debug debug.Logger } func (p *Parser) SetDebugWriter(writer io.Writer) { p.debug = debug.New(writer, "azure", "arm") } -func (p *Parser) SetSkipRequiredCheck(b bool) { - p.skipRequired = b -} - func New(targetFS fs.FS, opts ...options.ParserOption) *Parser { p := &Parser{ targetFS: targetFS, @@ -56,14 +49,13 @@ func (p *Parser) ParseFS(ctx context.Context, dir string) ([]azure2.Deployment, if entry.IsDir() { return nil } - if !p.Required(path) { - return nil - } + f, err := p.targetFS.Open(path) if err != nil { return err } defer f.Close() + deployment, err := p.parseFile(f, path) if err != nil { return err @@ -77,34 +69,6 @@ func (p *Parser) ParseFS(ctx context.Context, dir string) ([]azure2.Deployment, return deployments, nil } -func (p *Parser) Required(path string) bool { - if p.skipRequired { - return true - } - if !strings.HasSuffix(path, ".json") { - return false - } - data, err := fs.ReadFile(p.targetFS, path) - if err != nil { - return false - } - var template Template - root := types.NewMetadata( - types.NewRange(filepath.Base(path), 0, 0, "", p.targetFS), - "", - ) - if err := armjson.Unmarshal(data, &template, &root); err != nil { - p.debug.Log("Error scanning %s: %s", path, err) - return false - } - - if template.Schema.Kind != azure2.KindString { - return false - } - - return strings.HasPrefix(template.Schema.AsString(), "https://schema.management.azure.com") -} - func (p *Parser) parseFile(r io.Reader, filename string) (*azure2.Deployment, error) { var template Template data, err := io.ReadAll(r) diff --git a/pkg/iac/scanners/azure/arm/parser/parser_test.go b/pkg/iac/scanners/azure/arm/parser/parser_test.go index 3273c0dd6596..b16213d9bebd 100644 --- a/pkg/iac/scanners/azure/arm/parser/parser_test.go +++ b/pkg/iac/scanners/azure/arm/parser/parser_test.go @@ -36,11 +36,6 @@ func TestParser_Parse(t *testing.T) { want func() azure2.Deployment wantDeployment bool }{ - { - name: "invalid code", - input: `blah`, - wantDeployment: false, - }, { name: "basic param", input: `{ diff --git a/pkg/iac/scanners/azure/arm/scanner.go b/pkg/iac/scanners/azure/arm/scanner.go index b4bcfc539486..871b58df3f3d 100644 --- a/pkg/iac/scanners/azure/arm/scanner.go +++ b/pkg/iac/scanners/azure/arm/scanner.go @@ -24,12 +24,12 @@ import ( var _ scanners.FSScanner = (*Scanner)(nil) var _ options.ConfigurableScanner = (*Scanner)(nil) -type Scanner struct { // nolint: gocritic +type Scanner struct { + mu sync.Mutex scannerOptions []options.ScannerOption parserOptions []options.ParserOption debug debug.Logger frameworks []framework.Framework - skipRequired bool regoOnly bool loadEmbeddedPolicies bool loadEmbeddedLibraries bool @@ -37,7 +37,6 @@ type Scanner struct { // nolint: gocritic policyReaders []io.Reader regoScanner *rego.Scanner spec string - sync.Mutex } func (s *Scanner) SetIncludeDeprecatedChecks(b bool) {} @@ -73,9 +72,6 @@ func (s *Scanner) SetPolicyDirs(dirs ...string) { s.policyDirs = dirs } -func (s *Scanner) SetSkipRequiredCheck(skipRequired bool) { - s.skipRequired = skipRequired -} func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } @@ -106,8 +102,8 @@ func (s *Scanner) SetPolicyNamespaces(...string) {} func (s *Scanner) SetRegoErrorLimit(_ int) {} func (s *Scanner) initRegoScanner(srcFS fs.FS) error { - s.Lock() - defer s.Unlock() + s.mu.Lock() + defer s.mu.Unlock() if s.regoScanner != nil { return nil } diff --git a/pkg/iac/scanners/cloudformation/parser/parser.go b/pkg/iac/scanners/cloudformation/parser/parser.go index 5aa760e19882..d281b585035e 100644 --- a/pkg/iac/scanners/cloudformation/parser/parser.go +++ b/pkg/iac/scanners/cloudformation/parser/parser.go @@ -1,7 +1,6 @@ package parser import ( - "bytes" "context" "encoding/json" "errors" @@ -15,7 +14,6 @@ import ( "gopkg.in/yaml.v3" "github.com/aquasecurity/trivy/pkg/iac/debug" - "github.com/aquasecurity/trivy/pkg/iac/detection" "github.com/aquasecurity/trivy/pkg/iac/ignore" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) @@ -24,7 +22,6 @@ var _ options.ConfigurableParser = (*Parser)(nil) type Parser struct { debug debug.Logger - skipRequired bool parameterFiles []string parameters map[string]any overridedParameters Parameters @@ -59,10 +56,6 @@ func (p *Parser) SetDebugWriter(writer io.Writer) { p.debug = debug.New(writer, "cloudformation", "parser") } -func (p *Parser) SetSkipRequiredCheck(b bool) { - p.skipRequired = b -} - func New(opts ...options.ParserOption) *Parser { p := &Parser{} for _, option := range opts { @@ -86,11 +79,6 @@ func (p *Parser) ParseFS(ctx context.Context, fsys fs.FS, dir string) (FileConte return nil } - if !p.Required(fsys, path) { - p.debug.Log("not a CloudFormation file, skipping %s", path) - return nil - } - c, err := p.ParseFile(ctx, fsys, path) if err != nil { p.debug.Log("Error parsing file '%s': %s", path, err) @@ -104,23 +92,6 @@ func (p *Parser) ParseFS(ctx context.Context, fsys fs.FS, dir string) (FileConte return contexts, nil } -func (p *Parser) Required(fsys fs.FS, path string) bool { - if p.skipRequired { - return true - } - - f, err := fsys.Open(filepath.ToSlash(path)) - if err != nil { - return false - } - defer func() { _ = f.Close() }() - if data, err := io.ReadAll(f); err == nil { - return detection.IsType(path, bytes.NewReader(data), detection.FileTypeCloudFormation) - } - return false - -} - func (p *Parser) ParseFile(ctx context.Context, fsys fs.FS, path string) (fctx *FileContext, err error) { defer func() { if e := recover(); e != nil { diff --git a/pkg/iac/scanners/cloudformation/scanner.go b/pkg/iac/scanners/cloudformation/scanner.go index 1bbbe39f2117..20b96ce947fd 100644 --- a/pkg/iac/scanners/cloudformation/scanner.go +++ b/pkg/iac/scanners/cloudformation/scanner.go @@ -47,13 +47,13 @@ func WithConfigsFS(fsys fs.FS) options.ScannerOption { var _ scanners.FSScanner = (*Scanner)(nil) var _ options.ConfigurableScanner = (*Scanner)(nil) -type Scanner struct { // nolint: gocritic +type Scanner struct { + mu sync.Mutex debug debug.Logger policyDirs []string policyReaders []io.Reader parser *parser.Parser regoScanner *rego.Scanner - skipRequired bool regoOnly bool loadEmbeddedPolicies bool loadEmbeddedLibraries bool @@ -61,7 +61,6 @@ type Scanner struct { // nolint: gocritic parserOptions []options.ParserOption frameworks []framework.Framework spec string - sync.Mutex } func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} @@ -98,12 +97,9 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } -func (s *Scanner) SetSkipRequiredCheck(skip bool) { - s.skipRequired = skip -} - func (s *Scanner) SetDebugWriter(writer io.Writer) { s.debug = debug.New(writer, "cloudformation", "scanner") + s.parserOptions = append(s.parserOptions, options.ParserWithDebug(writer)) } func (s *Scanner) SetPolicyDirs(dirs ...string) { @@ -132,14 +128,13 @@ func New(opts ...options.ScannerOption) *Scanner { for _, opt := range opts { opt(s) } - s.addParserOptions(options.ParserWithSkipRequiredCheck(s.skipRequired)) s.parser = parser.New(s.parserOptions...) return s } func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { - s.Lock() - defer s.Unlock() + s.mu.Lock() + defer s.mu.Unlock() if s.regoScanner != nil { return s.regoScanner, nil } diff --git a/pkg/iac/scanners/dockerfile/parser/parser.go b/pkg/iac/scanners/dockerfile/parser/parser.go index d6ff7b4df21a..4255b4609b46 100644 --- a/pkg/iac/scanners/dockerfile/parser/parser.go +++ b/pkg/iac/scanners/dockerfile/parser/parser.go @@ -12,7 +12,6 @@ import ( "github.com/moby/buildkit/frontend/dockerfile/parser" "github.com/aquasecurity/trivy/pkg/iac/debug" - "github.com/aquasecurity/trivy/pkg/iac/detection" "github.com/aquasecurity/trivy/pkg/iac/providers/dockerfile" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) @@ -20,18 +19,13 @@ import ( var _ options.ConfigurableParser = (*Parser)(nil) type Parser struct { - debug debug.Logger - skipRequired bool + debug debug.Logger } func (p *Parser) SetDebugWriter(writer io.Writer) { p.debug = debug.New(writer, "dockerfile", "parser") } -func (p *Parser) SetSkipRequiredCheck(b bool) { - p.skipRequired = b -} - // New creates a new Dockerfile parser func New(opts ...options.ParserOption) *Parser { p := &Parser{} @@ -56,9 +50,7 @@ func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[st if entry.IsDir() { return nil } - if !p.Required(path) { - return nil - } + df, err := p.ParseFile(ctx, target, path) if err != nil { // TODO add debug for parse errors @@ -82,13 +74,6 @@ func (p *Parser) ParseFile(_ context.Context, fsys fs.FS, path string) (*dockerf return p.parse(path, f) } -func (p *Parser) Required(path string) bool { - if p.skipRequired { - return true - } - return detection.IsType(path, nil, detection.FileTypeDockerfile) -} - func (p *Parser) parse(path string, r io.Reader) (*dockerfile.Dockerfile, error) { parsed, err := parser.Parse(r) if err != nil { diff --git a/pkg/iac/scanners/dockerfile/scanner.go b/pkg/iac/scanners/dockerfile/scanner.go index 29df54634d58..561872c70636 100644 --- a/pkg/iac/scanners/dockerfile/scanner.go +++ b/pkg/iac/scanners/dockerfile/scanner.go @@ -19,17 +19,17 @@ import ( var _ scanners.FSScanner = (*Scanner)(nil) var _ options.ConfigurableScanner = (*Scanner)(nil) -type Scanner struct { // nolint: gocritic - debug debug.Logger - policyDirs []string - policyReaders []io.Reader - parser *parser.Parser - regoScanner *rego.Scanner - skipRequired bool - options []options.ScannerOption - frameworks []framework.Framework - spec string - sync.Mutex +type Scanner struct { + mu sync.Mutex + debug debug.Logger + policyDirs []string + policyReaders []io.Reader + parser *parser.Parser + regoScanner *rego.Scanner + options []options.ScannerOption + parserOpts []options.ParserOption + frameworks []framework.Framework + spec string loadEmbeddedLibraries bool loadEmbeddedPolicies bool } @@ -63,12 +63,9 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } -func (s *Scanner) SetSkipRequiredCheck(skip bool) { - s.skipRequired = skip -} - func (s *Scanner) SetDebugWriter(writer io.Writer) { s.debug = debug.New(writer, "dockerfile", "scanner") + s.parserOpts = append(s.parserOpts, options.ParserWithDebug(writer)) } func (s *Scanner) SetTraceWriter(_ io.Writer) { @@ -110,7 +107,7 @@ func NewScanner(opts ...options.ScannerOption) *Scanner { for _, opt := range opts { opt(s) } - s.parser = parser.New(options.ParserWithSkipRequiredCheck(s.skipRequired)) + s.parser = parser.New() return s } @@ -154,8 +151,8 @@ func (s *Scanner) ScanFile(ctx context.Context, fsys fs.FS, path string) (scan.R } func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { - s.Lock() - defer s.Unlock() + s.mu.Lock() + defer s.mu.Unlock() if s.regoScanner != nil { return s.regoScanner, nil } diff --git a/pkg/iac/scanners/helm/parser/parser.go b/pkg/iac/scanners/helm/parser/parser.go index 8768ac459867..bf4a9fc91721 100644 --- a/pkg/iac/scanners/helm/parser/parser.go +++ b/pkg/iac/scanners/helm/parser/parser.go @@ -34,7 +34,6 @@ type Parser struct { ChartSource string filepaths []string debug debug.Logger - skipRequired bool workingFS fs.FS valuesFiles []string values []string @@ -53,10 +52,6 @@ func (p *Parser) SetDebugWriter(writer io.Writer) { p.debug = debug.New(writer, "helm", "parser") } -func (p *Parser) SetSkipRequiredCheck(b bool) { - p.skipRequired = b -} - func (p *Parser) SetValuesFile(s ...string) { p.valuesFiles = s } @@ -129,10 +124,6 @@ func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) error { return nil } - if !p.required(path, p.workingFS) { - return nil - } - if detection.IsArchive(path) { tarFS, err := p.addTarToFS(path) if errors.Is(err, errSkipFS) { @@ -310,15 +301,3 @@ func getManifestPath(manifest string) string { } return manifestFilePathParts[0] } - -func (p *Parser) required(path string, workingFS fs.FS) bool { - if p.skipRequired { - return true - } - content, err := fs.ReadFile(workingFS, path) - if err != nil { - return false - } - - return detection.IsType(path, bytes.NewReader(content), detection.FileTypeHelm) -} diff --git a/pkg/iac/scanners/helm/scanner.go b/pkg/iac/scanners/helm/scanner.go index fc54af44781f..fe74911c51bc 100644 --- a/pkg/iac/scanners/helm/scanner.go +++ b/pkg/iac/scanners/helm/scanner.go @@ -36,7 +36,6 @@ type Scanner struct { loadEmbeddedLibraries bool loadEmbeddedPolicies bool policyFS fs.FS - skipRequired bool frameworks []framework.Framework spec string regoScanner *rego.Scanner @@ -88,12 +87,9 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } -func (s *Scanner) SetSkipRequiredCheck(skip bool) { - s.skipRequired = skip -} - func (s *Scanner) SetDebugWriter(writer io.Writer) { s.debug = debug.New(writer, "helm", "scanner") + s.parserOptions = append(s.parserOptions, options.ParserWithDebug(writer)) } func (s *Scanner) SetTraceWriter(_ io.Writer) { diff --git a/pkg/iac/scanners/json/parser/parser.go b/pkg/iac/scanners/json/parser/parser.go index 340f23c9d11c..8f35794229ef 100644 --- a/pkg/iac/scanners/json/parser/parser.go +++ b/pkg/iac/scanners/json/parser/parser.go @@ -8,25 +8,19 @@ import ( "path/filepath" "github.com/aquasecurity/trivy/pkg/iac/debug" - "github.com/aquasecurity/trivy/pkg/iac/detection" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) var _ options.ConfigurableParser = (*Parser)(nil) type Parser struct { - debug debug.Logger - skipRequired bool + debug debug.Logger } func (p *Parser) SetDebugWriter(writer io.Writer) { p.debug = debug.New(writer, "json", "parser") } -func (p *Parser) SetSkipRequiredCheck(b bool) { - p.skipRequired = b -} - // New creates a new parser func New(opts ...options.ParserOption) *Parser { p := &Parser{} @@ -51,14 +45,13 @@ func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[st if entry.IsDir() { return nil } - if !p.Required(path) { - return nil - } + df, err := p.ParseFile(ctx, target, path) if err != nil { p.debug.Log("Parse error in '%s': %s", path, err) return nil } + files[path] = df return nil }); err != nil { @@ -80,10 +73,3 @@ func (p *Parser) ParseFile(_ context.Context, fsys fs.FS, path string) (any, err } return target, nil } - -func (p *Parser) Required(path string) bool { - if p.skipRequired { - return true - } - return detection.IsType(path, nil, detection.FileTypeJSON) -} diff --git a/pkg/iac/scanners/json/scanner.go b/pkg/iac/scanners/json/scanner.go index 3d563c34c790..3aa0dffdb485 100644 --- a/pkg/iac/scanners/json/scanner.go +++ b/pkg/iac/scanners/json/scanner.go @@ -19,15 +19,15 @@ import ( var _ scanners.FSScanner = (*Scanner)(nil) var _ options.ConfigurableScanner = (*Scanner)(nil) -type Scanner struct { // nolint: gocritic - debug debug.Logger - policyDirs []string - policyReaders []io.Reader - parser *parser.Parser - regoScanner *rego.Scanner - skipRequired bool - options []options.ScannerOption - sync.Mutex +type Scanner struct { + mu sync.Mutex + debug debug.Logger + policyDirs []string + policyReaders []io.Reader + parser *parser.Parser + regoScanner *rego.Scanner + options []options.ScannerOption + parserOpts []options.ParserOption frameworks []framework.Framework spec string loadEmbeddedPolicies bool @@ -61,6 +61,7 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { func (s *Scanner) SetDebugWriter(writer io.Writer) { s.debug = debug.New(writer, "json", "scanner") + s.parserOpts = append(s.parserOpts, options.ParserWithDebug(writer)) } func (s *Scanner) SetTraceWriter(_ io.Writer) { @@ -76,10 +77,6 @@ func (s *Scanner) SetPolicyDirs(dirs ...string) { func (s *Scanner) SetDataDirs(_ ...string) {} func (s *Scanner) SetPolicyNamespaces(_ ...string) {} -func (s *Scanner) SetSkipRequiredCheck(skip bool) { - s.skipRequired = skip -} - func (s *Scanner) SetPolicyFilesystem(_ fs.FS) { // handled by rego when option is passed on } @@ -96,7 +93,7 @@ func NewScanner(opts ...options.ScannerOption) *Scanner { for _, opt := range opts { opt(s) } - s.parser = parser.New(options.ParserWithSkipRequiredCheck(s.skipRequired)) + s.parser = parser.New(s.parserOpts...) return s } @@ -144,8 +141,8 @@ func (s *Scanner) ScanFile(ctx context.Context, fsys fs.FS, path string) (scan.R } func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { - s.Lock() - defer s.Unlock() + s.mu.Lock() + defer s.mu.Unlock() if s.regoScanner != nil { return s.regoScanner, nil } diff --git a/pkg/iac/scanners/kubernetes/parser/parser.go b/pkg/iac/scanners/kubernetes/parser/parser.go index a1c5ecf46962..e2f225a9fb86 100644 --- a/pkg/iac/scanners/kubernetes/parser/parser.go +++ b/pkg/iac/scanners/kubernetes/parser/parser.go @@ -1,7 +1,6 @@ package parser import ( - "bytes" "context" "encoding/json" "fmt" @@ -15,25 +14,19 @@ import ( kyaml "sigs.k8s.io/yaml" "github.com/aquasecurity/trivy/pkg/iac/debug" - "github.com/aquasecurity/trivy/pkg/iac/detection" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) var _ options.ConfigurableParser = (*Parser)(nil) type Parser struct { - debug debug.Logger - skipRequired bool + debug debug.Logger } func (p *Parser) SetDebugWriter(writer io.Writer) { p.debug = debug.New(writer, "kubernetes", "parser") } -func (p *Parser) SetSkipRequiredCheck(b bool) { - p.skipRequired = b -} - // New creates a new K8s parser func New(opts ...options.ParserOption) *Parser { p := &Parser{} @@ -57,14 +50,13 @@ func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[st if entry.IsDir() { return nil } - if !p.required(target, path) { - return nil - } + parsed, err := p.ParseFile(ctx, target, path) if err != nil { p.debug.Log("Parse error in '%s': %s", path, err) return nil } + files[path] = parsed return nil }); err != nil { @@ -83,21 +75,6 @@ func (p *Parser) ParseFile(_ context.Context, fsys fs.FS, path string) ([]any, e return p.Parse(f, path) } -func (p *Parser) required(fsys fs.FS, path string) bool { - if p.skipRequired { - return true - } - f, err := fsys.Open(filepath.ToSlash(path)) - if err != nil { - return false - } - defer func() { _ = f.Close() }() - if data, err := io.ReadAll(f); err == nil { - return detection.IsType(path, bytes.NewReader(data), detection.FileTypeKubernetes) - } - return false -} - func (p *Parser) Parse(r io.Reader, path string) ([]any, error) { contents, err := io.ReadAll(r) diff --git a/pkg/iac/scanners/kubernetes/scanner.go b/pkg/iac/scanners/kubernetes/scanner.go index 44f13ce5b003..c5437f292d85 100644 --- a/pkg/iac/scanners/kubernetes/scanner.go +++ b/pkg/iac/scanners/kubernetes/scanner.go @@ -23,15 +23,15 @@ import ( var _ scanners.FSScanner = (*Scanner)(nil) var _ options.ConfigurableScanner = (*Scanner)(nil) -type Scanner struct { // nolint: gocritic - debug debug.Logger - options []options.ScannerOption - policyDirs []string - policyReaders []io.Reader - regoScanner *rego.Scanner - parser *parser.Parser - skipRequired bool - sync.Mutex +type Scanner struct { + mu sync.Mutex + debug debug.Logger + options []options.ScannerOption + parserOpts []options.ParserOption + policyDirs []string + policyReaders []io.Reader + regoScanner *rego.Scanner + parser *parser.Parser loadEmbeddedPolicies bool frameworks []framework.Framework spec string @@ -62,12 +62,9 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } -func (s *Scanner) SetSkipRequiredCheck(skip bool) { - s.skipRequired = skip -} - func (s *Scanner) SetDebugWriter(writer io.Writer) { s.debug = debug.New(writer, "kubernetes", "scanner") + s.parserOpts = append(s.parserOpts, options.ParserWithDebug(writer)) } func (s *Scanner) SetTraceWriter(_ io.Writer) { @@ -100,7 +97,7 @@ func NewScanner(opts ...options.ScannerOption) *Scanner { for _, opt := range opts { opt(s) } - s.parser = parser.New(options.ParserWithSkipRequiredCheck(s.skipRequired)) + s.parser = parser.New(s.parserOpts...) return s } @@ -109,8 +106,8 @@ func (s *Scanner) Name() string { } func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { - s.Lock() - defer s.Unlock() + s.mu.Lock() + defer s.mu.Unlock() if s.regoScanner != nil { return s.regoScanner, nil } diff --git a/pkg/iac/scanners/options/parser.go b/pkg/iac/scanners/options/parser.go index 65ec41bb825d..e411126a6329 100644 --- a/pkg/iac/scanners/options/parser.go +++ b/pkg/iac/scanners/options/parser.go @@ -4,17 +4,10 @@ import "io" type ConfigurableParser interface { SetDebugWriter(io.Writer) - SetSkipRequiredCheck(bool) } type ParserOption func(s ConfigurableParser) -func ParserWithSkipRequiredCheck(skip bool) ParserOption { - return func(s ConfigurableParser) { - s.SetSkipRequiredCheck(skip) - } -} - // ParserWithDebug specifies an io.Writer for debug logs - if not set, they are discarded func ParserWithDebug(w io.Writer) ParserOption { return func(s ConfigurableParser) { diff --git a/pkg/iac/scanners/options/scanner.go b/pkg/iac/scanners/options/scanner.go index 8e79b0c4a185..291400887037 100644 --- a/pkg/iac/scanners/options/scanner.go +++ b/pkg/iac/scanners/options/scanner.go @@ -14,7 +14,6 @@ type ConfigurableScanner interface { SetPolicyDirs(...string) SetDataDirs(...string) SetPolicyNamespaces(...string) - SetSkipRequiredCheck(bool) SetPolicyReaders([]io.Reader) SetPolicyFilesystem(fs.FS) SetDataFilesystem(fs.FS) @@ -104,12 +103,6 @@ func ScannerWithPolicyNamespaces(namespaces ...string) ScannerOption { } } -func ScannerWithSkipRequiredCheck(skip bool) ScannerOption { - return func(s ConfigurableScanner) { - s.SetSkipRequiredCheck(skip) - } -} - func ScannerWithPolicyFilesystem(f fs.FS) ScannerOption { return func(s ConfigurableScanner) { s.SetPolicyFilesystem(f) diff --git a/pkg/iac/scanners/terraform/parser/parser.go b/pkg/iac/scanners/terraform/parser/parser.go index fa511fed54c2..4f79c1fdf6f2 100644 --- a/pkg/iac/scanners/terraform/parser/parser.go +++ b/pkg/iac/scanners/terraform/parser/parser.go @@ -48,7 +48,6 @@ type Parser struct { allowDownloads bool skipCachedModules bool fsMap map[string]fs.FS - skipRequired bool configsFS fs.FS } @@ -76,10 +75,6 @@ func (p *Parser) SetSkipCachedModules(b bool) { p.skipCachedModules = b } -func (p *Parser) SetSkipRequiredCheck(b bool) { - p.skipRequired = b -} - func (p *Parser) SetConfigsFS(fsys fs.FS) { p.configsFS = fsys } diff --git a/pkg/iac/scanners/terraform/scanner.go b/pkg/iac/scanners/terraform/scanner.go index c999acf337f5..a64201e1fcc5 100644 --- a/pkg/iac/scanners/terraform/scanner.go +++ b/pkg/iac/scanners/terraform/scanner.go @@ -27,8 +27,8 @@ var _ scanners.FSScanner = (*Scanner)(nil) var _ options.ConfigurableScanner = (*Scanner)(nil) var _ ConfigurableTerraformScanner = (*Scanner)(nil) -type Scanner struct { // nolint: gocritic - sync.Mutex +type Scanner struct { + mu sync.Mutex options []options.ScannerOption parserOpt []options.ParserOption executorOpt []executor.Option @@ -87,10 +87,6 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } -func (s *Scanner) SetSkipRequiredCheck(skip bool) { - s.parserOpt = append(s.parserOpt, options.ParserWithSkipRequiredCheck(skip)) -} - func (s *Scanner) SetDebugWriter(writer io.Writer) { s.parserOpt = append(s.parserOpt, options.ParserWithDebug(writer)) s.executorOpt = append(s.executorOpt, executor.OptionWithDebugWriter(writer)) @@ -131,8 +127,8 @@ func New(opts ...options.ScannerOption) *Scanner { } func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { - s.Lock() - defer s.Unlock() + s.mu.Lock() + defer s.mu.Unlock() if s.regoScanner != nil { return s.regoScanner, nil } diff --git a/pkg/iac/scanners/terraformplan/tfjson/scanner.go b/pkg/iac/scanners/terraformplan/tfjson/scanner.go index 6f62d822177f..b25eed6ae42b 100644 --- a/pkg/iac/scanners/terraformplan/tfjson/scanner.go +++ b/pkg/iac/scanners/terraformplan/tfjson/scanner.go @@ -23,8 +23,8 @@ var tfPlanExts = []string{ } type Scanner struct { - parser parser.Parser - parserOpt []options.ParserOption + parser *parser.Parser + parserOpt []parser.Option debug debug.Logger options []options.ScannerOption @@ -68,12 +68,8 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } -func (s *Scanner) SetSkipRequiredCheck(skip bool) { - s.parserOpt = append(s.parserOpt, options.ParserWithSkipRequiredCheck(skip)) -} - func (s *Scanner) SetDebugWriter(writer io.Writer) { - s.parserOpt = append(s.parserOpt, options.ParserWithDebug(writer)) + s.parserOpt = append(s.parserOpt, parser.OptionWithDebugWriter(writer)) s.executorOpt = append(s.executorOpt, executor.OptionWithDebugWriter(writer)) s.debug = debug.New(writer, "tfplan", "scanner") } @@ -128,12 +124,12 @@ func (s *Scanner) ScanFS(ctx context.Context, inputFS fs.FS, dir string) (scan.R func New(opts ...options.ScannerOption) *Scanner { scanner := &Scanner{ - parser: *parser.New(), options: opts, } for _, o := range opts { o(scanner) } + scanner.parser = parser.New(scanner.parserOpt...) return scanner } diff --git a/pkg/iac/scanners/toml/parser/parser.go b/pkg/iac/scanners/toml/parser/parser.go index a8cdcd730f86..6beed83b1908 100644 --- a/pkg/iac/scanners/toml/parser/parser.go +++ b/pkg/iac/scanners/toml/parser/parser.go @@ -9,25 +9,19 @@ import ( "github.com/BurntSushi/toml" "github.com/aquasecurity/trivy/pkg/iac/debug" - "github.com/aquasecurity/trivy/pkg/iac/detection" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) var _ options.ConfigurableParser = (*Parser)(nil) type Parser struct { - debug debug.Logger - skipRequired bool + debug debug.Logger } func (p *Parser) SetDebugWriter(writer io.Writer) { p.debug = debug.New(writer, "toml", "parser") } -func (p *Parser) SetSkipRequiredCheck(b bool) { - p.skipRequired = b -} - // New creates a new parser func New(opts ...options.ParserOption) *Parser { p := &Parser{} @@ -52,9 +46,7 @@ func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[st if entry.IsDir() { return nil } - if !p.Required(path) { - return nil - } + df, err := p.ParseFile(ctx, target, path) if err != nil { p.debug.Log("Parse error in '%s': %s", path, err) @@ -81,10 +73,3 @@ func (p *Parser) ParseFile(_ context.Context, fsys fs.FS, path string) (any, err } return target, nil } - -func (p *Parser) Required(path string) bool { - if p.skipRequired { - return true - } - return detection.IsType(path, nil, detection.FileTypeTOML) -} diff --git a/pkg/iac/scanners/toml/scanner.go b/pkg/iac/scanners/toml/scanner.go index 0a05fdbac18f..37e1807ac254 100644 --- a/pkg/iac/scanners/toml/scanner.go +++ b/pkg/iac/scanners/toml/scanner.go @@ -17,15 +17,15 @@ import ( var _ options.ConfigurableScanner = (*Scanner)(nil) -type Scanner struct { // nolint: gocritic - debug debug.Logger - options []options.ScannerOption - policyDirs []string - policyReaders []io.Reader - parser *parser.Parser - regoScanner *rego.Scanner - skipRequired bool - sync.Mutex +type Scanner struct { + mu sync.Mutex + debug debug.Logger + options []options.ScannerOption + parserOptions []options.ParserOption + policyDirs []string + policyReaders []io.Reader + parser *parser.Parser + regoScanner *rego.Scanner frameworks []framework.Framework spec string loadEmbeddedPolicies bool @@ -60,12 +60,9 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } -func (s *Scanner) SetSkipRequiredCheck(skip bool) { - s.skipRequired = skip -} - func (s *Scanner) SetDebugWriter(writer io.Writer) { s.debug = debug.New(writer, "toml", "scanner") + s.parserOptions = append(s.parserOptions, options.ParserWithDebug(writer)) } func (s *Scanner) SetTraceWriter(_ io.Writer) {} @@ -94,7 +91,7 @@ func NewScanner(opts ...options.ScannerOption) *Scanner { for _, opt := range opts { opt(s) } - s.parser = parser.New(options.ParserWithSkipRequiredCheck(s.skipRequired)) + s.parser = parser.New(s.parserOptions...) return s } @@ -138,8 +135,8 @@ func (s *Scanner) ScanFile(ctx context.Context, fsys fs.FS, path string) (scan.R } func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { - s.Lock() - defer s.Unlock() + s.mu.Lock() + defer s.mu.Unlock() if s.regoScanner != nil { return s.regoScanner, nil } diff --git a/pkg/iac/scanners/yaml/parser/parser.go b/pkg/iac/scanners/yaml/parser/parser.go index 6f113635be4a..d8b50faf2437 100644 --- a/pkg/iac/scanners/yaml/parser/parser.go +++ b/pkg/iac/scanners/yaml/parser/parser.go @@ -11,25 +11,19 @@ import ( "gopkg.in/yaml.v3" "github.com/aquasecurity/trivy/pkg/iac/debug" - "github.com/aquasecurity/trivy/pkg/iac/detection" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) var _ options.ConfigurableParser = (*Parser)(nil) type Parser struct { - debug debug.Logger - skipRequired bool + debug debug.Logger } func (p *Parser) SetDebugWriter(writer io.Writer) { p.debug = debug.New(writer, "yaml", "parser") } -func (p *Parser) SetSkipRequiredCheck(b bool) { - p.skipRequired = b -} - // New creates a new parser func New(opts ...options.ParserOption) *Parser { p := &Parser{} @@ -54,9 +48,7 @@ func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[st if entry.IsDir() { return nil } - if !p.Required(path) { - return nil - } + df, err := p.ParseFile(ctx, target, path) if err != nil { p.debug.Log("Parse error in '%s': %s", path, err) @@ -101,10 +93,3 @@ func (p *Parser) ParseFile(_ context.Context, fsys fs.FS, path string) ([]any, e return results, nil } - -func (p *Parser) Required(path string) bool { - if p.skipRequired { - return true - } - return detection.IsType(path, nil, detection.FileTypeYAML) -} diff --git a/pkg/iac/scanners/yaml/scanner.go b/pkg/iac/scanners/yaml/scanner.go index 0adc43bbd4cf..534ccbd8cb7b 100644 --- a/pkg/iac/scanners/yaml/scanner.go +++ b/pkg/iac/scanners/yaml/scanner.go @@ -17,15 +17,15 @@ import ( var _ options.ConfigurableScanner = (*Scanner)(nil) -type Scanner struct { // nolint: gocritic - options []options.ScannerOption - debug debug.Logger - policyDirs []string - policyReaders []io.Reader - parser *parser.Parser - regoScanner *rego.Scanner - skipRequired bool - sync.Mutex +type Scanner struct { + mu sync.Mutex + options []options.ScannerOption + parserOptions []options.ParserOption + debug debug.Logger + policyDirs []string + policyReaders []io.Reader + parser *parser.Parser + regoScanner *rego.Scanner frameworks []framework.Framework spec string loadEmbeddedLibraries bool @@ -60,12 +60,9 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } -func (s *Scanner) SetSkipRequiredCheck(skip bool) { - s.skipRequired = skip -} - func (s *Scanner) SetDebugWriter(writer io.Writer) { s.debug = debug.New(writer, "yaml", "scanner") + s.parserOptions = append(s.parserOptions, options.ParserWithDebug(writer)) } func (s *Scanner) SetTraceWriter(_ io.Writer) {} @@ -93,7 +90,7 @@ func NewScanner(opts ...options.ScannerOption) *Scanner { for _, opt := range opts { opt(s) } - s.parser = parser.New(options.ParserWithSkipRequiredCheck(s.skipRequired)) + s.parser = parser.New(s.parserOptions...) return s } @@ -139,8 +136,8 @@ func (s *Scanner) ScanFile(ctx context.Context, fsys fs.FS, path string) (scan.R } func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { - s.Lock() - defer s.Unlock() + s.mu.Lock() + defer s.mu.Unlock() if s.regoScanner != nil { return s.regoScanner, nil } diff --git a/pkg/misconf/scanner.go b/pkg/misconf/scanner.go index 90ee90cb4216..8730b03d2faf 100644 --- a/pkg/misconf/scanner.go +++ b/pkg/misconf/scanner.go @@ -215,7 +215,6 @@ func (s *Scanner) filterFS(fsys fs.FS) (fs.FS, error) { func scannerOptions(t detection.FileType, opt ScannerOption) ([]options.ScannerOption, error) { opts := []options.ScannerOption{ - options.ScannerWithSkipRequiredCheck(true), options.ScannerWithEmbeddedPolicies(!opt.DisableEmbeddedPolicies), options.ScannerWithEmbeddedLibraries(!opt.DisableEmbeddedLibraries), options.ScannerWithIncludeDeprecatedChecks(opt.IncludeDeprecatedChecks), From fd8348d610f20c6c33da81cd7b0e7d5504ce26be Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Fri, 2 Aug 2024 14:41:56 +0400 Subject: [PATCH 008/183] feat(vuln): Add `--detection-priority` flag for accuracy tuning (#7288) Signed-off-by: knqyf263 --- docs/docs/coverage/language/dart.md | 16 +- docs/docs/coverage/language/golang.md | 9 +- docs/docs/coverage/language/java.md | 13 +- docs/docs/coverage/language/python.md | 11 +- docs/docs/coverage/os/conda.md | 5 + .../configuration/cli/trivy_filesystem.md | 4 + .../configuration/cli/trivy_image.md | 4 + .../configuration/cli/trivy_kubernetes.md | 4 + .../configuration/cli/trivy_repository.md | 4 + .../configuration/cli/trivy_rootfs.md | 4 + .../configuration/cli/trivy_sbom.md | 4 + .../references/configuration/cli/trivy_vm.md | 4 + docs/docs/scanner/vulnerability.md | 73 +++++++ integration/client_server_test.go | 14 +- integration/standalone_tar_test.go | 33 ++- integration/testdata/fixtures/db/python.yaml | 8 + .../testdata/fixtures/db/vulnerability.yaml | 21 +- .../testdata/ubi-7-comprehensive.json.golden | 192 ++++++++++++++++++ pkg/cache/key.go | 24 ++- pkg/cache/key_test.go | 51 +++-- pkg/commands/artifact/run.go | 6 + pkg/dependency/parser/dart/pub/parse.go | 24 ++- pkg/dependency/parser/dart/pub/parse_test.go | 42 +++- pkg/fanal/analyzer/analyzer.go | 34 ++-- .../analyzer/language/dart/pub/pubspec.go | 4 +- pkg/fanal/artifact/artifact.go | 2 + pkg/fanal/types/detection.go | 10 + pkg/flag/scan_flags.go | 91 +++++---- pkg/types/scan.go | 91 +++++++++ pkg/types/target.go | 94 --------- 30 files changed, 675 insertions(+), 221 deletions(-) create mode 100644 integration/testdata/ubi-7-comprehensive.json.golden create mode 100644 pkg/fanal/types/detection.go delete mode 100644 pkg/types/target.go diff --git a/docs/docs/coverage/language/dart.md b/docs/docs/coverage/language/dart.md index a64a19eb83c2..5e86b6c399f4 100644 --- a/docs/docs/coverage/language/dart.md +++ b/docs/docs/coverage/language/dart.md @@ -11,9 +11,9 @@ 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 | -|-------------------------|--------------|:-----------------------:|:----------------:|:------------------------------------:|:--------:| -| [Dart][dart-repository] | pubspec.lock | ✓ | Included | ✓ | - | +| Package manager | File | Transitive dependencies | Dev dependencies | [Dependency graph][dependency-graph] | Position | [Detection Priority][detection-priority] | +|-------------------------|--------------|:-----------------------:|:----------------:|:------------------------------------:|:--------:|:----------------------------------------:| +| [Dart][dart-repository] | pubspec.lock | ✓ | Included | ✓ | - | ✓ | ## Dart In order to detect dependencies, Trivy searches for `pubspec.lock`. @@ -22,11 +22,13 @@ Trivy marks indirect dependencies, but `pubspec.lock` file doesn't have options So Trivy includes all dependencies in report. ### SDK dependencies -Dart uses version `0.0.0` for SDK dependencies (e.g. Flutter). It is not possible to accurately determine the versions of these dependencies. +Dart uses version `0.0.0` for SDK dependencies (e.g. Flutter). +It is not possible to accurately determine the versions of these dependencies. +Trivy just treats them as `0.0.0`. -Therefore, we use the first version of the constraint for the SDK. +If [--detection-priority comprehensive][detection-priority] is passed, Trivy uses the minimum version of the constraint for the SDK. +For example, in the following case, the version of `flutter` would be `3.3.0`: -For example in this case the version of `flutter` should be `3.3.0`: ```yaml flutter: dependency: "direct main" @@ -40,6 +42,7 @@ sdks: ### Dependency tree To build `dependency tree` Trivy parses [cache directory][cache-directory]. Currently supported default directories and `PUB_CACHE` environment (absolute path only). + !!! note Make sure the cache directory contains all the dependencies installed in your application. To download missing dependencies, use `dart pub get` command. @@ -47,3 +50,4 @@ To build `dependency tree` Trivy parses [cache directory][cache-directory]. Curr [dart-repository]: https://pub.dev/ [dependency-graph]: ../../configuration/reporting.md#show-origins-of-vulnerable-dependencies [cache-directory]: https://dart.dev/tools/pub/glossary#system-cache +[detection-priority]: ../../scanner/vulnerability.md#detection-priority \ No newline at end of file diff --git a/docs/docs/coverage/language/golang.md b/docs/docs/coverage/language/golang.md index 6b3646329318..cf3e160a608b 100644 --- a/docs/docs/coverage/language/golang.md +++ b/docs/docs/coverage/language/golang.md @@ -16,10 +16,10 @@ The following scanners are supported. The table below provides an outline of the features Trivy offers. -| Artifact | Offline[^1] | Dev dependencies | [Dependency graph][dependency-graph] | Stdlib | -|----------|:-----------:|:-----------------|:------------------------------------:|:------:| -| Modules | ✅ | Include | ✅[^2] | - | -| Binaries | ✅ | Exclude | - | ✅[^4] | +| Artifact | Offline[^1] | Dev dependencies | [Dependency graph][dependency-graph] | Stdlib | [Detection Priority][detection-priority] | +|----------|:-----------:|:-----------------|:------------------------------------:|:------:|:----------------------------------------:| +| Modules | ✅ | Include | ✅[^2] | - | - | +| Binaries | ✅ | Exclude | - | ✅[^4] | Not needed | !!! note Trivy scans only dependencies of the Go project. @@ -95,3 +95,4 @@ empty if it cannot do so[^5]. For the second case, the version of such packages [^5]: See https://github.com/golang/go/issues/63432#issuecomment-1751610604 [dependency-graph]: ../../configuration/reporting.md#show-origins-of-vulnerable-dependencies +[detection-priority]: ../../scanner/vulnerability.md#detection-priority diff --git a/docs/docs/coverage/language/java.md b/docs/docs/coverage/language/java.md index bb90366c1772..67cd8c135b9d 100644 --- a/docs/docs/coverage/language/java.md +++ b/docs/docs/coverage/language/java.md @@ -12,12 +12,12 @@ Each artifact supports the following scanners: The following table provides an outline of the features Trivy offers. -| Artifact | Internet access | Dev dependencies | [Dependency graph][dependency-graph] | Position | -|------------------|:---------------------:|:----------------:|:------------------------------------:|:--------:| -| JAR/WAR/PAR/EAR | Trivy Java DB | Include | - | - | -| pom.xml | Maven repository [^1] | Exclude | ✓ | ✓[^7] | -| *gradle.lockfile | - | Exclude | ✓ | ✓ | -| *.sbt.lock | - | Exclude | - | ✓ | +| Artifact | Internet access | Dev dependencies | [Dependency graph][dependency-graph] | Position | [Detection Priority][detection-priority] | +|------------------|:---------------------:|:----------------:|:------------------------------------:|:--------:|:----------------------------------------:| +| JAR/WAR/PAR/EAR | Trivy Java DB | Include | - | - | Not needed | +| pom.xml | Maven repository [^1] | Exclude | ✓ | ✓[^7] | - | +| *gradle.lockfile | - | Exclude | ✓ | ✓ | Not needed | +| *.sbt.lock | - | Exclude | - | ✓ | Not needed | These may be enabled or disabled depending on the target. See [here](./index.md) for the detail. @@ -119,3 +119,4 @@ Make sure that you have cache[^8] directory to find licenses from `*.pom` depend [maven-central]: https://repo.maven.apache.org/maven2/ [maven-pom-repos]: https://maven.apache.org/settings.html#repositories [sbt-dependency-lock]: https://stringbean.github.io/sbt-dependency-lock +[detection-priority]: ../../scanner/vulnerability.md#detection-priority diff --git a/docs/docs/coverage/language/python.md b/docs/docs/coverage/language/python.md index c4f6b6d83e86..15cadd6f96c3 100644 --- a/docs/docs/coverage/language/python.md +++ b/docs/docs/coverage/language/python.md @@ -21,11 +21,11 @@ The following scanners are supported for Python packages. The following table provides an outline of the features Trivy offers. -| Package manager | File | Transitive dependencies | Dev dependencies | [Dependency graph][dependency-graph] | Position | -|-----------------|------------------|:-----------------------:|:----------------:|:------------------------------------:|:--------:| -| pip | requirements.txt | - | Include | - | ✓ | -| Pipenv | Pipfile.lock | ✓ | Include | - | ✓ | -| Poetry | poetry.lock | ✓ | Exclude | ✓ | - | +| Package manager | File | Transitive dependencies | Dev dependencies | [Dependency graph][dependency-graph] | Position | [Detection Priority][detection-priority] | +|-----------------|------------------|:-----------------------:|:----------------:|:------------------------------------:|:--------:|:----------------------------------------:| +| pip | requirements.txt | - | Include | - | ✓ | - | +| Pipenv | Pipfile.lock | ✓ | Include | - | ✓ | Not needed | +| Poetry | poetry.lock | ✓ | Exclude | ✓ | - | Not needed | | Packaging | Dependency graph | @@ -130,3 +130,4 @@ Trivy looks for `.dist-info/META-DATA` to identify Python packages. [^1]: Trivy checks `python`, `python3`, `python2` and `python.exe` file names. [dependency-graph]: ../../configuration/reporting.md#show-origins-of-vulnerable-dependencies +[detection-priority]: ../../scanner/vulnerability.md#detection-priority diff --git a/docs/docs/coverage/os/conda.md b/docs/docs/coverage/os/conda.md index 10c1e93c1b8c..773bd8097b6d 100644 --- a/docs/docs/coverage/os/conda.md +++ b/docs/docs/coverage/os/conda.md @@ -8,6 +8,9 @@ Trivy supports the following scanners for Conda packages. | Vulnerability | - | | License | ✓ | +| Package manager | File | Transitive dependencies | Dev dependencies | [Dependency graph][dependency-graph] | Position | [Detection Priority][detection-priority] | +|-----------------|-----------------|:-----------------------:|:----------------:|:------------------------------------:|:--------:|:----------------------------------------:| +| Conda | environment.yml | - | Include | - | ✓ | - | ## `.json` @@ -41,3 +44,5 @@ To correctly define licenses, make sure your `environment.yml`[^1] contains `pre [environment.yml]: https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#sharing-an-environment [env-version-range]: https://docs.conda.io/projects/conda-build/en/latest/resources/package-spec.html#examples-of-package-specs [prefix]: https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#specifying-a-location-for-an-environment +[dependency-graph]: ../../configuration/reporting.md#show-origins-of-vulnerable-dependencies +[detection-priority]: ../../scanner/vulnerability.md#detection-priority diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index 99f1df23c069..2202bc27f518 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -30,6 +30,10 @@ trivy filesystem [flags] PATH --custom-headers strings custom headers in client mode --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages + --detection-priority string specify the detection priority: + - "precise": Prioritizes precise by minimizing false positives. + - "comprehensive": Aims to detect more security findings at the cost of potential false positives. + (precise,comprehensive) (default "precise") --download-db-only download/update vulnerability database but don't run a scan --download-java-db-only download/update Java index database but don't run a scan --enable-modules strings [EXPERIMENTAL] module names to enable diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index e7f2e3c70ea1..a1de0595a7bc 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -44,6 +44,10 @@ trivy image [flags] IMAGE_NAME --custom-headers strings custom headers in client mode --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages + --detection-priority string specify the detection priority: + - "precise": Prioritizes precise by minimizing false positives. + - "comprehensive": Aims to detect more security findings at the cost of potential false positives. + (precise,comprehensive) (default "precise") --docker-host string unix domain socket path to use for docker scanning --download-db-only download/update vulnerability database but don't run a scan --download-java-db-only download/update Java index database but don't run a scan diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 6c98a35d9020..4516509d5834 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -39,6 +39,10 @@ trivy kubernetes [flags] [CONTEXT] --config-data strings specify paths from which data for the Rego checks will be recursively loaded --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages + --detection-priority string specify the detection priority: + - "precise": Prioritizes precise by minimizing false positives. + - "comprehensive": Aims to detect more security findings at the cost of potential false positives. + (precise,comprehensive) (default "precise") --disable-node-collector When the flag is activated, the node-collector job will not be executed, thus skipping misconfiguration findings on the node. --download-db-only download/update vulnerability database but don't run a scan --download-java-db-only download/update Java index database but don't run a scan diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index ba9aa4983d22..5d4bc5ce4161 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -30,6 +30,10 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --custom-headers strings custom headers in client mode --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages + --detection-priority string specify the detection priority: + - "precise": Prioritizes precise by minimizing false positives. + - "comprehensive": Aims to detect more security findings at the cost of potential false positives. + (precise,comprehensive) (default "precise") --download-db-only download/update vulnerability database but don't run a scan --download-java-db-only download/update Java index database but don't run a scan --enable-modules strings [EXPERIMENTAL] module names to enable diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index 39ccef2dd07a..60fdf4e623fa 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -32,6 +32,10 @@ trivy rootfs [flags] ROOTDIR --custom-headers strings custom headers in client mode --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages + --detection-priority string specify the detection priority: + - "precise": Prioritizes precise by minimizing false positives. + - "comprehensive": Aims to detect more security findings at the cost of potential false positives. + (precise,comprehensive) (default "precise") --download-db-only download/update vulnerability database but don't run a scan --download-java-db-only download/update Java index database but don't run a scan --enable-modules strings [EXPERIMENTAL] module names to enable diff --git a/docs/docs/references/configuration/cli/trivy_sbom.md b/docs/docs/references/configuration/cli/trivy_sbom.md index d6d1bf07e1c6..1b0df922c7fc 100644 --- a/docs/docs/references/configuration/cli/trivy_sbom.md +++ b/docs/docs/references/configuration/cli/trivy_sbom.md @@ -25,6 +25,10 @@ trivy sbom [flags] SBOM_PATH --compliance string compliance report to generate --custom-headers strings custom headers in client mode --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") + --detection-priority string specify the detection priority: + - "precise": Prioritizes precise by minimizing false positives. + - "comprehensive": Aims to detect more security findings at the cost of potential false positives. + (precise,comprehensive) (default "precise") --download-db-only download/update vulnerability database but don't run a scan --download-java-db-only download/update Java index database but don't run a scan --exit-code int specify exit code when any security issues are found diff --git a/docs/docs/references/configuration/cli/trivy_vm.md b/docs/docs/references/configuration/cli/trivy_vm.md index 110cc0a3ecb7..4bae981c7577 100644 --- a/docs/docs/references/configuration/cli/trivy_vm.md +++ b/docs/docs/references/configuration/cli/trivy_vm.md @@ -28,6 +28,10 @@ trivy vm [flags] VM_IMAGE --custom-headers strings custom headers in client mode --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages + --detection-priority string specify the detection priority: + - "precise": Prioritizes precise by minimizing false positives. + - "comprehensive": Aims to detect more security findings at the cost of potential false positives. + (precise,comprehensive) (default "precise") --download-db-only download/update vulnerability database but don't run a scan --download-java-db-only download/update Java index database but don't run a scan --enable-modules strings [EXPERIMENTAL] module names to enable diff --git a/docs/docs/scanner/vulnerability.md b/docs/docs/scanner/vulnerability.md index 9df2b43d8b80..00a9594ead62 100644 --- a/docs/docs/scanner/vulnerability.md +++ b/docs/docs/scanner/vulnerability.md @@ -198,6 +198,54 @@ The default is `ghcr.io/aquasecurity/trivy-java-db`. If authentication is required, you need to run `docker login YOUR_REGISTRY`. Currently, specifying a username and password is not supported. +## Detection Behavior +Trivy prioritizes precision in vulnerability detection, aiming to minimize false positives while potentially accepting some false negatives. +This approach is particularly relevant in two key areas: + +- Handling Software Installed via OS Packages +- Handling Packages with Unspecified Versions + +### Handling Software Installed via OS Packages +For files installed by OS package managers, such as `apt`, Trivy exclusively uses advisories from the OS vendor. +This means that even if a JAR file is present in a container image, if it was installed via an OS package manager (e.g., `apt`), Trivy will not analyze the JAR file itself and use upstream security advisories. + +For example, consider the Python `requests` package in Red Hat Universal Base Image 8: + +```bash +[root@987ee49dc93d /]# head -n 3 /usr/lib/python3.6/site-packages/requests-2.20.0-py3.6.egg-info/PKG-INFO +Metadata-Version: 2.1 +Name: requests +Version: 2.20.0 +``` + +Version 2.20.0 is installed, and this package is installed by `dnf`. + +```bash +[root@987ee49dc93d /]# rpm -ql python3-requests | grep PKG-INFO +/usr/lib/python3.6/site-packages/requests-2.20.0-py3.6.egg-info/PKG-INFO +``` + +At first glance, this might seem vulnerable to [CVE-2023-32681], which affects versions of requests prior to v2.31.0. +However, Red Hat backported the fix to v2.20.0-3 in [RHSA-2023:4520], and the package is not vulnerable. + +- Upstream (PyPI [requests]): Fixed in v2.31.0 +- Red Hat (`python-requests`): Backported fix applied in v2.20.0-3 (RHSA-2023:4520) + +If Trivy were to detect CVE-2023-32681 in this case, it would be a false positive. +This illustrates why using the correct security advisory is crucial to avoid false detections. +To minimize false positives, Trivy trusts the OS vendor's advisory for software installed via OS package managers and does not use upstream advisories for these packages. + +However, this approach may lead to false negatives if the OS vendor's advisories are delayed or missing. +In such cases, using [--detection-priority comprehensive](#detection-priority) allows Trivy to consider upstream advisories (e.g., [GitHub Advisory Database][ghsa]), potentially increasing false positives but reducing false negatives. + +### Handling Packages with Unspecified Versions +When a package version cannot be uniquely determined (e.g., `package-a: ">=3.0"`), Trivy typically skips vulnerability detection for that package to avoid false positives. +If a lock file is present with fixed versions, Trivy will use those for detection. + +To detect potential vulnerabilities even with unspecified versions, use [--detection-priority comprehensive](#detection-priority). +This option makes Trivy use the minimum version in the specified range for vulnerability detection. +While this may increase false positives if the actual version used is not the minimum, it helps reduce false negatives. + ## Configuration This section describes vulnerability-specific configuration. Other common options are documented [here](../configuration/index.md). @@ -307,6 +355,25 @@ By default, all relationships are included in the scan. !!! warning As it may not provide a complete package list, `--pkg-relationships` cannot be used with `--dependency-tree`, `--vex` or SBOM generation. +### Detection Priority + +Trivy provides a `--detection-priority` flag to control the balance between false positives and false negatives in vulnerability detection. +This concept is similar to the relationship between [precision and recall][precision-recall] in machine learning evaluation. + +```bash +$ trivy image --detection-priority {precise|comprehensive} alpine:3.15 +``` + +- `precise`: This mode prioritizes reducing false positives. It results in less noisy vulnerability reports but may miss some potential vulnerabilities. +- `comprehensive`: This mode aims to detect more vulnerabilities, potentially including some that might be false positives. + It provides broader coverage but may increase the noise in the results. + +The default value is `precise`. Also refer to the [detection behavior](#detection-behavior) section for more information. + +Regardless of the chosen mode, user review of detected vulnerabilities is crucial: + +- `precise`: Review thoroughly, considering potential missed vulnerabilities. +- `comprehensive`: Carefully investigate each reported vulnerability due to increased false positive possibility. [^1]: https://github.com/GoogleContainerTools/distroless @@ -353,3 +420,9 @@ By default, all relationships are included in the scan. [nvd]: https://nvd.nist.gov/vuln [k8s-cve]: https://kubernetes.io/docs/reference/issues-security/official-cve-feed/ + +[CVE-2023-32681]: https://nvd.nist.gov/vuln/detail/CVE-2023-32681 +[RHSA-2023:4520]: https://access.redhat.com/errata/RHSA-2023:4520 +[ghsa]: https://github.com/advisories +[requests]: https://pypi.org/project/requests/ +[precision-recall]: https://developers.google.com/machine-learning/crash-course/classification/precision-and-recall \ No newline at end of file diff --git a/integration/client_server_test.go b/integration/client_server_test.go index c6dd7fb74dc5..e0edce7aa6a8 100644 --- a/integration/client_server_test.go +++ b/integration/client_server_test.go @@ -287,7 +287,7 @@ func TestClientServer(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - osArgs := setupClient(t, tt.args, addr, cacheDir, tt.golden) + osArgs := setupClient(t, tt.args, addr, cacheDir) if tt.args.secretConfig != "" { osArgs = append(osArgs, "--secret-config", tt.args.secretConfig) @@ -407,7 +407,7 @@ func TestClientServerWithFormat(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Setenv("AWS_REGION", "test-region") t.Setenv("AWS_ACCOUNT_ID", "123456789012") - osArgs := setupClient(t, tt.args, addr, cacheDir, tt.golden) + osArgs := setupClient(t, tt.args, addr, cacheDir) runTest(t, osArgs, tt.golden, "", tt.args.Format, runOptions{ override: overrideUID, @@ -435,7 +435,7 @@ func TestClientServerWithCycloneDX(t *testing.T) { addr, cacheDir := setup(t, setupOptions{}) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - osArgs := setupClient(t, tt.args, addr, cacheDir, tt.golden) + osArgs := setupClient(t, tt.args, addr, cacheDir) runTest(t, osArgs, tt.golden, "", types.FormatCycloneDX, runOptions{ fakeUUID: "3ff14136-e09f-4df9-80ea-%012d", }) @@ -488,7 +488,7 @@ func TestClientServerWithToken(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - osArgs := setupClient(t, tt.args, addr, cacheDir, tt.golden) + osArgs := setupClient(t, tt.args, addr, cacheDir) runTest(t, osArgs, tt.golden, "", types.FormatJSON, runOptions{ override: overrideUID, wantErr: tt.wantErr, @@ -515,7 +515,7 @@ func TestClientServerWithRedis(t *testing.T) { golden := "testdata/alpine-39.json.golden" t.Run("alpine 3.9", func(t *testing.T) { - osArgs := setupClient(t, testArgs, addr, cacheDir, golden) + osArgs := setupClient(t, testArgs, addr, cacheDir) // Run Trivy client runTest(t, osArgs, golden, "", types.FormatJSON, runOptions{ @@ -527,7 +527,7 @@ func TestClientServerWithRedis(t *testing.T) { require.NoError(t, redisC.Terminate(ctx)) t.Run("sad path", func(t *testing.T) { - osArgs := setupClient(t, testArgs, addr, cacheDir, golden) + osArgs := setupClient(t, testArgs, addr, cacheDir) // Run Trivy client runTest(t, osArgs, "", "", types.FormatJSON, runOptions{ @@ -592,7 +592,7 @@ func setupServer(addr, token, tokenHeader, cacheDir, cacheBackend string) []stri return osArgs } -func setupClient(t *testing.T, c csArgs, addr string, cacheDir string, golden string) []string { +func setupClient(t *testing.T, c csArgs, addr string, cacheDir string) []string { if c.Command == "" { c.Command = "image" } diff --git a/integration/standalone_tar_test.go b/integration/standalone_tar_test.go index 2cb372b86b0a..dce852cf7f3c 100644 --- a/integration/standalone_tar_test.go +++ b/integration/standalone_tar_test.go @@ -8,6 +8,7 @@ import ( "strings" "testing" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/types" "github.com/stretchr/testify/require" @@ -15,13 +16,14 @@ import ( func TestTar(t *testing.T) { type args struct { - IgnoreUnfixed bool - Severity []string - IgnoreIDs []string - Format types.Format - Input string - SkipDirs []string - SkipFiles []string + IgnoreUnfixed bool + Severity []string + IgnoreIDs []string + Format types.Format + Input string + SkipDirs []string + SkipFiles []string + DetectionPriority ftypes.DetectionPriority } tests := []struct { name string @@ -240,7 +242,7 @@ func TestTar(t *testing.T) { golden: "testdata/centos-7.json.golden", }, { - name: "centos 7with --ignore-unfixed option", + name: "centos 7 with --ignore-unfixed option", args: args{ IgnoreUnfixed: true, Format: types.FormatJSON, @@ -274,6 +276,15 @@ func TestTar(t *testing.T) { }, golden: "testdata/ubi-7.json.golden", }, + { + name: "ubi 7 with comprehensive priority", + args: args{ + Format: types.FormatJSON, + Input: "testdata/fixtures/images/ubi-7.tar.gz", + DetectionPriority: ftypes.PriorityComprehensive, + }, + golden: "testdata/ubi-7-comprehensive.json.golden", + }, { name: "almalinux 8", args: args{ @@ -380,7 +391,7 @@ func TestTar(t *testing.T) { "-q", "--format", string(tt.args.Format), - "--skip-update", + "--skip-db-update", } if tt.args.IgnoreUnfixed { @@ -411,6 +422,10 @@ func TestTar(t *testing.T) { } } + if tt.args.DetectionPriority != "" { + osArgs = append(osArgs, "--detection-priority", string(tt.args.DetectionPriority)) + } + // Run Trivy runTest(t, osArgs, tt.golden, "", tt.args.Format, runOptions{}) }) diff --git a/integration/testdata/fixtures/db/python.yaml b/integration/testdata/fixtures/db/python.yaml index 2d484feff17c..728f11b67e6d 100644 --- a/integration/testdata/fixtures/db/python.yaml +++ b/integration/testdata/fixtures/db/python.yaml @@ -14,3 +14,11 @@ - 0.11.6 VulnerableVersions: - < 0.11.6 + - bucket: setuptools + pairs: + - key: CVE-2022-40897 + value: + PatchedVersions: + - 65.5.1 + VulnerableVersions: + - < 65.5.1 \ No newline at end of file diff --git a/integration/testdata/fixtures/db/vulnerability.yaml b/integration/testdata/fixtures/db/vulnerability.yaml index 9b16712d0dbc..6fcdcece75bd 100644 --- a/integration/testdata/fixtures/db/vulnerability.yaml +++ b/integration/testdata/fixtures/db/vulnerability.yaml @@ -1399,4 +1399,23 @@ - "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-14155" - "https://nvd.nist.gov/vuln/detail/CVE-2020-14155" PublishedDate: "2020-06-15T17:15:00Z" - LastModifiedDate: "2022-04-28T15:06:00Z" \ No newline at end of file + LastModifiedDate: "2022-04-28T15:06:00Z" + - key: CVE-2022-40897 + value: + Title: "pypa-setuptools: Regular Expression Denial of Service (ReDoS) in package_index.py" + Description: "Python Packaging Authority (PyPA) setuptools before 65.5.1 allows remote attackers to cause a denial of service via HTML in a crafted package or custom PackageIndex page. There is a Regular Expression Denial of Service (ReDoS) in package_index.py." + Severity: MEDIUM + CweIDs: + - CWE-1333 + VendorSeverity: + ghsa: 3 + nvd: 2 + CVSS: + nvd: + V3Vector: "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H" + V3Score: 5.9 + References: + - "https://access.redhat.com/errata/RHSA-2023:0952" + - "https://access.redhat.com/security/cve/CVE-2022-40897" + PublishedDate: "2022-12-23T00:15:13.987Z" + LastModifiedDate: "2024-06-21T19:15:23.877Z" diff --git a/integration/testdata/ubi-7-comprehensive.json.golden b/integration/testdata/ubi-7-comprehensive.json.golden new file mode 100644 index 000000000000..6df4b8241456 --- /dev/null +++ b/integration/testdata/ubi-7-comprehensive.json.golden @@ -0,0 +1,192 @@ +{ + "SchemaVersion": 2, + "CreatedAt": "2021-08-25T12:20:30.000000005Z", + "ArtifactName": "testdata/fixtures/images/ubi-7.tar.gz", + "ArtifactType": "container_image", + "Metadata": { + "OS": { + "Family": "redhat", + "Name": "7.7" + }, + "ImageID": "sha256:6fecccc91c83e11ae4fede6793e9410841221d4779520c2b9e9fb7f7b3830264", + "DiffIDs": [ + "sha256:4468e6d912c76d5b127f3554c3cd83b7dc07cce6107c6b916299ba76fa7d15ac", + "sha256:ecb0311889b3478bc9b62660fa9391d5ebf8da4c6ae143cb33434873668f9e36" + ], + "ImageConfig": { + "architecture": "amd64", + "created": "2019-09-02T12:56:43.939095Z", + "docker_version": "1.13.1", + "history": [ + { + "created": "2019-09-02T12:56:36.440695936Z", + "comment": "Imported from -" + }, + { + "created": "2019-09-02T12:56:43.939095Z" + } + ], + "os": "linux", + "rootfs": { + "type": "layers", + "diff_ids": [ + "sha256:4468e6d912c76d5b127f3554c3cd83b7dc07cce6107c6b916299ba76fa7d15ac", + "sha256:ecb0311889b3478bc9b62660fa9391d5ebf8da4c6ae143cb33434873668f9e36" + ] + }, + "config": { + "Cmd": [ + "/bin/bash" + ], + "Env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "container=oci" + ], + "Hostname": "0da2e3774382", + "Image": "2e9103a7b91a7ffe333e9162ce98ea078263747527571655e93bd4d35ee278f0", + "Labels": { + "architecture": "x86_64", + "authoritative-source-url": "registry.access.redhat.com", + "build-date": "2019-09-02T12:56:18.824770", + "com.redhat.build-host": "cpt-1005.osbs.prod.upshift.rdu2.redhat.com", + "com.redhat.component": "ubi7-container", + "com.redhat.license_terms": "https://www.redhat.com/en/about/red-hat-end-user-license-agreements#UBI", + "description": "The Universal Base Image is designed and engineered to be the base layer for all of your containerized applications, middleware and utilities. This base image is freely redistributable, but Red Hat only supports Red Hat technologies through subscriptions for Red Hat products. This image is maintained by Red Hat and updated regularly.", + "distribution-scope": "public", + "io.k8s.description": "The Universal Base Image is designed and engineered to be the base layer for all of your containerized applications, middleware and utilities. This base image is freely redistributable, but Red Hat only supports Red Hat technologies through subscriptions for Red Hat products. This image is maintained by Red Hat and updated regularly.", + "io.k8s.display-name": "Red Hat Universal Base Image 7", + "io.openshift.tags": "base rhel7", + "maintainer": "Red Hat, Inc.", + "name": "ubi7", + "release": "140", + "summary": "Provides the latest release of the Red Hat Universal Base Image 7.", + "url": "https://access.redhat.com/containers/#/registry.access.redhat.com/ubi7/images/7.7-140", + "vcs-ref": "4c80c8aa26e69950ab11b87789c8fb7665b1632d", + "vcs-type": "git", + "vendor": "Red Hat, Inc.", + "version": "7.7" + }, + "ArgsEscaped": true + } + } + }, + "Results": [ + { + "Target": "testdata/fixtures/images/ubi-7.tar.gz (redhat 7.7)", + "Class": "os-pkgs", + "Type": "redhat", + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2019-18276", + "PkgID": "bash@4.2.46-33.el7.x86_64", + "PkgName": "bash", + "PkgIdentifier": { + "PURL": "pkg:rpm/redhat/bash@4.2.46-33.el7?arch=x86_64\u0026distro=redhat-7.7", + "UID": "f5b786381193ad1b" + }, + "InstalledVersion": "4.2.46-33.el7", + "Status": "will_not_fix", + "Layer": { + "Digest": "sha256:7b1c937e0f6794db2535be6e4cb6d60a0b668ef78c2576611a3fb9c97a95ccdf", + "DiffID": "sha256:4468e6d912c76d5b127f3554c3cd83b7dc07cce6107c6b916299ba76fa7d15ac" + }, + "SeveritySource": "redhat", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2019-18276", + "Title": "bash: when effective UID is not equal to its real UID the saved UID is not dropped", + "Description": "An issue was discovered in disable_priv_mode in shell.c in GNU Bash through 5.0 patch 11. By default, if Bash is run with its effective UID not equal to its real UID, it will drop privileges by setting its effective UID to its real UID. However, it does so incorrectly. On Linux and other systems that support \"saved UID\" functionality, the saved UID is not dropped. An attacker with command execution in the shell can use \"enable -f\" for runtime loading of a new builtin, which can be a shared object that calls setuid() and therefore regains privileges. However, binaries running with an effective UID of 0 are unaffected.", + "Severity": "LOW", + "CweIDs": [ + "CWE-273" + ], + "VendorSeverity": { + "cbl-mariner": 3, + "nvd": 3, + "oracle-oval": 1, + "photon": 3, + "redhat": 1, + "ubuntu": 1 + }, + "CVSS": { + "nvd": { + "V2Vector": "AV:L/AC:L/Au:N/C:C/I:C/A:C", + "V3Vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", + "V2Score": 7.2, + "V3Score": 7.8 + }, + "redhat": { + "V3Vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H", + "V3Score": 7.8 + } + }, + "References": [ + "http://packetstormsecurity.com/files/155498/Bash-5.0-Patch-11-Privilege-Escalation.html", + "https://access.redhat.com/security/cve/CVE-2019-18276", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18276", + "https://github.com/bminor/bash/commit/951bdaad7a18cc0dc1036bba86b18b90874d39ff", + "https://linux.oracle.com/cve/CVE-2019-18276.html", + "https://linux.oracle.com/errata/ELSA-2021-1679.html", + "https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772@%3Cdev.mina.apache.org%3E", + "https://nvd.nist.gov/vuln/detail/CVE-2019-18276", + "https://security.gentoo.org/glsa/202105-34", + "https://security.netapp.com/advisory/ntap-20200430-0003/", + "https://www.youtube.com/watch?v=-wGtxJ8opa8" + ], + "PublishedDate": "2019-11-28T01:15:00Z", + "LastModifiedDate": "2021-05-26T12:15:00Z" + } + ] + }, + { + "Target": "Python", + "Class": "lang-pkgs", + "Type": "python-pkg", + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2022-40897", + "PkgName": "setuptools", + "PkgPath": "usr/lib/python2.7/site-packages/setuptools-0.9.8-py2.7.egg-info/PKG-INFO", + "PkgIdentifier": { + "PURL": "pkg:pypi/setuptools@0.9.8", + "UID": "3f4c89bf681c1d7a" + }, + "InstalledVersion": "0.9.8", + "FixedVersion": "65.5.1", + "Status": "fixed", + "Layer": { + "Digest": "sha256:7b1c937e0f6794db2535be6e4cb6d60a0b668ef78c2576611a3fb9c97a95ccdf", + "DiffID": "sha256:4468e6d912c76d5b127f3554c3cd83b7dc07cce6107c6b916299ba76fa7d15ac" + }, + "SeveritySource": "ghsa", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2022-40897", + "DataSource": { + "ID": "ghsa", + "Name": "GitHub Security Advisory Pip", + "URL": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Apip" + }, + "Title": "pypa-setuptools: Regular Expression Denial of Service (ReDoS) in package_index.py", + "Description": "Python Packaging Authority (PyPA) setuptools before 65.5.1 allows remote attackers to cause a denial of service via HTML in a crafted package or custom PackageIndex page. There is a Regular Expression Denial of Service (ReDoS) in package_index.py.", + "Severity": "HIGH", + "CweIDs": [ + "CWE-1333" + ], + "VendorSeverity": { + "ghsa": 3, + "nvd": 2 + }, + "CVSS": { + "nvd": { + "V3Vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 5.9 + } + }, + "References": [ + "https://access.redhat.com/errata/RHSA-2023:0952", + "https://access.redhat.com/security/cve/CVE-2022-40897" + ], + "PublishedDate": "2022-12-23T00:15:13.987Z", + "LastModifiedDate": "2024-06-21T19:15:23.877Z" + } + ] + } + ] +} diff --git a/pkg/cache/key.go b/pkg/cache/key.go index 7d6720393554..0ad0fde82fe1 100644 --- a/pkg/cache/key.go +++ b/pkg/cache/key.go @@ -13,6 +13,7 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/artifact" + "github.com/aquasecurity/trivy/pkg/fanal/types" ) func CalcKey(id string, analyzerVersions analyzer.Versions, hookVersions map[string]int, artifactOpt artifact.Option) (string, error) { @@ -24,13 +25,22 @@ func CalcKey(id string, analyzerVersions analyzer.Versions, hookVersions map[str // Write ID, analyzer/handler versions, skipped files/dirs and file patterns keyBase := struct { - ID string - AnalyzerVersions analyzer.Versions - HookVersions map[string]int - SkipFiles []string - SkipDirs []string - FilePatterns []string `json:",omitempty"` - }{id, analyzerVersions, hookVersions, artifactOpt.WalkerOption.SkipFiles, artifactOpt.WalkerOption.SkipDirs, artifactOpt.FilePatterns} + ID string + AnalyzerVersions analyzer.Versions + HookVersions map[string]int + SkipFiles []string + SkipDirs []string + FilePatterns []string `json:",omitempty"` + DetectionPriority types.DetectionPriority `json:",omitempty"` + }{ + id, + analyzerVersions, + hookVersions, + artifactOpt.WalkerOption.SkipFiles, + artifactOpt.WalkerOption.SkipDirs, + artifactOpt.FilePatterns, + artifactOpt.DetectionPriority, + } if err := json.NewEncoder(h).Encode(keyBase); err != nil { return "", xerrors.Errorf("json encode error: %w", err) diff --git a/pkg/cache/key_test.go b/pkg/cache/key_test.go index 012e9edd407f..d80748567683 100644 --- a/pkg/cache/key_test.go +++ b/pkg/cache/key_test.go @@ -8,21 +8,23 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/artifact" + "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/fanal/walker" "github.com/aquasecurity/trivy/pkg/misconf" ) func TestCalcKey(t *testing.T) { type args struct { - key string - analyzerVersions analyzer.Versions - hookVersions map[string]int - skipFiles []string - skipDirs []string - patterns []string - policy []string - data []string - secretConfigPath string + key string + analyzerVersions analyzer.Versions + hookVersions map[string]int + skipFiles []string + skipDirs []string + patterns []string + policy []string + data []string + secretConfigPath string + detectionPriority types.DetectionPriority } tests := []struct { name string @@ -115,7 +117,10 @@ func TestCalcKey(t *testing.T) { "debian": 1, }, }, - patterns: []string{"test", ""}, + patterns: []string{ + "test", + "", + }, }, want: "sha256:71abf09bf1422531e2838db692b80f9b9f48766f56b7d3d02aecdb36b019e103", }, @@ -129,7 +134,10 @@ func TestCalcKey(t *testing.T) { "debian": 1, }, }, - patterns: []string{"", "test"}, + patterns: []string{ + "", + "test", + }, }, want: "sha256:71abf09bf1422531e2838db692b80f9b9f48766f56b7d3d02aecdb36b019e103", }, @@ -177,6 +185,23 @@ func TestCalcKey(t *testing.T) { }, want: "sha256:363f70f4ee795f250873caea11c2fc94ef12945444327e7e2f8a99e3884695e0", }, + { + name: "detection priority", + args: args{ + key: "sha256:5c534be56eca62e756ef2ef51523feda0f19cd7c15bb0c015e3d6e3ae090bf6e", + analyzerVersions: analyzer.Versions{ + Analyzers: map[string]int{ + "alpine": 1, + "debian": 1, + }, + }, + skipFiles: []string{"app/deployment.yaml"}, + skipDirs: []string{"usr/java"}, + policy: []string{"testdata/policy"}, + detectionPriority: types.PriorityComprehensive, + }, + want: "sha256:2f1c898271e84f4382cd48ae7533069cc3dc656c2d688ac108f5db1a0d9fd393", + }, { name: "secret config", @@ -231,7 +256,8 @@ func TestCalcKey(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { artifactOpt := artifact.Option{ - FilePatterns: tt.args.patterns, + FilePatterns: tt.args.patterns, + DetectionPriority: tt.args.detectionPriority, MisconfScannerOption: misconf.ScannerOption{ PolicyPaths: tt.args.policy, @@ -249,7 +275,6 @@ func TestCalcKey(t *testing.T) { } got, err := CalcKey(tt.args.key, tt.args.analyzerVersions, tt.args.hookVersions, artifactOpt) if tt.wantErr != "" { - require.Error(t, err) assert.ErrorContains(t, err, tt.wantErr) return } diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index e49829e352fb..6528ec2c3d36 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -568,6 +568,10 @@ func (r *runner) initScannerConfig(opts flag.Options) (ScannerConfig, types.Scan fileChecksum = true } + // Disable the post handler for filtering system file when detection priority is comprehensive. + disabledHandlers := lo.Ternary(opts.DetectionPriority == ftypes.PriorityComprehensive, + []ftypes.HandlerType{ftypes.SystemFileFilteringPostHandler}, nil) + return ScannerConfig{ Target: target, CacheOptions: opts.CacheOpts(), @@ -579,6 +583,7 @@ func (r *runner) initScannerConfig(opts flag.Options) (ScannerConfig, types.Scan }, ArtifactOption: artifact.Option{ DisabledAnalyzers: disabledAnalyzers(opts), + DisabledHandlers: disabledHandlers, FilePatterns: opts.FilePatterns, Parallel: opts.Parallel, Offline: opts.OfflineScan, @@ -592,6 +597,7 @@ func (r *runner) initScannerConfig(opts flag.Options) (ScannerConfig, types.Scan AWSRegion: opts.Region, AWSEndpoint: opts.Endpoint, FileChecksum: fileChecksum, + DetectionPriority: opts.DetectionPriority, // For image scanning ImageOption: ftypes.ImageOptions{ diff --git a/pkg/dependency/parser/dart/pub/parse.go b/pkg/dependency/parser/dart/pub/parse.go index 1bd85a56f1d6..f17fedf0a2b0 100644 --- a/pkg/dependency/parser/dart/pub/parse.go +++ b/pkg/dependency/parser/dart/pub/parse.go @@ -19,12 +19,14 @@ const ( // Parser is a parser for pubspec.lock type Parser struct { - logger *log.Logger + logger *log.Logger + useMinVersion bool } -func NewParser() *Parser { +func NewParser(useMinVersion bool) *Parser { return &Parser{ - logger: log.WithPrefix("pub"), + logger: log.WithPrefix("pub"), + useMinVersion: useMinVersion, } } @@ -50,7 +52,7 @@ func (p Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency var pkgs []ftypes.Package for name, dep := range l.Packages { version := dep.Version - if version == "0.0.0" && dep.Source == "sdk" { + if version == "0.0.0" && dep.Source == "sdk" && p.useMinVersion { version = p.findSDKVersion(l, name, dep) } @@ -71,27 +73,27 @@ func (p Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency return pkgs, nil, nil } -// findSDKVersion detects the first version of the SDK constraint specified in the Description. +// findSDKVersion detects the minimum version of the SDK constraint specified in the Description. // If the constraint is not found, it returns the original version. func (p Parser) findSDKVersion(l *lock, name string, dep Dep) string { // Some dependencies use one of the SDK versions. // In this case dep.Version == `0.0.0`. // We can't get versions for these dependencies. - // Therefore, we use the first version of the SDK constraint specified in the Description. + // Therefore, we use the minimum version of the SDK constraint specified in the Description. // See https://github.com/aquasecurity/trivy/issues/6017 constraint, ok := l.Sdks[string(dep.Description)] if !ok { return dep.Version } - v, err := firstVersionOfConstrain(constraint) + v, err := minVersionOfConstrain(constraint) if err != nil { p.logger.Warn("Unable to get sdk version from constraint", log.Err(err)) return dep.Version } else if v == "" { return dep.Version } - p.logger.Info("Using the first version of the constraint from the sdk source", log.String("dep", name), + p.logger.Info("Using the minimum version of the constraint from the sdk source", log.String("dep", name), log.String("constraint", constraint)) return v } @@ -106,8 +108,8 @@ func (p Parser) relationship(dep string) ftypes.Relationship { return ftypes.RelationshipUnknown } -// firstVersionOfConstrain returns the first acceptable version for constraint -func firstVersionOfConstrain(constraint string) (string, error) { +// minVersionOfConstrain returns the minimum acceptable version for constraint +func minVersionOfConstrain(constraint string) (string, error) { css, err := goversion.NewConstraints(constraint) if err != nil { return "", xerrors.Errorf("unable to parse constraints: %w", err) @@ -119,7 +121,7 @@ func firstVersionOfConstrain(constraint string) (string, error) { if len(constraints) == 0 || len(constraints[0]) == 0 { return "", nil } - // We only need to get the first version from the range + // We only need to get the minimum version from the range if constraints[0][0].Operator() != ">=" && constraints[0][0].Operator() != "^" { return "", nil } diff --git a/pkg/dependency/parser/dart/pub/parse_test.go b/pkg/dependency/parser/dart/pub/parse_test.go index 5f4591201b7c..e884adf28306 100644 --- a/pkg/dependency/parser/dart/pub/parse_test.go +++ b/pkg/dependency/parser/dart/pub/parse_test.go @@ -15,14 +15,42 @@ import ( func TestParser_Parse(t *testing.T) { tests := []struct { - name string - inputFile string - want []ftypes.Package - wantErr assert.ErrorAssertionFunc + name string + useMinVersion bool + inputFile string + want []ftypes.Package + wantErr assert.ErrorAssertionFunc }{ { - name: "happy path", - inputFile: "testdata/happy.lock", + name: "not use minimum version", + useMinVersion: false, + inputFile: "testdata/happy.lock", + want: []ftypes.Package{ + { + ID: "crypto@3.0.2", + Name: "crypto", + Version: "3.0.2", + Relationship: ftypes.RelationshipDirect, + }, + { + ID: "flutter_test@0.0.0", + Name: "flutter_test", + Version: "0.0.0", + Relationship: ftypes.RelationshipDirect, + }, + { + ID: "uuid@3.0.6", + Name: "uuid", + Version: "3.0.6", + Relationship: ftypes.RelationshipIndirect, + }, + }, + wantErr: assert.NoError, + }, + { + name: "use minimum version", + useMinVersion: true, + inputFile: "testdata/happy.lock", want: []ftypes.Package{ { ID: "crypto@3.0.2", @@ -63,7 +91,7 @@ func TestParser_Parse(t *testing.T) { require.NoError(t, err) defer f.Close() - gotPkgs, _, err := pub.NewParser().Parse(f) + gotPkgs, _, err := pub.NewParser(tt.useMinVersion).Parse(f) if !tt.wantErr(t, err, fmt.Sprintf("Parse(%v)", tt.inputFile)) { return } diff --git a/pkg/fanal/analyzer/analyzer.go b/pkg/fanal/analyzer/analyzer.go index d2d07ffcc733..b5bb8e629acf 100644 --- a/pkg/fanal/analyzer/analyzer.go +++ b/pkg/fanal/analyzer/analyzer.go @@ -44,6 +44,7 @@ type AnalyzerOptions struct { Parallel int FilePatterns []string DisabledAnalyzers []Type + DetectionPriority types.DetectionPriority MisconfScannerOption misconf.ScannerOption SecretScannerOption SecretScannerOption LicenseScannerOption LicenseScannerOption @@ -120,10 +121,11 @@ type CustomGroup interface { type Opener func() (xio.ReadSeekCloserAt, error) type AnalyzerGroup struct { - logger *log.Logger - analyzers []analyzer - postAnalyzers []PostAnalyzer - filePatterns map[Type][]*regexp.Regexp + logger *log.Logger + analyzers []analyzer + postAnalyzers []PostAnalyzer + filePatterns map[Type][]*regexp.Regexp + detectionPriority types.DetectionPriority } /////////////////////////// @@ -312,17 +314,18 @@ func belongToGroup(groupName Group, analyzerType Type, disabledAnalyzers []Type, const separator = ":" -func NewAnalyzerGroup(opt AnalyzerOptions) (AnalyzerGroup, error) { - groupName := opt.Group +func NewAnalyzerGroup(opts AnalyzerOptions) (AnalyzerGroup, error) { + groupName := opts.Group if groupName == "" { groupName = GroupBuiltin } group := AnalyzerGroup{ - logger: log.WithPrefix("analyzer"), - filePatterns: make(map[Type][]*regexp.Regexp), + logger: log.WithPrefix("analyzer"), + filePatterns: make(map[Type][]*regexp.Regexp), + detectionPriority: opts.DetectionPriority, } - for _, p := range opt.FilePatterns { + for _, p := range opts.FilePatterns { // e.g. "dockerfile:my_dockerfile_*" s := strings.SplitN(p, separator, 2) if len(s) != 2 { @@ -343,12 +346,12 @@ func NewAnalyzerGroup(opt AnalyzerOptions) (AnalyzerGroup, error) { } for analyzerType, a := range analyzers { - if !belongToGroup(groupName, analyzerType, opt.DisabledAnalyzers, a) { + if !belongToGroup(groupName, analyzerType, opts.DisabledAnalyzers, a) { continue } // Initialize only scanners that have Init() if ini, ok := a.(Initializer); ok { - if err := ini.Init(opt); err != nil { + if err := ini.Init(opts); err != nil { return AnalyzerGroup{}, xerrors.Errorf("analyzer initialization error: %w", err) } } @@ -356,11 +359,11 @@ func NewAnalyzerGroup(opt AnalyzerOptions) (AnalyzerGroup, error) { } for analyzerType, init := range postAnalyzers { - a, err := init(opt) + a, err := init(opts) if err != nil { return AnalyzerGroup{}, xerrors.Errorf("post-analyzer init error: %w", err) } - if !belongToGroup(groupName, analyzerType, opt.DisabledAnalyzers, a) { + if !belongToGroup(groupName, analyzerType, opts.DisabledAnalyzers, a) { continue } group.postAnalyzers = append(group.postAnalyzers, a) @@ -473,6 +476,11 @@ func (ag AnalyzerGroup) PostAnalyze(ctx context.Context, compositeFS *CompositeF } skippedFiles := result.SystemInstalledFiles + if ag.detectionPriority == types.PriorityComprehensive { + // If the detection priority is comprehensive, system files installed by the OS package manager will not be skipped. + // It can lead to false positives and duplicates, but it may be necessary to detect all possible vulnerabilities. + skippedFiles = nil + } for _, app := range result.Applications { skippedFiles = append(skippedFiles, app.FilePath) for _, pkg := range app.Packages { diff --git a/pkg/fanal/analyzer/language/dart/pub/pubspec.go b/pkg/fanal/analyzer/language/dart/pub/pubspec.go index 9def336d406f..30fc2dadb18b 100644 --- a/pkg/fanal/analyzer/language/dart/pub/pubspec.go +++ b/pkg/fanal/analyzer/language/dart/pub/pubspec.go @@ -37,10 +37,10 @@ type pubSpecLockAnalyzer struct { parser language.Parser } -func newPubSpecLockAnalyzer(_ analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { +func newPubSpecLockAnalyzer(opts analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { return pubSpecLockAnalyzer{ logger: log.WithPrefix("pub"), - parser: pub.NewParser(), + parser: pub.NewParser(opts.DetectionPriority == types.PriorityComprehensive), }, nil } diff --git a/pkg/fanal/artifact/artifact.go b/pkg/fanal/artifact/artifact.go index e431278f6fc2..b6034cb5ac63 100644 --- a/pkg/fanal/artifact/artifact.go +++ b/pkg/fanal/artifact/artifact.go @@ -28,6 +28,7 @@ type Option struct { AWSRegion string AWSEndpoint string FileChecksum bool // For SPDX + DetectionPriority types.DetectionPriority // Git repositories RepoBranch string @@ -50,6 +51,7 @@ func (o *Option) AnalyzerOptions() analyzer.AnalyzerOptions { FilePatterns: o.FilePatterns, Parallel: o.Parallel, DisabledAnalyzers: o.DisabledAnalyzers, + DetectionPriority: o.DetectionPriority, MisconfScannerOption: o.MisconfScannerOption, SecretScannerOption: o.SecretScannerOption, LicenseScannerOption: o.LicenseScannerOption, diff --git a/pkg/fanal/types/detection.go b/pkg/fanal/types/detection.go new file mode 100644 index 000000000000..38d1634ed2a3 --- /dev/null +++ b/pkg/fanal/types/detection.go @@ -0,0 +1,10 @@ +package types + +// DetectionPriority represents the priority of detection +type DetectionPriority string + +// PriorityPrecise tries to minimize false positives +const PriorityPrecise DetectionPriority = "precise" + +// PriorityComprehensive tries to minimize false negatives +const PriorityComprehensive DetectionPriority = "comprehensive" diff --git a/pkg/flag/scan_flags.go b/pkg/flag/scan_flags.go index b413fce01fe9..544d56691883 100644 --- a/pkg/flag/scan_flags.go +++ b/pkg/flag/scan_flags.go @@ -5,6 +5,7 @@ import ( "github.com/samber/lo" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/types" xstrings "github.com/aquasecurity/trivy/pkg/x/strings" @@ -96,43 +97,59 @@ var ( Default: "https://rekor.sigstore.dev", Usage: "[EXPERIMENTAL] address of rekor STL server", } + DetectionPriority = Flag[string]{ + Name: "detection-priority", + ConfigName: "scan.detection-priority", + Default: string(ftypes.PriorityPrecise), + Values: xstrings.ToStringSlice([]ftypes.DetectionPriority{ + ftypes.PriorityPrecise, + ftypes.PriorityComprehensive, + }), + Usage: `specify the detection priority: + - "precise": Prioritizes precise by minimizing false positives. + - "comprehensive": Aims to detect more security findings at the cost of potential false positives. +`, + } ) type ScanFlagGroup struct { - SkipDirs *Flag[[]string] - SkipFiles *Flag[[]string] - OfflineScan *Flag[bool] - Scanners *Flag[[]string] - FilePatterns *Flag[[]string] - Slow *Flag[bool] // deprecated - Parallel *Flag[int] - SBOMSources *Flag[[]string] - RekorURL *Flag[string] + SkipDirs *Flag[[]string] + SkipFiles *Flag[[]string] + OfflineScan *Flag[bool] + Scanners *Flag[[]string] + FilePatterns *Flag[[]string] + Slow *Flag[bool] // deprecated + Parallel *Flag[int] + SBOMSources *Flag[[]string] + RekorURL *Flag[string] + DetectionPriority *Flag[string] } type ScanOptions struct { - Target string - SkipDirs []string - SkipFiles []string - OfflineScan bool - Scanners types.Scanners - FilePatterns []string - Parallel int - SBOMSources []string - RekorURL string + Target string + SkipDirs []string + SkipFiles []string + OfflineScan bool + Scanners types.Scanners + FilePatterns []string + Parallel int + SBOMSources []string + RekorURL string + DetectionPriority ftypes.DetectionPriority } func NewScanFlagGroup() *ScanFlagGroup { return &ScanFlagGroup{ - SkipDirs: SkipDirsFlag.Clone(), - SkipFiles: SkipFilesFlag.Clone(), - OfflineScan: OfflineScanFlag.Clone(), - Scanners: ScannersFlag.Clone(), - FilePatterns: FilePatternsFlag.Clone(), - Parallel: ParallelFlag.Clone(), - SBOMSources: SBOMSourcesFlag.Clone(), - RekorURL: RekorURLFlag.Clone(), - Slow: SlowFlag.Clone(), + SkipDirs: SkipDirsFlag.Clone(), + SkipFiles: SkipFilesFlag.Clone(), + OfflineScan: OfflineScanFlag.Clone(), + Scanners: ScannersFlag.Clone(), + FilePatterns: FilePatternsFlag.Clone(), + Parallel: ParallelFlag.Clone(), + SBOMSources: SBOMSourcesFlag.Clone(), + RekorURL: RekorURLFlag.Clone(), + Slow: SlowFlag.Clone(), + DetectionPriority: DetectionPriority.Clone(), } } @@ -151,6 +168,7 @@ func (f *ScanFlagGroup) Flags() []Flagger { f.Parallel, f.SBOMSources, f.RekorURL, + f.DetectionPriority, } } @@ -171,14 +189,15 @@ func (f *ScanFlagGroup) ToOptions(args []string) (ScanOptions, error) { } return ScanOptions{ - Target: target, - SkipDirs: f.SkipDirs.Value(), - SkipFiles: f.SkipFiles.Value(), - OfflineScan: f.OfflineScan.Value(), - Scanners: xstrings.ToTSlice[types.Scanner](f.Scanners.Value()), - FilePatterns: f.FilePatterns.Value(), - Parallel: parallel, - SBOMSources: f.SBOMSources.Value(), - RekorURL: f.RekorURL.Value(), + Target: target, + SkipDirs: f.SkipDirs.Value(), + SkipFiles: f.SkipFiles.Value(), + OfflineScan: f.OfflineScan.Value(), + Scanners: xstrings.ToTSlice[types.Scanner](f.Scanners.Value()), + FilePatterns: f.FilePatterns.Value(), + Parallel: parallel, + SBOMSources: f.SBOMSources.Value(), + RekorURL: f.RekorURL.Value(), + DetectionPriority: ftypes.DetectionPriority(f.DetectionPriority.Value()), }, nil } diff --git a/pkg/types/scan.go b/pkg/types/scan.go index 09b90e745c58..0fef0028bef3 100644 --- a/pkg/types/scan.go +++ b/pkg/types/scan.go @@ -1,9 +1,100 @@ package types import ( + "slices" + "github.com/aquasecurity/trivy/pkg/fanal/types" ) +// PkgType represents package type +type PkgType = string + +// Scanner represents the type of security scanning +type Scanner string + +// Scanners is a slice of scanners +type Scanners []Scanner + +const ( + // PkgTypeUnknown is a package type of unknown + PkgTypeUnknown PkgType = "unknown" + + // PkgTypeOS is a package type of OS packages + PkgTypeOS PkgType = "os" + + // PkgTypeLibrary is a package type of programming language dependencies + PkgTypeLibrary PkgType = "library" + + // UnknownScanner is the scanner of unknown + UnknownScanner Scanner = "unknown" + + // NoneScanner is the scanner of none + NoneScanner Scanner = "none" + + // SBOMScanner is the virtual scanner of SBOM, which cannot be enabled by the user + SBOMScanner Scanner = "sbom" + + // VulnerabilityScanner is the scanner of vulnerabilities + VulnerabilityScanner Scanner = "vuln" + + // MisconfigScanner is the scanner of misconfigurations + MisconfigScanner Scanner = "misconfig" + + // SecretScanner is the scanner of secrets + SecretScanner Scanner = "secret" + + // RBACScanner is the scanner of rbac assessment + RBACScanner Scanner = "rbac" + + // LicenseScanner is the scanner of licenses + LicenseScanner Scanner = "license" +) + +var ( + PkgTypes = []string{ + PkgTypeOS, + PkgTypeLibrary, + } + + AllScanners = Scanners{ + VulnerabilityScanner, + MisconfigScanner, + RBACScanner, + SecretScanner, + LicenseScanner, + NoneScanner, + } + + // AllImageConfigScanners has a list of available scanners on container image config. + // The container image in container registries consists of manifest, config and layers. + // Trivy is also able to detect security issues on the image config. + AllImageConfigScanners = Scanners{ + MisconfigScanner, + SecretScanner, + NoneScanner, + } +) + +func (scanners *Scanners) Enable(s Scanner) { + if !scanners.Enabled(s) { + *scanners = append(*scanners, s) + } +} + +func (scanners *Scanners) Enabled(s Scanner) bool { + return slices.Contains(*scanners, s) +} + +// AnyEnabled returns true if any of the passed scanners is included. +func (scanners *Scanners) AnyEnabled(ss ...Scanner) bool { + for _, s := range ss { + if scanners.Enabled(s) { + return true + } + } + return false +} + // ScanTarget holds the attributes for scanning. type ScanTarget struct { Name string // container image name, file path, etc diff --git a/pkg/types/target.go b/pkg/types/target.go deleted file mode 100644 index a8cccced3de7..000000000000 --- a/pkg/types/target.go +++ /dev/null @@ -1,94 +0,0 @@ -package types - -import ( - "slices" -) - -// PkgType represents package type -type PkgType = string - -// Scanner represents the type of security scanning -type Scanner string - -// Scanners is a slice of scanners -type Scanners []Scanner - -const ( - // PkgTypeUnknown is a package type of unknown - PkgTypeUnknown = PkgType("unknown") - - // PkgTypeOS is a package type of OS packages - PkgTypeOS = PkgType("os") - - // PkgTypeLibrary is a package type of programming language dependencies - PkgTypeLibrary = PkgType("library") - - // UnknownScanner is the scanner of unknown - UnknownScanner = Scanner("unknown") - - // NoneScanner is the scanner of none - NoneScanner = Scanner("none") - - // SBOMScanner is the virtual scanner of SBOM, which cannot be enabled by the user - SBOMScanner = Scanner("sbom") - - // VulnerabilityScanner is the scanner of vulnerabilities - VulnerabilityScanner = Scanner("vuln") - - // MisconfigScanner is the scanner of misconfigurations - MisconfigScanner = Scanner("misconfig") - - // SecretScanner is the scanner of secrets - SecretScanner = Scanner("secret") - - // RBACScanner is the scanner of rbac assessment - RBACScanner = Scanner("rbac") - - // LicenseScanner is the scanner of licenses - LicenseScanner = Scanner("license") -) - -var ( - PkgTypes = []string{ - PkgTypeOS, - PkgTypeLibrary, - } - - AllScanners = Scanners{ - VulnerabilityScanner, - MisconfigScanner, - RBACScanner, - SecretScanner, - LicenseScanner, - NoneScanner, - } - - // AllImageConfigScanners has a list of available scanners on container image config. - // The container image in container registries consists of manifest, config and layers. - // Trivy is also able to detect security issues on the image config. - AllImageConfigScanners = Scanners{ - MisconfigScanner, - SecretScanner, - NoneScanner, - } -) - -func (scanners *Scanners) Enable(s Scanner) { - if !scanners.Enabled(s) { - *scanners = append(*scanners, s) - } -} - -func (scanners *Scanners) Enabled(s Scanner) bool { - return slices.Contains(*scanners, s) -} - -// AnyEnabled returns true if any of the passed scanners is included. -func (scanners *Scanners) AnyEnabled(ss ...Scanner) bool { - for _, s := range ss { - if scanners.Enabled(s) { - return true - } - } - return false -} From 555ac8c11dc282fa55627083d9f6ca0171d1a231 Mon Sep 17 00:00:00 2001 From: afdesk Date: Mon, 5 Aug 2024 13:52:40 +0600 Subject: [PATCH 009/183] docs: add auto-generated config (#7261) Signed-off-by: knqyf263 Co-authored-by: knqyf263 --- .../references/configuration/config-file.md | 928 +++++++++--------- magefiles/docs.go | 125 +++ pkg/flag/global_flags.go | 2 +- pkg/flag/options.go | 10 + 4 files changed, 595 insertions(+), 470 deletions(-) diff --git a/docs/docs/references/configuration/config-file.md b/docs/docs/references/configuration/config-file.md index 535a1b9e657e..b3876d6ad225 100644 --- a/docs/docs/references/configuration/config-file.md +++ b/docs/docs/references/configuration/config-file.md @@ -5,615 +5,605 @@ The config path can be overridden by the `--config` flag. An example is [here][example]. -## Global Options +These samples contain default values for flags. +## Global options ```yaml -# Same as '--quiet' -# Default is false -quiet: false +cache: + # Same as '--cache-dir' + dir: "/path/to/cache" # Same as '--debug' -# Default is false debug: false # Same as '--insecure' -# Default is false insecure: false +# Same as '--quiet' +quiet: false + # Same as '--timeout' -# Default is '5m' -timeout: 10m +timeout: 5m0s -# Same as '--cache-dir' -# Default is your system cache dir -cache: - dir: $HOME/.cache/trivy ``` - -## Report Options +## Cache options ```yaml -# Same as '--format' -# Default is 'table' -format: table +cache: + # Same as '--cache-backend' + backend: "fs" -# Same as '--report' (available with 'trivy k8s') -# Default is all -report: all + # Same as '--clear-cache' + clear: false -# Same as '--template' -# Default is empty -template: - -# Same as '--dependency-tree' -# Default is false -dependency-tree: false + redis: + # Same as '--redis-ca' + ca: "" -# Same as '--list-all-pkgs' -# Default is false -list-all-pkgs: false + # Same as '--redis-cert' + cert: "" -# Same as '--ignorefile' -# Default is '.trivyignore' -ignorefile: .trivyignore + # Same as '--redis-key' + key: "" -# Same as '--ignore-policy' -# Default is empty -ignore-policy: + # Same as '--redis-tls' + tls: false -# Same as '--exit-code' -# Default is 0 -exit-code: 0 + # Same as '--cache-ttl' + ttl: 0s -# Same as '--exit-on-eol' -# Default is 0 -exit-on-eol: 0 +``` +## Clean options -# Same as '--output' -# Default is empty (stdout) -output: +```yaml +clean: + # Same as '--all' + all: false -# Same as '--severity' -# Default is all severities -severity: - - UNKNOWN - - LOW - - MEDIUM - - HIGH - - CRITICAL - -# Same as '--pkg-types' -# Default is 'os,library' -pkg-types: - - os - - library - + # Same as '--checks-bundle' + checks-bundle: false -scan: - # Same as '--compliance' - # Default is empty - compliance: + # Same as '--java-db' + java-db: false - # Same as '--show-suppressed' - # Default is false - show-suppressed: false -``` + # Same as '--scan-cache' + scan-cache: false -## Scan Options -Available in client/server mode + # Same as '--vex-repo' + vex-repo: false -```yaml -scan: - # Same as '--file-patterns' - # Default is empty - file-patterns: - - + # Same as '--vuln-db' + vuln-db: false - # Same as '--skip-dirs' - # Default is empty - skip-dirs: - - usr/local/ - - etc/ +``` +## Client/Server options - # Same as '--skip-files' - # Default is empty - skip-files: - - package-dev.json +```yaml +server: + # Same as '--server' + addr: "" - # Same as '--offline-scan' - # Default is false - offline: false + # Same as '--custom-headers' + custom-headers: [] - # Same as '--scanners' - # Default depends on subcommand - scanners: - - vuln - - misconfig - - secret - - license - - - # Same as '--parallel' - # Default is 5 - parallel: 1 + # Same as '--listen' + listen: "localhost:4954" - # Same as '--sbom-sources' - # Default is empty - sbom-sources: - - oci - - rekor + # Same as '--token' + token: "" - # Same as '--rekor-url' - # Default is 'https://rekor.sigstore.dev' - rekor-url: https://rekor.sigstore.dev + # Same as '--token-header' + token-header: "Trivy-Token" - # Same as '--include-dev-deps' - # Default is false - include-dev-deps: false ``` - -## Cache Options +## DB options ```yaml -cache: - # Same as '--cache-backend' - # Default is 'fs' - backend: 'fs' - - # Same as '--cache-ttl' - # Default is 0 (no ttl) - ttl: 0 +db: + # Same as '--download-java-db-only' + download-java-only: false - # Redis options - redis: - # Same as '--redis-tls' - # Default is false - tls: - # Same as '--redis-ca' - # Default is empty - ca: + # Same as '--download-db-only' + download-only: false - # Same as '--redis-cert' - # Default is empty - cert: + # Same as '--java-db-repository' + java-repository: "ghcr.io/aquasecurity/trivy-java-db:1" - # Same as '--redis-key' - # Default is empty - key: -``` + # Same as '--skip-java-db-update' + java-skip-update: false -## DB Options + # Same as '--light' + light: false -```yaml -db: # Same as '--no-progress' - # Default is false no-progress: false - - # Same as '--skip-db-update' - # Default is false - skip-update: false # Same as '--db-repository' - # Default is 'ghcr.io/aquasecurity/trivy-db:2' - repository: ghcr.io/aquasecurity/trivy-db:2 + repository: "ghcr.io/aquasecurity/trivy-db:2" - # Same as '--skip-java-db-update' - # Default is false - java-skip-update: false + # Same as '--skip-db-update' + skip-update: false - # Same as '--java-db-repository' - # Default is 'ghcr.io/aquasecurity/trivy-java-db:1' - java-repository: ghcr.io/aquasecurity/trivy-java-db:1 -``` +# Same as '--reset' +reset: false -## Registry Options +``` +## Image options ```yaml -registry: - # Same as '--username' - # Default is empty - username: +image: + docker: + # Same as '--docker-host' + host: "" - # Same as '--password' - # Default is empty - password: - - # Same as '--registry-token' - # Default is empty - registry-token: -``` + # Same as '--image-config-scanners' + image-config-scanners: [] -## Image Options -Available with container image scanning + # Same as '--input' + input: "" -```yaml -image: - # Same as '--input' (available with 'trivy image') - # Default is empty - input: + # Same as '--platform' + platform: "" + + podman: + # Same as '--podman-host' + host: "" # Same as '--removed-pkgs' - # Default is false removed-pkgs: false - - # Same as '--platform' - # Default is empty - platform: # Same as '--image-src' - # Default is 'docker,containerd,podman,remote' source: - - podman - - docker - - # Same as '--image-config-scanners' - # Default is empty - image-config-scanners: - - misconfig - - secret - - docker: - # Same as '--docker-host' - # Default is empty - host: - - podman: - # Same as '--podman-host' - # Default is empty - host: -``` + - docker + - containerd + - podman + - remote -## Vulnerability Options -Available with vulnerability scanning +``` +## Kubernetes options ```yaml -vulnerability: - # Same as '--ignore-unfixed' - # Default is false - ignore-unfixed: false +kubernetes: + # Same as '--burst' + burst: 10 - # Same as '--ignore-unfixed' - # Default is empty - ignore-status: - - end_of_life + # Same as '--disable-node-collector' + disableNodeCollector: false - # Same as '--vex' - # Default is empty - vex: - - path/to/vex/file - - repo + exclude: + # Same as '--exclude-nodes' + nodes: [] - # Same as '--skip-vex-repo-update' - # Default is false - skip-vex-repo-update: true -``` + # Same as '--exclude-owned' + owned: false -## License Options -Available with license scanning + # Same as '--exclude-kinds' + excludeKinds: [] -```yaml -license: - # Same as '--license-full' - # Default is false - full: false + # Same as '--exclude-namespaces' + excludeNamespaces: [] - # Same as '--ignored-licenses' - # Default is empty - ignored: - - MPL-2.0 - - MIT + # Same as '--include-kinds' + includeKinds: [] + # Same as '--include-namespaces' + includeNamespaces: [] + + # Same as '--k8s-version' + k8s-version: "" + + # Same as '--kubeconfig' + kubeconfig: "" + + node-collector: + # Same as '--node-collector-imageref' + imageref: "ghcr.io/aquasecurity/node-collector:0.3.1" + + # Same as '--node-collector-namespace' + namespace: "trivy-temp" + + # Same as '--qps' + qps: 5 + + # Same as '--skip-images' + skipImages: false + + # Same as '--tolerations' + tolerations: [] + +``` +## License options + +```yaml +license: # Same as '--license-confidence-level' - # Default is 0.9 confidenceLevel: 0.9 - # Set list of forbidden licenses - # Default is https://github.com/aquasecurity/trivy/blob/164b025413c5fb9c6759491e9a306b46b869be93/pkg/licensing/category.go#L171 forbidden: - - AGPL-1.0 - - AGPL-3.0 + - AGPL-1.0 + - AGPL-3.0 + - CC-BY-NC-1.0 + - CC-BY-NC-2.0 + - CC-BY-NC-2.5 + - CC-BY-NC-3.0 + - CC-BY-NC-4.0 + - CC-BY-NC-ND-1.0 + - CC-BY-NC-ND-2.0 + - CC-BY-NC-ND-2.5 + - CC-BY-NC-ND-3.0 + - CC-BY-NC-ND-4.0 + - CC-BY-NC-SA-1.0 + - CC-BY-NC-SA-2.0 + - CC-BY-NC-SA-2.5 + - CC-BY-NC-SA-3.0 + - CC-BY-NC-SA-4.0 + - Commons-Clause + - Facebook-2-Clause + - Facebook-3-Clause + - Facebook-Examples + - WTFPL - # Set list of restricted licenses - # Default is https://github.com/aquasecurity/trivy/blob/164b025413c5fb9c6759491e9a306b46b869be93/pkg/licensing/category.go#L199 - restricted: - - AGPL-1.0 - - AGPL-3.0 + # Same as '--license-full' + full: false - # Set list of reciprocal licenses - # Default is https://github.com/aquasecurity/trivy/blob/164b025413c5fb9c6759491e9a306b46b869be93/pkg/licensing/category.go#L238 - reciprocal: - - AGPL-1.0 - - AGPL-3.0 + # Same as '--ignored-licenses' + ignored: [] - # Set list of notice licenses - # Default is https://github.com/aquasecurity/trivy/blob/164b025413c5fb9c6759491e9a306b46b869be93/pkg/licensing/category.go#L260 notice: - - AGPL-1.0 - - AGPL-3.0 + - AFL-1.1 + - AFL-1.2 + - AFL-2.0 + - AFL-2.1 + - AFL-3.0 + - Apache-1.0 + - Apache-1.1 + - Apache-2.0 + - Artistic-1.0-cl8 + - Artistic-1.0-Perl + - Artistic-1.0 + - Artistic-2.0 + - BSL-1.0 + - BSD-2-Clause-FreeBSD + - BSD-2-Clause-NetBSD + - BSD-2-Clause + - BSD-3-Clause-Attribution + - BSD-3-Clause-Clear + - BSD-3-Clause-LBNL + - BSD-3-Clause + - BSD-4-Clause + - BSD-4-Clause-UC + - BSD-Protection + - CC-BY-1.0 + - CC-BY-2.0 + - CC-BY-2.5 + - CC-BY-3.0 + - CC-BY-4.0 + - FTL + - ISC + - ImageMagick + - Libpng + - Lil-1.0 + - Linux-OpenIB + - LPL-1.02 + - LPL-1.0 + - MS-PL + - MIT + - NCSA + - OpenSSL + - PHP-3.01 + - PHP-3.0 + - PIL + - Python-2.0 + - Python-2.0-complete + - PostgreSQL + - SGI-B-1.0 + - SGI-B-1.1 + - SGI-B-2.0 + - Unicode-DFS-2015 + - Unicode-DFS-2016 + - Unicode-TOU + - UPL-1.0 + - W3C-19980720 + - W3C-20150513 + - W3C + - X11 + - Xnet + - Zend-2.0 + - zlib-acknowledgement + - Zlib + - ZPL-1.1 + - ZPL-2.0 + - ZPL-2.1 + + permissive: [] - # Set list of permissive licenses - # Default is empty - permissive: - - AGPL-1.0 - - AGPL-3.0 + reciprocal: + - APSL-1.0 + - APSL-1.1 + - APSL-1.2 + - APSL-2.0 + - CDDL-1.0 + - CDDL-1.1 + - CPL-1.0 + - EPL-1.0 + - EPL-2.0 + - FreeImage + - IPL-1.0 + - MPL-1.0 + - MPL-1.1 + - MPL-2.0 + - Ruby + + restricted: + - BCL + - CC-BY-ND-1.0 + - CC-BY-ND-2.0 + - CC-BY-ND-2.5 + - CC-BY-ND-3.0 + - CC-BY-ND-4.0 + - CC-BY-SA-1.0 + - CC-BY-SA-2.0 + - CC-BY-SA-2.5 + - CC-BY-SA-3.0 + - CC-BY-SA-4.0 + - GPL-1.0 + - GPL-2.0 + - GPL-2.0-with-autoconf-exception + - GPL-2.0-with-bison-exception + - GPL-2.0-with-classpath-exception + - GPL-2.0-with-font-exception + - GPL-2.0-with-GCC-exception + - GPL-3.0 + - GPL-3.0-with-autoconf-exception + - GPL-3.0-with-GCC-exception + - LGPL-2.0 + - LGPL-2.1 + - LGPL-3.0 + - NPL-1.0 + - NPL-1.1 + - OSL-1.0 + - OSL-1.1 + - OSL-2.0 + - OSL-2.1 + - OSL-3.0 + - QPL-1.0 + - Sleepycat - # Set list of unencumbered licenses - # Default is https://github.com/aquasecurity/trivy/blob/164b025413c5fb9c6759491e9a306b46b869be93/pkg/licensing/category.go#L334 unencumbered: - - AGPL-1.0 - - AGPL-3.0 -``` + - CC0-1.0 + - Unlicense + - 0BSD -## Secret Options -Available with secret scanning +``` +## Misconfiguration options ```yaml -secret: - # Same as '--secret-config' - # Default is 'trivy-secret.yaml' - config: config/trivy/secret.yaml -``` +misconfiguration: + # Same as '--checks-bundle-repository' + checks-bundle-repository: "ghcr.io/aquasecurity/trivy-checks:0" -## Rego Options + cloudformation: + # Same as '--cf-params' + params: [] -```yaml -rego: - # Same as '--trace' - # Default is false - trace: false + helm: + # Same as '--helm-api-versions' + api-versions: [] - # Same as '--skip-check-update' - # Default is false - skip-check-update: false + # Same as '--helm-kube-version' + kube-version: "" - # Same as '--config-policy' - # Default is empty - policy: - - policy/repository - - policy/custom - - policy/some-policy.rego + # Same as '--helm-set' + set: [] - # Same as '--config-data' - # Default is empty - data: - - data/ - - # Same as '--policy-namespaces' - # Default is empty - namespaces: - - opa.examples - - users -``` + # Same as '--helm-set-file' + set-file: [] -## Misconfiguration Options -Available with misconfiguration scanning + # Same as '--helm-set-string' + set-string: [] + + # Same as '--helm-values' + values: [] -```yaml -misconfiguration: # Same as '--include-non-failures' - # Default is false include-non-failures: false - - # Same as '--include-deprecated-checks' - # Default is false - include-deprecated-checks: false - # Same as '--check-bundle-repository' and '--policy-bundle-repository' - # Default is 'ghcr.io/aquasecurity/trivy-checks:0' - check-bundle-repository: ghcr.io/aquasecurity/trivy-checks:0 - - # Same as '--miconfig-scanners' - # Default is all scanners + # Same as '--reset-checks-bundle' + reset-checks-bundle: false + + # Same as '--misconfig-scanners' scanners: - - dockerfile - - terraform + - azure-arm + - cloudformation + - dockerfile + - helm + - kubernetes + - terraform + - terraformplan-json + - terraformplan-snapshot - # helm value override configurations - helm: - # set individual values - set: - - securityContext.runAsUser=10001 + terraform: + # Same as '--tf-exclude-downloaded-modules' + exclude-downloaded-modules: false - # set values with file - values: - - overrides.yaml + # Same as '--tf-vars' + vars: [] - # set specific values from specific files - set-file: - - image=dev-overrides.yaml +``` +## Module options - # set as string and preserve type - set-string: - - name=true +```yaml +module: + # Same as '--module-dir' + dir: "$HOME/.trivy/modules" - # Available API versions used for Capabilities.APIVersions. This flag is the same as the api-versions flag of the helm template command. - api-versions: - - policy/v1/PodDisruptionBudget - - apps/v1/Deployment + # Same as '--enable-modules' + enable-modules: [] - # Kubernetes version used for Capabilities.KubeVersion. This flag is the same as the kube-version flag of the helm template command. - kube-version: "v1.21.0" +``` +## Registry options - # terraform tfvars overrrides - terraform: - vars: - - dev-terraform.tfvars - - common-terraform.tfvars - - # Same as '--tf-exclude-downloaded-modules' - # Default is false - exclude-downloaded-modules: false +```yaml +registry: + # Same as '--password' + password: [] + + # Same as '--registry-token' + token: "" + + # Same as '--username' + username: [] - # Same as '--cf-params' - # Default is false - cloudformation: - params: - - params.json ``` +## Rego options -## Kubernetes Options -Available with Kubernetes scanning +```yaml +rego: + # Same as '--config-check' + check: [] + + # Same as '--config-data' + data: [] + + # Same as '--include-deprecated-checks' + include-deprecated-checks: false + + # Same as '--check-namespaces' + namespaces: [] + + # Same as '--skip-check-update' + skip-check-update: false + + # Same as '--trace' + trace: false + +``` +## Report options ```yaml -kubernetes: - # Same as '--context' - # Default is empty - context: +# Same as '--dependency-tree' +dependency-tree: false + +# Same as '--exit-code' +exit-code: 0 - # Same as '--namespace' - # Default is empty - namespace: +# Same as '--exit-on-eol' +exit-on-eol: 0 - # Same as '--kubeconfig' - # Default is empty - kubeconfig: ~/.kube/config2 +# Same as '--format' +format: "table" - # Same as '--components' - # Default is 'workload,infra' - components: - - workload - - infra +# Same as '--ignore-policy' +ignore-policy: "" - # Same as '--k8s-version' - # Default is empty - k8s-version: 1.21.0 +# Same as '--ignorefile' +ignorefile: ".trivyignore" - # Same as '--tolerations' - # Default is empty - tolerations: - - key1=value1:NoExecute - - key2=value2:NoSchedule +# Same as '--list-all-pkgs' +list-all-pkgs: false - # Same as '--all-namespaces' - # Default is false - all-namespaces: false +# Same as '--output' +output: "" - node-collector: - # Same as '--node-collector-namespace' - # Default is 'trivy-temp' - namespace: ~/.kube/config2 +# Same as '--output-plugin-arg' +output-plugin-arg: "" - # Same as '--node-collector-imageref' - # Default is 'ghcr.io/aquasecurity/node-collector:0.0.9' - imageref: ghcr.io/aquasecurity/node-collector:0.0.9 +# Same as '--report' +report: "all" - exclude: - # Same as '--exclude-owned' - # Default is false - owned: true +scan: + # Same as '--compliance' + compliance: "" - # Same as '--exclude-nodes' - # Default is empty - nodes: - - kubernetes.io/arch:arm64 - - team:dev + # Same as '--show-suppressed' + show-suppressed: false - # Same as '--qps' - # Default is 5.0 - qps: 5.0 +# Same as '--severity' +severity: + - UNKNOWN + - LOW + - MEDIUM + - HIGH + - CRITICAL - # Same as '--burst' - # Default is 10 - burst: 10 -``` +# Same as '--template' +template: "" -## Repository Options -Available with git repository scanning (`trivy repo`) +``` +## Repository options ```yaml repository: # Same as '--branch' - # Default is empty - branch: + branch: "" # Same as '--commit' - # Default is empty - commit: + commit: "" # Same as '--tag' - # Default is empty - tag: -``` + tag: "" -## Client/Server Options -Available in client/server mode +``` +## Scan options ```yaml -server: - # Same as '--server' (available in client mode) - # Default is empty - addr: http://localhost:4954 +scan: + # Same as '--detection-priority' + detection-priority: "precise" - # Same as '--token' - # Default is empty - token: "something-secret" + # Same as '--file-patterns' + file-patterns: [] - # Same as '--token-header' - # Default is 'Trivy-Token' - token-header: 'My-Token-Header' + # Same as '--offline-scan' + offline: false - # Same as '--custom-headers' - # Default is empty - custom-headers: - - scanner: trivy - - x-api-token: xxx - - # Same as '--listen' (available in server mode) - # Default is 'localhost:4954' - listen: 0.0.0.0:10000 -``` + # Same as '--parallel' + parallel: 5 + + # Same as '--rekor-url' + rekor-url: "https://rekor.sigstore.dev" -## Cloud Options + # Same as '--sbom-sources' + sbom-sources: [] -Available for cloud scanning (currently only `trivy aws`) + # Same as '--scanners' + scanners: + - vuln + - secret -```yaml -cloud: - # whether to force a cache update for every scan - update-cache: false - - # how old cached results can be before being invalidated - max-cache-age: 24h - - # aws-specific cloud settings - aws: - # the aws region to use - region: us-east-1 - - # the aws endpoint to use (not required for general use) - endpoint: https://my.custom.aws.endpoint - - # the aws account to use (this will be determined from your environment when not set) - account: 123456789012 - - # the aws specific services - service: - - s3 - - ec2 - - # the aws specific arn - arn: arn:aws:s3:::example-bucket - - # skip the aws specific services - skip-service: - - s3 - - ec2 -``` + # Same as '--skip-dirs' + skip-dirs: [] + + # Same as '--skip-files' + skip-files: [] -## Module Options -Available for modules + # Same as '--slow' + slow: false + +``` +## Secret options ```yaml -module: - # Same as '--module-dir' - # Default is '$HOME/.trivy/modules' - dir: $HOME/.trivy/modules +secret: + # Same as '--secret-config' + config: "trivy-secret.yaml" - # Same as '--enable-modules' - # Default is empty - enable-modules: - - trivy-module-spring4shell - - trivy-module-wordpress ``` +## Vulnerability options + +```yaml +vulnerability: + # Same as '--ignore-status' + ignore-status: [] -[example]: https://github.com/aquasecurity/trivy/tree/{{ git.tag }}/examples/trivy-conf/trivy.yaml + # Same as '--ignore-unfixed' + ignore-unfixed: false + + # Same as '--skip-vex-repo-update' + skip-vex-repo-update: false + + # Same as '--vex' + vex: [] + +``` +[example]: https://github.com/aquasecurity/trivy/tree/{{ git.tag }}/examples/trivy-conf/trivy.yaml \ No newline at end of file diff --git a/magefiles/docs.go b/magefiles/docs.go index 1a59007de229..7d09d37e1092 100644 --- a/magefiles/docs.go +++ b/magefiles/docs.go @@ -3,7 +3,11 @@ package main import ( + "cmp" + "fmt" "os" + "slices" + "strings" "github.com/spf13/cobra/doc" @@ -12,6 +16,15 @@ import ( "github.com/aquasecurity/trivy/pkg/log" ) +const ( + title = "Config file" + description = "Trivy can be customized by tweaking a `trivy.yaml` file.\n" + + "The config path can be overridden by the `--config` flag.\n\n" + + "An example is [here][example].\n\n" + + "These samples contain default values for flags." + footer = "[example]: https://github.com/aquasecurity/trivy/tree/{{ git.tag }}/examples/trivy-conf/trivy.yaml" +) + // Generate CLI references func main() { // Set a dummy path for the documents @@ -26,4 +39,116 @@ func main() { if err := doc.GenMarkdownTree(cmd, "./docs/docs/references/configuration/cli"); err != nil { log.Fatal("Fatal error", log.Err(err)) } + if err := generateConfigDocs("./docs/docs/references/configuration/config-file.md"); err != nil { + log.Fatal("Fatal error in config file generation", log.Err(err)) + } +} + +// generateConfigDocs creates markdown file for Trivy config. +func generateConfigDocs(filename string) error { + // remoteFlags should contain Client and Server flags. + // NewClientFlags doesn't initialize `Listen` field + remoteFlags := flag.NewClientFlags() + remoteFlags.Listen = flag.ServerListenFlag.Clone() + + // These flags don't work from config file. + // Clear configName to skip them later. + globalFlags := flag.NewGlobalFlagGroup() + globalFlags.ConfigFile.ConfigName = "" + globalFlags.ShowVersion.ConfigName = "" + globalFlags.GenerateDefaultConfig.ConfigName = "" + + var allFlagGroups = []flag.FlagGroup{ + globalFlags, + flag.NewCacheFlagGroup(), + flag.NewCleanFlagGroup(), + remoteFlags, + flag.NewDBFlagGroup(), + flag.NewImageFlagGroup(), + flag.NewK8sFlagGroup(), + flag.NewLicenseFlagGroup(), + flag.NewMisconfFlagGroup(), + flag.NewModuleFlagGroup(), + flag.NewRegistryFlagGroup(), + flag.NewRegoFlagGroup(), + flag.NewReportFlagGroup(), + flag.NewRepoFlagGroup(), + flag.NewScanFlagGroup(), + flag.NewSecretFlagGroup(), + flag.NewVulnerabilityFlagGroup(), + } + + f, err := os.Create(filename) + if err != nil { + return err + } + defer f.Close() + f.WriteString("# " + title + "\n\n") + f.WriteString(description + "\n") + + for _, group := range allFlagGroups { + f.WriteString("## " + group.Name() + " options\n") + writeFlags(group, f) + } + + f.WriteString(footer) + return nil +} + +func writeFlags(group flag.FlagGroup, w *os.File) { + flags := group.Flags() + // Sort flags to avoid duplicates of non-last parts of config file + slices.SortFunc(flags, func(a, b flag.Flagger) int { + return cmp.Compare(a.GetConfigName(), b.GetConfigName()) + }) + w.WriteString("\n```yaml\n") + + var lastParts []string + for _, flg := range flags { + if flg.GetConfigName() == "" { + continue + } + // We need to split the config name on `.` to make the indentations needed in yaml. + parts := strings.Split(flg.GetConfigName(), ".") + for i := range parts { + // Skip already added part + if len(lastParts) >= i+1 && parts[i] == lastParts[i] { + continue + } + ind := strings.Repeat(" ", i) + // We need to add a comment and example values only for the last part of the config name. + isLastPart := i == len(parts)-1 + if isLastPart { + // Some `Flags` don't support flag for CLI. (e.g.`LicenseForbidden`). + if flg.GetName() != "" { + fmt.Fprintf(w, "%s# Same as '--%s'\n", ind, flg.GetName()) + } + } + w.WriteString(ind + parts[i] + ":") + if isLastPart { + writeFlagValue(flg.GetDefaultValue(), ind, w) + } + w.WriteString("\n") + } + lastParts = parts + } + w.WriteString("```\n") +} + +func writeFlagValue(val any, ind string, w *os.File) { + switch v := val.(type) { + case []string: + if len(v) > 0 { + w.WriteString("\n") + for _, vv := range v { + fmt.Fprintf(w, "%s - %s\n", ind, vv) + } + } else { + w.WriteString(" []\n") + } + case string: + fmt.Fprintf(w, " %q\n", v) + default: + fmt.Fprintf(w, " %v\n", v) + } } diff --git a/pkg/flag/global_flags.go b/pkg/flag/global_flags.go index ebd79bd5a06c..2d20611b8b72 100644 --- a/pkg/flag/global_flags.go +++ b/pkg/flag/global_flags.go @@ -106,7 +106,7 @@ func NewGlobalFlagGroup() *GlobalFlagGroup { } func (f *GlobalFlagGroup) Name() string { - return "global" + return "Global" } func (f *GlobalFlagGroup) Flags() []Flagger { diff --git a/pkg/flag/options.go b/pkg/flag/options.go index e5c46c81c64f..9bbcef79690b 100644 --- a/pkg/flag/options.go +++ b/pkg/flag/options.go @@ -196,6 +196,14 @@ func (f *Flag[T]) GetName() string { return f.Name } +func (f *Flag[T]) GetConfigName() string { + return f.ConfigName +} + +func (f *Flag[T]) GetDefaultValue() any { + return f.Default +} + func (f *Flag[T]) GetAliases() []Alias { return f.Aliases } @@ -302,6 +310,8 @@ type FlagGroup interface { type Flagger interface { GetName() string + GetConfigName() string + GetDefaultValue() any GetAliases() []Alias Parse() error From bb2e26a0ab707b718f6a890cbc87e2492298b6e5 Mon Sep 17 00:00:00 2001 From: Alberto Donato Date: Tue, 6 Aug 2024 02:54:58 +0200 Subject: [PATCH 010/183] fix(terraform): add aws_region name to presets (#7184) --- .../scanners/terraform/parser/parser_test.go | 39 +++++++++++++++++++ pkg/iac/terraform/presets.go | 5 ++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/pkg/iac/scanners/terraform/parser/parser_test.go b/pkg/iac/scanners/terraform/parser/parser_test.go index 10232b007fd9..a754d48d3bb2 100644 --- a/pkg/iac/scanners/terraform/parser/parser_test.go +++ b/pkg/iac/scanners/terraform/parser/parser_test.go @@ -1745,3 +1745,42 @@ func TestTFVarsFileDoesNotExist(t *testing.T) { _, _, err := parser.EvaluateAll(context.TODO()) assert.ErrorContains(t, err, "file does not exist") } + +func Test_AWSRegionNameDefined(t *testing.T) { + + fs := testutil.CreateFS(t, map[string]string{ + "code/test.tf": ` +data "aws_region" "current" {} + +data "aws_region" "other" { + name = "us-east-2" +} + +resource "something" "blah" { + r1 = data.aws_region.current.name + r2 = data.aws_region.other.name +} +`, + }) + + parser := New(fs, "", OptionStopOnHCLError(true)) + require.NoError(t, parser.ParseFS(context.TODO(), "code")) + modules, _, err := parser.EvaluateAll(context.TODO()) + require.NoError(t, err) + require.Len(t, modules, 1) + rootModule := modules[0] + + blocks := rootModule.GetResourcesByType("something") + require.Len(t, blocks, 1) + block := blocks[0] + + r1 := block.GetAttribute("r1") + require.NotNil(t, r1) + assert.True(t, r1.IsResolvable()) + assert.Equal(t, "current-region", r1.Value().AsString()) + + r2 := block.GetAttribute("r2") + require.NotNil(t, r2) + assert.True(t, r2.IsResolvable()) + assert.Equal(t, "us-east-2", r2.Value().AsString()) +} diff --git a/pkg/iac/terraform/presets.go b/pkg/iac/terraform/presets.go index d10d795a86d7..b29a5fc9c181 100644 --- a/pkg/iac/terraform/presets.go +++ b/pkg/iac/terraform/presets.go @@ -19,13 +19,16 @@ func createPresetValues(b *Block) map[string]cty.Value { presets["arn"] = cty.StringVal(b.ID()) } - // workaround for weird iam feature switch b.TypeLabel() { + // workaround for weird iam feature case "aws_iam_policy_document": presets["json"] = cty.StringVal(b.ID()) // If the user leaves the name blank, Terraform will automatically generate a unique name case "aws_launch_template": presets["name"] = cty.StringVal(uuid.New().String()) + // allow referencing the current region name + case "aws_region": + presets["name"] = cty.StringVal("current-region") } return presets From 85dadf56265647c000191561db10b08a4948c140 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Tue, 6 Aug 2024 11:13:28 +0700 Subject: [PATCH 011/183] perf(misconf): do not convert contents of a YAML file to string (#7292) Signed-off-by: nikpivkin --- pkg/iac/detection/detect.go | 10 +++++----- pkg/iac/scanners/yaml/parser/parser.go | 11 +++++------ 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/pkg/iac/detection/detect.go b/pkg/iac/detection/detect.go index 787b82cb0b6a..6a7eb1f8ca3d 100644 --- a/pkg/iac/detection/detect.go +++ b/pkg/iac/detection/detect.go @@ -221,15 +221,15 @@ func init() { } data := buf.Bytes() - marker := "\n---\n" - altMarker := "\r\n---\r\n" - if bytes.Contains(data, []byte(altMarker)) { + marker := []byte("\n---\n") + altMarker := []byte("\r\n---\r\n") + if bytes.Contains(data, altMarker) { marker = altMarker } - for _, partial := range strings.Split(string(data), marker) { + for _, partial := range bytes.Split(data, marker) { var result map[string]any - if err := yaml.Unmarshal([]byte(partial), &result); err != nil { + if err := yaml.Unmarshal(partial, &result); err != nil { continue } match := true diff --git a/pkg/iac/scanners/yaml/parser/parser.go b/pkg/iac/scanners/yaml/parser/parser.go index d8b50faf2437..febcfb100008 100644 --- a/pkg/iac/scanners/yaml/parser/parser.go +++ b/pkg/iac/scanners/yaml/parser/parser.go @@ -6,7 +6,6 @@ import ( "io" "io/fs" "path/filepath" - "strings" "gopkg.in/yaml.v3" @@ -77,15 +76,15 @@ func (p *Parser) ParseFile(_ context.Context, fsys fs.FS, path string) ([]any, e var results []any - marker := "\n---\n" - altMarker := "\r\n---\r\n" - if bytes.Contains(contents, []byte(altMarker)) { + marker := []byte("\n---\n") + altMarker := []byte("\r\n---\r\n") + if bytes.Contains(contents, altMarker) { marker = altMarker } - for _, partial := range strings.Split(string(contents), marker) { + for _, partial := range bytes.Split(contents, marker) { var target any - if err := yaml.Unmarshal([]byte(partial), &target); err != nil { + if err := yaml.Unmarshal(partial, &target); err != nil { return nil, err } results = append(results, target) From 13789b718d50df967ca3e3142a1a3295af750642 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Tue, 6 Aug 2024 11:14:06 +0700 Subject: [PATCH 012/183] refactor(misconf): remove unused universal scanner (#7293) Signed-off-by: nikpivkin --- pkg/iac/scanners/universal/scanner.go | 63 --------------------------- 1 file changed, 63 deletions(-) delete mode 100644 pkg/iac/scanners/universal/scanner.go diff --git a/pkg/iac/scanners/universal/scanner.go b/pkg/iac/scanners/universal/scanner.go deleted file mode 100644 index 3687da85fc3d..000000000000 --- a/pkg/iac/scanners/universal/scanner.go +++ /dev/null @@ -1,63 +0,0 @@ -package universal - -import ( - "context" - "io/fs" - - "github.com/aquasecurity/trivy/pkg/iac/scan" - "github.com/aquasecurity/trivy/pkg/iac/scanners" - "github.com/aquasecurity/trivy/pkg/iac/scanners/azure/arm" - "github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation" - "github.com/aquasecurity/trivy/pkg/iac/scanners/dockerfile" - "github.com/aquasecurity/trivy/pkg/iac/scanners/helm" - "github.com/aquasecurity/trivy/pkg/iac/scanners/json" - "github.com/aquasecurity/trivy/pkg/iac/scanners/kubernetes" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" - "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform" - "github.com/aquasecurity/trivy/pkg/iac/scanners/toml" - "github.com/aquasecurity/trivy/pkg/iac/scanners/yaml" -) - -type nestableFSScanners interface { - scanners.FSScanner - options.ConfigurableScanner -} - -var _ scanners.FSScanner = (*Scanner)(nil) - -type Scanner struct { - fsScanners []nestableFSScanners -} - -func New(opts ...options.ScannerOption) *Scanner { - s := &Scanner{ - fsScanners: []nestableFSScanners{ - terraform.New(opts...), - cloudformation.New(opts...), - dockerfile.NewScanner(opts...), - kubernetes.NewScanner(opts...), - json.NewScanner(opts...), - yaml.NewScanner(opts...), - toml.NewScanner(opts...), - helm.New(opts...), - arm.New(opts...), - }, - } - return s -} - -func (s *Scanner) Name() string { - return "Universal" -} - -func (s *Scanner) ScanFS(ctx context.Context, fsys fs.FS, dir string) (scan.Results, error) { - var results scan.Results - for _, inner := range s.fsScanners { - innerResults, err := inner.ScanFS(ctx, fsys, dir) - if err != nil { - return nil, err - } - results = append(results, innerResults...) - } - return results, nil -} From c766831069e188226efafeec184e41498685ed85 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Wed, 7 Aug 2024 00:06:24 +0700 Subject: [PATCH 013/183] perf(misconf): use json.Valid to check validity of JSON (#7308) Signed-off-by: nikpivkin --- pkg/iac/detection/detect.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/iac/detection/detect.go b/pkg/iac/detection/detect.go index 6a7eb1f8ca3d..cec90a79cdca 100644 --- a/pkg/iac/detection/detect.go +++ b/pkg/iac/detection/detect.go @@ -45,8 +45,8 @@ func init() { return true } - var content any - return json.NewDecoder(r).Decode(&content) == nil + b, err := io.ReadAll(r) + return err == nil && json.Valid(b) } matchers[FileTypeYAML] = func(name string, r io.ReadSeeker) bool { From a4180bddd43d86e479edf0afe0c362021d071482 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Wed, 7 Aug 2024 00:29:16 +0700 Subject: [PATCH 014/183] fix(misconf): load only submodule if it is specified in source (#7112) Signed-off-by: nikpivkin --- .../terraform/parser/resolvers/cache.go | 4 +- .../resolvers/cache_integration_test.go | 19 +++++---- .../terraform/parser/resolvers/registry.go | 2 +- .../terraform/parser/resolvers/remote.go | 4 +- .../terraform/parser/resolvers/source.go | 7 ++-- .../terraform/parser/resolvers/source_test.go | 42 +++++++++++-------- 6 files changed, 45 insertions(+), 33 deletions(-) diff --git a/pkg/iac/scanners/terraform/parser/resolvers/cache.go b/pkg/iac/scanners/terraform/parser/resolvers/cache.go index e08c43ff3ba0..c8b2f660ed33 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/cache.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/cache.go @@ -51,7 +51,7 @@ func (r *cacheResolver) Resolve(_ context.Context, _ fs.FS, opt Options) (filesy return nil, "", "", false, nil } - src := removeSubdirFromSource(opt.Source) + src, subdir := splitPackageSubdirRaw(opt.Source) key := cacheKey(src, opt.Version) opt.Debug("Trying to resolve: %s", key) @@ -62,7 +62,7 @@ func (r *cacheResolver) Resolve(_ context.Context, _ fs.FS, opt Options) (filesy return nil, "", "", true, err } - return os.DirFS(filepath.Join(cacheDir, key)), opt.OriginalSource, ".", true, nil + return os.DirFS(filepath.Join(cacheDir, key)), opt.OriginalSource, subdir, true, nil } return nil, "", "", false, nil } diff --git a/pkg/iac/scanners/terraform/parser/resolvers/cache_integration_test.go b/pkg/iac/scanners/terraform/parser/resolvers/cache_integration_test.go index a7c6704b6708..43ad7f06b15b 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/cache_integration_test.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/cache_integration_test.go @@ -21,9 +21,10 @@ func TestResolveModuleFromCache(t *testing.T) { } tests := []struct { - name string - opts resolvers.Options - firstResolver moduleResolver + name string + opts resolvers.Options + firstResolver moduleResolver + expectedSubdir string }{ { name: "registry", @@ -32,7 +33,8 @@ func TestResolveModuleFromCache(t *testing.T) { Source: "terraform-aws-modules/s3-bucket/aws", Version: "4.1.2", }, - firstResolver: resolvers.Registry, + firstResolver: resolvers.Registry, + expectedSubdir: ".", }, { name: "registry with subdir", @@ -41,7 +43,8 @@ func TestResolveModuleFromCache(t *testing.T) { Source: "terraform-aws-modules/s3-bucket/aws//modules/object", Version: "4.1.2", }, - firstResolver: resolvers.Registry, + firstResolver: resolvers.Registry, + expectedSubdir: "modules/object", }, { name: "remote", @@ -49,7 +52,8 @@ func TestResolveModuleFromCache(t *testing.T) { Name: "bucket", Source: "git::https://github.com/terraform-aws-modules/terraform-aws-s3-bucket.git?ref=v4.1.2", }, - firstResolver: resolvers.Remote, + firstResolver: resolvers.Remote, + expectedSubdir: ".", }, { name: "remote with subdir", @@ -57,7 +61,8 @@ func TestResolveModuleFromCache(t *testing.T) { Name: "object", Source: "git::https://github.com/terraform-aws-modules/terraform-aws-s3-bucket.git//modules/object?ref=v4.1.2", }, - firstResolver: resolvers.Remote, + firstResolver: resolvers.Remote, + expectedSubdir: "modules/object", }, } diff --git a/pkg/iac/scanners/terraform/parser/resolvers/registry.go b/pkg/iac/scanners/terraform/parser/resolvers/registry.go index bcdd4734974a..8f2ab2ecdde1 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/registry.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/registry.go @@ -45,7 +45,7 @@ func (r *registryResolver) Resolve(ctx context.Context, target fs.FS, opt Option } inputVersion := opt.Version - source := removeSubdirFromSource(opt.Source) + source, _ := splitPackageSubdirRaw(opt.Source) parts := strings.Split(source, "/") if len(parts) < 3 || len(parts) > 4 { return diff --git a/pkg/iac/scanners/terraform/parser/resolvers/remote.go b/pkg/iac/scanners/terraform/parser/resolvers/remote.go index df94c775da78..790b3509fd33 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/remote.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/remote.go @@ -38,7 +38,7 @@ func (r *remoteResolver) Resolve(ctx context.Context, _ fs.FS, opt Options) (fil return nil, "", "", false, nil } - src := removeSubdirFromSource(opt.OriginalSource) + src, subdir := splitPackageSubdirRaw(opt.OriginalSource) key := cacheKey(src, opt.OriginalVersion) opt.Debug("Storing with cache key %s", key) @@ -54,7 +54,7 @@ func (r *remoteResolver) Resolve(ctx context.Context, _ fs.FS, opt Options) (fil r.incrementCount(opt) opt.Debug("Successfully downloaded %s from %s", opt.Name, opt.Source) opt.Debug("Module '%s' resolved via remote download.", opt.Name) - return os.DirFS(cacheDir), opt.Source, filepath.Join(".", opt.RelativePath), true, nil + return os.DirFS(cacheDir), opt.Source, subdir, true, nil } func (r *remoteResolver) download(ctx context.Context, opt Options, dst string) error { diff --git a/pkg/iac/scanners/terraform/parser/resolvers/source.go b/pkg/iac/scanners/terraform/parser/resolvers/source.go index d7637ffaf8a5..ee5662d6c7d0 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/source.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/source.go @@ -2,7 +2,7 @@ package resolvers import "strings" -func removeSubdirFromSource(src string) string { +func splitPackageSubdirRaw(src string) (string, string) { stop := len(src) if idx := strings.Index(src, "?"); idx > -1 { stop = idx @@ -18,7 +18,7 @@ func removeSubdirFromSource(src string) string { // First see if we even have an explicit subdir idx := strings.Index(src[offset:stop], "//") if idx == -1 { - return src + return src, "." } idx += offset @@ -29,8 +29,9 @@ func removeSubdirFromSource(src string) string { // URL. if idx = strings.Index(subdir, "?"); idx > -1 { query := subdir[idx:] + subdir = subdir[:idx] src += query } - return src + return src, subdir } diff --git a/pkg/iac/scanners/terraform/parser/resolvers/source_test.go b/pkg/iac/scanners/terraform/parser/resolvers/source_test.go index 3f57ab68b6d3..46df7db700dc 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/source_test.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/source_test.go @@ -6,39 +6,45 @@ import ( "github.com/stretchr/testify/assert" ) -func TestRemoveSubdirFromSource(t *testing.T) { +func TestSplitPackageSubdirRaw(t *testing.T) { tests := []struct { - name string - source string - expected string + name string + source string + expectedPkg string + expectedSubdir string }{ { - name: "address with scheme and query string", - source: "git::https://github.com/aquasecurity/terraform-modules.git//modules/ecs-service?ref=v0.1.0", - expected: "git::https://github.com/aquasecurity/terraform-modules.git?ref=v0.1.0", + name: "address with scheme and query string", + source: "git::https://github.com/aquasecurity/terraform-modules.git//modules/ecs-service?ref=v0.1.0", + expectedPkg: "git::https://github.com/aquasecurity/terraform-modules.git?ref=v0.1.0", + expectedSubdir: "modules/ecs-service", }, { - name: "address with scheme", - source: "git::https://github.com/aquasecurity/terraform-modules.git//modules/ecs-service", - expected: "git::https://github.com/aquasecurity/terraform-modules.git", + name: "address with scheme", + source: "git::https://github.com/aquasecurity/terraform-modules.git//modules/ecs-service", + expectedPkg: "git::https://github.com/aquasecurity/terraform-modules.git", + expectedSubdir: "modules/ecs-service", }, { - name: "registry address", - source: "hashicorp/consul/aws//modules/consul-cluster", - expected: "hashicorp/consul/aws", + name: "registry address", + source: "hashicorp/consul/aws//modules/consul-cluster", + expectedPkg: "hashicorp/consul/aws", + expectedSubdir: "modules/consul-cluster", }, { - name: "without subdir", - source: `hashicorp/consul/aws`, - expected: `hashicorp/consul/aws`, + name: "without subdir", + source: `hashicorp/consul/aws`, + expectedPkg: `hashicorp/consul/aws`, + expectedSubdir: ".", }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got := removeSubdirFromSource(test.source) - assert.Equal(t, test.expected, got) + pkgAddr, subdir := splitPackageSubdirRaw(test.source) + assert.Equal(t, test.expectedPkg, pkgAddr) + assert.Equal(t, test.expectedSubdir, subdir) }) } } From a817fae85b7272b391b737ec86673a7cab722bae Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Wed, 7 Aug 2024 06:42:31 +0700 Subject: [PATCH 015/183] feat(misconf): support for policy and bucket grants (#7284) Signed-off-by: nikpivkin --- .../adapters/cloudformation/aws/s3/bucket.go | 35 ++++++++++++ .../adapters/cloudformation/aws/s3/s3_test.go | 33 ++++++++++++ .../adapters/terraform/aws/s3/adapt_test.go | 54 +++++++++++++++++++ pkg/iac/adapters/terraform/aws/s3/bucket.go | 50 +++++++++++++++++ pkg/iac/providers/aws/s3/bucket.go | 13 +++++ pkg/iac/rego/schemas/cloud.json | 44 +++++++++++++++ 6 files changed, 229 insertions(+) diff --git a/pkg/iac/adapters/cloudformation/aws/s3/bucket.go b/pkg/iac/adapters/cloudformation/aws/s3/bucket.go index 5f5329fc6714..ec56894dbee4 100644 --- a/pkg/iac/adapters/cloudformation/aws/s3/bucket.go +++ b/pkg/iac/adapters/cloudformation/aws/s3/bucket.go @@ -7,7 +7,9 @@ import ( "strings" s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" + "github.com/liamg/iamgo" + "github.com/aquasecurity/trivy/pkg/iac/providers/aws/iam" "github.com/aquasecurity/trivy/pkg/iac/providers/aws/s3" "github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation/parser" iacTypes "github.com/aquasecurity/trivy/pkg/iac/types" @@ -37,6 +39,7 @@ func getBuckets(cfFile parser.FileContext) []s3.Bucket { Website: getWebsite(r), BucketLocation: iacTypes.String("", r.Metadata()), Objects: nil, + BucketPolicies: getBucketPolicies(cfFile, r), } buckets = append(buckets, s3b) @@ -156,3 +159,35 @@ func getWebsite(r *parser.Resource) *s3.Website { } } } + +func getBucketPolicies(fctx parser.FileContext, r *parser.Resource) []iam.Policy { + + var policies []iam.Policy + for _, bucketPolicy := range fctx.GetResourcesByType("AWS::S3::BucketPolicy") { + bucket := bucketPolicy.GetStringProperty("Bucket") + if bucket.NotEqualTo(r.GetStringProperty("BucketName").Value()) && bucket.NotEqualTo(r.ID()) { + continue + } + + doc := bucketPolicy.GetProperty("PolicyDocument") + if doc.IsNil() { + continue + } + + parsed, err := iamgo.Parse(doc.GetJsonBytes()) + if err != nil { + continue + } + policies = append(policies, iam.Policy{ + Metadata: doc.Metadata(), + Name: iacTypes.StringDefault("", doc.Metadata()), + Document: iam.Document{ + Metadata: doc.Metadata(), + Parsed: *parsed, + }, + Builtin: iacTypes.Bool(false, doc.Metadata()), + }) + } + + return policies +} diff --git a/pkg/iac/adapters/cloudformation/aws/s3/s3_test.go b/pkg/iac/adapters/cloudformation/aws/s3/s3_test.go index ee8fffb39f75..707aae028f7f 100644 --- a/pkg/iac/adapters/cloudformation/aws/s3/s3_test.go +++ b/pkg/iac/adapters/cloudformation/aws/s3/s3_test.go @@ -3,7 +3,10 @@ package s3 import ( "testing" + "github.com/liamg/iamgo" + "github.com/aquasecurity/trivy/pkg/iac/adapters/cloudformation/testutil" + "github.com/aquasecurity/trivy/pkg/iac/providers/aws/iam" "github.com/aquasecurity/trivy/pkg/iac/providers/aws/s3" "github.com/aquasecurity/trivy/pkg/iac/types" ) @@ -57,6 +60,19 @@ Resources: Status: Enabled WebsiteConfiguration: IndexDocument: index.html + SampleBucketPolicy: + Type: AWS::S3::BucketPolicy + Properties: + Bucket: !Ref Bucket + PolicyDocument: + Version: 2012-10-17 + Statement: + - Action: + - 's3:GetObject' + Effect: Allow + Resource: !Join + - 'arn:aws:s3:::testbucket/*' + Principal: '*' `, expected: s3.S3{ Buckets: []s3.Bucket{ @@ -91,6 +107,23 @@ Resources: Enabled: types.BoolTest(true), }, Website: &s3.Website{}, + BucketPolicies: []iam.Policy{ + { + Document: iam.Document{ + Parsed: iamgo.NewPolicyBuilder(). + WithStatement( + iamgo.NewStatementBuilder(). + WithActions([]string{"s3:GetObject"}). + WithAllPrincipals(true). + WithEffect("Allow"). + WithResources([]string{"arn:aws:s3:::testbucket/*"}). + Build(), + ). + WithVersion("2012-10-17T00:00:00Z"). + Build(), + }, + }, + }, }, }, }, diff --git a/pkg/iac/adapters/terraform/aws/s3/adapt_test.go b/pkg/iac/adapters/terraform/aws/s3/adapt_test.go index 1cd1dec76270..ea12206f312b 100644 --- a/pkg/iac/adapters/terraform/aws/s3/adapt_test.go +++ b/pkg/iac/adapters/terraform/aws/s3/adapt_test.go @@ -149,6 +149,15 @@ func Test_Adapt(t *testing.T) { resource "aws_s3_bucket_acl" "example" { bucket = aws_s3_bucket.example.id acl = "private" + access_control_policy { + grant { + grantee { + type = "Group" + uri = "http://acs.amazonaws.com/groups/s3/LogDelivery" + } + permission = "READ_ACP" + } + } } resource "aws_s3_bucket_server_side_encryption_configuration" "example" { @@ -250,6 +259,51 @@ func Test_Adapt(t *testing.T) { TargetBucket: iacTypes.String("aws_s3_bucket.example", iacTypes.NewTestMetadata()), }, ACL: iacTypes.String("private", iacTypes.NewTestMetadata()), + Grants: []s3.Grant{ + { + Metadata: iacTypes.NewTestMetadata(), + Grantee: s3.Grantee{ + Type: iacTypes.StringTest("Group"), + URI: iacTypes.StringTest("http://acs.amazonaws.com/groups/s3/LogDelivery"), + }, + Permissions: iacTypes.StringValueList{ + iacTypes.StringTest("READ_ACP"), + }, + }, + }, + }, + }, + }, + }, + { + name: "bucket with grants", + terraform: ` +resource "aws_s3_bucket" "this" { + bucket = "test" + + grant { + type = "Group" + uri = "http://acs.amazonaws.com/groups/s3/LogDelivery" + permissions = ["FULL_CONTROL"] + } +} +`, + expected: s3.S3{ + Buckets: []s3.Bucket{ + { + Name: iacTypes.StringTest("test"), + ACL: iacTypes.StringTest("private"), + Grants: []s3.Grant{ + { + Grantee: s3.Grantee{ + Type: iacTypes.StringTest("Group"), + URI: iacTypes.StringTest("http://acs.amazonaws.com/groups/s3/LogDelivery"), + }, + Permissions: iacTypes.StringValueList{ + iacTypes.StringTest("FULL_CONTROL"), + }, + }, + }, }, }, }, diff --git a/pkg/iac/adapters/terraform/aws/s3/bucket.go b/pkg/iac/adapters/terraform/aws/s3/bucket.go index 5ecf7e9ba21b..206b0cbdabdf 100644 --- a/pkg/iac/adapters/terraform/aws/s3/bucket.go +++ b/pkg/iac/adapters/terraform/aws/s3/bucket.go @@ -26,6 +26,7 @@ func (a *adapter) adaptBuckets() []s3.Bucket { Versioning: getVersioning(block, a), Logging: getLogging(block, a), ACL: getBucketAcl(block, a), + Grants: getGrants(block, a), AccelerateConfigurationStatus: getAccelerateStatus(block, a), BucketLocation: block.GetAttribute("region").AsStringValueOrDefault("", block), LifecycleConfiguration: getLifecycle(block, a), @@ -193,6 +194,55 @@ func getBucketAcl(block *terraform.Block, a *adapter) iacTypes.StringValue { return iacTypes.StringDefault("private", block.GetMetadata()) } +func getGrants(block *terraform.Block, a *adapter) []s3.Grant { + if val, ok := applyForBucketRelatedResource(a, block, "aws_s3_bucket_acl", func(resource *terraform.Block) []s3.Grant { + var grants []s3.Grant + + if acessControlPolicy := resource.GetBlock("access_control_policy"); acessControlPolicy.IsNotNil() { + for _, grantBlock := range acessControlPolicy.GetBlocks("grant") { + grant := s3.Grant{ + Metadata: grantBlock.GetMetadata(), + Permissions: iacTypes.StringValueList{ + grantBlock.GetAttribute("permission").AsStringValueOrDefault("", grantBlock), + }, + } + + if granteeBlock := grantBlock.GetBlock("grantee"); granteeBlock.IsNotNil() { + grant.Grantee = s3.Grantee{ + Metadata: granteeBlock.GetMetadata(), + Type: granteeBlock.GetAttribute("type").AsStringValueOrDefault("", granteeBlock), + URI: granteeBlock.GetAttribute("uri").AsStringValueOrDefault("", granteeBlock), + } + } + + grants = append(grants, grant) + } + } + + return grants + + }); ok { + return val + } + + var grants []s3.Grant + for _, grantBlock := range block.GetBlocks("grant") { + grant := s3.Grant{ + Metadata: grantBlock.GetMetadata(), + Permissions: grantBlock.GetAttribute("permissions").AsStringValueSliceOrEmpty(), + Grantee: s3.Grantee{ + Metadata: grantBlock.GetMetadata(), + Type: grantBlock.GetAttribute("type").AsStringValueOrDefault("", grantBlock), + URI: grantBlock.GetAttribute("uri").AsStringValueOrDefault("", grantBlock), + }, + } + + grants = append(grants, grant) + } + + return grants +} + func isEncrypted(sseConfgihuration *terraform.Block) iacTypes.BoolValue { return terraform.MapNestedAttribute( sseConfgihuration, diff --git a/pkg/iac/providers/aws/s3/bucket.go b/pkg/iac/providers/aws/s3/bucket.go index e884bbd4a7ff..ccabe6974c99 100755 --- a/pkg/iac/providers/aws/s3/bucket.go +++ b/pkg/iac/providers/aws/s3/bucket.go @@ -14,6 +14,7 @@ type Bucket struct { Versioning Versioning Logging Logging ACL iacTypes.StringValue + Grants []Grant BucketLocation iacTypes.StringValue AccelerateConfigurationStatus iacTypes.StringValue LifecycleConfiguration []Rules @@ -65,3 +66,15 @@ type Contents struct { type Website struct { Metadata iacTypes.Metadata } + +type Grant struct { + Metadata iacTypes.Metadata + Grantee Grantee + Permissions iacTypes.StringValueList +} + +type Grantee struct { + Metadata iacTypes.Metadata + URI iacTypes.StringValue + Type iacTypes.StringValue +} diff --git a/pkg/iac/rego/schemas/cloud.json b/pkg/iac/rego/schemas/cloud.json index ad81b6488ae8..a4bab9423d38 100644 --- a/pkg/iac/rego/schemas/cloud.json +++ b/pkg/iac/rego/schemas/cloud.json @@ -3647,6 +3647,13 @@ "type": "object", "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.aws.s3.Encryption" }, + "grants": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.aws.s3.Grant" + } + }, "lifecycleconfiguration": { "type": "array", "items": { @@ -3713,6 +3720,43 @@ } } }, + "github.com.aquasecurity.trivy.pkg.iac.providers.aws.s3.Grant": { + "type": "object", + "properties": { + "__defsec_metadata": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.Metadata" + }, + "grantee": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.aws.s3.Grantee" + }, + "permissions": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue" + } + } + } + }, + "github.com.aquasecurity.trivy.pkg.iac.providers.aws.s3.Grantee": { + "type": "object", + "properties": { + "__defsec_metadata": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.Metadata" + }, + "type": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue" + }, + "uri": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue" + } + } + }, "github.com.aquasecurity.trivy.pkg.iac.providers.aws.s3.Logging": { "type": "object", "properties": { From f0ed5e4ced7e60af35c88d5d084aa4b7237f4973 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Wed, 7 Aug 2024 07:11:59 +0700 Subject: [PATCH 016/183] fix(misconf): do not set default value for default_cache_behavior (#7234) Signed-off-by: nikpivkin --- pkg/iac/adapters/terraform/aws/cloudfront/adapt.go | 6 +++--- pkg/iac/adapters/terraform/aws/cloudfront/adapt_test.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/iac/adapters/terraform/aws/cloudfront/adapt.go b/pkg/iac/adapters/terraform/aws/cloudfront/adapt.go index a981241a83a4..721ecf991d55 100644 --- a/pkg/iac/adapters/terraform/aws/cloudfront/adapt.go +++ b/pkg/iac/adapters/terraform/aws/cloudfront/adapt.go @@ -33,7 +33,7 @@ func adaptDistribution(resource *terraform.Block) cloudfront.Distribution { }, DefaultCacheBehaviour: cloudfront.CacheBehaviour{ Metadata: resource.GetMetadata(), - ViewerProtocolPolicy: types.String("allow-all", resource.GetMetadata()), + ViewerProtocolPolicy: types.StringDefault("", resource.GetMetadata()), }, OrdererCacheBehaviours: nil, ViewerCertificate: cloudfront.ViewerCertificate{ @@ -53,13 +53,13 @@ func adaptDistribution(resource *terraform.Block) cloudfront.Distribution { if defaultCacheBlock := resource.GetBlock("default_cache_behavior"); defaultCacheBlock.IsNotNil() { distribution.DefaultCacheBehaviour.Metadata = defaultCacheBlock.GetMetadata() viewerProtocolPolicyAttr := defaultCacheBlock.GetAttribute("viewer_protocol_policy") - distribution.DefaultCacheBehaviour.ViewerProtocolPolicy = viewerProtocolPolicyAttr.AsStringValueOrDefault("allow-all", defaultCacheBlock) + distribution.DefaultCacheBehaviour.ViewerProtocolPolicy = viewerProtocolPolicyAttr.AsStringValueOrDefault("", defaultCacheBlock) } orderedCacheBlocks := resource.GetBlocks("ordered_cache_behavior") for _, orderedCacheBlock := range orderedCacheBlocks { viewerProtocolPolicyAttr := orderedCacheBlock.GetAttribute("viewer_protocol_policy") - viewerProtocolPolicyVal := viewerProtocolPolicyAttr.AsStringValueOrDefault("allow-all", orderedCacheBlock) + viewerProtocolPolicyVal := viewerProtocolPolicyAttr.AsStringValueOrDefault("", orderedCacheBlock) distribution.OrdererCacheBehaviours = append(distribution.OrdererCacheBehaviours, cloudfront.CacheBehaviour{ Metadata: orderedCacheBlock.GetMetadata(), ViewerProtocolPolicy: viewerProtocolPolicyVal, diff --git a/pkg/iac/adapters/terraform/aws/cloudfront/adapt_test.go b/pkg/iac/adapters/terraform/aws/cloudfront/adapt_test.go index d20520cd4651..fd1bf65e9cc5 100644 --- a/pkg/iac/adapters/terraform/aws/cloudfront/adapt_test.go +++ b/pkg/iac/adapters/terraform/aws/cloudfront/adapt_test.go @@ -83,7 +83,7 @@ func Test_adaptDistribution(t *testing.T) { }, DefaultCacheBehaviour: cloudfront.CacheBehaviour{ Metadata: iacTypes.NewTestMetadata(), - ViewerProtocolPolicy: iacTypes.String("allow-all", iacTypes.NewTestMetadata()), + ViewerProtocolPolicy: iacTypes.String("", iacTypes.NewTestMetadata()), }, ViewerCertificate: cloudfront.ViewerCertificate{ From fe9207255a4f7f984ec1447f8a9219ae60e560c4 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Wed, 7 Aug 2024 07:33:56 +0700 Subject: [PATCH 017/183] feat(misconf): iterator argument support for dynamic blocks (#7236) Signed-off-by: nikpivkin Co-authored-by: simar7 <1254783+simar7@users.noreply.github.com> --- .../scanners/terraform/parser/evaluator.go | 12 +++++++ .../scanners/terraform/parser/parser_test.go | 36 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/pkg/iac/scanners/terraform/parser/evaluator.go b/pkg/iac/scanners/terraform/parser/evaluator.go index bf3e4f4ffc13..0e26103e8c96 100644 --- a/pkg/iac/scanners/terraform/parser/evaluator.go +++ b/pkg/iac/scanners/terraform/parser/evaluator.go @@ -340,6 +340,18 @@ func (e *evaluator) expandBlockForEaches(blocks terraform.Blocks, isDynamic bool ctx.Set(idx, block.TypeLabel(), "key") ctx.Set(val, block.TypeLabel(), "value") + if isDynamic { + if iterAttr := block.GetAttribute("iterator"); iterAttr.IsNotNil() { + refs := iterAttr.AllReferences() + if len(refs) == 1 { + ctx.Set(idx, refs[0].TypeLabel(), "key") + ctx.Set(val, refs[0].TypeLabel(), "value") + } else { + e.debug.Log("Ignoring iterator attribute in dynamic block, expected one reference but got %d", len(refs)) + } + } + } + forEachFiltered = append(forEachFiltered, clone) values := clone.Values() diff --git a/pkg/iac/scanners/terraform/parser/parser_test.go b/pkg/iac/scanners/terraform/parser/parser_test.go index a754d48d3bb2..e7a8041aa7ff 100644 --- a/pkg/iac/scanners/terraform/parser/parser_test.go +++ b/pkg/iac/scanners/terraform/parser/parser_test.go @@ -1746,6 +1746,42 @@ func TestTFVarsFileDoesNotExist(t *testing.T) { assert.ErrorContains(t, err, "file does not exist") } +func TestDynamicWithIterator(t *testing.T) { + fsys := fstest.MapFS{ + "main.tf": &fstest.MapFile{ + Data: []byte(`resource "aws_s3_bucket" "this" { + dynamic versioning { + for_each = [true] + iterator = ver + + content { + enabled = ver.value + } + } +}`), + }, + } + + parser := New( + fsys, "", + OptionStopOnHCLError(true), + OptionWithDownloads(false), + ) + require.NoError(t, parser.ParseFS(context.TODO(), ".")) + + modules, _, err := parser.EvaluateAll(context.TODO()) + require.NoError(t, err) + + assert.Len(t, modules, 1) + + buckets := modules.GetResourcesByType("aws_s3_bucket") + assert.Len(t, buckets, 1) + + attr, _ := buckets[0].GetNestedAttribute("versioning.enabled") + + assert.True(t, attr.Value().True()) +} + func Test_AWSRegionNameDefined(t *testing.T) { fs := testutil.CreateFS(t, map[string]string{ From ac3eb9d59cd43c707975bf39b455536bb99928e0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 7 Aug 2024 10:51:29 +0400 Subject: [PATCH 018/183] chore(deps): bump the common group across 1 directory with 7 updates (#7305) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 34 ++++++++++++------------ go.sum | 81 +++++++++++++++++++++++++++++----------------------------- 2 files changed, 57 insertions(+), 58 deletions(-) diff --git a/go.mod b/go.mod index 70277514b22a..ac6f232878bc 100644 --- a/go.mod +++ b/go.mod @@ -32,9 +32,9 @@ require ( github.com/aws/aws-sdk-go-v2 v1.30.3 github.com/aws/aws-sdk-go-v2/config v1.27.27 github.com/aws/aws-sdk-go-v2/credentials v1.17.27 - github.com/aws/aws-sdk-go-v2/service/ec2 v1.172.0 - github.com/aws/aws-sdk-go-v2/service/ecr v1.30.3 - github.com/aws/aws-sdk-go-v2/service/s3 v1.58.2 + github.com/aws/aws-sdk-go-v2/service/ec2 v1.173.0 + github.com/aws/aws-sdk-go-v2/service/ecr v1.31.0 + github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3 github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect github.com/aws/smithy-go v1.20.3 github.com/bitnami/go-version v0.0.0-20231130084017-bb00604d650c @@ -62,7 +62,7 @@ require ( github.com/hashicorp/go-uuid v1.0.3 github.com/hashicorp/go-version v1.7.0 github.com/hashicorp/golang-lru/v2 v2.0.7 - github.com/hashicorp/hc-install v0.7.0 + github.com/hashicorp/hc-install v0.8.0 github.com/hashicorp/hcl/v2 v2.21.0 github.com/hashicorp/terraform-exec v0.21.0 github.com/in-toto/in-toto-golang v0.9.0 @@ -88,7 +88,7 @@ require ( github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/mitchellh/mapstructure v1.5.0 github.com/moby/buildkit v0.15.1 - github.com/open-policy-agent/opa v0.66.0 + github.com/open-policy-agent/opa v0.67.0 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 github.com/openvex/discovery v0.1.0 @@ -119,9 +119,9 @@ require ( go.etcd.io/bbolt v1.3.10 golang.org/x/crypto v0.25.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect - golang.org/x/mod v0.19.0 + golang.org/x/mod v0.20.0 golang.org/x/net v0.27.0 - golang.org/x/sync v0.7.0 + golang.org/x/sync v0.8.0 golang.org/x/term v0.22.0 golang.org/x/text v0.16.0 golang.org/x/vuln v1.1.3 @@ -184,7 +184,7 @@ require ( github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/blang/semver v3.5.1+incompatible // indirect github.com/briandowns/spinner v1.23.0 // indirect - github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect github.com/cloudflare/circl v1.3.7 // indirect github.com/containerd/cgroups/v3 v3.0.2 // indirect @@ -261,7 +261,6 @@ require ( github.com/gorilla/websocket v1.5.0 // indirect github.com/gosuri/uitable v0.0.4 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/go-cleanhttp v0.5.2 // indirect github.com/hashicorp/go-safetemp v1.0.0 // indirect @@ -368,12 +367,11 @@ require ( go.mongodb.org/mongo-driver v1.14.0 // indirect go.opencensus.io v0.24.0 // indirect go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 // indirect - go.opentelemetry.io/otel v1.27.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 // indirect - go.opentelemetry.io/otel/metric v1.27.0 // indirect - go.opentelemetry.io/otel/sdk v1.27.0 // indirect - go.opentelemetry.io/otel/trace v1.27.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect + go.opentelemetry.io/otel v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.28.0 // indirect + go.opentelemetry.io/otel/sdk v1.28.0 // indirect + go.opentelemetry.io/otel/trace v1.28.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect @@ -384,9 +382,9 @@ require ( golang.org/x/tools v0.23.0 // indirect google.golang.org/api v0.172.0 // indirect google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 // indirect - google.golang.org/grpc v1.64.1 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect + google.golang.org/grpc v1.65.0 // indirect gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect gopkg.in/inf.v0 v0.9.1 // indirect diff --git a/go.sum b/go.sum index a5dde364799f..a24b98453b2c 100644 --- a/go.sum +++ b/go.sum @@ -381,10 +381,10 @@ github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7 github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7 h1:CRzzXjmgx9p362yO39D6hbZULdMI23gaKqSxijJCXHM= github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7/go.mod h1:wnsHqpi3RgDwklS5SPHUgjcUUpontGPKJ+GJYOdV7pY= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.172.0 h1:lJjLKG92RyKIIYujVvulR3JpVjr3yxaU34nwXCq8K2o= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.172.0/go.mod h1:o6QDjdVKpP5EF0dp/VlvqckzuSDATr1rLdHt3A5m0YY= -github.com/aws/aws-sdk-go-v2/service/ecr v1.30.3 h1:+v2hv29pWaVDASIScHuUhDC93nqJGVlGf6cujrJMHZE= -github.com/aws/aws-sdk-go-v2/service/ecr v1.30.3/go.mod h1:RhaP7Wil0+uuuhiE4FzOOEFZwkmFAk1ZflXzK+O3ptU= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.173.0 h1:ta62lid9JkIpKZtZZXSj6rP2AqY5x1qYGq53ffxqD9Q= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.173.0/go.mod h1:o6QDjdVKpP5EF0dp/VlvqckzuSDATr1rLdHt3A5m0YY= +github.com/aws/aws-sdk-go-v2/service/ecr v1.31.0 h1:vi/MwojjLGATEEUFn2GEdLiom7CFlB+qCIx4tDWqKfQ= +github.com/aws/aws-sdk-go-v2/service/ecr v1.31.0/go.mod h1:RhaP7Wil0+uuuhiE4FzOOEFZwkmFAk1ZflXzK+O3ptU= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2 h1:PpbXaecV3sLAS6rjQiaKw4/jyq3Z8gNzmoJupHAoBp0= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2/go.mod h1:fUHpGXr4DrXkEDpGAjClPsviWf+Bszeb0daKE0blxv8= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8= @@ -393,8 +393,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrx github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII= github.com/aws/aws-sdk-go-v2/service/kms v1.30.0 h1:yS0JkEdV6h9JOo8sy2JSpjX+i7vsKifU8SIeHrqiDhU= github.com/aws/aws-sdk-go-v2/service/kms v1.30.0/go.mod h1:+I8VUUSVD4p5ISQtzpgSva4I8cJ4SQ4b1dcBcof7O+g= -github.com/aws/aws-sdk-go-v2/service/s3 v1.58.2 h1:sZXIzO38GZOU+O0C+INqbH7C2yALwfMWpd64tONS/NE= -github.com/aws/aws-sdk-go-v2/service/s3 v1.58.2/go.mod h1:Lcxzg5rojyVPU/0eFwLtcyTaek/6Mtic5B1gJo7e/zE= +github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3 h1:hT8ZAZRIfqBqHbzKTII+CIiY8G2oC9OpLedkZ51DWl8= +github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3/go.mod h1:Lcxzg5rojyVPU/0eFwLtcyTaek/6Mtic5B1gJo7e/zE= github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM= github.com/aws/aws-sdk-go-v2/service/sso v1.22.4/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE= @@ -445,8 +445,8 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= -github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= -github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= github.com/cheggaaa/pb v1.0.27/go.mod h1:pQciLPpbU0oxA0h+VJYYLxO+XeDQb5pZijXscXHm81s= @@ -714,8 +714,8 @@ github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.0 h1:uCdmnmatrKCgMBlM4rMuJZWOkPDqdbZPnrMXDY4gI68= -github.com/golang/glog v1.2.0/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= +github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -864,6 +864,7 @@ github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= github.com/gosuri/uitable v0.0.4/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA= github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= +github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= @@ -901,8 +902,8 @@ github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/hashicorp/hc-install v0.7.0 h1:Uu9edVqjKQxxuD28mR5TikkKDd/p55S8vzPC1659aBk= -github.com/hashicorp/hc-install v0.7.0/go.mod h1:ELmmzZlGnEcqoUMKUuykHaPCIR1sYLYX+KSggWSKZuA= +github.com/hashicorp/hc-install v0.8.0 h1:LdpZeXkZYMQhoKPCecJHlKvUkQFixN/nvyR1CdfOLjI= +github.com/hashicorp/hc-install v0.8.0/go.mod h1:+MwJYjDfCruSD/udvBmRB22Nlkwwkwf5sAB6uTIhSaU= github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= github.com/hashicorp/hcl/v2 v2.21.0 h1:lve4q/o/2rqwYOgUg3y3V2YPyD1/zkCLGjIV74Jit14= @@ -1142,8 +1143,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.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE= github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk= -github.com/open-policy-agent/opa v0.66.0 h1:DbrvfJQja0FBRcPOB3Z/BOckocN+M4ApNWyNhSRJt0w= -github.com/open-policy-agent/opa v0.66.0/go.mod h1:EIgNnJcol7AvQR/IcWLwL13k64gHVbNAVG46b2G+/EY= +github.com/open-policy-agent/opa v0.67.0 h1:FOdsO9yNhfmrh+72oVK7ImWmzruG+VSpfbr5IBqEWVs= +github.com/open-policy-agent/opa v0.67.0/go.mod h1:aqKlHc8E2VAAylYE9x09zJYr/fYzGX+JKne89UGqFzk= 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.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -1426,25 +1427,25 @@ go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0 h1:9l89oX4ba9kHbBol3Xin3leYJ+252h0zszDtBwyKe2A= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.52.0/go.mod h1:XLZfZboOJWHNKUv7eH0inh0E9VV6eWDFB/9yJyTLPp0= -go.opentelemetry.io/otel v1.27.0 h1:9BZoF3yMK/O1AafMiQTVu0YDj5Ea4hPhxCs7sGva+cg= -go.opentelemetry.io/otel v1.27.0/go.mod h1:DMpAK8fzYRzs+bi3rS5REupisuqTheUlSZJ1WnZaPAQ= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0 h1:R9DE4kQ4k+YtfLI2ULwX82VtNQ2J8yZmA7ZIF/D+7Mc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.27.0/go.mod h1:OQFyQVrDlbe+R7xrEyDr/2Wr67Ol0hRUgsfA+V5A95s= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0 h1:tIqheXEFWAZ7O8A7m+J0aPTmpJN3YQ7qetUAdkkkKpk= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.21.0/go.mod h1:nUeKExfxAQVbiVFn32YXpXZZHZ61Cc3s3Rn1pDBGAb0= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= +go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I= -go.opentelemetry.io/otel/metric v1.27.0 h1:hvj3vdEKyeCi4YaYfNjv2NUje8FqKqUY8IlF0FxV/ik= -go.opentelemetry.io/otel/metric v1.27.0/go.mod h1:mVFgmRlhljgBiuk/MP/oKylr4hs85GZAylncepAX/ak= -go.opentelemetry.io/otel/sdk v1.27.0 h1:mlk+/Y1gLPLn84U4tI8d3GNJmGT/eXe3ZuOXN9kTWmI= -go.opentelemetry.io/otel/sdk v1.27.0/go.mod h1:Ha9vbLwJE6W86YstIywK2xFfPjbWlCuwPtMkKdz/Y4A= -go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5/Rscw= -go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= +go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= +go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= +go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= +go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= -go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= -go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= +go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= +go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca h1:VdD38733bfYv5tUZwEIskMM93VanwNIi5bIKnDrJdEY= go.starlark.net v0.0.0-20230525235612-a134d8f9ddca/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds= go.step.sm/crypto v0.44.2 h1:t3p3uQ7raP2jp2ha9P6xkQF85TJZh+87xmjSLaib+jk= @@ -1512,8 +1513,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= -golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= +golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1619,8 +1620,8 @@ golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1980,10 +1981,10 @@ google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 h1:ImUcDPHjTrAqNhlOkSocDLfG9rrNHH7w7uoKWPaWZ8s= google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7/go.mod h1:/3XmxOjePkvmKrHuBy4zNFw7IzxJXtAgdpXi8Ll990U= -google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5 h1:P8OJ/WCl/Xo4E4zoe4/bifHpSmmKwARqyqE4nW6J2GQ= -google.golang.org/genproto/googleapis/api v0.0.0-20240520151616-dc85e6b867a5/go.mod h1:RGnPtTG7r4i8sPlNyDeikXF99hMM+hN6QMm4ooG9g2g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291 h1:AgADTJarZTBqgjiUzRgfaBchgYB3/WFTC80GPwsMcRI= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240515191416-fc5f0ca64291/go.mod h1:EfXuqaE1J41VCDicxHzUDm+8rk+7ZdXzHV0IhO/I6s0= +google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= +google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -2019,8 +2020,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= -google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= +google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= +google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From 7278abd4e42d5d7379a7df7e7a8f028aa73a895f Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Wed, 7 Aug 2024 14:06:40 +0700 Subject: [PATCH 019/183] docs: update client/server docs for misconf and license scanning (#7277) Signed-off-by: nikpivkin Signed-off-by: knqyf263 Co-authored-by: knqyf263 --- docs/docs/references/modes/client-server.md | 21 ++++++-- pkg/commands/artifact/run.go | 53 ++++++++++----------- 2 files changed, 44 insertions(+), 30 deletions(-) diff --git a/docs/docs/references/modes/client-server.md b/docs/docs/references/modes/client-server.md index 518fe45efc8a..7aa90abf0b22 100644 --- a/docs/docs/references/modes/client-server.md +++ b/docs/docs/references/modes/client-server.md @@ -2,9 +2,22 @@ Trivy has client/server mode. Trivy server has vulnerability database and Trivy client doesn't have to download vulnerability database. It is useful if you want to scan images or files at multiple locations and do not want to download the database at every location. -| Client/Server Mode | Image | Rootfs | Filesystem | Repository | Config | AWS | K8s | -|:---------------------:|:-----:|:------:|:----------:|:----------:|:------:|:---:|:---:| -| Supported | ✅ | ✅ | ✅ | ✅ | ✅ | X | X | +| Client/Server Mode | Image | Rootfs | Filesystem | Repository | Config | K8s | +|:------------------:|:-----:|:------:|:----------:|:----------:|:------:|:---:| +| Supported | ✅ | ✅ | ✅ | ✅ | - | - | + +Some scanners run on the client side, even in client/server mode. + +| Scanner | Run on Client or Server | +|:----------------:|:-----------------------:| +| Vulnerability | Server | +| Misconfiguration | Client[^1] | +| Secret | Client[^2] | +| License | Server | + +!!! note + Scanning of misconfigurations and licenses is performed on the client side (as in standalone mode). + Otherwise, the client would need to send files to the server that may contain sensitive information. ## Server At first, you need to launch Trivy server. It downloads vulnerability database automatically and continue to fetch the latest DB in the background. @@ -338,3 +351,5 @@ Returns the `200 OK` status if the request was successful. ![architecture](../../../imgs/client-server.png) +[^1]: The checks bundle is also downloaded on the client side. +[^2]: The scan result with masked secrets is sent to the server \ No newline at end of file diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index 6528ec2c3d36..3cd1b9af74b5 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -40,7 +40,6 @@ const ( TargetFilesystem TargetKind = "fs" TargetRootfs TargetKind = "rootfs" TargetRepository TargetKind = "repo" - TargetImageArchive TargetKind = "archive" TargetSBOM TargetKind = "sbom" TargetVM TargetKind = "vm" ) @@ -345,6 +344,15 @@ func Run(ctx context.Context, opts flag.Options, targetKind TargetKind) (err err } }() + if opts.ServerAddr != "" && opts.Scanners.AnyEnabled(types.MisconfigScanner, types.SecretScanner) { + log.WarnContext(ctx, + fmt.Sprintf( + "Trivy runs in client/server mode, but misconfiguration and license scanning will be done on the client side, see %s", + doc.URL("/docs/references/modes/client-server", ""), + ), + ) + } + if opts.GenerateDefaultConfig { log.Info("Writing the default config to trivy-default.yaml...") return viper.SafeWriteConfigAs("trivy-default.yaml") @@ -359,32 +367,23 @@ func Run(ctx context.Context, opts flag.Options, targetKind TargetKind) (err err } defer r.Close(ctx) - var report types.Report - switch targetKind { - case TargetContainerImage, TargetImageArchive: - if report, err = r.ScanImage(ctx, opts); err != nil { - return xerrors.Errorf("image scan error: %w", err) - } - case TargetFilesystem: - if report, err = r.ScanFilesystem(ctx, opts); err != nil { - return xerrors.Errorf("filesystem scan error: %w", err) - } - case TargetRootfs: - if report, err = r.ScanRootfs(ctx, opts); err != nil { - return xerrors.Errorf("rootfs scan error: %w", err) - } - case TargetRepository: - if report, err = r.ScanRepository(ctx, opts); err != nil { - return xerrors.Errorf("repository scan error: %w", err) - } - case TargetSBOM: - if report, err = r.ScanSBOM(ctx, opts); err != nil { - return xerrors.Errorf("sbom scan error: %w", err) - } - case TargetVM: - if report, err = r.ScanVM(ctx, opts); err != nil { - return xerrors.Errorf("vm scan error: %w", err) - } + scans := map[TargetKind]func(context.Context, flag.Options) (types.Report, error){ + TargetContainerImage: r.ScanImage, + TargetFilesystem: r.ScanFilesystem, + TargetRootfs: r.ScanRootfs, + TargetRepository: r.ScanRepository, + TargetSBOM: r.ScanSBOM, + TargetVM: r.ScanVM, + } + + scanFunction, exists := scans[targetKind] + if !exists { + return xerrors.Errorf("unknown target kind: %s", targetKind) + } + + report, err := scanFunction(ctx, opts) + if err != nil { + return xerrors.Errorf("%s scan error: %w", targetKind, err) } report, err = r.Filter(ctx, opts, report) From 65d991cee7c5149095c5a0931595bb74725c61fc Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Thu, 8 Aug 2024 13:00:05 +0700 Subject: [PATCH 020/183] docs: update links to packaging.python.org (#7318) Signed-off-by: nikpivkin --- docs/docs/coverage/language/python.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/coverage/language/python.md b/docs/docs/coverage/language/python.md index 15cadd6f96c3..7a697b87d250 100644 --- a/docs/docs/coverage/language/python.md +++ b/docs/docs/coverage/language/python.md @@ -42,7 +42,7 @@ Trivy parses your files generated by package managers in filesystem/repository s ### pip #### Dependency detection -Trivy only parses [version specifiers](https://packaging.python.org/en/latest/specifications/version-specifiers/#id4) with `==` comparison operator and without `.*`. +Trivy only parses [version specifiers](https://packaging.python.org/en/latest/specifications/version-specifiers/#id5) with `==` comparison operator and without `.*`. To convert unsupported version specifiers - use the `pip freeze` command. ```bash @@ -119,7 +119,7 @@ License detection is not supported for `Poetry`. ## Packaging Trivy parses the manifest files of installed packages in container image scanning and so on. -See [here](https://packaging.python.org/en/latest/discussions/wheel-vs-egg/) for the detail. +See [here](https://packaging.python.org/en/latest/discussions/package-formats/) for the detail. ### Egg Trivy looks for `*.egg-info`, `*.egg-info/PKG-INFO`, `*.egg` and `EGG-INFO/PKG-INFO` to identify Python packages. From 2b6d8d9227fb6ecc9386a14333964c23c0370a52 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 9 Aug 2024 05:09:36 +0700 Subject: [PATCH 021/183] perf(misconf): optimize work with context (#6968) Signed-off-by: nikpivkin --- .../scanners/terraform/parser/evaluator.go | 56 ++++++++++++++----- pkg/iac/terraform/block.go | 5 +- pkg/iac/terraform/context/context.go | 49 ++++++++++------ pkg/iac/terraform/context/context_test.go | 37 ++++++++++++ 4 files changed, 113 insertions(+), 34 deletions(-) diff --git a/pkg/iac/scanners/terraform/parser/evaluator.go b/pkg/iac/scanners/terraform/parser/evaluator.go index 0e26103e8c96..e0231d2311a5 100644 --- a/pkg/iac/scanners/terraform/parser/evaluator.go +++ b/pkg/iac/scanners/terraform/parser/evaluator.go @@ -96,9 +96,8 @@ func (e *evaluator) evaluateStep() { e.ctx.Set(e.getValuesByBlockType("locals"), "local") e.ctx.Set(e.getValuesByBlockType("provider"), "provider") - resources := e.getValuesByBlockType("resource") - for key, resource := range resources.AsValueMap() { - e.ctx.Set(resource, key) + for typ, resource := range e.getResources() { + e.ctx.Set(resource, typ) } e.ctx.Set(e.getValuesByBlockType("data"), "data") @@ -224,10 +223,12 @@ func (e *evaluator) evaluateSteps() { var lastContext hcl.EvalContext for i := 0; i < maxContextIterations; i++ { + e.debug.Log("Starting iteration %d", i) e.evaluateStep() // if ctx matches the last evaluation, we can bail, nothing left to resolve if i > 0 && reflect.DeepEqual(lastContext.Variables, e.ctx.Inner().Variables) { + e.debug.Log("Context unchanged at i=%d", i) break } if len(e.ctx.Inner().Variables) != len(lastContext.Variables) { @@ -330,15 +331,16 @@ func (e *evaluator) expandBlockForEaches(blocks terraform.Blocks, isDynamic bool } clone := block.Clone(idx) - ctx := clone.Context() - e.copyVariables(block, clone) - ctx.SetByDot(idx, "each.key") - ctx.SetByDot(val, "each.value") - ctx.Set(idx, block.TypeLabel(), "key") - ctx.Set(val, block.TypeLabel(), "value") + eachObj := cty.ObjectVal(map[string]cty.Value{ + "key": idx, + "value": val, + }) + + ctx.Set(eachObj, "each") + ctx.Set(eachObj, block.TypeLabel()) if isDynamic { if iterAttr := block.GetAttribute("iterator"); iterAttr.IsNotNil() { @@ -354,9 +356,7 @@ func (e *evaluator) expandBlockForEaches(blocks terraform.Blocks, isDynamic bool forEachFiltered = append(forEachFiltered, clone) - values := clone.Values() - clones[idx.AsString()] = values - e.ctx.SetByDot(values, clone.GetMetadata().Reference()) + clones[idx.AsString()] = clone.Values() }) metadata := block.GetMetadata() @@ -434,11 +434,12 @@ func (e *evaluator) copyVariables(from, to *terraform.Block) { return } - srcValue := e.ctx.Root().Get(fromBase, fromRel) + rootCtx := e.ctx.Root() + srcValue := rootCtx.Get(fromBase, fromRel) if srcValue == cty.NilVal { return } - e.ctx.Root().Set(srcValue, fromBase, toRel) + rootCtx.Set(srcValue, fromBase, toRel) } func (e *evaluator) evaluateVariable(b *terraform.Block) (cty.Value, error) { @@ -530,7 +531,7 @@ func (e *evaluator) getValuesByBlockType(blockType string) cty.Value { continue } values[b.Label()] = b.Values() - case "resource", "data": + case "data": if len(b.Labels()) < 2 { continue } @@ -553,3 +554,28 @@ func (e *evaluator) getValuesByBlockType(blockType string) cty.Value { return cty.ObjectVal(values) } + +func (e *evaluator) getResources() map[string]cty.Value { + values := make(map[string]map[string]cty.Value) + + for _, b := range e.blocks { + if b.Type() != "resource" { + continue + } + + if len(b.Labels()) < 2 { + continue + } + + val, exists := values[b.Labels()[0]] + if !exists { + val = make(map[string]cty.Value) + values[b.Labels()[0]] = val + } + val[b.Labels()[1]] = b.Values() + } + + return lo.MapValues(values, func(v map[string]cty.Value, _ string) cty.Value { + return cty.ObjectVal(v) + }) +} diff --git a/pkg/iac/terraform/block.go b/pkg/iac/terraform/block.go index 8b49225b6e69..9245ad6c38a8 100644 --- a/pkg/iac/terraform/block.go +++ b/pkg/iac/terraform/block.go @@ -85,7 +85,7 @@ func NewBlock(hclBlock *hcl.Block, ctx *context.Context, moduleBlock *Block, par } b := Block{ - id: uuid.New().String(), + id: uuid.NewString(), context: ctx, hclBlock: hclBlock, moduleBlock: moduleBlock, @@ -446,6 +446,9 @@ func (b *Block) Attributes() map[string]*Attribute { func (b *Block) Values() cty.Value { values := createPresetValues(b) for _, attribute := range b.GetAttributes() { + if attribute.Name() == "for_each" { + continue + } values[attribute.Name()] = attribute.Value() } return cty.ObjectVal(postProcessValues(b, values)) diff --git a/pkg/iac/terraform/context/context.go b/pkg/iac/terraform/context/context.go index 0f4a58de9ac9..14e29a9a8378 100644 --- a/pkg/iac/terraform/context/context.go +++ b/pkg/iac/terraform/context/context.go @@ -46,17 +46,29 @@ func (c *Context) Get(parts ...string) cty.Value { if len(parts) == 0 { return cty.NilVal } - src := c.ctx.Variables - for i, part := range parts { - if i == len(parts)-1 { - return src[part] + + curr := c.ctx.Variables[parts[0]] + if len(parts) == 1 { + return curr + } + + for i, part := range parts[1:] { + if !curr.Type().HasAttribute(part) { + return cty.NilVal + } + + attr := curr.GetAttr(part) + + if i == len(parts)-2 { // iteration from the first element + return attr } - nextPart := src[part] - if nextPart == cty.NilVal { + + if !(attr.IsKnown() && attr.Type().IsObjectType()) { return cty.NilVal } - src = nextPart.AsValueMap() + curr = attr } + return cty.NilVal } @@ -97,13 +109,12 @@ func mergeVars(src cty.Value, parts []string, value cty.Value) cty.Value { } data := make(map[string]cty.Value) - if src.Type().IsObjectType() && !src.IsNull() && src.LengthInt() > 0 { + if isNotEmptyObject(src) { data = src.AsValueMap() - tmp, ok := src.AsValueMap()[parts[0]] - if !ok { - src = cty.ObjectVal(make(map[string]cty.Value)) + if attr, ok := data[parts[0]]; ok { + src = attr } else { - src = tmp + src = cty.EmptyObjectVal } } @@ -118,14 +129,16 @@ func mergeObjects(a, b cty.Value) cty.Value { for key, val := range a.AsValueMap() { output[key] = val } - for key, val := range b.AsValueMap() { - old, exists := output[key] - if exists && isNotEmptyObject(old) && isNotEmptyObject(val) { - output[key] = mergeObjects(old, val) + b.ForEachElement(func(key, val cty.Value) (stop bool) { + k := key.AsString() + old := output[k] + if old.IsKnown() && isNotEmptyObject(old) && isNotEmptyObject(val) { + output[k] = mergeObjects(old, val) } else { - output[key] = val + output[k] = val } - } + return false + }) return cty.ObjectVal(output) } diff --git a/pkg/iac/terraform/context/context_test.go b/pkg/iac/terraform/context/context_test.go index 8185d7b9892d..dfd8e05e5fac 100644 --- a/pkg/iac/terraform/context/context_test.go +++ b/pkg/iac/terraform/context/context_test.go @@ -52,6 +52,43 @@ func Test_ContextVariablesPreservation(t *testing.T) { } +func Test_SetWithMerge(t *testing.T) { + hctx := hcl.EvalContext{ + Variables: map[string]cty.Value{ + "my": cty.ObjectVal(map[string]cty.Value{ + "someValue": cty.ObjectVal(map[string]cty.Value{ + "foo": cty.StringVal("test"), + "bar": cty.ObjectVal(map[string]cty.Value{ + "foo": cty.StringVal("test"), + }), + }), + }), + }, + } + + ctx := NewContext(&hctx, nil) + + val := cty.ObjectVal(map[string]cty.Value{ + "foo2": cty.StringVal("test2"), + "bar": cty.ObjectVal(map[string]cty.Value{ + "foo2": cty.StringVal("test2"), + }), + }) + + ctx.Set(val, "my", "someValue") + got := ctx.Get("my", "someValue") + expected := cty.ObjectVal(map[string]cty.Value{ + "foo": cty.StringVal("test"), + "foo2": cty.StringVal("test2"), + "bar": cty.ObjectVal(map[string]cty.Value{ + "foo": cty.StringVal("test"), + "foo2": cty.StringVal("test2"), + }), + }) + + assert.Equal(t, expected, got) +} + func Test_ContextVariablesPreservationByDot(t *testing.T) { underlying := &hcl.EvalContext{} From 59c154144e4f33402e97039779c221c0e0bc296f Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 9 Aug 2024 13:13:30 +0700 Subject: [PATCH 022/183] refactor: replace ftypes.Gradle with packageurl.TypeGradle (#7323) Signed-off-by: nikpivkin --- pkg/purl/purl.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/purl/purl.go b/pkg/purl/purl.go index ba19d40c26a9..d9bff7b11e15 100644 --- a/pkg/purl/purl.go +++ b/pkg/purl/purl.go @@ -84,7 +84,7 @@ func New(t ftypes.TargetType, metadata types.Metadata, pkg ftypes.Package) (*Pac var qs packageurl.Qualifiers name, namespace, qs = parseApk(name, metadata.OS) qualifiers = append(qualifiers, qs...) - case packageurl.TypeMaven, string(ftypes.Gradle): // TODO: replace with packageurl.TypeGradle once they add it. + case packageurl.TypeMaven, packageurl.TypeGradle: namespace, name = parseMaven(name) case packageurl.TypePyPi: name = parsePyPI(name) From 08cc14bd2171afdc1973c6d614dd0d1fb82b7623 Mon Sep 17 00:00:00 2001 From: Itay Shakury Date: Fri, 9 Aug 2024 09:30:53 +0300 Subject: [PATCH 023/183] docs: update air-gapped docs (#7160) Signed-off-by: knqyf263 Co-authored-by: knqyf263 --- docs/docs/advanced/air-gap.md | 228 ++++++++++-------- docs/docs/compliance/contrib-compliance.md | 2 +- docs/docs/references/troubleshooting.md | 6 +- .../scanner/misconfiguration/check/builtin.md | 25 +- .../scanner/misconfiguration/custom/data.md | 22 +- .../scanner/misconfiguration/custom/index.md | 8 +- .../scanner/misconfiguration/custom/schema.md | 2 +- docs/docs/scanner/misconfiguration/index.md | 21 +- docs/docs/scanner/vulnerability.md | 43 +--- .../misconfiguration/custom-checks.md | 2 +- mkdocs.yml | 2 +- 11 files changed, 178 insertions(+), 183 deletions(-) diff --git a/docs/docs/advanced/air-gap.md b/docs/docs/advanced/air-gap.md index 171b80249eac..cf1df06f1bfe 100644 --- a/docs/docs/advanced/air-gap.md +++ b/docs/docs/advanced/air-gap.md @@ -1,142 +1,162 @@ -# Air-Gapped Environment +# Advanced Network Scenarios -Trivy can be used in air-gapped environments. Note that an allowlist is [here][allowlist]. +Trivy needs to connect to the internet occasionally in order to download relevant content. This document explains the network connectivity requirements of Trivy and setting up Trivy in particular scenarios. -## Air-Gapped Environment for vulnerabilities +## Network requirements -### Download the vulnerability database -At first, you need to download the vulnerability database for use in air-gapped environments. +Trivy's databases are distributed as OCI images via GitHub Container registry (GHCR): -=== "Trivy" +- +- +- - ``` - TRIVY_TEMP_DIR=$(mktemp -d) - trivy --cache-dir $TRIVY_TEMP_DIR image --download-db-only - tar -cf ./db.tar.gz -C $TRIVY_TEMP_DIR/db metadata.json trivy.db - rm -rf $TRIVY_TEMP_DIR - ``` +The following hosts are required in order to fetch them: -=== "oras >= v0.13.0" - Please follow [oras installation instruction][oras]. +- `ghcr.io` +- `pkg-containers.githubusercontent.com` - Download `db.tar.gz`: +The databases are pulled by Trivy using the [OCI Distribution](https://github.com/opencontainers/distribution-spec) specification, which is a simple HTTPS-based protocol. - ``` - $ oras pull ghcr.io/aquasecurity/trivy-db:2 - ``` +[VEX Hub](https://github.com/aquasecurity/vexhub) is distributed from GitHub over HTTPS. +The following hosts are required in order to fetch it: -=== "oras < v0.13.0" - Please follow [oras installation instruction][oras]. +- `api.github.com` +- `codeload.github.com` - Download `db.tar.gz`: +## Running Trivy in air-gapped environment - ``` - $ oras pull -a ghcr.io/aquasecurity/trivy-db:2 - ``` +An air-gapped environment refers to situations where the network connectivity from the machine Trivy runs on is blocked or restricted. -### Download the Java index database[^1] -Java users also need to download the Java index database for use in air-gapped environments. +In an air-gapped environment it is your responsibility to update the Trivy databases on a regular basis. -!!! note - You container image may contain JAR files even though you don't use Java directly. - In that case, you also need to download the Java index database. +## Offline Mode -=== "Trivy" +By default, Trivy will attempt to download latest databases. If it fails, the scan might fail. To avoid this behavior, you can tell Trivy to not attempt to download database files: - ``` - TRIVY_TEMP_DIR=$(mktemp -d) - trivy --cache-dir $TRIVY_TEMP_DIR image --download-java-db-only - tar -cf ./javadb.tar.gz -C $TRIVY_TEMP_DIR/java-db metadata.json trivy-java.db - rm -rf $TRIVY_TEMP_DIR - ``` -=== "oras >= v0.13.0" - Please follow [oras installation instruction][oras]. +- `--skip-db-update` to skip updating the main vulnerability database. +- `--skip-java-db-update` to skip updating the Java vulnerability database. +- `--skip-check-update` to skip updating the misconfiguration database. - Download `javadb.tar.gz`: +```shell +trivy image --skip-db-update --skip-java-db-update --offline-scan --skip-check-update myimage +``` + +## Self-Hosting - ``` - $ oras pull ghcr.io/aquasecurity/trivy-java-db:1 - ``` +### OCI Databases -=== "oras < v0.13.0" - Please follow [oras installation instruction][oras]. +You can host the databases on your own local OCI registry. - Download `javadb.tar.gz`: +First, make a copy of the databases in a container registry that is accessible to Trivy. The databases are in: - ``` - $ oras pull -a ghcr.io/aquasecurity/trivy-java-db:1 - ``` +- `ghcr.io/aquasecurity/trivy-db:2` +- `ghcr.io/aquasecurity/trivy-java-db:1` +- `ghcr.io/aquasecurity/trivy-checks:0` +Then, tell Trivy to use the local registry: -### Transfer the DB files into the air-gapped environment -The way of transfer depends on the environment. +```shell +trivy image \ + --db-repository myregistry.local/trivy-db \ + --java-db-repository myregistry.local/trivy-java-db \ + --checks-bundle-repository myregistry.local/trivy-checks \ + myimage +``` -=== "Vulnerability db" - ``` - $ rsync -av -e ssh /path/to/db.tar.gz [user]@[host]:dst - ``` +#### Authentication -=== "Java index db[^1]" - ``` - $ rsync -av -e ssh /path/to/javadb.tar.gz [user]@[host]:dst - ``` +If the registry requires authentication, you can configure it as described in the [private registry authentication document](../advanced/private-registries/index.md). -### Put the DB files in Trivy's cache directory -You have to know where to put the DB files. The following command shows the default cache directory. +### VEX Hub +You can host a copy of VEX Hub on your own internal server. + +First, make a copy of VEX Hub in a location that is accessible to Trivy. + +1. Download the [VEX Hub](https://github.com/aquasecurity/vexhub) archive from: . +1. Download the [VEX Hub Repository Manifest](https://github.com/aquasecurity/vex-repo-spec#2-repository-manifest) file from: . +1. Create or identify an internal HTTP server that can serve the VEX Hub repository in your environment (e.g `https://server.local`). +1. Make the downloaded archive file available for serving from your server (e.g `https://server.local/main.zip`). +1. Modify the downloaded manifest file's [Location URL](https://github.com/aquasecurity/vex-repo-spec?tab=readme-ov-file#locations-subfields) field to the URL of the archive file on your server (e.g `url: https://server.local/main.zip`). +1. Make the manifest file available for serving from your server under the `/.well-known` path (e.g `https://server.local/.well-known/vex-repository.json`). + +Then, tell Trivy to use the local VEX Repository: + +1. Locate your [Trivy VEX configuration file](../supply-chain/vex/repo/#configuration-file) by running `trivy vex repo init`. Make the following changes to the file. +1. Disable the default VEX Hub repo (`enabled: false`) +1. Add your internal VEX Hub repository as a [custom repository](../supply-chain/vex/repo/#custom-repositories) with the URL pointing to your local server (e.g `url: https://server.local`). + +#### Authentication + +If your server requires authentication, you can configure it as described in the [VEX Repository Authentication document](../supply-chain/vex/repo/#authentication). + +## Manual cache population + +You can also download the databases files manually and surgically populate the Trivy cache directory with them. + +### Downloading the DB files + +On a machine with internet access, pull the database container archive from the public registry into your local workspace: + +Note that these examples operate in the current working directory. + +=== "Using ORAS" +This example uses [ORAS](https://oras.land), but you can use any other container registry manipulation tool. + +```shell +oras pull ghcr.io/aquasecurity/trivy-db:2 ``` -$ ssh user@host -$ trivy -h | grep cache - --cache-dir value cache directory (default: "/home/myuser/.cache/trivy") [$TRIVY_CACHE_DIR] -``` -=== "Vulnerability db" - Put the DB file in the cache directory + `/db`. - - ``` - $ mkdir -p /home/myuser/.cache/trivy/db - $ cd /home/myuser/.cache/trivy/db - $ tar xvf /path/to/db.tar.gz -C /home/myuser/.cache/trivy/db - x trivy.db - x metadata.json - $ rm /path/to/db.tar.gz - ``` - -=== "Java index db[^1]" - Put the DB file in the cache directory + `/java-db`. - - ``` - $ mkdir -p /home/myuser/.cache/trivy/java-db - $ cd /home/myuser/.cache/trivy/java-db - $ tar xvf /path/to/javadb.tar.gz -C /home/myuser/.cache/trivy/java-db - x trivy-java.db - x metadata.json - $ rm /path/to/javadb.tar.gz - ``` - - - -In an air-gapped environment it is your responsibility to update the Trivy databases on a regular basis, so that the scanner can detect recently-identified vulnerabilities. - -### Run Trivy with the specific flags. -In an air-gapped environment, you have to specify `--skip-db-update` and `--skip-java-db-update`[^1] so that Trivy doesn't attempt to download the latest database files. -In addition, if you want to scan `pom.xml` dependencies, you need to specify `--offline-scan` since Trivy tries to issue API requests for scanning Java applications by default. +You should now have a file called `db.tar.gz`. Next, extract it to reveal the db files: + +```shell +tar -xzf db.tar.gz ``` -$ trivy image --skip-db-update --skip-java-db-update --offline-scan alpine:3.12 + +You should now have 2 new files, `metadata.json` and `trivy.db`. These are the Trivy DB files. + +=== "Using Trivy" +This example uses Trivy to pull the database container archive. The `--cache-dir` flag makes Trivy download the database files into our current working directory. The `--download-db-only` flag tells Trivy to only download the database files, not to scan any images. + +```shell +trivy image --cache-dir . --download-db-only ``` -## Air-Gapped Environment for misconfigurations +You should now have 2 new files, `metadata.json` and `trivy.db`. These are the Trivy DB files, copy them over to the air-gapped environment. -No special measures are required to detect misconfigurations in an air-gapped environment. +### Populating the Trivy Cache -### Run Trivy with `--skip-check-update` option -In an air-gapped environment, specify `--skip-check-update` so that Trivy doesn't attempt to download the latest misconfiguration checks. +In order to populate the cache, you need to identify the location of the cache directory. If it is under the default location, you can run the following command to find it: +```shell +trivy -h | grep cache ``` -$ trivy conf --skip-policy-update /path/to/conf + +For the example, we will assume the `TRIVY_CACHE_DIR` variable holds the cache location: + +```shell +TRIVY_CACHE_DIR=/home/user/.cache/trivy ``` -[allowlist]: ../references/troubleshooting.md -[oras]: https://oras.land/docs/installation +Put the Trivy DB files in the Trivy cache directory under a `db` subdirectory: + +```shell +# ensure cache db directory exists +mkdir -p ${TRIVY_CACHE_DIR}/db +# copy the db files +cp /path/to/trivy.db /path/to/metadata.json ${TRIVY_CACHE_DIR}/db/ +``` + +### Java DB + +For Java DB the process is the same, except for the following: + +1. Image location is `ghcr.io/aquasecurity/trivy-java-db:1` +2. Archive file name is `javadb.tar.gz` +3. DB file name is `trivy-java.db` + +## Misconfigurations scanning + +Note that the misconfigurations checks bundle is also embedded in the Trivy binary (at build time), and will be used as a fallback if the external database is not available. This means that you can still scan for misconfigurations in an air-gapped environment using the Checks from the time of the Trivy release you are using. -[^1]: This is only required to scan `jar` files. More information about `Java index db` [here](../coverage/language/java.md) +The misconfiguration scanner can be configured to load checks from a local directory, using the `--config-check` flag. In an air-gapped scenario you can copy the checks library from [Trivy checks repository](https://github.com/aquasecurity/trivy-checks) into a local directory, and load it with this flag. See more in the [Misconfiguration scanner documentation](../scanner/misconfiguration/index.md). diff --git a/docs/docs/compliance/contrib-compliance.md b/docs/docs/compliance/contrib-compliance.md index a848b1bf4367..0b83b688b664 100644 --- a/docs/docs/compliance/contrib-compliance.md +++ b/docs/docs/compliance/contrib-compliance.md @@ -35,7 +35,7 @@ Additional information is provided below. #### 1. Referencing a check that is already part of Trivy -Trivy has a comprehensive list of checks as part of its misconfiguration scanning. These can be found in the `trivy-policies/checks` directory ([Link](https://github.com/aquasecurity/trivy-checks/tree/main/checks)). If the check is present, the `AVD_ID` and other information from the check has to be used. +Trivy has a comprehensive list of checks as part of its misconfiguration scanning. These can be found in the `trivy-checks/checks` directory ([Link](https://github.com/aquasecurity/trivy-checks/tree/main/checks)). If the check is present, the `AVD_ID` and other information from the check has to be used. Note: Take a look at the more generic compliance specs that are already available in Trivy. If you are adding new compliance spec to Kubernetes e.g. AWS EKS CIS Benchmarks, chances are high that the check you would like to add to the new spec has already been defined in the general `k8s-ci-v.000.yaml` compliance spec. The same applies for creating specific Cloud Provider Compliance Specs and the [generic compliance specs](https://github.com/aquasecurity/trivy-checks/tree/main/specs/compliance) available. diff --git a/docs/docs/references/troubleshooting.md b/docs/docs/references/troubleshooting.md index d271882c5ecb..2c9a74a0e89a 100644 --- a/docs/docs/references/troubleshooting.md +++ b/docs/docs/references/troubleshooting.md @@ -203,10 +203,7 @@ Trivy v0.23.0 or later requires Trivy DB v2. Please update your local database o !!! error FATAL failed to download vulnerability DB -If trivy is running behind corporate firewall, you have to add the following urls to your allowlist. - -- ghcr.io -- pkg-containers.githubusercontent.com +If Trivy is running behind corporate firewall, refer to the necessary connectivity requirements as described [here][network]. ### Denied @@ -271,4 +268,5 @@ $ trivy clean --all ``` [air-gapped]: ../advanced/air-gap.md +[network]: ../advanced/air-gap.md#network-requirements [redis-cache]: ../../vulnerability/examples/cache/#cache-backend diff --git a/docs/docs/scanner/misconfiguration/check/builtin.md b/docs/docs/scanner/misconfiguration/check/builtin.md index 8b513f47607a..c4ca18e79006 100644 --- a/docs/docs/scanner/misconfiguration/check/builtin.md +++ b/docs/docs/scanner/misconfiguration/check/builtin.md @@ -1,21 +1,20 @@ # Built-in Checks -## Check Sources -Built-in checks are mainly written in [Rego][rego] and Go. -Those checks are managed under [trivy-checks repository][trivy-checks]. +## Checks Sources +Trivy has an extensive library of misconfiguration checks that is maintained at . +Trivy checks are mainly written in [Rego][rego], while some checks are written in Go. See [here](../../../coverage/iac/index.md) for the list of supported config types. -For suggestions or issues regarding policy content, please open an issue under the [trivy-checks][trivy-checks] repository. +## Checks Bundle +When performing a misconfiguration scan, Trivy will automatically download the relevant Checks bundle. The bundle is cached locally and Trivy will reuse it for subsequent scans on the same machine. Trivy takes care of updating the cache automatically, so normally users can be oblivious to it. -## Check Distribution -Trivy checks are distributed as an OPA bundle on [GitHub Container Registry][ghcr] (GHCR). -When misconfiguration detection is enabled, Trivy pulls the OPA bundle from GHCR as an OCI artifact and stores it in the cache. -Those checks are then loaded into Trivy OPA engine and used for detecting misconfigurations. -If Trivy is unable to pull down newer checks, it will use the embedded set of checks as a fallback. This is also the case in air-gap environments where `--skip-policy-update` might be passed. - -## Update Interval +## Checks Distribution +Trivy checks are distributed as an [OPA bundle](opa-bundle) hosted in the following GitHub Container Registry: . Trivy checks for updates to OPA bundle on GHCR every 24 hours and pulls it if there are any updates. +### External connectivity +Trivy needs to connect to the internet to download the bundle. If you are running Trivy in an air-gapped environment, or an tightly controlled network, please refer to the [Advanced Network Scenarios document](../../../advanced/air-gap.md). +The Checks bundle is also embedded in the Trivy binary (at build time), and will be used as a fallback if Trivy is unable to download the bundle. This means that you can still scan for misconfigurations in an air-gapped environment using the Checks from the time of the Trivy release you are using. + [rego]: https://www.openpolicyagent.org/docs/latest/policy-language/ -[trivy-checks]: https://github.com/aquasecurity/trivy-checks -[ghcr]: https://github.com/aquasecurity/trivy-checks/pkgs/container/trivy-checks \ No newline at end of file +[opa-bundle]: https://www.openpolicyagent.org/docs/latest/management-bundles/ diff --git a/docs/docs/scanner/misconfiguration/custom/data.md b/docs/docs/scanner/misconfiguration/custom/data.md index 51af206b4c63..2ccd9f1a2bfd 100644 --- a/docs/docs/scanner/misconfiguration/custom/data.md +++ b/docs/docs/scanner/misconfiguration/custom/data.md @@ -1,15 +1,14 @@ # Custom Data -Custom checks may require additional data in order to determine an answer. +Custom checks may require additional data in order to make a resolution. You can pass arbitrary data files to Trivy to be used when evaluating rego checks using the `--data` flag. +Trivy recursively searches the specified data paths for JSON (`*.json`) and YAML (`*.yaml`) files. -For example, an allowed list of resources that can be created. -Instead of hardcoding this information inside your policy, Trivy allows passing paths to data files with the `--data` flag. +For example, consider an allowed list of resources that can be created. +Instead of hardcoding this information inside your policy, you can maintain the list in a separate file. -Given the following yaml file: +Example data file: -```bash -$ cd examples/misconf/custom-data -$ cat data/ports.yaml [~/src/github.com/aquasecurity/trivy/examples/misconf/custom-data] +```yaml services: ports: - "20" @@ -19,7 +18,7 @@ services: - "23/tcp" ``` -This can be imported into your policy: +Example usage in a Rego check: ```rego import data.services @@ -27,9 +26,8 @@ import data.services ports := services.ports ``` -Then, you need to pass data paths through `--data` option. -Trivy recursively searches the specified paths for JSON (`*.json`) and YAML (`*.yaml`) files. +Example loading the data file: ```bash -$ trivy conf --policy ./policy --data data --namespaces user ./configs -``` \ No newline at end of file +trivy config --config-check ./checks --data ./data --namespaces user ./configs +``` diff --git a/docs/docs/scanner/misconfiguration/custom/index.md b/docs/docs/scanner/misconfiguration/custom/index.md index 925b72cedf09..7f471d873e8b 100644 --- a/docs/docs/scanner/misconfiguration/custom/index.md +++ b/docs/docs/scanner/misconfiguration/custom/index.md @@ -2,10 +2,10 @@ ## Overview You can write custom checks in [Rego][rego]. -Once you finish writing custom checks, you can pass the policy files or the directory where those policies are stored with `--policy` option. +Once you finish writing custom checks, you can pass the check files or the directory where those checks are stored with --config-check` option. ``` bash -trivy conf --policy /path/to/policy.rego --policy /path/to/custom_policies --namespaces user /path/to/config_dir +trivy conf --config-check /path/to/policy.rego --config-check /path/to/custom_checks --namespaces user /path/to/config_dir ``` As for `--namespaces` option, the detail is described as below. @@ -93,7 +93,7 @@ By default, only `builtin.*` packages will be evaluated. If you define custom packages, you have to specify the package prefix via `--namespaces` option. By default, Trivy only runs in its own namespace, unless specified by the user. Note that the custom namespace does not have to be `user` as in this example. It could be anything user-defined. ``` bash -trivy conf --policy /path/to/custom_policies --namespaces user /path/to/config_dir +trivy conf --config-check /path/to/custom_checks --namespaces user /path/to/config_dir ``` In this case, `user.*` will be evaluated. @@ -135,7 +135,7 @@ correct and do not reference incorrect properties/values. #### custom.avd_id and custom.id -The AVD_ID can be used to link the check to the Aqua Vulnerability Database (AVD) entry. For example, the `avd_id` `AVD-AWS-0176` is the ID of the check in the [AWS Vulnerability Database](https://avd.aquasec.com/). If you are [contributing your check to trivy-policies](../../../../community/contribute/checks/overview.md), you need to generate an ID using `make id` in the [trivy-checks](https://github.com/aquasecurity/trivy-checks) repository. The output of the command will provide you the next free IDs for the different providers in Trivy. +The AVD_ID can be used to link the check to the Aqua Vulnerability Database (AVD) entry. For example, the `avd_id` `AVD-AWS-0176` is the ID of the check in the [AWS Vulnerability Database](https://avd.aquasec.com/). If you are [contributing your check to trivy-checks](../../../../community/contribute/checks/overview.md), you need to generate an ID using `make id` in the [trivy-checks](https://github.com/aquasecurity/trivy-checks) repository. The output of the command will provide you the next free IDs for the different providers in Trivy. The ID is based on the AVD_ID. For instance if the `avd_id` is `AVD-AWS-0176`, the ID is `ID0176`. diff --git a/docs/docs/scanner/misconfiguration/custom/schema.md b/docs/docs/scanner/misconfiguration/custom/schema.md index 612025d38866..7b305cc10dbf 100644 --- a/docs/docs/scanner/misconfiguration/custom/schema.md +++ b/docs/docs/scanner/misconfiguration/custom/schema.md @@ -1,7 +1,7 @@ # Input Schema ## Overview -Policies can be defined with custom schemas that allow inputs to be verified against them. Adding a policy schema +Checks can be defined with custom schemas that allow inputs to be verified against them. Adding a policy schema enables Trivy to show more detailed error messages when an invalid input is encountered. In Trivy we have been able to define a schema for a [Dockerfile](https://github.com/aquasecurity/trivy/tree/main/pkg/iac/rego/schemas) diff --git a/docs/docs/scanner/misconfiguration/index.md b/docs/docs/scanner/misconfiguration/index.md index 701d469d658f..0726e7312417 100644 --- a/docs/docs/scanner/misconfiguration/index.md +++ b/docs/docs/scanner/misconfiguration/index.md @@ -315,6 +315,9 @@ Failures: 2 (MEDIUM: 2, HIGH: 0, CRITICAL: 0) This section describes misconfiguration-specific configuration. Other common options are documented [here](../../configuration/index.md). +### External connectivity +Trivy needs to connect to the internet to download the checks bundle. If you are running Trivy in an air-gapped environment, or an tightly controlled network, please refer to the [Advanced Network Scenarios document](../../advanced/air-gap.md). + ### Enabling a subset of misconfiguration scanners It's possible to only enable certain misconfiguration scanners if you prefer. You can do so by passing the `--misconfig-scanners` option. @@ -326,19 +329,19 @@ trivy config --misconfig-scanners=terraform,dockerfile . Will only scan for misconfigurations that pertain to Terraform and Dockerfiles. -### Passing custom checks -You can pass policy files or directories including your custom checks through `--policy` option. +### Loading custom checks +You can load check files or directories including your custom checks using the `--config-check` flag. This can be repeated for specifying multiple files or directories. ```bash -cd examplex/misconf/ -trivy conf --policy custom-policy/policy --policy combine/policy --policy policy.rego --namespaces user misconf/mixed +trivy conf --config-check custom-policy/policy --config-check combine/policy --config-check policy.rego --namespaces user myapp ``` -For more details, see [Custom Checks](./custom/index.md). +You can load checks bundle as OCI Image from a Container Registry using the `--checks-bundle-repository` flag. -!!! tip -You also need to specify `--namespaces` option. +```bash +trivy conf --checks-bundle-repository myregistry.local/mychecks --namespaces user myapp +``` ### Passing custom data You can pass directories including your custom data through `--data` option. @@ -346,7 +349,7 @@ This can be repeated for specifying multiple directories. ```bash cd examples/misconf/custom-data -trivy conf --policy ./policy --data ./data --namespaces user ./configs +trivy conf --config-check ./policy --data ./data --namespaces user ./configs ``` For more details, see [Custom Data](./custom/data.md). @@ -357,7 +360,7 @@ If you want to evaluate custom checks in other packages, you have to specify pac This can be repeated for specifying multiple packages. ``` bash -trivy conf --policy ./policy --namespaces main --namespaces user ./configs +trivy conf --config-check ./policy --namespaces main --namespaces user ./configs ``` ### Private terraform registries diff --git a/docs/docs/scanner/vulnerability.md b/docs/docs/scanner/vulnerability.md index 00a9594ead62..ba5d0014d6bf 100644 --- a/docs/docs/scanner/vulnerability.md +++ b/docs/docs/scanner/vulnerability.md @@ -158,45 +158,22 @@ Trivy can detect vulnerabilities in Kubernetes clusters and components by scanni [^1]: Some manual triage and correction has been made. -## Database -Trivy downloads [the vulnerability database](https://github.com/aquasecurity/trivy-db) every 6 hours. -Trivy uses two types of databases for vulnerability detection: - -- Vulnerability Database -- Java Index Database - -This page provides detailed information about these databases. - -### Vulnerability Database -Trivy utilizes a database containing vulnerability information. -This database is built every six hours on [GitHub](https://github.com/aquasecurity/trivy-db) and is distributed via [GitHub Container registry (GHCR)](https://ghcr.io/aquasecurity/trivy-db). -The database is cached and updated as needed. -As Trivy updates the database automatically during execution, users don't need to be concerned about it. +## Databases +Trivy utilizes several databases containing information relevant for vulnerability scanning. +When performing a vulnerability scan, Trivy will automatically downloads the relevant databases. The databases are cached locally and Trivy will reuse them for subsequent scans on the same machine. Trivy takes care of updating the databases cache automatically, so normally users can be oblivious to it. For CLI flags related to the database, please refer to [this page](../configuration/db.md). -#### Private Hosting -If you host the database on your own OCI registry, you can specify a different repository with the `--db-repository` flag. -The default is `ghcr.io/aquasecurity/trivy-db`. - -```shell -$ trivy image --db-repository YOUR_REPO YOUR_IMAGE -``` - -If authentication is required, it can be configured in the same way as for private images. -Please refer to [the documentation](../advanced/private-registries/index.md) for more details. +### Vulnerability Database +This is Trivy's main database which contains vulnerability information, as collected from the datasources mentioned above. +It is built every six hours on [GitHub](https://github.com/aquasecurity/trivy-db). ### Java Index Database -This database is only downloaded when scanning JAR files so that Trivy can identify the groupId, artifactId, and version of JAR files. -It is built once a day on [GitHub](https://github.com/aquasecurity/trivy-java-db) and distributed via [GitHub Container registry (GHCR)](https://ghcr.io/aquasecurity/trivy-java-db). -Like the vulnerability database, it is automatically downloaded and updated when needed, so users don't need to worry about it. - -#### Private Hosting -If you host the database on your own OCI registry, you can specify a different repository with the `--java-db-repository` flag. -The default is `ghcr.io/aquasecurity/trivy-java-db`. +When scanning JAR files, Trivy relies on a dedicated database for identifying the groupId, artifactId, and version of the scanned JAR files. This database is only used when scanning JAR files, however your scanned artifacts might contain JAR files that you're not aware of. +This database is built once a day on [GitHub](https://github.com/aquasecurity/trivy-java-db). -If authentication is required, you need to run `docker login YOUR_REGISTRY`. -Currently, specifying a username and password is not supported. +### External connectivity +Trivy needs to connect to the internet to download the databases. If you are running Trivy in an air-gapped environment, or an tightly controlled network, please refer to the [Advanced Network Scenarios document](../advanced/air-gap.md). ## Detection Behavior Trivy prioritizes precision in vulnerability detection, aiming to minimize false positives while potentially accepting some false negatives. diff --git a/docs/tutorials/misconfiguration/custom-checks.md b/docs/tutorials/misconfiguration/custom-checks.md index 97ab67a7f649..0058595c0dde 100644 --- a/docs/tutorials/misconfiguration/custom-checks.md +++ b/docs/tutorials/misconfiguration/custom-checks.md @@ -93,7 +93,7 @@ Note that Rego Ensure that you have Trivy installed and run the following command: ```bash -trivy fs --scanners misconf --policy ./docker-check.rego --namespaces custom ./Dockerfile +trivy fs --scanners misconf --config-check ./docker-check.rego --namespaces custom ./Dockerfile ``` Please replace: diff --git a/mkdocs.yml b/mkdocs.yml index 9585c8341f94..60ed74306674 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -141,7 +141,7 @@ nav: - Developer guide: docs/plugin/developer-guide.md - Advanced: - Modules: docs/advanced/modules.md - - Air-Gapped Environment: docs/advanced/air-gap.md + - Advanced Network Scenarios: docs/advanced/air-gap.md - Container Image: - Embed in Dockerfile: docs/advanced/container/embed-in-dockerfile.md - Unpacked container image filesystem: docs/advanced/container/unpacked-filesystem.md From ee339b5ed714b8b9edb52444a42ff5350ac3bc97 Mon Sep 17 00:00:00 2001 From: simar7 <1254783+simar7@users.noreply.github.com> Date: Tue, 13 Aug 2024 22:40:25 -0600 Subject: [PATCH 024/183] docs(misconf): Update callsites to use correct naming (#7335) --- docs/docs/configuration/filtering.md | 2 +- docs/docs/coverage/iac/cloudformation.md | 2 +- docs/docs/coverage/iac/helm.md | 6 +++--- docs/docs/coverage/iac/terraform.md | 8 ++++---- docs/docs/scanner/misconfiguration/custom/debug.md | 2 +- docs/docs/scanner/misconfiguration/custom/index.md | 4 ++-- docs/docs/scanner/misconfiguration/index.md | 10 +++++----- docs/tutorials/misconfiguration/terraform.md | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/docs/configuration/filtering.md b/docs/docs/configuration/filtering.md index abe8e84ff7e3..030813bd1bce 100644 --- a/docs/docs/configuration/filtering.md +++ b/docs/docs/configuration/filtering.md @@ -101,7 +101,7 @@ Total: 1785 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 1680, CRITICAL: 105) ```bash -trivy conf --severity HIGH,CRITICAL examples/misconf/mixed +trivy config --severity HIGH,CRITICAL examples/misconf/mixed ```
diff --git a/docs/docs/coverage/iac/cloudformation.md b/docs/docs/coverage/iac/cloudformation.md index 5665e1e77acd..7faea9769d7d 100644 --- a/docs/docs/coverage/iac/cloudformation.md +++ b/docs/docs/coverage/iac/cloudformation.md @@ -21,7 +21,7 @@ It evaluates properties, functions, and other elements within CloudFormation fil You can provide `cf-params` with path to [CloudFormation Parameters] file to Trivy to scan your CloudFormation code with parameters. ```bash -trivy conf --cf-params params.json ./infrastructure/cf +trivy config --cf-params params.json ./infrastructure/cf ``` You can check a [CloudFormation Parameters Example] diff --git a/docs/docs/coverage/iac/helm.md b/docs/docs/coverage/iac/helm.md index 8d0352fc42f1..0c213e1fd901 100644 --- a/docs/docs/coverage/iac/helm.md +++ b/docs/docs/coverage/iac/helm.md @@ -21,7 +21,7 @@ When override values are passed to the Helm scanner, the values will be used dur Overrides can be set inline on the command line ```bash -trivy conf --helm-set securityContext.runAsUser=0 ./charts/mySql +trivy config --helm-set securityContext.runAsUser=0 ./charts/mySql ``` #### Setting value file overrides @@ -35,7 +35,7 @@ securityContext: ``` ```bash -trivy conf --helm-values overrides.yaml ./charts/mySql +trivy config --helm-values overrides.yaml ./charts/mySql ``` #### Setting value as explicit string @@ -49,7 +49,7 @@ trivy config --helm-set-string name=false ./infrastructure/tf Specific override values can come from specific files ```bash -trivy conf --helm-set-file environment=dev.values.yaml ./charts/mySql +trivy config --helm-set-file environment=dev.values.yaml ./charts/mySql ``` ## Secret diff --git a/docs/docs/coverage/iac/terraform.md b/docs/docs/coverage/iac/terraform.md index e190c901cf05..55f1936cb040 100644 --- a/docs/docs/coverage/iac/terraform.md +++ b/docs/docs/coverage/iac/terraform.md @@ -18,13 +18,13 @@ It supports the following formats: Trivy can scan Terraform Plan files (snapshots) or their JSON representations. To create a Terraform Plan and scan it, run the following command: ```bash terraform plan --out tfplan -trivy conf tfplan +trivy config tfplan ``` To scan a Terraform Plan representation in JSON format, run the following command: ```bash terraform show -json tfplan > tfplan.json -trivy conf tfplan.json +trivy config tfplan.json ``` ## Misconfiguration @@ -35,7 +35,7 @@ It also evaluates variables, imports, and other elements within Terraform files You can provide `tf-vars` files to Trivy to override default values specified in the Terraform HCL code. ```bash -trivy conf --tf-vars dev.terraform.tfvars ./infrastructure/tf +trivy config --tf-vars dev.terraform.tfvars ./infrastructure/tf ``` ### Exclude Downloaded Terraform Modules @@ -43,7 +43,7 @@ By default, downloaded modules are also scanned. If you don't want to scan them, you can use the `--tf-exclude-downloaded-modules` flag. ```bash -trivy conf --tf-exclude-downloaded-modules ./configs +trivy config --tf-exclude-downloaded-modules ./configs ``` ## Secret diff --git a/docs/docs/scanner/misconfiguration/custom/debug.md b/docs/docs/scanner/misconfiguration/custom/debug.md index 751e43633efc..54ec9fd65273 100644 --- a/docs/docs/scanner/misconfiguration/custom/debug.md +++ b/docs/docs/scanner/misconfiguration/custom/debug.md @@ -7,7 +7,7 @@ This will output a large trace from Open Policy Agent like the following: Only failed checks show traces. If you want to debug a passed check, you need to make it fail on purpose. ```shell -$ trivy conf --trace configs/ +$ trivy config --trace configs/ 2022-05-16T13:47:58.853+0100 INFO Detected config files: 1 Dockerfile (dockerfile) diff --git a/docs/docs/scanner/misconfiguration/custom/index.md b/docs/docs/scanner/misconfiguration/custom/index.md index 7f471d873e8b..9598089b8562 100644 --- a/docs/docs/scanner/misconfiguration/custom/index.md +++ b/docs/docs/scanner/misconfiguration/custom/index.md @@ -5,7 +5,7 @@ You can write custom checks in [Rego][rego]. Once you finish writing custom checks, you can pass the check files or the directory where those checks are stored with --config-check` option. ``` bash -trivy conf --config-check /path/to/policy.rego --config-check /path/to/custom_checks --namespaces user /path/to/config_dir +trivy config --config-check /path/to/policy.rego --config-check /path/to/custom_checks --namespaces user /path/to/config_dir ``` As for `--namespaces` option, the detail is described as below. @@ -93,7 +93,7 @@ By default, only `builtin.*` packages will be evaluated. If you define custom packages, you have to specify the package prefix via `--namespaces` option. By default, Trivy only runs in its own namespace, unless specified by the user. Note that the custom namespace does not have to be `user` as in this example. It could be anything user-defined. ``` bash -trivy conf --config-check /path/to/custom_checks --namespaces user /path/to/config_dir +trivy config --config-check /path/to/custom_checks --namespaces user /path/to/config_dir ``` In this case, `user.*` will be evaluated. diff --git a/docs/docs/scanner/misconfiguration/index.md b/docs/docs/scanner/misconfiguration/index.md index 0726e7312417..eae768456029 100644 --- a/docs/docs/scanner/misconfiguration/index.md +++ b/docs/docs/scanner/misconfiguration/index.md @@ -101,7 +101,7 @@ For example, the following example holds IaC files for Terraform, CloudFormation ``` bash $ ls iac/ Dockerfile deployment.yaml main.tf mysql-8.8.26.tar -$ trivy conf --severity HIGH,CRITICAL ./iac +$ trivy config --severity HIGH,CRITICAL ./iac ```
@@ -334,13 +334,13 @@ You can load check files or directories including your custom checks using the ` This can be repeated for specifying multiple files or directories. ```bash -trivy conf --config-check custom-policy/policy --config-check combine/policy --config-check policy.rego --namespaces user myapp +trivy config --config-check custom-policy/policy --config-check combine/policy --config-check policy.rego --namespaces user myapp ``` You can load checks bundle as OCI Image from a Container Registry using the `--checks-bundle-repository` flag. ```bash -trivy conf --checks-bundle-repository myregistry.local/mychecks --namespaces user myapp +trivy config --checks-bundle-repository myregistry.local/mychecks --namespaces user myapp ``` ### Passing custom data @@ -349,7 +349,7 @@ This can be repeated for specifying multiple directories. ```bash cd examples/misconf/custom-data -trivy conf --config-check ./policy --data ./data --namespaces user ./configs +trivy config --config-check ./my-check --data ./data --namespaces user ./configs ``` For more details, see [Custom Data](./custom/data.md). @@ -360,7 +360,7 @@ If you want to evaluate custom checks in other packages, you have to specify pac This can be repeated for specifying multiple packages. ``` bash -trivy conf --config-check ./policy --namespaces main --namespaces user ./configs +trivy config --config-check ./my-check --namespaces main --namespaces user ./configs ``` ### Private terraform registries diff --git a/docs/tutorials/misconfiguration/terraform.md b/docs/tutorials/misconfiguration/terraform.md index 24b8eebfa69a..c51f2edfe181 100644 --- a/docs/tutorials/misconfiguration/terraform.md +++ b/docs/tutorials/misconfiguration/terraform.md @@ -86,7 +86,7 @@ trivy config --severity CRITICAL, MEDIUM terraform-infra You can pass terraform values to Trivy to override default values found in the Terraform HCL code. More information are provided [in the documentation.](https://aquasecurity.github.io/trivy/latest/docs/coverage/iac/terraform/#value-overrides) ``` -trivy conf --tf-vars terraform.tfvars ./ +trivy config --tf-vars terraform.tfvars ./ ``` ### Custom Checks From 0047dbf361eaea3d5b09f3e29102eb53450e20c2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 15 Aug 2024 12:54:11 +0400 Subject: [PATCH 025/183] chore(deps): bump the common group with 9 updates (#7333) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 22 +++++++++++----------- go.sum | 44 ++++++++++++++++++++++---------------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/go.mod b/go.mod index ac6f232878bc..31315bc0f550 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ toolchain go1.22.4 require ( github.com/Azure/azure-sdk-for-go v68.0.0+incompatible - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/BurntSushi/toml v1.4.0 github.com/CycloneDX/cyclonedx-go v0.9.0 @@ -51,7 +51,7 @@ require ( github.com/go-openapi/strfmt v0.23.0 github.com/go-redis/redis/v8 v8.11.5 github.com/golang-jwt/jwt/v5 v5.2.1 - github.com/google/go-containerregistry v0.20.1 + github.com/google/go-containerregistry v0.20.2 github.com/google/go-github/v62 v62.0.0 github.com/google/licenseclassifier/v2 v2.0.0 github.com/google/uuid v1.6.0 @@ -88,7 +88,7 @@ require ( github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/mitchellh/mapstructure v1.5.0 github.com/moby/buildkit v0.15.1 - github.com/open-policy-agent/opa v0.67.0 + github.com/open-policy-agent/opa v0.67.1 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 github.com/openvex/discovery v0.1.0 @@ -103,7 +103,7 @@ require ( github.com/sirupsen/logrus v1.9.3 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.6.0 + github.com/spf13/cast v1.7.0 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 @@ -117,13 +117,13 @@ require ( github.com/zclconf/go-cty v1.15.0 github.com/zclconf/go-cty-yaml v1.0.3 go.etcd.io/bbolt v1.3.10 - golang.org/x/crypto v0.25.0 + golang.org/x/crypto v0.26.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect golang.org/x/mod v0.20.0 - golang.org/x/net v0.27.0 + golang.org/x/net v0.28.0 golang.org/x/sync v0.8.0 - golang.org/x/term v0.22.0 - golang.org/x/text v0.16.0 + golang.org/x/term v0.23.0 + golang.org/x/text v0.17.0 golang.org/x/vuln v1.1.3 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 google.golang.org/protobuf v1.34.2 @@ -131,7 +131,7 @@ require ( helm.sh/helm/v3 v3.15.3 k8s.io/api v0.30.3 k8s.io/utils v0.0.0-20231127182322-b307cd553661 - modernc.org/sqlite v1.31.1 + modernc.org/sqlite v1.32.0 sigs.k8s.io/yaml v1.4.0 ) @@ -207,7 +207,7 @@ require ( github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/dlclark/regexp2 v1.4.0 // indirect - github.com/docker/cli v27.0.3+incompatible // indirect + github.com/docker/cli v27.1.1+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.2 // indirect github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect @@ -376,7 +376,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/oauth2 v0.20.0 // indirect - golang.org/x/sys v0.22.0 // indirect + golang.org/x/sys v0.23.0 // indirect golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.23.0 // indirect diff --git a/go.sum b/go.sum index a24b98453b2c..c34a319faf06 100644 --- a/go.sum +++ b/go.sum @@ -203,8 +203,8 @@ github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0/go.mod h1:GgeIE+1be8Ivm7Sh4RgwI42aTtC9qrcj+Y9Y6CjJhJs= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0 h1:GJHeeA2N7xrG3q30L2UXDyuWRzDM900/65j70wcM4Ww= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.13.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= @@ -542,8 +542,8 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/docker/cli v27.0.3+incompatible h1:usGs0/BoBW8MWxGeEtqPMkzOY56jZ6kYlSN5BLDioCQ= -github.com/docker/cli v27.0.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v27.1.1+incompatible h1:goaZxOqs4QKxznZjjBWKONQci/MywhtRv2oNn0GkeZE= +github.com/docker/cli v27.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= @@ -782,8 +782,8 @@ github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-containerregistry v0.20.1 h1:eTgx9QNYugV4DN5mz4U8hiAGTi1ybXn0TPi4Smd8du0= -github.com/google/go-containerregistry v0.20.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= +github.com/google/go-containerregistry v0.20.2 h1:B1wPJ1SN/S7pB+ZAimcciVD+r+yV/l/DSArMxlbwseo= +github.com/google/go-containerregistry v0.20.2/go.mod h1:z38EKdKh4h7IP2gSfUUqEvalZBqs6AoLeWfUy34nQC8= github.com/google/go-github/v55 v55.0.0 h1:4pp/1tNMB9X/LuAhs5i0KQAE40NmiR/y6prLNb9x9cg= github.com/google/go-github/v55 v55.0.0/go.mod h1:JLahOTA1DnXzhxEymmFF5PP2tSS9JVNj68mSZNDwskA= github.com/google/go-github/v62 v62.0.0 h1:/6mGCaRywZz9MuHyw9gD1CwsbmBX8GWsbFkwMmHdhl4= @@ -1143,8 +1143,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.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE= github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk= -github.com/open-policy-agent/opa v0.67.0 h1:FOdsO9yNhfmrh+72oVK7ImWmzruG+VSpfbr5IBqEWVs= -github.com/open-policy-agent/opa v0.67.0/go.mod h1:aqKlHc8E2VAAylYE9x09zJYr/fYzGX+JKne89UGqFzk= +github.com/open-policy-agent/opa v0.67.1 h1:rzy26J6g1X+CKknAcx0Vfbt41KqjuSzx4E0A8DAZf3E= +github.com/open-policy-agent/opa v0.67.1/go.mod h1:aqKlHc8E2VAAylYE9x09zJYr/fYzGX+JKne89UGqFzk= 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.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -1296,8 +1296,8 @@ github.com/spdx/tools-golang v0.5.5/go.mod h1:MVIsXx8ZZzaRWNQpUDhC4Dud34edUYJYec github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= -github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= -github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= +github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -1470,8 +1470,8 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4 golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1574,8 +1574,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= -golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= +golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1713,8 +1713,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= -golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= +golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 h1:FemxDzfMUcK2f3YY4H+05K9CDzbSVr2+q/JKN45pey0= golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1726,8 +1726,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1742,8 +1742,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2127,8 +2127,8 @@ modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= -modernc.org/sqlite v1.31.1 h1:XVU0VyzxrYHlBhIs1DiEgSl0ZtdnPtbLVy8hSkzxGrs= -modernc.org/sqlite v1.31.1/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA= +modernc.org/sqlite v1.32.0 h1:6BM4uGza7bWypsw4fdLRsLxut6bHe4c58VeqjRgST8s= +modernc.org/sqlite v1.32.0/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= From aadb09078843250c66087f46db9a2aa48094a118 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Thu, 15 Aug 2024 20:32:50 +0600 Subject: [PATCH 026/183] fix(misconf): change default TLS values for the Azure storage account (#7345) Signed-off-by: nikpivkin --- pkg/iac/adapters/arm/storage/adapt.go | 2 +- pkg/iac/adapters/arm/storage/adapt_test.go | 2 +- pkg/iac/adapters/terraform/azure/storage/adapt.go | 6 ++++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pkg/iac/adapters/arm/storage/adapt.go b/pkg/iac/adapters/arm/storage/adapt.go index 1b10ebbe9ad8..018949e24e10 100644 --- a/pkg/iac/adapters/arm/storage/adapt.go +++ b/pkg/iac/adapters/arm/storage/adapt.go @@ -59,7 +59,7 @@ func adaptAccounts(deployment azure.Deployment) []storage.Account { Metadata: resource.Properties.GetMetadata(), EnableLogging: types.BoolDefault(false, resource.Properties.GetMetadata()), }, - MinimumTLSVersion: resource.Properties.GetMapValue("minimumTlsVersion").AsStringValue("TLS1_0", resource.Properties.GetMetadata()), + MinimumTLSVersion: resource.Properties.GetMapValue("minimumTlsVersion").AsStringValue("", resource.Properties.GetMetadata()), Queues: queues, } accounts = append(accounts, account) diff --git a/pkg/iac/adapters/arm/storage/adapt_test.go b/pkg/iac/adapters/arm/storage/adapt_test.go index d1e124e2449e..f4fd81f47ad2 100644 --- a/pkg/iac/adapters/arm/storage/adapt_test.go +++ b/pkg/iac/adapters/arm/storage/adapt_test.go @@ -26,7 +26,7 @@ func Test_AdaptStorageDefaults(t *testing.T) { require.Len(t, output.Accounts, 1) account := output.Accounts[0] - assert.Equal(t, "TLS1_0", account.MinimumTLSVersion.Value()) + assert.Equal(t, "", account.MinimumTLSVersion.Value()) assert.False(t, account.EnforceHTTPS.Value()) } diff --git a/pkg/iac/adapters/terraform/azure/storage/adapt.go b/pkg/iac/adapters/terraform/azure/storage/adapt.go index edc5f0029be7..6a51cf1fca2b 100644 --- a/pkg/iac/adapters/terraform/azure/storage/adapt.go +++ b/pkg/iac/adapters/terraform/azure/storage/adapt.go @@ -6,6 +6,8 @@ import ( iacTypes "github.com/aquasecurity/trivy/pkg/iac/types" ) +const minimumTlsVersionOneTwo = "TLS1_2" + func Adapt(modules terraform.Modules) storage.Storage { accounts, containers, networkRules := adaptAccounts(modules) @@ -106,7 +108,7 @@ func adaptAccount(resource *terraform.Block) storage.Account { Metadata: resource.GetMetadata(), EnableLogging: iacTypes.BoolDefault(false, resource.GetMetadata()), }, - MinimumTLSVersion: iacTypes.StringDefault("TLS1_2", resource.GetMetadata()), + MinimumTLSVersion: iacTypes.StringDefault(minimumTlsVersionOneTwo, resource.GetMetadata()), } networkRulesBlocks := resource.GetBlocks("network_rules") @@ -127,7 +129,7 @@ func adaptAccount(resource *terraform.Block) storage.Account { } minTLSVersionAttr := resource.GetAttribute("min_tls_version") - account.MinimumTLSVersion = minTLSVersionAttr.AsStringValueOrDefault("TLS1_0", resource) + account.MinimumTLSVersion = minTLSVersionAttr.AsStringValueOrDefault(minimumTlsVersionOneTwo, resource) return account } From 0c6687d5ba0df5de2632aad26c21ea99565bd9e1 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 16 Aug 2024 04:58:27 +0600 Subject: [PATCH 027/183] refactor(misconf): highlight only affected rows (#7310) Signed-off-by: nikpivkin --- .../helm_testchart.overridden.json.golden | 2 +- pkg/iac/scan/code.go | 315 ++++++++++-------- pkg/iac/scan/code_test.go | 288 +++++++++++----- pkg/iac/scan/highlighting.go | 12 +- pkg/iac/types/range.go | 7 + 5 files changed, 396 insertions(+), 228 deletions(-) diff --git a/integration/testdata/helm_testchart.overridden.json.golden b/integration/testdata/helm_testchart.overridden.json.golden index 1b1ada2cd9a3..f4c984daa458 100644 --- a/integration/testdata/helm_testchart.overridden.json.golden +++ b/integration/testdata/helm_testchart.overridden.json.golden @@ -527,7 +527,7 @@ "IsCause": true, "Annotation": "", "Truncated": false, - "Highlighted": "\u001b[0m \u001b[38;5;33mrunAsUser\u001b[0m: \u001b[38;5;37m0", + "Highlighted": "\u001b[0m \u001b[38;5;33mrunAsUser\u001b[0m: \u001b[38;5;37m0\u001b[0m", "FirstCause": false, "LastCause": true } diff --git a/pkg/iac/scan/code.go b/pkg/iac/scan/code.go index e61b547988c6..8388dd4dbf6e 100644 --- a/pkg/iac/scan/code.go +++ b/pkg/iac/scan/code.go @@ -2,7 +2,6 @@ package scan import ( "bufio" - "bytes" "fmt" "io/fs" "path/filepath" @@ -15,6 +14,44 @@ type Code struct { Lines []Line } +func (c *Code) truncateLines(maxLines int) { + previouslyTruncated := maxLines-1 > 0 && c.Lines[maxLines-2].Truncated + if maxLines-1 > 0 && c.Lines[maxLines-1].LastCause { + c.Lines[maxLines-2].LastCause = true + } + c.Lines[maxLines-1] = Line{ + Truncated: true, + Number: c.Lines[maxLines-1].Number, + } + if previouslyTruncated { + c.Lines = c.Lines[:maxLines-1] + } else { + c.Lines = c.Lines[:maxLines] + } +} + +func (c *Code) markFirstAndLastCauses() { + var isFirst bool + var isLast bool + + for i, line := range c.Lines { + if line.IsCause && !isFirst { + c.Lines[i].FirstCause = true + isFirst = true + } + + if isFirst && !line.IsCause && i > 0 { + c.Lines[i-1].LastCause = true + isLast = true + break + } + } + + if !isLast && len(c.Lines) > 0 { + c.Lines[len(c.Lines)-1].LastCause = true + } +} + type Line struct { Number int `json:"Number"` Content string `json:"Content"` @@ -96,199 +133,187 @@ func OptionCodeWithHighlighted(include bool) CodeOption { } } -func validateRange(r iacTypes.Range) error { - if r.GetStartLine() < 0 || r.GetStartLine() > r.GetEndLine() || r.GetEndLine() < 0 { - return fmt.Errorf("invalid range: %s", r.String()) - } - return nil -} - -// nolint func (r *Result) GetCode(opts ...CodeOption) (*Code, error) { - settings := defaultCodeSettings for _, opt := range opts { opt(&settings) } - srcFS := r.Metadata().Range().GetFS() - if srcFS == nil { + fsys := r.Metadata().Range().GetFS() + if fsys == nil { return nil, fmt.Errorf("code unavailable: result was not mapped to a known filesystem") } - innerRange := r.Range() - outerRange := innerRange - metadata := r.Metadata() - for { - if parent := metadata.Parent(); parent != nil && - parent.Range().GetFilename() == metadata.Range().GetFilename() && - parent.Range().GetStartLine() > 0 { - outerRange = parent.Range() - metadata = *parent - continue - } - break + innerRange := r.metadata.Range() + if err := innerRange.Validate(); err != nil { + return nil, err } - if err := validateRange(innerRange); err != nil { - return nil, err + if innerRange.GetStartLine() == 0 { + return nil, fmt.Errorf("inner range has invalid start line: %s", innerRange.String()) } - if err := validateRange(outerRange); err != nil { + + outerRange := r.getOuterRange() + if err := outerRange.Validate(); err != nil { return nil, err } - slashed := filepath.ToSlash(r.fsPath) - slashed = strings.TrimPrefix(slashed, "/") - - content, err := fs.ReadFile(srcFS, slashed) + filePath := strings.TrimPrefix(filepath.ToSlash(r.fsPath), "/") + rawLines, err := readLinesFromFile(fsys, filePath, outerRange.GetStartLine(), outerRange.GetEndLine()) if err != nil { - return nil, fmt.Errorf("failed to read file from result filesystem (%#v): %w", srcFS, err) + return nil, err } - hasAnnotation := r.Annotation() != "" - - code := Code{ - Lines: nil, + if outerRange.GetEndLine()-outerRange.GetStartLine() > len(rawLines) { + return nil, fmt.Errorf("invalid outer range: %s", outerRange.String()) } - var rawLines []string - bs := bufio.NewScanner(bytes.NewReader(content)) - for bs.Scan() { - rawLines = append(rawLines, bs.Text()) - } - if bs.Err() != nil { - return nil, fmt.Errorf("failed to scan file : %w", err) - } + highlightedLines := r.getHighlightedLines(outerRange, innerRange, rawLines, settings) - var highlightedLines []string - if settings.includeHighlighted { - highlightedLines = highlight(iacTypes.CreateFSKey(innerRange.GetFS()), innerRange.GetLocalFilename(), content, settings.theme) - if len(highlightedLines) < len(rawLines) { - highlightedLines = rawLines - } + var code Code + + shrink := settings.allowTruncation && outerRange.LineCount() > (innerRange.LineCount()+10) + + if shrink { + code.Lines = r.getTruncatedLines(outerRange, innerRange, rawLines, highlightedLines) } else { - highlightedLines = make([]string, len(rawLines)) + code.Lines = r.getAllLines(outerRange, innerRange, rawLines, highlightedLines) } - if outerRange.GetEndLine()-1 >= len(rawLines) || innerRange.GetStartLine() == 0 { - return nil, fmt.Errorf("invalid line number") + if settings.allowTruncation && len(code.Lines) > settings.maxLines && settings.maxLines > 0 { + code.truncateLines(settings.maxLines) } - shrink := settings.allowTruncation && outerRange.LineCount() > (innerRange.LineCount()+10) + code.markFirstAndLastCauses() - if shrink { + return &code, nil +} - if outerRange.GetStartLine() < innerRange.GetStartLine() { - code.Lines = append( - code.Lines, - Line{ - Content: rawLines[outerRange.GetStartLine()-1], - Highlighted: highlightedLines[outerRange.GetStartLine()-1], - Number: outerRange.GetStartLine(), - }, - ) - if outerRange.GetStartLine()+1 < innerRange.GetStartLine() { - code.Lines = append( - code.Lines, - Line{ - Truncated: true, - Number: outerRange.GetStartLine() + 1, - }, - ) - } - } +func (r *Result) getHighlightedLines(outerRange, innerRange iacTypes.Range, rawLines []string, settings codeSettings) []string { - for lineNo := innerRange.GetStartLine(); lineNo <= innerRange.GetEndLine(); lineNo++ { + highlightedLines := make([]string, len(rawLines)) + if !settings.includeHighlighted { + return highlightedLines + } - if lineNo-1 >= len(rawLines) || lineNo-1 >= len(highlightedLines) { - break - } + content := strings.Join(rawLines, "\n") + fsKey := iacTypes.CreateFSKey(innerRange.GetFS()) + highlightedLines = highlight(fsKey, innerRange.GetLocalFilename(), + outerRange.GetStartLine(), outerRange.GetEndLine(), content, settings.theme) - line := Line{ - Number: lineNo, - Content: strings.TrimSuffix(rawLines[lineNo-1], "\r"), - Highlighted: strings.TrimSuffix(highlightedLines[lineNo-1], "\r"), - IsCause: true, - } + if len(highlightedLines) < len(rawLines) { + return rawLines + } - if hasAnnotation && lineNo == innerRange.GetStartLine() { - line.Annotation = r.Annotation() - } + return highlightedLines +} - code.Lines = append(code.Lines, line) - } +func (r *Result) getOuterRange() iacTypes.Range { + outer := r.Metadata().Range() + for parent := r.Metadata().Parent(); parent != nil && + parent.Range().GetFilename() == outer.GetFilename() && + parent.Range().GetStartLine() > 0; parent = parent.Parent() { + outer = parent.Range() + } + return outer +} - if outerRange.GetEndLine() > innerRange.GetEndLine() { - if outerRange.GetEndLine() > innerRange.GetEndLine()+1 { - code.Lines = append( - code.Lines, - Line{ - Truncated: true, - Number: outerRange.GetEndLine() - 1, - }, - ) - } - code.Lines = append( - code.Lines, - Line{ - Content: rawLines[outerRange.GetEndLine()-1], - Highlighted: highlightedLines[outerRange.GetEndLine()-1], - Number: outerRange.GetEndLine(), - }, - ) +func (r *Result) getTruncatedLines(outerRange, innerRange iacTypes.Range, rawLines, highlightedLines []string) []Line { + var lines []Line + + if outerRange.GetStartLine() < innerRange.GetStartLine() { + lines = append(lines, Line{ + Content: rawLines[0], + Highlighted: highlightedLines[0], + Number: outerRange.GetStartLine(), + }) + if outerRange.GetStartLine()+1 < innerRange.GetStartLine() { + lines = append(lines, Line{ + Truncated: true, + Number: outerRange.GetStartLine() + 1, + }) + } + } + for lineNo := innerRange.GetStartLine() - outerRange.GetStartLine(); lineNo <= innerRange.GetEndLine()-outerRange.GetStartLine(); lineNo++ { + if lineNo >= len(rawLines) || lineNo >= len(highlightedLines) { + break } - } else { - for lineNo := outerRange.GetStartLine(); lineNo <= outerRange.GetEndLine(); lineNo++ { + line := Line{ + Number: lineNo + outerRange.GetStartLine(), + Content: strings.TrimSuffix(rawLines[lineNo], "\r"), + Highlighted: strings.TrimSuffix(highlightedLines[lineNo], "\r"), + IsCause: true, + } - line := Line{ - Number: lineNo, - Content: strings.TrimSuffix(rawLines[lineNo-1], "\r"), - Highlighted: strings.TrimSuffix(highlightedLines[lineNo-1], "\r"), - IsCause: lineNo >= innerRange.GetStartLine() && lineNo <= innerRange.GetEndLine(), - } + if r.Annotation() != "" && lineNo == innerRange.GetStartLine()-outerRange.GetStartLine()-1 { + line.Annotation = r.Annotation() + } - if hasAnnotation && lineNo == innerRange.GetStartLine() { - line.Annotation = r.Annotation() - } + lines = append(lines, line) + } - code.Lines = append(code.Lines, line) + if outerRange.GetEndLine() > innerRange.GetEndLine() { + if outerRange.GetEndLine() > innerRange.GetEndLine()+1 { + lines = append(lines, Line{ + Truncated: true, + Number: outerRange.GetEndLine() - 1, + }) } + lines = append(lines, Line{ + Content: rawLines[outerRange.GetEndLine()-outerRange.GetStartLine()], + Highlighted: highlightedLines[outerRange.GetEndLine()-outerRange.GetStartLine()], + Number: outerRange.GetEndLine(), + }) } - if settings.allowTruncation && len(code.Lines) > settings.maxLines && settings.maxLines > 0 { - previouslyTruncated := settings.maxLines-1 > 0 && code.Lines[settings.maxLines-2].Truncated - if settings.maxLines-1 > 0 && code.Lines[settings.maxLines-1].LastCause { - code.Lines[settings.maxLines-2].LastCause = true - } - code.Lines[settings.maxLines-1] = Line{ - Truncated: true, - Number: code.Lines[settings.maxLines-1].Number, + return lines +} + +func (r *Result) getAllLines(outerRange, innerRange iacTypes.Range, rawLines, highlightedLines []string) []Line { + lines := make([]Line, 0, outerRange.GetEndLine()-outerRange.GetStartLine()+1) + + for lineNo := 0; lineNo <= outerRange.GetEndLine()-outerRange.GetStartLine(); lineNo++ { + line := Line{ + Number: lineNo + outerRange.GetStartLine(), + Content: strings.TrimSuffix(rawLines[lineNo], "\r"), + Highlighted: strings.TrimSuffix(highlightedLines[lineNo], "\r"), + IsCause: lineNo >= innerRange.GetStartLine()-outerRange.GetStartLine() && + lineNo <= innerRange.GetEndLine()-outerRange.GetStartLine(), } - if previouslyTruncated { - code.Lines = code.Lines[:settings.maxLines-1] - } else { - code.Lines = code.Lines[:settings.maxLines] + + if r.Annotation() != "" && lineNo == innerRange.GetStartLine()-outerRange.GetStartLine()-1 { + line.Annotation = r.Annotation() } + + lines = append(lines, line) } - var first, last bool - for i, line := range code.Lines { - if line.IsCause && !first { - code.Lines[i].FirstCause = true - first = true - continue - } - if first && !line.IsCause && i > 0 { - code.Lines[i-1].LastCause = true - last = true - break + return lines +} + +func readLinesFromFile(fsys fs.FS, path string, from, to int) ([]string, error) { + slashedPath := strings.TrimPrefix(filepath.ToSlash(path), "/") + + file, err := fsys.Open(slashedPath) + if err != nil { + return nil, fmt.Errorf("failed to read file from result filesystem: %w", err) + } + defer file.Close() + + scanner := bufio.NewScanner(file) + rawLines := make([]string, 0, to-from+1) + + for lineNum := 0; scanner.Scan() && lineNum < to; lineNum++ { + if lineNum >= from-1 { + rawLines = append(rawLines, scanner.Text()) } } - if !last && len(code.Lines) > 0 { - code.Lines[len(code.Lines)-1].LastCause = true + + if err := scanner.Err(); err != nil { + return nil, fmt.Errorf("failed to scan file: %w", err) } - return &code, nil + return rawLines, nil } diff --git a/pkg/iac/scan/code_test.go b/pkg/iac/scan/code_test.go index c3ffe3725ef1..559f1d9dfe69 100644 --- a/pkg/iac/scan/code_test.go +++ b/pkg/iac/scan/code_test.go @@ -1,11 +1,10 @@ package scan import ( - "os" "strings" "testing" + "testing/fstest" - "github.com/liamg/memoryfs" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -13,19 +12,18 @@ import ( ) func TestResult_GetCode(t *testing.T) { - + const line = "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind." tests := []struct { - name string - source string - filename string - start int - end int - outerStart int - outerEnd int - expected []Line - options []CodeOption - wantErr bool - annotation string + name string + source string + filename string + startInnerLine int + endInnerLine int + startOuterLine int + endOuterLine int + expected []Line + options []CodeOption + wantErr bool }{ { name: "basic w/ defaults", @@ -33,9 +31,9 @@ func TestResult_GetCode(t *testing.T) { 2 3 4`, - filename: "test.txt", - start: 2, - end: 3, + filename: "test.txt", + startInnerLine: 2, + endInnerLine: 3, expected: []Line{ { Number: 2, @@ -60,12 +58,12 @@ func TestResult_GetCode(t *testing.T) { source: `resource "aws_s3_bucket" "something" { bucket = "something" }`, - filename: "main.tf", - start: 2, - end: 2, - outerStart: 1, - outerEnd: 3, - options: []CodeOption{OptionCodeWithHighlighted(false)}, + filename: "main.tf", + startInnerLine: 2, + endInnerLine: 2, + startOuterLine: 1, + endOuterLine: 3, + options: []CodeOption{OptionCodeWithHighlighted(false)}, expected: []Line{ { Number: 1, @@ -90,10 +88,10 @@ func TestResult_GetCode(t *testing.T) { 2 3 4`, - filename: "", - start: 2, - end: 3, - wantErr: true, + filename: "", + startInnerLine: 2, + endInnerLine: 3, + wantErr: true, }, { name: "no line numbers", @@ -101,10 +99,10 @@ func TestResult_GetCode(t *testing.T) { 2 3 4`, - filename: "test.txt", - start: 0, - end: 0, - wantErr: true, + filename: "test.txt", + startInnerLine: 0, + endInnerLine: 0, + wantErr: true, }, { name: "negative line numbers", @@ -112,10 +110,10 @@ func TestResult_GetCode(t *testing.T) { 2 3 4`, - filename: "test.txt", - start: -2, - end: -1, - wantErr: true, + filename: "test.txt", + startInnerLine: -2, + endInnerLine: -1, + wantErr: true, }, { name: "invalid line numbers", @@ -123,17 +121,17 @@ func TestResult_GetCode(t *testing.T) { 2 3 4`, - filename: "test.txt", - start: 5, - end: 6, - wantErr: true, + filename: "test.txt", + startInnerLine: 5, + endInnerLine: 6, + wantErr: true, }, { - name: "syntax highlighting", - source: `FROM ubuntu`, - filename: "Dockerfile", - start: 1, - end: 1, + name: "syntax highlighting", + source: `FROM ubuntu`, + filename: "Dockerfile", + startInnerLine: 1, + endInnerLine: 1, expected: []Line{ { Number: 1, @@ -146,81 +144,81 @@ func TestResult_GetCode(t *testing.T) { }, }, { - name: "truncation", - source: strings.Repeat("If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.\n", 100), - filename: "longfile.txt", - start: 1, - end: 100, + name: "truncation", + source: strings.Repeat(line+"\n", 100), + filename: "longfile.txt", + startInnerLine: 1, + endInnerLine: 100, expected: []Line{ { Number: 1, - Content: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Content: line, IsCause: true, - Highlighted: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Highlighted: line, FirstCause: true, LastCause: false, }, { Number: 2, - Content: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Content: line, IsCause: true, - Highlighted: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Highlighted: line, FirstCause: false, LastCause: false, }, { Number: 3, - Content: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Content: line, IsCause: true, - Highlighted: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Highlighted: line, FirstCause: false, LastCause: false, }, { Number: 4, - Content: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Content: line, IsCause: true, - Highlighted: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Highlighted: line, FirstCause: false, LastCause: false, }, { Number: 5, - Content: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Content: line, IsCause: true, - Highlighted: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Highlighted: line, FirstCause: false, LastCause: false, }, { Number: 6, - Content: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Content: line, IsCause: true, - Highlighted: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Highlighted: line, FirstCause: false, LastCause: false, }, { Number: 7, - Content: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Content: line, IsCause: true, - Highlighted: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Highlighted: line, FirstCause: false, LastCause: false, }, { Number: 8, - Content: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Content: line, IsCause: true, - Highlighted: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Highlighted: line, FirstCause: false, LastCause: false, }, { Number: 9, - Content: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Content: line, IsCause: true, - Highlighted: "If you can do a half-assed job of anything, you're a one-eyed man in a kingdom of the blind.", + Highlighted: line, FirstCause: false, LastCause: true, }, @@ -230,26 +228,97 @@ func TestResult_GetCode(t *testing.T) { }, }, }, + { + name: "invalid inner range", + source: `Test`, + filename: "test.txt", + startInnerLine: 0, + endInnerLine: 0, + wantErr: true, + }, + { + name: "invalid outer range", + source: `Test`, + filename: "test.txt", + startInnerLine: 10, + endInnerLine: 12, + startOuterLine: 5, + endOuterLine: 3, + wantErr: true, + }, + { + name: "truncate with outer range", + source: strings.Repeat(line+"\n", 100), + filename: "longfile.txt", + startOuterLine: 1, + endOuterLine: 100, + startInnerLine: 10, + endInnerLine: 12, + options: []CodeOption{OptionCodeWithTruncation(true)}, + expected: []Line{ + { + Number: 1, + Content: line, + Highlighted: line, + }, + { + Number: 2, + Truncated: true, + }, + { + Number: 10, + Content: line, + IsCause: true, + FirstCause: true, + Highlighted: line, + }, + { + Number: 11, + Content: line, + IsCause: true, + Highlighted: line, + }, + { + Number: 12, + Content: line, + IsCause: true, + LastCause: true, + Highlighted: line, + }, + { + Number: 99, + Truncated: true, + }, + { + Number: 100, + Content: line, + Highlighted: line, + }, + }, + }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - system := memoryfs.New() - require.NoError(t, system.WriteFile(test.filename, []byte(test.source), os.ModePerm)) + fsys := fstest.MapFS{ + test.filename: &fstest.MapFile{ + Data: []byte(test.source), + }, + } + meta := iacTypes.NewMetadata( - iacTypes.NewRange(test.filename, test.start, test.end, "", system), + iacTypes.NewRange(test.filename, test.startInnerLine, test.endInnerLine, "", fsys), "", ) - if test.outerStart > 0 { + if test.startOuterLine > 0 { meta = meta.WithParent(iacTypes.NewMetadata( - iacTypes.NewRange(test.filename, test.outerStart, test.outerEnd, "", system), + iacTypes.NewRange(test.filename, test.startOuterLine, test.endOuterLine, "", fsys), "", )) } result := &Result{ - annotation: test.annotation, - metadata: meta, - fsPath: test.filename, + metadata: meta, + fsPath: test.filename, } code, err := result.GetCode(test.options...) if test.wantErr { @@ -262,3 +331,72 @@ func TestResult_GetCode(t *testing.T) { } } + +func TestCode_IsCauseMultiline(t *testing.T) { + + tests := []struct { + name string + code Code + expected bool + }{ + { + name: "no cause", + code: Code{ + Lines: []Line{ + { + Number: 1, + Content: "Test", + Highlighted: "Test", + }, + }, + }, + expected: false, + }, + { + name: "one cause", + code: Code{ + Lines: []Line{ + { + Number: 1, + Content: "Test", + IsCause: true, + Highlighted: "Test", + }, + }, + }, + expected: false, + }, + { + name: "multiple causes", + code: Code{ + Lines: []Line{ + { + Number: 1, + Content: "Test", + IsCause: true, + Highlighted: "Test", + }, + { + Number: 2, + Content: "Test", + IsCause: true, + Highlighted: "Test", + }, + { + Number: 3, + Content: "Test", + IsCause: true, + Highlighted: "Test", + }, + }, + }, + expected: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equal(t, tt.expected, tt.code.IsCauseMultiline()) + }) + } +} diff --git a/pkg/iac/scan/highlighting.go b/pkg/iac/scan/highlighting.go index 12bd3fe086cf..df260130d599 100644 --- a/pkg/iac/scan/highlighting.go +++ b/pkg/iac/scan/highlighting.go @@ -34,9 +34,9 @@ var globalCache = &cache{ data: make(map[string][]string), } -func highlight(fsKey, filename string, input []byte, theme string) []string { +func highlight(fsKey, filename string, startLine, endLine int, input, theme string) []string { - key := fmt.Sprintf("%s|%s", fsKey, filename) + key := fmt.Sprintf("%s|%s|%d-%d", fsKey, filename, startLine, endLine) if lines, ok := globalCache.Get(key); ok { return lines } @@ -56,15 +56,13 @@ func highlight(fsKey, filename string, input []byte, theme string) []string { formatter = formatters.Fallback } - // replace windows line endings - input = bytes.ReplaceAll(input, []byte{0x0d}, []byte{}) - iterator, err := lexer.Tokenise(nil, string(input)) + iterator, err := lexer.Tokenise(nil, input) if err != nil { return nil } - buffer := bytes.NewBuffer([]byte{}) - if err := formatter.Format(buffer, style, iterator); err != nil { + var buffer bytes.Buffer + if err := formatter.Format(&buffer, style, iterator); err != nil { return nil } diff --git a/pkg/iac/types/range.go b/pkg/iac/types/range.go index c06a2bf6fe1a..754ee29c9675 100755 --- a/pkg/iac/types/range.go +++ b/pkg/iac/types/range.go @@ -146,3 +146,10 @@ func (r Range) GetFS() fs.FS { func (r Range) GetSourcePrefix() string { return r.sourcePrefix } + +func (r Range) Validate() error { + if r.startLine < 0 || r.endLine < 0 || r.startLine > r.endLine { + return fmt.Errorf("invalid range: %s", r.String()) + } + return nil +} From c5c62d5ff05420321f9cdbfb93e2591e0866a342 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Tue, 20 Aug 2024 10:48:57 +0600 Subject: [PATCH 028/183] fix(misconf): wrap Azure PortRange in iac types (#7357) Signed-off-by: nikpivkin --- pkg/iac/adapters/arm/network/adapt.go | 8 ++++---- pkg/iac/adapters/terraform/azure/network/adapt.go | 12 ++++++------ .../adapters/terraform/azure/network/adapt_test.go | 8 ++++---- pkg/iac/providers/azure/network/network.go | 6 +++--- pkg/iac/rego/schemas/cloud.json | 6 ++++-- 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/pkg/iac/adapters/arm/network/adapt.go b/pkg/iac/adapters/arm/network/adapt.go index 5201b84761e7..214cf75c3c90 100644 --- a/pkg/iac/adapters/arm/network/adapt.go +++ b/pkg/iac/adapters/arm/network/adapt.go @@ -27,11 +27,11 @@ func adaptSecurityGroups(deployment azure.Deployment) (sgs []network.SecurityGro func adaptSecurityGroup(resource azure.Resource, deployment azure.Deployment) network.SecurityGroup { return network.SecurityGroup{ Metadata: resource.Metadata, - Rules: adaptSecurityGroupRules(resource, deployment), + Rules: adaptSecurityGroupRules(deployment), } } -func adaptSecurityGroupRules(resource azure.Resource, deployment azure.Deployment) (rules []network.SecurityGroupRule) { +func adaptSecurityGroupRules(deployment azure.Deployment) (rules []network.SecurityGroupRule) { for _, resource := range deployment.GetResourcesByType("Microsoft.Network/networkSecurityGroups/securityRules") { rules = append(rules, adaptSecurityGroupRule(resource)) } @@ -120,7 +120,7 @@ func expandRange(r string, m iacTypes.Metadata) network.PortRange { return network.PortRange{ Metadata: m, - Start: start, - End: end, + Start: iacTypes.Int(start, m), + End: iacTypes.Int(end, m), } } diff --git a/pkg/iac/adapters/terraform/azure/network/adapt.go b/pkg/iac/adapters/terraform/azure/network/adapt.go index b2866cd9100a..4bbcca6c5fd2 100644 --- a/pkg/iac/adapters/terraform/azure/network/adapt.go +++ b/pkg/iac/adapters/terraform/azure/network/adapt.go @@ -136,8 +136,8 @@ func (a *adapter) adaptSource(ruleBlock *terraform.Block, rule *network.Security f := sourcePortRangeAttr.AsNumber() rule.SourcePorts = append(rule.SourcePorts, network.PortRange{ Metadata: sourcePortRangeAttr.GetMetadata(), - Start: int(f), - End: int(f), + Start: iacTypes.Int(int(f), sourcePortRangeAttr.GetMetadata()), + End: iacTypes.Int(int(f), sourcePortRangeAttr.GetMetadata()), }) } } @@ -160,8 +160,8 @@ func (a *adapter) adaptDestination(ruleBlock *terraform.Block, rule *network.Sec f := destPortRangeAttr.AsNumber() rule.DestinationPorts = append(rule.DestinationPorts, network.PortRange{ Metadata: destPortRangeAttr.GetMetadata(), - Start: int(f), - End: int(f), + Start: iacTypes.Int(int(f), destPortRangeAttr.GetMetadata()), + End: iacTypes.Int(int(f), destPortRangeAttr.GetMetadata()), }) } } @@ -189,8 +189,8 @@ func expandRange(r string, m iacTypes.Metadata) network.PortRange { return network.PortRange{ Metadata: m, - Start: start, - End: end, + Start: iacTypes.Int(start, m), + End: iacTypes.Int(end, m), } } diff --git a/pkg/iac/adapters/terraform/azure/network/adapt_test.go b/pkg/iac/adapters/terraform/azure/network/adapt_test.go index 15b966b06ffc..99931b6b2d3e 100644 --- a/pkg/iac/adapters/terraform/azure/network/adapt_test.go +++ b/pkg/iac/adapters/terraform/azure/network/adapt_test.go @@ -65,15 +65,15 @@ func Test_Adapt(t *testing.T) { SourcePorts: []network.PortRange{ { Metadata: iacTypes.NewTestMetadata(), - Start: 0, - End: 65535, + Start: iacTypes.IntTest(0), + End: iacTypes.IntTest(65535), }, }, DestinationPorts: []network.PortRange{ { Metadata: iacTypes.NewTestMetadata(), - Start: 3389, - End: 3389, + Start: iacTypes.IntTest(3389), + End: iacTypes.IntTest(3389), }, }, Protocol: iacTypes.String("TCP", iacTypes.NewTestMetadata()), diff --git a/pkg/iac/providers/azure/network/network.go b/pkg/iac/providers/azure/network/network.go index 71c56b62b465..4fdc56e44e86 100755 --- a/pkg/iac/providers/azure/network/network.go +++ b/pkg/iac/providers/azure/network/network.go @@ -27,12 +27,12 @@ type SecurityGroupRule struct { type PortRange struct { Metadata iacTypes.Metadata - Start int - End int + Start iacTypes.IntValue + End iacTypes.IntValue } func (r PortRange) Includes(port int) bool { - return port >= r.Start && port <= r.End + return port >= r.Start.Value() && port <= r.End.Value() } type NetworkWatcherFlowLog struct { diff --git a/pkg/iac/rego/schemas/cloud.json b/pkg/iac/rego/schemas/cloud.json index a4bab9423d38..530ba5bfaa1f 100644 --- a/pkg/iac/rego/schemas/cloud.json +++ b/pkg/iac/rego/schemas/cloud.json @@ -5207,10 +5207,12 @@ "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.Metadata" }, "end": { - "type": "integer" + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.IntValue" }, "start": { - "type": "integer" + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.IntValue" } } }, From efdbd8f19ab0ab0c3b48293d43e51c81b7b03b89 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Tue, 20 Aug 2024 10:55:45 +0600 Subject: [PATCH 029/183] feat(misconf): scanning support for YAML and JSON (#7311) Signed-off-by: nikpivkin --- docs/docs/coverage/iac/index.md | 3 + .../configuration/cli/trivy_config.md | 1 + .../configuration/cli/trivy_filesystem.md | 1 + .../configuration/cli/trivy_image.md | 1 + .../configuration/cli/trivy_kubernetes.md | 1 + .../configuration/cli/trivy_repository.md | 1 + .../configuration/cli/trivy_rootfs.md | 1 + .../references/configuration/cli/trivy_vm.md | 1 + .../references/configuration/config-file.md | 3 + docs/docs/scanner/misconfiguration/index.md | 63 ++- pkg/commands/artifact/run.go | 84 +-- pkg/fanal/analyzer/analyzer.go | 6 +- pkg/fanal/analyzer/config/all/import.go | 2 + .../analyzer/config/azurearm/azurearm.go | 4 +- .../config/cloudformation/cloudformation.go | 4 +- pkg/fanal/analyzer/config/config.go | 7 +- pkg/fanal/analyzer/config/config_test.go | 17 +- .../analyzer/config/dockerfile/docker.go | 4 +- pkg/fanal/analyzer/config/helm/helm.go | 4 +- pkg/fanal/analyzer/config/json/json.go | 36 ++ pkg/fanal/analyzer/config/k8s/k8s.go | 4 +- .../analyzer/config/terraform/terraform.go | 3 +- .../config/terraformplan/json/json.go | 4 +- .../config/terraformplan/snapshot/snapshot.go | 4 +- pkg/fanal/analyzer/config/yaml/yaml.go | 36 ++ pkg/fanal/analyzer/const.go | 4 + .../analyzer/imgconf/dockerfile/dockerfile.go | 3 +- pkg/fanal/artifact/image/image_test.go | 110 ++-- pkg/fanal/artifact/local/fs_test.go | 513 ++++++++++++++---- .../multiple-failures/rego/policy.rego | 25 +- .../azurearm/no-results/rego/policy.rego | 25 +- .../azurearm/passed/rego/policy.rego | 25 +- .../azurearm/single-failure/rego/policy.rego | 25 +- .../multiple-failures/rego/policy.rego | 25 +- .../no-results/rego/policy.rego | 25 +- .../params/code/rego/policy.rego | 4 +- .../cloudformation/passed/rego/policy.rego | 25 +- .../single-failure/rego/policy.rego | 25 +- .../misconfig/json/passed/checks/test.rego | 17 + .../misconfig/json/passed/src/test1.json | 3 + .../misconfig/json/passed/src/test2.json | 3 + .../json/with-schema/checks/test.rego | 17 + .../json/with-schema/schemas/test.json | 9 + .../misconfig/json/with-schema/src/test1.json | 3 + .../misconfig/json/with-schema/src/test2.json | 3 + .../multiple-failures/rego/policy.rego | 25 +- .../kubernetes/no-results/rego/policy.rego | 25 +- .../kubernetes/passed/rego/policy.rego | 25 +- .../single-failure/rego/policy.rego | 25 +- .../testdata/misconfig/mixed/rego/policy.rego | 25 +- .../misconfig/yaml/passed/checks/test.rego | 17 + .../misconfig/yaml/passed/src/test1.yaml | 1 + .../misconfig/yaml/passed/src/test2.yml | 1 + .../yaml/with-schema/checks/test.rego | 17 + .../yaml/with-schema/schemas/test.json | 9 + .../misconfig/yaml/with-schema/src/test1.yaml | 1 + .../misconfig/yaml/with-schema/src/test2.yml | 1 + pkg/fanal/artifact/repo/git_test.go | 4 +- pkg/fanal/types/const.go | 1 + pkg/flag/misconf_flags.go | 18 +- pkg/iac/detection/detect.go | 48 +- pkg/iac/detection/detect_test.go | 138 +++++ pkg/iac/rego/build.go | 10 +- pkg/iac/rego/embed.go | 2 +- pkg/iac/rego/load.go | 2 +- pkg/iac/rego/scanner.go | 6 + pkg/iac/rego/scanner_test.go | 70 +++ pkg/iac/scanners/azure/arm/scanner.go | 3 +- pkg/iac/scanners/cloudformation/scanner.go | 3 +- pkg/iac/scanners/dockerfile/scanner.go | 3 +- pkg/iac/scanners/helm/scanner.go | 3 +- pkg/iac/scanners/json/scanner.go | 3 +- pkg/iac/scanners/kubernetes/scanner.go | 3 +- pkg/iac/scanners/options/scanner.go | 7 + pkg/iac/scanners/terraform/scanner.go | 3 +- .../scanners/terraformplan/tfjson/scanner.go | 3 +- pkg/iac/scanners/toml/scanner.go | 3 +- pkg/iac/scanners/yaml/scanner.go | 3 +- pkg/misconf/config_schema.go | 74 +++ pkg/misconf/config_schema_test.go | 41 ++ pkg/misconf/scanner.go | 98 ++-- pkg/misconf/scanner_test.go | 26 +- pkg/misconf/testdata/schemas/no-schema.file | 1 + .../schemas/schema-with-bad-regex.json | 9 + pkg/misconf/testdata/schemas/schema1.json | 9 + pkg/misconf/testdata/schemas/schema2.json | 9 + 86 files changed, 1516 insertions(+), 443 deletions(-) create mode 100644 pkg/fanal/analyzer/config/json/json.go create mode 100644 pkg/fanal/analyzer/config/yaml/yaml.go create mode 100644 pkg/fanal/artifact/local/testdata/misconfig/json/passed/checks/test.rego create mode 100644 pkg/fanal/artifact/local/testdata/misconfig/json/passed/src/test1.json create mode 100644 pkg/fanal/artifact/local/testdata/misconfig/json/passed/src/test2.json create mode 100644 pkg/fanal/artifact/local/testdata/misconfig/json/with-schema/checks/test.rego create mode 100644 pkg/fanal/artifact/local/testdata/misconfig/json/with-schema/schemas/test.json create mode 100644 pkg/fanal/artifact/local/testdata/misconfig/json/with-schema/src/test1.json create mode 100644 pkg/fanal/artifact/local/testdata/misconfig/json/with-schema/src/test2.json create mode 100644 pkg/fanal/artifact/local/testdata/misconfig/yaml/passed/checks/test.rego create mode 100644 pkg/fanal/artifact/local/testdata/misconfig/yaml/passed/src/test1.yaml create mode 100644 pkg/fanal/artifact/local/testdata/misconfig/yaml/passed/src/test2.yml create mode 100644 pkg/fanal/artifact/local/testdata/misconfig/yaml/with-schema/checks/test.rego create mode 100644 pkg/fanal/artifact/local/testdata/misconfig/yaml/with-schema/schemas/test.json create mode 100644 pkg/fanal/artifact/local/testdata/misconfig/yaml/with-schema/src/test1.yaml create mode 100644 pkg/fanal/artifact/local/testdata/misconfig/yaml/with-schema/src/test2.yml create mode 100644 pkg/misconf/config_schema.go create mode 100644 pkg/misconf/config_schema_test.go create mode 100644 pkg/misconf/testdata/schemas/no-schema.file create mode 100644 pkg/misconf/testdata/schemas/schema-with-bad-regex.json create mode 100644 pkg/misconf/testdata/schemas/schema1.json create mode 100644 pkg/misconf/testdata/schemas/schema2.json diff --git a/docs/docs/coverage/iac/index.md b/docs/docs/coverage/iac/index.md index 168c3dd650fa..963e9b11b8c5 100644 --- a/docs/docs/coverage/iac/index.md +++ b/docs/docs/coverage/iac/index.md @@ -17,6 +17,9 @@ Trivy scans Infrastructure as Code (IaC) files for | [CloudFormation](cloudformation.md) | \*.yml, \*.yaml, \*.json | | [Azure ARM Template](azure-arm.md) | \*.json | | [Helm](helm.md) | \*.yaml, \*.tpl, \*.tar.gz, etc. | +| [YAML][json-and-yaml] | \*.yaml, \*.yml | +| [JSON][json-and-yaml] | \*.json | [misconf]: ../../scanner/misconfiguration/index.md [secret]: ../../scanner/secret.md +[json-and-yaml]: ../../scanner/misconfiguration/index.md#scan-arbitrary-json-and-yaml-configurations diff --git a/docs/docs/references/configuration/cli/trivy_config.md b/docs/docs/references/configuration/cli/trivy_config.md index 0176c09ea58f..b32e74c1c752 100644 --- a/docs/docs/references/configuration/cli/trivy_config.md +++ b/docs/docs/references/configuration/cli/trivy_config.md @@ -17,6 +17,7 @@ trivy config [flags] DIR --compliance string compliance report to generate --config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files --config-data strings specify paths from which data for the Rego checks will be recursively loaded + --config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking --enable-modules strings [EXPERIMENTAL] module names to enable --exit-code int specify exit code when any security issues are found --file-patterns strings specify config file patterns diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index 2202bc27f518..16c5909549e3 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -27,6 +27,7 @@ trivy filesystem [flags] PATH --compliance string compliance report to generate --config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files --config-data strings specify paths from which data for the Rego checks will be recursively loaded + --config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking --custom-headers strings custom headers in client mode --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index a1de0595a7bc..bbd75e690cfc 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -41,6 +41,7 @@ trivy image [flags] IMAGE_NAME --compliance string compliance report to generate (docker-cis-1.6.0) --config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files --config-data strings specify paths from which data for the Rego checks will be recursively loaded + --config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking --custom-headers strings custom headers in client mode --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 4516509d5834..2bc84e905282 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -37,6 +37,7 @@ trivy kubernetes [flags] [CONTEXT] --compliance string compliance report to generate (k8s-nsa-1.0,k8s-cis-1.23,eks-cis-1.4,rke2-cis-1.24,k8s-pss-baseline-0.1,k8s-pss-restricted-0.1) --config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files --config-data strings specify paths from which data for the Rego checks will be recursively loaded + --config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages --detection-priority string specify the detection priority: diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index 5d4bc5ce4161..eeef161725a8 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -27,6 +27,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --commit string pass the commit hash to be scanned --config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files --config-data strings specify paths from which data for the Rego checks will be recursively loaded + --config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking --custom-headers strings custom headers in client mode --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index 60fdf4e623fa..88f5bd197779 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -29,6 +29,7 @@ trivy rootfs [flags] ROOTDIR --checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:0") --config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files --config-data strings specify paths from which data for the Rego checks will be recursively loaded + --config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking --custom-headers strings custom headers in client mode --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages diff --git a/docs/docs/references/configuration/cli/trivy_vm.md b/docs/docs/references/configuration/cli/trivy_vm.md index 4bae981c7577..fef17624222d 100644 --- a/docs/docs/references/configuration/cli/trivy_vm.md +++ b/docs/docs/references/configuration/cli/trivy_vm.md @@ -25,6 +25,7 @@ trivy vm [flags] VM_IMAGE --cache-ttl duration cache TTL when using redis as cache backend --checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:0") --compliance string compliance report to generate + --config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking --custom-headers strings custom headers in client mode --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages diff --git a/docs/docs/references/configuration/config-file.md b/docs/docs/references/configuration/config-file.md index b3876d6ad225..f3edb6a8e2b6 100644 --- a/docs/docs/references/configuration/config-file.md +++ b/docs/docs/references/configuration/config-file.md @@ -386,6 +386,9 @@ misconfiguration: # Same as '--cf-params' params: [] + # Same as '--config-file-schemas' + config-file-schemas: [] + helm: # Same as '--helm-api-versions' api-versions: [] diff --git a/docs/docs/scanner/misconfiguration/index.md b/docs/docs/scanner/misconfiguration/index.md index eae768456029..7615f3342265 100644 --- a/docs/docs/scanner/misconfiguration/index.md +++ b/docs/docs/scanner/misconfiguration/index.md @@ -107,7 +107,7 @@ $ trivy config --severity HIGH,CRITICAL ./iac
Result -``` +```bash 2022-06-06T11:01:21.142+0100 INFO Detected config files: 8 Dockerfile (dockerfile) @@ -343,6 +343,61 @@ You can load checks bundle as OCI Image from a Container Registry using the `--c trivy config --checks-bundle-repository myregistry.local/mychecks --namespaces user myapp ``` + +### Scan arbitrary JSON and YAML configurations +By default, scanning JSON and YAML configurations is disabled, since Trivy does not contain built-in checks for these configurations. To enable it, pass the `json` or `yaml` to `--misconfig-scanners`. See [Enabling a subset of misconfiguration scanners](#enabling-a-subset-of-misconfiguration-scanners) for more information. Trivy will pass each file as is to the checks input. + + +!!! example +```bash +$ cat iac/serverless.yaml +service: serverless-rest-api-with-pynamodb + +frameworkVersion: ">=2.24.0" + +plugins: + - serverless-python-requirements +... + +$ cat serverless.rego +# METADATA +# title: Serverless Framework service name not starting with "aws-" +# description: Ensure that Serverless Framework service names start with "aws-" +# schemas: +# - input: schema["serverless-schema"] +# custom: +# id: SF001 +# severity: LOW +package user.serverless001 + +deny[res] { + not startswith(input.service, "aws-") + res := result.new( + sprintf("Service name %q is not allowed", [input.service]), + input.service + ) +} + +$ trivy config --misconfig-scanners=json,yaml --config-check ./serverless.rego --check-namespaces user ./iac +serverless.yaml (yaml) + +Tests: 4 (SUCCESSES: 3, FAILURES: 1, EXCEPTIONS: 0) +Failures: 1 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 0, CRITICAL: 0) + +LOW: Service name "serverless-rest-api-with-pynamodb" is not allowed +═════════════════════════════════════════════════════════════════════════════════════════════════════════ +Ensure that Serverless Framework service names start with "aws-" +``` + +You can also pass schemas using the `config-file-schemas` flag. Trivy will use these schemas for file filtering and type checking in Rego checks. If the file does not match any of the passed schemas, it will be ignored. + +!!! example +```bash +$ trivy config --misconfig-scanners=json,yaml --config-check ./serverless.rego --check-namespaces user --config-file-schemas ./serverless-schema.json ./iac +``` + +If the schema is specified in the check metadata and is in the directory specified in the `--config-check` argument, it will be automatically loaded as specified [here](./custom/schema.md#custom-checks-with-custom-schemas), and will only be used for type checking in Rego. + ### Passing custom data You can pass directories including your custom data through `--data` option. This can be repeated for specifying multiple directories. @@ -363,12 +418,12 @@ This can be repeated for specifying multiple packages. trivy config --config-check ./my-check --namespaces main --namespaces user ./configs ``` -### Private terraform registries -Trivy can download terraform code from private registries. +### Private Terraform registries +Trivy can download Terraform code from private registries. To pass credentials you must use the `TF_TOKEN_` environment variables. You cannot use a `.terraformrc` or `terraform.rc` file, these are not supported by trivy yet. -From the terraform [docs](https://developer.hashicorp.com/terraform/cli/config/config-file#environment-variable-credentials): +From the Terraform [docs](https://developer.hashicorp.com/terraform/cli/config/config-file#environment-variable-credentials): > Environment variable names should have the prefix TF_TOKEN_ added to the domain name, with periods encoded as underscores. > For example, the value of a variable named `TF_TOKEN_app_terraform_io` will be used as a bearer authorization token when the CLI makes service requests to the hostname `app.terraform.io`. diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index 3cd1b9af74b5..3edc54dc723c 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -501,43 +501,13 @@ func (r *runner) initScannerConfig(opts flag.Options) (ScannerConfig, types.Scan log.WithPrefix(log.PrefixVulnerability).Info("Vulnerability scanning is enabled") } - // ScannerOption is filled only when config scanning is enabled. + // Misconfig ScannerOption is filled only when config scanning is enabled. var configScannerOptions misconf.ScannerOption if opts.Scanners.Enabled(types.MisconfigScanner) || opts.ImageConfigScanners.Enabled(types.MisconfigScanner) { - logger := log.WithPrefix(log.PrefixMisconfiguration) - logger.Info("Misconfiguration scanning is enabled") - - var downloadedPolicyPaths []string - var disableEmbedded bool - - downloadedPolicyPaths, err := operation.InitBuiltinPolicies(context.Background(), opts.CacheDir, opts.Quiet, opts.SkipCheckUpdate, opts.MisconfOptions.ChecksBundleRepository, opts.RegistryOpts()) + var err error + configScannerOptions, err = initMisconfScannerOption(opts) if err != nil { - if !opts.SkipCheckUpdate { - logger.Error("Falling back to embedded checks", log.Err(err)) - } - } else { - logger.Debug("Policies successfully loaded from disk") - disableEmbedded = true - } - configScannerOptions = misconf.ScannerOption{ - Debug: opts.Debug, - Trace: opts.Trace, - Namespaces: append(opts.CheckNamespaces, rego.BuiltinNamespaces()...), - PolicyPaths: append(opts.CheckPaths, downloadedPolicyPaths...), - DataPaths: opts.DataPaths, - HelmValues: opts.HelmValues, - HelmValueFiles: opts.HelmValueFiles, - HelmFileValues: opts.HelmFileValues, - HelmStringValues: opts.HelmStringValues, - HelmAPIVersions: opts.HelmAPIVersions, - HelmKubeVersion: opts.HelmKubeVersion, - TerraformTFVars: opts.TerraformTFVars, - CloudFormationParamVars: opts.CloudFormationParamVars, - K8sVersion: opts.K8sVersion, - DisableEmbeddedPolicies: disableEmbedded, - DisableEmbeddedLibraries: disableEmbedded, - IncludeDeprecatedChecks: opts.IncludeDeprecatedChecks, - TfExcludeDownloaded: opts.TfExcludeDownloaded, + return ScannerConfig{}, types.ScanOptions{}, err } } @@ -650,3 +620,49 @@ func (r *runner) scan(ctx context.Context, opts flag.Options, initializeScanner } return report, nil } + +func initMisconfScannerOption(opts flag.Options) (misconf.ScannerOption, error) { + logger := log.WithPrefix(log.PrefixMisconfiguration) + logger.Info("Misconfiguration scanning is enabled") + + var downloadedPolicyPaths []string + var disableEmbedded bool + + downloadedPolicyPaths, err := operation.InitBuiltinPolicies(context.Background(), opts.CacheDir, opts.Quiet, opts.SkipCheckUpdate, opts.MisconfOptions.ChecksBundleRepository, opts.RegistryOpts()) + if err != nil { + if !opts.SkipCheckUpdate { + logger.Error("Falling back to embedded checks", log.Err(err)) + } + } else { + logger.Debug("Checks successfully loaded from disk") + disableEmbedded = true + } + + configSchemas, err := misconf.LoadConfigSchemas(opts.ConfigFileSchemas) + if err != nil { + return misconf.ScannerOption{}, xerrors.Errorf("load schemas error: %w", err) + } + + return misconf.ScannerOption{ + Debug: opts.Debug, + Trace: opts.Trace, + Namespaces: append(opts.CheckNamespaces, rego.BuiltinNamespaces()...), + PolicyPaths: append(opts.CheckPaths, downloadedPolicyPaths...), + DataPaths: opts.DataPaths, + HelmValues: opts.HelmValues, + HelmValueFiles: opts.HelmValueFiles, + HelmFileValues: opts.HelmFileValues, + HelmStringValues: opts.HelmStringValues, + HelmAPIVersions: opts.HelmAPIVersions, + HelmKubeVersion: opts.HelmKubeVersion, + TerraformTFVars: opts.TerraformTFVars, + CloudFormationParamVars: opts.CloudFormationParamVars, + K8sVersion: opts.K8sVersion, + DisableEmbeddedPolicies: disableEmbedded, + DisableEmbeddedLibraries: disableEmbedded, + IncludeDeprecatedChecks: opts.IncludeDeprecatedChecks, + TfExcludeDownloaded: opts.TfExcludeDownloaded, + FilePatterns: opts.FilePatterns, + ConfigFileSchemas: configSchemas, + }, nil +} diff --git a/pkg/fanal/analyzer/analyzer.go b/pkg/fanal/analyzer/analyzer.go index b5bb8e629acf..abedb4b90638 100644 --- a/pkg/fanal/analyzer/analyzer.go +++ b/pkg/fanal/analyzer/analyzer.go @@ -214,7 +214,11 @@ func (r *AnalysisResult) Sort() { // Misconfigurations sort.Slice(r.Misconfigurations, func(i, j int) bool { - return r.Misconfigurations[i].FilePath < r.Misconfigurations[j].FilePath + if r.Misconfigurations[i].FileType != r.Misconfigurations[j].FileType { + return r.Misconfigurations[i].FileType < r.Misconfigurations[j].FileType + } else { + return r.Misconfigurations[i].FilePath < r.Misconfigurations[j].FilePath + } }) // Secrets diff --git a/pkg/fanal/analyzer/config/all/import.go b/pkg/fanal/analyzer/config/all/import.go index b171ab5e8a7f..74ba00ba49a8 100644 --- a/pkg/fanal/analyzer/config/all/import.go +++ b/pkg/fanal/analyzer/config/all/import.go @@ -5,8 +5,10 @@ import ( _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/cloudformation" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/dockerfile" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/helm" + _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/json" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/k8s" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/terraform" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/terraformplan/json" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/terraformplan/snapshot" + _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config/yaml" ) diff --git a/pkg/fanal/analyzer/config/azurearm/azurearm.go b/pkg/fanal/analyzer/config/azurearm/azurearm.go index 3c0c4b9828f1..ecd7826173a0 100644 --- a/pkg/fanal/analyzer/config/azurearm/azurearm.go +++ b/pkg/fanal/analyzer/config/azurearm/azurearm.go @@ -6,7 +6,7 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config" - "github.com/aquasecurity/trivy/pkg/misconf" + "github.com/aquasecurity/trivy/pkg/iac/detection" ) const ( @@ -25,7 +25,7 @@ type azureARMConfigAnalyzer struct { } func newAzureARMConfigAnalyzer(opts analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { - a, err := config.NewAnalyzer(analyzerType, version, misconf.NewAzureARMScanner, opts) + a, err := config.NewAnalyzer(analyzerType, version, detection.FileTypeAzureARM, opts) if err != nil { return nil, err } diff --git a/pkg/fanal/analyzer/config/cloudformation/cloudformation.go b/pkg/fanal/analyzer/config/cloudformation/cloudformation.go index 06f7e458a859..02f281cbbb8a 100644 --- a/pkg/fanal/analyzer/config/cloudformation/cloudformation.go +++ b/pkg/fanal/analyzer/config/cloudformation/cloudformation.go @@ -3,7 +3,7 @@ package cloudformation import ( "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config" - "github.com/aquasecurity/trivy/pkg/misconf" + "github.com/aquasecurity/trivy/pkg/iac/detection" ) const ( @@ -22,7 +22,7 @@ type cloudFormationConfigAnalyzer struct { } func newCloudFormationConfigAnalyzer(opts analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { - a, err := config.NewAnalyzer(analyzerType, version, misconf.NewCloudFormationScanner, opts) + a, err := config.NewAnalyzer(analyzerType, version, detection.FileTypeCloudFormation, opts) if err != nil { return nil, err } diff --git a/pkg/fanal/analyzer/config/config.go b/pkg/fanal/analyzer/config/config.go index b5f3569d0ab4..020ae1ae3562 100644 --- a/pkg/fanal/analyzer/config/config.go +++ b/pkg/fanal/analyzer/config/config.go @@ -9,6 +9,7 @@ import ( "k8s.io/utils/strings/slices" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" + "github.com/aquasecurity/trivy/pkg/iac/detection" "github.com/aquasecurity/trivy/pkg/misconf" ) @@ -26,10 +27,8 @@ type Analyzer struct { scanner *misconf.Scanner } -type NewScanner func([]string, misconf.ScannerOption) (*misconf.Scanner, error) - -func NewAnalyzer(t analyzer.Type, version int, newScanner NewScanner, opts analyzer.AnalyzerOptions) (*Analyzer, error) { - s, err := newScanner(opts.FilePatterns, opts.MisconfScannerOption) +func NewAnalyzer(t analyzer.Type, version int, fileType detection.FileType, opts analyzer.AnalyzerOptions) (*Analyzer, error) { + s, err := misconf.NewScanner(fileType, opts.MisconfScannerOption) if err != nil { return nil, xerrors.Errorf("%s scanner init error: %w", t, err) } diff --git a/pkg/fanal/analyzer/config/config_test.go b/pkg/fanal/analyzer/config/config_test.go index 147b1f4d3201..34503bde2995 100644 --- a/pkg/fanal/analyzer/config/config_test.go +++ b/pkg/fanal/analyzer/config/config_test.go @@ -12,14 +12,15 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config" "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/iac/detection" "github.com/aquasecurity/trivy/pkg/misconf" ) func TestAnalyzer_PostAnalyze(t *testing.T) { type fields struct { - typ analyzer.Type - newScanner config.NewScanner - opts analyzer.AnalyzerOptions + typ analyzer.Type + fileType detection.FileType + opts analyzer.AnalyzerOptions } tests := []struct { name string @@ -31,8 +32,8 @@ func TestAnalyzer_PostAnalyze(t *testing.T) { { name: "dockerfile", fields: fields{ - typ: analyzer.TypeDockerfile, - newScanner: misconf.NewDockerfileScanner, + typ: analyzer.TypeDockerfile, + fileType: detection.FileTypeDockerfile, opts: analyzer.AnalyzerOptions{ MisconfScannerOption: misconf.ScannerOption{ Namespaces: []string{"user"}, @@ -74,8 +75,8 @@ func TestAnalyzer_PostAnalyze(t *testing.T) { { name: "non-existent dir", fields: fields{ - typ: analyzer.TypeDockerfile, - newScanner: misconf.NewDockerfileScanner, + typ: analyzer.TypeDockerfile, + fileType: detection.FileTypeDockerfile, opts: analyzer.AnalyzerOptions{ MisconfScannerOption: misconf.ScannerOption{ Namespaces: []string{"user"}, @@ -90,7 +91,7 @@ func TestAnalyzer_PostAnalyze(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - a, err := config.NewAnalyzer(tt.fields.typ, 0, tt.fields.newScanner, tt.fields.opts) + a, err := config.NewAnalyzer(tt.fields.typ, 0, tt.fields.fileType, tt.fields.opts) require.NoError(t, err) got, err := a.PostAnalyze(context.Background(), analyzer.PostAnalysisInput{ diff --git a/pkg/fanal/analyzer/config/dockerfile/docker.go b/pkg/fanal/analyzer/config/dockerfile/docker.go index 353cef4eb62a..0c4463dd528e 100644 --- a/pkg/fanal/analyzer/config/dockerfile/docker.go +++ b/pkg/fanal/analyzer/config/dockerfile/docker.go @@ -7,7 +7,7 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config" - "github.com/aquasecurity/trivy/pkg/misconf" + "github.com/aquasecurity/trivy/pkg/iac/detection" ) const ( @@ -28,7 +28,7 @@ type dockerConfigAnalyzer struct { } func newDockerfileConfigAnalyzer(opts analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { - a, err := config.NewAnalyzer(analyzerType, version, misconf.NewDockerfileScanner, opts) + a, err := config.NewAnalyzer(analyzerType, version, detection.FileTypeDockerfile, opts) if err != nil { return nil, err } diff --git a/pkg/fanal/analyzer/config/helm/helm.go b/pkg/fanal/analyzer/config/helm/helm.go index 14ea6aff63de..42542ce6c835 100644 --- a/pkg/fanal/analyzer/config/helm/helm.go +++ b/pkg/fanal/analyzer/config/helm/helm.go @@ -7,7 +7,7 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config" - "github.com/aquasecurity/trivy/pkg/misconf" + "github.com/aquasecurity/trivy/pkg/iac/detection" ) const ( @@ -29,7 +29,7 @@ type helmConfigAnalyzer struct { } func newHelmConfigAnalyzer(opts analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { - a, err := config.NewAnalyzer(analyzerType, version, misconf.NewHelmScanner, opts) + a, err := config.NewAnalyzer(analyzerType, version, detection.FileTypeHelm, opts) if err != nil { return nil, err } diff --git a/pkg/fanal/analyzer/config/json/json.go b/pkg/fanal/analyzer/config/json/json.go new file mode 100644 index 000000000000..c2a6eaa73d63 --- /dev/null +++ b/pkg/fanal/analyzer/config/json/json.go @@ -0,0 +1,36 @@ +package json + +import ( + "os" + "path/filepath" + + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" + "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config" + "github.com/aquasecurity/trivy/pkg/iac/detection" +) + +const ( + analyzerType = analyzer.TypeJSON + version = 1 +) + +func init() { + analyzer.RegisterPostAnalyzer(analyzerType, newJSONConfigAnalyzer) +} + +// jsonConfigAnalyzer analyzes JSON files +type jsonConfigAnalyzer struct { + *config.Analyzer +} + +func newJSONConfigAnalyzer(opts analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { + a, err := config.NewAnalyzer(analyzerType, version, detection.FileTypeJSON, opts) + if err != nil { + return nil, err + } + return &jsonConfigAnalyzer{Analyzer: a}, nil +} + +func (*jsonConfigAnalyzer) Required(filePath string, _ os.FileInfo) bool { + return filepath.Ext(filePath) == ".json" +} diff --git a/pkg/fanal/analyzer/config/k8s/k8s.go b/pkg/fanal/analyzer/config/k8s/k8s.go index 6f3a58af16b5..dabdf41a990b 100644 --- a/pkg/fanal/analyzer/config/k8s/k8s.go +++ b/pkg/fanal/analyzer/config/k8s/k8s.go @@ -3,7 +3,7 @@ package k8s import ( "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config" - "github.com/aquasecurity/trivy/pkg/misconf" + "github.com/aquasecurity/trivy/pkg/iac/detection" ) const ( @@ -22,7 +22,7 @@ type kubernetesConfigAnalyzer struct { } func newKubernetesConfigAnalyzer(opts analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { - a, err := config.NewAnalyzer(analyzerType, version, misconf.NewKubernetesScanner, opts) + a, err := config.NewAnalyzer(analyzerType, version, detection.FileTypeKubernetes, opts) if err != nil { return nil, err } diff --git a/pkg/fanal/analyzer/config/terraform/terraform.go b/pkg/fanal/analyzer/config/terraform/terraform.go index 363d35de87fe..14b683742413 100644 --- a/pkg/fanal/analyzer/config/terraform/terraform.go +++ b/pkg/fanal/analyzer/config/terraform/terraform.go @@ -6,7 +6,6 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config" "github.com/aquasecurity/trivy/pkg/iac/detection" - "github.com/aquasecurity/trivy/pkg/misconf" ) const ( @@ -25,7 +24,7 @@ type terraformConfigAnalyzer struct { } func newTerraformConfigAnalyzer(opts analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { - a, err := config.NewAnalyzer(analyzerType, version, misconf.NewTerraformScanner, opts) + a, err := config.NewAnalyzer(analyzerType, version, detection.FileTypeTerraform, opts) if err != nil { return nil, err } diff --git a/pkg/fanal/analyzer/config/terraformplan/json/json.go b/pkg/fanal/analyzer/config/terraformplan/json/json.go index 5272f0f990f9..f0cb2c518549 100644 --- a/pkg/fanal/analyzer/config/terraformplan/json/json.go +++ b/pkg/fanal/analyzer/config/terraformplan/json/json.go @@ -8,7 +8,7 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config" - "github.com/aquasecurity/trivy/pkg/misconf" + "github.com/aquasecurity/trivy/pkg/iac/detection" ) const ( @@ -31,7 +31,7 @@ type terraformPlanConfigAnalyzer struct { } func newTerraformPlanJSONConfigAnalyzer(opts analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { - a, err := config.NewAnalyzer(analyzerType, version, misconf.NewTerraformPlanJSONScanner, opts) + a, err := config.NewAnalyzer(analyzerType, version, detection.FileTypeTerraformPlanJSON, opts) if err != nil { return nil, err } diff --git a/pkg/fanal/analyzer/config/terraformplan/snapshot/snapshot.go b/pkg/fanal/analyzer/config/terraformplan/snapshot/snapshot.go index 0597c137d96c..13316914874d 100644 --- a/pkg/fanal/analyzer/config/terraformplan/snapshot/snapshot.go +++ b/pkg/fanal/analyzer/config/terraformplan/snapshot/snapshot.go @@ -6,7 +6,7 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config" - "github.com/aquasecurity/trivy/pkg/misconf" + "github.com/aquasecurity/trivy/pkg/iac/detection" ) const ( @@ -25,7 +25,7 @@ type terraformPlanConfigAnalyzer struct { } func newTerraformPlanSnapshotConfigAnalyzer(opts analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { - a, err := config.NewAnalyzer(analyzerType, version, misconf.NewTerraformPlanSnapshotScanner, opts) + a, err := config.NewAnalyzer(analyzerType, version, detection.FileTypeTerraformPlanSnapshot, opts) if err != nil { return nil, err } diff --git a/pkg/fanal/analyzer/config/yaml/yaml.go b/pkg/fanal/analyzer/config/yaml/yaml.go new file mode 100644 index 000000000000..f8b5569f5bed --- /dev/null +++ b/pkg/fanal/analyzer/config/yaml/yaml.go @@ -0,0 +1,36 @@ +package yaml + +import ( + "os" + "path/filepath" + + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" + "github.com/aquasecurity/trivy/pkg/fanal/analyzer/config" + "github.com/aquasecurity/trivy/pkg/iac/detection" +) + +const ( + analyzerType = analyzer.TypeYAML + version = 1 +) + +func init() { + analyzer.RegisterPostAnalyzer(analyzerType, newYAMLConfigAnalyzer) +} + +// yamlConfigAnalyzer analyzes YAML files +type yamlConfigAnalyzer struct { + *config.Analyzer +} + +func newYAMLConfigAnalyzer(opts analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { + a, err := config.NewAnalyzer(analyzerType, version, detection.FileTypeYAML, opts) + if err != nil { + return nil, err + } + return &yamlConfigAnalyzer{Analyzer: a}, nil +} + +func (*yamlConfigAnalyzer) Required(filePath string, _ os.FileInfo) bool { + return filepath.Ext(filePath) == ".yaml" || filepath.Ext(filePath) == ".yml" +} diff --git a/pkg/fanal/analyzer/const.go b/pkg/fanal/analyzer/const.go index 681f8b9987cc..ea2108e89281 100644 --- a/pkg/fanal/analyzer/const.go +++ b/pkg/fanal/analyzer/const.go @@ -124,6 +124,8 @@ const ( TypeTerraform Type = Type(detection.FileTypeTerraform) TypeTerraformPlanJSON Type = Type(detection.FileTypeTerraformPlanJSON) TypeTerraformPlanSnapshot Type = Type(detection.FileTypeTerraformPlanSnapshot) + TypeYAML Type = Type(detection.FileTypeYAML) + TypeJSON Type = Type(detection.FileTypeJSON) // ======== // License @@ -245,5 +247,7 @@ var ( TypeTerraform, TypeTerraformPlanJSON, TypeTerraformPlanSnapshot, + TypeYAML, + TypeJSON, } ) diff --git a/pkg/fanal/analyzer/imgconf/dockerfile/dockerfile.go b/pkg/fanal/analyzer/imgconf/dockerfile/dockerfile.go index e0c70cc34cd0..5a974a8dd1d1 100644 --- a/pkg/fanal/analyzer/imgconf/dockerfile/dockerfile.go +++ b/pkg/fanal/analyzer/imgconf/dockerfile/dockerfile.go @@ -11,6 +11,7 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/image" "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/iac/detection" "github.com/aquasecurity/trivy/pkg/mapfs" "github.com/aquasecurity/trivy/pkg/misconf" ) @@ -26,7 +27,7 @@ type historyAnalyzer struct { } func newHistoryAnalyzer(opts analyzer.ConfigAnalyzerOptions) (analyzer.ConfigAnalyzer, error) { - s, err := misconf.NewDockerfileScanner(opts.FilePatterns, opts.MisconfScannerOption) + s, err := misconf.NewScanner(detection.FileTypeDockerfile, opts.MisconfScannerOption) if err != nil { return nil, xerrors.Errorf("misconfiguration scanner error: %w", err) } diff --git a/pkg/fanal/artifact/image/image_test.go b/pkg/fanal/artifact/image/image_test.go index cd7fea2df1e2..a69ab03708e2 100644 --- a/pkg/fanal/artifact/image/image_test.go +++ b/pkg/fanal/artifact/image/image_test.go @@ -352,17 +352,17 @@ func TestArtifact_Inspect(t *testing.T) { missingBlobsExpectation: cache.ArtifactCacheMissingBlobsExpectation{ Args: cache.ArtifactCacheMissingBlobsArgs{ ArtifactID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313", - BlobIDs: []string{"sha256:d4e6142cda465c55c8adf5b6c3148f3417a2c5582a76f933836738206e01b638"}, + BlobIDs: []string{"sha256:24a7af33784fabfedf01999d9e0dc456e8e1c1943f7d4421f7c05164026788a4"}, }, Returns: cache.ArtifactCacheMissingBlobsReturns{ MissingArtifact: true, - MissingBlobIDs: []string{"sha256:d4e6142cda465c55c8adf5b6c3148f3417a2c5582a76f933836738206e01b638"}, + MissingBlobIDs: []string{"sha256:24a7af33784fabfedf01999d9e0dc456e8e1c1943f7d4421f7c05164026788a4"}, }, }, putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{ { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:d4e6142cda465c55c8adf5b6c3148f3417a2c5582a76f933836738206e01b638", + BlobID: "sha256:24a7af33784fabfedf01999d9e0dc456e8e1c1943f7d4421f7c05164026788a4", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Digest: "", @@ -429,7 +429,7 @@ func TestArtifact_Inspect(t *testing.T) { Name: "../../test/testdata/alpine-311.tar.gz", Type: artifact.TypeContainerImage, ID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313", - BlobIDs: []string{"sha256:d4e6142cda465c55c8adf5b6c3148f3417a2c5582a76f933836738206e01b638"}, + BlobIDs: []string{"sha256:24a7af33784fabfedf01999d9e0dc456e8e1c1943f7d4421f7c05164026788a4"}, ImageMetadata: artifact.ImageMetadata{ ID: "sha256:a187dde48cd289ac374ad8539930628314bc581a481cdb41409c9289419ddb72", DiffIDs: []string{ @@ -488,25 +488,25 @@ func TestArtifact_Inspect(t *testing.T) { Args: cache.ArtifactCacheMissingBlobsArgs{ ArtifactID: "sha256:33f9415ed2cd5a9cef5d5144333619745b9ec0f851f0684dd45fa79c6b26a650", BlobIDs: []string{ - "sha256:a3eb0f92862bc742ea1e7ee875dd5623568ee17213ae7d29f05960eb1135fa6d", - "sha256:05b96a707dab6e1fcd9543f0df6a0e4cdf5c7e26272d7f6bc7ed2e1cf23afa9f", - "sha256:677cd3a664e4923227de2c2571c40b9956d99e4775b2e11ce8aa207842123119", - "sha256:e870ba0421bc71c046819f809c8369e98f59a2cde34961fdd429a2102da33c0c", + "sha256:4a26915356c961f038d5a7b7f73f24cd1eec53dcf6fdeecd39b310ddc066faec", + "sha256:e23e1d428a2a4ca9607cde5c556f744c7e9f3a1d3bfe835707c0fea107caf453", + "sha256:b8ae022ed4f8b8bf827c04a825c2e6998217581d44c0b28b59a4e66ca65bbaa5", + "sha256:8c51dcc708602d983f3f0507f0d26de609819c4391db92497639417e54378d11", }, }, Returns: cache.ArtifactCacheMissingBlobsReturns{ MissingBlobIDs: []string{ - "sha256:a3eb0f92862bc742ea1e7ee875dd5623568ee17213ae7d29f05960eb1135fa6d", - "sha256:05b96a707dab6e1fcd9543f0df6a0e4cdf5c7e26272d7f6bc7ed2e1cf23afa9f", - "sha256:677cd3a664e4923227de2c2571c40b9956d99e4775b2e11ce8aa207842123119", - "sha256:e870ba0421bc71c046819f809c8369e98f59a2cde34961fdd429a2102da33c0c", + "sha256:4a26915356c961f038d5a7b7f73f24cd1eec53dcf6fdeecd39b310ddc066faec", + "sha256:e23e1d428a2a4ca9607cde5c556f744c7e9f3a1d3bfe835707c0fea107caf453", + "sha256:b8ae022ed4f8b8bf827c04a825c2e6998217581d44c0b28b59a4e66ca65bbaa5", + "sha256:8c51dcc708602d983f3f0507f0d26de609819c4391db92497639417e54378d11", }, }, }, putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{ { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:a3eb0f92862bc742ea1e7ee875dd5623568ee17213ae7d29f05960eb1135fa6d", + BlobID: "sha256:4a26915356c961f038d5a7b7f73f24cd1eec53dcf6fdeecd39b310ddc066faec", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Digest: "", @@ -594,7 +594,7 @@ func TestArtifact_Inspect(t *testing.T) { }, { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:05b96a707dab6e1fcd9543f0df6a0e4cdf5c7e26272d7f6bc7ed2e1cf23afa9f", + BlobID: "sha256:e23e1d428a2a4ca9607cde5c556f744c7e9f3a1d3bfe835707c0fea107caf453", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Digest: "", @@ -690,7 +690,7 @@ func TestArtifact_Inspect(t *testing.T) { }, { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:677cd3a664e4923227de2c2571c40b9956d99e4775b2e11ce8aa207842123119", + BlobID: "sha256:b8ae022ed4f8b8bf827c04a825c2e6998217581d44c0b28b59a4e66ca65bbaa5", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Digest: "", @@ -898,7 +898,7 @@ func TestArtifact_Inspect(t *testing.T) { }, { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:e870ba0421bc71c046819f809c8369e98f59a2cde34961fdd429a2102da33c0c", + BlobID: "sha256:8c51dcc708602d983f3f0507f0d26de609819c4391db92497639417e54378d11", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Digest: "", @@ -1761,10 +1761,10 @@ func TestArtifact_Inspect(t *testing.T) { Type: artifact.TypeContainerImage, ID: "sha256:33f9415ed2cd5a9cef5d5144333619745b9ec0f851f0684dd45fa79c6b26a650", BlobIDs: []string{ - "sha256:a3eb0f92862bc742ea1e7ee875dd5623568ee17213ae7d29f05960eb1135fa6d", - "sha256:05b96a707dab6e1fcd9543f0df6a0e4cdf5c7e26272d7f6bc7ed2e1cf23afa9f", - "sha256:677cd3a664e4923227de2c2571c40b9956d99e4775b2e11ce8aa207842123119", - "sha256:e870ba0421bc71c046819f809c8369e98f59a2cde34961fdd429a2102da33c0c", + "sha256:4a26915356c961f038d5a7b7f73f24cd1eec53dcf6fdeecd39b310ddc066faec", + "sha256:e23e1d428a2a4ca9607cde5c556f744c7e9f3a1d3bfe835707c0fea107caf453", + "sha256:b8ae022ed4f8b8bf827c04a825c2e6998217581d44c0b28b59a4e66ca65bbaa5", + "sha256:8c51dcc708602d983f3f0507f0d26de609819c4391db92497639417e54378d11", }, ImageMetadata: artifact.ImageMetadata{ ID: "sha256:58701fd185bda36cab0557bb6438661831267aa4a9e0b54211c4d5317a48aff4", @@ -1858,25 +1858,25 @@ func TestArtifact_Inspect(t *testing.T) { Args: cache.ArtifactCacheMissingBlobsArgs{ ArtifactID: "sha256:33f9415ed2cd5a9cef5d5144333619745b9ec0f851f0684dd45fa79c6b26a650", BlobIDs: []string{ - "sha256:f46989447d5a1357f6b2427b86ca2af827dd380dbd7fbf392d2abf9a5d457323", - "sha256:487a6fb0914825c8fb9f3a0662a608039bd5a8b6488d76b9de2eb1a684e908e1", - "sha256:a23b05a9c95939a0d30d6b4f6c25393473252bde47b2daa03258c27461367509", - "sha256:47226d3c41a3ffd99dacdbcd2b197a7394ee8948270710ee035181427f88dfab", + "sha256:139bc12e936e0c46090b9380c4a29456d3ad8d8abd50c7bdc6160018cd887462", + "sha256:c491838e70ff0fcfdd0605af1ba84e86d6958c0846b16c52a84e06bb344e8e8d", + "sha256:25e775ef81049a93eafd865447b0b79da9e9956ab74bc02b5916eaea21c87c7c", + "sha256:a8a4798a22b65739cda9ca99ddb2cd86125c1dd86df6fc3971f937a0ff5b9ec3", }, }, Returns: cache.ArtifactCacheMissingBlobsReturns{ MissingBlobIDs: []string{ - "sha256:f46989447d5a1357f6b2427b86ca2af827dd380dbd7fbf392d2abf9a5d457323", - "sha256:487a6fb0914825c8fb9f3a0662a608039bd5a8b6488d76b9de2eb1a684e908e1", - "sha256:a23b05a9c95939a0d30d6b4f6c25393473252bde47b2daa03258c27461367509", - "sha256:47226d3c41a3ffd99dacdbcd2b197a7394ee8948270710ee035181427f88dfab", + "sha256:139bc12e936e0c46090b9380c4a29456d3ad8d8abd50c7bdc6160018cd887462", + "sha256:c491838e70ff0fcfdd0605af1ba84e86d6958c0846b16c52a84e06bb344e8e8d", + "sha256:25e775ef81049a93eafd865447b0b79da9e9956ab74bc02b5916eaea21c87c7c", + "sha256:a8a4798a22b65739cda9ca99ddb2cd86125c1dd86df6fc3971f937a0ff5b9ec3", }, }, }, putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{ { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:f46989447d5a1357f6b2427b86ca2af827dd380dbd7fbf392d2abf9a5d457323", + BlobID: "sha256:139bc12e936e0c46090b9380c4a29456d3ad8d8abd50c7bdc6160018cd887462", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Digest: "", @@ -1887,7 +1887,7 @@ func TestArtifact_Inspect(t *testing.T) { }, { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:487a6fb0914825c8fb9f3a0662a608039bd5a8b6488d76b9de2eb1a684e908e1", + BlobID: "sha256:c491838e70ff0fcfdd0605af1ba84e86d6958c0846b16c52a84e06bb344e8e8d", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Digest: "", @@ -1898,7 +1898,7 @@ func TestArtifact_Inspect(t *testing.T) { }, { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:a23b05a9c95939a0d30d6b4f6c25393473252bde47b2daa03258c27461367509", + BlobID: "sha256:25e775ef81049a93eafd865447b0b79da9e9956ab74bc02b5916eaea21c87c7c", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Digest: "", @@ -1910,7 +1910,7 @@ func TestArtifact_Inspect(t *testing.T) { }, { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:47226d3c41a3ffd99dacdbcd2b197a7394ee8948270710ee035181427f88dfab", + BlobID: "sha256:a8a4798a22b65739cda9ca99ddb2cd86125c1dd86df6fc3971f937a0ff5b9ec3", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Digest: "", @@ -1926,10 +1926,10 @@ func TestArtifact_Inspect(t *testing.T) { Type: artifact.TypeContainerImage, ID: "sha256:33f9415ed2cd5a9cef5d5144333619745b9ec0f851f0684dd45fa79c6b26a650", BlobIDs: []string{ - "sha256:f46989447d5a1357f6b2427b86ca2af827dd380dbd7fbf392d2abf9a5d457323", - "sha256:487a6fb0914825c8fb9f3a0662a608039bd5a8b6488d76b9de2eb1a684e908e1", - "sha256:a23b05a9c95939a0d30d6b4f6c25393473252bde47b2daa03258c27461367509", - "sha256:47226d3c41a3ffd99dacdbcd2b197a7394ee8948270710ee035181427f88dfab", + "sha256:139bc12e936e0c46090b9380c4a29456d3ad8d8abd50c7bdc6160018cd887462", + "sha256:c491838e70ff0fcfdd0605af1ba84e86d6958c0846b16c52a84e06bb344e8e8d", + "sha256:25e775ef81049a93eafd865447b0b79da9e9956ab74bc02b5916eaea21c87c7c", + "sha256:a8a4798a22b65739cda9ca99ddb2cd86125c1dd86df6fc3971f937a0ff5b9ec3", }, ImageMetadata: artifact.ImageMetadata{ ID: "sha256:58701fd185bda36cab0557bb6438661831267aa4a9e0b54211c4d5317a48aff4", @@ -2012,7 +2012,7 @@ func TestArtifact_Inspect(t *testing.T) { missingBlobsExpectation: cache.ArtifactCacheMissingBlobsExpectation{ Args: cache.ArtifactCacheMissingBlobsArgs{ ArtifactID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313", - BlobIDs: []string{"sha256:d4e6142cda465c55c8adf5b6c3148f3417a2c5582a76f933836738206e01b638"}, + BlobIDs: []string{"sha256:24a7af33784fabfedf01999d9e0dc456e8e1c1943f7d4421f7c05164026788a4"}, }, Returns: cache.ArtifactCacheMissingBlobsReturns{ Err: xerrors.New("MissingBlobs failed"), @@ -2026,16 +2026,16 @@ func TestArtifact_Inspect(t *testing.T) { missingBlobsExpectation: cache.ArtifactCacheMissingBlobsExpectation{ Args: cache.ArtifactCacheMissingBlobsArgs{ ArtifactID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313", - BlobIDs: []string{"sha256:d4e6142cda465c55c8adf5b6c3148f3417a2c5582a76f933836738206e01b638"}, + BlobIDs: []string{"sha256:24a7af33784fabfedf01999d9e0dc456e8e1c1943f7d4421f7c05164026788a4"}, }, Returns: cache.ArtifactCacheMissingBlobsReturns{ - MissingBlobIDs: []string{"sha256:d4e6142cda465c55c8adf5b6c3148f3417a2c5582a76f933836738206e01b638"}, + MissingBlobIDs: []string{"sha256:24a7af33784fabfedf01999d9e0dc456e8e1c1943f7d4421f7c05164026788a4"}, }, }, putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{ { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:d4e6142cda465c55c8adf5b6c3148f3417a2c5582a76f933836738206e01b638", + BlobID: "sha256:24a7af33784fabfedf01999d9e0dc456e8e1c1943f7d4421f7c05164026788a4", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Digest: "", @@ -2095,18 +2095,18 @@ func TestArtifact_Inspect(t *testing.T) { Args: cache.ArtifactCacheMissingBlobsArgs{ ArtifactID: "sha256:33f9415ed2cd5a9cef5d5144333619745b9ec0f851f0684dd45fa79c6b26a650", BlobIDs: []string{ - "sha256:a3eb0f92862bc742ea1e7ee875dd5623568ee17213ae7d29f05960eb1135fa6d", - "sha256:05b96a707dab6e1fcd9543f0df6a0e4cdf5c7e26272d7f6bc7ed2e1cf23afa9f", - "sha256:677cd3a664e4923227de2c2571c40b9956d99e4775b2e11ce8aa207842123119", - "sha256:e870ba0421bc71c046819f809c8369e98f59a2cde34961fdd429a2102da33c0c", + "sha256:4a26915356c961f038d5a7b7f73f24cd1eec53dcf6fdeecd39b310ddc066faec", + "sha256:e23e1d428a2a4ca9607cde5c556f744c7e9f3a1d3bfe835707c0fea107caf453", + "sha256:b8ae022ed4f8b8bf827c04a825c2e6998217581d44c0b28b59a4e66ca65bbaa5", + "sha256:8c51dcc708602d983f3f0507f0d26de609819c4391db92497639417e54378d11", }, }, Returns: cache.ArtifactCacheMissingBlobsReturns{ MissingBlobIDs: []string{ - "sha256:a3eb0f92862bc742ea1e7ee875dd5623568ee17213ae7d29f05960eb1135fa6d", - "sha256:05b96a707dab6e1fcd9543f0df6a0e4cdf5c7e26272d7f6bc7ed2e1cf23afa9f", - "sha256:677cd3a664e4923227de2c2571c40b9956d99e4775b2e11ce8aa207842123119", - "sha256:e870ba0421bc71c046819f809c8369e98f59a2cde34961fdd429a2102da33c0c", + "sha256:4a26915356c961f038d5a7b7f73f24cd1eec53dcf6fdeecd39b310ddc066faec", + "sha256:e23e1d428a2a4ca9607cde5c556f744c7e9f3a1d3bfe835707c0fea107caf453", + "sha256:b8ae022ed4f8b8bf827c04a825c2e6998217581d44c0b28b59a4e66ca65bbaa5", + "sha256:8c51dcc708602d983f3f0507f0d26de609819c4391db92497639417e54378d11", }, }, }, @@ -2114,7 +2114,7 @@ func TestArtifact_Inspect(t *testing.T) { { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:a3eb0f92862bc742ea1e7ee875dd5623568ee17213ae7d29f05960eb1135fa6d", + BlobID: "sha256:4a26915356c961f038d5a7b7f73f24cd1eec53dcf6fdeecd39b310ddc066faec", BlobInfoAnything: true, }, @@ -2125,7 +2125,7 @@ func TestArtifact_Inspect(t *testing.T) { { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:05b96a707dab6e1fcd9543f0df6a0e4cdf5c7e26272d7f6bc7ed2e1cf23afa9f", + BlobID: "sha256:e23e1d428a2a4ca9607cde5c556f744c7e9f3a1d3bfe835707c0fea107caf453", BlobInfoAnything: true, }, @@ -2136,7 +2136,7 @@ func TestArtifact_Inspect(t *testing.T) { { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:677cd3a664e4923227de2c2571c40b9956d99e4775b2e11ce8aa207842123119", + BlobID: "sha256:b8ae022ed4f8b8bf827c04a825c2e6998217581d44c0b28b59a4e66ca65bbaa5", BlobInfoAnything: true, }, @@ -2147,7 +2147,7 @@ func TestArtifact_Inspect(t *testing.T) { { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:e870ba0421bc71c046819f809c8369e98f59a2cde34961fdd429a2102da33c0c", + BlobID: "sha256:8c51dcc708602d983f3f0507f0d26de609819c4391db92497639417e54378d11", BlobInfoAnything: true, }, @@ -2164,17 +2164,17 @@ func TestArtifact_Inspect(t *testing.T) { missingBlobsExpectation: cache.ArtifactCacheMissingBlobsExpectation{ Args: cache.ArtifactCacheMissingBlobsArgs{ ArtifactID: "sha256:c232b7d8ac8aa08aa767313d0b53084c4380d1c01a213a5971bdb039e6538313", - BlobIDs: []string{"sha256:d4e6142cda465c55c8adf5b6c3148f3417a2c5582a76f933836738206e01b638"}, + BlobIDs: []string{"sha256:24a7af33784fabfedf01999d9e0dc456e8e1c1943f7d4421f7c05164026788a4"}, }, Returns: cache.ArtifactCacheMissingBlobsReturns{ MissingArtifact: true, - MissingBlobIDs: []string{"sha256:d4e6142cda465c55c8adf5b6c3148f3417a2c5582a76f933836738206e01b638"}, + MissingBlobIDs: []string{"sha256:24a7af33784fabfedf01999d9e0dc456e8e1c1943f7d4421f7c05164026788a4"}, }, }, putBlobExpectations: []cache.ArtifactCachePutBlobExpectation{ { Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:d4e6142cda465c55c8adf5b6c3148f3417a2c5582a76f933836738206e01b638", + BlobID: "sha256:24a7af33784fabfedf01999d9e0dc456e8e1c1943f7d4421f7c05164026788a4", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Digest: "", diff --git a/pkg/fanal/artifact/local/fs_test.go b/pkg/fanal/artifact/local/fs_test.go index d27b5ffb4366..ba6d2879bda2 100644 --- a/pkg/fanal/artifact/local/fs_test.go +++ b/pkg/fanal/artifact/local/fs_test.go @@ -47,7 +47,7 @@ func TestArtifact_Inspect(t *testing.T) { }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:e480047f53bccb8a9107a424fab43452dc59df641022a300d34326639254a0cf", + BlobID: "sha256:5ba63074e071e3f0247d03dd7e544b6a75f7224ee238618482c490b36f4792dc", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, OS: types.OS{ @@ -82,9 +82,9 @@ func TestArtifact_Inspect(t *testing.T) { want: artifact.Reference{ Name: "host", Type: artifact.TypeFilesystem, - ID: "sha256:e480047f53bccb8a9107a424fab43452dc59df641022a300d34326639254a0cf", + ID: "sha256:5ba63074e071e3f0247d03dd7e544b6a75f7224ee238618482c490b36f4792dc", BlobIDs: []string{ - "sha256:e480047f53bccb8a9107a424fab43452dc59df641022a300d34326639254a0cf", + "sha256:5ba63074e071e3f0247d03dd7e544b6a75f7224ee238618482c490b36f4792dc", }, }, }, @@ -102,7 +102,7 @@ func TestArtifact_Inspect(t *testing.T) { }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:7db98974b2231d3e25f4890008c4d42f6f26a7da5a8aba99e954dec97f050bd6", + BlobID: "sha256:649ddb291d142363aafcf9e9cf8a6e32dc0a6ae5a95ab43d09b8201d86ed8f7a", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, }, @@ -112,9 +112,9 @@ func TestArtifact_Inspect(t *testing.T) { want: artifact.Reference{ Name: "host", Type: artifact.TypeFilesystem, - ID: "sha256:7db98974b2231d3e25f4890008c4d42f6f26a7da5a8aba99e954dec97f050bd6", + ID: "sha256:649ddb291d142363aafcf9e9cf8a6e32dc0a6ae5a95ab43d09b8201d86ed8f7a", BlobIDs: []string{ - "sha256:7db98974b2231d3e25f4890008c4d42f6f26a7da5a8aba99e954dec97f050bd6", + "sha256:649ddb291d142363aafcf9e9cf8a6e32dc0a6ae5a95ab43d09b8201d86ed8f7a", }, }, }, @@ -125,7 +125,7 @@ func TestArtifact_Inspect(t *testing.T) { }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:e480047f53bccb8a9107a424fab43452dc59df641022a300d34326639254a0cf", + BlobID: "sha256:5ba63074e071e3f0247d03dd7e544b6a75f7224ee238618482c490b36f4792dc", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, OS: types.OS{ @@ -175,7 +175,7 @@ func TestArtifact_Inspect(t *testing.T) { }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:c91a594202ba114ce4d067d9cac40b545c7ba2a96520c9ca8050b437020c3ab9", + BlobID: "sha256:00e49bf14e0a8c15b2d611d8e5c231276f1e10f22b3307177e513605fd18d807", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Applications: []types.Application{ @@ -203,9 +203,9 @@ func TestArtifact_Inspect(t *testing.T) { want: artifact.Reference{ Name: "testdata/requirements.txt", Type: artifact.TypeFilesystem, - ID: "sha256:c91a594202ba114ce4d067d9cac40b545c7ba2a96520c9ca8050b437020c3ab9", + ID: "sha256:00e49bf14e0a8c15b2d611d8e5c231276f1e10f22b3307177e513605fd18d807", BlobIDs: []string{ - "sha256:c91a594202ba114ce4d067d9cac40b545c7ba2a96520c9ca8050b437020c3ab9", + "sha256:00e49bf14e0a8c15b2d611d8e5c231276f1e10f22b3307177e513605fd18d807", }, }, }, @@ -216,7 +216,7 @@ func TestArtifact_Inspect(t *testing.T) { }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ - BlobID: "sha256:c91a594202ba114ce4d067d9cac40b545c7ba2a96520c9ca8050b437020c3ab9", + BlobID: "sha256:00e49bf14e0a8c15b2d611d8e5c231276f1e10f22b3307177e513605fd18d807", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Applications: []types.Application{ @@ -244,9 +244,9 @@ func TestArtifact_Inspect(t *testing.T) { want: artifact.Reference{ Name: "testdata/requirements.txt", Type: artifact.TypeFilesystem, - ID: "sha256:c91a594202ba114ce4d067d9cac40b545c7ba2a96520c9ca8050b437020c3ab9", + ID: "sha256:00e49bf14e0a8c15b2d611d8e5c231276f1e10f22b3307177e513605fd18d807", BlobIDs: []string{ - "sha256:c91a594202ba114ce4d067d9cac40b545c7ba2a96520c9ca8050b437020c3ab9", + "sha256:00e49bf14e0a8c15b2d611d8e5c231276f1e10f22b3307177e513605fd18d807", }, }, }, @@ -341,9 +341,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraform/single-failure", Type: artifact.TypeFilesystem, - ID: "sha256:5e4ca8ffaa89f49c69acfbac6d7cebb0a372b07d4c4c9876f9a58043c8ee56e9", + ID: "sha256:4f2a334086f1d175c0ee57cd4220f20b187b456dc36bbe39a63c42b5637b2179", BlobIDs: []string{ - "sha256:5e4ca8ffaa89f49c69acfbac6d7cebb0a372b07d4c4c9876f9a58043c8ee56e9", + "sha256:4f2a334086f1d175c0ee57cd4220f20b187b456dc36bbe39a63c42b5637b2179", }, }, }, @@ -426,9 +426,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraform/multiple-failures", Type: artifact.TypeFilesystem, - ID: "sha256:1832cedd0d8baeb172c7297acb56417c0dec454c280a79ee2a8f413e1ffca192", + ID: "sha256:ff7a84de97729e169c94107a89bc9da88f5ecf94873cdbd9bf0844e1af5f5b30", BlobIDs: []string{ - "sha256:1832cedd0d8baeb172c7297acb56417c0dec454c280a79ee2a8f413e1ffca192", + "sha256:ff7a84de97729e169c94107a89bc9da88f5ecf94873cdbd9bf0844e1af5f5b30", }, }, }, @@ -456,9 +456,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraform/no-results", Type: artifact.TypeFilesystem, - ID: "sha256:00e01cf7bf052dbf8f02739d281675eff16f5ddf004256472cdddb55cf974fd6", + ID: "sha256:06406e9bb7ba09d8d24c73c0995ac3b94fc1d6ce059e5a45418d7c0ab2b6dca4", BlobIDs: []string{ - "sha256:00e01cf7bf052dbf8f02739d281675eff16f5ddf004256472cdddb55cf974fd6", + "sha256:06406e9bb7ba09d8d24c73c0995ac3b94fc1d6ce059e5a45418d7c0ab2b6dca4", }, }, }, @@ -505,9 +505,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraform/passed", Type: artifact.TypeFilesystem, - ID: "sha256:9ee9fe14c3fcff202bc8c72f9e20a3035442ae394ec5cd201e1cb29d2111b4e1", + ID: "sha256:107251e6ee7312c8c27ff04e71dd943b92021777c575971809f57b60bf41bba4", BlobIDs: []string{ - "sha256:9ee9fe14c3fcff202bc8c72f9e20a3035442ae394ec5cd201e1cb29d2111b4e1", + "sha256:107251e6ee7312c8c27ff04e71dd943b92021777c575971809f57b60bf41bba4", }, }, }, @@ -571,9 +571,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraform/busted-relative-paths/child/main.tf", Type: artifact.TypeFilesystem, - ID: "sha256:c3e6c9e68cd7a9900cd8aa690e1d5af174ddcc00ddb9438a858c3e329b9ea8f4", + ID: "sha256:f2f07f41dbd6816d41ce6f28b3922fcedab611b8602d95e328571afd5c53b31d", BlobIDs: []string{ - "sha256:c3e6c9e68cd7a9900cd8aa690e1d5af174ddcc00ddb9438a858c3e329b9ea8f4", + "sha256:f2f07f41dbd6816d41ce6f28b3922fcedab611b8602d95e328571afd5c53b31d", }, }, }, @@ -621,9 +621,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraform/tfvar-outside/tf", Type: artifact.TypeFilesystem, - ID: "sha256:9ee9fe14c3fcff202bc8c72f9e20a3035442ae394ec5cd201e1cb29d2111b4e1", + ID: "sha256:107251e6ee7312c8c27ff04e71dd943b92021777c575971809f57b60bf41bba4", BlobIDs: []string{ - "sha256:9ee9fe14c3fcff202bc8c72f9e20a3035442ae394ec5cd201e1cb29d2111b4e1", + "sha256:107251e6ee7312c8c27ff04e71dd943b92021777c575971809f57b60bf41bba4", }, }, }, @@ -711,9 +711,9 @@ func TestTerraformMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraform/relative-paths/child", Type: artifact.TypeFilesystem, - ID: "sha256:44d28d3fc115f1f8dd3f8978c7e9432ba255dd82661c3810178276897e2d8fb7", + ID: "sha256:f04c37d8e5300ce9344c795c2d4e0bb1dbef251b15538a6e0c11d6d9a86664d1", BlobIDs: []string{ - "sha256:44d28d3fc115f1f8dd3f8978c7e9432ba255dd82661c3810178276897e2d8fb7", + "sha256:f04c37d8e5300ce9344c795c2d4e0bb1dbef251b15538a6e0c11d6d9a86664d1", }, }, }, @@ -830,9 +830,9 @@ func TestTerraformPlanSnapshotMisconfScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraformplan/snapshots/single-failure", Type: artifact.TypeFilesystem, - ID: "sha256:39babdcb854331c58dc1e20c20dc67c2b4bda23895bf2861cc72d187de2bc716", + ID: "sha256:c21e15d7d0cfe7c1ef1e1933b443f781d1411b864500431302a1e45fe0950529", BlobIDs: []string{ - "sha256:39babdcb854331c58dc1e20c20dc67c2b4bda23895bf2861cc72d187de2bc716", + "sha256:c21e15d7d0cfe7c1ef1e1933b443f781d1411b864500431302a1e45fe0950529", }, }, }, @@ -906,9 +906,9 @@ func TestTerraformPlanSnapshotMisconfScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraformplan/snapshots/multiple-failures", Type: artifact.TypeFilesystem, - ID: "sha256:32debc3c2857404ceeec978a938609a4b20f1c53c304603815955885377f286c", + ID: "sha256:800c9ce07be36c7f4d1a4876ecfaaa77c1d90b15f43c58eaf52ea27670afcc42", BlobIDs: []string{ - "sha256:32debc3c2857404ceeec978a938609a4b20f1c53c304603815955885377f286c", + "sha256:800c9ce07be36c7f4d1a4876ecfaaa77c1d90b15f43c58eaf52ea27670afcc42", }, }, }, @@ -946,9 +946,9 @@ func TestTerraformPlanSnapshotMisconfScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/terraformplan/snapshots/passed", Type: artifact.TypeFilesystem, - ID: "sha256:2432b64e4583676ec1e94903d31c4faf79a1e0f4ed49bf24aef2bf9b44517ca2", + ID: "sha256:3d90bb96d2dc0af277ab0ce28972670eb81968d00775d1e92edce54ae2d165c0", BlobIDs: []string{ - "sha256:2432b64e4583676ec1e94903d31c4faf79a1e0f4ed49bf24aef2bf9b44517ca2", + "sha256:3d90bb96d2dc0af277ab0ce28972670eb81968d00775d1e92edce54ae2d165c0", }, }, }, @@ -1045,7 +1045,7 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { }, CauseMetadata: types.CauseMetadata{ Resource: "main.yaml:3-6", - Provider: "Generic", + Provider: "Cloud", Service: "general", StartLine: 3, EndLine: 6, @@ -1061,9 +1061,9 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/cloudformation/single-failure/src", Type: artifact.TypeFilesystem, - ID: "sha256:43bb7ce5253686cf96a68e6d4bd30c33e163019ae2893968602da9e5e86b1aab", + ID: "sha256:bd481a673eb07ed7b51e1ff2a6e7aca08b433d11288eb9f5e9aa2d2f482a0c16", BlobIDs: []string{ - "sha256:43bb7ce5253686cf96a68e6d4bd30c33e163019ae2893968602da9e5e86b1aab", + "sha256:bd481a673eb07ed7b51e1ff2a6e7aca08b433d11288eb9f5e9aa2d2f482a0c16", }, }, }, @@ -1107,7 +1107,7 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { }, CauseMetadata: types.CauseMetadata{ Resource: "main.yaml:2-5", - Provider: "Generic", + Provider: "Cloud", Service: "general", StartLine: 2, EndLine: 5, @@ -1129,7 +1129,7 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { }, CauseMetadata: types.CauseMetadata{ Resource: "main.yaml:6-9", - Provider: "Generic", + Provider: "Cloud", Service: "general", StartLine: 6, EndLine: 9, @@ -1145,9 +1145,9 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/cloudformation/multiple-failures/src", Type: artifact.TypeFilesystem, - ID: "sha256:4609d64f57187099483e76a979d2f74862a092a5f42a9945e6f1242c372a811c", + ID: "sha256:c25676d23114b9c912067d45285cd9e662cefae5e3cc82c40f67df5fee39f92a", BlobIDs: []string{ - "sha256:4609d64f57187099483e76a979d2f74862a092a5f42a9945e6f1242c372a811c", + "sha256:c25676d23114b9c912067d45285cd9e662cefae5e3cc82c40f67df5fee39f92a", }, }, }, @@ -1177,9 +1177,9 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/cloudformation/no-results/src", Type: artifact.TypeFilesystem, - ID: "sha256:a3d40c3290bf45542f9c0aa364f2c16aca06cdccb4868a2e442b7e6a56c6157a", + ID: "sha256:522b19ad182f50b7b04217831c914df52c2d2eb1bdddb02eb9cd2b4e14c9a32b", BlobIDs: []string{ - "sha256:a3d40c3290bf45542f9c0aa364f2c16aca06cdccb4868a2e442b7e6a56c6157a", + "sha256:522b19ad182f50b7b04217831c914df52c2d2eb1bdddb02eb9cd2b4e14c9a32b", }, }, }, @@ -1235,9 +1235,9 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/cloudformation/params/code/src", Type: artifact.TypeFilesystem, - ID: "sha256:abaeb2f443a59940afd63e015d0bb737127ebde06306840f529dd40d65390703", + ID: "sha256:40d6550292de7518fd7229f7b14803c67cbffbad3376e773ad7e6dc003846e87", BlobIDs: []string{ - "sha256:abaeb2f443a59940afd63e015d0bb737127ebde06306840f529dd40d65390703", + "sha256:40d6550292de7518fd7229f7b14803c67cbffbad3376e773ad7e6dc003846e87", }, }, }, @@ -1279,7 +1279,7 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { References: []string{"https://trivy.dev/"}, }, CauseMetadata: types.CauseMetadata{ - Provider: "Generic", + Provider: "Cloud", Service: "general", }, }, @@ -1293,9 +1293,9 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/cloudformation/passed/src", Type: artifact.TypeFilesystem, - ID: "sha256:73bb13d7c722bfcdf6c00f51f368befda453e1acba31ba62aad31b5b04b235e8", + ID: "sha256:e2269b8ea44e29aedeaeea83368f879b3fb0cb97bfe46bcca4383a637280cace", BlobIDs: []string{ - "sha256:73bb13d7c722bfcdf6c00f51f368befda453e1acba31ba62aad31b5b04b235e8", + "sha256:e2269b8ea44e29aedeaeea83368f879b3fb0cb97bfe46bcca4383a637280cace", }, }, }, @@ -1381,9 +1381,9 @@ func TestDockerfileMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/dockerfile/single-failure/src", Type: artifact.TypeFilesystem, - ID: "sha256:059f081288e7ea418286bddcee78167e8ebf33b47e365c20754b6cfa180d997d", + ID: "sha256:3551bddb0f53fb9e0c32390e3ac33f841e3cc15a52ddbcbd9ea07f7e6d1d4437", BlobIDs: []string{ - "sha256:059f081288e7ea418286bddcee78167e8ebf33b47e365c20754b6cfa180d997d", + "sha256:3551bddb0f53fb9e0c32390e3ac33f841e3cc15a52ddbcbd9ea07f7e6d1d4437", }, }, }, @@ -1439,9 +1439,9 @@ func TestDockerfileMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/dockerfile/multiple-failures/src", Type: artifact.TypeFilesystem, - ID: "sha256:059f081288e7ea418286bddcee78167e8ebf33b47e365c20754b6cfa180d997d", + ID: "sha256:3551bddb0f53fb9e0c32390e3ac33f841e3cc15a52ddbcbd9ea07f7e6d1d4437", BlobIDs: []string{ - "sha256:059f081288e7ea418286bddcee78167e8ebf33b47e365c20754b6cfa180d997d", + "sha256:3551bddb0f53fb9e0c32390e3ac33f841e3cc15a52ddbcbd9ea07f7e6d1d4437", }, }, }, @@ -1469,9 +1469,9 @@ func TestDockerfileMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/dockerfile/no-results/src", Type: artifact.TypeFilesystem, - ID: "sha256:a3d40c3290bf45542f9c0aa364f2c16aca06cdccb4868a2e442b7e6a56c6157a", + ID: "sha256:e57ad1b0be7370a131e1265a25ac8790bbfec2bb5867315916cf92799e5855d3", BlobIDs: []string{ - "sha256:a3d40c3290bf45542f9c0aa364f2c16aca06cdccb4868a2e442b7e6a56c6157a", + "sha256:e57ad1b0be7370a131e1265a25ac8790bbfec2bb5867315916cf92799e5855d3", }, }, }, @@ -1529,9 +1529,9 @@ func TestDockerfileMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/dockerfile/passed/src", Type: artifact.TypeFilesystem, - ID: "sha256:5f6504b01b68ef1418d59210c0c7b3604fe63f8575a72721d1172d9d2fdd2e23", + ID: "sha256:ff4a3a7aed57bd8190277cf2cc16213eef43b7a37f26f8458525f2efd9793e8f", BlobIDs: []string{ - "sha256:5f6504b01b68ef1418d59210c0c7b3604fe63f8575a72721d1172d9d2fdd2e23", + "sha256:ff4a3a7aed57bd8190277cf2cc16213eef43b7a37f26f8458525f2efd9793e8f", }, }, }, @@ -1605,7 +1605,7 @@ func TestKubernetesMisconfigurationScan(t *testing.T) { }, }, CauseMetadata: types.CauseMetadata{ - Provider: "Generic", + Provider: "Kubernetes", Service: "general", StartLine: 7, EndLine: 9, @@ -1621,9 +1621,9 @@ func TestKubernetesMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/kubernetes/single-failure/src", Type: artifact.TypeFilesystem, - ID: "sha256:14768f3c82388c43e0af6579632535b5ecd6bd4ac802d063d74b636725191fe9", + ID: "sha256:63ceedb6582e29ee4184b8b776ee27efe226d07a932461639c05bfbe47bf7efa", BlobIDs: []string{ - "sha256:14768f3c82388c43e0af6579632535b5ecd6bd4ac802d063d74b636725191fe9", + "sha256:63ceedb6582e29ee4184b8b776ee27efe226d07a932461639c05bfbe47bf7efa", }, }, }, @@ -1668,7 +1668,7 @@ func TestKubernetesMisconfigurationScan(t *testing.T) { }, }, CauseMetadata: types.CauseMetadata{ - Provider: "Generic", + Provider: "Kubernetes", Service: "general", StartLine: 7, EndLine: 9, @@ -1691,7 +1691,7 @@ func TestKubernetesMisconfigurationScan(t *testing.T) { }, }, CauseMetadata: types.CauseMetadata{ - Provider: "Generic", + Provider: "Kubernetes", Service: "general", StartLine: 10, EndLine: 12, @@ -1707,9 +1707,9 @@ func TestKubernetesMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/kubernetes/multiple-failures/src", Type: artifact.TypeFilesystem, - ID: "sha256:d7b5fe7fb0e8d51cb6a06b5f2027b1e976e25a2462ff40241f86e13e69ff210c", + ID: "sha256:47fcc85b182385fc6cd7ca08270efff33281ba7717c7a97c7b28a47bef24fae3", BlobIDs: []string{ - "sha256:d7b5fe7fb0e8d51cb6a06b5f2027b1e976e25a2462ff40241f86e13e69ff210c", + "sha256:47fcc85b182385fc6cd7ca08270efff33281ba7717c7a97c7b28a47bef24fae3", }, }, }, @@ -1737,9 +1737,9 @@ func TestKubernetesMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/kubernetes/no-results/src", Type: artifact.TypeFilesystem, - ID: "sha256:ddd0e363b0ebab71250f9d36de65d485ca2faa9510ab6ddea940de7af8267b67", + ID: "sha256:4aad6cb079f406935fa383e126616cee6c82e326a92c163042d6043596f18e04", BlobIDs: []string{ - "sha256:ddd0e363b0ebab71250f9d36de65d485ca2faa9510ab6ddea940de7af8267b67", + "sha256:4aad6cb079f406935fa383e126616cee6c82e326a92c163042d6043596f18e04", }, }, }, @@ -1783,7 +1783,7 @@ func TestKubernetesMisconfigurationScan(t *testing.T) { }, }, CauseMetadata: types.CauseMetadata{ - Provider: "Generic", + Provider: "Kubernetes", Service: "general", }, }, @@ -1797,9 +1797,9 @@ func TestKubernetesMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/kubernetes/passed/src", Type: artifact.TypeFilesystem, - ID: "sha256:af77d733739a4366b6e03e95605f5282262d45905efed501d83ec7ecc97a7574", + ID: "sha256:b781859c685b32a25e96e54b331957d696cedfc98162146819ac64d3f157660e", BlobIDs: []string{ - "sha256:af77d733739a4366b6e03e95605f5282262d45905efed501d83ec7ecc97a7574", + "sha256:b781859c685b32a25e96e54b331957d696cedfc98162146819ac64d3f157660e", }, }, }, @@ -1870,7 +1870,7 @@ func TestAzureARMMisconfigurationScan(t *testing.T) { }, CauseMetadata: types.CauseMetadata{ Resource: "resources[0]", - Provider: "Generic", + Provider: "Cloud", Service: "general", StartLine: 30, EndLine: 40, @@ -1886,9 +1886,9 @@ func TestAzureARMMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/azurearm/single-failure/src", Type: artifact.TypeFilesystem, - ID: "sha256:ff25ae7d346f724faf4d2653868bc249bf221460bcf6d364cf50372c303342d2", + ID: "sha256:62a167d993f603f5552042e4b3c7ac3a65dbbe62bad28e72631c69c9a8f5e2b5", BlobIDs: []string{ - "sha256:ff25ae7d346f724faf4d2653868bc249bf221460bcf6d364cf50372c303342d2", + "sha256:62a167d993f603f5552042e4b3c7ac3a65dbbe62bad28e72631c69c9a8f5e2b5", }, }, }, @@ -1930,7 +1930,7 @@ func TestAzureARMMisconfigurationScan(t *testing.T) { }, CauseMetadata: types.CauseMetadata{ Resource: "resources[0]", - Provider: "Generic", + Provider: "Cloud", Service: "general", StartLine: 30, EndLine: 40, @@ -1952,7 +1952,7 @@ func TestAzureARMMisconfigurationScan(t *testing.T) { }, CauseMetadata: types.CauseMetadata{ Resource: "resources[1]", - Provider: "Generic", + Provider: "Cloud", Service: "general", StartLine: 41, EndLine: 51, @@ -1968,9 +1968,9 @@ func TestAzureARMMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/azurearm/multiple-failures/src", Type: artifact.TypeFilesystem, - ID: "sha256:e5c5ad752c6ff8d26f1b6764a9fb6dec345157df7c816b86d491b0af9e9f4ae6", + ID: "sha256:3cc8c966f10a75dc902589329cf202168176243ef8fdec7219452bb54d02af8e", BlobIDs: []string{ - "sha256:e5c5ad752c6ff8d26f1b6764a9fb6dec345157df7c816b86d491b0af9e9f4ae6", + "sha256:3cc8c966f10a75dc902589329cf202168176243ef8fdec7219452bb54d02af8e", }, }, }, @@ -1998,9 +1998,9 @@ func TestAzureARMMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/azurearm/no-results/src", Type: artifact.TypeFilesystem, - ID: "sha256:a3d40c3290bf45542f9c0aa364f2c16aca06cdccb4868a2e442b7e6a56c6157a", + ID: "sha256:522b19ad182f50b7b04217831c914df52c2d2eb1bdddb02eb9cd2b4e14c9a32b", BlobIDs: []string{ - "sha256:a3d40c3290bf45542f9c0aa364f2c16aca06cdccb4868a2e442b7e6a56c6157a", + "sha256:522b19ad182f50b7b04217831c914df52c2d2eb1bdddb02eb9cd2b4e14c9a32b", }, }, }, @@ -2040,7 +2040,7 @@ func TestAzureARMMisconfigurationScan(t *testing.T) { References: []string{"https://trivy.dev/"}, }, CauseMetadata: types.CauseMetadata{ - Provider: "Generic", + Provider: "Cloud", Service: "general", }, }, @@ -2054,9 +2054,9 @@ func TestAzureARMMisconfigurationScan(t *testing.T) { want: artifact.Reference{ Name: "testdata/misconfig/azurearm/passed/src", Type: artifact.TypeFilesystem, - ID: "sha256:0702eea6f699984f98c788c737f3adf74ae00db2b24b7d44577c7eedc31b1eb1", + ID: "sha256:d6a4722cb6865cac6f55c1789d64c57479539e9198722519918764a230586b4b", BlobIDs: []string{ - "sha256:0702eea6f699984f98c788c737f3adf74ae00db2b24b7d44577c7eedc31b1eb1", + "sha256:d6a4722cb6865cac6f55c1789d64c57479539e9198722519918764a230586b4b", }, }, }, @@ -2110,8 +2110,8 @@ func TestMixedConfigurationScan(t *testing.T) { SchemaVersion: 2, Misconfigurations: []types.Misconfiguration{ { - FileType: "terraform", - FilePath: "main.tf", + FileType: "cloudformation", + FilePath: "main.yaml", Failures: types.MisconfResults{ { Namespace: "user.something", @@ -2120,7 +2120,7 @@ func TestMixedConfigurationScan(t *testing.T) { PolicyMetadata: types.PolicyMetadata{ ID: "TEST001", AVDID: "AVD-TEST-0001", - Type: "Terraform Security Check", + Type: "CloudFormation Security Check", Title: "Test policy", Description: "This is a test policy.", Severity: "LOW", @@ -2128,18 +2128,18 @@ func TestMixedConfigurationScan(t *testing.T) { References: []string{"https://trivy.dev/"}, }, CauseMetadata: types.CauseMetadata{ - Resource: "aws_s3_bucket.asd", - Provider: "Generic", + Resource: "main.yaml:3-6", + Provider: "Cloud", Service: "general", - StartLine: 1, - EndLine: 3, + StartLine: 3, + EndLine: 6, }, }, }, }, { - FileType: "cloudformation", - FilePath: "main.yaml", + FileType: "terraform", + FilePath: "main.tf", Failures: types.MisconfResults{ { Namespace: "user.something", @@ -2148,7 +2148,7 @@ func TestMixedConfigurationScan(t *testing.T) { PolicyMetadata: types.PolicyMetadata{ ID: "TEST001", AVDID: "AVD-TEST-0001", - Type: "CloudFormation Security Check", + Type: "Terraform Security Check", Title: "Test policy", Description: "This is a test policy.", Severity: "LOW", @@ -2156,11 +2156,11 @@ func TestMixedConfigurationScan(t *testing.T) { References: []string{"https://trivy.dev/"}, }, CauseMetadata: types.CauseMetadata{ - Resource: "main.yaml:3-6", - Provider: "Generic", + Resource: "aws_s3_bucket.asd", + Provider: "Cloud", Service: "general", - StartLine: 3, - EndLine: 6, + StartLine: 1, + EndLine: 3, }, }, }, @@ -2195,5 +2195,332 @@ func TestMixedConfigurationScan(t *testing.T) { assert.Equal(t, tt.want.Type, got.Type) }) } +} + +func TestJSONConfigScan(t *testing.T) { + type fields struct { + dir string + schemas []string + } + + tests := []struct { + name string + fields fields + artifactOpt artifact.Option + putBlobExpectation cache.ArtifactCachePutBlobExpectation + want artifact.Reference + }{ + { + name: "happy path without custom schema", + fields: fields{ + dir: "./testdata/misconfig/json/passed/src", + }, + artifactOpt: artifact.Option{ + MisconfScannerOption: misconf.ScannerOption{ + RegoOnly: true, + Namespaces: []string{"user"}, + PolicyPaths: []string{"./testdata/misconfig/json/passed/checks"}, + DisableEmbeddedPolicies: true, + }, + }, + putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ + Args: cache.ArtifactCachePutBlobArgs{ + BlobIDAnything: true, + BlobInfo: types.BlobInfo{ + SchemaVersion: types.BlobJSONSchemaVersion, + Misconfigurations: []types.Misconfiguration{ + { + FileType: types.JSON, + FilePath: "test1.json", + Failures: types.MisconfResults{ + { + Namespace: "user.test_json_check", + Query: "data.user.test_json_check.deny", + Message: `Service "foo" should not be used`, + PolicyMetadata: types.PolicyMetadata{ + ID: "TEST001", + AVDID: "TEST001", + Type: "JSON Security Check", + Title: "Test check", + Severity: "LOW", + }, + CauseMetadata: types.CauseMetadata{ + Provider: "Generic", + Service: "general", + }, + }, + }, + }, + { + FileType: types.JSON, + FilePath: "test2.json", + Failures: types.MisconfResults{ + { + Namespace: "user.test_json_check", + Query: "data.user.test_json_check.deny", + Message: `Provider "bar" should not be used`, + PolicyMetadata: types.PolicyMetadata{ + ID: "TEST001", + AVDID: "TEST001", + Type: "JSON Security Check", + Title: "Test check", + Severity: "LOW", + }, + CauseMetadata: types.CauseMetadata{ + Provider: "Generic", + Service: "general", + }, + }, + }, + }, + }, + }, + }, + Returns: cache.ArtifactCachePutBlobReturns{}, + }, + want: artifact.Reference{ + Name: "testdata/misconfig/json/passed/src", + Type: artifact.TypeFilesystem, + }, + }, + { + name: "happy path with custom schema", + fields: fields{ + dir: "./testdata/misconfig/json/with-schema/src", + schemas: []string{"./testdata/misconfig/json/with-schema/schemas"}, + }, + artifactOpt: artifact.Option{ + MisconfScannerOption: misconf.ScannerOption{ + RegoOnly: true, + Namespaces: []string{"user"}, + PolicyPaths: []string{"./testdata/misconfig/json/with-schema/checks"}, + DisableEmbeddedPolicies: true, + }, + }, + putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ + Args: cache.ArtifactCachePutBlobArgs{ + BlobIDAnything: true, + BlobInfo: types.BlobInfo{ + SchemaVersion: types.BlobJSONSchemaVersion, + Misconfigurations: []types.Misconfiguration{ + { + FileType: types.JSON, + FilePath: "test1.json", + Failures: types.MisconfResults{ + { + Namespace: "user.test_json_check", + Query: "data.user.test_json_check.deny", + Message: `Service "foo" should not be used`, + PolicyMetadata: types.PolicyMetadata{ + ID: "TEST001", + AVDID: "TEST001", + Type: "JSON Security Check", + Title: "Test check", + Severity: "LOW", + }, + CauseMetadata: types.CauseMetadata{ + Provider: "Generic", + Service: "general", + }, + }, + }, + }, + }, + }, + }, + Returns: cache.ArtifactCachePutBlobReturns{}, + }, + want: artifact.Reference{ + Name: "testdata/misconfig/json/with-schema/src", + Type: artifact.TypeFilesystem, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := new(cache.MockArtifactCache) + c.ApplyPutBlobExpectation(tt.putBlobExpectation) + + if len(tt.fields.schemas) > 0 { + schemas, err := misconf.LoadConfigSchemas(tt.fields.schemas) + require.NoError(t, err) + tt.artifactOpt.MisconfScannerOption.ConfigFileSchemas = schemas + } + + a, err := NewArtifact(tt.fields.dir, c, walker.NewFS(), tt.artifactOpt) + require.NoError(t, err) + + got, err := a.Inspect(context.Background()) + require.NoError(t, err) + require.NotNil(t, got) + + assert.Equal(t, tt.want.Name, got.Name) + assert.Equal(t, tt.want.Type, got.Type) + }) + } +} + +func TestYAMLConfigScan(t *testing.T) { + type fields struct { + dir string + schemas []string + } + + tests := []struct { + name string + fields fields + artifactOpt artifact.Option + putBlobExpectation cache.ArtifactCachePutBlobExpectation + want artifact.Reference + }{ + { + name: "happy path without custom schema", + fields: fields{ + dir: "./testdata/misconfig/yaml/passed/src", + }, + artifactOpt: artifact.Option{ + MisconfScannerOption: misconf.ScannerOption{ + RegoOnly: true, + Namespaces: []string{"user"}, + PolicyPaths: []string{"./testdata/misconfig/yaml/passed/checks"}, + DisableEmbeddedPolicies: true, + }, + }, + putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ + Args: cache.ArtifactCachePutBlobArgs{ + BlobIDAnything: true, + BlobInfo: types.BlobInfo{ + SchemaVersion: types.BlobJSONSchemaVersion, + Misconfigurations: []types.Misconfiguration{ + { + FileType: types.YAML, + FilePath: "test1.yaml", + Failures: types.MisconfResults{ + { + Namespace: "user.test_yaml_check", + Query: "data.user.test_yaml_check.deny", + Message: `Service "foo" should not be used`, + PolicyMetadata: types.PolicyMetadata{ + ID: "TEST001", + AVDID: "TEST001", + Type: "YAML Security Check", + Title: "Test check", + Severity: "LOW", + }, + CauseMetadata: types.CauseMetadata{ + Provider: "Generic", + Service: "general", + }, + }, + }, + }, + { + FileType: types.YAML, + FilePath: "test2.yml", + Failures: types.MisconfResults{ + { + Namespace: "user.test_yaml_check", + Query: "data.user.test_yaml_check.deny", + Message: `Provider "bar" should not be used`, + PolicyMetadata: types.PolicyMetadata{ + ID: "TEST001", + AVDID: "TEST001", + Type: "YAML Security Check", + Title: "Test check", + Severity: "LOW", + }, + CauseMetadata: types.CauseMetadata{ + Provider: "Generic", + Service: "general", + }, + }, + }, + }, + }, + }, + }, + Returns: cache.ArtifactCachePutBlobReturns{}, + }, + want: artifact.Reference{ + Name: "testdata/misconfig/yaml/passed/src", + Type: artifact.TypeFilesystem, + }, + }, + { + name: "happy path with custom schema", + fields: fields{ + dir: "./testdata/misconfig/yaml/with-schema/src", + schemas: []string{"./testdata/misconfig/yaml/with-schema/schemas"}, + }, + artifactOpt: artifact.Option{ + MisconfScannerOption: misconf.ScannerOption{ + RegoOnly: true, + Namespaces: []string{"user"}, + PolicyPaths: []string{"./testdata/misconfig/yaml/with-schema/checks"}, + DisableEmbeddedPolicies: true, + }, + }, + putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ + Args: cache.ArtifactCachePutBlobArgs{ + BlobIDAnything: true, + BlobInfo: types.BlobInfo{ + SchemaVersion: types.BlobJSONSchemaVersion, + Misconfigurations: []types.Misconfiguration{ + { + FileType: types.YAML, + FilePath: "test1.yaml", + Failures: types.MisconfResults{ + { + Namespace: "user.test_yaml_check", + Query: "data.user.test_yaml_check.deny", + Message: `Service "foo" should not be used`, + PolicyMetadata: types.PolicyMetadata{ + ID: "TEST001", + AVDID: "TEST001", + Type: "YAML Security Check", + Title: "Test check", + Severity: "LOW", + }, + CauseMetadata: types.CauseMetadata{ + Provider: "Generic", + Service: "general", + }, + }, + }, + }, + }, + }, + }, + Returns: cache.ArtifactCachePutBlobReturns{}, + }, + want: artifact.Reference{ + Name: "testdata/misconfig/yaml/with-schema/src", + Type: artifact.TypeFilesystem, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + c := new(cache.MockArtifactCache) + c.ApplyPutBlobExpectation(tt.putBlobExpectation) + + if len(tt.fields.schemas) > 0 { + schemas, err := misconf.LoadConfigSchemas(tt.fields.schemas) + require.NoError(t, err) + tt.artifactOpt.MisconfScannerOption.ConfigFileSchemas = schemas + } + + a, err := NewArtifact(tt.fields.dir, c, walker.NewFS(), tt.artifactOpt) + require.NoError(t, err) + + got, err := a.Inspect(context.Background()) + require.NoError(t, err) + require.NotNil(t, got) + + assert.Equal(t, tt.want.Name, got.Name) + assert.Equal(t, tt.want.Type, got.Type) + }) + } } diff --git a/pkg/fanal/artifact/local/testdata/misconfig/azurearm/multiple-failures/rego/policy.rego b/pkg/fanal/artifact/local/testdata/misconfig/azurearm/multiple-failures/rego/policy.rego index fca807d18e9d..4b5158649568 100644 --- a/pkg/fanal/artifact/local/testdata/misconfig/azurearm/multiple-failures/rego/policy.rego +++ b/pkg/fanal/artifact/local/testdata/misconfig/azurearm/multiple-failures/rego/policy.rego @@ -1,16 +1,19 @@ +# METADATA +# title: Test policy +# description: This is a test policy. +# related_resources: +# - "https://trivy.dev/" +# custom: +# id: TEST001 +# avd_id: AVD-TEST-0001 +# severity: LOW +# short_code: no-buckets +# recommended_actions: Have a cup of tea. +# input: +# selector: +# - type: cloud package user.something -__rego_metadata__ := { - "id": "TEST001", - "avd_id": "AVD-TEST-0001", - "title": "Test policy", - "short_code": "no-buckets", - "severity": "LOW", - "description": "This is a test policy.", - "recommended_actions": "Have a cup of tea.", - "url": "https://trivy.dev/", -} - # taken from defsec rego lib to mimic behaviour result(msg, cause) = result { metadata := object.get(cause, "__defsec_metadata", cause) diff --git a/pkg/fanal/artifact/local/testdata/misconfig/azurearm/no-results/rego/policy.rego b/pkg/fanal/artifact/local/testdata/misconfig/azurearm/no-results/rego/policy.rego index ecf4506727a3..22c65aaf287c 100644 --- a/pkg/fanal/artifact/local/testdata/misconfig/azurearm/no-results/rego/policy.rego +++ b/pkg/fanal/artifact/local/testdata/misconfig/azurearm/no-results/rego/policy.rego @@ -1,16 +1,19 @@ +# METADATA +# title: Test policy +# description: This is a test policy. +# related_resources: +# - "https://trivy.dev/" +# custom: +# id: TEST001 +# avd_id: AVD-TEST-0001 +# severity: LOW +# short_code: no-buckets +# recommended_actions: Have a cup of tea. +# input: +# selector: +# - type: cloud package user.something -__rego_metadata__ := { - "id": "TEST001", - "avd_id": "AVD-TEST-0001", - "title": "Test policy", - "short_code": "no-buckets", - "severity": "LOW", - "description": "This is a test policy.", - "recommended_actions": "Have a cup of tea.", - "url": "https://trivy.dev/", -} - # taken from defsec rego lib to mimic behaviour result(msg, cause) = result { metadata := object.get(cause, "__defsec_metadata", cause) diff --git a/pkg/fanal/artifact/local/testdata/misconfig/azurearm/passed/rego/policy.rego b/pkg/fanal/artifact/local/testdata/misconfig/azurearm/passed/rego/policy.rego index efae52a8f62c..243eb8e0d9ec 100644 --- a/pkg/fanal/artifact/local/testdata/misconfig/azurearm/passed/rego/policy.rego +++ b/pkg/fanal/artifact/local/testdata/misconfig/azurearm/passed/rego/policy.rego @@ -1,16 +1,19 @@ +# METADATA +# title: Test policy +# description: This is a test policy. +# related_resources: +# - "https://trivy.dev/" +# custom: +# id: TEST001 +# avd_id: AVD-TEST-0001 +# severity: LOW +# short_code: no-buckets +# recommended_actions: Have a cup of tea. +# input: +# selector: +# - type: cloud package user.something -__rego_metadata__ := { - "id": "TEST001", - "avd_id": "AVD-TEST-0001", - "title": "Test policy", - "short_code": "no-buckets", - "severity": "LOW", - "description": "This is a test policy.", - "recommended_actions": "Have a cup of tea.", - "url": "https://trivy.dev/", -} - # taken from defsec rego lib to mimic behaviour result(msg, cause) = result { metadata := object.get(cause, "__defsec_metadata", cause) diff --git a/pkg/fanal/artifact/local/testdata/misconfig/azurearm/single-failure/rego/policy.rego b/pkg/fanal/artifact/local/testdata/misconfig/azurearm/single-failure/rego/policy.rego index fca807d18e9d..4b5158649568 100644 --- a/pkg/fanal/artifact/local/testdata/misconfig/azurearm/single-failure/rego/policy.rego +++ b/pkg/fanal/artifact/local/testdata/misconfig/azurearm/single-failure/rego/policy.rego @@ -1,16 +1,19 @@ +# METADATA +# title: Test policy +# description: This is a test policy. +# related_resources: +# - "https://trivy.dev/" +# custom: +# id: TEST001 +# avd_id: AVD-TEST-0001 +# severity: LOW +# short_code: no-buckets +# recommended_actions: Have a cup of tea. +# input: +# selector: +# - type: cloud package user.something -__rego_metadata__ := { - "id": "TEST001", - "avd_id": "AVD-TEST-0001", - "title": "Test policy", - "short_code": "no-buckets", - "severity": "LOW", - "description": "This is a test policy.", - "recommended_actions": "Have a cup of tea.", - "url": "https://trivy.dev/", -} - # taken from defsec rego lib to mimic behaviour result(msg, cause) = result { metadata := object.get(cause, "__defsec_metadata", cause) diff --git a/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/multiple-failures/rego/policy.rego b/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/multiple-failures/rego/policy.rego index ecf4506727a3..22c65aaf287c 100644 --- a/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/multiple-failures/rego/policy.rego +++ b/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/multiple-failures/rego/policy.rego @@ -1,16 +1,19 @@ +# METADATA +# title: Test policy +# description: This is a test policy. +# related_resources: +# - "https://trivy.dev/" +# custom: +# id: TEST001 +# avd_id: AVD-TEST-0001 +# severity: LOW +# short_code: no-buckets +# recommended_actions: Have a cup of tea. +# input: +# selector: +# - type: cloud package user.something -__rego_metadata__ := { - "id": "TEST001", - "avd_id": "AVD-TEST-0001", - "title": "Test policy", - "short_code": "no-buckets", - "severity": "LOW", - "description": "This is a test policy.", - "recommended_actions": "Have a cup of tea.", - "url": "https://trivy.dev/", -} - # taken from defsec rego lib to mimic behaviour result(msg, cause) = result { metadata := object.get(cause, "__defsec_metadata", cause) diff --git a/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/no-results/rego/policy.rego b/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/no-results/rego/policy.rego index ecf4506727a3..22c65aaf287c 100644 --- a/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/no-results/rego/policy.rego +++ b/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/no-results/rego/policy.rego @@ -1,16 +1,19 @@ +# METADATA +# title: Test policy +# description: This is a test policy. +# related_resources: +# - "https://trivy.dev/" +# custom: +# id: TEST001 +# avd_id: AVD-TEST-0001 +# severity: LOW +# short_code: no-buckets +# recommended_actions: Have a cup of tea. +# input: +# selector: +# - type: cloud package user.something -__rego_metadata__ := { - "id": "TEST001", - "avd_id": "AVD-TEST-0001", - "title": "Test policy", - "short_code": "no-buckets", - "severity": "LOW", - "description": "This is a test policy.", - "recommended_actions": "Have a cup of tea.", - "url": "https://trivy.dev/", -} - # taken from defsec rego lib to mimic behaviour result(msg, cause) = result { metadata := object.get(cause, "__defsec_metadata", cause) diff --git a/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/params/code/rego/policy.rego b/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/params/code/rego/policy.rego index 1a94609aaa8b..1d8cd4a1463b 100644 --- a/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/params/code/rego/policy.rego +++ b/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/params/code/rego/policy.rego @@ -12,7 +12,9 @@ # severity: HIGH # short_code: foo-bar-baz # recommended_action: "Remove bad stuff" - +# input: +# selector: +# - type: cloud package user.something deny[res] { diff --git a/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/passed/rego/policy.rego b/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/passed/rego/policy.rego index d844d6cd2e75..ce267bc752a6 100644 --- a/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/passed/rego/policy.rego +++ b/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/passed/rego/policy.rego @@ -1,16 +1,19 @@ +# METADATA +# title: Test policy +# description: This is a test policy. +# related_resources: +# - "https://trivy.dev/" +# custom: +# id: TEST001 +# avd_id: AVD-TEST-0001 +# severity: LOW +# short_code: no-buckets +# recommended_actions: Have a cup of tea. +# input: +# selector: +# - type: cloud package user.something -__rego_metadata__ := { - "id": "TEST001", - "avd_id": "AVD-TEST-0001", - "title": "Test policy", - "short_code": "no-buckets", - "severity": "LOW", - "description": "This is a test policy.", - "recommended_actions": "Have a cup of tea.", - "url": "https://trivy.dev/", -} - # taken from defsec rego lib to mimic behaviour result(msg, cause) = result { metadata := object.get(cause, "__defsec_metadata", cause) diff --git a/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/single-failure/rego/policy.rego b/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/single-failure/rego/policy.rego index ecf4506727a3..22c65aaf287c 100644 --- a/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/single-failure/rego/policy.rego +++ b/pkg/fanal/artifact/local/testdata/misconfig/cloudformation/single-failure/rego/policy.rego @@ -1,16 +1,19 @@ +# METADATA +# title: Test policy +# description: This is a test policy. +# related_resources: +# - "https://trivy.dev/" +# custom: +# id: TEST001 +# avd_id: AVD-TEST-0001 +# severity: LOW +# short_code: no-buckets +# recommended_actions: Have a cup of tea. +# input: +# selector: +# - type: cloud package user.something -__rego_metadata__ := { - "id": "TEST001", - "avd_id": "AVD-TEST-0001", - "title": "Test policy", - "short_code": "no-buckets", - "severity": "LOW", - "description": "This is a test policy.", - "recommended_actions": "Have a cup of tea.", - "url": "https://trivy.dev/", -} - # taken from defsec rego lib to mimic behaviour result(msg, cause) = result { metadata := object.get(cause, "__defsec_metadata", cause) diff --git a/pkg/fanal/artifact/local/testdata/misconfig/json/passed/checks/test.rego b/pkg/fanal/artifact/local/testdata/misconfig/json/passed/checks/test.rego new file mode 100644 index 000000000000..b8e61860e873 --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/misconfig/json/passed/checks/test.rego @@ -0,0 +1,17 @@ +# METADATA +# title: Test check +# custom: +# id: TEST001 +# avd_id: TEST001 +# severity: LOW +package user.test_json_check + +deny[res] { + input.service == "foo" + res := result.new(`Service "foo" should not be used`, input.service) +} + +deny[res] { + input.provider == "bar" + res := result.new(`Provider "bar" should not be used`, input.provider) +} \ No newline at end of file diff --git a/pkg/fanal/artifact/local/testdata/misconfig/json/passed/src/test1.json b/pkg/fanal/artifact/local/testdata/misconfig/json/passed/src/test1.json new file mode 100644 index 000000000000..95b9d38deb71 --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/misconfig/json/passed/src/test1.json @@ -0,0 +1,3 @@ +{ + "service": "foo" +} \ No newline at end of file diff --git a/pkg/fanal/artifact/local/testdata/misconfig/json/passed/src/test2.json b/pkg/fanal/artifact/local/testdata/misconfig/json/passed/src/test2.json new file mode 100644 index 000000000000..22e90bf288b3 --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/misconfig/json/passed/src/test2.json @@ -0,0 +1,3 @@ +{ + "provider": "bar" +} \ No newline at end of file diff --git a/pkg/fanal/artifact/local/testdata/misconfig/json/with-schema/checks/test.rego b/pkg/fanal/artifact/local/testdata/misconfig/json/with-schema/checks/test.rego new file mode 100644 index 000000000000..b8e61860e873 --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/misconfig/json/with-schema/checks/test.rego @@ -0,0 +1,17 @@ +# METADATA +# title: Test check +# custom: +# id: TEST001 +# avd_id: TEST001 +# severity: LOW +package user.test_json_check + +deny[res] { + input.service == "foo" + res := result.new(`Service "foo" should not be used`, input.service) +} + +deny[res] { + input.provider == "bar" + res := result.new(`Provider "bar" should not be used`, input.provider) +} \ No newline at end of file diff --git a/pkg/fanal/artifact/local/testdata/misconfig/json/with-schema/schemas/test.json b/pkg/fanal/artifact/local/testdata/misconfig/json/with-schema/schemas/test.json new file mode 100644 index 000000000000..f72cdb0d2016 --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/misconfig/json/with-schema/schemas/test.json @@ -0,0 +1,9 @@ +{ + "$id": "https://example.com/test.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "service": { "type": "string" } + }, + "required": ["service"] +} \ No newline at end of file diff --git a/pkg/fanal/artifact/local/testdata/misconfig/json/with-schema/src/test1.json b/pkg/fanal/artifact/local/testdata/misconfig/json/with-schema/src/test1.json new file mode 100644 index 000000000000..95b9d38deb71 --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/misconfig/json/with-schema/src/test1.json @@ -0,0 +1,3 @@ +{ + "service": "foo" +} \ No newline at end of file diff --git a/pkg/fanal/artifact/local/testdata/misconfig/json/with-schema/src/test2.json b/pkg/fanal/artifact/local/testdata/misconfig/json/with-schema/src/test2.json new file mode 100644 index 000000000000..22e90bf288b3 --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/misconfig/json/with-schema/src/test2.json @@ -0,0 +1,3 @@ +{ + "provider": "bar" +} \ No newline at end of file diff --git a/pkg/fanal/artifact/local/testdata/misconfig/kubernetes/multiple-failures/rego/policy.rego b/pkg/fanal/artifact/local/testdata/misconfig/kubernetes/multiple-failures/rego/policy.rego index 6acb90f8b852..2e914843a266 100644 --- a/pkg/fanal/artifact/local/testdata/misconfig/kubernetes/multiple-failures/rego/policy.rego +++ b/pkg/fanal/artifact/local/testdata/misconfig/kubernetes/multiple-failures/rego/policy.rego @@ -1,16 +1,19 @@ +# METADATA +# title: Test policy +# description: This is a test policy. +# related_resources: +# - "https://trivy.dev/" +# custom: +# id: TEST001 +# avd_id: AVD-TEST-0001 +# severity: LOW +# short_code: no-buckets +# recommended_actions: Have a cup of tea. +# input: +# selector: +# - type: kubernetes package user.something -__rego_metadata__ := { - "id": "TEST001", - "avd_id": "AVD-TEST-0001", - "title": "Test policy", - "short_code": "no-buckets", - "severity": "LOW", - "description": "This is a test policy.", - "recommended_actions": "Have a cup of tea.", - "url": "https://trivy.dev/", -} - # taken from defsec rego lib to mimic behaviour result(msg, cause) = result { metadata := object.get(cause, "__defsec_metadata", cause) diff --git a/pkg/fanal/artifact/local/testdata/misconfig/kubernetes/no-results/rego/policy.rego b/pkg/fanal/artifact/local/testdata/misconfig/kubernetes/no-results/rego/policy.rego index 87c2e8f830b8..e46dea74b0a9 100644 --- a/pkg/fanal/artifact/local/testdata/misconfig/kubernetes/no-results/rego/policy.rego +++ b/pkg/fanal/artifact/local/testdata/misconfig/kubernetes/no-results/rego/policy.rego @@ -1,16 +1,19 @@ +# METADATA +# title: Test policy +# description: This is a test policy. +# related_resources: +# - "https://trivy.dev/" +# custom: +# id: TEST001 +# avd_id: AVD-TEST-0001 +# severity: LOW +# short_code: no-buckets +# recommended_actions: Have a cup of tea. +# input: +# selector: +# - type: kubernetes package user.something -__rego_metadata__ := { - "id": "TEST001", - "avd_id": "AVD-TEST-0001", - "title": "Test policy", - "short_code": "no-buckets", - "severity": "LOW", - "description": "This is a test policy.", - "recommended_actions": "Have a cup of tea.", - "url": "https://trivy.dev/", -} - # taken from defsec rego lib to mimic behaviour result(msg, cause) = result { metadata := object.get(cause, "__defsec_metadata", cause) diff --git a/pkg/fanal/artifact/local/testdata/misconfig/kubernetes/passed/rego/policy.rego b/pkg/fanal/artifact/local/testdata/misconfig/kubernetes/passed/rego/policy.rego index c46411777481..fd312f3d26d5 100644 --- a/pkg/fanal/artifact/local/testdata/misconfig/kubernetes/passed/rego/policy.rego +++ b/pkg/fanal/artifact/local/testdata/misconfig/kubernetes/passed/rego/policy.rego @@ -1,16 +1,19 @@ +# METADATA +# title: Test policy +# description: This is a test policy. +# related_resources: +# - "https://trivy.dev/" +# custom: +# id: TEST001 +# avd_id: AVD-TEST-0001 +# severity: LOW +# short_code: no-buckets +# recommended_actions: Have a cup of tea. +# input: +# selector: +# - type: kubernetes package user.something -__rego_metadata__ := { - "id": "TEST001", - "avd_id": "AVD-TEST-0001", - "title": "Test policy", - "short_code": "no-buckets", - "severity": "LOW", - "description": "This is a test policy.", - "recommended_actions": "Have a cup of tea.", - "url": "https://trivy.dev/", -} - # taken from defsec rego lib to mimic behaviour result(msg, cause) = result { metadata := object.get(cause, "__defsec_metadata", cause) diff --git a/pkg/fanal/artifact/local/testdata/misconfig/kubernetes/single-failure/rego/policy.rego b/pkg/fanal/artifact/local/testdata/misconfig/kubernetes/single-failure/rego/policy.rego index de8ae68d4d5d..d01bb39ce435 100644 --- a/pkg/fanal/artifact/local/testdata/misconfig/kubernetes/single-failure/rego/policy.rego +++ b/pkg/fanal/artifact/local/testdata/misconfig/kubernetes/single-failure/rego/policy.rego @@ -1,16 +1,19 @@ +# METADATA +# title: Test policy +# description: This is a test policy. +# related_resources: +# - https://trivy.dev/ +# custom: +# id: TEST001 +# avd_id: AVD-TEST-0001 +# severity: LOW +# short_code: no-evil +# recommended_actions: Have a cup of tea. +# input: +# selector: +# - type: kubernetes package user.something -__rego_metadata__ := { - "id": "TEST001", - "avd_id": "AVD-TEST-0001", - "title": "Test policy", - "short_code": "no-evil", - "severity": "LOW", - "description": "This is a test policy.", - "recommended_actions": "Have a cup of tea.", - "url": "https://trivy.dev/", -} - # taken from defsec rego lib to mimic behaviour result(msg, cause) = result { metadata := object.get(cause, "__defsec_metadata", cause) diff --git a/pkg/fanal/artifact/local/testdata/misconfig/mixed/rego/policy.rego b/pkg/fanal/artifact/local/testdata/misconfig/mixed/rego/policy.rego index a9399362d285..410a3c8ada8d 100644 --- a/pkg/fanal/artifact/local/testdata/misconfig/mixed/rego/policy.rego +++ b/pkg/fanal/artifact/local/testdata/misconfig/mixed/rego/policy.rego @@ -1,16 +1,19 @@ +# METADATA +# title: Test policy +# description: This is a test policy. +# related_resources: +# - "https://trivy.dev/" +# custom: +# id: TEST001 +# avd_id: AVD-TEST-0001 +# severity: LOW +# short_code: no-buckets +# recommended_actions: Have a cup of tea. +# input: +# selector: +# - type: cloud package user.something - __rego_metadata__ := { - "id": "TEST001", - "avd_id": "AVD-TEST-0001", - "title": "Test policy", - "short_code": "no-buckets", - "severity": "LOW", - "description": "This is a test policy.", - "recommended_actions": "Have a cup of tea.", - "url": "https://trivy.dev/", - } - # taken from defsec rego lib to mimic behaviour result(msg, cause) = result { metadata := object.get(cause, "__defsec_metadata", cause) diff --git a/pkg/fanal/artifact/local/testdata/misconfig/yaml/passed/checks/test.rego b/pkg/fanal/artifact/local/testdata/misconfig/yaml/passed/checks/test.rego new file mode 100644 index 000000000000..ef60d7c9f702 --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/misconfig/yaml/passed/checks/test.rego @@ -0,0 +1,17 @@ +# METADATA +# title: Test check +# custom: +# id: TEST001 +# avd_id: TEST001 +# severity: LOW +package user.test_yaml_check + +deny[res] { + input.service == "foo" + res := result.new(`Service "foo" should not be used`, input.service) +} + +deny[res] { + input.provider == "bar" + res := result.new(`Provider "bar" should not be used`, input.provider) +} \ No newline at end of file diff --git a/pkg/fanal/artifact/local/testdata/misconfig/yaml/passed/src/test1.yaml b/pkg/fanal/artifact/local/testdata/misconfig/yaml/passed/src/test1.yaml new file mode 100644 index 000000000000..18d05964b79b --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/misconfig/yaml/passed/src/test1.yaml @@ -0,0 +1 @@ +service: foo \ No newline at end of file diff --git a/pkg/fanal/artifact/local/testdata/misconfig/yaml/passed/src/test2.yml b/pkg/fanal/artifact/local/testdata/misconfig/yaml/passed/src/test2.yml new file mode 100644 index 000000000000..067ebe333ddf --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/misconfig/yaml/passed/src/test2.yml @@ -0,0 +1 @@ +provider: bar \ No newline at end of file diff --git a/pkg/fanal/artifact/local/testdata/misconfig/yaml/with-schema/checks/test.rego b/pkg/fanal/artifact/local/testdata/misconfig/yaml/with-schema/checks/test.rego new file mode 100644 index 000000000000..ef60d7c9f702 --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/misconfig/yaml/with-schema/checks/test.rego @@ -0,0 +1,17 @@ +# METADATA +# title: Test check +# custom: +# id: TEST001 +# avd_id: TEST001 +# severity: LOW +package user.test_yaml_check + +deny[res] { + input.service == "foo" + res := result.new(`Service "foo" should not be used`, input.service) +} + +deny[res] { + input.provider == "bar" + res := result.new(`Provider "bar" should not be used`, input.provider) +} \ No newline at end of file diff --git a/pkg/fanal/artifact/local/testdata/misconfig/yaml/with-schema/schemas/test.json b/pkg/fanal/artifact/local/testdata/misconfig/yaml/with-schema/schemas/test.json new file mode 100644 index 000000000000..f72cdb0d2016 --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/misconfig/yaml/with-schema/schemas/test.json @@ -0,0 +1,9 @@ +{ + "$id": "https://example.com/test.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "service": { "type": "string" } + }, + "required": ["service"] +} \ No newline at end of file diff --git a/pkg/fanal/artifact/local/testdata/misconfig/yaml/with-schema/src/test1.yaml b/pkg/fanal/artifact/local/testdata/misconfig/yaml/with-schema/src/test1.yaml new file mode 100644 index 000000000000..18d05964b79b --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/misconfig/yaml/with-schema/src/test1.yaml @@ -0,0 +1 @@ +service: foo \ No newline at end of file diff --git a/pkg/fanal/artifact/local/testdata/misconfig/yaml/with-schema/src/test2.yml b/pkg/fanal/artifact/local/testdata/misconfig/yaml/with-schema/src/test2.yml new file mode 100644 index 000000000000..067ebe333ddf --- /dev/null +++ b/pkg/fanal/artifact/local/testdata/misconfig/yaml/with-schema/src/test2.yml @@ -0,0 +1 @@ +provider: bar \ No newline at end of file diff --git a/pkg/fanal/artifact/repo/git_test.go b/pkg/fanal/artifact/repo/git_test.go index 8de1f3d8864b..fbfbe39ff85f 100644 --- a/pkg/fanal/artifact/repo/git_test.go +++ b/pkg/fanal/artifact/repo/git_test.go @@ -197,9 +197,9 @@ func TestArtifact_Inspect(t *testing.T) { want: artifact.Reference{ Name: ts.URL + "/test-repo.git", Type: artifact.TypeRepository, - ID: "sha256:6a89d4fcd50f840a79da64523c255da80171acd3d286df2acc60056c778d9304", + ID: "sha256:88233504639eb201433a0505956309ba0c48156f45beb786f95ccd3e8a343e9d", BlobIDs: []string{ - "sha256:6a89d4fcd50f840a79da64523c255da80171acd3d286df2acc60056c778d9304", + "sha256:88233504639eb201433a0505956309ba0c48156f45beb786f95ccd3e8a343e9d", }, }, }, diff --git a/pkg/fanal/types/const.go b/pkg/fanal/types/const.go index c257154e24ea..ffe1e0718764 100644 --- a/pkg/fanal/types/const.go +++ b/pkg/fanal/types/const.go @@ -97,6 +97,7 @@ var AggregatingTypes = []LangType{ // Config files const ( JSON ConfigType = "json" + YAML ConfigType = "yaml" Dockerfile ConfigType = "dockerfile" Terraform ConfigType = "terraform" TerraformPlanJSON ConfigType = "terraformplan" diff --git a/pkg/flag/misconf_flags.go b/pkg/flag/misconf_flags.go index fc7505fec393..128ecfcac42e 100644 --- a/pkg/flag/misconf_flags.go +++ b/pkg/flag/misconf_flags.go @@ -3,6 +3,8 @@ package flag import ( "fmt" + "github.com/samber/lo" + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/policy" xstrings "github.com/aquasecurity/trivy/pkg/x/strings" @@ -96,8 +98,15 @@ var ( MisconfigScannersFlag = Flag[[]string]{ Name: "misconfig-scanners", ConfigName: "misconfiguration.scanners", - Default: xstrings.ToStringSlice(analyzer.TypeConfigFiles), - Usage: "comma-separated list of misconfig scanners to use for misconfiguration scanning", + Default: xstrings.ToStringSlice( + lo.Without(analyzer.TypeConfigFiles, analyzer.TypeYAML, analyzer.TypeJSON), + ), + Usage: "comma-separated list of misconfig scanners to use for misconfiguration scanning", + } + ConfigFileSchemasFlag = Flag[[]string]{ + Name: "config-file-schemas", + ConfigName: "misconfiguration.config-file-schemas", + Usage: "specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking", } ) @@ -118,6 +127,7 @@ type MisconfFlagGroup struct { CloudformationParamVars *Flag[[]string] TerraformExcludeDownloaded *Flag[bool] MisconfigScanners *Flag[[]string] + ConfigFileSchemas *Flag[[]string] } type MisconfOptions struct { @@ -136,6 +146,7 @@ type MisconfOptions struct { CloudFormationParamVars []string TfExcludeDownloaded bool MisconfigScanners []analyzer.Type + ConfigFileSchemas []string } func NewMisconfFlagGroup() *MisconfFlagGroup { @@ -154,6 +165,7 @@ func NewMisconfFlagGroup() *MisconfFlagGroup { CloudformationParamVars: CfParamsFlag.Clone(), TerraformExcludeDownloaded: TerraformExcludeDownloaded.Clone(), MisconfigScanners: MisconfigScannersFlag.Clone(), + ConfigFileSchemas: ConfigFileSchemasFlag.Clone(), } } @@ -176,6 +188,7 @@ func (f *MisconfFlagGroup) Flags() []Flagger { f.TerraformExcludeDownloaded, f.CloudformationParamVars, f.MisconfigScanners, + f.ConfigFileSchemas, } } @@ -198,5 +211,6 @@ func (f *MisconfFlagGroup) ToOptions() (MisconfOptions, error) { CloudFormationParamVars: f.CloudformationParamVars.Value(), TfExcludeDownloaded: f.TerraformExcludeDownloaded.Value(), MisconfigScanners: xstrings.ToTSlice[analyzer.Type](f.MisconfigScanners.Value()), + ConfigFileSchemas: f.ConfigFileSchemas.Value(), }, nil } diff --git a/pkg/iac/detection/detect.go b/pkg/iac/detection/detect.go index cec90a79cdca..fcfab15f83b2 100644 --- a/pkg/iac/detection/detect.go +++ b/pkg/iac/detection/detect.go @@ -7,11 +7,13 @@ import ( "path/filepath" "strings" + "github.com/xeipuuv/gojsonschema" "gopkg.in/yaml.v3" "github.com/aquasecurity/trivy/pkg/iac/scanners/azure/arm/parser/armjson" "github.com/aquasecurity/trivy/pkg/iac/scanners/terraformplan/snapshot" "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" ) type FileType string @@ -33,12 +35,12 @@ const ( var matchers = make(map[FileType]func(name string, r io.ReadSeeker) bool) +// TODO(nikita): refactor. If the file matches the schema, it no longer needs to be checked for other scanners. // nolint func init() { matchers[FileTypeJSON] = func(name string, r io.ReadSeeker) bool { - ext := filepath.Ext(filepath.Base(name)) - if !strings.EqualFold(ext, ".json") { + if !isJSON(name) { return false } if resetReader(r) == nil { @@ -50,8 +52,7 @@ func init() { } matchers[FileTypeYAML] = func(name string, r io.ReadSeeker) bool { - ext := filepath.Ext(filepath.Base(name)) - if !strings.EqualFold(ext, ".yaml") && !strings.EqualFold(ext, ".yml") { + if !isYAML(name) { return false } if resetReader(r) == nil { @@ -309,3 +310,42 @@ func resetReader(r io.Reader) io.ReadSeeker { } return ensureSeeker(r) } + +func isJSON(name string) bool { + ext := filepath.Ext(name) + return strings.EqualFold(ext, ".json") +} +func isYAML(name string) bool { + ext := filepath.Ext(name) + return strings.EqualFold(ext, ".yaml") || strings.EqualFold(ext, ".yml") +} + +func IsFileMatchesSchemas(schemas map[string]*gojsonschema.Schema, typ FileType, name string, r io.ReadSeeker) bool { + defer resetReader(r) + + var l gojsonschema.JSONLoader + switch { + case typ == FileTypeJSON && isJSON(name): + b, err := io.ReadAll(r) + if err != nil { + return false + } + l = gojsonschema.NewBytesLoader(b) + case typ == FileTypeYAML && isYAML(name): + var content any + if err := yaml.NewDecoder(r).Decode(&content); err != nil { + return false + } + l = gojsonschema.NewGoLoader(content) + default: + return false + } + + for schemaPath, schema := range schemas { + if res, err := schema.Validate(l); err == nil && res.Valid() { + log.Debug("File matched schema", log.FilePath(name), log.String("schema_path", schemaPath)) + return true + } + } + return false +} diff --git a/pkg/iac/detection/detect_test.go b/pkg/iac/detection/detect_test.go index 20998427d99d..f082220f2f00 100644 --- a/pkg/iac/detection/detect_test.go +++ b/pkg/iac/detection/detect_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/xeipuuv/gojsonschema" ) func Test_Detection(t *testing.T) { @@ -473,3 +474,140 @@ func BenchmarkIsType_BigFile(b *testing.B) { _ = IsType(fmt.Sprintf("./testdata/%s", "big.file"), bytes.NewReader(data), FileTypeAzureARM) } } + +func Test_IsFileMatchesSchemas(t *testing.T) { + + schema := `{ + "$id": "https://example.com/test.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "service": { "type": "string" } + }, + "required": ["service"] +}` + + schema2 := `{ + "$id": "https://example.com/test.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "provider": { "type": "string" } + }, + "required": ["provider"] + }` + + type args struct { + schemas []string + fileType FileType + fileName string + fileContent string + } + tests := []struct { + name string + args args + matches bool + }{ + { + name: "json file matches", + args: args{ + schemas: []string{schema}, + fileType: FileTypeJSON, + fileName: "test.json", + fileContent: `{ + "service": "test" +}`, + }, + matches: true, + }, + { + name: "json file dost not matches", + args: args{ + schemas: []string{schema}, + fileType: FileTypeJSON, + fileName: "test.json", + fileContent: `{ + "somefield": "test", +}`, + }, + matches: false, + }, + { + name: "json file matches, but file type is yaml", + args: args{ + schemas: []string{schema}, + fileType: FileTypeYAML, + fileName: "test.json", + fileContent: `{ + "service": "test" +}`, + }, + matches: false, + }, + { + name: "broken json file", + args: args{ + schemas: []string{schema}, + fileType: FileTypeJSON, + fileName: "test.json", + fileContent: `{ + "service": "test",, +}`, + }, + matches: false, + }, + { + name: "yaml file matches", + args: args{ + schemas: []string{schema}, + fileType: FileTypeYAML, + fileName: "test.yml", + fileContent: `service: test`, + }, + matches: true, + }, + { + name: "yaml file does not matches", + args: args{ + schemas: []string{schema}, + fileType: FileTypeYAML, + fileName: "test.yaml", + fileContent: `somefield: test`, + }, + matches: false, + }, + { + name: "broken yaml file", + args: args{ + schemas: []string{schema}, + fileType: FileTypeYAML, + fileName: "test.yaml", + fileContent: `text foobar +number: 2`, + }, + matches: false, + }, + { + name: "multiple schemas", + args: args{ + schemas: []string{schema, schema2}, + fileType: FileTypeYAML, + fileName: "test.yaml", + fileContent: `provider: test`, + }, + matches: true, + }, + } + for _, tt := range tests { + schemas := make(map[string]*gojsonschema.Schema) + for i, content := range tt.args.schemas { + l := gojsonschema.NewStringLoader(content) + s, err := gojsonschema.NewSchema(l) + require.NoError(t, err) + schemas[fmt.Sprintf("schema-%d.json", i)] = s + } + rs := strings.NewReader(tt.args.fileContent) + got := IsFileMatchesSchemas(schemas, tt.args.fileType, tt.args.fileName, rs) + assert.Equal(t, tt.matches, got) + } +} diff --git a/pkg/iac/rego/build.go b/pkg/iac/rego/build.go index a56ee042fb52..6c84c52617fb 100644 --- a/pkg/iac/rego/build.go +++ b/pkg/iac/rego/build.go @@ -13,7 +13,7 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/types" ) -func BuildSchemaSetFromPolicies(policies map[string]*ast.Module, paths []string, fsys fs.FS) (*ast.SchemaSet, bool, error) { +func BuildSchemaSetFromPolicies(policies map[string]*ast.Module, paths []string, fsys fs.FS, customSchemas map[string][]byte) (*ast.SchemaSet, bool, error) { schemaSet := ast.NewSchemaSet() schemaSet.Put(ast.MustParseRef("schema.input"), make(map[string]any)) // for backwards compat only var customFound bool @@ -26,9 +26,15 @@ func BuildSchemaSetFromPolicies(policies map[string]*ast.Module, paths []string, continue } + if schemaSet.Get(ss.Schema) != nil { + continue + } + var schema []byte if s, ok := schemas.SchemaMap[types.Source(schemaName)]; ok { schema = []byte(s) + } else if s, ok := customSchemas[schemaName]; ok { + schema = s } else { b, err := findSchemaInFS(paths, fsys, schemaName) if err != nil { @@ -47,7 +53,7 @@ func BuildSchemaSetFromPolicies(policies map[string]*ast.Module, paths []string, return schemaSet, false, fmt.Errorf("could not parse schema %q: %w", schemaName, err) } customFound = true - schemaSet.Put(ast.MustParseRef(ss.Schema.String()), rawSchema) + schemaSet.Put(ss.Schema, rawSchema) } } } diff --git a/pkg/iac/rego/embed.go b/pkg/iac/rego/embed.go index 9d1ac6458c52..6f542d9a0b2b 100644 --- a/pkg/iac/rego/embed.go +++ b/pkg/iac/rego/embed.go @@ -33,7 +33,7 @@ func init() { func RegisterRegoRules(modules map[string]*ast.Module) { ctx := context.TODO() - schemaSet, _, _ := BuildSchemaSetFromPolicies(modules, nil, nil) + schemaSet, _, _ := BuildSchemaSetFromPolicies(modules, nil, nil, make(map[string][]byte)) compiler := ast.NewCompiler(). WithSchemas(schemaSet). diff --git a/pkg/iac/rego/load.go b/pkg/iac/rego/load.go index f2e4c0645c4f..bd474a23be4d 100644 --- a/pkg/iac/rego/load.go +++ b/pkg/iac/rego/load.go @@ -230,7 +230,7 @@ func (s *Scanner) prunePoliciesWithError(compiler *ast.Compiler) error { func (s *Scanner) compilePolicies(srcFS fs.FS, paths []string) error { - schemaSet, custom, err := BuildSchemaSetFromPolicies(s.policies, paths, srcFS) + schemaSet, custom, err := BuildSchemaSetFromPolicies(s.policies, paths, srcFS, s.customSchemas) if err != nil { return err } diff --git a/pkg/iac/rego/scanner.go b/pkg/iac/rego/scanner.go index f7293c46a0c5..fe0553d6bc00 100644 --- a/pkg/iac/rego/scanner.go +++ b/pkg/iac/rego/scanner.go @@ -65,6 +65,7 @@ type Scanner struct { embeddedLibs map[string]*ast.Module embeddedChecks map[string]*ast.Module + customSchemas map[string][]byte } func (s *Scanner) SetIncludeDeprecatedChecks(b bool) { @@ -142,6 +143,10 @@ func (s *Scanner) SetRegoErrorLimit(limit int) { s.regoErrorLimit = limit } +func (s *Scanner) SetCustomSchemas(v map[string][]byte) { + s.customSchemas = v +} + type DynamicMetadata struct { Warning bool Filepath string @@ -161,6 +166,7 @@ func NewScanner(source types.Source, opts ...options.ScannerOption) *Scanner { sourceType: source, ruleNamespaces: make(map[string]struct{}), runtimeValues: addRuntimeValues(), + customSchemas: make(map[string][]byte), } maps.Copy(s.ruleNamespaces, builtinNamespaces) diff --git a/pkg/iac/rego/scanner_test.go b/pkg/iac/rego/scanner_test.go index 67a80f51c2fd..de2b7427ae8a 100644 --- a/pkg/iac/rego/scanner_test.go +++ b/pkg/iac/rego/scanner_test.go @@ -3,6 +3,7 @@ package rego import ( "bytes" "context" + "io" "io/fs" "os" "path/filepath" @@ -1086,3 +1087,72 @@ deny { }) } } + +func Test_RegoScanner_WithCustomSchemas(t *testing.T) { + + schema := `{ + "$id": "https://example.com/test.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "service": { "type": "string" } + }, + "required": ["service"] +}` + + tests := []struct { + name string + check string + expectedResults int + }{ + { + name: "happy path", + check: `# METADATA +# title: test check +# schemas: +# - input: schema["test"] +package user.test + +deny { + input.service == "test" +} +`, + expectedResults: 1, + }, + { + name: "sad path", + check: `# METADATA +# title: test check +# schemas: +# - input: schema["test"] +package user.test + +deny { + input.other == "test" +} +`, + expectedResults: 0, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + scanner := NewScanner( + types.SourceYAML, + options.ScannerWithCustomSchemas(map[string][]byte{ + "test": []byte(schema), + }), + options.ScannerWithPolicyNamespaces("user"), + ) + err := scanner.LoadPolicies(false, false, nil, nil, []io.Reader{strings.NewReader(tc.check)}) + require.NoError(t, err) + + results, err := scanner.ScanInput(context.TODO(), Input{ + Path: "test.yaml", + Contents: map[string]any{"service": "test"}, + }) + require.NoError(t, err) + require.Len(t, results, tc.expectedResults, tc.name) + }) + } +} diff --git a/pkg/iac/scanners/azure/arm/scanner.go b/pkg/iac/scanners/azure/arm/scanner.go index 871b58df3f3d..fd585a5955c5 100644 --- a/pkg/iac/scanners/azure/arm/scanner.go +++ b/pkg/iac/scanners/azure/arm/scanner.go @@ -39,7 +39,8 @@ type Scanner struct { spec string } -func (s *Scanner) SetIncludeDeprecatedChecks(b bool) {} +func (s *Scanner) SetIncludeDeprecatedChecks(b bool) {} +func (s *Scanner) SetCustomSchemas(map[string][]byte) {} func (s *Scanner) SetSpec(spec string) { s.spec = spec diff --git a/pkg/iac/scanners/cloudformation/scanner.go b/pkg/iac/scanners/cloudformation/scanner.go index 20b96ce947fd..cedd18ea6297 100644 --- a/pkg/iac/scanners/cloudformation/scanner.go +++ b/pkg/iac/scanners/cloudformation/scanner.go @@ -63,7 +63,8 @@ type Scanner struct { spec string } -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetCustomSchemas(map[string][]byte) {} func (s *Scanner) addParserOptions(opt options.ParserOption) { s.parserOptions = append(s.parserOptions, opt) diff --git a/pkg/iac/scanners/dockerfile/scanner.go b/pkg/iac/scanners/dockerfile/scanner.go index 561872c70636..6358aada12c2 100644 --- a/pkg/iac/scanners/dockerfile/scanner.go +++ b/pkg/iac/scanners/dockerfile/scanner.go @@ -34,7 +34,8 @@ type Scanner struct { loadEmbeddedPolicies bool } -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetCustomSchemas(map[string][]byte) {} func (s *Scanner) SetSpec(spec string) { s.spec = spec diff --git a/pkg/iac/scanners/helm/scanner.go b/pkg/iac/scanners/helm/scanner.go index fe74911c51bc..944187df4dee 100644 --- a/pkg/iac/scanners/helm/scanner.go +++ b/pkg/iac/scanners/helm/scanner.go @@ -42,7 +42,8 @@ type Scanner struct { mu sync.Mutex } -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetCustomSchemas(map[string][]byte) {} func (s *Scanner) SetSpec(spec string) { s.spec = spec diff --git a/pkg/iac/scanners/json/scanner.go b/pkg/iac/scanners/json/scanner.go index 3aa0dffdb485..7a18df363823 100644 --- a/pkg/iac/scanners/json/scanner.go +++ b/pkg/iac/scanners/json/scanner.go @@ -34,7 +34,8 @@ type Scanner struct { loadEmbeddedLibraries bool } -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetCustomSchemas(map[string][]byte) {} func (s *Scanner) SetRegoOnly(bool) { } diff --git a/pkg/iac/scanners/kubernetes/scanner.go b/pkg/iac/scanners/kubernetes/scanner.go index c5437f292d85..9612fe03ebe4 100644 --- a/pkg/iac/scanners/kubernetes/scanner.go +++ b/pkg/iac/scanners/kubernetes/scanner.go @@ -38,7 +38,8 @@ type Scanner struct { loadEmbeddedLibraries bool } -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetCustomSchemas(map[string][]byte) {} func (s *Scanner) SetSpec(spec string) { s.spec = spec diff --git a/pkg/iac/scanners/options/scanner.go b/pkg/iac/scanners/options/scanner.go index 291400887037..f5b3b982ee67 100644 --- a/pkg/iac/scanners/options/scanner.go +++ b/pkg/iac/scanners/options/scanner.go @@ -24,6 +24,7 @@ type ConfigurableScanner interface { SetRegoErrorLimit(limit int) SetUseEmbeddedLibraries(bool) SetIncludeDeprecatedChecks(bool) + SetCustomSchemas(map[string][]byte) } type ScannerOption func(s ConfigurableScanner) @@ -126,3 +127,9 @@ func ScannerWithRegoErrorLimits(limit int) ScannerOption { s.SetRegoErrorLimit(limit) } } + +func ScannerWithCustomSchemas(schemas map[string][]byte) ScannerOption { + return func(s ConfigurableScanner) { + s.SetCustomSchemas(schemas) + } +} diff --git a/pkg/iac/scanners/terraform/scanner.go b/pkg/iac/scanners/terraform/scanner.go index a64201e1fcc5..5e7cea83abfd 100644 --- a/pkg/iac/scanners/terraform/scanner.go +++ b/pkg/iac/scanners/terraform/scanner.go @@ -45,7 +45,8 @@ type Scanner struct { loadEmbeddedPolicies bool } -func (s *Scanner) SetIncludeDeprecatedChecks(b bool) {} +func (s *Scanner) SetIncludeDeprecatedChecks(b bool) {} +func (s *Scanner) SetCustomSchemas(map[string][]byte) {} func (s *Scanner) SetSpec(spec string) { s.spec = spec diff --git a/pkg/iac/scanners/terraformplan/tfjson/scanner.go b/pkg/iac/scanners/terraformplan/tfjson/scanner.go index b25eed6ae42b..b390d4d10213 100644 --- a/pkg/iac/scanners/terraformplan/tfjson/scanner.go +++ b/pkg/iac/scanners/terraformplan/tfjson/scanner.go @@ -38,7 +38,8 @@ type Scanner struct { policyReaders []io.Reader } -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetCustomSchemas(map[string][]byte) {} func (s *Scanner) SetUseEmbeddedLibraries(b bool) { s.loadEmbeddedLibraries = b diff --git a/pkg/iac/scanners/toml/scanner.go b/pkg/iac/scanners/toml/scanner.go index 37e1807ac254..b7dc3510da8f 100644 --- a/pkg/iac/scanners/toml/scanner.go +++ b/pkg/iac/scanners/toml/scanner.go @@ -32,7 +32,8 @@ type Scanner struct { loadEmbeddedLibraries bool } -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetCustomSchemas(map[string][]byte) {} func (s *Scanner) SetRegoOnly(bool) {} diff --git a/pkg/iac/scanners/yaml/scanner.go b/pkg/iac/scanners/yaml/scanner.go index 534ccbd8cb7b..3ec508fdd6f5 100644 --- a/pkg/iac/scanners/yaml/scanner.go +++ b/pkg/iac/scanners/yaml/scanner.go @@ -32,7 +32,8 @@ type Scanner struct { loadEmbeddedPolicies bool } -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetCustomSchemas(map[string][]byte) {} func (s *Scanner) SetRegoOnly(bool) {} diff --git a/pkg/misconf/config_schema.go b/pkg/misconf/config_schema.go new file mode 100644 index 000000000000..a728bfa01e3b --- /dev/null +++ b/pkg/misconf/config_schema.go @@ -0,0 +1,74 @@ +package misconf + +import ( + "bytes" + "io/fs" + "os" + "path/filepath" + "regexp" + "strings" + + "github.com/xeipuuv/gojsonschema" + "golang.org/x/xerrors" +) + +type ConfigFileSchema struct { + path string + name string + source []byte + schema *gojsonschema.Schema +} + +func LoadConfigSchemas(paths []string) ([]*ConfigFileSchema, error) { + var configSchemas []*ConfigFileSchema + for _, path := range paths { + walkFn := func(path string, info fs.DirEntry, err error) error { + if err != nil { + return err + } + if info.IsDir() || !strings.HasSuffix(info.Name(), ".json") { + return nil + } + + schema, err := newConfigFileSchema(path) + if err != nil { + return xerrors.Errorf("load config file schema: %w", err) + } + + configSchemas = append(configSchemas, schema) + return nil + } + if err := filepath.WalkDir(path, walkFn); err != nil { + return nil, xerrors.Errorf("walk error: %w", err) + } + } + + return configSchemas, nil +} + +func newConfigFileSchema(path string) (*ConfigFileSchema, error) { + b, err := os.ReadFile(path) + if err != nil { + return nil, xerrors.Errorf("read config schema error: %w", err) + } + + // Go's regular expression engine does not support \Z + b = bytes.ReplaceAll(b, []byte(`\\Z`), []byte(`$`)) + + // Go's regular expression engine does not support negative lookahead + b = regexp.MustCompile(`\(\?\!.*\)`).ReplaceAll(b, []byte{}) + schema, err := gojsonschema.NewSchema(gojsonschema.NewBytesLoader(b)) + if err != nil { + return nil, xerrors.Errorf("compile config schema %s error: %w", path, err) + } + + fileName := filepath.Base(path) + schemaName := strings.TrimSuffix(fileName, filepath.Ext(fileName)) + + return &ConfigFileSchema{ + path: path, + name: schemaName, + schema: schema, + source: b, + }, nil +} diff --git a/pkg/misconf/config_schema_test.go b/pkg/misconf/config_schema_test.go new file mode 100644 index 000000000000..8290dbdfaf7c --- /dev/null +++ b/pkg/misconf/config_schema_test.go @@ -0,0 +1,41 @@ +package misconf_test + +import ( + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/aquasecurity/trivy/pkg/misconf" +) + +func Test_LoadConfigSchemas(t *testing.T) { + tests := []struct { + name string + paths []string + want int + }{ + { + name: "load one schema", + paths: []string{ + filepath.Join("testdata", "schemas", "schema1.json"), + }, + want: 1, + }, + { + name: "load dir with schemas", + paths: []string{ + filepath.Join("testdata", "schemas"), + }, + want: 3, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := misconf.LoadConfigSchemas(tt.paths) + require.NoError(t, err) + assert.Len(t, got, tt.want) + }) + } +} diff --git a/pkg/misconf/scanner.go b/pkg/misconf/scanner.go index 8730b03d2faf..5737b3b8d3bc 100644 --- a/pkg/misconf/scanner.go +++ b/pkg/misconf/scanner.go @@ -12,6 +12,7 @@ import ( "strings" "github.com/samber/lo" + "github.com/xeipuuv/gojsonschema" "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/fanal/types" @@ -22,12 +23,14 @@ import ( cfscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation" cfparser "github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation/parser" dfscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/dockerfile" - helm2 "github.com/aquasecurity/trivy/pkg/iac/scanners/helm" + "github.com/aquasecurity/trivy/pkg/iac/scanners/helm" + jsonscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/json" k8sscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/kubernetes" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform" tfprawscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/terraformplan/snapshot" tfpjsonscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/terraformplan/tfjson" + yamlscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/yaml" "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/mapfs" @@ -43,6 +46,8 @@ var enablediacTypes = map[detection.FileType]types.ConfigType{ detection.FileTypeHelm: types.Helm, detection.FileTypeTerraformPlanJSON: types.TerraformPlanJSON, detection.FileTypeTerraformPlanSnapshot: types.TerraformPlanSnapshot, + detection.FileTypeJSON: types.JSON, + detection.FileTypeYAML: types.YAML, } type ScannerOption struct { @@ -66,6 +71,9 @@ type ScannerOption struct { CloudFormationParamVars []string TfExcludeDownloaded bool K8sVersion string + + FilePatterns []string + ConfigFileSchemas []*ConfigFileSchema } func (o *ScannerOption) Sort() { @@ -75,44 +83,13 @@ func (o *ScannerOption) Sort() { } type Scanner struct { - fileType detection.FileType - scanner scanners.FSScanner - hasFilePattern bool -} - -func NewAzureARMScanner(filePatterns []string, opt ScannerOption) (*Scanner, error) { - return newScanner(detection.FileTypeAzureARM, filePatterns, opt) -} - -func NewCloudFormationScanner(filePatterns []string, opt ScannerOption) (*Scanner, error) { - return newScanner(detection.FileTypeCloudFormation, filePatterns, opt) -} - -func NewDockerfileScanner(filePatterns []string, opt ScannerOption) (*Scanner, error) { - return newScanner(detection.FileTypeDockerfile, filePatterns, opt) -} - -func NewHelmScanner(filePatterns []string, opt ScannerOption) (*Scanner, error) { - return newScanner(detection.FileTypeHelm, filePatterns, opt) -} - -func NewKubernetesScanner(filePatterns []string, opt ScannerOption) (*Scanner, error) { - return newScanner(detection.FileTypeKubernetes, filePatterns, opt) -} - -func NewTerraformScanner(filePatterns []string, opt ScannerOption) (*Scanner, error) { - return newScanner(detection.FileTypeTerraform, filePatterns, opt) + fileType detection.FileType + scanner scanners.FSScanner + hasFilePattern bool + configFileSchemas []*ConfigFileSchema } -func NewTerraformPlanJSONScanner(filePatterns []string, opt ScannerOption) (*Scanner, error) { - return newScanner(detection.FileTypeTerraformPlanJSON, filePatterns, opt) -} - -func NewTerraformPlanSnapshotScanner(filePatterns []string, opt ScannerOption) (*Scanner, error) { - return newScanner(detection.FileTypeTerraformPlanSnapshot, filePatterns, opt) -} - -func newScanner(t detection.FileType, filePatterns []string, opt ScannerOption) (*Scanner, error) { +func NewScanner(t detection.FileType, opt ScannerOption) (*Scanner, error) { opts, err := scannerOptions(t, opt) if err != nil { return nil, err @@ -127,7 +104,7 @@ func newScanner(t detection.FileType, filePatterns []string, opt ScannerOption) case detection.FileTypeDockerfile: scanner = dfscanner.NewScanner(opts...) case detection.FileTypeHelm: - scanner = helm2.New(opts...) + scanner = helm.New(opts...) case detection.FileTypeKubernetes: scanner = k8sscanner.NewScanner(opts...) case detection.FileTypeTerraform: @@ -136,12 +113,19 @@ func newScanner(t detection.FileType, filePatterns []string, opt ScannerOption) scanner = tfpjsonscanner.New(opts...) case detection.FileTypeTerraformPlanSnapshot: scanner = tfprawscanner.New(opts...) + case detection.FileTypeYAML: + scanner = yamlscanner.NewScanner(opts...) + case detection.FileTypeJSON: + scanner = jsonscanner.NewScanner(opts...) + default: + return nil, xerrors.Errorf("unknown file type: %s", t) } return &Scanner{ - fileType: t, - scanner: scanner, - hasFilePattern: hasFilePattern(t, filePatterns), + fileType: t, + scanner: scanner, + hasFilePattern: hasFilePattern(t, opt.FilePatterns), + configFileSchemas: opt.ConfigFileSchemas, }, nil } @@ -185,21 +169,31 @@ func (s *Scanner) filterFS(fsys fs.FS) (fs.FS, error) { return fsys, nil } + schemas := lo.SliceToMap(s.configFileSchemas, func(schema *ConfigFileSchema) (string, *gojsonschema.Schema) { + return schema.path, schema.schema + }) + var foundRelevantFile bool filter := func(path string, d fs.DirEntry) (bool, error) { file, err := fsys.Open(path) if err != nil { return false, err } + defer file.Close() + rs, ok := file.(io.ReadSeeker) if !ok { return false, xerrors.Errorf("type assertion error: %w", err) } - defer file.Close() - if !s.hasFilePattern && !detection.IsType(path, rs, s.fileType) { + if len(schemas) > 0 && + (s.fileType == detection.FileTypeYAML || s.fileType == detection.FileTypeJSON) && + !detection.IsFileMatchesSchemas(schemas, s.fileType, path, rs) { + return true, nil + } else if !s.hasFilePattern && !detection.IsType(path, rs, s.fileType) { return true, nil } + foundRelevantFile = true return false, nil } @@ -232,9 +226,15 @@ func scannerOptions(t detection.FileType, opt ScannerOption) ([]options.ScannerO if err != nil { return nil, err } + + schemas := lo.SliceToMap(opt.ConfigFileSchemas, func(schema *ConfigFileSchema) (string, []byte) { + return schema.name, schema.source + }) + opts = append(opts, options.ScannerWithDataDirs(dataPaths...), options.ScannerWithDataFilesystem(dataFS), + options.ScannerWithCustomSchemas(schemas), ) if opt.Debug { @@ -320,27 +320,27 @@ func addCFOpts(opts []options.ScannerOption, scannerOption ScannerOption) ([]opt func addHelmOpts(opts []options.ScannerOption, scannerOption ScannerOption) []options.ScannerOption { if len(scannerOption.HelmValueFiles) > 0 { - opts = append(opts, helm2.ScannerWithValuesFile(scannerOption.HelmValueFiles...)) + opts = append(opts, helm.ScannerWithValuesFile(scannerOption.HelmValueFiles...)) } if len(scannerOption.HelmValues) > 0 { - opts = append(opts, helm2.ScannerWithValues(scannerOption.HelmValues...)) + opts = append(opts, helm.ScannerWithValues(scannerOption.HelmValues...)) } if len(scannerOption.HelmFileValues) > 0 { - opts = append(opts, helm2.ScannerWithFileValues(scannerOption.HelmFileValues...)) + opts = append(opts, helm.ScannerWithFileValues(scannerOption.HelmFileValues...)) } if len(scannerOption.HelmStringValues) > 0 { - opts = append(opts, helm2.ScannerWithStringValues(scannerOption.HelmStringValues...)) + opts = append(opts, helm.ScannerWithStringValues(scannerOption.HelmStringValues...)) } if len(scannerOption.HelmAPIVersions) > 0 { - opts = append(opts, helm2.ScannerWithAPIVersions(scannerOption.HelmAPIVersions...)) + opts = append(opts, helm.ScannerWithAPIVersions(scannerOption.HelmAPIVersions...)) } if scannerOption.HelmKubeVersion != "" { - opts = append(opts, helm2.ScannerWithKubeVersion(scannerOption.HelmKubeVersion)) + opts = append(opts, helm.ScannerWithKubeVersion(scannerOption.HelmKubeVersion)) } return opts diff --git a/pkg/misconf/scanner_test.go b/pkg/misconf/scanner_test.go index 6270b78b65e2..e85caf651a53 100644 --- a/pkg/misconf/scanner_test.go +++ b/pkg/misconf/scanner_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/iac/detection" "github.com/aquasecurity/trivy/pkg/mapfs" ) @@ -82,8 +83,7 @@ func TestScannerOption_Sort(t *testing.T) { func TestScanner_Scan(t *testing.T) { type fields struct { - filePatterns []string - opt ScannerOption + opt ScannerOption } type file struct { path string @@ -91,7 +91,7 @@ func TestScanner_Scan(t *testing.T) { } tests := []struct { name string - scannerFunc func(filePatterns []string, opt ScannerOption) (*Scanner, error) + fileType detection.FileType fields fields files []file wantFilePath string @@ -99,8 +99,8 @@ func TestScanner_Scan(t *testing.T) { misconfsExpected int }{ { - name: "happy path. Dockerfile", - scannerFunc: NewDockerfileScanner, + name: "happy path. Dockerfile", + fileType: detection.FileTypeDockerfile, fields: fields{ opt: ScannerOption{}, }, @@ -115,11 +115,12 @@ func TestScanner_Scan(t *testing.T) { misconfsExpected: 1, }, { - name: "happy path. Dockerfile with custom file name", - scannerFunc: NewDockerfileScanner, + name: "happy path. Dockerfile with custom file name", + fileType: detection.FileTypeDockerfile, fields: fields{ - filePatterns: []string{"dockerfile:dockerf"}, - opt: ScannerOption{}, + opt: ScannerOption{ + FilePatterns: []string{"dockerfile:dockerf"}, + }, }, files: []file{ { @@ -132,8 +133,8 @@ func TestScanner_Scan(t *testing.T) { misconfsExpected: 1, }, { - name: "happy path. terraform plan file", - scannerFunc: NewTerraformPlanJSONScanner, + name: "happy path. terraform plan file", + fileType: detection.FileTypeTerraformPlanJSON, files: []file{ { path: "main.tfplan.json", @@ -154,7 +155,8 @@ func TestScanner_Scan(t *testing.T) { require.NoError(t, err) } - s, err := tt.scannerFunc(tt.fields.filePatterns, tt.fields.opt) + // s, err := tt.scannerFunc(tt.fields.filePatterns, tt.fields.opt) + s, err := NewScanner(tt.fileType, tt.fields.opt) require.NoError(t, err) misconfs, err := s.Scan(context.Background(), fsys) diff --git a/pkg/misconf/testdata/schemas/no-schema.file b/pkg/misconf/testdata/schemas/no-schema.file new file mode 100644 index 000000000000..7b4d68d70fca --- /dev/null +++ b/pkg/misconf/testdata/schemas/no-schema.file @@ -0,0 +1 @@ +empty \ No newline at end of file diff --git a/pkg/misconf/testdata/schemas/schema-with-bad-regex.json b/pkg/misconf/testdata/schemas/schema-with-bad-regex.json new file mode 100644 index 000000000000..522a1ccb46e3 --- /dev/null +++ b/pkg/misconf/testdata/schemas/schema-with-bad-regex.json @@ -0,0 +1,9 @@ +{ + "$id": "https://example.com/test.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "patternProperties": { + "^(?![\\.0-9]).": { "type": "string" }, + "test\\Z": { "type": "string" } + } +} diff --git a/pkg/misconf/testdata/schemas/schema1.json b/pkg/misconf/testdata/schemas/schema1.json new file mode 100644 index 000000000000..f72cdb0d2016 --- /dev/null +++ b/pkg/misconf/testdata/schemas/schema1.json @@ -0,0 +1,9 @@ +{ + "$id": "https://example.com/test.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "service": { "type": "string" } + }, + "required": ["service"] +} \ No newline at end of file diff --git a/pkg/misconf/testdata/schemas/schema2.json b/pkg/misconf/testdata/schemas/schema2.json new file mode 100644 index 000000000000..f72cdb0d2016 --- /dev/null +++ b/pkg/misconf/testdata/schemas/schema2.json @@ -0,0 +1,9 @@ +{ + "$id": "https://example.com/test.schema.json", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "service": { "type": "string" } + }, + "required": ["service"] +} \ No newline at end of file From db2c95598da098ca610825089eb4ab63b789b215 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Wed, 21 Aug 2024 07:01:30 +0600 Subject: [PATCH 030/183] feat(misconf): variable support for Terraform Plan (#7228) Signed-off-by: nikpivkin --- go.mod | 2 + go.sum | 4 + magefiles/magefile.go | 23 +- pkg/iac/scanners/terraform/parser/option.go | 11 + pkg/iac/scanners/terraform/parser/parser.go | 15 +- .../scanners/terraform/parser/parser_test.go | 27 +++ .../scanners/terraformplan/snapshot/plan.go | 64 +++++ .../snapshot/planproto/planfile.pb.go | 222 ++++++++++++++++++ .../snapshot/planproto/planfile.proto | 12 + .../terraformplan/snapshot/scanner.go | 5 + .../terraformplan/snapshot/scanner_test.go | 5 +- .../terraformplan/snapshot/snapshot.go | 24 +- .../terraformplan/snapshot/snapshot_test.go | 16 ++ .../with-var/checks/s3-bucket-name.rego | 21 ++ .../snapshot/testdata/with-var/main.tf | 5 + .../snapshot/testdata/with-var/tfplan | Bin 0 -> 2364 bytes 16 files changed, 446 insertions(+), 10 deletions(-) create mode 100644 pkg/iac/scanners/terraformplan/snapshot/plan.go create mode 100644 pkg/iac/scanners/terraformplan/snapshot/planproto/planfile.pb.go create mode 100644 pkg/iac/scanners/terraformplan/snapshot/planproto/planfile.proto create mode 100644 pkg/iac/scanners/terraformplan/snapshot/testdata/with-var/checks/s3-bucket-name.rego create mode 100644 pkg/iac/scanners/terraformplan/snapshot/testdata/with-var/main.tf create mode 100644 pkg/iac/scanners/terraformplan/snapshot/testdata/with-var/tfplan diff --git a/go.mod b/go.mod index 31315bc0f550..192669315152 100644 --- a/go.mod +++ b/go.mod @@ -358,6 +358,8 @@ require ( github.com/transparency-dev/merkle v0.0.2 // indirect github.com/ulikunitz/xz v0.5.11 // indirect github.com/vbatts/tar-split v0.11.5 // indirect + github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect + github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect diff --git a/go.sum b/go.sum index c34a319faf06..035cf8935436 100644 --- a/go.sum +++ b/go.sum @@ -1368,7 +1368,11 @@ github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/X github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts= github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk= github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= +github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU= +github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= +github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= github.com/xanzy/go-gitlab v0.102.0 h1:ExHuJ1OTQ2yt25zBMMj0G96ChBirGYv8U7HyUiYkZ+4= github.com/xanzy/go-gitlab v0.102.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= diff --git a/magefiles/magefile.go b/magefiles/magefile.go index 7ce148d885a0..b1dbcd3439ad 100644 --- a/magefiles/magefile.go +++ b/magefiles/magefile.go @@ -30,6 +30,10 @@ var ( } ) +var protoFiles = []string{ + "pkg/iac/scanners/terraformplan/snapshot/planproto/planfile.proto", +} + func init() { slog.SetDefault(log.New(log.NewHandler(os.Stderr, nil))) // stdout is suppressed in mage } @@ -154,11 +158,11 @@ func Mock(dir string) error { func Protoc() error { // It is called in the protoc container if _, ok := os.LookupEnv("TRIVY_PROTOC_CONTAINER"); ok { - protoFiles, err := findProtoFiles() + rpcProtoFiles, err := findRPCProtoFiles() if err != nil { return err } - for _, file := range protoFiles { + for _, file := range rpcProtoFiles { // Check if the generated Go file is up-to-date dst := strings.TrimSuffix(file, ".proto") + ".pb.go" if updated, err := target.Path(dst, file); err != nil { @@ -173,6 +177,13 @@ func Protoc() error { return err } } + + for _, file := range protoFiles { + if err := sh.RunV("protoc", ".", "paths=source_relative", "--go_out", ".", "--go_opt", + "paths=source_relative", file); err != nil { + return err + } + } return nil } @@ -331,11 +342,13 @@ func Fmt() error { } // Format proto files - protoFiles, err := findProtoFiles() + rpcProtoFiles, err := findRPCProtoFiles() if err != nil { return err } - for _, file := range protoFiles { + + allProtoFiles := append(protoFiles, rpcProtoFiles...) + for _, file := range allProtoFiles { if err = sh.Run("clang-format", "-i", file); err != nil { return err } @@ -422,7 +435,7 @@ func (Docs) Generate() error { return sh.RunWith(ENV, "go", "run", "-tags=mage_docs", "./magefiles") } -func findProtoFiles() ([]string, error) { +func findRPCProtoFiles() ([]string, error) { var files []string err := filepath.WalkDir("rpc", func(path string, d fs.DirEntry, err error) error { switch { diff --git a/pkg/iac/scanners/terraform/parser/option.go b/pkg/iac/scanners/terraform/parser/option.go index 887899496f1b..76146a4ea6bf 100644 --- a/pkg/iac/scanners/terraform/parser/option.go +++ b/pkg/iac/scanners/terraform/parser/option.go @@ -3,12 +3,15 @@ package parser import ( "io/fs" + "github.com/zclconf/go-cty/cty" + "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) type ConfigurableTerraformParser interface { options.ConfigurableParser SetTFVarsPaths(...string) + SetTFVars(vars map[string]cty.Value) SetStopOnHCLError(bool) SetWorkspaceName(string) SetAllowDownloads(bool) @@ -26,6 +29,14 @@ func OptionWithTFVarsPaths(paths ...string) options.ParserOption { } } +func OptionsWithTfVars(vars map[string]cty.Value) options.ParserOption { + return func(p options.ConfigurableParser) { + if tf, ok := p.(ConfigurableTerraformParser); ok { + tf.SetTFVars(vars) + } + } +} + func OptionStopOnHCLError(stop bool) options.ParserOption { return func(p options.ConfigurableParser) { if tf, ok := p.(ConfigurableTerraformParser); ok { diff --git a/pkg/iac/scanners/terraform/parser/parser.go b/pkg/iac/scanners/terraform/parser/parser.go index 4f79c1fdf6f2..a5b2b909a462 100644 --- a/pkg/iac/scanners/terraform/parser/parser.go +++ b/pkg/iac/scanners/terraform/parser/parser.go @@ -39,6 +39,7 @@ type Parser struct { moduleBlock *terraform.Block files []sourceFile tfvarsPaths []string + tfvars map[string]cty.Value stopOnHCLError bool workspaceName string underlying *hclparse.Parser @@ -59,6 +60,10 @@ func (p *Parser) SetTFVarsPaths(s ...string) { p.tfvarsPaths = s } +func (p *Parser) SetTFVars(vars map[string]cty.Value) { + p.tfvars = vars +} + func (p *Parser) SetStopOnHCLError(b bool) { p.stopOnHCLError = b } @@ -90,6 +95,7 @@ func New(moduleFS fs.FS, moduleSource string, opts ...options.ParserOption) *Par moduleFS: moduleFS, moduleSource: moduleSource, configsFS: moduleFS, + tfvars: make(map[string]cty.Value), } for _, option := range opts { @@ -215,10 +221,15 @@ func (p *Parser) Load(ctx context.Context) (*evaluator, error) { p.debug.Log("Read %d block(s) and %d ignore(s) for module '%s' (%d file[s])...", len(blocks), len(ignores), p.moduleName, len(p.files)) var inputVars map[string]cty.Value - if p.moduleBlock != nil { + + switch { + case p.moduleBlock != nil: inputVars = p.moduleBlock.Values().AsValueMap() p.debug.Log("Added %d input variables from module definition.", len(inputVars)) - } else { + case len(p.tfvars) > 0: + inputVars = p.tfvars + p.debug.Log("Added %d input variables from tfvars.", len(inputVars)) + default: inputVars, err = loadTFVars(p.configsFS, p.tfvarsPaths) if err != nil { return nil, err diff --git a/pkg/iac/scanners/terraform/parser/parser_test.go b/pkg/iac/scanners/terraform/parser/parser_test.go index e7a8041aa7ff..df06dd2aa393 100644 --- a/pkg/iac/scanners/terraform/parser/parser_test.go +++ b/pkg/iac/scanners/terraform/parser/parser_test.go @@ -1746,6 +1746,33 @@ func TestTFVarsFileDoesNotExist(t *testing.T) { assert.ErrorContains(t, err, "file does not exist") } +func Test_OptionsWithTfVars(t *testing.T) { + fs := testutil.CreateFS(t, map[string]string{ + "main.tf": `resource "test" "this" { + foo = var.foo +} +variable "foo" {} +`}) + + parser := New(fs, "", OptionsWithTfVars( + map[string]cty.Value{ + "foo": cty.StringVal("bar"), + }, + )) + + require.NoError(t, parser.ParseFS(context.TODO(), ".")) + + modules, _, err := parser.EvaluateAll(context.TODO()) + require.NoError(t, err) + assert.Len(t, modules, 1) + + rootModule := modules[0] + + blocks := rootModule.GetResourcesByType("test") + assert.Len(t, blocks, 1) + assert.Equal(t, "bar", blocks[0].GetAttribute("foo").Value().AsString()) +} + func TestDynamicWithIterator(t *testing.T) { fsys := fstest.MapFS{ "main.tf": &fstest.MapFile{ diff --git a/pkg/iac/scanners/terraformplan/snapshot/plan.go b/pkg/iac/scanners/terraformplan/snapshot/plan.go new file mode 100644 index 000000000000..3f0c3adcd791 --- /dev/null +++ b/pkg/iac/scanners/terraformplan/snapshot/plan.go @@ -0,0 +1,64 @@ +package snapshot + +import ( + "fmt" + "io" + + "github.com/zclconf/go-cty/cty" + ctymsgpack "github.com/zclconf/go-cty/cty/msgpack" + "google.golang.org/protobuf/proto" + + "github.com/aquasecurity/trivy/pkg/iac/scanners/terraformplan/snapshot/planproto" +) + +type DynamicValue []byte + +func (v DynamicValue) Decode(ty cty.Type) (cty.Value, error) { + if v == nil { + return cty.NilVal, nil + } + + return ctymsgpack.Unmarshal([]byte(v), ty) +} + +type Plan struct { + variableValues map[string]DynamicValue +} + +func (p Plan) inputVariables() (map[string]cty.Value, error) { + vars := make(map[string]cty.Value) + for k, v := range p.variableValues { + val, err := v.Decode(cty.DynamicPseudoType) + if err != nil { + return nil, err + } + vars[k] = val + } + return vars, nil +} + +func readTfPlan(r io.Reader) (*Plan, error) { + b, err := io.ReadAll(r) + if err != nil { + return nil, fmt.Errorf("failed to read plan: %w", err) + } + + var rawPlan planproto.Plan + if err := proto.Unmarshal(b, &rawPlan); err != nil { + return nil, fmt.Errorf("failed to unmarshal plan: %w", err) + } + + plan := Plan{ + variableValues: make(map[string]DynamicValue), + } + + for k, v := range rawPlan.Variables { + if len(v.Msgpack) == 0 { // len(0) because that's the default value for a "bytes" in protobuf + return nil, fmt.Errorf("dynamic value does not have msgpack serialization") + } + + plan.variableValues[k] = DynamicValue(v.Msgpack) + } + + return &plan, nil +} diff --git a/pkg/iac/scanners/terraformplan/snapshot/planproto/planfile.pb.go b/pkg/iac/scanners/terraformplan/snapshot/planproto/planfile.pb.go new file mode 100644 index 000000000000..1aa3ae5a7ceb --- /dev/null +++ b/pkg/iac/scanners/terraformplan/snapshot/planproto/planfile.pb.go @@ -0,0 +1,222 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.32.0 +// protoc v5.27.1 +// source: pkg/iac/scanners/terraformplan/snapshot/planproto/planfile.proto + +package planproto + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type DynamicValue struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Msgpack []byte `protobuf:"bytes,1,opt,name=msgpack,proto3" json:"msgpack,omitempty"` +} + +func (x *DynamicValue) Reset() { + *x = DynamicValue{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DynamicValue) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DynamicValue) ProtoMessage() {} + +func (x *DynamicValue) ProtoReflect() protoreflect.Message { + mi := &file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DynamicValue.ProtoReflect.Descriptor instead. +func (*DynamicValue) Descriptor() ([]byte, []int) { + return file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_rawDescGZIP(), []int{0} +} + +func (x *DynamicValue) GetMsgpack() []byte { + if x != nil { + return x.Msgpack + } + return nil +} + +type Plan struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Variables map[string]*DynamicValue `protobuf:"bytes,2,rep,name=variables,proto3" json:"variables,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *Plan) Reset() { + *x = Plan{} + if protoimpl.UnsafeEnabled { + mi := &file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Plan) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Plan) ProtoMessage() {} + +func (x *Plan) ProtoReflect() protoreflect.Message { + mi := &file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Plan.ProtoReflect.Descriptor instead. +func (*Plan) Descriptor() ([]byte, []int) { + return file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_rawDescGZIP(), []int{1} +} + +func (x *Plan) GetVariables() map[string]*DynamicValue { + if x != nil { + return x.Variables + } + return nil +} + +var File_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto protoreflect.FileDescriptor + +var file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_rawDesc = []byte{ + 0x0a, 0x40, 0x70, 0x6b, 0x67, 0x2f, 0x69, 0x61, 0x63, 0x2f, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, + 0x72, 0x73, 0x2f, 0x74, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x70, 0x6c, 0x61, 0x6e, + 0x2f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x6e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x6c, 0x61, 0x6e, 0x66, 0x69, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x12, 0x06, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x22, 0x28, 0x0a, 0x0c, 0x44, 0x79, + 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x73, + 0x67, 0x70, 0x61, 0x63, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6d, 0x73, 0x67, + 0x70, 0x61, 0x63, 0x6b, 0x22, 0x95, 0x01, 0x0a, 0x04, 0x50, 0x6c, 0x61, 0x6e, 0x12, 0x39, 0x0a, + 0x09, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1b, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x2e, 0x56, + 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x76, + 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x1a, 0x52, 0x0a, 0x0e, 0x56, 0x61, 0x72, 0x69, + 0x61, 0x62, 0x6c, 0x65, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, + 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2a, 0x0a, 0x05, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x66, + 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x4d, 0x5a, 0x4b, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x71, 0x75, 0x61, 0x73, + 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2f, 0x69, 0x61, + 0x63, 0x2f, 0x73, 0x63, 0x61, 0x6e, 0x6e, 0x65, 0x72, 0x73, 0x2f, 0x74, 0x65, 0x72, 0x72, 0x61, + 0x66, 0x6f, 0x72, 0x6d, 0x70, 0x6c, 0x61, 0x6e, 0x2f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, + 0x74, 0x2f, 0x70, 0x6c, 0x61, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x33, +} + +var ( + file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_rawDescOnce sync.Once + file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_rawDescData = file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_rawDesc +) + +func file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_rawDescGZIP() []byte { + file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_rawDescOnce.Do(func() { + file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_rawDescData = protoimpl.X.CompressGZIP(file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_rawDescData) + }) + return file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_rawDescData +} + +var file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_goTypes = []interface{}{ + (*DynamicValue)(nil), // 0: tfplan.DynamicValue + (*Plan)(nil), // 1: tfplan.Plan + nil, // 2: tfplan.Plan.VariablesEntry +} +var file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_depIdxs = []int32{ + 2, // 0: tfplan.Plan.variables:type_name -> tfplan.Plan.VariablesEntry + 0, // 1: tfplan.Plan.VariablesEntry.value:type_name -> tfplan.DynamicValue + 2, // [2:2] is the sub-list for method output_type + 2, // [2:2] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_init() } +func file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_init() { + if File_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DynamicValue); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Plan); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_goTypes, + DependencyIndexes: file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_depIdxs, + MessageInfos: file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_msgTypes, + }.Build() + File_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto = out.File + file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_rawDesc = nil + file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_goTypes = nil + file_pkg_iac_scanners_terraformplan_snapshot_planproto_planfile_proto_depIdxs = nil +} diff --git a/pkg/iac/scanners/terraformplan/snapshot/planproto/planfile.proto b/pkg/iac/scanners/terraformplan/snapshot/planproto/planfile.proto new file mode 100644 index 000000000000..c5615b819e66 --- /dev/null +++ b/pkg/iac/scanners/terraformplan/snapshot/planproto/planfile.proto @@ -0,0 +1,12 @@ +syntax = "proto3"; +package tfplan; + +option go_package = "github.com/aquasecurity/trivy/iac/scanners/terraformplan/snapshot/planproto"; + +message DynamicValue { + bytes msgpack = 1; +} + +message Plan { + map variables = 2; +} \ No newline at end of file diff --git a/pkg/iac/scanners/terraformplan/snapshot/scanner.go b/pkg/iac/scanners/terraformplan/snapshot/scanner.go index e2a8d2807fa1..3c8dcc8fce0b 100644 --- a/pkg/iac/scanners/terraformplan/snapshot/scanner.go +++ b/pkg/iac/scanners/terraformplan/snapshot/scanner.go @@ -10,6 +10,7 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" terraformScanner "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform" + tfparser "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/parser" ) type Scanner struct { @@ -71,5 +72,9 @@ func (s *Scanner) Scan(ctx context.Context, reader io.Reader) (scan.Results, err if err != nil { return nil, fmt.Errorf("failed to convert snapshot to FS: %w", err) } + + s.inner.AddParserOptions( + tfparser.OptionsWithTfVars(snap.inputVariables), + ) return s.inner.ScanFS(ctx, fsys, ".") } diff --git a/pkg/iac/scanners/terraformplan/snapshot/scanner_test.go b/pkg/iac/scanners/terraformplan/snapshot/scanner_test.go index 9eca249c1f16..6e7299e19dd1 100644 --- a/pkg/iac/scanners/terraformplan/snapshot/scanner_test.go +++ b/pkg/iac/scanners/terraformplan/snapshot/scanner_test.go @@ -98,6 +98,10 @@ func Test_ScanFS(t *testing.T) { dir: "with-remote-module", expectedIDs: []string{"ID001"}, }, + { + dir: "with-var", + expectedIDs: []string{"ID001"}, + }, } for _, tc := range tests { @@ -133,5 +137,4 @@ func Test_ScanFS(t *testing.T) { assert.Equal(t, tc.expectedIDs, ids) }) } - } diff --git a/pkg/iac/scanners/terraformplan/snapshot/snapshot.go b/pkg/iac/scanners/terraformplan/snapshot/snapshot.go index e32e47790c32..72556a984479 100644 --- a/pkg/iac/scanners/terraformplan/snapshot/snapshot.go +++ b/pkg/iac/scanners/terraformplan/snapshot/snapshot.go @@ -13,6 +13,7 @@ import ( "strings" "github.com/liamg/memoryfs" + "github.com/zclconf/go-cty/cty" iox "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -74,7 +75,8 @@ func parseSnapshot(r io.Reader) (*snapshot, error) { } snap := &snapshot{ - modules: make(map[string]*snapshotModule), + modules: make(map[string]*snapshotModule), + inputVariables: make(map[string]cty.Value), } var moduleManifest configSnapshotModuleManifest @@ -91,6 +93,23 @@ func parseSnapshot(r io.Reader) (*snapshot, error) { if err := snap.addFile(file); err != nil { return nil, err } + case file.Name == tfplanFilename: + r, err := file.Open() + if err != nil { + return nil, fmt.Errorf("failed to open plan: %w", err) + } + + plan, err := readTfPlan(r) + if err != nil { + _ = r.Close() + return nil, fmt.Errorf("failed to read tfplan: %w", err) + } + _ = r.Close() + + snap.inputVariables, err = plan.inputVariables() + if err != nil { + return nil, err + } } } @@ -140,7 +159,8 @@ type ( } snapshot struct { - modules map[string]*snapshotModule + modules map[string]*snapshotModule + inputVariables map[string]cty.Value } ) diff --git a/pkg/iac/scanners/terraformplan/snapshot/snapshot_test.go b/pkg/iac/scanners/terraformplan/snapshot/snapshot_test.go index 22f26e5e7b6b..c85791b2f283 100644 --- a/pkg/iac/scanners/terraformplan/snapshot/snapshot_test.go +++ b/pkg/iac/scanners/terraformplan/snapshot/snapshot_test.go @@ -11,6 +11,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/zclconf/go-cty/cty" ) func TestReadSnapshot(t *testing.T) { @@ -108,3 +109,18 @@ func TestIsPlanSnapshot(t *testing.T) { assert.False(t, got) }) } + +func TestPlanWithVariables(t *testing.T) { + f, err := os.Open(filepath.Join("testdata", "with-var", "tfplan")) + require.NoError(t, err) + defer f.Close() + + snapshot, err := parseSnapshot(f) + require.NoError(t, err) + require.NotNil(t, snapshot) + + expectedVars := map[string]cty.Value{ + "bucket_name": cty.StringVal("test-bucket"), + } + assert.Equal(t, expectedVars, snapshot.inputVariables) +} diff --git a/pkg/iac/scanners/terraformplan/snapshot/testdata/with-var/checks/s3-bucket-name.rego b/pkg/iac/scanners/terraformplan/snapshot/testdata/with-var/checks/s3-bucket-name.rego new file mode 100644 index 000000000000..798b1b705a49 --- /dev/null +++ b/pkg/iac/scanners/terraformplan/snapshot/testdata/with-var/checks/s3-bucket-name.rego @@ -0,0 +1,21 @@ +# METADATA +# title: Test rego +# description: A bucket named "test-bucket" is not allowed +# schemas: +# - input: schema["cloud"] +# custom: +# avd_id: ID001 +# severity: LOW +# input: +# selector: +# - type: cloud +# subtypes: +# - service: s3 +# provider: aws +package user.aws.ID001 + +deny[res] { + bucket := input.aws.s3.buckets[_] + bucket.name.value == "test-bucket" + res := result.new("Bucket not allowed", bucket.name) +} \ No newline at end of file diff --git a/pkg/iac/scanners/terraformplan/snapshot/testdata/with-var/main.tf b/pkg/iac/scanners/terraformplan/snapshot/testdata/with-var/main.tf new file mode 100644 index 000000000000..a6fc475bfb3e --- /dev/null +++ b/pkg/iac/scanners/terraformplan/snapshot/testdata/with-var/main.tf @@ -0,0 +1,5 @@ +variable "bucket_name" {} + +resource "aws_s3_bucket" "this" { + bucket = var.bucket_name +} \ No newline at end of file diff --git a/pkg/iac/scanners/terraformplan/snapshot/testdata/with-var/tfplan b/pkg/iac/scanners/terraformplan/snapshot/testdata/with-var/tfplan new file mode 100644 index 0000000000000000000000000000000000000000..78be033f53d4cefbfb73bc2bf9805b93a2b4011e GIT binary patch literal 2364 zcmWIWW@Zs#-~htQ%|9a;kN_J4CqqeEK~7>`Xb39Djr$A;WaLdHKDRy}Qr6J8BpxRmUW&+oHmv>a@hkgzcj+A1Buj z-4``|9Gu~AdheatQ~BA1yZ74LXHS<1NWa+GrnoK7Wc}Vh+XO89gPtF(?myRFTKDnv zpTDWzX~D}p{Fx5LSouHRwsFPYlU>^u)>Ja&DYPo?=1~^6sr|5eqrvrG7c=Ve|D>7w zJ8*<}JXm`1PUVMIZOLk8C*S%d-p9VZ%1l?UpTp^MR$$4zS2~i`vldP>m>jK|JU`uG z>6wgx=dbQ_I`;)HTy}P*Vxx`g^OHUM_nqb3qAzJJC-L0y>G@tay~~p}UcdZ3;v~<} z2o0Om8{ul_m!9)JW;ZiMw)Od`4qm;Ub189Gyr=cdo#VTx%_Y%wM|$t1q!`z&_qy6I zXlZ6upZhE$Xs3OlGB2?w#OT}SY0kG?9{DXh5y&ld`+wQHsuOpgEU2`kU+z9r27`TW-Uht~RZw*1|Pl`Lz=(WBKFH=Ca2;?sz;+{Xw2WyJLNI zy5@nrNveA-xB?kk=JKs;%f5LlN@D$y)rCq`NvHawQBqJr`aO8?} zj+atC26ah_oVr}I{BCwR|MPVvi{E)kd_DB;uKUHkbuwQc-+OG&$iVRbe}FeT$Evm8 z+BBFL7_68X7y@u6GInqxD=tYaNrk5}mo8f_Cqtfw@AH&WrnPq|e9=J}8G zmJN3I3WMF7oS&DLnXaF!tDl>gnWtBh26wiWx6UaapHrTp0bW|Z=lpa#&wHQo4Gmhc z?&%{fFWqzcx?X-jDINVjeY3vy6#+p3S|?BFgaxg578KCHp?O1VimKR4#hC{}xjA6r zI6wYCw;wPJBk_i#D2luCQ%ZAEi}kXK^AW{N7tjijH9+vmZ*9n?pn#xDjRmnr-3~Ff zs(P%gQR^ZcfL1`#+1#bsvYJ312;+`CP+;hlq!tw=rsWsq>gD7oXX|Ao=fDFatxZpN-)${xB`WQnG`3AXoCLV4STr%VC+>Lw+6HU%9DaA zOU`fl`F#1@+L&W6i|VrPU#tCp8HF`R6Wn$<-PxXkXPn^ zj`wf=+Vu19yl?#H$H#}Ke|@<9JKsLOZrA?*Pfsj=C;$Kd)9e1{pPybX-?x1C-~azk z|EsB)zM1Wt8vNfg*-Ig^{qS#{Q7gCong9a<-R*5>e>$h4yuRkMEgeVVcJ*bJR(S!XYF z1%&cBZCcRiwKs9LM}Xq_zDv3*x-}TZcQ4ht#W34!xk+D;Zqf?r=`tK0Y7_e z$g;^evcYP`9*bYRrcuKBk{1iI!u7AZ^Qyd!Sm|CqiK&MpD95U;RQ6Ui?`DJVMc!Wx zS`$*;bl%P2-M~?P;%JxQZsi>Ye4+2cRy><$Dxy=IxRyO--VeT?L*I5qv z>-P4 Date: Wed, 21 Aug 2024 08:37:42 +0600 Subject: [PATCH 031/183] fix: safely check if the directory exists (#7353) Signed-off-by: nikpivkin --- pkg/utils/fsutils/fs.go | 14 +++----- pkg/utils/fsutils/fs_test.go | 62 ++++++++++++++++++++++++++---------- 2 files changed, 49 insertions(+), 27 deletions(-) diff --git a/pkg/utils/fsutils/fs.go b/pkg/utils/fsutils/fs.go index e0518236f9a8..b2aea51dda0a 100644 --- a/pkg/utils/fsutils/fs.go +++ b/pkg/utils/fsutils/fs.go @@ -1,7 +1,6 @@ package fsutils import ( - "errors" "fmt" "io" "io/fs" @@ -59,18 +58,13 @@ func CopyFile(src, dst string) (int64, error) { } func DirExists(path string) bool { - if f, err := os.Stat(path); os.IsNotExist(err) || !f.IsDir() { - return false - } - return true + f, err := os.Stat(path) + return err == nil && f.IsDir() } func FileExists(filename string) bool { - _, err := os.Stat(filename) - if errors.Is(err, os.ErrNotExist) { - return false - } - return err == nil + f, err := os.Stat(filename) + return err == nil && !f.IsDir() } type WalkDirRequiredFunc func(path string, d fs.DirEntry) bool diff --git a/pkg/utils/fsutils/fs_test.go b/pkg/utils/fsutils/fs_test.go index fef4b7f5a32c..42a4b113a5ef 100644 --- a/pkg/utils/fsutils/fs_test.go +++ b/pkg/utils/fsutils/fs_test.go @@ -2,29 +2,13 @@ package fsutils import ( "os" + "path/filepath" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) -func touch(t *testing.T, name string) { - f, err := os.Create(name) - if err != nil { - t.Fatal(err) - } - if err := f.Close(); err != nil { - t.Fatal(err) - } -} - -func write(t *testing.T, name, content string) { - err := os.WriteFile(name, []byte(content), 0666) - if err != nil { - t.Fatal(err) - } -} - func TestCopyFile(t *testing.T) { type args struct { src string @@ -72,3 +56,47 @@ func TestCopyFile(t *testing.T) { }) } } + +func TestDirExists(t *testing.T) { + t.Run("invalid path", func(t *testing.T) { + assert.False(t, DirExists("\000invalid:path")) + }) + + t.Run("valid path", func(t *testing.T) { + assert.True(t, DirExists(t.TempDir())) + }) + + t.Run("dir not exist", func(t *testing.T) { + assert.False(t, DirExists(filepath.Join(t.TempDir(), "tmp"))) + }) + + t.Run("file path", func(t *testing.T) { + filePath := filepath.Join(t.TempDir(), "tmp") + f, err := os.Create(filePath) + require.NoError(t, f.Close()) + require.NoError(t, err) + assert.False(t, DirExists(filePath)) + }) +} + +func TestFileExists(t *testing.T) { + t.Run("invalid path", func(t *testing.T) { + assert.False(t, FileExists("\000invalid:path")) + }) + + t.Run("valid path", func(t *testing.T) { + filePath := filepath.Join(t.TempDir(), "tmp") + f, err := os.Create(filePath) + require.NoError(t, f.Close()) + require.NoError(t, err) + assert.True(t, FileExists(filePath)) + }) + + t.Run("file not exist", func(t *testing.T) { + assert.False(t, FileExists(filepath.Join(t.TempDir(), "tmp"))) + }) + + t.Run("dir path", func(t *testing.T) { + assert.False(t, FileExists(t.TempDir())) + }) +} From 3f0e7ebe0dfaca16d073f56c484c00c65c7f025a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Aug 2024 06:38:42 +0400 Subject: [PATCH 032/183] chore(deps): bump the aws group across 1 directory with 7 updates (#7358) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 32 ++++++++++++++--------------- go.sum | 64 +++++++++++++++++++++++++++++----------------------------- 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/go.mod b/go.mod index 192669315152..1465ad2b2343 100644 --- a/go.mod +++ b/go.mod @@ -29,14 +29,14 @@ require ( github.com/aquasecurity/trivy-db v0.0.0-20240718084044-d23a6ca8ba04 github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20240707095038-0300bc49b68b - github.com/aws/aws-sdk-go-v2 v1.30.3 - github.com/aws/aws-sdk-go-v2/config v1.27.27 - github.com/aws/aws-sdk-go-v2/credentials v1.17.27 - github.com/aws/aws-sdk-go-v2/service/ec2 v1.173.0 - github.com/aws/aws-sdk-go-v2/service/ecr v1.31.0 - github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3 - github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect - github.com/aws/smithy-go v1.20.3 + github.com/aws/aws-sdk-go-v2 v1.30.4 + github.com/aws/aws-sdk-go-v2/config v1.27.28 + github.com/aws/aws-sdk-go-v2/credentials v1.17.28 + github.com/aws/aws-sdk-go-v2/service/ec2 v1.175.1 + github.com/aws/aws-sdk-go-v2/service/ecr v1.32.1 + github.com/aws/aws-sdk-go-v2/service/s3 v1.59.0 + github.com/aws/aws-sdk-go-v2/service/sts v1.30.4 // indirect + github.com/aws/smithy-go v1.20.4 github.com/bitnami/go-version v0.0.0-20231130084017-bb00604d650c github.com/bmatcuk/doublestar/v4 v4.6.1 github.com/cenkalti/backoff/v4 v4.3.0 @@ -171,15 +171,15 @@ require ( github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go v1.54.6 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/blang/semver v3.5.1+incompatible // indirect diff --git a/go.sum b/go.sum index 035cf8935436..1a1e285e8de6 100644 --- a/go.sum +++ b/go.sum @@ -365,44 +365,44 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:W github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.54.6 h1:HEYUib3yTt8E6vxjMWM3yAq5b+qjj/6aKA62mkgux9g= github.com/aws/aws-sdk-go v1.54.6/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.30.3 h1:jUeBtG0Ih+ZIFH0F4UkmL9w3cSpaMv9tYYDbzILP8dY= -github.com/aws/aws-sdk-go-v2 v1.30.3/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc= -github.com/aws/aws-sdk-go-v2/config v1.27.27 h1:HdqgGt1OAP0HkEDDShEl0oSYa9ZZBSOmKpdpsDMdO90= -github.com/aws/aws-sdk-go-v2/config v1.27.27/go.mod h1:MVYamCg76dFNINkZFu4n4RjDixhVr51HLj4ErWzrVwg= -github.com/aws/aws-sdk-go-v2/credentials v1.17.27 h1:2raNba6gr2IfA0eqqiP2XiQ0UVOpGPgDSi0I9iAP+UI= -github.com/aws/aws-sdk-go-v2/credentials v1.17.27/go.mod h1:gniiwbGahQByxan6YjQUMcW4Aov6bLC3m+evgcoN4r4= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11 h1:KreluoV8FZDEtI6Co2xuNk/UqI9iwMrOx/87PBNIKqw= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.11/go.mod h1:SeSUYBLsMYFoRvHE0Tjvn7kbxaUhl75CJi1sbfhMxkU= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15 h1:SoNJ4RlFEQEbtDcCEt+QG56MY4fm4W8rYirAmq+/DdU= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.15/go.mod h1:U9ke74k1n2bf+RIgoX1SXFed1HLs51OgUSs+Ph0KJP8= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15 h1:C6WHdGnTDIYETAm5iErQUiVNsclNx9qbJVPIt03B6bI= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.15/go.mod h1:ZQLZqhcu+JhSrA9/NXRm8SkDvsycE+JkV3WGY41e+IM= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= +github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDagTk8= +github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= +github.com/aws/aws-sdk-go-v2/config v1.27.28 h1:OTxWGW/91C61QlneCtnD62NLb4W616/NM1jA8LhJqbg= +github.com/aws/aws-sdk-go-v2/config v1.27.28/go.mod h1:uzVRVtJSU5EFv6Fu82AoVFKozJi2ZCY6WRCXj06rbvs= +github.com/aws/aws-sdk-go-v2/credentials v1.17.28 h1:m8+AHY/ND8CMHJnPoH7PJIRakWGa4gbfbxuY9TGTUXM= +github.com/aws/aws-sdk-go-v2/credentials v1.17.28/go.mod h1:6TF7dSc78ehD1SL6KpRIPKMA1GyyWflIkjqg+qmf4+c= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 h1:yjwoSyDZF8Jth+mUk5lSPJCkMC0lMy6FaCD51jm6ayE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12/go.mod h1:fuR57fAgMk7ot3WcNQfb6rSEn+SUffl7ri+aa8uKysI= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 h1:TNyt/+X43KJ9IJJMjKfa3bNTiZbUP7DeCxfbTROESwY= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16/go.mod h1:2DwJF39FlNAUiX5pAc0UNeiz16lK2t7IaFcm0LFHEgc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 h1:jYfy8UPmd+6kJW5YhY0L1/KftReOGxI/4NtVSTh9O/I= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16/go.mod h1:7ZfEPZxkW42Afq4uQB8H2E2e6ebh6mXTueEpYzjCzcs= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7 h1:CRzzXjmgx9p362yO39D6hbZULdMI23gaKqSxijJCXHM= github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7/go.mod h1:wnsHqpi3RgDwklS5SPHUgjcUUpontGPKJ+GJYOdV7pY= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.173.0 h1:ta62lid9JkIpKZtZZXSj6rP2AqY5x1qYGq53ffxqD9Q= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.173.0/go.mod h1:o6QDjdVKpP5EF0dp/VlvqckzuSDATr1rLdHt3A5m0YY= -github.com/aws/aws-sdk-go-v2/service/ecr v1.31.0 h1:vi/MwojjLGATEEUFn2GEdLiom7CFlB+qCIx4tDWqKfQ= -github.com/aws/aws-sdk-go-v2/service/ecr v1.31.0/go.mod h1:RhaP7Wil0+uuuhiE4FzOOEFZwkmFAk1ZflXzK+O3ptU= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.175.1 h1:7B5ppg4i5N2B6t+aH77WLbAu8sD98MLlzruWzq5scyY= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.175.1/go.mod h1:ISODge3zgdwOEa4Ou6WM9PKbxJWJ15DYKnr2bfmCAIA= +github.com/aws/aws-sdk-go-v2/service/ecr v1.32.1 h1:PxM8EHsv1sd9eWGamMQCvqBEjxytK5kAwjrxlfG3tac= +github.com/aws/aws-sdk-go-v2/service/ecr v1.32.1/go.mod h1:kdk+WJbHcGVbIlRQfSrKyuKkbWDdD8I9NScyS5vZ8eQ= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2 h1:PpbXaecV3sLAS6rjQiaKw4/jyq3Z8gNzmoJupHAoBp0= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2/go.mod h1:fUHpGXr4DrXkEDpGAjClPsviWf+Bszeb0daKE0blxv8= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3 h1:dT3MqvGhSoaIhRseqw2I0yH81l7wiR2vjs57O51EAm8= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.3/go.mod h1:GlAeCkHwugxdHaueRr4nhPuY+WW+gR8UjlcqzPr1SPI= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17 h1:HGErhhrxZlQ044RiM+WdoZxp0p+EGM62y3L6pwA4olE= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.17/go.mod h1:RkZEx4l0EHYDJpWppMJ3nD9wZJAa8/0lq9aVC+r2UII= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4/go.mod h1:Vz1JQXliGcQktFTN/LN6uGppAIRoLBR2bMvIMP0gOjc= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 h1:tJ5RnkHCiSH0jyd6gROjlJtNwov0eGYNz8s8nFcR0jQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18/go.mod h1:++NHzT+nAF7ZPrHPsA+ENvsXkOO8wEu+C6RXltAG4/c= github.com/aws/aws-sdk-go-v2/service/kms v1.30.0 h1:yS0JkEdV6h9JOo8sy2JSpjX+i7vsKifU8SIeHrqiDhU= github.com/aws/aws-sdk-go-v2/service/kms v1.30.0/go.mod h1:+I8VUUSVD4p5ISQtzpgSva4I8cJ4SQ4b1dcBcof7O+g= -github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3 h1:hT8ZAZRIfqBqHbzKTII+CIiY8G2oC9OpLedkZ51DWl8= -github.com/aws/aws-sdk-go-v2/service/s3 v1.58.3/go.mod h1:Lcxzg5rojyVPU/0eFwLtcyTaek/6Mtic5B1gJo7e/zE= -github.com/aws/aws-sdk-go-v2/service/sso v1.22.4 h1:BXx0ZIxvrJdSgSvKTZ+yRBeSqqgPM89VPlulEcl37tM= -github.com/aws/aws-sdk-go-v2/service/sso v1.22.4/go.mod h1:ooyCOXjvJEsUw7x+ZDHeISPMhtwI3ZCB7ggFMcFfWLU= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4 h1:yiwVzJW2ZxZTurVbYWA7QOrAaCYQR72t0wrSBfoesUE= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.4/go.mod h1:0oxfLkpz3rQ/CHlx5hB7H69YUpFiI1tql6Q6Ne+1bCw= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 h1:ZsDKRLXGWHk8WdtyYMoGNO7bTudrvuKpDKgMVRlepGE= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.3/go.mod h1:zwySh8fpFyXp9yOr/KVzxOl8SRqgf/IDw5aUt9UKFcQ= -github.com/aws/smithy-go v1.20.3 h1:ryHwveWzPV5BIof6fyDvor6V3iUL7nTfiTKXHiW05nE= -github.com/aws/smithy-go v1.20.3/go.mod h1:krry+ya/rV9RDcV/Q16kpu6ypI4K2czasz0NC3qS14E= +github.com/aws/aws-sdk-go-v2/service/s3 v1.59.0 h1:Cso4Ev/XauMVsbwdhYEoxg8rxZWw43CFqqaPB5w3W2c= +github.com/aws/aws-sdk-go-v2/service/s3 v1.59.0/go.mod h1:BSPI0EfnYUuNHPS0uqIo5VrRwzie+Fp+YhQOUs16sKI= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 h1:zCsFCKvbj25i7p1u94imVoO447I/sFv8qq+lGJhRN0c= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.5/go.mod h1:ZeDX1SnKsVlejeuz41GiajjZpRSWR7/42q/EyA/QEiM= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 h1:SKvPgvdvmiTWoi0GAJ7AsJfOz3ngVkD/ERbs5pUnHNI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5/go.mod h1:20sz31hv/WsPa3HhU3hfrIet2kxM4Pe0r20eBZ20Tac= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.4 h1:iAckBT2OeEK/kBDyN/jDtpEExhjeeA/Im2q4X0rJZT8= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.4/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0= +github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= +github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 h1:SoFYaT9UyGkR0+nogNyD/Lj+bsixB+SNuAS4ABlEs6M= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8/go.mod h1:2JF49jcDOrLStIXN/j/K1EKRq8a8R2qRnlZA6/o/c7c= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= From 24a45636867b893ff54c5ce07197f3b5c6db1d9b Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Wed, 21 Aug 2024 09:26:11 +0400 Subject: [PATCH 033/183] feat(server): add internal `--path-prefix` flag for client/server mode (#7321) Signed-off-by: knqyf263 --- .../references/configuration/config-file.md | 15 ----- integration/client_server_test.go | 59 ++++++++++++------- magefiles/docs.go | 2 +- pkg/cache/remote.go | 9 ++- pkg/commands/artifact/run.go | 6 +- pkg/commands/server/run.go | 2 +- pkg/flag/options.go | 30 ++++++++-- pkg/flag/remote_flags.go | 21 ++++++- pkg/rpc/client/client.go | 19 +++--- pkg/rpc/server/listen.go | 32 ++++++---- pkg/rpc/server/listen_test.go | 12 ++-- 11 files changed, 130 insertions(+), 77 deletions(-) diff --git a/docs/docs/references/configuration/config-file.md b/docs/docs/references/configuration/config-file.md index f3edb6a8e2b6..932710f6e2b9 100644 --- a/docs/docs/references/configuration/config-file.md +++ b/docs/docs/references/configuration/config-file.md @@ -33,9 +33,6 @@ cache: # Same as '--cache-backend' backend: "fs" - # Same as '--clear-cache' - clear: false - redis: # Same as '--redis-ca' ca: "" @@ -112,9 +109,6 @@ db: # Same as '--skip-java-db-update' java-skip-update: false - # Same as '--light' - light: false - # Same as '--no-progress' no-progress: false @@ -124,9 +118,6 @@ db: # Same as '--skip-db-update' skip-update: false -# Same as '--reset' -reset: false - ``` ## Image options @@ -411,9 +402,6 @@ misconfiguration: # Same as '--include-non-failures' include-non-failures: false - # Same as '--reset-checks-bundle' - reset-checks-bundle: false - # Same as '--misconfig-scanners' scanners: - azure-arm @@ -580,9 +568,6 @@ scan: # Same as '--skip-files' skip-files: [] - # Same as '--slow' - slow: false - ``` ## Secret options diff --git a/integration/client_server_test.go b/integration/client_server_test.go index e0edce7aa6a8..adeab3f4c7b3 100644 --- a/integration/client_server_test.go +++ b/integration/client_server_test.go @@ -32,6 +32,7 @@ type csArgs struct { Input string ClientToken string ClientTokenHeader string + PathPrefix string ListAllPackages bool Target string secretConfig string @@ -443,7 +444,11 @@ func TestClientServerWithCycloneDX(t *testing.T) { } } -func TestClientServerWithToken(t *testing.T) { +func TestClientServerWithCustomOptions(t *testing.T) { + token := "token" + tokenHeader := "Trivy-Token" + pathPrefix := "prefix" + tests := []struct { name string args csArgs @@ -451,11 +456,12 @@ func TestClientServerWithToken(t *testing.T) { wantErr string }{ { - name: "alpine 3.9 with token", + name: "alpine 3.9 with token and prefix", args: csArgs{ Input: "testdata/fixtures/images/alpine-39.tar.gz", - ClientToken: "token", - ClientTokenHeader: "Trivy-Token", + ClientToken: token, + ClientTokenHeader: tokenHeader, + PathPrefix: pathPrefix, }, golden: "testdata/alpine-39.json.golden", }, @@ -464,7 +470,8 @@ func TestClientServerWithToken(t *testing.T) { args: csArgs{ Input: "testdata/fixtures/images/distroless-base.tar.gz", ClientToken: "invalidtoken", - ClientTokenHeader: "Trivy-Token", + ClientTokenHeader: tokenHeader, + PathPrefix: pathPrefix, }, wantErr: "twirp error unauthenticated: invalid token", }, @@ -472,18 +479,28 @@ func TestClientServerWithToken(t *testing.T) { name: "invalid token header", args: csArgs{ Input: "testdata/fixtures/images/distroless-base.tar.gz", - ClientToken: "token", + ClientToken: token, ClientTokenHeader: "Unknown-Header", + PathPrefix: pathPrefix, }, wantErr: "twirp error unauthenticated: invalid token", }, + { + name: "wrong path prefix", + args: csArgs{ + Input: "testdata/fixtures/images/distroless-base.tar.gz", + ClientToken: token, + ClientTokenHeader: tokenHeader, + PathPrefix: "wrong", + }, + wantErr: "HTTP status code 404", + }, } - serverToken := "token" - serverTokenHeader := "Trivy-Token" addr, cacheDir := setup(t, setupOptions{ - token: serverToken, - tokenHeader: serverTokenHeader, + token: token, + tokenHeader: tokenHeader, + pathPrefix: pathPrefix, }) for _, tt := range tests { @@ -539,6 +556,7 @@ func TestClientServerWithRedis(t *testing.T) { type setupOptions struct { token string tokenHeader string + pathPrefix string cacheBackend string } @@ -556,7 +574,7 @@ func setup(t *testing.T, options setupOptions) (string, string) { addr := fmt.Sprintf("localhost:%d", port) go func() { - osArgs := setupServer(addr, options.token, options.tokenHeader, cacheDir, options.cacheBackend) + osArgs := setupServer(addr, options.token, options.tokenHeader, options.pathPrefix, cacheDir, options.cacheBackend) // Run Trivy server require.NoError(t, execute(osArgs)) @@ -569,22 +587,20 @@ func setup(t *testing.T, options setupOptions) (string, string) { return addr, cacheDir } -func setupServer(addr, token, tokenHeader, cacheDir, cacheBackend string) []string { +func setupServer(addr, token, tokenHeader, pathPrefix, cacheDir, cacheBackend string) []string { osArgs := []string{ "--cache-dir", cacheDir, "server", - "--skip-update", + "--skip-db-update", "--listen", addr, } if token != "" { - osArgs = append(osArgs, []string{ - "--token", - token, - "--token-header", - tokenHeader, - }...) + osArgs = append(osArgs, "--token", token, "--token-header", tokenHeader) + } + if pathPrefix != "" { + osArgs = append(osArgs, "--path-prefix", pathPrefix) } if cacheBackend != "" { osArgs = append(osArgs, "--cache-backend", cacheBackend) @@ -593,13 +609,13 @@ func setupServer(addr, token, tokenHeader, cacheDir, cacheBackend string) []stri } func setupClient(t *testing.T, c csArgs, addr string, cacheDir string) []string { + t.Helper() if c.Command == "" { c.Command = "image" } if c.RemoteAddrOption == "" { c.RemoteAddrOption = "--server" } - t.Helper() osArgs := []string{ "--cache-dir", cacheDir, @@ -639,6 +655,9 @@ func setupClient(t *testing.T, c csArgs, addr string, cacheDir string) []string if c.ClientToken != "" { osArgs = append(osArgs, "--token", c.ClientToken, "--token-header", c.ClientTokenHeader) } + if c.PathPrefix != "" { + osArgs = append(osArgs, "--path-prefix", c.PathPrefix) + } if c.Input != "" { osArgs = append(osArgs, "--input", c.Input) } diff --git a/magefiles/docs.go b/magefiles/docs.go index 7d09d37e1092..bdb85c5357cb 100644 --- a/magefiles/docs.go +++ b/magefiles/docs.go @@ -105,7 +105,7 @@ func writeFlags(group flag.FlagGroup, w *os.File) { var lastParts []string for _, flg := range flags { - if flg.GetConfigName() == "" { + if flg.GetConfigName() == "" || flg.Hidden() { continue } // We need to split the config name on `.` to make the indentations needed in yaml. diff --git a/pkg/cache/remote.go b/pkg/cache/remote.go index 44c9f63c92d8..19d748bf7923 100644 --- a/pkg/cache/remote.go +++ b/pkg/cache/remote.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "net/http" + "github.com/twitchtv/twirp" "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/fanal/types" @@ -19,6 +20,7 @@ type RemoteOptions struct { ServerAddr string CustomHeaders http.Header Insecure bool + PathPrefix string } // RemoteCache implements remote cache @@ -39,7 +41,12 @@ func NewRemoteCache(opts RemoteOptions) *RemoteCache { }, }, } - c := rpcCache.NewCacheProtobufClient(opts.ServerAddr, httpClient) + + var twirpOpts []twirp.ClientOption + if opts.PathPrefix != "" { + twirpOpts = append(twirpOpts, twirp.WithClientPathPrefix(opts.PathPrefix)) + } + c := rpcCache.NewCacheProtobufClient(opts.ServerAddr, httpClient, twirpOpts...) return &RemoteCache{ ctx: ctx, client: c, diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index 3edc54dc723c..59b3313d2f15 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -545,11 +545,7 @@ func (r *runner) initScannerConfig(opts flag.Options) (ScannerConfig, types.Scan Target: target, CacheOptions: opts.CacheOpts(), RemoteCacheOptions: opts.RemoteCacheOpts(), - ServerOption: client.ScannerOption{ - RemoteURL: opts.ServerAddr, - CustomHeaders: opts.CustomHeaders, - Insecure: opts.Insecure, - }, + ServerOption: opts.ClientScannerOpts(), ArtifactOption: artifact.Option{ DisabledAnalyzers: disabledAnalyzers(opts), DisabledHandlers: disabledHandlers, diff --git a/pkg/commands/server/run.go b/pkg/commands/server/run.go index 19b24f990396..6c5316d7465a 100644 --- a/pkg/commands/server/run.go +++ b/pkg/commands/server/run.go @@ -50,6 +50,6 @@ func Run(ctx context.Context, opts flag.Options) (err error) { m.Register() server := rpcServer.NewServer(opts.AppVersion, opts.Listen, opts.CacheDir, opts.Token, opts.TokenHeader, - opts.DBRepository, opts.RegistryOpts()) + opts.PathPrefix, opts.DBRepository, opts.RegistryOpts()) return server.ListenAndServe(ctx, cacheClient, opts.SkipDBUpdate) } diff --git a/pkg/flag/options.go b/pkg/flag/options.go index 9bbcef79690b..e00aa4cfa922 100644 --- a/pkg/flag/options.go +++ b/pkg/flag/options.go @@ -23,6 +23,7 @@ import ( "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/plugin" "github.com/aquasecurity/trivy/pkg/result" + "github.com/aquasecurity/trivy/pkg/rpc/client" "github.com/aquasecurity/trivy/pkg/types" "github.com/aquasecurity/trivy/pkg/version/app" ) @@ -56,15 +57,21 @@ type Flag[T FlagType] struct { // Usage explains how to use the flag. Usage string - // Persistent represents if the flag is persistent + // Persistent represents if the flag is persistent. Persistent bool - // Deprecated represents if the flag is deprecated + // Deprecated represents if the flag is deprecated. + // It shows a warning message when the flag is used. Deprecated string - // Removed represents if the flag is removed and no longer works + // Removed represents if the flag is removed and no longer works. + // It shows an error message when the flag is used. Removed string + // Internal represents if the flag is for internal use only. + // It is not shown in the usage message. + Internal bool + // Aliases represents aliases Aliases []Alias @@ -208,6 +215,10 @@ func (f *Flag[T]) GetAliases() []Alias { return f.Aliases } +func (f *Flag[T]) Hidden() bool { + return f.Deprecated != "" || f.Removed != "" || f.Internal +} + func (f *Flag[T]) Value() (t T) { if f == nil { return t @@ -249,7 +260,7 @@ func (f *Flag[T]) Add(cmd *cobra.Command) { flags.Float64P(f.Name, f.Shorthand, v, f.Usage) } - if f.Deprecated != "" || f.Removed != "" { + if f.Hidden() { _ = flags.MarkHidden(f.Name) } } @@ -313,6 +324,7 @@ type Flagger interface { GetConfigName() string GetDefaultValue() any GetAliases() []Alias + Hidden() bool Parse() error Add(cmd *cobra.Command) @@ -480,6 +492,16 @@ func (o *Options) RemoteCacheOpts() cache.RemoteOptions { ServerAddr: o.ServerAddr, CustomHeaders: o.CustomHeaders, Insecure: o.Insecure, + PathPrefix: o.PathPrefix, + } +} + +func (o *Options) ClientScannerOpts() client.ScannerOption { + return client.ScannerOption{ + RemoteURL: o.ServerAddr, + CustomHeaders: o.CustomHeaders, + Insecure: o.Insecure, + PathPrefix: o.PathPrefix, } } diff --git a/pkg/flag/remote_flags.go b/pkg/flag/remote_flags.go index 2348ef649e66..b09e89a48104 100644 --- a/pkg/flag/remote_flags.go +++ b/pkg/flag/remote_flags.go @@ -39,6 +39,12 @@ var ( Default: "localhost:4954", Usage: "listen address in server mode", } + ServerPathPrefixFlag = Flag[string]{ + Name: "path-prefix", + ConfigName: "server.path-prefix", + Usage: "prefix for the server endpoint", + Internal: true, // Internal use + } ) // RemoteFlagGroup composes common printer flag structs @@ -47,6 +53,7 @@ type RemoteFlagGroup struct { // for client/server Token *Flag[string] TokenHeader *Flag[string] + PathPrefix *Flag[string] // for client ServerAddr *Flag[string] @@ -63,12 +70,17 @@ type RemoteOptions struct { ServerAddr string Listen string CustomHeaders http.Header + + // Server endpoint: []/./ (default prefix: /twirp) + // e.g., http://localhost:4954/twirp/trivy.scanner.v1.Scanner/Scan + PathPrefix string } func NewClientFlags() *RemoteFlagGroup { return &RemoteFlagGroup{ Token: ServerTokenFlag.Clone(), TokenHeader: ServerTokenHeaderFlag.Clone(), + PathPrefix: ServerPathPrefixFlag.Clone(), ServerAddr: ServerAddrFlag.Clone(), CustomHeaders: ServerCustomHeadersFlag.Clone(), } @@ -76,9 +88,10 @@ func NewClientFlags() *RemoteFlagGroup { func NewServerFlags() *RemoteFlagGroup { return &RemoteFlagGroup{ - Token: &ServerTokenFlag, - TokenHeader: &ServerTokenHeaderFlag, - Listen: &ServerListenFlag, + Token: ServerTokenFlag.Clone(), + TokenHeader: ServerTokenHeaderFlag.Clone(), + PathPrefix: ServerPathPrefixFlag.Clone(), + Listen: ServerListenFlag.Clone(), } } @@ -90,6 +103,7 @@ func (f *RemoteFlagGroup) Flags() []Flagger { return []Flagger{ f.Token, f.TokenHeader, + f.PathPrefix, f.ServerAddr, f.CustomHeaders, f.Listen, @@ -129,6 +143,7 @@ func (f *RemoteFlagGroup) ToOptions() (RemoteOptions, error) { return RemoteOptions{ Token: token, TokenHeader: tokenHeader, + PathPrefix: f.PathPrefix.Value(), ServerAddr: serverAddr, CustomHeaders: customHeaders, Listen: listen, diff --git a/pkg/rpc/client/client.go b/pkg/rpc/client/client.go index 9e13db8ded48..ed7d130dcb06 100644 --- a/pkg/rpc/client/client.go +++ b/pkg/rpc/client/client.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "net/http" + "github.com/twitchtv/twirp" "golang.org/x/xerrors" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" @@ -32,6 +33,7 @@ type ScannerOption struct { RemoteURL string Insecure bool CustomHeaders http.Header + PathPrefix string } // Scanner implements the RPC scanner @@ -42,16 +44,15 @@ type Scanner struct { // NewScanner is the factory method to return RPC Scanner func NewScanner(scannerOptions ScannerOption, opts ...Option) Scanner { - httpClient := &http.Client{ - Transport: &http.Transport{ - Proxy: http.ProxyFromEnvironment, - TLSClientConfig: &tls.Config{ - InsecureSkipVerify: scannerOptions.Insecure, - }, - }, - } + tr := http.DefaultTransport.(*http.Transport).Clone() + tr.TLSClientConfig = &tls.Config{InsecureSkipVerify: scannerOptions.Insecure} + httpClient := &http.Client{Transport: tr} - c := rpc.NewScannerProtobufClient(scannerOptions.RemoteURL, httpClient) + var twirpOpts []twirp.ClientOption + if scannerOptions.PathPrefix != "" { + twirpOpts = append(twirpOpts, twirp.WithClientPathPrefix(scannerOptions.PathPrefix)) + } + c := rpc.NewScannerProtobufClient(scannerOptions.RemoteURL, httpClient, twirpOpts...) o := &options{rpcClient: c} for _, opt := range opts { diff --git a/pkg/rpc/server/listen.go b/pkg/rpc/server/listen.go index 0c4484930773..2b6d1288b7ff 100644 --- a/pkg/rpc/server/listen.go +++ b/pkg/rpc/server/listen.go @@ -5,6 +5,7 @@ import ( "encoding/json" "net/http" "os" + "strings" "sync" "time" @@ -30,9 +31,11 @@ const updateInterval = 1 * time.Hour type Server struct { appVersion string addr string + cacheDir string dbDir string token string tokenHeader string + pathPrefix string dbRepository name.Reference // For OCI registries @@ -40,13 +43,15 @@ type Server struct { } // NewServer returns an instance of Server -func NewServer(appVersion, addr, cacheDir, token, tokenHeader string, dbRepository name.Reference, opt types.RegistryOptions) Server { +func NewServer(appVersion, addr, cacheDir, token, tokenHeader, pathPrefix string, dbRepository name.Reference, opt types.RegistryOptions) Server { return Server{ appVersion: appVersion, addr: addr, + cacheDir: cacheDir, dbDir: db.Dir(cacheDir), token: token, tokenHeader: tokenHeader, + pathPrefix: pathPrefix, dbRepository: dbRepository, RegistryOptions: opt, } @@ -67,14 +72,13 @@ func (s Server) ListenAndServe(ctx context.Context, serverCache cache.Cache, ski } }() - mux := newServeMux(ctx, serverCache, dbUpdateWg, requestWg, s.token, s.tokenHeader, s.dbDir) + mux := s.newServeMux(ctx, serverCache, dbUpdateWg, requestWg) log.Infof("Listening %s...", s.addr) return http.ListenAndServe(s.addr, mux) } -func newServeMux(ctx context.Context, serverCache cache.Cache, dbUpdateWg, requestWg *sync.WaitGroup, - token, tokenHeader, cacheDir string) *http.ServeMux { +func (s Server) newServeMux(ctx context.Context, serverCache cache.Cache, dbUpdateWg, requestWg *sync.WaitGroup) *http.ServeMux { withWaitGroup := func(base http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Stop processing requests during DB update @@ -91,13 +95,19 @@ func newServeMux(ctx context.Context, serverCache cache.Cache, dbUpdateWg, reque mux := http.NewServeMux() - scanServer := rpcScanner.NewScannerServer(initializeScanServer(serverCache), nil) - scanHandler := withToken(withWaitGroup(scanServer), token, tokenHeader) - mux.Handle(rpcScanner.ScannerPathPrefix, gziphandler.GzipHandler(scanHandler)) + var twirpOpts []any + if s.pathPrefix != "" { + pathPrefix := "/" + strings.TrimPrefix(s.pathPrefix, "/") // Twirp requires the leading slash + twirpOpts = append(twirpOpts, twirp.WithServerPathPrefix(pathPrefix)) + } + + scanServer := rpcScanner.NewScannerServer(initializeScanServer(serverCache), twirpOpts...) + scanHandler := withToken(withWaitGroup(scanServer), s.token, s.tokenHeader) + mux.Handle(scanServer.PathPrefix(), gziphandler.GzipHandler(scanHandler)) - layerServer := rpcCache.NewCacheServer(NewCacheServer(serverCache), nil) - layerHandler := withToken(withWaitGroup(layerServer), token, tokenHeader) - mux.Handle(rpcCache.CachePathPrefix, gziphandler.GzipHandler(layerHandler)) + cacheServer := rpcCache.NewCacheServer(NewCacheServer(serverCache), twirpOpts...) + layerHandler := withToken(withWaitGroup(cacheServer), s.token, s.tokenHeader) + mux.Handle(cacheServer.PathPrefix(), gziphandler.GzipHandler(layerHandler)) mux.HandleFunc("/healthz", func(rw http.ResponseWriter, r *http.Request) { if _, err := rw.Write([]byte("ok")); err != nil { @@ -108,7 +118,7 @@ func newServeMux(ctx context.Context, serverCache cache.Cache, dbUpdateWg, reque mux.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) { w.Header().Add("Content-Type", "application/json") - if err := json.NewEncoder(w).Encode(version.NewVersionInfo(cacheDir)); err != nil { + if err := json.NewEncoder(w).Encode(version.NewVersionInfo(s.cacheDir)); err != nil { log.Error("Version error", log.Err(err)) } }) diff --git a/pkg/rpc/server/listen_test.go b/pkg/rpc/server/listen_test.go index 8457cef042d7..fa61e228806c 100644 --- a/pkg/rpc/server/listen_test.go +++ b/pkg/rpc/server/listen_test.go @@ -115,7 +115,7 @@ func Test_dbWorker_update(t *testing.T) { } } -func Test_newServeMux(t *testing.T) { +func TestServer_newServeMux(t *testing.T) { type args struct { token string tokenHeader string @@ -182,9 +182,8 @@ func Test_newServeMux(t *testing.T) { require.NoError(t, err) defer func() { _ = c.Close() }() - ts := httptest.NewServer(newServeMux(context.Background(), c, dbUpdateWg, requestWg, tt.args.token, - tt.args.tokenHeader, ""), - ) + s := NewServer("", "", "", tt.args.token, tt.args.tokenHeader, "", nil, ftypes.RegistryOptions{}) + ts := httptest.NewServer(s.newServeMux(context.Background(), c, dbUpdateWg, requestWg)) defer ts.Close() var resp *http.Response @@ -214,9 +213,8 @@ func Test_VersionEndpoint(t *testing.T) { require.NoError(t, err) defer func() { _ = c.Close() }() - ts := httptest.NewServer(newServeMux(context.Background(), c, dbUpdateWg, requestWg, "", "", - "testdata/testcache"), - ) + s := NewServer("", "", "testdata/testcache", "", "", "", nil, ftypes.RegistryOptions{}) + ts := httptest.NewServer(s.newServeMux(context.Background(), c, dbUpdateWg, requestWg)) defer ts.Close() resp, err := http.Get(ts.URL + "/version") From 6fe672732b46e0379fa14c2bbf4ba01881b8155a Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Thu, 22 Aug 2024 06:21:39 +0600 Subject: [PATCH 034/183] chore(deps): bump trivy-checks (#7350) Signed-off-by: nikpivkin --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1465ad2b2343..230470d8f12c 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/aquasecurity/table v1.8.0 github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8 github.com/aquasecurity/tml v0.6.1 - github.com/aquasecurity/trivy-checks v0.13.0 + github.com/aquasecurity/trivy-checks v0.13.1-0.20240809030752-558fcff75807 github.com/aquasecurity/trivy-db v0.0.0-20240718084044-d23a6ca8ba04 github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20240707095038-0300bc49b68b diff --git a/go.sum b/go.sum index 1a1e285e8de6..860b788ae605 100644 --- a/go.sum +++ b/go.sum @@ -348,8 +348,8 @@ github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8 h1:b43UVqY github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8/go.mod h1:wXA9k3uuaxY3yu7gxrxZDPo/04FEMJtwyecdAlYrEIo= github.com/aquasecurity/tml v0.6.1 h1:y2ZlGSfrhnn7t4ZJ/0rotuH+v5Jgv6BDDO5jB6A9gwo= github.com/aquasecurity/tml v0.6.1/go.mod h1:OnYMWY5lvI9ejU7yH9LCberWaaTBW7hBFsITiIMY2yY= -github.com/aquasecurity/trivy-checks v0.13.0 h1:na6PTdY4U0uK/fjz3HNRYBxvYSJ8vgTb57a5T8Y5t9w= -github.com/aquasecurity/trivy-checks v0.13.0/go.mod h1:Xec/SMVGV66I7RgUqOX9MEr+YxBqHXDVLTYmpspPi3E= +github.com/aquasecurity/trivy-checks v0.13.1-0.20240809030752-558fcff75807 h1:yw2INXrbfekt1yHDQAlNZlHIUZQXMcSS+mWI9XWJUN0= +github.com/aquasecurity/trivy-checks v0.13.1-0.20240809030752-558fcff75807/go.mod h1:Xec/SMVGV66I7RgUqOX9MEr+YxBqHXDVLTYmpspPi3E= github.com/aquasecurity/trivy-db v0.0.0-20240718084044-d23a6ca8ba04 h1:6/T8sFdNVG/AwOGoK6X55h7hF7LYqK8bsuPz8iEz8jM= github.com/aquasecurity/trivy-db v0.0.0-20240718084044-d23a6ca8ba04/go.mod h1:0T6oy2t1Iedt+yi3Ml5cpOYp5FZT4MI1/mx+3p+PIs8= github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 h1:JVgBIuIYbwG+ekC5lUHUpGJboPYiCcxiz06RCtz8neI= From bfdf5cfc305c6617e1030ea16b5632c9137c916e Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 23 Aug 2024 10:27:17 +0600 Subject: [PATCH 035/183] refactor(misconf): use slog (#7295) Signed-off-by: nikpivkin --- pkg/commands/artifact/run.go | 1 - pkg/iac/debug/debug.go | 38 ----- pkg/iac/rego/load.go | 39 +++-- pkg/iac/rego/load_test.go | 8 +- pkg/iac/rego/scanner.go | 34 +++-- pkg/iac/rego/scanner_test.go | 4 - pkg/iac/scanners/azure/arm/parser/parser.go | 46 +++--- .../scanners/azure/arm/parser/parser_test.go | 6 +- pkg/iac/scanners/azure/arm/scanner.go | 15 +- .../cloudformation/parser/file_context.go | 12 +- .../parser/file_context_test.go | 46 +++++- .../scanners/cloudformation/parser/parser.go | 55 ++++--- .../cloudformation/parser/resource.go | 2 +- pkg/iac/scanners/cloudformation/scanner.go | 27 ++-- .../cloudformation/test/cf_scanning_test.go | 17 --- pkg/iac/scanners/dockerfile/parser/parser.go | 21 +-- pkg/iac/scanners/dockerfile/scanner.go | 14 +- pkg/iac/scanners/dockerfile/scanner_test.go | 2 - pkg/iac/scanners/helm/options.go | 29 ++-- pkg/iac/scanners/helm/parser/option.go | 53 +++---- pkg/iac/scanners/helm/parser/parser.go | 37 +---- pkg/iac/scanners/helm/parser/parser_tar.go | 5 +- pkg/iac/scanners/helm/scanner.go | 22 ++- pkg/iac/scanners/helm/test/option_test.go | 9 +- pkg/iac/scanners/json/parser/parser.go | 22 +-- pkg/iac/scanners/json/scanner.go | 16 +-- pkg/iac/scanners/kubernetes/parser/parser.go | 21 +-- pkg/iac/scanners/kubernetes/scanner.go | 16 +-- pkg/iac/scanners/kubernetes/scanner_test.go | 2 - pkg/iac/scanners/options/parser.go | 16 --- pkg/iac/scanners/options/scanner.go | 8 -- .../scanners/terraform/executor/executor.go | 28 ++-- pkg/iac/scanners/terraform/executor/option.go | 9 -- pkg/iac/scanners/terraform/fs_test.go | 1 - pkg/iac/scanners/terraform/module_test.go | 13 +- pkg/iac/scanners/terraform/options.go | 2 +- .../scanners/terraform/parser/evaluator.go | 99 +++++++++---- .../scanners/terraform/parser/load_module.go | 24 +++- .../terraform/parser/module_retrieval.go | 6 +- pkg/iac/scanners/terraform/parser/option.go | 71 +++------- pkg/iac/scanners/terraform/parser/parser.go | 106 +++++++------- .../scanners/terraform/parser/parser_test.go | 41 +++++- .../terraform/parser/resolvers/cache.go | 10 +- .../terraform/parser/resolvers/local.go | 10 +- .../terraform/parser/resolvers/options.go | 8 +- .../terraform/parser/resolvers/registry.go | 18 ++- .../terraform/parser/resolvers/remote.go | 16 ++- pkg/iac/scanners/terraform/scanner.go | 44 +++--- .../terraform/scanner_integration_test.go | 16 --- pkg/iac/scanners/terraform/scanner_test.go | 134 +----------------- .../terraformplan/snapshot/scanner_test.go | 3 - .../terraformplan/tfjson/parser/option.go | 17 --- .../terraformplan/tfjson/parser/parser.go | 21 +-- .../scanners/terraformplan/tfjson/scanner.go | 20 +-- .../terraformplan/tfjson/scanner_test.go | 8 +- pkg/iac/scanners/toml/parser/parser.go | 22 +-- pkg/iac/scanners/toml/scanner.go | 16 +-- pkg/iac/scanners/yaml/parser/parser.go | 24 ++-- pkg/iac/scanners/yaml/scanner.go | 16 +-- pkg/log/logger.go | 16 --- pkg/misconf/scanner.go | 5 - 61 files changed, 566 insertions(+), 901 deletions(-) delete mode 100644 pkg/iac/debug/debug.go delete mode 100644 pkg/iac/scanners/options/parser.go delete mode 100644 pkg/iac/scanners/terraformplan/tfjson/parser/option.go diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index 59b3313d2f15..fa454c0cd276 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -640,7 +640,6 @@ func initMisconfScannerOption(opts flag.Options) (misconf.ScannerOption, error) } return misconf.ScannerOption{ - Debug: opts.Debug, Trace: opts.Trace, Namespaces: append(opts.CheckNamespaces, rego.BuiltinNamespaces()...), PolicyPaths: append(opts.CheckPaths, downloadedPolicyPaths...), diff --git a/pkg/iac/debug/debug.go b/pkg/iac/debug/debug.go deleted file mode 100644 index 489c777dd205..000000000000 --- a/pkg/iac/debug/debug.go +++ /dev/null @@ -1,38 +0,0 @@ -package debug - -import ( - "fmt" - "io" - "strings" - "time" -) - -const timeFormat = "04:05.000000000" - -type Logger struct { - writer io.Writer - prefix string -} - -func New(w io.Writer, parts ...string) Logger { - return Logger{ - writer: w, - prefix: strings.Join(parts, "."), - } -} - -func (l *Logger) Extend(parts ...string) Logger { - return Logger{ - writer: l.writer, - prefix: strings.Join(append([]string{l.prefix}, parts...), "."), - } -} - -func (l *Logger) Log(format string, args ...any) { - if l.writer == nil { - return - } - message := fmt.Sprintf(format, args...) - line := fmt.Sprintf("%s %-32s %s\n", time.Now().Format(timeFormat), l.prefix, message) - _, _ = l.writer.Write([]byte(line)) -} diff --git a/pkg/iac/rego/load.go b/pkg/iac/rego/load.go index bd474a23be4d..249e55992c2c 100644 --- a/pkg/iac/rego/load.go +++ b/pkg/iac/rego/load.go @@ -10,6 +10,8 @@ import ( "github.com/open-policy-agent/opa/ast" "github.com/open-policy-agent/opa/bundle" "github.com/samber/lo" + + "github.com/aquasecurity/trivy/pkg/log" ) var builtinNamespaces = map[string]struct{}{ @@ -61,14 +63,14 @@ func (s *Scanner) loadEmbedded() error { return fmt.Errorf("failed to load embedded rego libraries: %w", err) } s.embeddedLibs = loaded - s.debug.Log("Loaded %d embedded libraries.", len(loaded)) + s.logger.Debug("Embedded libraries are loaded", log.Int("count", len(loaded))) loaded, err = LoadEmbeddedPolicies() if err != nil { - return fmt.Errorf("failed to load embedded rego policies: %w", err) + return fmt.Errorf("failed to load embedded rego checks: %w", err) } s.embeddedChecks = loaded - s.debug.Log("Loaded %d embedded policies.", len(loaded)) + s.logger.Debug("Embedded checks are loaded", log.Int("count", len(loaded))) return nil } @@ -80,7 +82,7 @@ func (s *Scanner) LoadPolicies(enableEmbeddedLibraries, enableEmbeddedPolicies b } if s.policyFS != nil { - s.debug.Log("Overriding filesystem for checks!") + s.logger.Debug("Overriding filesystem for checks") srcFS = s.policyFS } @@ -105,7 +107,7 @@ func (s *Scanner) LoadPolicies(enableEmbeddedLibraries, enableEmbeddedPolicies b for name, policy := range loaded { s.policies[name] = policy } - s.debug.Log("Loaded %d checks from disk.", len(loaded)) + s.logger.Debug("Checks from disk are loaded", log.Int("count", len(loaded))) } if len(readers) > 0 { @@ -116,7 +118,7 @@ func (s *Scanner) LoadPolicies(enableEmbeddedLibraries, enableEmbeddedPolicies b for name, policy := range loaded { s.policies[name] = policy } - s.debug.Log("Loaded %d checks from reader(s).", len(loaded)) + s.logger.Debug("Checks from readers are loaded", log.Int("count", len(loaded))) } // gather namespaces @@ -132,7 +134,7 @@ func (s *Scanner) LoadPolicies(enableEmbeddedLibraries, enableEmbeddedPolicies b dataFS := srcFS if s.dataFS != nil { - s.debug.Log("Overriding filesystem for data!") + s.logger.Debug("Overriding filesystem for data") dataFS = s.dataFS } store, err := initStore(dataFS, s.dataDirs, namespaces) @@ -168,15 +170,19 @@ func (s *Scanner) fallbackChecks(compiler *ast.Compiler) { continue } - s.debug.Log("Error occurred while parsing: %s, %s. Trying to fallback to embedded check.", loc, e.Error()) + s.logger.Error( + "Error occurred while parsing. Trying to fallback to embedded check", + log.FilePath(loc), + log.Err(e), + ) embedded := s.findMatchedEmbeddedCheck(badPolicy) if embedded == nil { - s.debug.Log("Failed to find embedded check: %s", loc) + s.logger.Error("Failed to find embedded check, skipping", log.FilePath(loc)) continue } - s.debug.Log("Found embedded check: %s", embedded.Package.Location.File) + s.logger.Debug("Found embedded check", log.FilePath(embedded.Package.Location.File)) delete(s.policies, loc) // remove bad check s.policies[embedded.Package.Location.File] = embedded delete(s.embeddedChecks, embedded.Package.Location.File) // avoid infinite loop if embedded check contains ref error @@ -214,7 +220,7 @@ func (s *Scanner) findMatchedEmbeddedCheck(badPolicy *ast.Module) *ast.Module { func (s *Scanner) prunePoliciesWithError(compiler *ast.Compiler) error { if len(compiler.Errors) > s.regoErrorLimit { - s.debug.Log("Error(s) occurred while loading checks") + s.logger.Error("Error(s) occurred while loading checks") return compiler.Errors } @@ -222,7 +228,10 @@ func (s *Scanner) prunePoliciesWithError(compiler *ast.Compiler) error { if e.Location == nil { continue } - s.debug.Log("Error occurred while parsing: %s, %s", e.Location.File, e.Error()) + s.logger.Error( + "Error occurred while parsing", + log.FilePath(e.Location.File), log.Err(e), + ) delete(s.policies, e.Location.File) } return nil @@ -282,7 +291,11 @@ func (s *Scanner) filterModules(retriever *MetadataRetriever) error { return err } if len(meta.InputOptions.Selectors) == 0 { - s.debug.Log("WARNING: Module %s has no input selectors - it will be loaded for all inputs!", name) + s.logger.Warn( + "Module has no input selectors - it will be loaded for all inputs!", + log.FilePath(module.Package.Location.File), + log.String("module", name), + ) filtered[name] = module continue } diff --git a/pkg/iac/rego/load_test.go b/pkg/iac/rego/load_test.go index ede06e4610ed..e0c136562d45 100644 --- a/pkg/iac/rego/load_test.go +++ b/pkg/iac/rego/load_test.go @@ -5,6 +5,7 @@ import ( "embed" "fmt" "io" + "log/slog" "strings" "testing" "testing/fstest" @@ -17,6 +18,7 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" ) //go:embed all:testdata/policies @@ -28,10 +30,10 @@ var embeddedChecksFS embed.FS func Test_RegoScanning_WithSomeInvalidPolicies(t *testing.T) { t.Run("allow no errors", func(t *testing.T) { var debugBuf bytes.Buffer + slog.SetDefault(log.New(log.NewHandler(&debugBuf, nil))) scanner := rego.NewScanner( types.SourceDockerfile, options.ScannerWithRegoErrorLimits(0), - options.ScannerWithDebug(&debugBuf), ) err := scanner.LoadPolicies(false, false, testEmbedFS, []string{"."}, nil) @@ -41,16 +43,16 @@ func Test_RegoScanning_WithSomeInvalidPolicies(t *testing.T) { t.Run("allow up to max 1 error", func(t *testing.T) { var debugBuf bytes.Buffer + slog.SetDefault(log.New(log.NewHandler(&debugBuf, nil))) scanner := rego.NewScanner( types.SourceDockerfile, options.ScannerWithRegoErrorLimits(1), - options.ScannerWithDebug(&debugBuf), ) err := scanner.LoadPolicies(false, false, testEmbedFS, []string{"."}, nil) require.NoError(t, err) - assert.Contains(t, debugBuf.String(), "Error occurred while parsing: testdata/policies/invalid.rego, testdata/policies/invalid.rego:7") + assert.Contains(t, debugBuf.String(), "Error occurred while parsing\tfile_path=\"testdata/policies/invalid.rego\" err=\"testdata/policies/invalid.rego:7") }) t.Run("schema does not exist", func(t *testing.T) { diff --git a/pkg/iac/rego/scanner.go b/pkg/iac/rego/scanner.go index fe0553d6bc00..23a1e04bc2b8 100644 --- a/pkg/iac/rego/scanner.go +++ b/pkg/iac/rego/scanner.go @@ -15,13 +15,13 @@ import ( "github.com/open-policy-agent/opa/storage" "github.com/open-policy-agent/opa/util" - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/framework" "github.com/aquasecurity/trivy/pkg/iac/providers" "github.com/aquasecurity/trivy/pkg/iac/rego/schemas" "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" ) var checkTypesWithSubtype = map[types.Source]struct{}{ @@ -51,7 +51,7 @@ type Scanner struct { runtimeValues *ast.Term compiler *ast.Compiler regoErrorLimit int - debug debug.Logger + logger *log.Logger traceWriter io.Writer tracePerResult bool retriever *MetadataRetriever @@ -113,10 +113,6 @@ func (s *Scanner) SetPolicyReaders(_ []io.Reader) { // NOTE: Policy readers option not applicable for rego, policies are loaded on-demand by other scanners. } -func (s *Scanner) SetDebugWriter(writer io.Writer) { - s.debug = debug.New(writer, "rego", "scanner") -} - func (s *Scanner) SetTraceWriter(writer io.Writer) { s.traceWriter = writer } @@ -166,6 +162,7 @@ func NewScanner(source types.Source, opts ...options.ScannerOption) *Scanner { sourceType: source, ruleNamespaces: make(map[string]struct{}), runtimeValues: addRuntimeValues(), + logger: log.WithPrefix("rego"), customSchemas: make(map[string][]byte), } @@ -183,10 +180,6 @@ func NewScanner(source types.Source, opts ...options.ScannerOption) *Scanner { return s } -func (s *Scanner) SetParentDebugLogger(l debug.Logger) { - s.debug = l.Extend("rego") -} - func (s *Scanner) runQuery(ctx context.Context, query string, input ast.Value, disableTracing bool) (rego.ResultSet, []string, error) { trace := (s.traceWriter != nil || s.tracePerResult) && !disableTracing @@ -247,7 +240,7 @@ func GetInputsContents(inputs []Input) []any { func (s *Scanner) ScanInput(ctx context.Context, inputs ...Input) (scan.Results, error) { - s.debug.Log("Scanning %d inputs...", len(inputs)) + s.logger.Debug("Scannning inputs", "count", len(inputs)) var results scan.Results @@ -267,9 +260,11 @@ func (s *Scanner) ScanInput(ctx context.Context, inputs ...Input) (scan.Results, staticMeta, err := s.retriever.RetrieveMetadata(ctx, module, GetInputsContents(inputs)...) if err != nil { - s.debug.Log( - "Error occurred while retrieving metadata from check %q: %s", - module.Package.Location.File, err) + s.logger.Error( + "Error occurred while retrieving metadata from check", + log.FilePath(module.Package.Location.File), + log.Err(err), + ) continue } @@ -300,9 +295,12 @@ func (s *Scanner) ScanInput(ctx context.Context, inputs ...Input) (scan.Results, if isEnforcedRule(ruleName) { ruleResults, err := s.applyRule(ctx, namespace, ruleName, inputs, staticMeta.InputOptions.Combined) if err != nil { - s.debug.Log( - "Error occurred while applying rule %q from check %q: %s", - ruleName, module.Package.Location.File, err) + s.logger.Error( + "Error occurred while applying rule from check", + log.String("rule", ruleName), + log.FilePath(module.Package.Location.File), + log.Err(err), + ) continue } results = append(results, s.embellishResultsWithRuleMetadata(ruleResults, *staticMeta)...) @@ -390,7 +388,7 @@ func (s *Scanner) applyRule(ctx context.Context, namespace, rule string, inputs s.trace("INPUT", input) parsedInput, err := parseRawInput(input.Contents) if err != nil { - s.debug.Log("Error occurred while parsing input: %s", err) + s.logger.Error("Error occurred while parsing input", log.Err(err)) continue } if ignored, err := s.isIgnored(ctx, namespace, rule, parsedInput); err != nil { diff --git a/pkg/iac/rego/scanner_test.go b/pkg/iac/rego/scanner_test.go index de2b7427ae8a..c453cc984b1c 100644 --- a/pkg/iac/rego/scanner_test.go +++ b/pkg/iac/rego/scanner_test.go @@ -998,10 +998,8 @@ deny { }, } - var buf bytes.Buffer scanner := NewScanner( types.SourceYAML, - options.ScannerWithDebug(&buf), ) require.NoError( t, @@ -1009,8 +1007,6 @@ deny { ) _, err := scanner.ScanInput(context.TODO(), Input{}) require.NoError(t, err) - assert.Contains(t, buf.String(), - `Error occurred while applying rule "deny" from check "checks/bad.rego"`) } func Test_RegoScanning_WithDeprecatedCheck(t *testing.T) { diff --git a/pkg/iac/scanners/azure/arm/parser/parser.go b/pkg/iac/scanners/azure/arm/parser/parser.go index 9fbf7b7019a8..53f9eb21431b 100644 --- a/pkg/iac/scanners/azure/arm/parser/parser.go +++ b/pkg/iac/scanners/azure/arm/parser/parser.go @@ -6,36 +6,28 @@ import ( "io" "io/fs" - "github.com/aquasecurity/trivy/pkg/iac/debug" - azure2 "github.com/aquasecurity/trivy/pkg/iac/scanners/azure" + "github.com/aquasecurity/trivy/pkg/iac/scanners/azure" "github.com/aquasecurity/trivy/pkg/iac/scanners/azure/arm/parser/armjson" "github.com/aquasecurity/trivy/pkg/iac/scanners/azure/resolver" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" ) type Parser struct { targetFS fs.FS - debug debug.Logger + logger *log.Logger } -func (p *Parser) SetDebugWriter(writer io.Writer) { - p.debug = debug.New(writer, "azure", "arm") -} - -func New(targetFS fs.FS, opts ...options.ParserOption) *Parser { - p := &Parser{ +func New(targetFS fs.FS) *Parser { + return &Parser{ targetFS: targetFS, + logger: log.WithPrefix("arm parser"), } - for _, opt := range opts { - opt(p) - } - return p } -func (p *Parser) ParseFS(ctx context.Context, dir string) ([]azure2.Deployment, error) { +func (p *Parser) ParseFS(ctx context.Context, dir string) ([]azure.Deployment, error) { - var deployments []azure2.Deployment + var deployments []azure.Deployment if err := fs.WalkDir(p.targetFS, dir, func(path string, entry fs.DirEntry, err error) error { if err != nil { @@ -69,7 +61,7 @@ func (p *Parser) ParseFS(ctx context.Context, dir string) ([]azure2.Deployment, return deployments, nil } -func (p *Parser) parseFile(r io.Reader, filename string) (*azure2.Deployment, error) { +func (p *Parser) parseFile(r io.Reader, filename string) (*azure.Deployment, error) { var template Template data, err := io.ReadAll(r) if err != nil { @@ -86,11 +78,11 @@ func (p *Parser) parseFile(r io.Reader, filename string) (*azure2.Deployment, er return p.convertTemplate(template), nil } -func (p *Parser) convertTemplate(template Template) *azure2.Deployment { +func (p *Parser) convertTemplate(template Template) *azure.Deployment { - deployment := azure2.Deployment{ + deployment := azure.Deployment{ Metadata: template.Metadata, - TargetScope: azure2.ScopeResourceGroup, // TODO: override from --resource-group? + TargetScope: azure.ScopeResourceGroup, // TODO: override from --resource-group? Parameters: nil, Variables: nil, Resources: nil, @@ -103,8 +95,8 @@ func (p *Parser) convertTemplate(template Template) *azure2.Deployment { // TODO: the references passed here should probably not be the name - maybe params.NAME.DefaultValue? for name, param := range template.Parameters { - deployment.Parameters = append(deployment.Parameters, azure2.Parameter{ - Variable: azure2.Variable{ + deployment.Parameters = append(deployment.Parameters, azure.Parameter{ + Variable: azure.Variable{ Name: name, Value: param.DefaultValue, }, @@ -114,14 +106,14 @@ func (p *Parser) convertTemplate(template Template) *azure2.Deployment { } for name, variable := range template.Variables { - deployment.Variables = append(deployment.Variables, azure2.Variable{ + deployment.Variables = append(deployment.Variables, azure.Variable{ Name: name, Value: variable, }) } for name, output := range template.Outputs { - deployment.Outputs = append(deployment.Outputs, azure2.Output{ + deployment.Outputs = append(deployment.Outputs, azure.Output{ Name: name, Value: output, }) @@ -134,15 +126,15 @@ func (p *Parser) convertTemplate(template Template) *azure2.Deployment { return &deployment } -func (p *Parser) convertResource(input Resource) azure2.Resource { +func (p *Parser) convertResource(input Resource) azure.Resource { - var children []azure2.Resource + var children []azure.Resource for _, child := range input.Resources { children = append(children, p.convertResource(child)) } - resource := azure2.Resource{ + resource := azure.Resource{ Metadata: input.Metadata, APIVersion: input.APIVersion, Type: input.Type, diff --git a/pkg/iac/scanners/azure/arm/parser/parser_test.go b/pkg/iac/scanners/azure/arm/parser/parser_test.go index b16213d9bebd..ff1444a60655 100644 --- a/pkg/iac/scanners/azure/arm/parser/parser_test.go +++ b/pkg/iac/scanners/azure/arm/parser/parser_test.go @@ -3,7 +3,6 @@ package parser import ( "context" "io/fs" - "os" "testing" "github.com/liamg/memoryfs" @@ -12,7 +11,6 @@ import ( azure2 "github.com/aquasecurity/trivy/pkg/iac/scanners/azure" "github.com/aquasecurity/trivy/pkg/iac/scanners/azure/resolver" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/types" ) @@ -205,7 +203,7 @@ func TestParser_Parse(t *testing.T) { require.NoError(t, targetFS.WriteFile(filename, []byte(tt.input), 0644)) - p := New(targetFS, options.ParserWithDebug(os.Stderr)) + p := New(targetFS) got, err := p.ParseFS(context.Background(), ".") require.NoError(t, err) @@ -293,7 +291,7 @@ func Test_NestedResourceParsing(t *testing.T) { require.NoError(t, targetFS.WriteFile("nested.json", []byte(input), 0644)) - p := New(targetFS, options.ParserWithDebug(os.Stderr)) + p := New(targetFS) got, err := p.ParseFS(context.Background(), ".") require.NoError(t, err) require.Len(t, got, 1) diff --git a/pkg/iac/scanners/azure/arm/scanner.go b/pkg/iac/scanners/azure/arm/scanner.go index fd585a5955c5..66bab2b4f806 100644 --- a/pkg/iac/scanners/azure/arm/scanner.go +++ b/pkg/iac/scanners/azure/arm/scanner.go @@ -8,7 +8,6 @@ import ( "sync" "github.com/aquasecurity/trivy/pkg/iac/adapters/arm" - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/framework" "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/rules" @@ -19,6 +18,7 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/state" "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" ) var _ scanners.FSScanner = (*Scanner)(nil) @@ -27,8 +27,7 @@ var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { mu sync.Mutex scannerOptions []options.ScannerOption - parserOptions []options.ParserOption - debug debug.Logger + logger *log.Logger frameworks []framework.Framework regoOnly bool loadEmbeddedPolicies bool @@ -53,6 +52,7 @@ func (s *Scanner) SetRegoOnly(regoOnly bool) { func New(opts ...options.ScannerOption) *Scanner { scanner := &Scanner{ scannerOptions: opts, + logger: log.WithPrefix("azure-arm"), } for _, opt := range opts { opt(scanner) @@ -64,11 +64,6 @@ func (s *Scanner) Name() string { return "Azure ARM" } -func (s *Scanner) SetDebugWriter(writer io.Writer) { - s.debug = debug.New(writer, "azure", "arm") - s.parserOptions = append(s.parserOptions, options.ParserWithDebug(writer)) -} - func (s *Scanner) SetPolicyDirs(dirs ...string) { s.policyDirs = dirs } @@ -109,7 +104,6 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) error { return nil } regoScanner := rego.NewScanner(types.SourceCloud, s.scannerOptions...) - regoScanner.SetParentDebugLogger(s.debug) if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { return err } @@ -118,7 +112,7 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) error { } func (s *Scanner) ScanFS(ctx context.Context, fsys fs.FS, dir string) (scan.Results, error) { - p := parser.New(fsys, s.parserOptions...) + p := parser.New(fsys) deployments, err := p.ParseFS(ctx, dir) if err != nil { return nil, err @@ -160,7 +154,6 @@ func (s *Scanner) scanDeployment(ctx context.Context, deployment azure.Deploymen continue } ruleResults := rule.Evaluate(deploymentState) - s.debug.Log("Found %d results for %s", len(ruleResults), rule.GetRule().AVDID) if len(ruleResults) > 0 { results = append(results, ruleResults...) } diff --git a/pkg/iac/scanners/cloudformation/parser/file_context.go b/pkg/iac/scanners/cloudformation/parser/file_context.go index 78a267cabb04..949add1ca7c4 100644 --- a/pkg/iac/scanners/cloudformation/parser/file_context.go +++ b/pkg/iac/scanners/cloudformation/parser/file_context.go @@ -54,10 +54,20 @@ func (t *FileContext) Metadata() iacTypes.Metadata { return iacTypes.NewMetadata(rng, NewCFReference("Template", rng).String()) } -func (t *FileContext) OverrideParameters(params map[string]any) { +func (t *FileContext) overrideParameters(params map[string]any) { for key := range t.Parameters { if val, ok := params[key]; ok { t.Parameters[key].UpdateDefault(val) } } } + +func (t *FileContext) missingParameterValues() []string { + var missing []string + for key := range t.Parameters { + if t.Parameters[key].inner.Default == nil { + missing = append(missing, key) + } + } + return missing +} diff --git a/pkg/iac/scanners/cloudformation/parser/file_context_test.go b/pkg/iac/scanners/cloudformation/parser/file_context_test.go index bbf5db4ddc39..80bdfa72eb05 100644 --- a/pkg/iac/scanners/cloudformation/parser/file_context_test.go +++ b/pkg/iac/scanners/cloudformation/parser/file_context_test.go @@ -1,6 +1,7 @@ package parser import ( + "slices" "testing" "github.com/stretchr/testify/assert" @@ -54,8 +55,51 @@ func TestFileContext_OverrideParameters(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - tt.ctx.OverrideParameters(tt.arg) + tt.ctx.overrideParameters(tt.arg) assert.Equal(t, tt.expected, tt.ctx.Parameters) }) } } + +func TestFileContext_MissingParameterValues(t *testing.T) { + + tests := []struct { + name string + ctx FileContext + expected []string + }{ + { + name: "happy", + ctx: FileContext{ + Parameters: map[string]*Parameter{ + "BucketName": { + inner: parameterInner{ + Type: "String", + Default: "test", + }, + }, + "QueueName": { + inner: parameterInner{ + Type: "String", + }, + }, + "KMSKey": { + inner: parameterInner{ + Type: "String", + Default: nil, + }, + }, + }, + }, + expected: []string{"KMSKey", "QueueName"}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := tt.ctx.missingParameterValues() + slices.Sort(got) + assert.Equal(t, tt.expected, got) + }) + } +} diff --git a/pkg/iac/scanners/cloudformation/parser/parser.go b/pkg/iac/scanners/cloudformation/parser/parser.go index d281b585035e..40d0035f6cd2 100644 --- a/pkg/iac/scanners/cloudformation/parser/parser.go +++ b/pkg/iac/scanners/cloudformation/parser/parser.go @@ -13,51 +13,42 @@ import ( "github.com/liamg/jfather" "gopkg.in/yaml.v3" - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/ignore" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" + "github.com/aquasecurity/trivy/pkg/log" ) -var _ options.ConfigurableParser = (*Parser)(nil) - type Parser struct { - debug debug.Logger + logger *log.Logger parameterFiles []string parameters map[string]any overridedParameters Parameters configsFS fs.FS } -func WithParameters(params map[string]any) options.ParserOption { - return func(cp options.ConfigurableParser) { - if p, ok := cp.(*Parser); ok { - p.parameters = params - } - } -} +type Option func(*Parser) -func WithParameterFiles(files ...string) options.ParserOption { - return func(cp options.ConfigurableParser) { - if p, ok := cp.(*Parser); ok { - p.parameterFiles = files - } +func WithParameters(params map[string]any) Option { + return func(p *Parser) { + p.parameters = params } } -func WithConfigsFS(fsys fs.FS) options.ParserOption { - return func(cp options.ConfigurableParser) { - if p, ok := cp.(*Parser); ok { - p.configsFS = fsys - } +func WithParameterFiles(files ...string) Option { + return func(p *Parser) { + p.parameterFiles = files } } -func (p *Parser) SetDebugWriter(writer io.Writer) { - p.debug = debug.New(writer, "cloudformation", "parser") +func WithConfigsFS(fsys fs.FS) Option { + return func(p *Parser) { + p.configsFS = fsys + } } -func New(opts ...options.ParserOption) *Parser { - p := &Parser{} +func New(opts ...Option) *Parser { + p := &Parser{ + logger: log.WithPrefix("cloudformation parser"), + } for _, option := range opts { option(p) } @@ -81,7 +72,7 @@ func (p *Parser) ParseFS(ctx context.Context, fsys fs.FS, dir string) (FileConte c, err := p.ParseFile(ctx, fsys, path) if err != nil { - p.debug.Log("Error parsing file '%s': %s", path, err) + p.logger.Error("Error parsing file", log.FilePath(path), log.Err(err)) return nil } contexts = append(contexts, c) @@ -149,13 +140,17 @@ func (p *Parser) ParseFile(ctx context.Context, fsys fs.FS, path string) (fctx * } } - fctx.OverrideParameters(p.overridedParameters) + fctx.overrideParameters(p.overridedParameters) + + if params := fctx.missingParameterValues(); len(params) > 0 { + p.logger.Warn("Missing parameter values", log.FilePath(path), log.String("parameters", strings.Join(params, ", "))) + } fctx.lines = lines fctx.SourceFormat = sourceFmt fctx.filepath = path - p.debug.Log("Context loaded from source %s", path) + p.logger.Debug("Context loaded from source", log.FilePath(path)) // the context must be set to conditions before resources for _, c := range fctx.Conditions { @@ -163,7 +158,7 @@ func (p *Parser) ParseFile(ctx context.Context, fsys fs.FS, path string) (fctx * } for name, r := range fctx.Resources { - r.ConfigureResource(name, fsys, path, fctx) + r.configureResource(name, fsys, path, fctx) } return fctx, nil diff --git a/pkg/iac/scanners/cloudformation/parser/resource.go b/pkg/iac/scanners/cloudformation/parser/resource.go index bd1351f234df..ed4b2834d573 100644 --- a/pkg/iac/scanners/cloudformation/parser/resource.go +++ b/pkg/iac/scanners/cloudformation/parser/resource.go @@ -23,7 +23,7 @@ type ResourceInner struct { Properties map[string]*Property `json:"Properties" yaml:"Properties"` } -func (r *Resource) ConfigureResource(id string, target fs.FS, filepath string, ctx *FileContext) { +func (r *Resource) configureResource(id string, target fs.FS, filepath string, ctx *FileContext) { r.setId(id) r.setFile(target, filepath) r.setContext(ctx) diff --git a/pkg/iac/scanners/cloudformation/scanner.go b/pkg/iac/scanners/cloudformation/scanner.go index cedd18ea6297..6db08c0d15bb 100644 --- a/pkg/iac/scanners/cloudformation/scanner.go +++ b/pkg/iac/scanners/cloudformation/scanner.go @@ -9,7 +9,6 @@ import ( "sync" adapter "github.com/aquasecurity/trivy/pkg/iac/adapters/cloudformation" - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/framework" "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/rules" @@ -18,12 +17,13 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation/parser" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" ) func WithParameters(params map[string]any) options.ScannerOption { return func(cs options.ConfigurableScanner) { if s, ok := cs.(*Scanner); ok { - s.addParserOptions(parser.WithParameters(params)) + s.addParserOption(parser.WithParameters(params)) } } } @@ -31,7 +31,7 @@ func WithParameters(params map[string]any) options.ScannerOption { func WithParameterFiles(files ...string) options.ScannerOption { return func(cs options.ConfigurableScanner) { if s, ok := cs.(*Scanner); ok { - s.addParserOptions(parser.WithParameterFiles(files...)) + s.addParserOption(parser.WithParameterFiles(files...)) } } } @@ -39,7 +39,7 @@ func WithParameterFiles(files ...string) options.ScannerOption { func WithConfigsFS(fsys fs.FS) options.ScannerOption { return func(cs options.ConfigurableScanner) { if s, ok := cs.(*Scanner); ok { - s.addParserOptions(parser.WithConfigsFS(fsys)) + s.addParserOption(parser.WithConfigsFS(fsys)) } } } @@ -49,7 +49,7 @@ var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { mu sync.Mutex - debug debug.Logger + logger *log.Logger policyDirs []string policyReaders []io.Reader parser *parser.Parser @@ -58,7 +58,7 @@ type Scanner struct { loadEmbeddedPolicies bool loadEmbeddedLibraries bool options []options.ScannerOption - parserOptions []options.ParserOption + parserOptions []parser.Option frameworks []framework.Framework spec string } @@ -66,7 +66,7 @@ type Scanner struct { func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} func (s *Scanner) SetCustomSchemas(map[string][]byte) {} -func (s *Scanner) addParserOptions(opt options.ParserOption) { +func (s *Scanner) addParserOption(opt parser.Option) { s.parserOptions = append(s.parserOptions, opt) } @@ -98,11 +98,6 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } -func (s *Scanner) SetDebugWriter(writer io.Writer) { - s.debug = debug.New(writer, "cloudformation", "scanner") - s.parserOptions = append(s.parserOptions, options.ParserWithDebug(writer)) -} - func (s *Scanner) SetPolicyDirs(dirs ...string) { s.policyDirs = dirs } @@ -125,6 +120,7 @@ func (s *Scanner) SetPolicyNamespaces(_ ...string) {} func New(opts ...options.ScannerOption) *Scanner { s := &Scanner{ options: opts, + logger: log.WithPrefix("cloudformation scanner"), } for _, opt := range opts { opt(s) @@ -140,7 +136,6 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { return s.regoScanner, nil } regoScanner := rego.NewScanner(types.SourceCloud, s.options...) - regoScanner.SetParentDebugLogger(s.debug) if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { return nil, err } @@ -221,7 +216,6 @@ func (s *Scanner) scanFileContext(ctx context.Context, regoScanner *rego.Scanner } evalResult := rule.Evaluate(state) if len(evalResult) > 0 { - s.debug.Log("Found %d results for %s", len(evalResult), rule.GetRule().AVDID) for _, scanResult := range evalResult { ref := scanResult.Metadata().Reference() @@ -250,7 +244,10 @@ func (s *Scanner) scanFileContext(ctx context.Context, regoScanner *rego.Scanner results.Ignore(cfCtx.Ignores, nil) for _, ignored := range results.GetIgnored() { - s.debug.Log("Ignored '%s' at '%s'.", ignored.Rule().LongID(), ignored.Range()) + s.logger.Info("Ignore finding", + log.String("rule", ignored.Rule().LongID()), + log.String("range", ignored.Range().String()), + ) } return results, nil diff --git a/pkg/iac/scanners/cloudformation/test/cf_scanning_test.go b/pkg/iac/scanners/cloudformation/test/cf_scanning_test.go index 4ab3009d4dab..396963447ca9 100644 --- a/pkg/iac/scanners/cloudformation/test/cf_scanning_test.go +++ b/pkg/iac/scanners/cloudformation/test/cf_scanning_test.go @@ -1,7 +1,6 @@ package test import ( - "bytes" "context" "os" "testing" @@ -30,19 +29,3 @@ func Test_cloudformation_scanning_has_expected_errors(t *testing.T) { assert.NotEmpty(t, results.GetFailed()) } - -func Test_cloudformation_scanning_with_debug(t *testing.T) { - - debugWriter := bytes.NewBufferString("") - - scannerOptions := []options.ScannerOption{ - options.ScannerWithDebug(debugWriter), - } - cfScanner := cloudformation.New(scannerOptions...) - - _, err := cfScanner.ScanFS(context.TODO(), os.DirFS("./examples/bucket"), ".") - require.NoError(t, err) - - // check debug is as expected - assert.NotEmpty(t, debugWriter.String()) -} diff --git a/pkg/iac/scanners/dockerfile/parser/parser.go b/pkg/iac/scanners/dockerfile/parser/parser.go index 4255b4609b46..e92116ae3079 100644 --- a/pkg/iac/scanners/dockerfile/parser/parser.go +++ b/pkg/iac/scanners/dockerfile/parser/parser.go @@ -11,28 +11,19 @@ import ( "github.com/moby/buildkit/frontend/dockerfile/instructions" "github.com/moby/buildkit/frontend/dockerfile/parser" - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/providers/dockerfile" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" + "github.com/aquasecurity/trivy/pkg/log" ) -var _ options.ConfigurableParser = (*Parser)(nil) - type Parser struct { - debug debug.Logger -} - -func (p *Parser) SetDebugWriter(writer io.Writer) { - p.debug = debug.New(writer, "dockerfile", "parser") + logger *log.Logger } // New creates a new Dockerfile parser -func New(opts ...options.ParserOption) *Parser { - p := &Parser{} - for _, option := range opts { - option(p) +func New() *Parser { + return &Parser{ + logger: log.WithPrefix("dockerfile parser"), } - return p } func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[string]*dockerfile.Dockerfile, error) { @@ -53,7 +44,7 @@ func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[st df, err := p.ParseFile(ctx, target, path) if err != nil { - // TODO add debug for parse errors + p.logger.Error("Failed to parse Dockerfile", log.FilePath(path), log.Err(err)) return nil } files[path] = df diff --git a/pkg/iac/scanners/dockerfile/scanner.go b/pkg/iac/scanners/dockerfile/scanner.go index 6358aada12c2..e0d6ebd9ebde 100644 --- a/pkg/iac/scanners/dockerfile/scanner.go +++ b/pkg/iac/scanners/dockerfile/scanner.go @@ -6,7 +6,6 @@ import ( "io/fs" "sync" - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/framework" "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scan" @@ -14,6 +13,7 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/scanners/dockerfile/parser" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" ) var _ scanners.FSScanner = (*Scanner)(nil) @@ -21,13 +21,12 @@ var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { mu sync.Mutex - debug debug.Logger + logger *log.Logger policyDirs []string policyReaders []io.Reader parser *parser.Parser regoScanner *rego.Scanner options []options.ScannerOption - parserOpts []options.ParserOption frameworks []framework.Framework spec string loadEmbeddedLibraries bool @@ -64,11 +63,6 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } -func (s *Scanner) SetDebugWriter(writer io.Writer) { - s.debug = debug.New(writer, "dockerfile", "scanner") - s.parserOpts = append(s.parserOpts, options.ParserWithDebug(writer)) -} - func (s *Scanner) SetTraceWriter(_ io.Writer) { // handled by rego later - nothing to do for now... } @@ -104,6 +98,7 @@ func (s *Scanner) SetRegoErrorLimit(_ int) { func NewScanner(opts ...options.ScannerOption) *Scanner { s := &Scanner{ options: opts, + logger: log.WithPrefix("dockerfile scanner"), } for _, opt := range opts { opt(s) @@ -144,7 +139,7 @@ func (s *Scanner) ScanFile(ctx context.Context, fsys fs.FS, path string) (scan.R if err != nil { return nil, err } - s.debug.Log("Scanning %s...", path) + s.logger.Debug("Scanning", log.FilePath(path)) return s.scanRego(ctx, fsys, rego.Input{ Path: path, Contents: dockerfile.ToRego(), @@ -159,7 +154,6 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { } regoScanner := rego.NewScanner(types.SourceDockerfile, s.options...) - regoScanner.SetParentDebugLogger(s.debug) if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { return nil, err } diff --git a/pkg/iac/scanners/dockerfile/scanner_test.go b/pkg/iac/scanners/dockerfile/scanner_test.go index 72c48f6a9f5e..437c37ec9660 100644 --- a/pkg/iac/scanners/dockerfile/scanner_test.go +++ b/pkg/iac/scanners/dockerfile/scanner_test.go @@ -566,12 +566,10 @@ COPY --from=dep /binary /` fs := testutil.CreateFS(t, regoMap) var traceBuf bytes.Buffer - var debugBuf bytes.Buffer scanner := NewScanner( options.ScannerWithPolicyDirs("rules"), options.ScannerWithTrace(&traceBuf), - options.ScannerWithDebug(&debugBuf), options.ScannerWithRegoErrorLimits(0), ) diff --git a/pkg/iac/scanners/helm/options.go b/pkg/iac/scanners/helm/options.go index 6ac412bf1e34..c4439d928845 100644 --- a/pkg/iac/scanners/helm/options.go +++ b/pkg/iac/scanners/helm/options.go @@ -5,55 +5,50 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) -type ConfigurableHelmScanner interface { - options.ConfigurableScanner - AddParserOptions(options ...options.ParserOption) -} - func ScannerWithValuesFile(paths ...string) options.ScannerOption { return func(s options.ConfigurableScanner) { - if helmScanner, ok := s.(ConfigurableHelmScanner); ok { - helmScanner.AddParserOptions(parser.OptionWithValuesFile(paths...)) + if helmScanner, ok := s.(*Scanner); ok { + helmScanner.addParserOptions(parser.OptionWithValuesFile(paths...)) } } } func ScannerWithValues(values ...string) options.ScannerOption { return func(s options.ConfigurableScanner) { - if helmScanner, ok := s.(ConfigurableHelmScanner); ok { - helmScanner.AddParserOptions(parser.OptionWithValues(values...)) + if helmScanner, ok := s.(*Scanner); ok { + helmScanner.addParserOptions(parser.OptionWithValues(values...)) } } } func ScannerWithFileValues(values ...string) options.ScannerOption { return func(s options.ConfigurableScanner) { - if helmScanner, ok := s.(ConfigurableHelmScanner); ok { - helmScanner.AddParserOptions(parser.OptionWithFileValues(values...)) + if helmScanner, ok := s.(*Scanner); ok { + helmScanner.addParserOptions(parser.OptionWithFileValues(values...)) } } } func ScannerWithStringValues(values ...string) options.ScannerOption { return func(s options.ConfigurableScanner) { - if helmScanner, ok := s.(ConfigurableHelmScanner); ok { - helmScanner.AddParserOptions(parser.OptionWithStringValues(values...)) + if helmScanner, ok := s.(*Scanner); ok { + helmScanner.addParserOptions(parser.OptionWithStringValues(values...)) } } } func ScannerWithAPIVersions(values ...string) options.ScannerOption { return func(s options.ConfigurableScanner) { - if helmScanner, ok := s.(ConfigurableHelmScanner); ok { - helmScanner.AddParserOptions(parser.OptionWithAPIVersions(values...)) + if helmScanner, ok := s.(*Scanner); ok { + helmScanner.addParserOptions(parser.OptionWithAPIVersions(values...)) } } } func ScannerWithKubeVersion(values string) options.ScannerOption { return func(s options.ConfigurableScanner) { - if helmScanner, ok := s.(ConfigurableHelmScanner); ok { - helmScanner.AddParserOptions(parser.OptionWithKubeVersion(values)) + if helmScanner, ok := s.(*Scanner); ok { + helmScanner.addParserOptions(parser.OptionWithKubeVersion(values)) } } } diff --git a/pkg/iac/scanners/helm/parser/option.go b/pkg/iac/scanners/helm/parser/option.go index 6de98d765182..0f2eae3cc291 100644 --- a/pkg/iac/scanners/helm/parser/option.go +++ b/pkg/iac/scanners/helm/parser/option.go @@ -1,9 +1,6 @@ package parser -import "github.com/aquasecurity/trivy/pkg/iac/scanners/options" - type ConfigurableHelmParser interface { - options.ConfigurableParser SetValuesFile(...string) SetValues(...string) SetFileValues(...string) @@ -12,50 +9,40 @@ type ConfigurableHelmParser interface { SetKubeVersion(string) } -func OptionWithValuesFile(paths ...string) options.ParserOption { - return func(p options.ConfigurableParser) { - if helmParser, ok := p.(ConfigurableHelmParser); ok { - helmParser.SetValuesFile(paths...) - } +type Option func(p *Parser) + +func OptionWithValuesFile(paths ...string) Option { + return func(p *Parser) { + p.valuesFiles = paths } } -func OptionWithValues(values ...string) options.ParserOption { - return func(p options.ConfigurableParser) { - if helmParser, ok := p.(ConfigurableHelmParser); ok { - helmParser.SetValues(values...) - } +func OptionWithValues(values ...string) Option { + return func(p *Parser) { + p.values = values } } -func OptionWithFileValues(values ...string) options.ParserOption { - return func(p options.ConfigurableParser) { - if helmParser, ok := p.(ConfigurableHelmParser); ok { - helmParser.SetValues(values...) - } +func OptionWithFileValues(values ...string) Option { + return func(p *Parser) { + p.fileValues = values } } -func OptionWithStringValues(values ...string) options.ParserOption { - return func(p options.ConfigurableParser) { - if helmParser, ok := p.(ConfigurableHelmParser); ok { - helmParser.SetValues(values...) - } +func OptionWithStringValues(values ...string) Option { + return func(p *Parser) { + p.stringValues = values } } -func OptionWithAPIVersions(values ...string) options.ParserOption { - return func(p options.ConfigurableParser) { - if helmParser, ok := p.(ConfigurableHelmParser); ok { - helmParser.SetAPIVersions(values...) - } +func OptionWithAPIVersions(values ...string) Option { + return func(p *Parser) { + p.apiVersions = values } } -func OptionWithKubeVersion(value string) options.ParserOption { - return func(p options.ConfigurableParser) { - if helmParser, ok := p.(ConfigurableHelmParser); ok { - helmParser.SetKubeVersion(value) - } +func OptionWithKubeVersion(value string) Option { + return func(p *Parser) { + p.kubeVersion = value } } diff --git a/pkg/iac/scanners/helm/parser/parser.go b/pkg/iac/scanners/helm/parser/parser.go index bf4a9fc91721..e38f032b6221 100644 --- a/pkg/iac/scanners/helm/parser/parser.go +++ b/pkg/iac/scanners/helm/parser/parser.go @@ -5,7 +5,6 @@ import ( "context" "errors" "fmt" - "io" "io/fs" "path/filepath" "regexp" @@ -21,19 +20,18 @@ import ( "helm.sh/helm/v3/pkg/release" "helm.sh/helm/v3/pkg/releaseutil" - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/detection" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" + "github.com/aquasecurity/trivy/pkg/log" ) var manifestNameRegex = regexp.MustCompile("# Source: [^/]+/(.+)") type Parser struct { + logger *log.Logger helmClient *action.Install rootPath string ChartSource string filepaths []string - debug debug.Logger workingFS fs.FS valuesFiles []string values []string @@ -48,35 +46,7 @@ type ChartFile struct { ManifestContent string } -func (p *Parser) SetDebugWriter(writer io.Writer) { - p.debug = debug.New(writer, "helm", "parser") -} - -func (p *Parser) SetValuesFile(s ...string) { - p.valuesFiles = s -} - -func (p *Parser) SetValues(values ...string) { - p.values = values -} - -func (p *Parser) SetFileValues(values ...string) { - p.fileValues = values -} - -func (p *Parser) SetStringValues(values ...string) { - p.stringValues = values -} - -func (p *Parser) SetAPIVersions(values ...string) { - p.apiVersions = values -} - -func (p *Parser) SetKubeVersion(value string) { - p.kubeVersion = value -} - -func New(path string, opts ...options.ParserOption) (*Parser, error) { +func New(path string, opts ...Option) (*Parser, error) { client := action.NewInstall(&action.Configuration{}) client.DryRun = true // don't do anything @@ -86,6 +56,7 @@ func New(path string, opts ...options.ParserOption) (*Parser, error) { p := &Parser{ helmClient: client, ChartSource: path, + logger: log.WithPrefix("helm parser"), } for _, option := range opts { diff --git a/pkg/iac/scanners/helm/parser/parser_tar.go b/pkg/iac/scanners/helm/parser/parser_tar.go index f8d692eaa977..8e2ba97a81d2 100644 --- a/pkg/iac/scanners/helm/parser/parser_tar.go +++ b/pkg/iac/scanners/helm/parser/parser_tar.go @@ -14,6 +14,7 @@ import ( "github.com/liamg/memoryfs" "github.com/aquasecurity/trivy/pkg/iac/detection" + "github.com/aquasecurity/trivy/pkg/log" ) var errSkipFS = errors.New("skip parse FS") @@ -75,13 +76,13 @@ func (p *Parser) addTarToFS(archivePath string) (fs.FS, error) { return nil, err } case tar.TypeReg: - p.debug.Log("Unpacking tar entry %s", targetPath) + p.logger.Debug("Unpacking tar entry", log.FilePath(targetPath)) if err := copyFile(tarFS, tr, targetPath); err != nil { return nil, err } case tar.TypeSymlink: if path.IsAbs(link) { - p.debug.Log("Symlink %s is absolute, skipping", link) + p.logger.Debug("Symlink is absolute, skipping", log.String("link", link)) continue } diff --git a/pkg/iac/scanners/helm/scanner.go b/pkg/iac/scanners/helm/scanner.go index 944187df4dee..305a116b56b7 100644 --- a/pkg/iac/scanners/helm/scanner.go +++ b/pkg/iac/scanners/helm/scanner.go @@ -11,7 +11,6 @@ import ( "github.com/liamg/memoryfs" - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/detection" "github.com/aquasecurity/trivy/pkg/iac/framework" "github.com/aquasecurity/trivy/pkg/iac/rego" @@ -21,6 +20,7 @@ import ( kparser "github.com/aquasecurity/trivy/pkg/iac/scanners/kubernetes/parser" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" ) var _ scanners.FSScanner = (*Scanner)(nil) @@ -29,9 +29,9 @@ var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { policyDirs []string dataDirs []string - debug debug.Logger + logger *log.Logger options []options.ScannerOption - parserOptions []options.ParserOption + parserOptions []parser.Option policyReaders []io.Reader loadEmbeddedLibraries bool loadEmbeddedPolicies bool @@ -60,6 +60,7 @@ func (s *Scanner) SetFrameworks(frameworks []framework.Framework) { func New(opts ...options.ScannerOption) *Scanner { s := &Scanner{ options: opts, + logger: log.WithPrefix("helm scanner"), } for _, option := range opts { @@ -68,7 +69,7 @@ func New(opts ...options.ScannerOption) *Scanner { return s } -func (s *Scanner) AddParserOptions(opts ...options.ParserOption) { +func (s *Scanner) addParserOptions(opts ...parser.Option) { s.parserOptions = append(s.parserOptions, opts...) } @@ -88,11 +89,6 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } -func (s *Scanner) SetDebugWriter(writer io.Writer) { - s.debug = debug.New(writer, "helm", "scanner") - s.parserOptions = append(s.parserOptions, options.ParserWithDebug(writer)) -} - func (s *Scanner) SetTraceWriter(_ io.Writer) { // handled by rego later - nothing to do for now... } @@ -180,13 +176,16 @@ func (s *Scanner) getScanResults(path string, ctx context.Context, target fs.FS) chartFiles, err := helmParser.RenderedChartFiles() if err != nil { // not valid helm, maybe some other yaml etc., abort - s.debug.Log("Failed to render Chart files: %s", err) + s.logger.Error( + "Failed to render Chart files", + log.FilePath(path), log.Err(err), + ) return nil, nil } for _, file := range chartFiles { file := file - s.debug.Log("Processing rendered chart file: %s", file.TemplateFilePath) + s.logger.Debug("Processing rendered chart file", log.FilePath(file.TemplateFilePath)) manifests, err := kparser.New().Parse(strings.NewReader(file.ManifestContent), file.TemplateFilePath) if err != nil { @@ -229,7 +228,6 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) error { return nil } regoScanner := rego.NewScanner(types.SourceKubernetes, s.options...) - regoScanner.SetParentDebugLogger(s.debug) if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { return err } diff --git a/pkg/iac/scanners/helm/test/option_test.go b/pkg/iac/scanners/helm/test/option_test.go index 8efb03f16116..05bf96ee01d3 100644 --- a/pkg/iac/scanners/helm/test/option_test.go +++ b/pkg/iac/scanners/helm/test/option_test.go @@ -11,7 +11,6 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/iac/scanners/helm/parser" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) func Test_helm_parser_with_options_with_values_file(t *testing.T) { @@ -34,7 +33,7 @@ func Test_helm_parser_with_options_with_values_file(t *testing.T) { t.Logf("Running test: %s", test.testName) - var opts []options.ParserOption + var opts []parser.Option if test.valuesFile != "" { opts = append(opts, parser.OptionWithValuesFile(test.valuesFile)) @@ -84,7 +83,7 @@ func Test_helm_parser_with_options_with_set_value(t *testing.T) { t.Logf("Running test: %s", test.testName) - var opts []options.ParserOption + var opts []parser.Option if test.valuesFile != "" { opts = append(opts, parser.OptionWithValuesFile(test.valuesFile)) @@ -138,7 +137,7 @@ func Test_helm_parser_with_options_with_api_versions(t *testing.T) { t.Logf("Running test: %s", test.testName) - var opts []options.ParserOption + var opts []parser.Option if len(test.apiVersions) > 0 { opts = append(opts, parser.OptionWithAPIVersions(test.apiVersions...)) @@ -195,7 +194,7 @@ func Test_helm_parser_with_options_with_kube_versions(t *testing.T) { t.Logf("Running test: %s", test.testName) - var opts []options.ParserOption + var opts []parser.Option opts = append(opts, parser.OptionWithKubeVersion(test.kubeVersion)) diff --git a/pkg/iac/scanners/json/parser/parser.go b/pkg/iac/scanners/json/parser/parser.go index 8f35794229ef..c97e54b40bd9 100644 --- a/pkg/iac/scanners/json/parser/parser.go +++ b/pkg/iac/scanners/json/parser/parser.go @@ -3,31 +3,21 @@ package parser import ( "context" "encoding/json" - "io" "io/fs" "path/filepath" - "github.com/aquasecurity/trivy/pkg/iac/debug" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" + "github.com/aquasecurity/trivy/pkg/log" ) -var _ options.ConfigurableParser = (*Parser)(nil) - type Parser struct { - debug debug.Logger -} - -func (p *Parser) SetDebugWriter(writer io.Writer) { - p.debug = debug.New(writer, "json", "parser") + logger *log.Logger } // New creates a new parser -func New(opts ...options.ParserOption) *Parser { - p := &Parser{} - for _, opt := range opts { - opt(p) +func New() *Parser { + return &Parser{ + logger: log.WithPrefix("json parser"), } - return p } func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[string]any, error) { @@ -48,7 +38,7 @@ func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[st df, err := p.ParseFile(ctx, target, path) if err != nil { - p.debug.Log("Parse error in '%s': %s", path, err) + p.logger.Error("Parse error", log.FilePath(path), log.Err(err)) return nil } diff --git a/pkg/iac/scanners/json/scanner.go b/pkg/iac/scanners/json/scanner.go index 7a18df363823..8991120be26f 100644 --- a/pkg/iac/scanners/json/scanner.go +++ b/pkg/iac/scanners/json/scanner.go @@ -6,7 +6,6 @@ import ( "io/fs" "sync" - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/framework" "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scan" @@ -14,6 +13,7 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/scanners/json/parser" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" ) var _ scanners.FSScanner = (*Scanner)(nil) @@ -21,13 +21,12 @@ var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { mu sync.Mutex - debug debug.Logger + logger *log.Logger policyDirs []string policyReaders []io.Reader parser *parser.Parser regoScanner *rego.Scanner options []options.ScannerOption - parserOpts []options.ParserOption frameworks []framework.Framework spec string loadEmbeddedPolicies bool @@ -60,11 +59,6 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } -func (s *Scanner) SetDebugWriter(writer io.Writer) { - s.debug = debug.New(writer, "json", "scanner") - s.parserOpts = append(s.parserOpts, options.ParserWithDebug(writer)) -} - func (s *Scanner) SetTraceWriter(_ io.Writer) { } @@ -90,11 +84,12 @@ func (s *Scanner) SetRegoErrorLimit(_ int) {} func NewScanner(opts ...options.ScannerOption) *Scanner { s := &Scanner{ options: opts, + logger: log.WithPrefix("json scanner"), + parser: parser.New(), } for _, opt := range opts { opt(s) } - s.parser = parser.New(s.parserOpts...) return s } @@ -134,7 +129,7 @@ func (s *Scanner) ScanFile(ctx context.Context, fsys fs.FS, path string) (scan.R if err != nil { return nil, err } - s.debug.Log("Scanning %s...", path) + s.logger.Debug("Scanning", log.FilePath(path)) return s.scanRego(ctx, fsys, rego.Input{ Path: path, Contents: parsed, @@ -148,7 +143,6 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { return s.regoScanner, nil } regoScanner := rego.NewScanner(types.SourceJSON, s.options...) - regoScanner.SetParentDebugLogger(s.debug) if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { return nil, err } diff --git a/pkg/iac/scanners/kubernetes/parser/parser.go b/pkg/iac/scanners/kubernetes/parser/parser.go index e2f225a9fb86..f3ca7d613562 100644 --- a/pkg/iac/scanners/kubernetes/parser/parser.go +++ b/pkg/iac/scanners/kubernetes/parser/parser.go @@ -13,27 +13,18 @@ import ( "gopkg.in/yaml.v3" kyaml "sigs.k8s.io/yaml" - "github.com/aquasecurity/trivy/pkg/iac/debug" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" + "github.com/aquasecurity/trivy/pkg/log" ) -var _ options.ConfigurableParser = (*Parser)(nil) - type Parser struct { - debug debug.Logger -} - -func (p *Parser) SetDebugWriter(writer io.Writer) { - p.debug = debug.New(writer, "kubernetes", "parser") + logger *log.Logger } // New creates a new K8s parser -func New(opts ...options.ParserOption) *Parser { - p := &Parser{} - for _, option := range opts { - option(p) +func New() *Parser { + return &Parser{ + logger: log.WithPrefix("k8s parser"), } - return p } func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[string][]any, error) { @@ -53,7 +44,7 @@ func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[st parsed, err := p.ParseFile(ctx, target, path) if err != nil { - p.debug.Log("Parse error in '%s': %s", path, err) + p.logger.Error("Parse error", log.FilePath(path), log.Err(err)) return nil } diff --git a/pkg/iac/scanners/kubernetes/scanner.go b/pkg/iac/scanners/kubernetes/scanner.go index 9612fe03ebe4..e9e9eacd73e8 100644 --- a/pkg/iac/scanners/kubernetes/scanner.go +++ b/pkg/iac/scanners/kubernetes/scanner.go @@ -10,7 +10,6 @@ import ( "github.com/liamg/memoryfs" - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/framework" "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scan" @@ -18,6 +17,7 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/scanners/kubernetes/parser" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" ) var _ scanners.FSScanner = (*Scanner)(nil) @@ -25,9 +25,8 @@ var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { mu sync.Mutex - debug debug.Logger + logger *log.Logger options []options.ScannerOption - parserOpts []options.ParserOption policyDirs []string policyReaders []io.Reader regoScanner *rego.Scanner @@ -63,11 +62,6 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } -func (s *Scanner) SetDebugWriter(writer io.Writer) { - s.debug = debug.New(writer, "kubernetes", "scanner") - s.parserOpts = append(s.parserOpts, options.ParserWithDebug(writer)) -} - func (s *Scanner) SetTraceWriter(_ io.Writer) { } @@ -94,11 +88,12 @@ func (s *Scanner) SetRegoErrorLimit(_ int) {} func NewScanner(opts ...options.ScannerOption) *Scanner { s := &Scanner{ options: opts, + logger: log.WithPrefix("k8s scanner"), + parser: parser.New(), } for _, opt := range opts { opt(s) } - s.parser = parser.New(s.parserOpts...) return s } @@ -113,7 +108,6 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { return s.regoScanner, nil } regoScanner := rego.NewScanner(types.SourceKubernetes, s.options...) - regoScanner.SetParentDebugLogger(s.debug) if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { return nil, err } @@ -163,7 +157,7 @@ func (s *Scanner) ScanFS(ctx context.Context, target fs.FS, dir string) (scan.Re return nil, err } - s.debug.Log("Scanning %d files...", len(inputs)) + s.logger.Debug("Scanning files", log.Int("count", len(inputs))) results, err := regoScanner.ScanInput(ctx, inputs...) if err != nil { return nil, err diff --git a/pkg/iac/scanners/kubernetes/scanner_test.go b/pkg/iac/scanners/kubernetes/scanner_test.go index a75173f67c0e..d972e52e8e80 100644 --- a/pkg/iac/scanners/kubernetes/scanner_test.go +++ b/pkg/iac/scanners/kubernetes/scanner_test.go @@ -486,7 +486,6 @@ deny[msg] { func Test_FileScanWithMetadata(t *testing.T) { results, err := NewScanner( - options.ScannerWithDebug(os.Stdout), options.ScannerWithTrace(os.Stdout), options.ScannerWithPolicyReader(strings.NewReader(`package defsec @@ -526,7 +525,6 @@ spec: func Test_FileScanExampleWithResultFunction(t *testing.T) { results, err := NewScanner( - options.ScannerWithDebug(os.Stdout), options.ScannerWithEmbeddedPolicies(true), options.ScannerWithEmbeddedLibraries(true), options.ScannerWithPolicyReader(strings.NewReader(`package defsec diff --git a/pkg/iac/scanners/options/parser.go b/pkg/iac/scanners/options/parser.go deleted file mode 100644 index e411126a6329..000000000000 --- a/pkg/iac/scanners/options/parser.go +++ /dev/null @@ -1,16 +0,0 @@ -package options - -import "io" - -type ConfigurableParser interface { - SetDebugWriter(io.Writer) -} - -type ParserOption func(s ConfigurableParser) - -// ParserWithDebug specifies an io.Writer for debug logs - if not set, they are discarded -func ParserWithDebug(w io.Writer) ParserOption { - return func(s ConfigurableParser) { - s.SetDebugWriter(w) - } -} diff --git a/pkg/iac/scanners/options/scanner.go b/pkg/iac/scanners/options/scanner.go index f5b3b982ee67..4f07c4d14b0a 100644 --- a/pkg/iac/scanners/options/scanner.go +++ b/pkg/iac/scanners/options/scanner.go @@ -8,7 +8,6 @@ import ( ) type ConfigurableScanner interface { - SetDebugWriter(io.Writer) SetTraceWriter(io.Writer) SetPerResultTracingEnabled(bool) SetPolicyDirs(...string) @@ -47,13 +46,6 @@ func ScannerWithPolicyReader(readers ...io.Reader) ScannerOption { } } -// ScannerWithDebug specifies an io.Writer for debug logs - if not set, they are discarded -func ScannerWithDebug(w io.Writer) ScannerOption { - return func(s ConfigurableScanner) { - s.SetDebugWriter(w) - } -} - func ScannerWithEmbeddedPolicies(embedded bool) ScannerOption { return func(s ConfigurableScanner) { s.SetUseEmbeddedPolicies(embedded) diff --git a/pkg/iac/scanners/terraform/executor/executor.go b/pkg/iac/scanners/terraform/executor/executor.go index 88dc1fa9801c..c6337a2bfd1d 100644 --- a/pkg/iac/scanners/terraform/executor/executor.go +++ b/pkg/iac/scanners/terraform/executor/executor.go @@ -8,7 +8,6 @@ import ( "github.com/zclconf/go-cty/cty" adapter "github.com/aquasecurity/trivy/pkg/iac/adapters/terraform" - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/framework" "github.com/aquasecurity/trivy/pkg/iac/ignore" "github.com/aquasecurity/trivy/pkg/iac/rego" @@ -16,12 +15,13 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/terraform" "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" ) // Executor scans HCL blocks by running all registered rules against them type Executor struct { workspaceName string - debug debug.Logger + logger *log.Logger resultsFilters []func(scan.Results) scan.Results regoScanner *rego.Scanner regoOnly bool @@ -32,6 +32,7 @@ type Executor struct { func New(options ...Option) *Executor { s := &Executor{ regoOnly: false, + logger: log.WithPrefix("terraform executor"), } for _, option := range options { option(s) @@ -41,31 +42,30 @@ func New(options ...Option) *Executor { func (e *Executor) Execute(modules terraform.Modules) (scan.Results, error) { - e.debug.Log("Adapting modules...") + e.logger.Debug("Adapting modules...") infra := adapter.Adapt(modules) - e.debug.Log("Adapted %d module(s) into defsec state data.", len(modules)) + e.logger.Debug("Adapted module(s) into state data.", log.Int("count", len(modules))) threads := runtime.NumCPU() if threads > 1 { threads-- } - e.debug.Log("Using max routines of %d", threads) + e.logger.Debug("Using max routines", log.Int("count", threads)) registeredRules := rules.GetRegistered(e.frameworks...) - e.debug.Log("Initialized %d rule(s).", len(registeredRules)) + e.logger.Debug("Initialized rule(s).", log.Int("count", len(registeredRules))) pool := NewPool(threads, registeredRules, modules, infra, e.regoScanner, e.regoOnly) - e.debug.Log("Created pool with %d worker(s) to apply rules.", threads) results, err := pool.Run() if err != nil { return nil, err } - e.debug.Log("Finished applying rules.") + e.logger.Debug("Finished applying rules.") - e.debug.Log("Applying ignores...") + e.logger.Debug("Applying ignores...") var ignores ignore.Rules for _, module := range modules { ignores = append(ignores, module.Ignores()...) @@ -79,7 +79,10 @@ func (e *Executor) Execute(modules terraform.Modules) (scan.Results, error) { results.Ignore(ignores, ignorers) for _, ignored := range results.GetIgnored() { - e.debug.Log("Ignored '%s' at '%s'.", ignored.Rule().LongID(), ignored.Range()) + e.logger.Info("Ignore finding", + log.String("rule", ignored.Rule().LongID()), + log.String("range", ignored.Range().String()), + ) } results = e.filterResults(results) @@ -91,11 +94,12 @@ func (e *Executor) Execute(modules terraform.Modules) (scan.Results, error) { func (e *Executor) filterResults(results scan.Results) scan.Results { if len(e.resultsFilters) > 0 && len(results) > 0 { before := len(results.GetIgnored()) - e.debug.Log("Applying %d results filters to %d results...", len(results), before) + e.logger.Debug("Applying results filters...") for _, filter := range e.resultsFilters { results = filter(results) } - e.debug.Log("Filtered out %d results.", len(results.GetIgnored())-before) + e.logger.Debug("Applied results filters.", + log.Int("count", len(results.GetIgnored())-before)) } return results diff --git a/pkg/iac/scanners/terraform/executor/option.go b/pkg/iac/scanners/terraform/executor/option.go index a58d72867b54..d2414878c98f 100644 --- a/pkg/iac/scanners/terraform/executor/option.go +++ b/pkg/iac/scanners/terraform/executor/option.go @@ -1,9 +1,6 @@ package executor import ( - "io" - - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/framework" "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scan" @@ -23,12 +20,6 @@ func OptionWithResultsFilter(f func(scan.Results) scan.Results) Option { } } -func OptionWithDebugWriter(w io.Writer) Option { - return func(s *Executor) { - s.debug = debug.New(w, "terraform", "executor") - } -} - func OptionWithWorkspaceName(workspaceName string) Option { return func(s *Executor) { s.workspaceName = workspaceName diff --git a/pkg/iac/scanners/terraform/fs_test.go b/pkg/iac/scanners/terraform/fs_test.go index 79b0844fe983..649062792514 100644 --- a/pkg/iac/scanners/terraform/fs_test.go +++ b/pkg/iac/scanners/terraform/fs_test.go @@ -13,7 +13,6 @@ import ( func Test_OS_FS(t *testing.T) { s := New( - options.ScannerWithDebug(os.Stderr), options.ScannerWithEmbeddedPolicies(true), options.ScannerWithEmbeddedLibraries(true), ) diff --git a/pkg/iac/scanners/terraform/module_test.go b/pkg/iac/scanners/terraform/module_test.go index 5469204e741f..d0d289a9d562 100644 --- a/pkg/iac/scanners/terraform/module_test.go +++ b/pkg/iac/scanners/terraform/module_test.go @@ -1,10 +1,7 @@ package terraform import ( - "bytes" "context" - "fmt" - "os" "testing" "github.com/stretchr/testify/require" @@ -14,7 +11,6 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/providers" "github.com/aquasecurity/trivy/pkg/iac/rules" "github.com/aquasecurity/trivy/pkg/iac/scan" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/executor" "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/parser" "github.com/aquasecurity/trivy/pkg/iac/severity" @@ -86,9 +82,7 @@ resource "problem" "uhoh" { `, }) - debug := bytes.NewBuffer([]byte{}) - - p := parser.New(fs, "", parser.OptionStopOnHCLError(true), options.ParserWithDebug(debug)) + p := parser.New(fs, "", parser.OptionStopOnHCLError(true)) err := p.ParseFS(context.TODO(), "project") require.NoError(t, err) modules, _, err := p.EvaluateAll(context.TODO()) @@ -98,9 +92,6 @@ resource "problem" "uhoh" { require.NoError(t, err) testutil.AssertRuleFound(t, badRule.LongID(), results, "") - if t.Failed() { - fmt.Println(debug.String()) - } } func Test_ProblemInModuleInSiblingDir(t *testing.T) { @@ -293,7 +284,7 @@ resource "problem" "uhoh" { `, }) - p := parser.New(fs, "", parser.OptionStopOnHCLError(true), options.ParserWithDebug(os.Stderr)) + p := parser.New(fs, "", parser.OptionStopOnHCLError(true)) err := p.ParseFS(context.TODO(), "project") require.NoError(t, err) modules, _, err := p.EvaluateAll(context.TODO()) diff --git a/pkg/iac/scanners/terraform/options.go b/pkg/iac/scanners/terraform/options.go index f5a0d2223534..d256f0a34daa 100644 --- a/pkg/iac/scanners/terraform/options.go +++ b/pkg/iac/scanners/terraform/options.go @@ -14,7 +14,7 @@ type ConfigurableTerraformScanner interface { options.ConfigurableScanner SetForceAllDirs(bool) AddExecutorOptions(options ...executor.Option) - AddParserOptions(options ...options.ParserOption) + AddParserOptions(options ...parser.Option) } func ScannerWithTFVarsPaths(paths ...string) options.ScannerOption { diff --git a/pkg/iac/scanners/terraform/parser/evaluator.go b/pkg/iac/scanners/terraform/parser/evaluator.go index e0231d2311a5..811f618787b5 100644 --- a/pkg/iac/scanners/terraform/parser/evaluator.go +++ b/pkg/iac/scanners/terraform/parser/evaluator.go @@ -13,11 +13,11 @@ import ( "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/convert" - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/ignore" "github.com/aquasecurity/trivy/pkg/iac/terraform" tfcontext "github.com/aquasecurity/trivy/pkg/iac/terraform/context" "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" ) const ( @@ -25,6 +25,7 @@ const ( ) type evaluator struct { + logger *log.Logger filesystem fs.FS ctx *tfcontext.Context blocks terraform.Blocks @@ -35,7 +36,6 @@ type evaluator struct { moduleName string ignores ignore.Rules parentParser *Parser - debug debug.Logger allowDownloads bool skipCachedModules bool } @@ -52,7 +52,7 @@ func newEvaluator( moduleMetadata *modulesMetadata, workspace string, ignores ignore.Rules, - logger debug.Logger, + logger *log.Logger, allowDownloads bool, skipCachedModules bool, ) *evaluator { @@ -84,7 +84,7 @@ func newEvaluator( inputVars: inputVars, moduleMetadata: moduleMetadata, ignores: ignores, - debug: logger, + logger: logger, allowDownloads: allowDownloads, skipCachedModules: skipCachedModules, } @@ -114,20 +114,24 @@ func (e *evaluator) exportOutputs() cty.Value { continue } data[block.Label()] = attr.Value() - e.debug.Log("Added module output %s=%s.", block.Label(), attr.Value().GoString()) + e.logger.Debug( + "Added module output", + log.String("block", block.Label()), + log.String("value", attr.Value().GoString()), + ) } return cty.ObjectVal(data) } func (e *evaluator) EvaluateAll(ctx context.Context) (terraform.Modules, map[string]fs.FS) { - fsKey := types.CreateFSKey(e.filesystem) - e.debug.Log("Filesystem key is '%s'", fsKey) + e.logger.Debug("Starting module evaluation...", log.String("path", e.modulePath)) - fsMap := make(map[string]fs.FS) - fsMap[fsKey] = e.filesystem + fsKey := types.CreateFSKey(e.filesystem) + fsMap := map[string]fs.FS{ + fsKey: e.filesystem, + } - e.debug.Log("Starting module evaluation...") e.evaluateSteps() // expand out resources and modules via count, for-each and dynamic @@ -135,21 +139,37 @@ func (e *evaluator) EvaluateAll(ctx context.Context) (terraform.Modules, map[str e.blocks = e.expandBlocks(e.blocks) e.blocks = e.expandBlocks(e.blocks) - e.debug.Log("Starting submodule evaluation...") + submodules := e.evaluateSubmodules(ctx, fsMap) + + e.logger.Debug("Starting post-submodules evaluation...") + e.evaluateSteps() + + e.logger.Debug("Module evaluation complete.") + rootModule := terraform.NewModule(e.projectRootPath, e.modulePath, e.blocks, e.ignores) + return append(terraform.Modules{rootModule}, submodules...), fsMap +} + +func (e *evaluator) evaluateSubmodules(ctx context.Context, fsMap map[string]fs.FS) terraform.Modules { submodules := e.loadSubmodules(ctx) + if len(submodules) == 0 { + return nil + } + + e.logger.Debug("Starting submodules evaluation...") + for i := 0; i < maxContextIterations; i++ { changed := false for _, sm := range submodules { changed = changed || e.evaluateSubmodule(ctx, sm) } if !changed { - e.debug.Log("All submodules are evaluated at i=%d", i) + e.logger.Debug("All submodules are evaluated", log.Int("loop", i)) break } } - e.debug.Log("Starting post-submodule evaluation...") + e.logger.Debug("Starting post-submodule evaluation...") e.evaluateSteps() var modules terraform.Modules @@ -158,11 +178,8 @@ func (e *evaluator) EvaluateAll(ctx context.Context) (terraform.Modules, map[str fsMap = lo.Assign(fsMap, sm.fsMap) } - e.debug.Log("Finished processing %d submodule(s).", len(modules)) - - e.debug.Log("Module evaluation complete.") - rootModule := terraform.NewModule(e.projectRootPath, e.modulePath, e.blocks, e.ignores) - return append(terraform.Modules{rootModule}, modules...), fsMap + e.logger.Debug("Finished processing submodule(s).", log.Int("count", len(modules))) + return modules } type submodule struct { @@ -181,7 +198,7 @@ func (e *evaluator) loadSubmodules(ctx context.Context) []*submodule { if errors.Is(err, ErrNoFiles) { continue } else if err != nil { - e.debug.Log("Failed to load submodule '%s': %s.", definition.Name, err) + e.logger.Error("Failed to load submodule", log.String("name", definition.Name), log.Err(err)) continue } @@ -199,12 +216,12 @@ func (e *evaluator) evaluateSubmodule(ctx context.Context, sm *submodule) bool { inputVars := sm.definition.inputVars() if len(sm.modules) > 0 { if reflect.DeepEqual(inputVars, sm.lastState) { - e.debug.Log("Submodule %s inputs unchanged", sm.definition.Name) + e.logger.Debug("Submodule inputs unchanged", log.String("name", sm.definition.Name)) return false } } - e.debug.Log("Evaluating submodule %s", sm.definition.Name) + e.logger.Debug("Evaluating submodule", log.String("name", sm.definition.Name)) sm.eval.inputVars = inputVars sm.modules, sm.fsMap = sm.eval.EvaluateAll(ctx) outputs := sm.eval.exportOutputs() @@ -223,12 +240,12 @@ func (e *evaluator) evaluateSteps() { var lastContext hcl.EvalContext for i := 0; i < maxContextIterations; i++ { - e.debug.Log("Starting iteration %d", i) + e.logger.Debug("Starting iteration", log.Int("iteration", i)) e.evaluateStep() // if ctx matches the last evaluation, we can bail, nothing left to resolve if i > 0 && reflect.DeepEqual(lastContext.Variables, e.ctx.Inner().Variables) { - e.debug.Log("Context unchanged at i=%d", i) + e.logger.Debug("Context unchanged", log.Int("iteration", i)) break } if len(e.ctx.Inner().Variables) != len(lastContext.Variables) { @@ -283,6 +300,7 @@ func isBlockSupportsForEachMetaArgument(block *terraform.Block) bool { } func (e *evaluator) expandBlockForEaches(blocks terraform.Blocks, isDynamic bool) terraform.Blocks { + var forEachFiltered terraform.Blocks for _, block := range blocks { @@ -297,6 +315,10 @@ func (e *evaluator) expandBlockForEaches(blocks terraform.Blocks, isDynamic bool forEachVal := forEachAttr.Value() if forEachVal.IsNull() || !forEachVal.IsKnown() || !forEachAttr.IsIterable() { + e.logger.Error(`Failed to expand block. Invalid "for-each" argument. Must be known and iterable.`, + log.String("block", block.FullName()), + log.String("value", forEachVal.GoString()), + ) continue } @@ -310,9 +332,12 @@ func (e *evaluator) expandBlockForEaches(blocks terraform.Blocks, isDynamic bool // instances are identified by a map key (or set member) from the value provided to for_each idx, err := convert.Convert(key, cty.String) if err != nil { - e.debug.Log( - `Invalid "for-each" argument: map key (or set value) is not a string, but %s`, - key.Type().FriendlyName(), + e.logger.Error( + `Failed to expand block. Invalid "for-each" argument: map key (or set value) is not a string`, + log.String("block", block.FullName()), + log.String("key", key.GoString()), + log.String("value", val.GoString()), + log.Err(err), ) return } @@ -324,7 +349,13 @@ func (e *evaluator) expandBlockForEaches(blocks terraform.Blocks, isDynamic bool !forEachVal.Type().IsMapType() && !isDynamic { stringVal, err := convert.Convert(val, cty.String) if err != nil { - e.debug.Log("Failed to convert for-each arg %v to string", val) + e.logger.Error( + "Failed to expand block. Invalid 'for-each' argument: value is not a string", + log.String("block", block.FullName()), + log.String("key", idx.AsString()), + log.String("value", val.GoString()), + log.Err(err), + ) return } idx = stringVal @@ -349,7 +380,8 @@ func (e *evaluator) expandBlockForEaches(blocks terraform.Blocks, isDynamic bool ctx.Set(idx, refs[0].TypeLabel(), "key") ctx.Set(val, refs[0].TypeLabel(), "value") } else { - e.debug.Log("Ignoring iterator attribute in dynamic block, expected one reference but got %d", len(refs)) + e.logger.Debug("Ignoring iterator attribute in dynamic block, expected one reference", + log.Int("refs", len(refs))) } } } @@ -367,7 +399,10 @@ func (e *evaluator) expandBlockForEaches(blocks terraform.Blocks, isDynamic bool // So we must replace the old resource with a map with the attributes of the resource. e.ctx.Replace(cty.ObjectVal(clones), metadata.Reference()) } - e.debug.Log("Expanded block '%s' into %d clones via 'for_each' attribute.", block.LocalName(), len(clones)) + e.logger.Debug("Expanded block into clones via 'for_each' attribute.", + log.String("block", block.FullName()), + log.Int("clones", len(clones)), + ) } return forEachFiltered @@ -409,7 +444,11 @@ func (e *evaluator) expandBlockCounts(blocks terraform.Blocks) terraform.Blocks } else { e.ctx.SetByDot(cty.TupleVal(clones), metadata.Reference()) } - e.debug.Log("Expanded block '%s' into %d clones via 'count' attribute.", block.LocalName(), len(clones)) + e.logger.Debug( + "Expanded block into clones via 'count' attribute.", + log.String("block", block.FullName()), + log.Int("clones", len(clones)), + ) } return countFiltered diff --git a/pkg/iac/scanners/terraform/parser/load_module.go b/pkg/iac/scanners/terraform/parser/load_module.go index 0bd6a6395936..78ebe3430b4e 100644 --- a/pkg/iac/scanners/terraform/parser/load_module.go +++ b/pkg/iac/scanners/terraform/parser/load_module.go @@ -11,6 +11,7 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/parser/resolvers" "github.com/aquasecurity/trivy/pkg/iac/terraform" + "github.com/aquasecurity/trivy/pkg/log" ) type ModuleDefinition struct { @@ -42,11 +43,11 @@ func (e *evaluator) loadModules(ctx context.Context) []*ModuleDefinition { } moduleDefinition, err := e.loadModule(ctx, moduleBlock) if err != nil { - e.debug.Log("Failed to load module %q. Maybe try 'terraform init'?", err) + e.logger.Error("Failed to load module. Maybe try 'terraform init'?", log.Err(err)) continue } - e.debug.Log("Loaded module %q from %q.", moduleDefinition.Name, moduleDefinition.Path) + e.logger.Debug("Loaded module", log.String("name", moduleDefinition.Name), log.FilePath(moduleDefinition.Path)) moduleDefinitions = append(moduleDefinitions, moduleDefinition) } @@ -77,7 +78,7 @@ func (e *evaluator) loadModule(ctx context.Context, b *terraform.Block) (*Module } if def, err := e.loadModuleFromTerraformCache(ctx, b, source); err == nil { - e.debug.Log("found module '%s' in .terraform/modules", source) + e.logger.Debug("Using module from Terraform cache .terraform/modules", log.String("source", source)) return def, nil } @@ -110,7 +111,11 @@ func (e *evaluator) loadModuleFromTerraformCache(ctx context.Context, b *terrafo } } - e.debug.Log("Module '%s' resolved to path '%s' in filesystem '%s' using modules.json", b.FullName(), modulePath, e.filesystem) + e.logger.Debug("Module resolved using modules.json", + log.String("block", b.FullName()), + log.String("source", source), + log.String("modulePath", modulePath), + ) moduleParser := e.parentParser.newModuleParser(e.filesystem, source, modulePath, b.Label(), b) if err := moduleParser.ParseFS(ctx, modulePath); err != nil { return nil, err @@ -126,7 +131,7 @@ func (e *evaluator) loadModuleFromTerraformCache(ctx context.Context, b *terrafo func (e *evaluator) loadExternalModule(ctx context.Context, b *terraform.Block, source string) (*ModuleDefinition, error) { - e.debug.Log("locating non-initialized module '%s'...", source) + e.logger.Debug("Locating non-initialized module", log.String("source", source)) version := b.GetAttribute("version").AsStringValueOrDefault("", b).Value() opt := resolvers.Options{ @@ -137,7 +142,7 @@ func (e *evaluator) loadExternalModule(ctx context.Context, b *terraform.Block, WorkingDir: e.projectRootPath, Name: b.FullName(), ModulePath: e.modulePath, - DebugLogger: e.debug.Extend("resolver"), + Logger: log.WithPrefix("module resolver"), AllowDownloads: e.allowDownloads, SkipCache: e.skipCachedModules, } @@ -147,7 +152,12 @@ func (e *evaluator) loadExternalModule(ctx context.Context, b *terraform.Block, return nil, err } prefix = path.Join(e.parentParser.moduleSource, prefix) - e.debug.Log("Module '%s' resolved to path '%s' in filesystem '%s' with prefix '%s'", b.FullName(), downloadPath, filesystem, prefix) + e.logger.Debug("Module resolved", + log.String("block", b.FullName()), + log.String("source", source), + log.String("prefix", prefix), + log.FilePath(downloadPath), + ) moduleParser := e.parentParser.newModuleParser(filesystem, prefix, downloadPath, b.Label(), b) if err := moduleParser.ParseFS(ctx, downloadPath); err != nil { return nil, err diff --git a/pkg/iac/scanners/terraform/parser/module_retrieval.go b/pkg/iac/scanners/terraform/parser/module_retrieval.go index 165f64eef1cb..cc374b68eeb7 100644 --- a/pkg/iac/scanners/terraform/parser/module_retrieval.go +++ b/pkg/iac/scanners/terraform/parser/module_retrieval.go @@ -6,6 +6,7 @@ import ( "io/fs" "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/parser/resolvers" + "github.com/aquasecurity/trivy/pkg/log" ) type ModuleResolver interface { @@ -20,12 +21,13 @@ var defaultResolvers = []ModuleResolver{ } func resolveModule(ctx context.Context, current fs.FS, opt resolvers.Options) (filesystem fs.FS, sourcePrefix, downloadPath string, err error) { - opt.Debug("Resolving module '%s' with source: '%s'...", opt.Name, opt.Source) + opt.Logger.Debug("Resolving module", + log.String("name", opt.Name), log.String("source", opt.Source)) for _, resolver := range defaultResolvers { if filesystem, prefix, path, applies, err := resolver.Resolve(ctx, current, opt); err != nil { return nil, "", "", err } else if applies { - opt.Debug("Module path is %s", path) + opt.Logger.Debug("Module resolved", log.FilePath(path)) return filesystem, prefix, path, nil } } diff --git a/pkg/iac/scanners/terraform/parser/option.go b/pkg/iac/scanners/terraform/parser/option.go index 76146a4ea6bf..277cf2a58c61 100644 --- a/pkg/iac/scanners/terraform/parser/option.go +++ b/pkg/iac/scanners/terraform/parser/option.go @@ -4,75 +4,48 @@ import ( "io/fs" "github.com/zclconf/go-cty/cty" - - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) -type ConfigurableTerraformParser interface { - options.ConfigurableParser - SetTFVarsPaths(...string) - SetTFVars(vars map[string]cty.Value) - SetStopOnHCLError(bool) - SetWorkspaceName(string) - SetAllowDownloads(bool) - SetSkipCachedModules(bool) - SetConfigsFS(fsys fs.FS) -} - -type Option func(p ConfigurableTerraformParser) +type Option func(p *Parser) -func OptionWithTFVarsPaths(paths ...string) options.ParserOption { - return func(p options.ConfigurableParser) { - if tf, ok := p.(ConfigurableTerraformParser); ok { - tf.SetTFVarsPaths(paths...) - } +func OptionWithTFVarsPaths(paths ...string) Option { + return func(p *Parser) { + p.tfvarsPaths = paths } } -func OptionsWithTfVars(vars map[string]cty.Value) options.ParserOption { - return func(p options.ConfigurableParser) { - if tf, ok := p.(ConfigurableTerraformParser); ok { - tf.SetTFVars(vars) - } +func OptionStopOnHCLError(stop bool) Option { + return func(p *Parser) { + p.stopOnHCLError = stop } } -func OptionStopOnHCLError(stop bool) options.ParserOption { - return func(p options.ConfigurableParser) { - if tf, ok := p.(ConfigurableTerraformParser); ok { - tf.SetStopOnHCLError(stop) - } +func OptionsWithTfVars(vars map[string]cty.Value) Option { + return func(p *Parser) { + p.tfvars = vars } } -func OptionWithWorkspaceName(workspaceName string) options.ParserOption { - return func(p options.ConfigurableParser) { - if tf, ok := p.(ConfigurableTerraformParser); ok { - tf.SetWorkspaceName(workspaceName) - } +func OptionWithWorkspaceName(workspaceName string) Option { + return func(p *Parser) { + p.workspaceName = workspaceName } } -func OptionWithDownloads(allowed bool) options.ParserOption { - return func(p options.ConfigurableParser) { - if tf, ok := p.(ConfigurableTerraformParser); ok { - tf.SetAllowDownloads(allowed) - } +func OptionWithDownloads(allowed bool) Option { + return func(p *Parser) { + p.allowDownloads = allowed } } -func OptionWithSkipCachedModules(b bool) options.ParserOption { - return func(p options.ConfigurableParser) { - if tf, ok := p.(ConfigurableTerraformParser); ok { - tf.SetSkipCachedModules(b) - } +func OptionWithSkipCachedModules(b bool) Option { + return func(p *Parser) { + p.skipCachedModules = b } } -func OptionWithConfigsFS(fsys fs.FS) options.ParserOption { - return func(s options.ConfigurableParser) { - if p, ok := s.(ConfigurableTerraformParser); ok { - p.SetConfigsFS(fsys) - } +func OptionWithConfigsFS(fsys fs.FS) Option { + return func(p *Parser) { + p.configsFS = fsys } } diff --git a/pkg/iac/scanners/terraform/parser/parser.go b/pkg/iac/scanners/terraform/parser/parser.go index a5b2b909a462..60940d6c6241 100644 --- a/pkg/iac/scanners/terraform/parser/parser.go +++ b/pkg/iac/scanners/terraform/parser/parser.go @@ -15,11 +15,10 @@ import ( "github.com/hashicorp/hcl/v2/hclparse" "github.com/zclconf/go-cty/cty" - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/ignore" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/terraform" tfcontext "github.com/aquasecurity/trivy/pkg/iac/terraform/context" + "github.com/aquasecurity/trivy/pkg/log" ) type sourceFile struct { @@ -27,8 +26,6 @@ type sourceFile struct { path string } -var _ ConfigurableTerraformParser = (*Parser)(nil) - // Parser is a tool for parsing terraform templates at a given file system location type Parser struct { projectRoot string @@ -44,48 +41,16 @@ type Parser struct { workspaceName string underlying *hclparse.Parser children []*Parser - options []options.ParserOption - debug debug.Logger + options []Option + logger *log.Logger allowDownloads bool skipCachedModules bool fsMap map[string]fs.FS configsFS fs.FS } -func (p *Parser) SetDebugWriter(writer io.Writer) { - p.debug = debug.New(writer, "terraform", "parser", "<"+p.moduleName+">") -} - -func (p *Parser) SetTFVarsPaths(s ...string) { - p.tfvarsPaths = s -} - -func (p *Parser) SetTFVars(vars map[string]cty.Value) { - p.tfvars = vars -} - -func (p *Parser) SetStopOnHCLError(b bool) { - p.stopOnHCLError = b -} - -func (p *Parser) SetWorkspaceName(s string) { - p.workspaceName = s -} - -func (p *Parser) SetAllowDownloads(b bool) { - p.allowDownloads = b -} - -func (p *Parser) SetSkipCachedModules(b bool) { - p.skipCachedModules = b -} - -func (p *Parser) SetConfigsFS(fsys fs.FS) { - p.configsFS = fsys -} - // New creates a new Parser -func New(moduleFS fs.FS, moduleSource string, opts ...options.ParserOption) *Parser { +func New(moduleFS fs.FS, moduleSource string, opts ...Option) *Parser { p := &Parser{ workspaceName: "default", underlying: hclparse.NewParser(), @@ -95,6 +60,7 @@ func New(moduleFS fs.FS, moduleSource string, opts ...options.ParserOption) *Par moduleFS: moduleFS, moduleSource: moduleSource, configsFS: moduleFS, + logger: log.WithPrefix("terraform parser").With("module", "root"), tfvars: make(map[string]cty.Value), } @@ -110,6 +76,7 @@ func (p *Parser) newModuleParser(moduleFS fs.FS, moduleSource, modulePath, modul mp.modulePath = modulePath mp.moduleBlock = moduleBlock mp.moduleName = moduleName + mp.logger = log.WithPrefix("terraform parser").With("module", moduleName) mp.projectRoot = p.projectRoot p.children = append(p.children, mp) for _, option := range p.options { @@ -126,7 +93,7 @@ func (p *Parser) ParseFile(_ context.Context, fullPath string) error { return nil } - p.debug.Log("Parsing '%s'...", fullPath) + p.logger.Debug("Parsing", log.FilePath(fullPath)) f, err := p.moduleFS.Open(filepath.ToSlash(fullPath)) if err != nil { return err @@ -139,7 +106,7 @@ func (p *Parser) ParseFile(_ context.Context, fullPath string) error { } if dir := path.Dir(fullPath); p.projectRoot == "" { - p.debug.Log("Setting project/module root to '%s'", dir) + p.logger.Debug("Setting project/module root", log.FilePath(dir)) p.projectRoot = dir p.modulePath = dir } @@ -160,7 +127,7 @@ func (p *Parser) ParseFile(_ context.Context, fullPath string) error { path: fullPath, }) - p.debug.Log("Added file %s.", fullPath) + p.logger.Debug("Added file", log.FilePath(fullPath)) return nil } @@ -170,13 +137,13 @@ func (p *Parser) ParseFS(ctx context.Context, dir string) error { dir = path.Clean(dir) if p.projectRoot == "" { - p.debug.Log("Setting project/module root to '%s'", dir) + p.logger.Debug("Setting project/module root", log.FilePath(dir)) p.projectRoot = dir p.modulePath = dir } slashed := filepath.ToSlash(dir) - p.debug.Log("Parsing FS from '%s'", slashed) + p.logger.Debug("Parsing FS", log.FilePath(slashed)) fileInfos, err := fs.ReadDir(p.moduleFS, slashed) if err != nil { return err @@ -196,7 +163,7 @@ func (p *Parser) ParseFS(ctx context.Context, dir string) error { if p.stopOnHCLError { return err } - p.debug.Log("error parsing '%s': %s", path, err) + p.logger.Error("Error parsing file", log.FilePath(path), log.Err(err)) continue } } @@ -207,10 +174,10 @@ func (p *Parser) ParseFS(ctx context.Context, dir string) error { var ErrNoFiles = errors.New("no files found") func (p *Parser) Load(ctx context.Context) (*evaluator, error) { - p.debug.Log("Evaluating module...") + p.logger.Debug("Loading module", log.String("module", p.moduleName)) if len(p.files) == 0 { - p.debug.Log("No files found, nothing to do.") + p.logger.Info("No files found, nothing to do.") return nil, ErrNoFiles } @@ -218,31 +185,43 @@ func (p *Parser) Load(ctx context.Context) (*evaluator, error) { if err != nil { return nil, err } - p.debug.Log("Read %d block(s) and %d ignore(s) for module '%s' (%d file[s])...", len(blocks), len(ignores), p.moduleName, len(p.files)) + p.logger.Debug("Read block(s) and ignore(s)", + log.Int("blocks", len(blocks)), log.Int("ignores", len(ignores))) var inputVars map[string]cty.Value switch { case p.moduleBlock != nil: inputVars = p.moduleBlock.Values().AsValueMap() - p.debug.Log("Added %d input variables from module definition.", len(inputVars)) + p.logger.Debug("Added input variables from module definition", + log.Int("count", len(inputVars))) case len(p.tfvars) > 0: inputVars = p.tfvars - p.debug.Log("Added %d input variables from tfvars.", len(inputVars)) + p.logger.Debug("Added input variables from tfvars.", log.Int("count", len(inputVars))) default: inputVars, err = loadTFVars(p.configsFS, p.tfvarsPaths) if err != nil { return nil, err } - p.debug.Log("Added %d variables from tfvars.", len(inputVars)) + p.logger.Debug("Added input variables from tfvars", log.Int("count", len(inputVars))) + + if missingVars := missingVariableValues(blocks, inputVars); len(missingVars) > 0 { + p.logger.Warn( + "Variable values was not found in the environment or variable files. Evaluating may not work correctly.", + log.String("variables", strings.Join(missingVars, ", ")), + ) + } } modulesMetadata, metadataPath, err := loadModuleMetadata(p.moduleFS, p.projectRoot) if err != nil && !errors.Is(err, os.ErrNotExist) { - p.debug.Log("Error loading module metadata: %s.", err) + p.logger.Error("Error loading module metadata", log.Err(err)) } else if err == nil { - p.debug.Log("Loaded module metadata for %d module(s) from %q.", len(modulesMetadata.Modules), metadataPath) + p.logger.Debug("Loaded module metadata for modules", + log.FilePath(metadataPath), + log.Int("count", len(modulesMetadata.Modules)), + ) } workingDir, err := os.Getwd() @@ -250,7 +229,7 @@ func (p *Parser) Load(ctx context.Context) (*evaluator, error) { return nil, err } - p.debug.Log("Working directory for module evaluation is %q", workingDir) + p.logger.Debug("Working directory for module evaluation", log.FilePath(workingDir)) return newEvaluator( p.moduleFS, p, @@ -263,12 +242,25 @@ func (p *Parser) Load(ctx context.Context) (*evaluator, error) { modulesMetadata, p.workspaceName, ignores, - p.debug.Extend("evaluator"), + log.WithPrefix("terraform evaluator"), p.allowDownloads, p.skipCachedModules, ), nil } +func missingVariableValues(blocks terraform.Blocks, inputVars map[string]cty.Value) []string { + var missing []string + for _, varBlock := range blocks.OfType("variable") { + if varBlock.GetAttribute("default") == nil { + if _, ok := inputVars[varBlock.TypeLabel()]; !ok { + missing = append(missing, varBlock.TypeLabel()) + } + } + } + + return missing +} + func (p *Parser) EvaluateAll(ctx context.Context) (terraform.Modules, cty.Value, error) { e, err := p.Load(ctx) @@ -279,7 +271,7 @@ func (p *Parser) EvaluateAll(ctx context.Context) (terraform.Modules, cty.Value, } modules, fsMap := e.EvaluateAll(ctx) - p.debug.Log("Finished parsing module '%s'.", p.moduleName) + p.logger.Debug("Finished parsing module") p.fsMap = fsMap return modules, e.exportOutputs(), nil } @@ -301,7 +293,7 @@ func (p *Parser) readBlocks(files []sourceFile) (terraform.Blocks, ignore.Rules, if p.stopOnHCLError { return nil, nil, err } - p.debug.Log("Encountered HCL parse error: %s", err) + p.logger.Error("Encountered HCL parse error", log.FilePath(file.path), log.Err(err)) continue } for _, fileBlock := range fileBlocks { diff --git a/pkg/iac/scanners/terraform/parser/parser_test.go b/pkg/iac/scanners/terraform/parser/parser_test.go index df06dd2aa393..e3bd817748f6 100644 --- a/pkg/iac/scanners/terraform/parser/parser_test.go +++ b/pkg/iac/scanners/terraform/parser/parser_test.go @@ -1,7 +1,9 @@ package parser import ( + "bytes" "context" + "log/slog" "os" "path/filepath" "sort" @@ -13,8 +15,8 @@ import ( "github.com/zclconf/go-cty/cty" "github.com/aquasecurity/trivy/internal/testutil" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/terraform" + "github.com/aquasecurity/trivy/pkg/log" ) func Test_BasicParsing(t *testing.T) { @@ -172,7 +174,7 @@ output "mod_result" { `, }) - parser := New(fs, "", OptionStopOnHCLError(true), options.ParserWithDebug(os.Stderr)) + parser := New(fs, "", OptionStopOnHCLError(true)) require.NoError(t, parser.ParseFS(context.TODO(), "code")) modules, _, err := parser.EvaluateAll(context.TODO()) @@ -1847,3 +1849,38 @@ resource "something" "blah" { assert.True(t, r2.IsResolvable()) assert.Equal(t, "us-east-2", r2.Value().AsString()) } + +func TestLogAboutMissingVariableValues(t *testing.T) { + var buf bytes.Buffer + slog.SetDefault(slog.New(log.NewHandler(&buf, nil))) + + fsys := fstest.MapFS{ + "main.tf": &fstest.MapFile{ + Data: []byte(` +variable "foo" {} + +variable "bar" { + default = "bar" +} + +variable "baz" {} +`), + }, + "main.tfvars": &fstest.MapFile{ + Data: []byte(`baz = "baz"`), + }, + } + + parser := New( + fsys, "", + OptionStopOnHCLError(true), + OptionWithTFVarsPaths("main.tfvars"), + ) + require.NoError(t, parser.ParseFS(context.TODO(), ".")) + + _, err := parser.Load(context.TODO()) + require.NoError(t, err) + + assert.Contains(t, buf.String(), "Variable values was not found in the environment or variable files.") + assert.Contains(t, buf.String(), "variables=\"foo\"") +} diff --git a/pkg/iac/scanners/terraform/parser/resolvers/cache.go b/pkg/iac/scanners/terraform/parser/resolvers/cache.go index c8b2f660ed33..24f803f60139 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/cache.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/cache.go @@ -8,6 +8,8 @@ import ( "io/fs" "os" "path/filepath" + + "github.com/aquasecurity/trivy/pkg/log" ) type cacheResolver struct{} @@ -42,21 +44,21 @@ func locateCacheDir(cacheDir string) (string, error) { func (r *cacheResolver) Resolve(_ context.Context, _ fs.FS, opt Options) (filesystem fs.FS, prefix, downloadPath string, applies bool, err error) { if opt.SkipCache { - opt.Debug("Cache is disabled.") + opt.Logger.Debug("Module caching is disabled") return nil, "", "", false, nil } cacheFS, err := locateCacheFS(opt.CacheDir) if err != nil { - opt.Debug("No cache filesystem is available on this machine.") + opt.Logger.Debug("No cache filesystem is available on this machine.", log.Err(err)) return nil, "", "", false, nil } src, subdir := splitPackageSubdirRaw(opt.Source) key := cacheKey(src, opt.Version) - opt.Debug("Trying to resolve: %s", key) + opt.Logger.Debug("Trying to resolve module via cache", log.String("key", key)) if info, err := fs.Stat(cacheFS, filepath.ToSlash(key)); err == nil && info.IsDir() { - opt.Debug("Module '%s' resolving via cache...", opt.Name) + opt.Logger.Debug("Module resolved from cache", log.String("key", key)) cacheDir, err := locateCacheDir(opt.CacheDir) if err != nil { return nil, "", "", true, err diff --git a/pkg/iac/scanners/terraform/parser/resolvers/local.go b/pkg/iac/scanners/terraform/parser/resolvers/local.go index eb053741c8ab..a11a294edcfb 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/local.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/local.go @@ -5,6 +5,8 @@ import ( "io/fs" "path" "path/filepath" + + "github.com/aquasecurity/trivy/pkg/log" ) type localResolver struct{} @@ -17,11 +19,15 @@ func (r *localResolver) Resolve(_ context.Context, target fs.FS, opt Options) (f } joined := path.Clean(path.Join(opt.ModulePath, opt.Source)) if _, err := fs.Stat(target, filepath.ToSlash(joined)); err == nil { - opt.Debug("Module '%s' resolved locally to %s", opt.Name, joined) + opt.Logger.Debug("Module resolved locally", + log.String("name", opt.Name), log.FilePath(joined), + ) return target, "", joined, true, nil } clean := path.Clean(opt.Source) - opt.Debug("Module '%s' resolved locally to %s", opt.Name, clean) + opt.Logger.Debug("Module resolved locally", + log.String("name", opt.Name), log.FilePath(clean), + ) return target, "", clean, true, nil } diff --git a/pkg/iac/scanners/terraform/parser/resolvers/options.go b/pkg/iac/scanners/terraform/parser/resolvers/options.go index cdfde6b01bcc..73fd39689e84 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/options.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/options.go @@ -3,12 +3,12 @@ package resolvers import ( "strings" - "github.com/aquasecurity/trivy/pkg/iac/debug" + "github.com/aquasecurity/trivy/pkg/log" ) type Options struct { Source, OriginalSource, Version, OriginalVersion, WorkingDir, Name, ModulePath string - DebugLogger debug.Logger + Logger *log.Logger AllowDownloads bool SkipCache bool RelativePath string @@ -23,7 +23,3 @@ func (o *Options) hasPrefix(prefixes ...string) bool { } return false } - -func (o *Options) Debug(format string, args ...any) { - o.DebugLogger.Log(format, args...) -} diff --git a/pkg/iac/scanners/terraform/parser/resolvers/registry.go b/pkg/iac/scanners/terraform/parser/resolvers/registry.go index 8f2ab2ecdde1..471416463cad 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/registry.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/registry.go @@ -14,6 +14,7 @@ import ( "golang.org/x/net/idna" "github.com/aquasecurity/go-version/pkg/version" + "github.com/aquasecurity/trivy/pkg/log" ) type registryResolver struct { @@ -59,9 +60,11 @@ func (r *registryResolver) Resolve(ctx context.Context, target fs.FS, opt Option token, err = getPrivateRegistryTokenFromEnvVars(hostname) if err == nil { - opt.Debug("Found a token for the registry at %s", hostname) + opt.Logger.Debug("Found a token for the registry", log.String("hostname", hostname)) } else { - opt.Debug(err.Error()) + opt.Logger.Error( + "Failed to find a token for the registry", + log.String("hostname", hostname), log.Err(err)) } } @@ -69,7 +72,8 @@ func (r *registryResolver) Resolve(ctx context.Context, target fs.FS, opt Option if opt.Version != "" { versionUrl := fmt.Sprintf("https://%s/v1/modules/%s/versions", hostname, moduleName) - opt.Debug("Requesting module versions from registry using '%s'...", versionUrl) + opt.Logger.Debug("Requesting module versions from registry using", + log.String("url", versionUrl)) req, err := http.NewRequestWithContext(ctx, http.MethodGet, versionUrl, nil) if err != nil { return nil, "", "", true, err @@ -94,7 +98,8 @@ func (r *registryResolver) Resolve(ctx context.Context, target fs.FS, opt Option if err != nil { return nil, "", "", true, err } - opt.Debug("Found version '%s' for constraint '%s'", opt.Version, inputVersion) + opt.Logger.Debug("Found module version", + log.String("version", opt.Version), log.String("constraint", inputVersion)) } var url string @@ -104,7 +109,7 @@ func (r *registryResolver) Resolve(ctx context.Context, target fs.FS, opt Option url = fmt.Sprintf("https://%s/v1/modules/%s/%s/download", hostname, moduleName, opt.Version) } - opt.Debug("Requesting module source from registry using '%s'...", url) + opt.Logger.Debug("Requesting module source from registry", log.String("url", url)) req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { @@ -145,7 +150,8 @@ func (r *registryResolver) Resolve(ctx context.Context, target fs.FS, opt Option return nil, "", "", true, fmt.Errorf("no source was found for the registry at %s", hostname) } - opt.Debug("Module '%s' resolved via registry to new source: '%s'", opt.Name, opt.Source) + opt.Logger.Debug("Module resolved via registry to new source", + log.String("source", opt.Source), log.String("name", moduleName)) filesystem, prefix, downloadPath, _, err = Remote.Resolve(ctx, target, opt) if err != nil { diff --git a/pkg/iac/scanners/terraform/parser/resolvers/remote.go b/pkg/iac/scanners/terraform/parser/resolvers/remote.go index 790b3509fd33..467f2cee6970 100644 --- a/pkg/iac/scanners/terraform/parser/resolvers/remote.go +++ b/pkg/iac/scanners/terraform/parser/resolvers/remote.go @@ -9,6 +9,8 @@ import ( "sync/atomic" "github.com/hashicorp/go-getter" + + "github.com/aquasecurity/trivy/pkg/log" ) type remoteResolver struct { @@ -20,9 +22,9 @@ var Remote = &remoteResolver{ } func (r *remoteResolver) incrementCount(o Options) { - o.Debug("Incrementing the download counter") + atomic.CompareAndSwapInt32(&r.count, r.count, r.count+1) - o.Debug("Download counter is now %d", r.count) + o.Logger.Debug("Incrementing the download counter", log.Int("count", int(r.count))) } func (r *remoteResolver) GetDownloadCount() int { @@ -40,7 +42,7 @@ func (r *remoteResolver) Resolve(ctx context.Context, _ fs.FS, opt Options) (fil src, subdir := splitPackageSubdirRaw(opt.OriginalSource) key := cacheKey(src, opt.OriginalVersion) - opt.Debug("Storing with cache key %s", key) + opt.Logger.Debug("Caching module", log.String("key", key)) baseCacheDir, err := locateCacheDir(opt.CacheDir) if err != nil { @@ -52,8 +54,10 @@ func (r *remoteResolver) Resolve(ctx context.Context, _ fs.FS, opt Options) (fil } r.incrementCount(opt) - opt.Debug("Successfully downloaded %s from %s", opt.Name, opt.Source) - opt.Debug("Module '%s' resolved via remote download.", opt.Name) + opt.Logger.Debug("Successfully resolve module via remote download", + log.String("name", opt.Name), + log.String("source", opt.Source), + ) return os.DirFS(cacheDir), opt.Source, subdir, true, nil } @@ -68,7 +72,7 @@ func (r *remoteResolver) download(ctx context.Context, opt Options, dst string) // Overwrite the file getter so that a file will be copied getter.Getters["file"] = &getter.FileGetter{Copy: true} - opt.Debug("Downloading %s...", opt.Source) + opt.Logger.Debug("Downloading module", log.String("source", opt.Source)) // Build the client client := &getter.Client{ diff --git a/pkg/iac/scanners/terraform/scanner.go b/pkg/iac/scanners/terraform/scanner.go index 5e7cea83abfd..080d26c0d155 100644 --- a/pkg/iac/scanners/terraform/scanner.go +++ b/pkg/iac/scanners/terraform/scanner.go @@ -11,7 +11,6 @@ import ( "strings" "sync" - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/framework" "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scan" @@ -21,6 +20,7 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/parser" "github.com/aquasecurity/trivy/pkg/iac/terraform" "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" ) var _ scanners.FSScanner = (*Scanner)(nil) @@ -28,17 +28,18 @@ var _ options.ConfigurableScanner = (*Scanner)(nil) var _ ConfigurableTerraformScanner = (*Scanner)(nil) type Scanner struct { - mu sync.Mutex - options []options.ScannerOption - parserOpt []options.ParserOption - executorOpt []executor.Option - dirs map[string]struct{} - forceAllDirs bool - policyDirs []string - policyReaders []io.Reader - regoScanner *rego.Scanner - execLock sync.RWMutex - debug debug.Logger + mu sync.Mutex + logger *log.Logger + options []options.ScannerOption + parserOpt []parser.Option + executorOpt []executor.Option + dirs map[string]struct{} + forceAllDirs bool + policyDirs []string + policyReaders []io.Reader + regoScanner *rego.Scanner + execLock sync.RWMutex + frameworks []framework.Framework spec string loadEmbeddedLibraries bool @@ -76,7 +77,7 @@ func (s *Scanner) SetForceAllDirs(b bool) { s.forceAllDirs = b } -func (s *Scanner) AddParserOptions(opts ...options.ParserOption) { +func (s *Scanner) AddParserOptions(opts ...parser.Option) { s.parserOpt = append(s.parserOpt, opts...) } @@ -88,12 +89,6 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } -func (s *Scanner) SetDebugWriter(writer io.Writer) { - s.parserOpt = append(s.parserOpt, options.ParserWithDebug(writer)) - s.executorOpt = append(s.executorOpt, executor.OptionWithDebugWriter(writer)) - s.debug = debug.New(writer, "terraform", "scanner") -} - func (s *Scanner) SetTraceWriter(_ io.Writer) { } @@ -120,6 +115,7 @@ func New(opts ...options.ScannerOption) *Scanner { s := &Scanner{ dirs: make(map[string]struct{}), options: opts, + logger: log.WithPrefix("terraform scanner"), } for _, opt := range opts { opt(s) @@ -134,8 +130,6 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { return s.regoScanner, nil } regoScanner := rego.NewScanner(types.SourceCloud, s.options...) - regoScanner.SetParentDebugLogger(s.debug) - if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { return nil, err } @@ -152,14 +146,14 @@ type terraformRootModule struct { func (s *Scanner) ScanFS(ctx context.Context, target fs.FS, dir string) (scan.Results, error) { - s.debug.Log("Scanning [%s] at '%s'...", target, dir) + s.logger.Debug("Scanning directory", log.FilePath(dir)) // find directories which directly contain tf files modulePaths := s.findModules(target, dir, dir) sort.Strings(modulePaths) if len(modulePaths) == 0 { - s.debug.Log("no modules found") + s.logger.Info("No modules found, skipping directory", log.FilePath(dir)) return nil, nil } @@ -185,7 +179,7 @@ func (s *Scanner) ScanFS(ctx context.Context, target fs.FS, dir string) (scan.Re // parse all root module directories for _, dir := range rootDirs { - s.debug.Log("Scanning root module '%s'...", dir) + s.logger.Info("Scanning root module", log.FilePath(dir)) p := parser.New(target, "", s.parserOpt...) @@ -295,7 +289,7 @@ func (s *Scanner) findModules(target fs.FS, scanDir string, dirs ...string) []st func (s *Scanner) isRootModule(target fs.FS, dir string) bool { files, err := fs.ReadDir(target, filepath.ToSlash(dir)) if err != nil { - s.debug.Log("failed to read dir '%s' from filesystem [%s]: %s", dir, target, err) + s.logger.Error("Failed to read dir", log.FilePath(dir), log.Err(err)) return false } for _, file := range files { diff --git a/pkg/iac/scanners/terraform/scanner_integration_test.go b/pkg/iac/scanners/terraform/scanner_integration_test.go index 6c60dd8a9f2c..098d6a91d450 100644 --- a/pkg/iac/scanners/terraform/scanner_integration_test.go +++ b/pkg/iac/scanners/terraform/scanner_integration_test.go @@ -1,9 +1,7 @@ package terraform import ( - "bytes" "context" - "fmt" "testing" "github.com/stretchr/testify/assert" @@ -45,10 +43,7 @@ deny[res] { }`, }) - debugLog := bytes.NewBuffer([]byte{}) - scanner := New( - options.ScannerWithDebug(debugLog), options.ScannerWithPolicyFilesystem(fs), options.ScannerWithPolicyDirs("rules"), options.ScannerWithEmbeddedPolicies(false), @@ -62,10 +57,6 @@ deny[res] { require.NoError(t, err) assert.Len(t, results.GetPassed(), 1) - - if t.Failed() { - fmt.Printf("Debug logs:\n%s\n", debugLog.String()) - } } func Test_ScanChildUseRemoteModule(t *testing.T) { @@ -109,10 +100,7 @@ deny[res] { }`, }) - debugLog := bytes.NewBuffer([]byte{}) - scanner := New( - options.ScannerWithDebug(debugLog), options.ScannerWithPolicyFilesystem(fs), options.ScannerWithPolicyDirs("rules"), options.ScannerWithEmbeddedPolicies(false), @@ -126,10 +114,6 @@ deny[res] { require.NoError(t, err) assert.Len(t, results.GetPassed(), 1) - - if t.Failed() { - fmt.Printf("Debug logs:\n%s\n", debugLog.String()) - } } func Test_OptionWithSkipDownloaded(t *testing.T) { diff --git a/pkg/iac/scanners/terraform/scanner_test.go b/pkg/iac/scanners/terraform/scanner_test.go index 20e839ff91ab..5c85995027f4 100644 --- a/pkg/iac/scanners/terraform/scanner_test.go +++ b/pkg/iac/scanners/terraform/scanner_test.go @@ -1,7 +1,6 @@ package terraform import ( - "bytes" "context" "fmt" "strconv" @@ -11,31 +10,10 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/internal/testutil" - "github.com/aquasecurity/trivy/pkg/iac/providers" - "github.com/aquasecurity/trivy/pkg/iac/rules" "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" - "github.com/aquasecurity/trivy/pkg/iac/severity" - "github.com/aquasecurity/trivy/pkg/iac/terraform" ) -var alwaysFailRule = scan.Rule{ - Provider: providers.AWSProvider, - Service: "service", - ShortCode: "abc", - Severity: severity.High, - CustomChecks: scan.CustomChecks{ - Terraform: &scan.TerraformCustomCheck{ - RequiredTypes: []string{}, - RequiredLabels: []string{}, - Check: func(resourceBlock *terraform.Block, _ *terraform.Module) (results scan.Results) { - results.Add("oh no", resourceBlock) - return - }, - }, - }, -} - const emptyBucketRule = ` # METADATA # schemas: @@ -56,33 +34,6 @@ deny[res] { } ` -func scanWithOptions(t *testing.T, code string, opt ...options.ScannerOption) scan.Results { - - fs := testutil.CreateFS(t, map[string]string{ - "project/main.tf": code, - }) - - scanner := New(opt...) - results, err := scanner.ScanFS(context.TODO(), fs, "project") - require.NoError(t, err) - return results -} - -func Test_OptionWithDebugWriter(t *testing.T) { - reg := rules.Register(alwaysFailRule) - defer rules.Deregister(reg) - - buffer := bytes.NewBuffer([]byte{}) - - scannerOpts := []options.ScannerOption{ - options.ScannerWithDebug(buffer), - } - _ = scanWithOptions(t, ` -resource "something" "else" {} -`, scannerOpts...) - require.Positive(t, buffer.Len()) -} - func Test_OptionWithPolicyDirs(t *testing.T) { fs := testutil.CreateFS(t, map[string]string{ @@ -119,9 +70,7 @@ deny[cause] { `, }) - debugLog := bytes.NewBuffer([]byte{}) scanner := New( - options.ScannerWithDebug(debugLog), options.ScannerWithPolicyFilesystem(fs), options.ScannerWithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), @@ -168,10 +117,6 @@ deny[cause] { }, }, actualCode.Lines) - if t.Failed() { - fmt.Printf("Debug logs:\n%s\n", debugLog.String()) - } - } func Test_OptionWithPolicyNamespaces(t *testing.T) { @@ -278,7 +223,6 @@ cause := bucket.name } } assert.Equal(t, test.wantFailure, found) - }) } @@ -320,9 +264,7 @@ deny[cause] { `, }) - debugLog := bytes.NewBuffer([]byte{}) scanner := New( - options.ScannerWithDebug(debugLog), options.ScannerWithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), ) @@ -332,10 +274,6 @@ deny[cause] { require.Len(t, results.GetFailed(), 1) assert.Equal(t, "AVD-TEST-0123", results[0].Rule().AVDID) - - if t.Failed() { - fmt.Printf("Debug logs:\n%s\n", debugLog.String()) - } } func Test_OptionWithRegoOnly_CodeHighlighting(t *testing.T) { @@ -374,9 +312,7 @@ deny[res] { `, }) - debugLog := bytes.NewBuffer([]byte{}) scanner := New( - options.ScannerWithDebug(debugLog), options.ScannerWithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), options.ScannerWithEmbeddedLibraries(true), @@ -388,10 +324,6 @@ deny[res] { require.Len(t, results.GetFailed(), 1) assert.Equal(t, "AVD-TEST-0123", results[0].Rule().AVDID) assert.NotNil(t, results[0].Metadata().Range().GetFS()) - - if t.Failed() { - fmt.Printf("Debug logs:\n%s\n", debugLog.String()) - } } func Test_IAMPolicyRego(t *testing.T) { @@ -448,21 +380,12 @@ deny[res] { `, }) - debugLog := bytes.NewBuffer([]byte{}) scanner := New( - options.ScannerWithDebug(debugLog), - options.ScannerWithTrace(debugLog), options.ScannerWithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), options.ScannerWithEmbeddedLibraries(true), ) - defer func() { - if t.Failed() { - fmt.Printf("Debug logs:\n%s\n", debugLog.String()) - } - }() - results, err := scanner.ScanFS(context.TODO(), fs, "code") require.NoError(t, err) @@ -541,9 +464,7 @@ deny[res] { `, }) - debugLog := bytes.NewBuffer([]byte{}) scanner := New( - options.ScannerWithDebug(debugLog), options.ScannerWithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), options.ScannerWithEmbeddedLibraries(true), @@ -556,9 +477,6 @@ deny[res] { assert.Equal(t, "AVD-TEST-0123", results[0].Rule().AVDID) assert.NotNil(t, results[0].Metadata().Range().GetFS()) - if t.Failed() { - fmt.Printf("Debug logs:\n%s\n", debugLog.String()) - } } func Test_S3_Linking(t *testing.T) { @@ -603,10 +521,7 @@ resource "aws_s3_bucket_public_access_block" "foo" { "code/main.tf": code, }) - debugLog := bytes.NewBuffer([]byte{}) - scanner := New( - options.ScannerWithDebug(debugLog), - ) + scanner := New() results, err := scanner.ScanFS(context.TODO(), fs, "code") require.NoError(t, err) @@ -622,10 +537,6 @@ resource "aws_s3_bucket_public_access_block" "foo" { // versioning assert.NotEqual(t, "AVD-AWS-0090", result.Rule().AVDID) } - - if t.Failed() { - fmt.Printf("Debug logs:\n%s\n", debugLog.String()) - } } func Test_S3_Linking_PublicAccess(t *testing.T) { @@ -673,10 +584,7 @@ resource "aws_s3_bucket_public_access_block" "testB" { "code/main.tf": code, }) - debugLog := bytes.NewBuffer([]byte{}) - scanner := New( - options.ScannerWithDebug(debugLog), - ) + scanner := New() results, err := scanner.ScanFS(context.TODO(), fs, "code") require.NoError(t, err) @@ -686,9 +594,6 @@ resource "aws_s3_bucket_public_access_block" "testB" { assert.NotEqual(t, "AVD-AWS-0094", result.Rule().AVDID) } - if t.Failed() { - fmt.Printf("Debug logs:\n%s\n", debugLog.String()) - } } // PoC for replacing Go with Rego: AVD-AWS-0001 @@ -732,9 +637,7 @@ deny[res] { `, }) - debugLog := bytes.NewBuffer([]byte{}) scanner := New( - options.ScannerWithDebug(debugLog), options.ScannerWithPolicyFilesystem(fs), options.ScannerWithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), @@ -788,11 +691,6 @@ deny[res] { Annotation: "", }, }, actualCode.Lines) - - if t.Failed() { - fmt.Printf("Debug logs:\n%s\n", debugLog.String()) - } - } func Test_OptionWithConfigsFileSystem(t *testing.T) { @@ -814,9 +712,7 @@ bucket_name = "test" `, }) - debugLog := bytes.NewBuffer([]byte{}) scanner := New( - options.ScannerWithDebug(debugLog), options.ScannerWithPolicyDirs("rules"), options.ScannerWithPolicyFilesystem(fs), options.ScannerWithRegoOnly(true), @@ -832,10 +728,6 @@ bucket_name = "test" assert.Len(t, results, 1) assert.Len(t, results.GetPassed(), 1) - - if t.Failed() { - fmt.Printf("Debug logs:\n%s\n", debugLog.String()) - } } func Test_OptionWithConfigsFileSystem_ConfigInCode(t *testing.T) { @@ -854,9 +746,7 @@ bucket_name = "test" `, }) - debugLog := bytes.NewBuffer([]byte{}) scanner := New( - options.ScannerWithDebug(debugLog), options.ScannerWithPolicyDirs("rules"), options.ScannerWithPolicyFilesystem(fs), options.ScannerWithRegoOnly(true), @@ -872,10 +762,6 @@ bucket_name = "test" assert.Len(t, results, 1) assert.Len(t, results.GetPassed(), 1) - - if t.Failed() { - fmt.Printf("Debug logs:\n%s\n", debugLog.String()) - } } func Test_DoNotScanNonRootModules(t *testing.T) { @@ -953,9 +839,7 @@ deny[res] { `, }) - debugLog := bytes.NewBuffer([]byte{}) scanner := New( - options.ScannerWithDebug(debugLog), options.ScannerWithPolicyFilesystem(fs), options.ScannerWithPolicyDirs("rules"), options.ScannerWithEmbeddedPolicies(false), @@ -970,10 +854,6 @@ deny[res] { assert.Len(t, results.GetPassed(), 2) require.Len(t, results.GetFailed(), 1) assert.Equal(t, "AVD-AWS-0002", results.GetFailed()[0].Rule().AVDID) - - if t.Failed() { - fmt.Printf("Debug logs:\n%s\n", debugLog.String()) - } } func Test_RoleRefToOutput(t *testing.T) { @@ -1029,9 +909,7 @@ deny[res] { `, }) - debugLog := bytes.NewBuffer([]byte{}) scanner := New( - options.ScannerWithDebug(debugLog), options.ScannerWithPolicyDirs("rules"), options.ScannerWithPolicyFilesystem(fs), options.ScannerWithRegoOnly(true), @@ -1100,9 +978,7 @@ deny[res] { }`, }) - debugLog := bytes.NewBuffer([]byte{}) scanner := New( - options.ScannerWithDebug(debugLog), options.ScannerWithPolicyDirs("rules"), options.ScannerWithPolicyFilesystem(fs), options.ScannerWithRegoOnly(true), @@ -1121,10 +997,6 @@ deny[res] { require.Len(t, results.GetPassed(), 1) assert.Equal(t, "AVD-AWS-0002", results.GetPassed()[0].Rule().AVDID) - - if t.Failed() { - fmt.Printf("Debug logs:\n%s\n", debugLog.String()) - } } func TestScanModuleWithCount(t *testing.T) { @@ -1170,9 +1042,7 @@ deny[res] { `, }) - debugLog := bytes.NewBuffer([]byte{}) scanner := New( - options.ScannerWithDebug(debugLog), options.ScannerWithPolicyDirs("rules"), options.ScannerWithPolicyFilesystem(fs), options.ScannerWithRegoOnly(true), diff --git a/pkg/iac/scanners/terraformplan/snapshot/scanner_test.go b/pkg/iac/scanners/terraformplan/snapshot/scanner_test.go index 6e7299e19dd1..c7ad3a3b4e0b 100644 --- a/pkg/iac/scanners/terraformplan/snapshot/scanner_test.go +++ b/pkg/iac/scanners/terraformplan/snapshot/scanner_test.go @@ -1,7 +1,6 @@ package snapshot import ( - "bytes" "context" "os" "path" @@ -108,9 +107,7 @@ func Test_ScanFS(t *testing.T) { t.Run(tc.dir, func(t *testing.T) { fs := os.DirFS("testdata") - debugLog := bytes.NewBuffer([]byte{}) scanner := New( - options.ScannerWithDebug(debugLog), options.ScannerWithPolicyDirs(path.Join(tc.dir, "checks")), options.ScannerWithPolicyFilesystem(fs), options.ScannerWithRegoOnly(true), diff --git a/pkg/iac/scanners/terraformplan/tfjson/parser/option.go b/pkg/iac/scanners/terraformplan/tfjson/parser/option.go deleted file mode 100644 index 09e09b97bed5..000000000000 --- a/pkg/iac/scanners/terraformplan/tfjson/parser/option.go +++ /dev/null @@ -1,17 +0,0 @@ -package parser - -import "io" - -type Option func(p *Parser) - -func OptionWithDebugWriter(w io.Writer) Option { - return func(p *Parser) { - p.debugWriter = w - } -} - -func OptionStopOnHCLError(stop bool) Option { - return func(p *Parser) { - p.stopOnHCLError = stop - } -} diff --git a/pkg/iac/scanners/terraformplan/tfjson/parser/parser.go b/pkg/iac/scanners/terraformplan/tfjson/parser/parser.go index 85d565bd307f..a55cfa99384f 100644 --- a/pkg/iac/scanners/terraformplan/tfjson/parser/parser.go +++ b/pkg/iac/scanners/terraformplan/tfjson/parser/parser.go @@ -11,28 +11,17 @@ import ( "github.com/liamg/memoryfs" "github.com/aquasecurity/trivy/pkg/iac/terraform" + "github.com/aquasecurity/trivy/pkg/log" ) type Parser struct { - debugWriter io.Writer - stopOnHCLError bool + logger *log.Logger } -func New(options ...Option) *Parser { - parser := &Parser{} - - for _, o := range options { - o(parser) +func New() *Parser { + return &Parser{ + logger: log.WithPrefix("tfjson parser"), } - return parser -} - -func (p *Parser) SetDebugWriter(writer io.Writer) { - p.debugWriter = writer -} - -func (p *Parser) SetStopOnHCLError(b bool) { - p.stopOnHCLError = b } func (p *Parser) ParseFile(filepath string) (*PlanFile, error) { diff --git a/pkg/iac/scanners/terraformplan/tfjson/scanner.go b/pkg/iac/scanners/terraformplan/tfjson/scanner.go index b390d4d10213..875644d1dd2a 100644 --- a/pkg/iac/scanners/terraformplan/tfjson/scanner.go +++ b/pkg/iac/scanners/terraformplan/tfjson/scanner.go @@ -8,13 +8,13 @@ import ( "github.com/bmatcuk/doublestar/v4" - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/framework" "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" terraformScanner "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform" "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/executor" "github.com/aquasecurity/trivy/pkg/iac/scanners/terraformplan/tfjson/parser" + "github.com/aquasecurity/trivy/pkg/log" ) var tfPlanExts = []string{ @@ -23,10 +23,8 @@ var tfPlanExts = []string{ } type Scanner struct { - parser *parser.Parser - parserOpt []parser.Option - debug debug.Logger - + parser *parser.Parser + logger *log.Logger options []options.ScannerOption spec string executorOpt []executor.Option @@ -69,12 +67,6 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } -func (s *Scanner) SetDebugWriter(writer io.Writer) { - s.parserOpt = append(s.parserOpt, parser.OptionWithDebugWriter(writer)) - s.executorOpt = append(s.executorOpt, executor.OptionWithDebugWriter(writer)) - s.debug = debug.New(writer, "tfplan", "scanner") -} - func (s *Scanner) SetTraceWriter(_ io.Writer) { } @@ -126,17 +118,19 @@ func (s *Scanner) ScanFS(ctx context.Context, inputFS fs.FS, dir string) (scan.R func New(opts ...options.ScannerOption) *Scanner { scanner := &Scanner{ options: opts, + logger: log.WithPrefix("tfjson scanner"), + parser: parser.New(), } for _, o := range opts { o(scanner) } - scanner.parser = parser.New(scanner.parserOpt...) + return scanner } func (s *Scanner) ScanFile(filepath string, fsys fs.FS) (scan.Results, error) { - s.debug.Log("Scanning file %s", filepath) + s.logger.Debug("Scanning file", log.FilePath(filepath)) file, err := fsys.Open(filepath) if err != nil { return nil, err diff --git a/pkg/iac/scanners/terraformplan/tfjson/scanner_test.go b/pkg/iac/scanners/terraformplan/tfjson/scanner_test.go index 8a878e206bb3..678b32e00f48 100644 --- a/pkg/iac/scanners/terraformplan/tfjson/scanner_test.go +++ b/pkg/iac/scanners/terraformplan/tfjson/scanner_test.go @@ -1,9 +1,7 @@ package tfjson import ( - "bytes" "context" - "fmt" "os" "testing" @@ -130,8 +128,7 @@ deny[cause] { "/rules/test.rego": tc.inputRego, }) - debugLog := bytes.NewBuffer([]byte{}) - so := append(tc.options, options.ScannerWithDebug(debugLog), options.ScannerWithPolicyFilesystem(fs)) + so := append(tc.options, options.ScannerWithPolicyFilesystem(fs)) scanner := New(so...) results, err := scanner.ScanFS(context.TODO(), fs, "code") @@ -142,9 +139,6 @@ deny[cause] { failure := results.GetFailed()[0] assert.Equal(t, "AVD-TEST-0123", failure.Rule().AVDID) - if t.Failed() { - fmt.Printf("Debug logs:\n%s\n", debugLog.String()) - } }) } } diff --git a/pkg/iac/scanners/toml/parser/parser.go b/pkg/iac/scanners/toml/parser/parser.go index 6beed83b1908..95444389d74d 100644 --- a/pkg/iac/scanners/toml/parser/parser.go +++ b/pkg/iac/scanners/toml/parser/parser.go @@ -2,33 +2,23 @@ package parser import ( "context" - "io" "io/fs" "path/filepath" "github.com/BurntSushi/toml" - "github.com/aquasecurity/trivy/pkg/iac/debug" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" + "github.com/aquasecurity/trivy/pkg/log" ) -var _ options.ConfigurableParser = (*Parser)(nil) - type Parser struct { - debug debug.Logger -} - -func (p *Parser) SetDebugWriter(writer io.Writer) { - p.debug = debug.New(writer, "toml", "parser") + logger *log.Logger } // New creates a new parser -func New(opts ...options.ParserOption) *Parser { - p := &Parser{} - for _, opt := range opts { - opt(p) +func New() *Parser { + return &Parser{ + logger: log.WithPrefix("toml parser"), } - return p } func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[string]any, error) { @@ -49,7 +39,7 @@ func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[st df, err := p.ParseFile(ctx, target, path) if err != nil { - p.debug.Log("Parse error in '%s': %s", path, err) + p.logger.Error("Parse error", log.FilePath(path), log.Err(err)) return nil } files[path] = df diff --git a/pkg/iac/scanners/toml/scanner.go b/pkg/iac/scanners/toml/scanner.go index b7dc3510da8f..235cc65dada5 100644 --- a/pkg/iac/scanners/toml/scanner.go +++ b/pkg/iac/scanners/toml/scanner.go @@ -6,22 +6,21 @@ import ( "io/fs" "sync" - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/framework" "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/scanners/toml/parser" "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" ) var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { mu sync.Mutex - debug debug.Logger + logger *log.Logger options []options.ScannerOption - parserOptions []options.ParserOption policyDirs []string policyReaders []io.Reader parser *parser.Parser @@ -61,11 +60,6 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } -func (s *Scanner) SetDebugWriter(writer io.Writer) { - s.debug = debug.New(writer, "toml", "scanner") - s.parserOptions = append(s.parserOptions, options.ParserWithDebug(writer)) -} - func (s *Scanner) SetTraceWriter(_ io.Writer) {} func (s *Scanner) SetPerResultTracingEnabled(_ bool) {} @@ -88,11 +82,12 @@ func (s *Scanner) SetRegoErrorLimit(_ int) {} func NewScanner(opts ...options.ScannerOption) *Scanner { s := &Scanner{ options: opts, + logger: log.WithPrefix("toml scanner"), } for _, opt := range opts { opt(s) } - s.parser = parser.New(s.parserOptions...) + s.parser = parser.New() return s } @@ -128,7 +123,7 @@ func (s *Scanner) ScanFile(ctx context.Context, fsys fs.FS, path string) (scan.R if err != nil { return nil, err } - s.debug.Log("Scanning %s...", path) + s.logger.Debug("Scanning", log.FilePath(path)) return s.scanRego(ctx, fsys, rego.Input{ Path: path, Contents: parsed, @@ -142,7 +137,6 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { return s.regoScanner, nil } regoScanner := rego.NewScanner(types.SourceTOML, s.options...) - regoScanner.SetParentDebugLogger(s.debug) if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { return nil, err } diff --git a/pkg/iac/scanners/yaml/parser/parser.go b/pkg/iac/scanners/yaml/parser/parser.go index febcfb100008..9b1f026ae248 100644 --- a/pkg/iac/scanners/yaml/parser/parser.go +++ b/pkg/iac/scanners/yaml/parser/parser.go @@ -9,33 +9,25 @@ import ( "gopkg.in/yaml.v3" - "github.com/aquasecurity/trivy/pkg/iac/debug" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" + "github.com/aquasecurity/trivy/pkg/log" ) -var _ options.ConfigurableParser = (*Parser)(nil) - type Parser struct { - debug debug.Logger -} - -func (p *Parser) SetDebugWriter(writer io.Writer) { - p.debug = debug.New(writer, "yaml", "parser") + logger *log.Logger } -// New creates a new parser -func New(opts ...options.ParserOption) *Parser { - p := &Parser{} - for _, opt := range opts { - opt(p) +// New creates a new YAML parser +func New() *Parser { + return &Parser{ + logger: log.WithPrefix("yaml parser"), } - return p } func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[string][]any, error) { files := make(map[string][]any) if err := fs.WalkDir(target, filepath.ToSlash(path), func(path string, entry fs.DirEntry, err error) error { + select { case <-ctx.Done(): return ctx.Err() @@ -50,7 +42,7 @@ func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[st df, err := p.ParseFile(ctx, target, path) if err != nil { - p.debug.Log("Parse error in '%s': %s", path, err) + p.logger.Error("Parse error", log.FilePath(path), log.Err(err)) return nil } files[path] = df diff --git a/pkg/iac/scanners/yaml/scanner.go b/pkg/iac/scanners/yaml/scanner.go index 3ec508fdd6f5..67b661ee5971 100644 --- a/pkg/iac/scanners/yaml/scanner.go +++ b/pkg/iac/scanners/yaml/scanner.go @@ -6,13 +6,13 @@ import ( "io/fs" "sync" - "github.com/aquasecurity/trivy/pkg/iac/debug" "github.com/aquasecurity/trivy/pkg/iac/framework" "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/scanners/yaml/parser" "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" ) var _ options.ConfigurableScanner = (*Scanner)(nil) @@ -20,8 +20,7 @@ var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { mu sync.Mutex options []options.ScannerOption - parserOptions []options.ParserOption - debug debug.Logger + logger *log.Logger policyDirs []string policyReaders []io.Reader parser *parser.Parser @@ -61,11 +60,6 @@ func (s *Scanner) SetPolicyReaders(readers []io.Reader) { s.policyReaders = readers } -func (s *Scanner) SetDebugWriter(writer io.Writer) { - s.debug = debug.New(writer, "yaml", "scanner") - s.parserOptions = append(s.parserOptions, options.ParserWithDebug(writer)) -} - func (s *Scanner) SetTraceWriter(_ io.Writer) {} func (s *Scanner) SetPerResultTracingEnabled(_ bool) {} @@ -87,11 +81,12 @@ func (s *Scanner) SetRegoErrorLimit(_ int) {} func NewScanner(opts ...options.ScannerOption) *Scanner { s := &Scanner{ options: opts, + logger: log.WithPrefix("yaml scanner"), + parser: parser.New(), } for _, opt := range opts { opt(s) } - s.parser = parser.New(s.parserOptions...) return s } @@ -129,7 +124,7 @@ func (s *Scanner) ScanFile(ctx context.Context, fsys fs.FS, path string) (scan.R if err != nil { return nil, err } - s.debug.Log("Scanning %s...", path) + s.logger.Debug("Scanning", log.String("path", path)) return s.scanRego(ctx, fsys, rego.Input{ Path: path, Contents: parsed, @@ -143,7 +138,6 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { return s.regoScanner, nil } regoScanner := rego.NewScanner(types.SourceYAML, s.options...) - regoScanner.SetParentDebugLogger(s.debug) if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { return nil, err } diff --git a/pkg/log/logger.go b/pkg/log/logger.go index 6eb8bde70dc2..73c4231fd4af 100644 --- a/pkg/log/logger.go +++ b/pkg/log/logger.go @@ -6,7 +6,6 @@ import ( "io" "log/slog" "os" - "strings" "github.com/samber/lo" ) @@ -83,18 +82,3 @@ func Fatal(msg string, args ...any) { slog.Default().Log(context.Background(), LevelFatal, msg, args...) os.Exit(1) } - -// WriteLogger is a wrapper around Logger to implement io.Writer -type WriteLogger struct { - logger *Logger -} - -// NewWriteLogger creates a new WriteLogger -func NewWriteLogger(logger *Logger) *WriteLogger { - return &WriteLogger{logger: logger} -} - -func (l *WriteLogger) Write(p []byte) (n int, err error) { - l.logger.Debug(strings.TrimSpace(string(p))) - return len(p), nil -} diff --git a/pkg/misconf/scanner.go b/pkg/misconf/scanner.go index 5737b3b8d3bc..2e979caba5e9 100644 --- a/pkg/misconf/scanner.go +++ b/pkg/misconf/scanner.go @@ -51,7 +51,6 @@ var enablediacTypes = map[detection.FileType]types.ConfigType{ } type ScannerOption struct { - Debug bool Trace bool RegoOnly bool Namespaces []string @@ -237,10 +236,6 @@ func scannerOptions(t detection.FileType, opt ScannerOption) ([]options.ScannerO options.ScannerWithCustomSchemas(schemas), ) - if opt.Debug { - opts = append(opts, options.ScannerWithDebug(log.NewWriteLogger(log.WithPrefix("misconf")))) - } - if opt.Trace { opts = append(opts, options.ScannerWithPerResultTracing(true)) } From 9ef05fc6b171a264516a025b0b0bcbbc8cff10bc Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 23 Aug 2024 13:43:10 +0600 Subject: [PATCH 036/183] feat(misconf): ignore duplicate checks (#7317) Signed-off-by: nikpivkin --- pkg/iac/rego/embed.go | 28 ++++++++++++++++++---- pkg/iac/rego/embed_test.go | 48 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/pkg/iac/rego/embed.go b/pkg/iac/rego/embed.go index 6f542d9a0b2b..e582508a396b 100644 --- a/pkg/iac/rego/embed.go +++ b/pkg/iac/rego/embed.go @@ -2,6 +2,7 @@ package rego import ( "context" + "fmt" "io/fs" "path/filepath" "strings" @@ -10,6 +11,7 @@ import ( checks "github.com/aquasecurity/trivy-checks" "github.com/aquasecurity/trivy/pkg/iac/rules" + "github.com/aquasecurity/trivy/pkg/log" ) func init() { @@ -47,17 +49,34 @@ func RegisterRegoRules(modules map[string]*ast.Module) { } retriever := NewMetadataRetriever(compiler) + regoCheckIDs := make(map[string]struct{}) + for _, module := range modules { metadata, err := retriever.RetrieveMetadata(ctx, module) if err != nil { + log.Warn("Failed to retrieve metadata", log.String("avdid", metadata.AVDID), log.Err(err)) continue } + if metadata.AVDID == "" { + log.Warn("Check ID is empty", log.FilePath(module.Package.Location.File)) continue } - rules.Register( - metadata.ToRule(), - ) + + if !metadata.Deprecated { + regoCheckIDs[metadata.AVDID] = struct{}{} + } + + rules.Register(metadata.ToRule()) + } + + for _, check := range rules.GetRegistered() { + if !check.Deprecated && check.CanCheck() { + if _, exists := regoCheckIDs[check.AVDID]; exists { + log.Warn("Ignore duplicate Go check", log.String("avdid", check.AVDID)) + rules.Deregister(check) + } + } } } @@ -95,8 +114,7 @@ func LoadPoliciesFromDirs(target fs.FS, paths ...string) (map[string]*ast.Module ProcessAnnotation: true, }) if err != nil { - // s.debug.Log("Failed to load module: %s, err: %s", filepath.ToSlash(path), err.Error()) - return err + return fmt.Errorf("failed to parse Rego module: %w", err) } modules[path] = module return nil diff --git a/pkg/iac/rego/embed_test.go b/pkg/iac/rego/embed_test.go index 15001119a934..5b6368dec2eb 100644 --- a/pkg/iac/rego/embed_test.go +++ b/pkg/iac/rego/embed_test.go @@ -2,6 +2,7 @@ package rego import ( "testing" + "testing/fstest" "github.com/open-policy-agent/opa/ast" "github.com/stretchr/testify/assert" @@ -10,6 +11,7 @@ import ( checks "github.com/aquasecurity/trivy-checks" "github.com/aquasecurity/trivy/pkg/iac/rules" "github.com/aquasecurity/trivy/pkg/iac/scan" + "github.com/aquasecurity/trivy/pkg/iac/state" ) func Test_EmbeddedLoading(t *testing.T) { @@ -204,3 +206,49 @@ deny[res]{ }) } } + +func Test_IgnoreDuplicateChecks(t *testing.T) { + rules.Reset() + + r := scan.Rule{ + AVDID: "TEST001", + Check: func(s *state.State) (results scan.Results) { + for _, bucket := range s.AWS.S3.Buckets { + if bucket.Name.Value() == "evil" { + results.Add("Bucket name should not be evil", bucket.Name) + } + } + return + }, + } + reg := rules.Register(r) + defer rules.Deregister(reg) + + fsys := fstest.MapFS{ + "test.rego": &fstest.MapFile{ + Data: []byte(` +# METADATA +# title: "Test rego" +# scope: package +# schemas: +# - input: schema["cloud"] +# custom: +# avd_id: TEST001 +# severity: LOW +package user.test001 + +deny[res] { + res := result.new("test", {}) +} +`), + }, + } + + modules, err := LoadPoliciesFromDirs(fsys, ".") + require.NoError(t, err) + + RegisterRegoRules(modules) + registered := rules.GetRegistered() + assert.Len(t, registered, 1) + assert.Equal(t, "TEST001", registered[0].AVDID) +} From b65b32ddfa6fc62ac81ad9fa580e1f5a327864f5 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Sat, 24 Aug 2024 01:59:30 +0600 Subject: [PATCH 037/183] fix(misconf): init frameworks before updating them (#7376) Signed-off-by: nikpivkin --- pkg/iac/rego/metadata.go | 3 +++ pkg/iac/rego/metadata_test.go | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/pkg/iac/rego/metadata.go b/pkg/iac/rego/metadata.go index 907b8450bdcb..57602ce97b8c 100644 --- a/pkg/iac/rego/metadata.go +++ b/pkg/iac/rego/metadata.go @@ -54,6 +54,9 @@ func NewStaticMetadata(pkgPath string, inputOpt InputOptions) *StaticMetadata { } func (sm *StaticMetadata) Update(meta map[string]any) error { + if sm.Frameworks == nil { + sm.Frameworks = make(map[framework.Framework][]string) + } upd := func(field *string, key string) { if raw, ok := meta[key]; ok { diff --git a/pkg/iac/rego/metadata_test.go b/pkg/iac/rego/metadata_test.go index 6b4bb9773a92..6535e21c14ac 100644 --- a/pkg/iac/rego/metadata_test.go +++ b/pkg/iac/rego/metadata_test.go @@ -97,6 +97,7 @@ func Test_UpdateStaticMetadata(t *testing.T) { References: []string{"r", "r1_n", "r2_n"}, CloudFormation: &scan.EngineMetadata{}, Terraform: &scan.EngineMetadata{}, + Frameworks: make(map[framework.Framework][]string), } assert.Equal(t, expected, sm) @@ -114,6 +115,7 @@ func Test_UpdateStaticMetadata(t *testing.T) { References: []string{"r", "r1_n", "r2_n"}, CloudFormation: &scan.EngineMetadata{}, Terraform: &scan.EngineMetadata{}, + Frameworks: make(map[framework.Framework][]string), } assert.Equal(t, expected, sm) @@ -131,10 +133,19 @@ func Test_UpdateStaticMetadata(t *testing.T) { Deprecated: true, CloudFormation: &scan.EngineMetadata{}, Terraform: &scan.EngineMetadata{}, + Frameworks: make(map[framework.Framework][]string), } assert.Equal(t, expected, sm) }) + + t.Run("frameworks is not initialized", func(t *testing.T) { + sm := StaticMetadata{} + err := sm.Update(map[string]any{ + "frameworks": map[string]any{"all": []any{"a", "b", "c"}}, + }) + require.NoError(t, err) + }) } func Test_NewEngineMetadata(t *testing.T) { From 2a6c7ab3b338ce4a8f99d6ac3508c2531dcbe812 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Sat, 24 Aug 2024 02:00:09 +0600 Subject: [PATCH 038/183] fix(misconf): support deprecating for Go checks (#7377) Signed-off-by: nikpivkin --- pkg/iac/scanners/azure/arm/scanner.go | 38 ++++++++------ pkg/iac/scanners/cloudformation/scanner.go | 38 ++++++++------ .../scanners/terraform/executor/executor.go | 25 ++++++--- pkg/iac/scanners/terraform/executor/option.go | 6 +++ pkg/iac/scanners/terraform/scanner.go | 5 +- pkg/iac/scanners/terraform/scanner_test.go | 52 +++++++++++++++++++ 6 files changed, 123 insertions(+), 41 deletions(-) diff --git a/pkg/iac/scanners/azure/arm/scanner.go b/pkg/iac/scanners/azure/arm/scanner.go index 66bab2b4f806..e4b3258f823f 100644 --- a/pkg/iac/scanners/azure/arm/scanner.go +++ b/pkg/iac/scanners/azure/arm/scanner.go @@ -25,20 +25,24 @@ var _ scanners.FSScanner = (*Scanner)(nil) var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { - mu sync.Mutex - scannerOptions []options.ScannerOption - logger *log.Logger - frameworks []framework.Framework - regoOnly bool - loadEmbeddedPolicies bool - loadEmbeddedLibraries bool - policyDirs []string - policyReaders []io.Reader - regoScanner *rego.Scanner - spec string -} - -func (s *Scanner) SetIncludeDeprecatedChecks(b bool) {} + mu sync.Mutex + scannerOptions []options.ScannerOption + logger *log.Logger + frameworks []framework.Framework + regoOnly bool + loadEmbeddedPolicies bool + loadEmbeddedLibraries bool + policyDirs []string + policyReaders []io.Reader + regoScanner *rego.Scanner + spec string + includeDeprecatedChecks bool +} + +func (s *Scanner) SetIncludeDeprecatedChecks(b bool) { + s.includeDeprecatedChecks = b +} + func (s *Scanner) SetCustomSchemas(map[string][]byte) {} func (s *Scanner) SetSpec(spec string) { @@ -150,9 +154,11 @@ func (s *Scanner) scanDeployment(ctx context.Context, deployment azure.Deploymen return nil, ctx.Err() default: } - if rule.GetRule().RegoPackage != "" { - continue + + if !s.includeDeprecatedChecks && rule.Deprecated { + continue // skip deprecated checks } + ruleResults := rule.Evaluate(deploymentState) if len(ruleResults) > 0 { results = append(results, ruleResults...) diff --git a/pkg/iac/scanners/cloudformation/scanner.go b/pkg/iac/scanners/cloudformation/scanner.go index 6db08c0d15bb..e7677926944d 100644 --- a/pkg/iac/scanners/cloudformation/scanner.go +++ b/pkg/iac/scanners/cloudformation/scanner.go @@ -48,22 +48,26 @@ var _ scanners.FSScanner = (*Scanner)(nil) var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { - mu sync.Mutex - logger *log.Logger - policyDirs []string - policyReaders []io.Reader - parser *parser.Parser - regoScanner *rego.Scanner - regoOnly bool - loadEmbeddedPolicies bool - loadEmbeddedLibraries bool - options []options.ScannerOption - parserOptions []parser.Option - frameworks []framework.Framework - spec string + mu sync.Mutex + logger *log.Logger + policyDirs []string + policyReaders []io.Reader + parser *parser.Parser + regoScanner *rego.Scanner + regoOnly bool + loadEmbeddedPolicies bool + loadEmbeddedLibraries bool + options []options.ScannerOption + parserOptions []parser.Option + frameworks []framework.Framework + spec string + includeDeprecatedChecks bool +} + +func (s *Scanner) SetIncludeDeprecatedChecks(bool) { + s.includeDeprecatedChecks = true } -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} func (s *Scanner) SetCustomSchemas(map[string][]byte) {} func (s *Scanner) addParserOption(opt parser.Option) { @@ -211,9 +215,11 @@ func (s *Scanner) scanFileContext(ctx context.Context, regoScanner *rego.Scanner return nil, ctx.Err() default: } - if rule.GetRule().RegoPackage != "" { - continue + + if !s.includeDeprecatedChecks && rule.Deprecated { + continue // skip deprecated checks } + evalResult := rule.Evaluate(state) if len(evalResult) > 0 { for _, scanResult := range evalResult { diff --git a/pkg/iac/scanners/terraform/executor/executor.go b/pkg/iac/scanners/terraform/executor/executor.go index c6337a2bfd1d..e7561997305d 100644 --- a/pkg/iac/scanners/terraform/executor/executor.go +++ b/pkg/iac/scanners/terraform/executor/executor.go @@ -5,6 +5,7 @@ import ( "runtime" "sort" + "github.com/samber/lo" "github.com/zclconf/go-cty/cty" adapter "github.com/aquasecurity/trivy/pkg/iac/adapters/terraform" @@ -15,17 +16,19 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/terraform" "github.com/aquasecurity/trivy/pkg/iac/types" + ruleTypes "github.com/aquasecurity/trivy/pkg/iac/types/rules" "github.com/aquasecurity/trivy/pkg/log" ) // Executor scans HCL blocks by running all registered rules against them type Executor struct { - workspaceName string - logger *log.Logger - resultsFilters []func(scan.Results) scan.Results - regoScanner *rego.Scanner - regoOnly bool - frameworks []framework.Framework + workspaceName string + logger *log.Logger + resultsFilters []func(scan.Results) scan.Results + regoScanner *rego.Scanner + regoOnly bool + includeDeprecatedChecks bool + frameworks []framework.Framework } // New creates a new Executor @@ -53,8 +56,14 @@ func (e *Executor) Execute(modules terraform.Modules) (scan.Results, error) { e.logger.Debug("Using max routines", log.Int("count", threads)) - registeredRules := rules.GetRegistered(e.frameworks...) - e.logger.Debug("Initialized rule(s).", log.Int("count", len(registeredRules))) + registeredRules := lo.Filter(rules.GetRegistered(e.frameworks...), func(r ruleTypes.RegisteredRule, _ int) bool { + if !e.includeDeprecatedChecks && r.Deprecated { + return false // skip deprecated checks + } + + return true + }) + e.logger.Debug("Initialized Go check(s).", log.Int("count", len(registeredRules))) pool := NewPool(threads, registeredRules, modules, infra, e.regoScanner, e.regoOnly) diff --git a/pkg/iac/scanners/terraform/executor/option.go b/pkg/iac/scanners/terraform/executor/option.go index d2414878c98f..70dd1a9520c3 100644 --- a/pkg/iac/scanners/terraform/executor/option.go +++ b/pkg/iac/scanners/terraform/executor/option.go @@ -37,3 +37,9 @@ func OptionWithRegoOnly(regoOnly bool) Option { e.regoOnly = regoOnly } } + +func OptionWithIncludeDeprecatedChecks(b bool) Option { + return func(e *Executor) { + e.includeDeprecatedChecks = b + } +} diff --git a/pkg/iac/scanners/terraform/scanner.go b/pkg/iac/scanners/terraform/scanner.go index 080d26c0d155..d01afb8d962e 100644 --- a/pkg/iac/scanners/terraform/scanner.go +++ b/pkg/iac/scanners/terraform/scanner.go @@ -46,7 +46,10 @@ type Scanner struct { loadEmbeddedPolicies bool } -func (s *Scanner) SetIncludeDeprecatedChecks(b bool) {} +func (s *Scanner) SetIncludeDeprecatedChecks(b bool) { + s.executorOpt = append(s.executorOpt, executor.OptionWithIncludeDeprecatedChecks(b)) +} + func (s *Scanner) SetCustomSchemas(map[string][]byte) {} func (s *Scanner) SetSpec(spec string) { diff --git a/pkg/iac/scanners/terraform/scanner_test.go b/pkg/iac/scanners/terraform/scanner_test.go index 5c85995027f4..cd1663ec0eda 100644 --- a/pkg/iac/scanners/terraform/scanner_test.go +++ b/pkg/iac/scanners/terraform/scanner_test.go @@ -10,8 +10,13 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/internal/testutil" + "github.com/aquasecurity/trivy/pkg/iac/providers" + "github.com/aquasecurity/trivy/pkg/iac/rules" "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" + "github.com/aquasecurity/trivy/pkg/iac/severity" + "github.com/aquasecurity/trivy/pkg/iac/state" + "github.com/aquasecurity/trivy/pkg/iac/types" ) const emptyBucketRule = ` @@ -1065,3 +1070,50 @@ deny[res] { occurrences := failed[0].Occurrences() assert.Equal(t, "code/example/main.tf", occurrences[0].Filename) } + +func TestSkipDeprecatedGoChecks(t *testing.T) { + + check := scan.Rule{ + Provider: providers.AWSProvider, + Service: "service", + ShortCode: "abc", + Severity: severity.High, + Check: func(s *state.State) (results scan.Results) { + results.Add("Deny", types.NewTestMetadata()) + return + }, + } + + fsys := testutil.CreateFS(t, map[string]string{ + "main.tf": `resource "foo" "bar" {}`, + }) + + scanner := New( + options.ScannerWithPolicyFilesystem(fsys), + options.ScannerWithEmbeddedLibraries(false), + options.ScannerWithEmbeddedPolicies(false), + ScannerWithAllDirectories(true), + ) + + t.Run("deprecated", func(t *testing.T) { + check.Deprecated = true + reg := rules.Register(check) + defer rules.Deregister(reg) + + results, err := scanner.ScanFS(context.TODO(), fsys, ".") + require.NoError(t, err) + + require.Empty(t, results) + }) + + t.Run("not deprecated", func(t *testing.T) { + check.Deprecated = false + reg := rules.Register(check) + defer rules.Deregister(reg) + + results, err := scanner.ScanFS(context.TODO(), fsys, ".") + require.NoError(t, err) + + require.Len(t, results, 1) + }) +} From e9b43f81e67789b067352fcb6aa55bc9478bc518 Mon Sep 17 00:00:00 2001 From: afdesk Date: Sat, 24 Aug 2024 09:23:29 +0600 Subject: [PATCH 039/183] feat(python): use minimum version for pip packages (#7348) --- docs/docs/coverage/language/python.md | 15 +++++++-- pkg/dependency/parser/python/pip/parse.go | 27 +++++++++++++--- .../parser/python/pip/parse_test.go | 15 ++++++--- .../parser/python/pip/parse_testcase.go | 32 +++++++++++++++++++ .../pip/testdata/requirements_compatible.txt | 5 +++ pkg/fanal/analyzer/language/python/pip/pip.go | 16 ++++++---- 6 files changed, 93 insertions(+), 17 deletions(-) create mode 100644 pkg/dependency/parser/python/pip/testdata/requirements_compatible.txt diff --git a/docs/docs/coverage/language/python.md b/docs/docs/coverage/language/python.md index 7a697b87d250..27b776ec2d75 100644 --- a/docs/docs/coverage/language/python.md +++ b/docs/docs/coverage/language/python.md @@ -23,7 +23,7 @@ The following table provides an outline of the features Trivy offers. | Package manager | File | Transitive dependencies | Dev dependencies | [Dependency graph][dependency-graph] | Position | [Detection Priority][detection-priority] | |-----------------|------------------|:-----------------------:|:----------------:|:------------------------------------:|:--------:|:----------------------------------------:| -| pip | requirements.txt | - | Include | - | ✓ | - | +| pip | requirements.txt | - | Include | - | ✓ | ✓ | | Pipenv | Pipfile.lock | ✓ | Include | - | ✓ | Not needed | | Poetry | poetry.lock | ✓ | Exclude | ✓ | - | Not needed | @@ -42,8 +42,17 @@ Trivy parses your files generated by package managers in filesystem/repository s ### pip #### Dependency detection -Trivy only parses [version specifiers](https://packaging.python.org/en/latest/specifications/version-specifiers/#id5) with `==` comparison operator and without `.*`. -To convert unsupported version specifiers - use the `pip freeze` command. +By default, Trivy only parses [version specifiers](https://packaging.python.org/en/latest/specifications/version-specifiers/#id5) with `==` comparison operator and without `.*`. + +Using the [--detection-priority comprehensive](#detection-priority) option ensures that the tool establishes a minimum version, which is particularly useful in scenarios where identifying the exact version is challenging. +In such case Trivy parses specifiers `>=`,`~=` and a trailing `.*`. + +``` +keyring >= 4.1.1 # Minimum version 4.1.1 +Mopidy-Dirble ~= 1.1 # Minimum version 1.1 +python-gitlab==2.0.* # Minimum version 2.0.0 +``` +Also, there is a way to convert unsupported version specifiers - use the `pip freeze` command. ```bash $ cat requirements.txt diff --git a/pkg/dependency/parser/python/pip/parse.go b/pkg/dependency/parser/python/pip/parse.go index 0d9e040f952b..981b7def69c3 100644 --- a/pkg/dependency/parser/python/pip/parse.go +++ b/pkg/dependency/parser/python/pip/parse.go @@ -25,14 +25,29 @@ const ( ) type Parser struct { - logger *log.Logger + logger *log.Logger + useMinVersion bool } -func NewParser() *Parser { +func NewParser(useMinVersion bool) *Parser { return &Parser{ - logger: log.WithPrefix("pip"), + logger: log.WithPrefix("pip"), + useMinVersion: useMinVersion, } } +func (p *Parser) splitLine(line string) []string { + separators := []string{"~=", ">=", "=="} + // Without useMinVersion check only `==` + if !p.useMinVersion { + separators = []string{"=="} + } + for _, sep := range separators { + if result := strings.Split(line, sep); len(result) == 2 { + return result + } + } + return nil +} func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { // `requirements.txt` can use byte order marks (BOM) @@ -53,10 +68,14 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc line = rStripByKey(line, commentMarker) line = rStripByKey(line, endColon) line = rStripByKey(line, hashMarker) - s := strings.Split(line, "==") + + s := p.splitLine(line) if len(s) != 2 { continue } + if p.useMinVersion && strings.HasSuffix(s[1], ".*") { + s[1] = strings.TrimSuffix(s[1], "*") + "0" + } if !isValidName(s[0]) || !isValidVersion(s[1]) { p.logger.Debug("Invalid package name/version in requirements.txt.", log.String("line", text)) diff --git a/pkg/dependency/parser/python/pip/parse_test.go b/pkg/dependency/parser/python/pip/parse_test.go index 3a13c5272cc8..97964ea77a4a 100644 --- a/pkg/dependency/parser/python/pip/parse_test.go +++ b/pkg/dependency/parser/python/pip/parse_test.go @@ -12,9 +12,10 @@ import ( func TestParse(t *testing.T) { tests := []struct { - name string - filePath string - want []ftypes.Package + name string + filePath string + useMinVersion bool + want []ftypes.Package }{ { name: "happy path", @@ -66,6 +67,12 @@ func TestParse(t *testing.T) { filePath: "testdata/requirements_with_templating_engine.txt", want: nil, }, + { + name: "compatible versions", + filePath: "testdata/requirements_compatible.txt", + useMinVersion: true, + want: requirementsCompatibleVersions, + }, } for _, tt := range tests { @@ -73,7 +80,7 @@ func TestParse(t *testing.T) { f, err := os.Open(tt.filePath) require.NoError(t, err) - got, _, err := NewParser().Parse(f) + got, _, err := NewParser(tt.useMinVersion).Parse(f) require.NoError(t, err) assert.Equal(t, tt.want, got) diff --git a/pkg/dependency/parser/python/pip/parse_testcase.go b/pkg/dependency/parser/python/pip/parse_testcase.go index e8192ee1775d..e4a8d83d7117 100644 --- a/pkg/dependency/parser/python/pip/parse_testcase.go +++ b/pkg/dependency/parser/python/pip/parse_testcase.go @@ -3,6 +3,38 @@ package pip import ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" var ( + requirementsCompatibleVersions = []ftypes.Package{ + { + Name: "keyring", + Version: "4.1.1", + Locations: []ftypes.Location{ + { + StartLine: 1, + EndLine: 1, + }, + }, + }, + { + Name: "Mopidy-Dirble", + Version: "1.1", + Locations: []ftypes.Location{ + { + StartLine: 2, + EndLine: 2, + }, + }, + }, + { + Name: "python-gitlab", + Version: "2.0.0", + Locations: []ftypes.Location{ + { + StartLine: 3, + EndLine: 3, + }, + }, + }, + } requirementsFlask = []ftypes.Package{ { Name: "click", diff --git a/pkg/dependency/parser/python/pip/testdata/requirements_compatible.txt b/pkg/dependency/parser/python/pip/testdata/requirements_compatible.txt new file mode 100644 index 000000000000..dbcde5b7ab10 --- /dev/null +++ b/pkg/dependency/parser/python/pip/testdata/requirements_compatible.txt @@ -0,0 +1,5 @@ +keyring >= 4.1.1 # Minimum version 4.1.1 +Mopidy-Dirble ~= 1.1 # Compatible release. Same as >= 1.1, == 1.* +python-gitlab==2.0.* +django==5.*.* # this dep should be skipped +django==4.*.1 \ No newline at end of file diff --git a/pkg/fanal/analyzer/language/python/pip/pip.go b/pkg/fanal/analyzer/language/python/pip/pip.go index e08a90e7a70b..670dd195bb50 100644 --- a/pkg/fanal/analyzer/language/python/pip/pip.go +++ b/pkg/fanal/analyzer/language/python/pip/pip.go @@ -38,14 +38,16 @@ var pythonExecNames = []string{ } type pipLibraryAnalyzer struct { - logger *log.Logger - metadataParser packaging.Parser + logger *log.Logger + metadataParser packaging.Parser + detectionPriority types.DetectionPriority } -func newPipLibraryAnalyzer(_ analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { +func newPipLibraryAnalyzer(opts analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { return pipLibraryAnalyzer{ - logger: log.WithPrefix("pip"), - metadataParser: *packaging.NewParser(), + logger: log.WithPrefix("pip"), + metadataParser: *packaging.NewParser(), + detectionPriority: opts.DetectionPriority, }, nil } @@ -62,8 +64,10 @@ func (a pipLibraryAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAn return true } + useMinVersion := a.detectionPriority == types.PriorityComprehensive + if err = fsutils.WalkDir(input.FS, ".", required, func(pathPath string, d fs.DirEntry, r io.Reader) error { - app, err := language.Parse(types.Pip, pathPath, r, pip.NewParser()) + app, err := language.Parse(types.Pip, pathPath, r, pip.NewParser(useMinVersion)) if err != nil { return xerrors.Errorf("unable to parse requirements.txt: %w", err) } From 45a962705444e373e634cb0c47d0f83e9804d1db Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Sat, 24 Aug 2024 09:25:48 +0600 Subject: [PATCH 040/183] docs: add pkg flags to config file page (#7370) --- .../references/configuration/config-file.md | 20 +++++++++++++++++++ magefiles/docs.go | 1 + 2 files changed, 21 insertions(+) diff --git a/docs/docs/references/configuration/config-file.md b/docs/docs/references/configuration/config-file.md index 932710f6e2b9..6a54b8e27bdc 100644 --- a/docs/docs/references/configuration/config-file.md +++ b/docs/docs/references/configuration/config-file.md @@ -431,6 +431,26 @@ module: # Same as '--enable-modules' enable-modules: [] +``` +## Package options + +```yaml +pkg: + # Same as '--include-dev-deps' + include-dev-deps: false + + # Same as '--pkg-relationships' + relationships: + - unknown + - root + - direct + - indirect + + # Same as '--pkg-types' + types: + - os + - library + ``` ## Registry options diff --git a/magefiles/docs.go b/magefiles/docs.go index bdb85c5357cb..bfdd7480d2a9 100644 --- a/magefiles/docs.go +++ b/magefiles/docs.go @@ -69,6 +69,7 @@ func generateConfigDocs(filename string) error { flag.NewLicenseFlagGroup(), flag.NewMisconfFlagGroup(), flag.NewModuleFlagGroup(), + flag.NewPackageFlagGroup(), flag.NewRegistryFlagGroup(), flag.NewRegoFlagGroup(), flag.NewReportFlagGroup(), From be861265cafc89787fda09c59b2ef175e3d04204 Mon Sep 17 00:00:00 2001 From: simar7 <1254783+simar7@users.noreply.github.com> Date: Mon, 26 Aug 2024 18:29:10 -0600 Subject: [PATCH 041/183] feat(misconf): Add support for using spec from on-disk bundle (#7179) --- pkg/compliance/spec/compliance.go | 41 +++++++++++++-- pkg/compliance/spec/compliance_test.go | 52 +++++++++++++++++++ .../content/specs/compliance/invalid.yaml | 1 + .../content/specs/compliance/testspec.yaml | 15 ++++++ .../testdata/testcache/policy/metadata.json | 1 + pkg/flag/report_flags.go | 3 +- 6 files changed, 108 insertions(+), 5 deletions(-) create mode 100644 pkg/compliance/spec/testdata/testcache/policy/content/specs/compliance/invalid.yaml create mode 100644 pkg/compliance/spec/testdata/testcache/policy/content/specs/compliance/testspec.yaml create mode 100644 pkg/compliance/spec/testdata/testcache/policy/metadata.json diff --git a/pkg/compliance/spec/compliance.go b/pkg/compliance/spec/compliance.go index 7b0b4f6cffdd..70355eaa926f 100644 --- a/pkg/compliance/spec/compliance.go +++ b/pkg/compliance/spec/compliance.go @@ -3,6 +3,7 @@ package spec import ( "fmt" "os" + "path/filepath" "strings" "github.com/samber/lo" @@ -11,6 +12,7 @@ import ( sp "github.com/aquasecurity/trivy-checks/pkg/spec" iacTypes "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/types" ) @@ -70,18 +72,41 @@ func scannerByCheckID(checkID string) types.Scanner { } } +func checksDir(cacheDir string) string { + return filepath.Join(cacheDir, "policy") +} + +func complianceSpecDir(cacheDir string) string { + return filepath.Join(checksDir(cacheDir), "content", "specs", "compliance") +} + // GetComplianceSpec accepct compliance flag name/path and return builtin or file system loaded spec -func GetComplianceSpec(specNameOrPath string) (ComplianceSpec, error) { +func GetComplianceSpec(specNameOrPath, cacheDir string) (ComplianceSpec, error) { + if specNameOrPath == "" { + return ComplianceSpec{}, nil + } + var b []byte var err error - if strings.HasPrefix(specNameOrPath, "@") { + if strings.HasPrefix(specNameOrPath, "@") { // load user specified spec from disk b, err = os.ReadFile(strings.TrimPrefix(specNameOrPath, "@")) if err != nil { return ComplianceSpec{}, fmt.Errorf("error retrieving compliance spec from path: %w", err) } + log.Debug("Compliance spec loaded from specified path", log.String("path", specNameOrPath)) } else { - // TODO: GetSpecByName() should return []byte - b = []byte(sp.NewSpecLoader().GetSpecByName(specNameOrPath)) + _, err := os.Stat(filepath.Join(checksDir(cacheDir), "metadata.json")) + if err != nil { // cache corrupt or bundle does not exist, load embedded version + b = []byte(sp.NewSpecLoader().GetSpecByName(specNameOrPath)) + log.Debug("Compliance spec loaded from embedded library", log.String("spec", specNameOrPath)) + } else { + // load from bundle on disk + b, err = LoadFromBundle(cacheDir, specNameOrPath) + if err != nil { + return ComplianceSpec{}, err + } + log.Debug("Compliance spec loaded from disk bundle", log.String("spec", specNameOrPath)) + } } var complianceSpec ComplianceSpec @@ -91,3 +116,11 @@ func GetComplianceSpec(specNameOrPath string) (ComplianceSpec, error) { return complianceSpec, nil } + +func LoadFromBundle(cacheDir, specNameOrPath string) ([]byte, error) { + b, err := os.ReadFile(filepath.Join(complianceSpecDir(cacheDir), specNameOrPath+".yaml")) + if err != nil { + return nil, fmt.Errorf("error retrieving compliance spec from bundle %s: %w", specNameOrPath, err) + } + return b, nil +} diff --git a/pkg/compliance/spec/compliance_test.go b/pkg/compliance/spec/compliance_test.go index a4ee4961973e..0b44702b4159 100644 --- a/pkg/compliance/spec/compliance_test.go +++ b/pkg/compliance/spec/compliance_test.go @@ -1,10 +1,12 @@ package spec_test import ( + "path/filepath" "sort" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/compliance/spec" iacTypes "github.com/aquasecurity/trivy/pkg/iac/types" @@ -239,3 +241,53 @@ func TestComplianceSpec_CheckIDs(t *testing.T) { }) } } + +func TestComplianceSpec_LoadFromDiskBundle(t *testing.T) { + + t.Run("load user specified spec from disk", func(t *testing.T) { + cs, err := spec.GetComplianceSpec(filepath.Join("@testdata", "testcache", "policy", "content", "specs", "compliance", "testspec.yaml"), filepath.Join("testdata", "testcache")) + require.NoError(t, err) + assert.Equal(t, spec.ComplianceSpec{Spec: iacTypes.Spec{ + ID: "test-spec-1.2", + Title: "Test Spec", + Description: "This is a test spec", + RelatedResources: []string{ + "https://www.google.ca", + }, + Version: "1.2", + Controls: []iacTypes.Control{ + { + Name: "moar-testing", + Description: "Test needs foo bar baz", + ID: "1.1", + Checks: []iacTypes.SpecCheck{ + {ID: "AVD-TEST-1234"}, + }, + Severity: "LOW", + }, + }, + }}, cs) + }) + + t.Run("load user specified spec from disk fails", func(t *testing.T) { + _, err := spec.GetComplianceSpec("@doesnotexist", "does-not-matter") + assert.Contains(t, err.Error(), "error retrieving compliance spec from path") + }) + + t.Run("bundle does not exist", func(t *testing.T) { + cs, err := spec.GetComplianceSpec("aws-cis-1.2", "does-not-matter") + require.NoError(t, err) + assert.Equal(t, "aws-cis-1.2", cs.Spec.ID) + }) + + t.Run("load spec from disk", func(t *testing.T) { + cs, err := spec.GetComplianceSpec("testspec", filepath.Join("testdata", "testcache")) + require.NoError(t, err) + assert.Equal(t, "test-spec-1.2", cs.Spec.ID) + }) + + t.Run("load spec yaml unmarshal failure", func(t *testing.T) { + _, err := spec.GetComplianceSpec("invalid", filepath.Join("testdata", "testcache")) + assert.Contains(t, err.Error(), "spec yaml decode error") + }) +} diff --git a/pkg/compliance/spec/testdata/testcache/policy/content/specs/compliance/invalid.yaml b/pkg/compliance/spec/testdata/testcache/policy/content/specs/compliance/invalid.yaml new file mode 100644 index 000000000000..29dcba2e15af --- /dev/null +++ b/pkg/compliance/spec/testdata/testcache/policy/content/specs/compliance/invalid.yaml @@ -0,0 +1 @@ +this is not yaml but easier to read \ No newline at end of file diff --git a/pkg/compliance/spec/testdata/testcache/policy/content/specs/compliance/testspec.yaml b/pkg/compliance/spec/testdata/testcache/policy/content/specs/compliance/testspec.yaml new file mode 100644 index 000000000000..ec1f75f52970 --- /dev/null +++ b/pkg/compliance/spec/testdata/testcache/policy/content/specs/compliance/testspec.yaml @@ -0,0 +1,15 @@ +spec: + id: test-spec-1.2 + title: Test Spec + description: This is a test spec + version: "1.2" + relatedResources: + - https://www.google.ca + controls: + - id: "1.1" + name: moar-testing + description: |- + Test needs foo bar baz + checks: + - id: AVD-TEST-1234 + severity: LOW \ No newline at end of file diff --git a/pkg/compliance/spec/testdata/testcache/policy/metadata.json b/pkg/compliance/spec/testdata/testcache/policy/metadata.json new file mode 100644 index 000000000000..ba37beda3850 --- /dev/null +++ b/pkg/compliance/spec/testdata/testcache/policy/metadata.json @@ -0,0 +1 @@ +{"Digest":"sha256:ef2d9ad4fce0f933b20a662004d7e55bf200987c180e7f2cd531af631f408bb3","DownloadedAt":"2024-08-07T20:07:48.917915-06:00"} \ No newline at end of file diff --git a/pkg/flag/report_flags.go b/pkg/flag/report_flags.go index ce833cc1b13e..67d553b65553 100644 --- a/pkg/flag/report_flags.go +++ b/pkg/flag/report_flags.go @@ -9,6 +9,7 @@ import ( "golang.org/x/xerrors" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" + "github.com/aquasecurity/trivy/pkg/cache" "github.com/aquasecurity/trivy/pkg/compliance/spec" "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/result" @@ -260,7 +261,7 @@ func loadComplianceTypes(compliance string) (spec.ComplianceSpec, error) { return spec.ComplianceSpec{}, xerrors.Errorf("unknown compliance : %v", compliance) } - cs, err := spec.GetComplianceSpec(compliance) + cs, err := spec.GetComplianceSpec(compliance, cache.DefaultDir()) if err != nil { return spec.ComplianceSpec{}, xerrors.Errorf("spec loading from file system error: %w", err) } From dd9733e950d3127aa2ac90c45ec7e2b88a2b47ca Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Tue, 27 Aug 2024 08:56:53 +0600 Subject: [PATCH 042/183] fix(report): escape `Message` field in `asff.tpl` template (#7401) --- contrib/asff.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/asff.tpl b/contrib/asff.tpl index d6833a1d7ff1..3cadbb03ce79 100644 --- a/contrib/asff.tpl +++ b/contrib/asff.tpl @@ -108,7 +108,7 @@ "Region": "{{ env "AWS_REGION" }}", "Details": { "Other": { - "Message": "{{ .Message }}", + "Message": "{{ escapeString .Message }}", "Filename": "{{ $target }}", "StartLine": "{{ .CauseMetadata.StartLine }}", "EndLine": "{{ .CauseMetadata.EndLine }}" From 0799770b8827a8276ad0d6d9ac7e0381c286757c Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Wed, 28 Aug 2024 04:07:07 +0600 Subject: [PATCH 043/183] fix(misconf): use module to log when metadata retrieval fails (#7405) Signed-off-by: nikpivkin --- pkg/iac/rego/embed.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/iac/rego/embed.go b/pkg/iac/rego/embed.go index e582508a396b..082870071c90 100644 --- a/pkg/iac/rego/embed.go +++ b/pkg/iac/rego/embed.go @@ -54,11 +54,11 @@ func RegisterRegoRules(modules map[string]*ast.Module) { for _, module := range modules { metadata, err := retriever.RetrieveMetadata(ctx, module) if err != nil { - log.Warn("Failed to retrieve metadata", log.String("avdid", metadata.AVDID), log.Err(err)) + log.Warn("Failed to retrieve metadata", log.String("package", module.Package.String()), log.Err(err)) continue } - if metadata.AVDID == "" { + if !metadata.Library && metadata.AVDID == "" { log.Warn("Check ID is empty", log.FilePath(module.Package.Location.File)) continue } From 44e468603d44b077cc4606327fb3e7d7ca435e05 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Thu, 29 Aug 2024 05:26:02 +0600 Subject: [PATCH 044/183] feat(misconf): support for ignore by nested attributes (#7205) Signed-off-by: nikpivkin --- docs/docs/scanner/misconfiguration/index.md | 7 +- .../scanners/terraform/executor/executor.go | 17 +- pkg/iac/scanners/terraform/ignore_test.go | 163 ++++++++++++++++++ pkg/iac/terraform/block.go | 115 ++++++++++++ 4 files changed, 287 insertions(+), 15 deletions(-) diff --git a/docs/docs/scanner/misconfiguration/index.md b/docs/docs/scanner/misconfiguration/index.md index 7615f3342265..9824936b8e53 100644 --- a/docs/docs/scanner/misconfiguration/index.md +++ b/docs/docs/scanner/misconfiguration/index.md @@ -534,7 +534,7 @@ If you want to ignore multiple resources on different attributes, you can specif #trivy:ignore:aws-ec2-no-public-ingress-sgr[from_port=5432] ``` -You can also ignore a resource on multiple attributes: +You can also ignore a resource on multiple attributes in the same rule: ```tf locals { rules = { @@ -563,10 +563,7 @@ resource "aws_security_group_rule" "example" { } ``` -Checks can also be ignored by nested attributes, but certain restrictions apply: - -- You cannot access an individual block using indexes, for example when working with dynamic blocks. -- Special variables like [each](https://developer.hashicorp.com/terraform/language/meta-arguments/for_each#the-each-object) and [count](https://developer.hashicorp.com/terraform/language/meta-arguments/count#the-count-object) cannot be accessed. +Checks can also be ignored by nested attributes: ```tf #trivy:ignore:*[logging_config.prefix=myprefix] diff --git a/pkg/iac/scanners/terraform/executor/executor.go b/pkg/iac/scanners/terraform/executor/executor.go index e7561997305d..452e47dcc8de 100644 --- a/pkg/iac/scanners/terraform/executor/executor.go +++ b/pkg/iac/scanners/terraform/executor/executor.go @@ -135,26 +135,23 @@ func ignoreByParams(params map[string]string, modules terraform.Modules, m *type if block == nil { return true } - for key, val := range params { - attr, _ := block.GetNestedAttribute(key) - if attr.IsNil() || !attr.Value().IsKnown() { - return false - } - switch attr.Type() { + for key, param := range params { + val := block.GetValueByPath(key) + switch val.Type() { case cty.String: - if !attr.Equals(val) { + if val.AsString() != param { return false } case cty.Number: - bf := attr.Value().AsBigFloat() + bf := val.AsBigFloat() f64, _ := bf.Float64() comparableInt := fmt.Sprintf("%d", int(f64)) comparableFloat := fmt.Sprintf("%f", f64) - if val != comparableInt && val != comparableFloat { + if param != comparableInt && param != comparableFloat { return false } case cty.Bool: - if fmt.Sprintf("%t", attr.IsTrue()) != val { + if fmt.Sprintf("%t", val.True()) != param { return false } default: diff --git a/pkg/iac/scanners/terraform/ignore_test.go b/pkg/iac/scanners/terraform/ignore_test.go index 6183469d5296..4a2cbce14a86 100644 --- a/pkg/iac/scanners/terraform/ignore_test.go +++ b/pkg/iac/scanners/terraform/ignore_test.go @@ -442,6 +442,21 @@ resource "bad" "my-rule" { } } } +`, + assertLength: 0, + }, + { + name: "ignore by indexed dynamic block value", + inputOptions: ` +// trivy:ignore:*[secure_settings.0.enabled=false] +resource "bad" "my-rule" { + dynamic "secure_settings" { + for_each = ["false", "true"] + content { + enabled = secure_settings.value + } + } +} `, assertLength: 0, }, @@ -604,6 +619,154 @@ data "aws_iam_policy_document" "test_policy" { resources = ["*"] # trivy:ignore:aws-iam-enforce-mfa } } +`, + assertLength: 0, + }, + { + name: "ignore by each.value", + inputOptions: ` +// trivy:ignore:*[each.value=false] +resource "bad" "my-rule" { + for_each = toset(["false", "true", "false"]) + secure = each.value +} +`, + assertLength: 0, + }, + { + name: "ignore by nested each.value", + inputOptions: ` +locals { + vms = [ + { + ip_address = "10.0.0.1" + name = "vm-1" + }, + { + ip_address = "10.0.0.2" + name = "vm-2" + } + ] +} +// trivy:ignore:*[each.value.name=vm-2] +resource "bad" "my-rule" { + secure = false + for_each = { for vm in local.vms : vm.name => vm } + ip_address = each.value.ip_address +} +`, + assertLength: 1, + }, + { + name: "ignore resource with `count` meta-argument", + inputOptions: ` +// trivy:ignore:*[count.index=1] +resource "bad" "my-rule" { + count = 2 + secure = false +} +`, + assertLength: 1, + }, + { + name: "invalid index when accessing blocks", + inputOptions: ` +// trivy:ignore:*[ingress.99.port=9090] +// trivy:ignore:*[ingress.-10.port=9090] +resource "bad" "my-rule" { + secure = false + dynamic "ingress" { + for_each = [8080, 9090] + content { + port = ingress.value + } + } +} +`, + assertLength: 1, + }, + { + name: "ignore by list value", + inputOptions: ` +#trivy:ignore:*[someattr.1.Environment=dev] +resource "bad" "my-rule" { + secure = false + someattr = [ + { + Environment = "prod" + }, + { + Environment = "dev" + } + ] +} +`, + assertLength: 0, + }, + { + name: "ignore by list value with invalid index", + inputOptions: ` +#trivy:ignore:*[someattr.-2.Environment=dev] +resource "bad" "my-rule" { + secure = false + someattr = [ + { + Environment = "prod" + }, + { + Environment = "dev" + } + ] +} +`, + assertLength: 1, + }, + { + name: "ignore by object value", + inputOptions: ` +#trivy:ignore:*[tags.Environment=dev] +resource "bad" "my-rule" { + secure = false + tags = { + Environment = "dev" + } +} +`, + assertLength: 0, + }, + { + name: "ignore by object value in block", + inputOptions: ` +#trivy:ignore:*[someblock.tags.Environment=dev] +resource "bad" "my-rule" { + secure = false + someblock { + tags = { + Environment = "dev" + } + } +} +`, + assertLength: 0, + }, + { + name: "ignore by list value in map", + inputOptions: ` +variable "testvar" { + type = map(list(string)) + default = { + server1 = ["web", "dev"] + server2 = ["prod"] + } +} + +#trivy:ignore:*[someblock.someattr.server1.1=dev] +resource "bad" "my-rule" { + secure = false + someblock { + someattr = var.testvar + } +} `, assertLength: 0, }, diff --git a/pkg/iac/terraform/block.go b/pkg/iac/terraform/block.go index 9245ad6c38a8..dbf7352959d0 100644 --- a/pkg/iac/terraform/block.go +++ b/pkg/iac/terraform/block.go @@ -3,6 +3,7 @@ package terraform import ( "fmt" "io/fs" + "strconv" "strings" "github.com/google/uuid" @@ -298,6 +299,120 @@ func (b *Block) GetAttribute(name string) *Attribute { return nil } +// GetValueByPath returns the value of the attribute located at the given path. +// Supports special paths like "count.index," "each.key," and "each.value." +// The path may contain indices, keys and dots (used as separators). +func (b *Block) GetValueByPath(path string) cty.Value { + + if path == "count.index" || path == "each.key" || path == "each.value" { + return b.Context().GetByDot(path) + } + + if restPath, ok := strings.CutPrefix(path, "each.value."); ok { + if restPath == "" { + return cty.NilVal + } + + val := b.Context().GetByDot("each.value") + res, err := getValueByPath(val, strings.Split(restPath, ".")) + if err != nil { + return cty.NilVal + } + return res + } + + attr, restPath := b.getAttributeByPath(path) + + if attr == nil { + return cty.NilVal + } + + if !attr.IsIterable() || len(restPath) == 0 { + return attr.Value() + } + + res, err := getValueByPath(attr.Value(), restPath) + if err != nil { + return cty.NilVal + } + return res +} + +func (b *Block) getAttributeByPath(path string) (*Attribute, []string) { + steps := strings.Split(path, ".") + + if len(steps) == 1 { + return b.GetAttribute(steps[0]), nil + } + + var ( + attribute *Attribute + stepIndex int + ) + + for currentBlock := b; currentBlock != nil && stepIndex < len(steps); { + blocks := currentBlock.GetBlocks(steps[stepIndex]) + var nextBlock *Block + if !hasIndex(steps, stepIndex+1) && len(blocks) > 0 { + // if index is not provided then return the first block for backwards compatibility + nextBlock = blocks[0] + } else if len(blocks) > 1 && stepIndex < len(steps)-2 { + // handling the case when there are multiple blocks with the same name, + // e.g. when using a `dynamic` block + indexVal, err := strconv.Atoi(steps[stepIndex+1]) + if err == nil && indexVal >= 0 && indexVal < len(blocks) { + nextBlock = blocks[indexVal] + stepIndex++ + } + } + + if nextBlock == nil { + attribute = currentBlock.GetAttribute(steps[stepIndex]) + } + + currentBlock = nextBlock + stepIndex++ + } + + return attribute, steps[stepIndex:] +} + +func hasIndex(steps []string, idx int) bool { + if idx < 0 || idx >= len(steps) { + return false + } + _, err := strconv.Atoi(steps[idx]) + return err == nil +} + +func getValueByPath(val cty.Value, path []string) (cty.Value, error) { + var err error + for _, step := range path { + switch valType := val.Type(); { + case valType.IsMapType(): + val, err = cty.IndexStringPath(step).Apply(val) + case valType.IsObjectType(): + val, err = cty.GetAttrPath(step).Apply(val) + case valType.IsListType() || valType.IsTupleType(): + var idx int + idx, err = strconv.Atoi(step) + if err != nil { + return cty.NilVal, fmt.Errorf("index %q is not a number", step) + } + val, err = cty.IndexIntPath(idx).Apply(val) + default: + return cty.NilVal, fmt.Errorf( + "unexpected value type %s for path step %q", + valType.FriendlyName(), step, + ) + } + if err != nil { + return cty.NilVal, err + } + } + return val, nil +} + func (b *Block) GetNestedAttribute(name string) (*Attribute, *Block) { parts := strings.Split(name, ".") From 9d7264af8e85bcc0dba600b8366d0470d455251c Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Thu, 29 Aug 2024 05:51:25 +0600 Subject: [PATCH 045/183] fix(misconf): do not filter Terraform plan JSON by name (#7406) Signed-off-by: nikpivkin --- docs/docs/coverage/iac/index.md | 22 +++--- pkg/iac/detection/detect.go | 16 ++-- .../scanners/terraformplan/tfjson/scanner.go | 38 +++++----- .../terraformplan/tfjson/scanner_test.go | 73 ++++++++----------- .../tfjson/test/testdata/arbitrary_name.json | 1 + 5 files changed, 71 insertions(+), 79 deletions(-) create mode 100644 pkg/iac/scanners/terraformplan/tfjson/test/testdata/arbitrary_name.json diff --git a/docs/docs/coverage/iac/index.md b/docs/docs/coverage/iac/index.md index 963e9b11b8c5..40f0a88023dd 100644 --- a/docs/docs/coverage/iac/index.md +++ b/docs/docs/coverage/iac/index.md @@ -8,17 +8,17 @@ Trivy scans Infrastructure as Code (IaC) files for ## Supported configurations -| Config type | File patterns | -|-------------------------------------|-----------------------------------------------| -| [Kubernetes](kubernetes.md) | \*.yml, \*.yaml, \*.json | -| [Docker](docker.md) | Dockerfile, Containerfile | -| [Terraform](terraform.md) | \*.tf, \*.tf.json, \*.tfvars | -| [Terraform Plan](terraform.md) | tfplan, \*.tfplan, \*.tfplan.json, \*.tf.json | -| [CloudFormation](cloudformation.md) | \*.yml, \*.yaml, \*.json | -| [Azure ARM Template](azure-arm.md) | \*.json | -| [Helm](helm.md) | \*.yaml, \*.tpl, \*.tar.gz, etc. | -| [YAML][json-and-yaml] | \*.yaml, \*.yml | -| [JSON][json-and-yaml] | \*.json | +| Config type | File patterns | +|-------------------------------------|----------------------------------| +| [Kubernetes](kubernetes.md) | \*.yml, \*.yaml, \*.json | +| [Docker](docker.md) | Dockerfile, Containerfile | +| [Terraform](terraform.md) | \*.tf, \*.tf.json, \*.tfvars | +| [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. | +| [YAML][json-and-yaml] | \*.yaml, \*.yml | +| [JSON][json-and-yaml] | \*.json | [misconf]: ../../scanner/misconfiguration/index.md [secret]: ../../scanner/secret.md diff --git a/pkg/iac/detection/detect.go b/pkg/iac/detection/detect.go index fcfab15f83b2..fcaad6a36179 100644 --- a/pkg/iac/detection/detect.go +++ b/pkg/iac/detection/detect.go @@ -88,12 +88,17 @@ func init() { contents := make(map[string]any) err := json.NewDecoder(r).Decode(&contents) - if err == nil { - if _, ok := contents["terraform_version"]; ok { - _, stillOk := contents["format_version"] - return stillOk + if err != nil { + return false + } + + for _, k := range []string{"terraform_version", "format_version"} { + if _, ok := contents[k]; !ok { + return false } } + + return true } return false } @@ -150,8 +155,7 @@ func init() { return false } - return (sniff.Parameters != nil && len(sniff.Parameters) > 0) || - (sniff.Resources != nil && len(sniff.Resources) > 0) + return len(sniff.Parameters) > 0 || len(sniff.Resources) > 0 } matchers[FileTypeDockerfile] = func(name string, _ io.ReadSeeker) bool { diff --git a/pkg/iac/scanners/terraformplan/tfjson/scanner.go b/pkg/iac/scanners/terraformplan/tfjson/scanner.go index 875644d1dd2a..8b16ecb43116 100644 --- a/pkg/iac/scanners/terraformplan/tfjson/scanner.go +++ b/pkg/iac/scanners/terraformplan/tfjson/scanner.go @@ -6,8 +6,6 @@ import ( "io" "io/fs" - "github.com/bmatcuk/doublestar/v4" - "github.com/aquasecurity/trivy/pkg/iac/framework" "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" @@ -17,11 +15,6 @@ import ( "github.com/aquasecurity/trivy/pkg/log" ) -var tfPlanExts = []string{ - "**/*tfplan.json", - "**/*tf.json", -} - type Scanner struct { parser *parser.Parser logger *log.Logger @@ -93,25 +86,32 @@ func (s *Scanner) Name() string { return "Terraform Plan JSON" } -func (s *Scanner) ScanFS(ctx context.Context, inputFS fs.FS, dir string) (scan.Results, error) { - var filesFound []string +func (s *Scanner) ScanFS(ctx context.Context, fsys fs.FS, dir string) (scan.Results, error) { + + var results scan.Results - for _, ext := range tfPlanExts { - files, err := doublestar.Glob(inputFS, ext, doublestar.WithFilesOnly()) + walkFn := func(path string, d fs.DirEntry, err error) error { if err != nil { - return nil, fmt.Errorf("unable to scan for terraform plan files: %w", err) + return err } - filesFound = append(filesFound, files...) - } - var results scan.Results - for _, f := range filesFound { - res, err := s.ScanFile(f, inputFS) + if d.IsDir() { + return nil + } + + res, err := s.ScanFile(path, fsys) if err != nil { - return nil, err + return fmt.Errorf("failed to scan %s: %w", path, err) } + results = append(results, res...) + return nil } + + if err := fs.WalkDir(fsys, dir, walkFn); err != nil { + return nil, err + } + return results, nil } @@ -148,7 +148,7 @@ func (s *Scanner) Scan(reader io.Reader) (scan.Results, error) { planFS, err := planFile.ToFS() if err != nil { - return nil, err + return nil, fmt.Errorf("failed to convert plan to FS: %w", err) } scanner := terraformScanner.New(s.options...) diff --git a/pkg/iac/scanners/terraformplan/tfjson/scanner_test.go b/pkg/iac/scanners/terraformplan/tfjson/scanner_test.go index 678b32e00f48..289147f482dd 100644 --- a/pkg/iac/scanners/terraformplan/tfjson/scanner_test.go +++ b/pkg/iac/scanners/terraformplan/tfjson/scanner_test.go @@ -12,20 +12,7 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) -func Test_TerraformScanner(t *testing.T) { - t.Parallel() - - testCases := []struct { - name string - inputFile string - inputRego string - options []options.ScannerOption - }{ - { - name: "old rego metadata", - inputFile: "test/testdata/plan.json", - inputRego: ` -package defsec.abcdefg +const defaultCheck = `package defsec.abcdefg __rego_metadata__ := { "id": "TEST123", @@ -48,48 +35,40 @@ deny[cause] { bucket := input.aws.s3.buckets[_] bucket.name.value == "tfsec-plan-testing" cause := bucket.name -} -`, +}` + +func Test_TerraformScanner(t *testing.T) { + t.Parallel() + + testCases := []struct { + name string + inputFile string + check string + options []options.ScannerOption + }{ + { + name: "old rego metadata", + inputFile: "test/testdata/plan.json", + check: defaultCheck, options: []options.ScannerOption{ options.ScannerWithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), - options.ScannerWithEmbeddedPolicies(false)}, + }, }, { name: "with user namespace", inputFile: "test/testdata/plan.json", - inputRego: ` -# METADATA -# title: Bad buckets are bad -# description: Bad buckets are bad because they are not good. -# scope: package -# schemas: -# - input: schema["input"] -# custom: -# avd_id: AVD-TEST-0123 -# severity: CRITICAL -# short_code: very-bad-misconfig -# recommended_action: "Fix the s3 bucket" - -package user.foobar.ABC001 - -deny[cause] { - bucket := input.aws.s3.buckets[_] - bucket.name.value == "tfsec-plan-testing" - cause := bucket.name -} -`, + check: defaultCheck, options: []options.ScannerOption{ options.ScannerWithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), - options.ScannerWithEmbeddedPolicies(false), options.ScannerWithPolicyNamespaces("user"), }, }, { name: "with templated plan json", inputFile: "test/testdata/plan_with_template.json", - inputRego: ` + check: ` # METADATA # title: Bad buckets are bad # description: Bad buckets are bad because they are not good. @@ -113,19 +92,27 @@ deny[cause] { options: []options.ScannerOption{ options.ScannerWithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), - options.ScannerWithEmbeddedPolicies(false), + options.ScannerWithPolicyNamespaces("user"), + }, + }, + { + name: "plan with arbitrary name", + inputFile: "test/testdata/arbitrary_name.json", + check: defaultCheck, + options: []options.ScannerOption{ + options.ScannerWithPolicyDirs("rules"), + options.ScannerWithRegoOnly(true), options.ScannerWithPolicyNamespaces("user"), }, }, } for _, tc := range testCases { - tc := tc t.Run(tc.name, func(t *testing.T) { b, _ := os.ReadFile(tc.inputFile) fs := testutil.CreateFS(t, map[string]string{ "/code/main.tfplan.json": string(b), - "/rules/test.rego": tc.inputRego, + "/rules/test.rego": tc.check, }) so := append(tc.options, options.ScannerWithPolicyFilesystem(fs)) diff --git a/pkg/iac/scanners/terraformplan/tfjson/test/testdata/arbitrary_name.json b/pkg/iac/scanners/terraformplan/tfjson/test/testdata/arbitrary_name.json new file mode 100644 index 000000000000..e0109b0325a8 --- /dev/null +++ b/pkg/iac/scanners/terraformplan/tfjson/test/testdata/arbitrary_name.json @@ -0,0 +1 @@ +{"format_version":"1.2","terraform_version":"1.8.1","planned_values":{"root_module":{"resources":[{"address":"aws_s3_bucket.this","mode":"managed","type":"aws_s3_bucket","name":"this","provider_name":"registry.opentofu.org/hashicorp/aws","schema_version":0,"values":{"bucket":"tfsec-plan-testing","force_destroy":false,"tags":null,"timeouts":null},"sensitive_values":{"cors_rule":[],"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"replication_configuration":[],"server_side_encryption_configuration":[],"tags_all":{},"versioning":[],"website":[]}}]}},"resource_drift":[{"address":"aws_security_group.this","mode":"managed","type":"aws_security_group","name":"this","provider_name":"registry.opentofu.org/hashicorp/aws","change":{"actions":["delete"],"before":{"arn":"arn:aws:ec2:us-west-1:145167242158:security-group/sg-0f3ac859864629452","description":"Managed by Terraform","egress":[{"cidr_blocks":[],"description":"","from_port":0,"ipv6_cidr_blocks":[],"prefix_list_ids":[],"protocol":"-1","security_groups":[],"self":false,"to_port":0}],"id":"sg-0f3ac859864629452","ingress":[],"name":"test_sg","name_prefix":"","owner_id":"145167242158","revoke_rules_on_delete":false,"tags":null,"tags_all":{},"timeouts":null,"vpc_id":"vpc-06165c55f5a70fdfa"},"after":null,"after_unknown":{},"before_sensitive":{"egress":[{"cidr_blocks":[],"ipv6_cidr_blocks":[],"prefix_list_ids":[],"security_groups":[]}],"ingress":[],"tags_all":{}},"after_sensitive":false}}],"resource_changes":[{"address":"aws_s3_bucket.this","mode":"managed","type":"aws_s3_bucket","name":"this","provider_name":"registry.opentofu.org/hashicorp/aws","change":{"actions":["create"],"before":null,"after":{"bucket":"tfsec-plan-testing","force_destroy":false,"tags":null,"timeouts":null},"after_unknown":{"acceleration_status":true,"acl":true,"arn":true,"bucket_domain_name":true,"bucket_prefix":true,"bucket_regional_domain_name":true,"cors_rule":true,"grant":true,"hosted_zone_id":true,"id":true,"lifecycle_rule":true,"logging":true,"object_lock_configuration":true,"object_lock_enabled":true,"policy":true,"region":true,"replication_configuration":true,"request_payer":true,"server_side_encryption_configuration":true,"tags_all":true,"versioning":true,"website":true,"website_domain":true,"website_endpoint":true},"before_sensitive":false,"after_sensitive":{"cors_rule":[],"grant":[],"lifecycle_rule":[],"logging":[],"object_lock_configuration":[],"replication_configuration":[],"server_side_encryption_configuration":[],"tags_all":{},"versioning":[],"website":[]}}}],"configuration":{"provider_config":{"aws":{"name":"aws","full_name":"registry.opentofu.org/hashicorp/aws"}},"root_module":{"resources":[{"address":"aws_s3_bucket.this","mode":"managed","type":"aws_s3_bucket","name":"this","provider_config_key":"aws","expressions":{"bucket":{"constant_value":"tfsec-plan-testing"}},"schema_version":0}]}},"timestamp":"2024-08-28T04:27:38Z","errored":false} From 98e136eb7baa2b66f4233d96875c1490144e1594 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Thu, 29 Aug 2024 06:02:05 +0600 Subject: [PATCH 046/183] feat(misconf): port and protocol support for EC2 networks (#7146) Signed-off-by: nikpivkin --- .../cloudformation/aws/ec2/adapt_test.go | 23 ++++++++++--- .../adapters/cloudformation/aws/ec2/nacl.go | 15 +++++++- .../cloudformation/aws/ec2/security_group.go | 19 +++++++++++ pkg/iac/adapters/terraform/aws/ec2/subnet.go | 4 +-- .../adapters/terraform/aws/ec2/subnet_test.go | 2 +- pkg/iac/adapters/terraform/aws/ec2/vpc.go | 34 +++++++++---------- .../adapters/terraform/aws/ec2/vpc_test.go | 24 ++++++++++++- pkg/iac/providers/aws/ec2/vpc.go | 5 +++ .../parser/property_conversion.go | 8 ++++- 9 files changed, 106 insertions(+), 28 deletions(-) diff --git a/pkg/iac/adapters/cloudformation/aws/ec2/adapt_test.go b/pkg/iac/adapters/cloudformation/aws/ec2/adapt_test.go index 01fb201768e9..b218b95a4e99 100644 --- a/pkg/iac/adapters/cloudformation/aws/ec2/adapt_test.go +++ b/pkg/iac/adapters/cloudformation/aws/ec2/adapt_test.go @@ -51,15 +51,15 @@ Resources: SecurityGroupIngress: - IpProtocol: tcp Description: ingress - FromPort: 80 + FromPort: "80" ToPort: 80 CidrIp: 0.0.0.0/0 SecurityGroupEgress: - - IpProtocol: tcp + - IpProtocol: -1 Description: egress FromPort: 80 - ToPort: 80 - CidrIp: 0.0.0.0/0 + ToPort: "80" + CidrIp: "0.0.0.0/0" myNetworkAcl: Type: AWS::EC2::NetworkAcl Properties: @@ -73,6 +73,9 @@ Resources: Protocol: 6 RuleAction: allow CidrBlock: 172.16.0.0/24 + PortRange: + From: 22 + To: "23" myLaunchConfig: Type: AWS::AutoScaling::LaunchConfiguration Properties: @@ -137,6 +140,9 @@ Resources: CIDRs: []types.StringValue{ types.StringTest("0.0.0.0/0"), }, + FromPort: types.IntTest(80), + ToPort: types.IntTest(80), + Protocol: types.StringTest("tcp"), }, }, EgressRules: []ec2.SecurityGroupRule{ @@ -145,6 +151,9 @@ Resources: CIDRs: []types.StringValue{ types.StringTest("0.0.0.0/0"), }, + FromPort: types.IntTest(80), + ToPort: types.IntTest(80), + Protocol: types.StringTest("-1"), }, }, }, @@ -159,6 +168,8 @@ Resources: CIDRs: []types.StringValue{ types.StringTest("172.16.0.0/24"), }, + FromPort: types.IntTest(22), + ToPort: types.IntTest(23), }, }, }, @@ -309,6 +320,8 @@ Resources: CIDRs: []types.StringValue{ types.StringTest("0.0.0.0/0"), }, + FromPort: types.IntTest(-1), + ToPort: types.IntTest(-1), }, }, EgressRules: []ec2.SecurityGroupRule{ @@ -317,6 +330,8 @@ Resources: CIDRs: []types.StringValue{ types.StringTest("0.0.0.0/0"), }, + FromPort: types.IntTest(-1), + ToPort: types.IntTest(-1), }, }, }, diff --git a/pkg/iac/adapters/cloudformation/aws/ec2/nacl.go b/pkg/iac/adapters/cloudformation/aws/ec2/nacl.go index 0f908f78ae08..a91a12569994 100644 --- a/pkg/iac/adapters/cloudformation/aws/ec2/nacl.go +++ b/pkg/iac/adapters/cloudformation/aws/ec2/nacl.go @@ -4,6 +4,7 @@ import ( "strconv" "github.com/aquasecurity/trivy/pkg/iac/providers/aws/ec2" + "github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation/cftypes" "github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation/parser" iacTypes "github.com/aquasecurity/trivy/pkg/iac/types" ) @@ -29,7 +30,8 @@ func getRules(id string, ctx parser.FileContext) (rules []ec2.NetworkACLRule) { Metadata: ruleResource.Metadata(), Type: iacTypes.StringDefault(ec2.TypeIngress, ruleResource.Metadata()), Action: iacTypes.StringDefault(ec2.ActionAllow, ruleResource.Metadata()), - Protocol: iacTypes.String("-1", ruleResource.Metadata()), + FromPort: iacTypes.IntDefault(-1, ruleResource.Metadata()), + ToPort: iacTypes.IntDefault(-1, ruleResource.Metadata()), CIDRs: nil, } @@ -62,6 +64,17 @@ func getRules(id string, ctx parser.FileContext) (rules []ec2.NetworkACLRule) { rule.CIDRs = append(rule.CIDRs, ipv6Cidr.AsStringValue()) } + portRange := ruleResource.GetProperty("PortRange") + fromPort := portRange.GetProperty("From").ConvertTo(cftypes.Int) + if fromPort.IsInt() { + rule.FromPort = fromPort.AsIntValue() + } + + toPort := portRange.GetProperty("To").ConvertTo(cftypes.Int) + if toPort.IsInt() { + rule.ToPort = toPort.AsIntValue() + } + rules = append(rules, rule) } } diff --git a/pkg/iac/adapters/cloudformation/aws/ec2/security_group.go b/pkg/iac/adapters/cloudformation/aws/ec2/security_group.go index 6770062affb2..e85a91cdecb6 100644 --- a/pkg/iac/adapters/cloudformation/aws/ec2/security_group.go +++ b/pkg/iac/adapters/cloudformation/aws/ec2/security_group.go @@ -4,6 +4,7 @@ import ( "github.com/samber/lo" "github.com/aquasecurity/trivy/pkg/iac/providers/aws/ec2" + "github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation/cftypes" "github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation/parser" "github.com/aquasecurity/trivy/pkg/iac/types" ) @@ -75,7 +76,10 @@ func adaptRule(r interface { rule := ec2.SecurityGroupRule{ Metadata: r.Metadata(), Description: r.GetStringProperty("Description"), + FromPort: types.IntDefault(-1, r.Metadata()), + ToPort: types.IntDefault(-1, r.Metadata()), } + v4Cidr := r.GetProperty("CidrIp") if v4Cidr.IsString() && v4Cidr.AsStringValue().IsNotEmpty() { rule.CIDRs = append(rule.CIDRs, types.StringExplicit(v4Cidr.AsString(), v4Cidr.Metadata())) @@ -85,5 +89,20 @@ func adaptRule(r interface { rule.CIDRs = append(rule.CIDRs, types.StringExplicit(v6Cidr.AsString(), v6Cidr.Metadata())) } + fromPort := r.GetProperty("FromPort").ConvertTo(cftypes.Int) + if fromPort.IsInt() { + rule.FromPort = fromPort.AsIntValue() + } + + toPort := r.GetProperty("ToPort").ConvertTo(cftypes.Int) + if toPort.IsInt() { + rule.ToPort = toPort.AsIntValue() + } + + protocol := r.GetProperty("IpProtocol").ConvertTo(cftypes.String) + if protocol.IsString() { + rule.Protocol = protocol.AsStringValue() + } + return rule } diff --git a/pkg/iac/adapters/terraform/aws/ec2/subnet.go b/pkg/iac/adapters/terraform/aws/ec2/subnet.go index 4e4e49c4f59e..41a68eb2832c 100644 --- a/pkg/iac/adapters/terraform/aws/ec2/subnet.go +++ b/pkg/iac/adapters/terraform/aws/ec2/subnet.go @@ -9,13 +9,13 @@ func adaptSubnets(modules terraform.Modules) []ec2.Subnet { var subnets []ec2.Subnet for _, module := range modules { for _, resource := range module.GetResourcesByType("aws_subnet") { - subnets = append(subnets, adaptSubnet(resource, module)) + subnets = append(subnets, adaptSubnet(resource)) } } return subnets } -func adaptSubnet(resource *terraform.Block, module *terraform.Module) ec2.Subnet { +func adaptSubnet(resource *terraform.Block) ec2.Subnet { mapPublicIpOnLaunchAttr := resource.GetAttribute("map_public_ip_on_launch") mapPublicIpOnLaunchVal := mapPublicIpOnLaunchAttr.AsBoolValueOrDefault(false, resource) diff --git a/pkg/iac/adapters/terraform/aws/ec2/subnet_test.go b/pkg/iac/adapters/terraform/aws/ec2/subnet_test.go index c371ef4f504f..33a0a642245a 100644 --- a/pkg/iac/adapters/terraform/aws/ec2/subnet_test.go +++ b/pkg/iac/adapters/terraform/aws/ec2/subnet_test.go @@ -61,7 +61,7 @@ func Test_adaptSubnet(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { modules := tftestutil.CreateModulesFromSource(t, test.terraform, ".tf") - adapted := adaptSubnet(modules.GetBlocks()[0], modules[0]) + adapted := adaptSubnet(modules.GetBlocks()[0]) testutil.AssertDefsecEqual(t, test.expected, adapted) }) } diff --git a/pkg/iac/adapters/terraform/aws/ec2/vpc.go b/pkg/iac/adapters/terraform/aws/ec2/vpc.go index 92ee730e0947..6be6cbaf672d 100644 --- a/pkg/iac/adapters/terraform/aws/ec2/vpc.go +++ b/pkg/iac/adapters/terraform/aws/ec2/vpc.go @@ -72,9 +72,9 @@ func (a *sgAdapter) adaptSecurityGroups(modules terraform.Modules) []ec2.Securit } for _, sgRule := range orphanResources { if sgRule.GetAttribute("type").Equals("ingress") { - orphanage.IngressRules = append(orphanage.IngressRules, adaptSGRule(sgRule, modules)) + orphanage.IngressRules = append(orphanage.IngressRules, adaptSGRule(sgRule)) } else if sgRule.GetAttribute("type").Equals("egress") { - orphanage.EgressRules = append(orphanage.EgressRules, adaptSGRule(sgRule, modules)) + orphanage.EgressRules = append(orphanage.EgressRules, adaptSGRule(sgRule)) } } securityGroups = append(securityGroups, orphanage) @@ -116,21 +116,21 @@ func (a *sgAdapter) adaptSecurityGroup(resource *terraform.Block, module terrafo ingressBlocks := resource.GetBlocks("ingress") for _, ingressBlock := range ingressBlocks { - ingressRules = append(ingressRules, adaptSGRule(ingressBlock, module)) + ingressRules = append(ingressRules, adaptSGRule(ingressBlock)) } egressBlocks := resource.GetBlocks("egress") for _, egressBlock := range egressBlocks { - egressRules = append(egressRules, adaptSGRule(egressBlock, module)) + egressRules = append(egressRules, adaptSGRule(egressBlock)) } rulesBlocks := module.GetReferencingResources(resource, "aws_security_group_rule", "security_group_id") for _, ruleBlock := range rulesBlocks { a.sgRuleIDs.Resolve(ruleBlock.ID()) if ruleBlock.GetAttribute("type").Equals("ingress") { - ingressRules = append(ingressRules, adaptSGRule(ruleBlock, module)) + ingressRules = append(ingressRules, adaptSGRule(ruleBlock)) } else if ruleBlock.GetAttribute("type").Equals("egress") { - egressRules = append(egressRules, adaptSGRule(ruleBlock, module)) + egressRules = append(egressRules, adaptSGRule(ruleBlock)) } } @@ -154,7 +154,7 @@ func (a *sgAdapter) adaptSecurityGroup(resource *terraform.Block, module terrafo } } -func adaptSGRule(resource *terraform.Block, modules terraform.Modules) ec2.SecurityGroupRule { +func adaptSGRule(resource *terraform.Block) ec2.SecurityGroupRule { ruleDescAttr := resource.GetAttribute("description") ruleDescVal := ruleDescAttr.AsStringValueOrDefault("", resource) @@ -162,16 +162,6 @@ func adaptSGRule(resource *terraform.Block, modules terraform.Modules) ec2.Secur cidrBlocks := resource.GetAttribute("cidr_blocks") ipv6cidrBlocks := resource.GetAttribute("ipv6_cidr_blocks") - varBlocks := modules.GetBlocks().OfType("variable") - - for _, vb := range varBlocks { - if cidrBlocks.IsNotNil() && cidrBlocks.ReferencesBlock(vb) { - cidrBlocks = vb.GetAttribute("default") - } - if ipv6cidrBlocks.IsNotNil() && ipv6cidrBlocks.ReferencesBlock(vb) { - ipv6cidrBlocks = vb.GetAttribute("default") - } - } if cidrBlocks.IsNotNil() { cidrs = cidrBlocks.AsStringValues() @@ -185,6 +175,9 @@ func adaptSGRule(resource *terraform.Block, modules terraform.Modules) ec2.Secur Metadata: resource.GetMetadata(), Description: ruleDescVal, CIDRs: cidrs, + FromPort: resource.GetAttribute("from_port").AsIntValueOrDefault(-1, resource), + ToPort: resource.GetAttribute("to_port").AsIntValueOrDefault(-1, resource), + Protocol: resource.GetAttribute("protocol").AsStringValueOrDefault("", resource), } } @@ -203,6 +196,9 @@ func adaptSingleSGRule(resource *terraform.Block) ec2.SecurityGroupRule { Metadata: resource.GetMetadata(), Description: description, CIDRs: cidrs, + FromPort: resource.GetAttribute("from_port").AsIntValueOrDefault(-1, resource), + ToPort: resource.GetAttribute("to_port").AsIntValueOrDefault(-1, resource), + Protocol: resource.GetAttribute("ip_protocol").AsStringValueOrDefault("", resource), } } @@ -236,7 +232,7 @@ func adaptNetworkACLRule(resource *terraform.Block) ec2.NetworkACLRule { actionVal := actionAttr.AsStringValueOrDefault("", resource) protocolAtrr := resource.GetAttribute("protocol") - protocolVal := protocolAtrr.AsStringValueOrDefault("-1", resource) + protocolVal := protocolAtrr.AsStringValueOrDefault("", resource) cidrAttr := resource.GetAttribute("cidr_block") if cidrAttr.IsNotNil() { @@ -253,5 +249,7 @@ func adaptNetworkACLRule(resource *terraform.Block) ec2.NetworkACLRule { Action: actionVal, Protocol: protocolVal, CIDRs: cidrs, + FromPort: resource.GetAttribute("from_port").AsIntValueOrDefault(-1, resource), + ToPort: resource.GetAttribute("to_port").AsIntValueOrDefault(-1, resource), } } diff --git a/pkg/iac/adapters/terraform/aws/ec2/vpc_test.go b/pkg/iac/adapters/terraform/aws/ec2/vpc_test.go index 611f8ca8527d..1acee8146d3e 100644 --- a/pkg/iac/adapters/terraform/aws/ec2/vpc_test.go +++ b/pkg/iac/adapters/terraform/aws/ec2/vpc_test.go @@ -102,6 +102,9 @@ func Test_AdaptVPC(t *testing.T) { CIDRs: []iacTypes.StringValue{ iacTypes.String("4.5.6.7/32", iacTypes.NewTestMetadata()), }, + FromPort: iacTypes.IntTest(80), + ToPort: iacTypes.IntTest(80), + Protocol: iacTypes.StringTest("tcp"), }, { Metadata: iacTypes.NewTestMetadata(), @@ -111,6 +114,9 @@ func Test_AdaptVPC(t *testing.T) { iacTypes.String("1.2.3.4/32", iacTypes.NewTestMetadata()), iacTypes.String("4.5.6.7/32", iacTypes.NewTestMetadata()), }, + FromPort: iacTypes.IntTest(22), + ToPort: iacTypes.IntTest(22), + Protocol: iacTypes.StringTest("tcp"), }, }, @@ -121,6 +127,8 @@ func Test_AdaptVPC(t *testing.T) { CIDRs: []iacTypes.StringValue{ iacTypes.String("1.2.3.4/32", iacTypes.NewTestMetadata()), }, + FromPort: iacTypes.IntTest(-1), + ToPort: iacTypes.IntTest(-1), }, }, }, @@ -137,6 +145,8 @@ func Test_AdaptVPC(t *testing.T) { CIDRs: []iacTypes.StringValue{ iacTypes.String("10.0.0.0/16", iacTypes.NewTestMetadata()), }, + FromPort: iacTypes.IntTest(22), + ToPort: iacTypes.IntTest(22), }, }, IsDefaultRule: iacTypes.Bool(false, iacTypes.NewTestMetadata()), @@ -169,6 +179,8 @@ func Test_AdaptVPC(t *testing.T) { { Metadata: iacTypes.NewTestMetadata(), Description: iacTypes.String("", iacTypes.NewTestMetadata()), + FromPort: iacTypes.IntTest(-1), + ToPort: iacTypes.IntTest(-1), }, }, @@ -176,6 +188,8 @@ func Test_AdaptVPC(t *testing.T) { { Metadata: iacTypes.NewTestMetadata(), Description: iacTypes.String("", iacTypes.NewTestMetadata()), + FromPort: iacTypes.IntTest(-1), + ToPort: iacTypes.IntTest(-1), }, }, }, @@ -188,7 +202,9 @@ func Test_AdaptVPC(t *testing.T) { Metadata: iacTypes.NewTestMetadata(), Type: iacTypes.String("ingress", iacTypes.NewTestMetadata()), Action: iacTypes.String("", iacTypes.NewTestMetadata()), - Protocol: iacTypes.String("-1", iacTypes.NewTestMetadata()), + Protocol: iacTypes.String("", iacTypes.NewTestMetadata()), + FromPort: iacTypes.IntTest(-1), + ToPort: iacTypes.IntTest(-1), }, }, IsDefaultRule: iacTypes.Bool(false, iacTypes.NewTestMetadata()), @@ -252,6 +268,9 @@ resource "aws_vpc_security_group_ingress_rule" "test" { CIDRs: []iacTypes.StringValue{ iacTypes.StringTest("0.0.0.0/0"), }, + Protocol: iacTypes.StringTest("tcp"), + FromPort: iacTypes.IntTest(22), + ToPort: iacTypes.IntTest(22), }, }, EgressRules: []ec2.SecurityGroupRule{ @@ -259,6 +278,9 @@ resource "aws_vpc_security_group_ingress_rule" "test" { CIDRs: []iacTypes.StringValue{ iacTypes.StringTest("0.0.0.0/0"), }, + Protocol: iacTypes.StringTest("-1"), + FromPort: iacTypes.IntTest(-1), + ToPort: iacTypes.IntTest(-1), }, }, }, diff --git a/pkg/iac/providers/aws/ec2/vpc.go b/pkg/iac/providers/aws/ec2/vpc.go index bce7fb4de2a8..d6bff4fe7025 100644 --- a/pkg/iac/providers/aws/ec2/vpc.go +++ b/pkg/iac/providers/aws/ec2/vpc.go @@ -23,6 +23,9 @@ type SecurityGroupRule struct { Metadata iacTypes.Metadata Description iacTypes.StringValue CIDRs []iacTypes.StringValue + Protocol iacTypes.StringValue + FromPort iacTypes.IntValue + ToPort iacTypes.IntValue } type VPC struct { @@ -49,4 +52,6 @@ type NetworkACLRule struct { Action iacTypes.StringValue Protocol iacTypes.StringValue CIDRs []iacTypes.StringValue + FromPort iacTypes.IntValue + ToPort iacTypes.IntValue } diff --git a/pkg/iac/scanners/cloudformation/parser/property_conversion.go b/pkg/iac/scanners/cloudformation/parser/property_conversion.go index d286fa4dd797..35847bb35c5b 100644 --- a/pkg/iac/scanners/cloudformation/parser/property_conversion.go +++ b/pkg/iac/scanners/cloudformation/parser/property_conversion.go @@ -43,6 +43,8 @@ func (p *Property) isConvertableToBool() bool { case cftypes.Int: return p.EqualTo(1) || p.EqualTo(0) + case cftypes.Bool: + return true } return false } @@ -53,7 +55,7 @@ func (p *Property) isConvertableToInt() bool { if _, err := strconv.Atoi(p.AsString()); err == nil { return true } - case cftypes.Bool: + case cftypes.Bool, cftypes.Int: return true } return false @@ -61,6 +63,10 @@ func (p *Property) isConvertableToInt() bool { func (p *Property) ConvertTo(conversionType cftypes.CfType) *Property { + if p.Type() == conversionType { + return p + } + if !p.IsConvertableTo(conversionType) { _, _ = fmt.Fprintf(os.Stderr, "property of type %s cannot be converted to %s\n", p.Type(), conversionType) return p From 344dafd253b2a3ae2695e62525ed9cf8545dc967 Mon Sep 17 00:00:00 2001 From: aasish-r Date: Thu, 29 Aug 2024 15:32:40 +0530 Subject: [PATCH 047/183] chore: fix allow rule of ignoring test files to make it case insensitive (#7415) --- pkg/fanal/secret/builtin-allow-rules.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fanal/secret/builtin-allow-rules.go b/pkg/fanal/secret/builtin-allow-rules.go index 5e02f3241a04..634037fbceec 100644 --- a/pkg/fanal/secret/builtin-allow-rules.go +++ b/pkg/fanal/secret/builtin-allow-rules.go @@ -4,7 +4,7 @@ var builtinAllowRules = []AllowRule{ { ID: "tests", Description: "Avoid test files and paths", - Path: MustCompile(`(^test|\/test|-test|_test|\.test)`), + Path: MustCompile(`(^(?i)test|\/test|-test|_test|\.test)`), }, { ID: "examples", From 391448aba9fcb0a4138225e5ab305e4e6707c603 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:06:05 +0600 Subject: [PATCH 048/183] fix(secret): use only line with secret for long secret lines (#7412) --- pkg/fanal/secret/scanner.go | 4 +-- pkg/fanal/secret/scanner_test.go | 45 ++++++++++++++++++++++++ pkg/fanal/secret/testdata/jwt-secret.txt | 4 +++ 3 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 pkg/fanal/secret/testdata/jwt-secret.txt diff --git a/pkg/fanal/secret/scanner.go b/pkg/fanal/secret/scanner.go index b8591a69228c..98a01f08323e 100644 --- a/pkg/fanal/secret/scanner.go +++ b/pkg/fanal/secret/scanner.go @@ -504,8 +504,8 @@ func findLocation(start, end int, content []byte) (int, int, types.Code, string) } if lineEnd-lineStart > 100 { - lineStart = lo.Ternary(start-30 < 0, 0, start-30) - lineEnd = lo.Ternary(end+20 > len(content), len(content), end+20) + lineStart = lo.Ternary(start-lineStart-30 < 0, lineStart, start-30) + lineEnd = lo.Ternary(end+20 > lineEnd, lineEnd, end+20) } matchLine := string(content[lineStart:lineEnd]) endLineNum := startLineNum + bytes.Count(content[start:end], lineSep) diff --git a/pkg/fanal/secret/scanner_test.go b/pkg/fanal/secret/scanner_test.go index 86d813f4785e..44b5a2458e79 100644 --- a/pkg/fanal/secret/scanner_test.go +++ b/pkg/fanal/secret/scanner_test.go @@ -742,6 +742,42 @@ func TestSecretScanner(t *testing.T) { }, }, } + wantFindingJWT := types.SecretFinding{ + RuleID: "jwt-token", + Category: "JWT", + Title: "JWT token", + Severity: "MEDIUM", + StartLine: 3, + EndLine: 3, + Match: "jwt: ***********************************************************************************************************************************************************", + Code: types.Code{ + Lines: []types.Line{ + { + Number: 1, + Content: "asd", + Highlighted: "asd", + }, + { + Number: 2, + Content: "aaaa", + Highlighted: "aaaa", + }, + { + Number: 3, + Content: "jwt: ***********************************************************************************************************************************************************", + Highlighted: "jwt: ***********************************************************************************************************************************************************", + IsCause: true, + FirstCause: true, + LastCause: true, + }, + { + Number: 4, + Content: "asda", + Highlighted: "asda", + }, + }, + }, + } tests := []struct { name string @@ -822,6 +858,15 @@ func TestSecretScanner(t *testing.T) { Findings: []types.SecretFinding{wantFindingHuggingFace}, }, }, + { + name: "find JWT token", + configPath: filepath.Join("testdata", "config.yaml"), + inputFilePath: filepath.Join("testdata", "jwt-secret.txt"), + want: types.Secret{ + FilePath: filepath.Join("testdata", "jwt-secret.txt"), + Findings: []types.SecretFinding{wantFindingJWT}, + }, + }, { name: "include when keyword found", configPath: filepath.Join("testdata", "config-happy-keywords.yaml"), diff --git a/pkg/fanal/secret/testdata/jwt-secret.txt b/pkg/fanal/secret/testdata/jwt-secret.txt new file mode 100644 index 000000000000..b23e942b3d98 --- /dev/null +++ b/pkg/fanal/secret/testdata/jwt-secret.txt @@ -0,0 +1,4 @@ +asd +aaaa +jwt: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c +asda \ No newline at end of file From 84118d0f3dab190009e9e452519a679702898367 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Thu, 29 Aug 2024 14:09:08 +0400 Subject: [PATCH 049/183] chore: update CODEOWNERS (#7398) Signed-off-by: knqyf263 --- .github/CODEOWNERS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 46f4b5c85c25..9866e518d80f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -15,8 +15,8 @@ pkg/cloud/ @simar7 @nikpivkin pkg/iac/ @simar7 @nikpivkin # Helm chart -helm/trivy/ @chen-keinan +helm/trivy/ @afdesk # Kubernetes scanning -pkg/k8s/ @chen-keinan -docs/docs/target/kubernetes.md @chen-keinan +pkg/k8s/ @afdesk +docs/docs/target/kubernetes.md @afdesk From 4c6e8ca9cc9591799907cc73075f2d740e303b8f Mon Sep 17 00:00:00 2001 From: Ori <59772293+orizerah@users.noreply.github.com> Date: Thu, 29 Aug 2024 15:59:54 +0530 Subject: [PATCH 050/183] feat(server): Make Trivy Server Multiplexer Exported (#7389) --- pkg/rpc/server/listen.go | 4 ++-- pkg/rpc/server/listen_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/rpc/server/listen.go b/pkg/rpc/server/listen.go index 2b6d1288b7ff..f1e39fa1b2f0 100644 --- a/pkg/rpc/server/listen.go +++ b/pkg/rpc/server/listen.go @@ -72,13 +72,13 @@ func (s Server) ListenAndServe(ctx context.Context, serverCache cache.Cache, ski } }() - mux := s.newServeMux(ctx, serverCache, dbUpdateWg, requestWg) + mux := s.NewServeMux(ctx, serverCache, dbUpdateWg, requestWg) log.Infof("Listening %s...", s.addr) return http.ListenAndServe(s.addr, mux) } -func (s Server) newServeMux(ctx context.Context, serverCache cache.Cache, dbUpdateWg, requestWg *sync.WaitGroup) *http.ServeMux { +func (s Server) NewServeMux(ctx context.Context, serverCache cache.Cache, dbUpdateWg, requestWg *sync.WaitGroup) *http.ServeMux { withWaitGroup := func(base http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Stop processing requests during DB update diff --git a/pkg/rpc/server/listen_test.go b/pkg/rpc/server/listen_test.go index fa61e228806c..7f97bdbcb31e 100644 --- a/pkg/rpc/server/listen_test.go +++ b/pkg/rpc/server/listen_test.go @@ -183,7 +183,7 @@ func TestServer_newServeMux(t *testing.T) { defer func() { _ = c.Close() }() s := NewServer("", "", "", tt.args.token, tt.args.tokenHeader, "", nil, ftypes.RegistryOptions{}) - ts := httptest.NewServer(s.newServeMux(context.Background(), c, dbUpdateWg, requestWg)) + ts := httptest.NewServer(s.NewServeMux(context.Background(), c, dbUpdateWg, requestWg)) defer ts.Close() var resp *http.Response @@ -214,7 +214,7 @@ func Test_VersionEndpoint(t *testing.T) { defer func() { _ = c.Close() }() s := NewServer("", "", "testdata/testcache", "", "", "", nil, ftypes.RegistryOptions{}) - ts := httptest.NewServer(s.newServeMux(context.Background(), c, dbUpdateWg, requestWg)) + ts := httptest.NewServer(s.NewServeMux(context.Background(), c, dbUpdateWg, requestWg)) defer ts.Close() resp, err := http.Get(ts.URL + "/version") From 7aea79dd93cfb61453766dbbb2e3fc0fbd317852 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Thu, 29 Aug 2024 14:35:04 +0400 Subject: [PATCH 051/183] feat(report): export modified findings in JSON (#7383) Signed-off-by: knqyf263 --- docs/docs/configuration/filtering.md | 2 +- pkg/report/json.go | 11 +++++++++-- pkg/report/writer.go | 5 +++-- pkg/types/report.go | 4 ++-- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/docs/docs/configuration/filtering.md b/docs/docs/configuration/filtering.md index 030813bd1bce..befcc54180ac 100644 --- a/docs/docs/configuration/filtering.md +++ b/docs/docs/configuration/filtering.md @@ -238,7 +238,7 @@ You can filter the results by To show the suppressed results, use the `--show-suppressed` flag. !!! note - This flag is currently available only in the table format. + It's exported as `ExperimentalModifiedFindings` in the JSON output. ```bash $ trivy image --vex debian11.csaf.vex --ignorefile .trivyignore.yaml --show-suppressed debian:11 diff --git a/pkg/report/json.go b/pkg/report/json.go index 8529b5274560..e51d524d6509 100644 --- a/pkg/report/json.go +++ b/pkg/report/json.go @@ -14,8 +14,9 @@ import ( // JSONWriter implements result Writer type JSONWriter struct { - Output io.Writer - ListAllPkgs bool + Output io.Writer + ListAllPkgs bool + ShowSuppressed bool } // Write writes the results in JSON format @@ -26,6 +27,12 @@ func (jw JSONWriter) Write(_ context.Context, report types.Report) error { report.Results[i].Packages = nil } } + if !jw.ShowSuppressed { + // Delete suppressed findings + for i := range report.Results { + report.Results[i].ModifiedFindings = nil + } + } report.Results = lo.Filter(report.Results, func(r types.Result, _ int) bool { return r.Target != "" || !r.IsEmpty() }) diff --git a/pkg/report/writer.go b/pkg/report/writer.go index 041c9acdfe8e..a5b7ae231599 100644 --- a/pkg/report/writer.go +++ b/pkg/report/writer.go @@ -56,8 +56,9 @@ func Write(ctx context.Context, report types.Report, option flag.Options) (err e } case types.FormatJSON: writer = &JSONWriter{ - Output: output, - ListAllPkgs: option.ListAllPkgs, + Output: output, + ListAllPkgs: option.ListAllPkgs, + ShowSuppressed: option.ShowSuppressed, } case types.FormatGitHub: writer = &github.Writer{ diff --git a/pkg/types/report.go b/pkg/types/report.go index 6937f8ce7960..af364c95a11d 100644 --- a/pkg/types/report.go +++ b/pkg/types/report.go @@ -120,8 +120,8 @@ type Result struct { // ModifiedFindings holds a list of findings that have been modified from their original state. // This can include vulnerabilities that have been marked as ignored, not affected, or have had - // their severity adjusted. It is currently available only in the table format. - ModifiedFindings []ModifiedFinding `json:"-"` + // their severity adjusted. It's still in an experimental stage and may change in the future. + ModifiedFindings []ModifiedFinding `json:"ExperimentalModifiedFindings,omitempty"` } func (r *Result) IsEmpty() bool { From c96dcdd440a14cdd1b01ac473b2c15e4698e387b Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:35:48 +0600 Subject: [PATCH 052/183] fix(sbom): use `NOASSERTION` for licenses fields in SPDX formats (#7403) --- integration/testdata/julia-spdx.json.golden | 12 +++---- pkg/sbom/spdx/marshal.go | 3 +- pkg/sbom/spdx/marshal_test.go | 40 ++++++++++----------- 3 files changed, 28 insertions(+), 27 deletions(-) diff --git a/integration/testdata/julia-spdx.json.golden b/integration/testdata/julia-spdx.json.golden index 8ae4ead23a7d..89a4edb3f287 100644 --- a/integration/testdata/julia-spdx.json.golden +++ b/integration/testdata/julia-spdx.json.golden @@ -31,8 +31,8 @@ "downloadLocation": "NONE", "filesAnalyzed": false, "sourceInfo": "package found in: Manifest.toml", - "licenseConcluded": "NONE", - "licenseDeclared": "NONE", + "licenseConcluded": "NOASSERTION", + "licenseDeclared": "NOASSERTION", "externalRefs": [ { "referenceCategory": "PACKAGE-MANAGER", @@ -54,8 +54,8 @@ "downloadLocation": "NONE", "filesAnalyzed": false, "sourceInfo": "package found in: Manifest.toml", - "licenseConcluded": "NONE", - "licenseDeclared": "NONE", + "licenseConcluded": "NOASSERTION", + "licenseDeclared": "NOASSERTION", "externalRefs": [ { "referenceCategory": "PACKAGE-MANAGER", @@ -77,8 +77,8 @@ "downloadLocation": "NONE", "filesAnalyzed": false, "sourceInfo": "package found in: Manifest.toml", - "licenseConcluded": "NONE", - "licenseDeclared": "NONE", + "licenseConcluded": "NOASSERTION", + "licenseDeclared": "NOASSERTION", "externalRefs": [ { "referenceCategory": "PACKAGE-MANAGER", diff --git a/pkg/sbom/spdx/marshal.go b/pkg/sbom/spdx/marshal.go index 35bd0448aa5d..33952ab41441 100644 --- a/pkg/sbom/spdx/marshal.go +++ b/pkg/sbom/spdx/marshal.go @@ -33,6 +33,7 @@ const ( CreatorOrganization = "aquasecurity" CreatorTool = "trivy" noneField = "NONE" + noAssertionField = "NOASSERTION" ) const ( @@ -378,7 +379,7 @@ func (m *Marshaler) spdxAttributionTexts(c *core.Component) []string { func (m *Marshaler) spdxLicense(c *core.Component) string { if len(c.Licenses) == 0 { - return noneField + return noAssertionField } return NormalizeLicense(c.Licenses) } diff --git a/pkg/sbom/spdx/marshal_test.go b/pkg/sbom/spdx/marshal_test.go index 3cd034803ffc..ef64cf4651d5 100644 --- a/pkg/sbom/spdx/marshal_test.go +++ b/pkg/sbom/spdx/marshal_test.go @@ -217,8 +217,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageDownloadLocation: "NONE", PackageName: "actioncontroller", PackageVersion: "7.0.1", - PackageLicenseConcluded: "NONE", - PackageLicenseDeclared: "NONE", + PackageLicenseConcluded: "NOASSERTION", + PackageLicenseDeclared: "NOASSERTION", PackageAttributionTexts: []string{ "PkgType: bundler", }, @@ -238,8 +238,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageDownloadLocation: "NONE", PackageName: "actionpack", PackageVersion: "7.0.1", - PackageLicenseConcluded: "NONE", - PackageLicenseDeclared: "NONE", + PackageLicenseConcluded: "NOASSERTION", + PackageLicenseDeclared: "NOASSERTION", PackageAttributionTexts: []string{ "PkgType: bundler", }, @@ -259,8 +259,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageDownloadLocation: "NONE", PackageName: "actionpack", PackageVersion: "7.0.1", - PackageLicenseConcluded: "NONE", - PackageLicenseDeclared: "NONE", + PackageLicenseConcluded: "NOASSERTION", + PackageLicenseDeclared: "NOASSERTION", PackageAttributionTexts: []string{ "PkgType: bundler", }, @@ -536,8 +536,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageDownloadLocation: "NONE", PackageName: "actionpack", PackageVersion: "7.0.1", - PackageLicenseConcluded: "NONE", - PackageLicenseDeclared: "NONE", + PackageLicenseConcluded: "NOASSERTION", + PackageLicenseDeclared: "NOASSERTION", PackageExternalReferences: []*spdx.PackageExternalReference{ { Category: tspdx.CategoryPackageManager, @@ -561,8 +561,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageDownloadLocation: "NONE", PackageName: "actionpack", PackageVersion: "7.0.1", - PackageLicenseConcluded: "NONE", - PackageLicenseDeclared: "NONE", + PackageLicenseConcluded: "NOASSERTION", + PackageLicenseDeclared: "NOASSERTION", PackageExternalReferences: []*spdx.PackageExternalReference{ { Category: tspdx.CategoryPackageManager, @@ -750,8 +750,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageDownloadLocation: "NONE", PackageName: "actioncable", PackageVersion: "6.1.4.1", - PackageLicenseConcluded: "NONE", - PackageLicenseDeclared: "NONE", + PackageLicenseConcluded: "NOASSERTION", + PackageLicenseDeclared: "NOASSERTION", PackageExternalReferences: []*spdx.PackageExternalReference{ { Category: tspdx.CategoryPackageManager, @@ -771,8 +771,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageDownloadLocation: "NONE", PackageName: "com.example:example", PackageVersion: "1.0.0", - PackageLicenseConcluded: "NONE", - PackageLicenseDeclared: "NONE", + PackageLicenseConcluded: "NOASSERTION", + PackageLicenseDeclared: "NOASSERTION", PackageExternalReferences: []*spdx.PackageExternalReference{ { Category: tspdx.CategoryPackageManager, @@ -889,8 +889,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageDownloadLocation: "NONE", PackageName: "org.apache.logging.log4j:log4j-core", PackageVersion: "2.17.0", - PackageLicenseConcluded: "NONE", - PackageLicenseDeclared: "NONE", + PackageLicenseConcluded: "NOASSERTION", + PackageLicenseDeclared: "NOASSERTION", PackageExternalReferences: []*spdx.PackageExternalReference{ { Category: tspdx.CategoryPackageManager, @@ -1229,8 +1229,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageSPDXIdentifier: spdx.ElementID("Package-b1c3b9e2363f5ff7"), PackageDownloadLocation: "NONE", PackageName: "./private_repos/cnrm.googlesource.com/cnrm/", - PackageLicenseConcluded: "NONE", - PackageLicenseDeclared: "NONE", + PackageLicenseConcluded: "NOASSERTION", + PackageLicenseDeclared: "NOASSERTION", PrimaryPackagePurpose: tspdx.PackagePurposeLibrary, PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion}, PackageSourceInfo: "package found in: /usr/local/bin/test", @@ -1243,8 +1243,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageDownloadLocation: "NONE", PackageName: "golang.org/x/crypto", PackageVersion: "v0.0.1", - PackageLicenseConcluded: "NONE", - PackageLicenseDeclared: "NONE", + PackageLicenseConcluded: "NOASSERTION", + PackageLicenseDeclared: "NOASSERTION", PackageExternalReferences: []*spdx.PackageExternalReference{ { Category: tspdx.CategoryPackageManager, From a5aa63eff7e229744090f9ad300c1bec3259397e Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Thu, 29 Aug 2024 20:34:33 +0600 Subject: [PATCH 053/183] fix(misconf): do not register Rego libs in checks registry (#7420) Signed-off-by: nikpivkin --- pkg/iac/rego/embed.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pkg/iac/rego/embed.go b/pkg/iac/rego/embed.go index 082870071c90..fddc069d9283 100644 --- a/pkg/iac/rego/embed.go +++ b/pkg/iac/rego/embed.go @@ -58,8 +58,10 @@ func RegisterRegoRules(modules map[string]*ast.Module) { continue } - if !metadata.Library && metadata.AVDID == "" { - log.Warn("Check ID is empty", log.FilePath(module.Package.Location.File)) + if metadata.AVDID == "" { + if !metadata.Library { + log.Warn("Check ID is empty", log.FilePath(module.Package.Location.File)) + } continue } From 39c80248bcafd296e0bb6712113da3abe70e4ce2 Mon Sep 17 00:00:00 2001 From: simar7 <1254783+simar7@users.noreply.github.com> Date: Fri, 30 Aug 2024 00:17:54 -0600 Subject: [PATCH 054/183] chore(deps): Bump trivy-checks (#7417) Signed-off-by: nikpivkin Co-authored-by: nikpivkin --- go.mod | 2 +- go.sum | 4 +- pkg/fanal/artifact/local/fs_test.go | 112 ++++-------------- pkg/iac/rego/load.go | 5 + pkg/iac/rego/metadata.go | 60 +++++++--- pkg/iac/rego/metadata_test.go | 16 +-- .../scanners/cloudformation/scanner_test.go | 4 +- pkg/iac/scanners/dockerfile/scanner_test.go | 27 ++--- pkg/iac/scanners/json/scanner_test.go | 4 +- pkg/iac/scanners/kubernetes/scanner_test.go | 8 +- .../terraformplan/tfjson/test/scanner_test.go | 2 +- pkg/iac/scanners/toml/scanner_test.go | 4 +- pkg/iac/scanners/yaml/scanner_test.go | 4 +- 13 files changed, 112 insertions(+), 140 deletions(-) diff --git a/go.mod b/go.mod index 230470d8f12c..844135ff79f8 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/aquasecurity/table v1.8.0 github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8 github.com/aquasecurity/tml v0.6.1 - github.com/aquasecurity/trivy-checks v0.13.1-0.20240809030752-558fcff75807 + github.com/aquasecurity/trivy-checks v0.13.1-0.20240830035934-7761a83288cd github.com/aquasecurity/trivy-db v0.0.0-20240718084044-d23a6ca8ba04 github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20240707095038-0300bc49b68b diff --git a/go.sum b/go.sum index 860b788ae605..e760459b4d51 100644 --- a/go.sum +++ b/go.sum @@ -348,8 +348,8 @@ github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8 h1:b43UVqY github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8/go.mod h1:wXA9k3uuaxY3yu7gxrxZDPo/04FEMJtwyecdAlYrEIo= github.com/aquasecurity/tml v0.6.1 h1:y2ZlGSfrhnn7t4ZJ/0rotuH+v5Jgv6BDDO5jB6A9gwo= github.com/aquasecurity/tml v0.6.1/go.mod h1:OnYMWY5lvI9ejU7yH9LCberWaaTBW7hBFsITiIMY2yY= -github.com/aquasecurity/trivy-checks v0.13.1-0.20240809030752-558fcff75807 h1:yw2INXrbfekt1yHDQAlNZlHIUZQXMcSS+mWI9XWJUN0= -github.com/aquasecurity/trivy-checks v0.13.1-0.20240809030752-558fcff75807/go.mod h1:Xec/SMVGV66I7RgUqOX9MEr+YxBqHXDVLTYmpspPi3E= +github.com/aquasecurity/trivy-checks v0.13.1-0.20240830035934-7761a83288cd h1:/6sPLCU4JICPPYAmY2iUsLGpgYBXUH6M/0fy57AhNWY= +github.com/aquasecurity/trivy-checks v0.13.1-0.20240830035934-7761a83288cd/go.mod h1:zLBeXaTJkAvPZqKiRACAsP49ZywCEXFEjXMLa8kmc8Q= github.com/aquasecurity/trivy-db v0.0.0-20240718084044-d23a6ca8ba04 h1:6/T8sFdNVG/AwOGoK6X55h7hF7LYqK8bsuPz8iEz8jM= github.com/aquasecurity/trivy-db v0.0.0-20240718084044-d23a6ca8ba04/go.mod h1:0T6oy2t1Iedt+yi3Ml5cpOYp5FZT4MI1/mx+3p+PIs8= github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 h1:JVgBIuIYbwG+ekC5lUHUpGJboPYiCcxiz06RCtz8neI= diff --git a/pkg/fanal/artifact/local/fs_test.go b/pkg/fanal/artifact/local/fs_test.go index ba6d2879bda2..dbef68e893bb 100644 --- a/pkg/fanal/artifact/local/fs_test.go +++ b/pkg/fanal/artifact/local/fs_test.go @@ -299,15 +299,6 @@ func TestTerraformMisconfigurationScan(t *testing.T) { fields: fields{ dir: "./testdata/misconfig/terraform/single-failure", }, - artifactOpt: artifact.Option{ - MisconfScannerOption: misconf.ScannerOption{ - RegoOnly: true, - Namespaces: []string{"user"}, - PolicyPaths: []string{"./testdata/misconfig/terraform/rego"}, - DisableEmbeddedPolicies: true, - DisableEmbeddedLibraries: true, - }, - }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ BlobIDAnything: true, @@ -352,15 +343,6 @@ func TestTerraformMisconfigurationScan(t *testing.T) { fields: fields{ dir: "./testdata/misconfig/terraform/multiple-failures", }, - artifactOpt: artifact.Option{ - MisconfScannerOption: misconf.ScannerOption{ - RegoOnly: true, - Namespaces: []string{"user"}, - PolicyPaths: []string{"./testdata/misconfig/terraform/rego"}, - DisableEmbeddedPolicies: true, - DisableEmbeddedLibraries: true, - }, - }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ BlobIDAnything: true, @@ -437,13 +419,6 @@ func TestTerraformMisconfigurationScan(t *testing.T) { fields: fields{ dir: "./testdata/misconfig/terraform/no-results", }, - artifactOpt: artifact.Option{ - MisconfScannerOption: misconf.ScannerOption{ - RegoOnly: true, - Namespaces: []string{"user"}, - PolicyPaths: []string{"./testdata/misconfig/terraform/rego"}, - }, - }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ BlobIDAnything: true, @@ -467,15 +442,6 @@ func TestTerraformMisconfigurationScan(t *testing.T) { fields: fields{ dir: "./testdata/misconfig/terraform/passed", }, - artifactOpt: artifact.Option{ - MisconfScannerOption: misconf.ScannerOption{ - RegoOnly: true, - Namespaces: []string{"user"}, - PolicyPaths: []string{"./testdata/misconfig/terraform/rego"}, - DisableEmbeddedPolicies: true, - DisableEmbeddedLibraries: true, - }, - }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ BlobIDAnything: true, @@ -516,15 +482,6 @@ func TestTerraformMisconfigurationScan(t *testing.T) { fields: fields{ dir: "./testdata/misconfig/terraform/busted-relative-paths/child/main.tf", }, - artifactOpt: artifact.Option{ - MisconfScannerOption: misconf.ScannerOption{ - RegoOnly: true, - Namespaces: []string{"user"}, - PolicyPaths: []string{"./testdata/misconfig/terraform/rego"}, - DisableEmbeddedPolicies: true, - DisableEmbeddedLibraries: true, - }, - }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ BlobIDAnything: true, @@ -584,12 +541,7 @@ func TestTerraformMisconfigurationScan(t *testing.T) { }, artifactOpt: artifact.Option{ MisconfScannerOption: misconf.ScannerOption{ - RegoOnly: true, - Namespaces: []string{"user"}, - PolicyPaths: []string{"./testdata/misconfig/terraform/rego"}, - TerraformTFVars: []string{"./testdata/misconfig/terraform/tfvar-outside/main.tfvars"}, - TfExcludeDownloaded: true, - DisableEmbeddedPolicies: true, + TerraformTFVars: []string{"./testdata/misconfig/terraform/tfvar-outside/main.tfvars"}, }, }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ @@ -632,14 +584,6 @@ func TestTerraformMisconfigurationScan(t *testing.T) { fields: fields{ dir: "./testdata/misconfig/terraform/relative-paths/child", }, - artifactOpt: artifact.Option{ - MisconfScannerOption: misconf.ScannerOption{ - RegoOnly: true, - Namespaces: []string{"user"}, - PolicyPaths: []string{"./testdata/misconfig/terraform/rego"}, - DisableEmbeddedPolicies: true, - }, - }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ Args: cache.ArtifactCachePutBlobArgs{ BlobIDAnything: true, @@ -726,6 +670,8 @@ func TestTerraformMisconfigurationScan(t *testing.T) { types.SystemFileFilteringPostHandler, } tt.artifactOpt.MisconfScannerOption.DisableEmbeddedPolicies = true + tt.artifactOpt.MisconfScannerOption.Namespaces = []string{"user"} + tt.artifactOpt.MisconfScannerOption.PolicyPaths = []string{"./testdata/misconfig/terraform/rego"} a, err := NewArtifact(tt.fields.dir, c, walker.NewFS(), tt.artifactOpt) require.NoError(t, err) @@ -972,9 +918,8 @@ func TestTerraformPlanSnapshotMisconfScan(t *testing.T) { types.SystemFileFilteringPostHandler, }, MisconfScannerOption: misconf.ScannerOption{ - RegoOnly: true, - DisableEmbeddedPolicies: true, - + RegoOnly: true, + DisableEmbeddedPolicies: true, DisableEmbeddedLibraries: false, Namespaces: []string{"user"}, PolicyPaths: []string{tmpDir}, @@ -983,7 +928,6 @@ func TestTerraformPlanSnapshotMisconfScan(t *testing.T) { SkipFiles: []string{"*.tf"}, }, } - a, err := NewArtifact(tt.fields.dir, c, walker.NewFS(), opt) require.NoError(t, err) @@ -1015,7 +959,6 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { RegoOnly: true, Namespaces: []string{"user"}, PolicyPaths: []string{"./testdata/misconfig/cloudformation/single-failure/rego"}, - DisableEmbeddedPolicies: true, DisableEmbeddedLibraries: true, }, }, @@ -1077,7 +1020,6 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { RegoOnly: true, Namespaces: []string{"user"}, PolicyPaths: []string{"./testdata/misconfig/cloudformation/multiple-failures/rego"}, - DisableEmbeddedPolicies: true, DisableEmbeddedLibraries: true, }, }, @@ -1161,7 +1103,6 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { RegoOnly: true, Namespaces: []string{"user"}, PolicyPaths: []string{"./testdata/misconfig/cloudformation/no-results/rego"}, - DisableEmbeddedPolicies: true, DisableEmbeddedLibraries: true, }, }, @@ -1194,7 +1135,6 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { Namespaces: []string{"user"}, PolicyPaths: []string{"./testdata/misconfig/cloudformation/params/code/rego"}, CloudFormationParamVars: []string{"./testdata/misconfig/cloudformation/params/cfparams.json"}, - DisableEmbeddedPolicies: true, DisableEmbeddedLibraries: true, }, }, @@ -1251,7 +1191,6 @@ func TestCloudFormationMisconfigurationScan(t *testing.T) { RegoOnly: true, Namespaces: []string{"user"}, PolicyPaths: []string{"./testdata/misconfig/cloudformation/passed/rego"}, - DisableEmbeddedPolicies: true, DisableEmbeddedLibraries: true, }, }, @@ -1339,7 +1278,6 @@ func TestDockerfileMisconfigurationScan(t *testing.T) { RegoOnly: true, Namespaces: []string{"user"}, PolicyPaths: []string{"./testdata/misconfig/dockerfile/single-failure/rego"}, - DisableEmbeddedPolicies: true, DisableEmbeddedLibraries: true, }, }, @@ -1397,7 +1335,6 @@ func TestDockerfileMisconfigurationScan(t *testing.T) { RegoOnly: true, Namespaces: []string{"user"}, PolicyPaths: []string{"./testdata/misconfig/dockerfile/multiple-failures/rego"}, - DisableEmbeddedPolicies: true, DisableEmbeddedLibraries: true, }, }, @@ -1485,7 +1422,6 @@ func TestDockerfileMisconfigurationScan(t *testing.T) { RegoOnly: true, Namespaces: []string{"user"}, PolicyPaths: []string{"./testdata/misconfig/dockerfile/passed/rego"}, - DisableEmbeddedPolicies: true, DisableEmbeddedLibraries: true, }, }, @@ -1543,6 +1479,7 @@ func TestDockerfileMisconfigurationScan(t *testing.T) { tt.artifactOpt.DisabledHandlers = []types.HandlerType{ types.SystemFileFilteringPostHandler, } + tt.artifactOpt.MisconfScannerOption.DisableEmbeddedPolicies = true a, err := NewArtifact(tt.fields.dir, c, walker.NewFS(), tt.artifactOpt) require.NoError(t, err) @@ -1574,7 +1511,6 @@ func TestKubernetesMisconfigurationScan(t *testing.T) { RegoOnly: true, Namespaces: []string{"user"}, PolicyPaths: []string{"./testdata/misconfig/kubernetes/single-failure/rego"}, - DisableEmbeddedPolicies: true, DisableEmbeddedLibraries: true, }, }, @@ -1637,7 +1573,6 @@ func TestKubernetesMisconfigurationScan(t *testing.T) { RegoOnly: true, Namespaces: []string{"user"}, PolicyPaths: []string{"./testdata/misconfig/kubernetes/multiple-failures/rego"}, - DisableEmbeddedPolicies: true, DisableEmbeddedLibraries: true, }, }, @@ -1753,7 +1688,6 @@ func TestKubernetesMisconfigurationScan(t *testing.T) { RegoOnly: true, Namespaces: []string{"user"}, PolicyPaths: []string{"./testdata/misconfig/kubernetes/passed/rego"}, - DisableEmbeddedPolicies: true, DisableEmbeddedLibraries: true, }, }, @@ -1811,6 +1745,7 @@ func TestKubernetesMisconfigurationScan(t *testing.T) { tt.artifactOpt.DisabledHandlers = []types.HandlerType{ types.SystemFileFilteringPostHandler, } + tt.artifactOpt.MisconfScannerOption.DisableEmbeddedPolicies = true a, err := NewArtifact(tt.fields.dir, c, walker.NewFS(), tt.artifactOpt) require.NoError(t, err) @@ -2068,6 +2003,7 @@ func TestAzureARMMisconfigurationScan(t *testing.T) { tt.artifactOpt.DisabledHandlers = []types.HandlerType{ types.SystemFileFilteringPostHandler, } + tt.artifactOpt.MisconfScannerOption.DisableEmbeddedPolicies = true a, err := NewArtifact(tt.fields.dir, c, walker.NewFS(), tt.artifactOpt) require.NoError(t, err) @@ -2099,7 +2035,6 @@ func TestMixedConfigurationScan(t *testing.T) { RegoOnly: true, Namespaces: []string{"user"}, PolicyPaths: []string{"./testdata/misconfig/mixed/rego"}, - DisableEmbeddedPolicies: true, DisableEmbeddedLibraries: true, }, }, @@ -2184,6 +2119,7 @@ func TestMixedConfigurationScan(t *testing.T) { tt.artifactOpt.DisabledHandlers = []types.HandlerType{ types.SystemFileFilteringPostHandler, } + tt.artifactOpt.MisconfScannerOption.DisableEmbeddedPolicies = true a, err := NewArtifact(tt.fields.dir, c, walker.NewFS(), tt.artifactOpt) require.NoError(t, err) @@ -2217,10 +2153,9 @@ func TestJSONConfigScan(t *testing.T) { }, artifactOpt: artifact.Option{ MisconfScannerOption: misconf.ScannerOption{ - RegoOnly: true, - Namespaces: []string{"user"}, - PolicyPaths: []string{"./testdata/misconfig/json/passed/checks"}, - DisableEmbeddedPolicies: true, + RegoOnly: true, + Namespaces: []string{"user"}, + PolicyPaths: []string{"./testdata/misconfig/json/passed/checks"}, }, }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ @@ -2291,10 +2226,9 @@ func TestJSONConfigScan(t *testing.T) { }, artifactOpt: artifact.Option{ MisconfScannerOption: misconf.ScannerOption{ - RegoOnly: true, - Namespaces: []string{"user"}, - PolicyPaths: []string{"./testdata/misconfig/json/with-schema/checks"}, - DisableEmbeddedPolicies: true, + RegoOnly: true, + Namespaces: []string{"user"}, + PolicyPaths: []string{"./testdata/misconfig/json/with-schema/checks"}, }, }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ @@ -2342,6 +2276,7 @@ func TestJSONConfigScan(t *testing.T) { c := new(cache.MockArtifactCache) c.ApplyPutBlobExpectation(tt.putBlobExpectation) + tt.artifactOpt.MisconfScannerOption.DisableEmbeddedPolicies = true if len(tt.fields.schemas) > 0 { schemas, err := misconf.LoadConfigSchemas(tt.fields.schemas) require.NoError(t, err) @@ -2381,10 +2316,9 @@ func TestYAMLConfigScan(t *testing.T) { }, artifactOpt: artifact.Option{ MisconfScannerOption: misconf.ScannerOption{ - RegoOnly: true, - Namespaces: []string{"user"}, - PolicyPaths: []string{"./testdata/misconfig/yaml/passed/checks"}, - DisableEmbeddedPolicies: true, + RegoOnly: true, + Namespaces: []string{"user"}, + PolicyPaths: []string{"./testdata/misconfig/yaml/passed/checks"}, }, }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ @@ -2455,10 +2389,9 @@ func TestYAMLConfigScan(t *testing.T) { }, artifactOpt: artifact.Option{ MisconfScannerOption: misconf.ScannerOption{ - RegoOnly: true, - Namespaces: []string{"user"}, - PolicyPaths: []string{"./testdata/misconfig/yaml/with-schema/checks"}, - DisableEmbeddedPolicies: true, + RegoOnly: true, + Namespaces: []string{"user"}, + PolicyPaths: []string{"./testdata/misconfig/yaml/with-schema/checks"}, }, }, putBlobExpectation: cache.ArtifactCachePutBlobExpectation{ @@ -2506,6 +2439,7 @@ func TestYAMLConfigScan(t *testing.T) { c := new(cache.MockArtifactCache) c.ApplyPutBlobExpectation(tt.putBlobExpectation) + tt.artifactOpt.MisconfScannerOption.DisableEmbeddedPolicies = true if len(tt.fields.schemas) > 0 { schemas, err := misconf.LoadConfigSchemas(tt.fields.schemas) require.NoError(t, err) diff --git a/pkg/iac/rego/load.go b/pkg/iac/rego/load.go index 249e55992c2c..26a6c9e6f2d1 100644 --- a/pkg/iac/rego/load.go +++ b/pkg/iac/rego/load.go @@ -290,6 +290,11 @@ func (s *Scanner) filterModules(retriever *MetadataRetriever) error { if err != nil { return err } + + if !meta.hasAnyFramework(s.frameworks) { + continue + } + if len(meta.InputOptions.Selectors) == 0 { s.logger.Warn( "Module has no input selectors - it will be loaded for all inputs!", diff --git a/pkg/iac/rego/metadata.go b/pkg/iac/rego/metadata.go index 57602ce97b8c..cb1d38724e8a 100644 --- a/pkg/iac/rego/metadata.go +++ b/pkg/iac/rego/metadata.go @@ -49,11 +49,13 @@ func NewStaticMetadata(pkgPath string, inputOpt InputOptions) *StaticMetadata { Description: fmt.Sprintf("Rego module: %s", pkgPath), Package: pkgPath, InputOptions: inputOpt, - Frameworks: make(map[framework.Framework][]string), + Frameworks: map[framework.Framework][]string{ + framework.Default: {}, + }, } } -func (sm *StaticMetadata) Update(meta map[string]any) error { +func (sm *StaticMetadata) update(meta map[string]any) error { if sm.Frameworks == nil { sm.Frameworks = make(map[framework.Framework][]string) } @@ -125,21 +127,31 @@ func (sm *StaticMetadata) Update(meta map[string]any) error { } func (sm *StaticMetadata) updateFrameworks(meta map[string]any) error { - if raw, ok := meta["frameworks"]; ok { - frameworks, ok := raw.(map[string]any) + raw, ok := meta["frameworks"] + if !ok { + return nil + } + + frameworks, ok := raw.(map[string]any) + if !ok { + return fmt.Errorf("frameworks metadata is not an object, got %T", raw) + } + + if len(frameworks) > 0 { + sm.Frameworks = make(map[framework.Framework][]string) + } + + for fw, rawIDs := range frameworks { + ids, ok := rawIDs.([]any) if !ok { - return fmt.Errorf("frameworks metadata is not an object, got %T", raw) + return fmt.Errorf("framework ids is not an array, got %T", rawIDs) } - for fw, rawIDs := range frameworks { - ids, ok := rawIDs.([]any) - if !ok { - return fmt.Errorf("framework ids is not an array, got %T", rawIDs) - } - fr := framework.Framework(fw) - for _, id := range ids { - if str, ok := id.(string); ok { - sm.Frameworks[fr] = append(sm.Frameworks[fr], str) - } + fr := framework.Framework(fw) + for _, id := range ids { + if str, ok := id.(string); ok { + sm.Frameworks[fr] = append(sm.Frameworks[fr], str) + } else { + sm.Frameworks[fr] = []string{} } } } @@ -166,7 +178,7 @@ func (sm *StaticMetadata) FromAnnotations(annotations *ast.Annotations) error { sm.References = append(sm.References, resource.Ref.String()) } if custom := annotations.Custom; custom != nil { - if err := sm.Update(custom); err != nil { + if err := sm.update(custom); err != nil { return err } } @@ -329,7 +341,7 @@ func (m *MetadataRetriever) RetrieveMetadata(ctx context.Context, module *ast.Mo return nil, fmt.Errorf("failed to parse metadata: not an object") } - if err := metadata.Update(meta); err != nil { + if err := metadata.update(meta); err != nil { return nil, err } @@ -436,3 +448,17 @@ func metadataFromRegoModule(module *ast.Module) (*StaticMetadata, error) { } return meta, nil } + +func (m *StaticMetadata) hasAnyFramework(frameworks []framework.Framework) bool { + if len(frameworks) == 0 { + frameworks = []framework.Framework{framework.Default} + } + + for _, fr := range frameworks { + if _, exists := m.Frameworks[fr]; exists { + return true + } + } + + return false +} diff --git a/pkg/iac/rego/metadata_test.go b/pkg/iac/rego/metadata_test.go index 6535e21c14ac..b421df69bb30 100644 --- a/pkg/iac/rego/metadata_test.go +++ b/pkg/iac/rego/metadata_test.go @@ -27,12 +27,9 @@ func Test_UpdateStaticMetadata(t *testing.T) { Provider: "pr", Service: "srvc", Library: false, - Frameworks: map[framework.Framework][]string{ - framework.Default: {"dd"}, - }, } - require.NoError(t, sm.Update( + require.NoError(t, sm.update( map[string]any{ "id": "i_n", "avd_id": "a_n", @@ -68,8 +65,7 @@ func Test_UpdateStaticMetadata(t *testing.T) { Service: "srvc_n", Library: true, Frameworks: map[framework.Framework][]string{ - framework.Default: {"dd"}, - framework.ALL: {"aa"}, + framework.ALL: {"aa"}, }, CloudFormation: &scan.EngineMetadata{}, Terraform: &scan.EngineMetadata{}, @@ -82,7 +78,7 @@ func Test_UpdateStaticMetadata(t *testing.T) { sm := StaticMetadata{ References: []string{"r"}, } - require.NoError(t, sm.Update(map[string]any{ + require.NoError(t, sm.update(map[string]any{ "related_resources": []map[string]any{ { "ref": "r1_n", @@ -107,7 +103,7 @@ func Test_UpdateStaticMetadata(t *testing.T) { sm := StaticMetadata{ References: []string{"r"}, } - require.NoError(t, sm.Update(map[string]any{ + require.NoError(t, sm.update(map[string]any{ "related_resources": []string{"r1_n", "r2_n"}, })) @@ -125,7 +121,7 @@ func Test_UpdateStaticMetadata(t *testing.T) { sm := StaticMetadata{ Deprecated: false, } - require.NoError(t, sm.Update(map[string]any{ + require.NoError(t, sm.update(map[string]any{ "deprecated": true, })) @@ -141,7 +137,7 @@ func Test_UpdateStaticMetadata(t *testing.T) { t.Run("frameworks is not initialized", func(t *testing.T) { sm := StaticMetadata{} - err := sm.Update(map[string]any{ + err := sm.update(map[string]any{ "frameworks": map[string]any{"all": []any{"a", "b", "c"}}, }) require.NoError(t, err) diff --git a/pkg/iac/scanners/cloudformation/scanner_test.go b/pkg/iac/scanners/cloudformation/scanner_test.go index baa8ed81ba59..21d185c5ec06 100644 --- a/pkg/iac/scanners/cloudformation/scanner_test.go +++ b/pkg/iac/scanners/cloudformation/scanner_test.go @@ -82,7 +82,9 @@ deny[res] { Terraform: (*scan.TerraformCustomCheck)(nil), }, RegoPackage: "data.builtin.dockerfile.DS006", - Frameworks: make(map[framework.Framework][]string), + Frameworks: map[framework.Framework][]string{ + framework.Default: {}, + }, }, results.GetFailed()[0].Rule()) failure := results.GetFailed()[0] diff --git a/pkg/iac/scanners/dockerfile/scanner_test.go b/pkg/iac/scanners/dockerfile/scanner_test.go index 437c37ec9660..4cbd86667a17 100644 --- a/pkg/iac/scanners/dockerfile/scanner_test.go +++ b/pkg/iac/scanners/dockerfile/scanner_test.go @@ -10,7 +10,6 @@ import ( "github.com/aquasecurity/trivy/internal/testutil" "github.com/aquasecurity/trivy/pkg/iac/framework" - "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/rego/schemas" "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" @@ -252,7 +251,9 @@ USER root CustomChecks: scan.CustomChecks{ Terraform: (*scan.TerraformCustomCheck)(nil)}, RegoPackage: "data.builtin.dockerfile.DS006", - Frameworks: make(map[framework.Framework][]string), + Frameworks: map[framework.Framework][]string{ + framework.Default: {}, + }, }, results.GetFailed()[0].Rule(), ) @@ -553,27 +554,23 @@ res := true for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - regoMap := make(map[string]string) - libs, err := rego.LoadEmbeddedLibraries() - require.NoError(t, err) - for name, library := range libs { - regoMap["/rules/"+name] = library.String() - } - regoMap["/code/Dockerfile"] = `FROM golang:1.7.3 as dep + fsysMap := make(map[string]string) + fsysMap["/code/Dockerfile"] = `FROM golang:1.7.3 as dep COPY --from=dep /binary /` - regoMap["/rules/rule.rego"] = tc.inputRegoPolicy - regoMap["/rules/schemas/myfancydockerfile.json"] = string(schemas.Dockerfile) // just use the same for testing - fs := testutil.CreateFS(t, regoMap) + fsysMap["/rules/rule.rego"] = tc.inputRegoPolicy + fsysMap["/rules/schemas/myfancydockerfile.json"] = string(schemas.Dockerfile) // just use the same for testing + fsys := testutil.CreateFS(t, fsysMap) var traceBuf bytes.Buffer scanner := NewScanner( options.ScannerWithPolicyDirs("rules"), + options.ScannerWithEmbeddedLibraries(true), options.ScannerWithTrace(&traceBuf), options.ScannerWithRegoErrorLimits(0), ) - results, err := scanner.ScanFS(context.TODO(), fs, "code") + results, err := scanner.ScanFS(context.TODO(), fsys, "code") if tc.expectedError != "" && err != nil { require.Equal(t, tc.expectedError, err.Error(), tc.name) } else { @@ -605,7 +602,9 @@ COPY --from=dep /binary /` CustomChecks: scan.CustomChecks{ Terraform: (*scan.TerraformCustomCheck)(nil)}, RegoPackage: "data.builtin.dockerfile.DS006", - Frameworks: make(map[framework.Framework][]string), + Frameworks: map[framework.Framework][]string{ + framework.Default: {}, + }, }, results.GetFailed()[0].Rule(), ) diff --git a/pkg/iac/scanners/json/scanner_test.go b/pkg/iac/scanners/json/scanner_test.go index 7e7f1c308186..e126768e55d8 100644 --- a/pkg/iac/scanners/json/scanner_test.go +++ b/pkg/iac/scanners/json/scanner_test.go @@ -73,6 +73,8 @@ deny[res] { Terraform: (*scan.TerraformCustomCheck)(nil), }, RegoPackage: "data.builtin.json.lol", - Frameworks: make(map[framework.Framework][]string), + Frameworks: map[framework.Framework][]string{ + framework.Default: {}, + }, }, results.GetFailed()[0].Rule()) } diff --git a/pkg/iac/scanners/kubernetes/scanner_test.go b/pkg/iac/scanners/kubernetes/scanner_test.go index d972e52e8e80..c981634a0ee6 100644 --- a/pkg/iac/scanners/kubernetes/scanner_test.go +++ b/pkg/iac/scanners/kubernetes/scanner_test.go @@ -119,7 +119,9 @@ deny[res] { CloudFormation: &scan.EngineMetadata{}, CustomChecks: scan.CustomChecks{Terraform: (*scan.TerraformCustomCheck)(nil)}, RegoPackage: "data.builtin.kubernetes.KSV011", - Frameworks: make(map[framework.Framework][]string), + Frameworks: map[framework.Framework][]string{ + framework.Default: {}, + }, }, results.GetFailed()[0].Rule()) failure := results.GetFailed()[0] @@ -279,7 +281,9 @@ deny[res] { CloudFormation: &scan.EngineMetadata{}, CustomChecks: scan.CustomChecks{Terraform: (*scan.TerraformCustomCheck)(nil)}, RegoPackage: "data.builtin.kubernetes.KSV011", - Frameworks: make(map[framework.Framework][]string), + Frameworks: map[framework.Framework][]string{ + framework.Default: {}, + }, }, results.GetFailed()[0].Rule()) failure := results.GetFailed()[0] diff --git a/pkg/iac/scanners/terraformplan/tfjson/test/scanner_test.go b/pkg/iac/scanners/terraformplan/tfjson/test/scanner_test.go index 5b684dc77ed0..dd77c2d89f6e 100644 --- a/pkg/iac/scanners/terraformplan/tfjson/test/scanner_test.go +++ b/pkg/iac/scanners/terraformplan/tfjson/test/scanner_test.go @@ -33,7 +33,7 @@ func Test_Scanning_Plan(t *testing.T) { failedResults = append(failedResults, r) } } - assert.Len(t, results, 15) + assert.Len(t, failedResults, 9) } diff --git a/pkg/iac/scanners/toml/scanner_test.go b/pkg/iac/scanners/toml/scanner_test.go index c2fdcda26faa..d3c4e51e3b63 100644 --- a/pkg/iac/scanners/toml/scanner_test.go +++ b/pkg/iac/scanners/toml/scanner_test.go @@ -76,7 +76,9 @@ deny[res] { CustomChecks: scan.CustomChecks{ Terraform: (*scan.TerraformCustomCheck)(nil)}, RegoPackage: "data.builtin.toml.lol", - Frameworks: make(map[framework.Framework][]string), + Frameworks: map[framework.Framework][]string{ + framework.Default: {}, + }, }, results.GetFailed()[0].Rule(), ) diff --git a/pkg/iac/scanners/yaml/scanner_test.go b/pkg/iac/scanners/yaml/scanner_test.go index 771bf45ef7d2..02468158fcf9 100644 --- a/pkg/iac/scanners/yaml/scanner_test.go +++ b/pkg/iac/scanners/yaml/scanner_test.go @@ -79,7 +79,9 @@ deny[res] { CustomChecks: scan.CustomChecks{ Terraform: (*scan.TerraformCustomCheck)(nil)}, RegoPackage: "data.builtin.yaml.lol", - Frameworks: make(map[framework.Framework][]string), + Frameworks: map[framework.Framework][]string{ + framework.Default: {}, + }, }, results.GetFailed()[0].Rule(), ) From 3a5d091759564496992a83fb2015a21c84a22213 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 30 Aug 2024 12:18:15 +0600 Subject: [PATCH 055/183] fix(misconf): do not recreate filesystem map (#7416) Signed-off-by: nikpivkin --- pkg/iac/scanners/terraform/parser/evaluator.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pkg/iac/scanners/terraform/parser/evaluator.go b/pkg/iac/scanners/terraform/parser/evaluator.go index 811f618787b5..809498f35c63 100644 --- a/pkg/iac/scanners/terraform/parser/evaluator.go +++ b/pkg/iac/scanners/terraform/parser/evaluator.go @@ -175,7 +175,9 @@ func (e *evaluator) evaluateSubmodules(ctx context.Context, fsMap map[string]fs. var modules terraform.Modules for _, sm := range submodules { modules = append(modules, sm.modules...) - fsMap = lo.Assign(fsMap, sm.fsMap) + for k, v := range sm.fsMap { + fsMap[k] = v + } } e.logger.Debug("Finished processing submodule(s).", log.Int("count", len(modules))) From bf64003ac8b209f34b88f228918a96d4f9dac5e0 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Fri, 30 Aug 2024 13:15:10 +0600 Subject: [PATCH 056/183] fix(secret): use `.eyJ` keyword for JWT secret (#7410) --- pkg/fanal/secret/builtin-rules.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fanal/secret/builtin-rules.go b/pkg/fanal/secret/builtin-rules.go index 9cb0aa361025..a83d8eba35ba 100644 --- a/pkg/fanal/secret/builtin-rules.go +++ b/pkg/fanal/secret/builtin-rules.go @@ -604,7 +604,7 @@ var builtinRules = []Rule{ Title: "JWT token", Severity: "MEDIUM", Regex: MustCompile(`ey[a-zA-Z0-9]{17,}\.ey[a-zA-Z0-9\/\\_-]{17,}\.(?:[a-zA-Z0-9\/\\_-]{10,}={0,2})?`), - Keywords: []string{"jwt"}, + Keywords: []string{".eyJ"}, }, { ID: "linear-api-token", From 0cac3ac7075017628a21a7990941df04cbc16dbe Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Sat, 31 Aug 2024 13:06:34 +0600 Subject: [PATCH 057/183] fix(misconf): fix infer type for null value (#7424) Signed-off-by: nikpivkin --- .../scanners/cloudformation/cftypes/types.go | 3 +++ .../cloudformation/parser/parser_test.go | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/pkg/iac/scanners/cloudformation/cftypes/types.go b/pkg/iac/scanners/cloudformation/cftypes/types.go index 21949ae099cf..6a533aae179c 100644 --- a/pkg/iac/scanners/cloudformation/cftypes/types.go +++ b/pkg/iac/scanners/cloudformation/cftypes/types.go @@ -15,6 +15,9 @@ const ( ) func TypeFromGoValue(value any) CfType { + if value == nil { + return Unknown + } switch reflect.TypeOf(value).Kind() { case reflect.String: return String diff --git a/pkg/iac/scanners/cloudformation/parser/parser_test.go b/pkg/iac/scanners/cloudformation/parser/parser_test.go index 0d37440e2e1a..aa058c4df855 100644 --- a/pkg/iac/scanners/cloudformation/parser/parser_test.go +++ b/pkg/iac/scanners/cloudformation/parser/parser_test.go @@ -419,3 +419,24 @@ func TestJsonWithNumbers(t *testing.T) { assert.Equal(t, 1, res[0].GetProperty("SomeIntProp").AsIntValue().Value()) assert.Equal(t, 0, res[0].GetProperty("SomeFloatProp").AsIntValue().Value()) } + +func TestParameterIsNull(t *testing.T) { + src := `--- +AWSTemplateFormatVersion: 2010-09-09 + +Parameters: + Email: + Type: String + +Conditions: + SubscribeEmail: !Not [!Equals [ !Ref Email, ""]] +` + + fsys := testutil.CreateFS(t, map[string]string{ + "main.yaml": src, + }) + + files, err := New().ParseFS(context.TODO(), fsys, ".") + require.NoError(t, err) + require.Len(t, files, 1) +} From feaef9699df5d8ca399770e701a59d7c0ff979a3 Mon Sep 17 00:00:00 2001 From: Kevin Conner Date: Sun, 1 Sep 2024 20:27:42 -0700 Subject: [PATCH 058/183] fix(aws): handle ECR repositories in different regions (#6217) Signed-off-by: Kevin Conner --- pkg/fanal/image/registry/azure/azure.go | 30 ++++---- pkg/fanal/image/registry/azure/azure_test.go | 2 +- pkg/fanal/image/registry/ecr/ecr.go | 54 +++++++++++---- pkg/fanal/image/registry/ecr/ecr_test.go | 68 +++++++++++++++++-- pkg/fanal/image/registry/google/google.go | 18 +++-- .../image/registry/google/google_test.go | 12 ++-- pkg/fanal/image/registry/intf/registry.go | 15 ++++ pkg/fanal/image/registry/token.go | 14 ++-- 8 files changed, 159 insertions(+), 54 deletions(-) create mode 100644 pkg/fanal/image/registry/intf/registry.go diff --git a/pkg/fanal/image/registry/azure/azure.go b/pkg/fanal/image/registry/azure/azure.go index 3203829f3d3d..67368c8bb3c8 100644 --- a/pkg/fanal/image/registry/azure/azure.go +++ b/pkg/fanal/image/registry/azure/azure.go @@ -14,15 +14,19 @@ import ( "github.com/Azure/azure-sdk-for-go/sdk/azidentity" "golang.org/x/xerrors" + "github.com/aquasecurity/trivy/pkg/fanal/image/registry/intf" "github.com/aquasecurity/trivy/pkg/fanal/types" ) -type Registry struct { +type RegistryClient struct { domain string scope string cloud cloud.Configuration } +type Registry struct { +} + const ( azureURL = ".azurecr.io" chinaAzureURL = ".azurecr.cn" @@ -31,23 +35,25 @@ const ( scheme = "https" ) -func (r *Registry) CheckOptions(domain string, _ types.RegistryOptions) error { +func (r *Registry) CheckOptions(domain string, _ types.RegistryOptions) (intf.RegistryClient, error) { if strings.HasSuffix(domain, azureURL) { - r.domain = domain - r.scope = scope - r.cloud = cloud.AzurePublic - return nil + return &RegistryClient{ + domain: domain, + scope: scope, + cloud: cloud.AzurePublic, + }, nil } else if strings.HasSuffix(domain, chinaAzureURL) { - r.domain = domain - r.scope = chinaScope - r.cloud = cloud.AzureChina - return nil + return &RegistryClient{ + domain: domain, + scope: scope, + cloud: cloud.AzureChina, + }, nil } - return xerrors.Errorf("Azure registry: %w", types.InvalidURLPattern) + return nil, xerrors.Errorf("Azure registry: %w", types.InvalidURLPattern) } -func (r *Registry) GetCredential(ctx context.Context) (string, string, error) { +func (r *RegistryClient) GetCredential(ctx context.Context) (string, string, error) { opts := azcore.ClientOptions{Cloud: r.cloud} cred, err := azidentity.NewDefaultAzureCredential(&azidentity.DefaultAzureCredentialOptions{ClientOptions: opts}) if err != nil { diff --git a/pkg/fanal/image/registry/azure/azure_test.go b/pkg/fanal/image/registry/azure/azure_test.go index 0fb4839e8fee..5be56f777a51 100644 --- a/pkg/fanal/image/registry/azure/azure_test.go +++ b/pkg/fanal/image/registry/azure/azure_test.go @@ -38,7 +38,7 @@ func TestRegistry_CheckOptions(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := azure.Registry{} - err := r.CheckOptions(tt.domain, types.RegistryOptions{}) + _, err := r.CheckOptions(tt.domain, types.RegistryOptions{}) if tt.wantErr != "" { assert.EqualError(t, err, tt.wantErr) } else { diff --git a/pkg/fanal/image/registry/ecr/ecr.go b/pkg/fanal/image/registry/ecr/ecr.go index 261030d1a584..c9bb0dea5330 100644 --- a/pkg/fanal/image/registry/ecr/ecr.go +++ b/pkg/fanal/image/registry/ecr/ecr.go @@ -3,6 +3,7 @@ package ecr import ( "context" "encoding/base64" + "regexp" "strings" "github.com/aws/aws-sdk-go-v2/aws" @@ -11,48 +12,73 @@ import ( "github.com/aws/aws-sdk-go-v2/service/ecr" "golang.org/x/xerrors" + "github.com/aquasecurity/trivy/pkg/fanal/image/registry/intf" "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/log" ) -const ecrURLSuffix = ".amazonaws.com" -const ecrURLPartial = ".dkr.ecr" - type ecrAPI interface { GetAuthorizationToken(ctx context.Context, params *ecr.GetAuthorizationTokenInput, optFns ...func(*ecr.Options)) (*ecr.GetAuthorizationTokenOutput, error) } type ECR struct { +} + +type ECRClient struct { Client ecrAPI } -func getSession(option types.RegistryOptions) (aws.Config, error) { +func getSession(domain, region string, option types.RegistryOptions) (aws.Config, error) { // create custom credential information if option is valid if option.AWSSecretKey != "" && option.AWSAccessKey != "" && option.AWSRegion != "" { + if region != option.AWSRegion { + log.Warnf("The region from AWS_REGION (%s) is being overridden. The region from domain (%s) was used.", option.AWSRegion, domain) + } return config.LoadDefaultConfig( context.TODO(), - config.WithRegion(option.AWSRegion), + config.WithRegion(region), config.WithCredentialsProvider(credentials.NewStaticCredentialsProvider(option.AWSAccessKey, option.AWSSecretKey, option.AWSSessionToken)), ) } - return config.LoadDefaultConfig(context.TODO()) + return config.LoadDefaultConfig(context.TODO(), config.WithRegion(region)) } -func (e *ECR) CheckOptions(domain string, option types.RegistryOptions) error { - if !strings.HasSuffix(domain, ecrURLSuffix) && !strings.Contains(domain, ecrURLPartial) { - return xerrors.Errorf("ECR : %w", types.InvalidURLPattern) +func (e *ECR) CheckOptions(domain string, option types.RegistryOptions) (intf.RegistryClient, error) { + region := determineRegion(domain) + if region == "" { + return nil, xerrors.Errorf("ECR : %w", types.InvalidURLPattern) } - cfg, err := getSession(option) + cfg, err := getSession(domain, region, option) if err != nil { - return err + return nil, err } svc := ecr.NewFromConfig(cfg) - e.Client = svc - return nil + return &ECRClient{Client: svc}, nil +} + +// Endpoints take the form +// .dkr.ecr..amazonaws.com +// .dkr.ecr-fips..amazonaws.com +// .dkr.ecr..amazonaws.com.cn +// .dkr.ecr..sc2s.sgov.gov +// .dkr.ecr..c2s.ic.gov +// see +// - https://docs.aws.amazon.com/general/latest/gr/ecr.html +// - https://docs.amazonaws.cn/en_us/aws/latest/userguide/endpoints-arns.html +// - https://github.com/boto/botocore/blob/1.34.51/botocore/data/endpoints.json +var ecrEndpointMatch = regexp.MustCompile(`^[^.]+\.dkr\.ecr(?:-fips)?\.([^.]+)\.(?:amazonaws\.com(?:\.cn)?|sc2s\.sgov\.gov|c2s\.ic\.gov)$`) + +func determineRegion(domain string) string { + matches := ecrEndpointMatch.FindStringSubmatch(domain) + if matches != nil { + return matches[1] + } + return "" } -func (e *ECR) GetCredential(ctx context.Context) (username, password string, err error) { +func (e *ECRClient) GetCredential(ctx context.Context) (username, password string, err error) { input := &ecr.GetAuthorizationTokenInput{} result, err := e.Client.GetAuthorizationToken(ctx, input) if err != nil { diff --git a/pkg/fanal/image/registry/ecr/ecr_test.go b/pkg/fanal/image/registry/ecr/ecr_test.go index 68b1870f07da..321de7f8639d 100644 --- a/pkg/fanal/image/registry/ecr/ecr_test.go +++ b/pkg/fanal/image/registry/ecr/ecr_test.go @@ -8,14 +8,20 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ecr" awstypes "github.com/aws/aws-sdk-go-v2/service/ecr/types" + "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/pkg/fanal/types" ) +type testECRClient interface { + Options() ecr.Options +} + func TestCheckOptions(t *testing.T) { var tests = map[string]struct { - domain string - wantErr error + domain string + expectedRegion string + wantErr error }{ "InvalidURL": { domain: "alpine:3.9", @@ -30,19 +36,71 @@ func TestCheckOptions(t *testing.T) { wantErr: types.InvalidURLPattern, }, "NoOption": { - domain: "xxx.ecr.ap-northeast-1.amazonaws.com", + domain: "xxx.dkr.ecr.ap-northeast-1.amazonaws.com", + expectedRegion: "ap-northeast-1", + }, + "region-1": { + domain: "xxx.dkr.ecr.region-1.amazonaws.com", + expectedRegion: "region-1", + }, + "region-2": { + domain: "xxx.dkr.ecr.region-2.amazonaws.com", + expectedRegion: "region-2", + }, + "fips-region-1": { + domain: "xxx.dkr.ecr-fips.fips-region.amazonaws.com", + expectedRegion: "fips-region", + }, + "cn-region-1": { + domain: "xxx.dkr.ecr.region-1.amazonaws.com.cn", + expectedRegion: "region-1", + }, + "cn-region-2": { + domain: "xxx.dkr.ecr.region-2.amazonaws.com.cn", + expectedRegion: "region-2", + }, + "sc2s-region-1": { + domain: "xxx.dkr.ecr.sc2s-region.sc2s.sgov.gov", + expectedRegion: "sc2s-region", + }, + "c2s-region-1": { + domain: "xxx.dkr.ecr.c2s-region.c2s.ic.gov", + expectedRegion: "c2s-region", + }, + "invalid-ecr": { + domain: "xxx.dkrecr.region-1.amazonaws.com", + wantErr: types.InvalidURLPattern, + }, + "invalid-fips": { + domain: "xxx.dkr.ecrfips.fips-region.amazonaws.com", + wantErr: types.InvalidURLPattern, + }, + "invalid-cn": { + domain: "xxx.dkr.ecr.region-2.amazonaws.cn", + wantErr: types.InvalidURLPattern, + }, + "invalid-sc2s": { + domain: "xxx.dkr.ecr.sc2s-region.sc2s.sgov", + wantErr: types.InvalidURLPattern, + }, + "invalid-cs2": { + domain: "xxx.dkr.ecr.c2s-region.c2s.ic", + wantErr: types.InvalidURLPattern, }, } for testname, v := range tests { a := &ECR{} - err := a.CheckOptions(v.domain, types.RegistryOptions{}) + ecrClient, err := a.CheckOptions(v.domain, types.RegistryOptions{}) if err != nil { if !errors.Is(err, v.wantErr) { t.Errorf("[%s]\nexpected error based on %v\nactual : %v", testname, v.wantErr, err) } continue } + + client := (ecrClient.(*ECRClient)).Client.(testECRClient) + require.Equal(t, v.expectedRegion, client.Options().Region) } } @@ -90,7 +148,7 @@ func TestECRGetCredential(t *testing.T) { } for i, c := range cases { - e := ECR{ + e := ECRClient{ Client: mockedECR{Resp: c.Resp}, } username, password, err := e.GetCredential(context.Background()) diff --git a/pkg/fanal/image/registry/google/google.go b/pkg/fanal/image/registry/google/google.go index fe52c85f7493..3c58f0de005f 100644 --- a/pkg/fanal/image/registry/google/google.go +++ b/pkg/fanal/image/registry/google/google.go @@ -9,14 +9,18 @@ import ( "github.com/GoogleCloudPlatform/docker-credential-gcr/store" "golang.org/x/xerrors" + "github.com/aquasecurity/trivy/pkg/fanal/image/registry/intf" "github.com/aquasecurity/trivy/pkg/fanal/types" ) -type Registry struct { +type GoogleRegistryClient struct { Store store.GCRCredStore domain string } +type Registry struct { +} + // Google container registry const gcrURLDomain = "gcr.io" const gcrURLSuffix = ".gcr.io" @@ -24,18 +28,18 @@ const gcrURLSuffix = ".gcr.io" // Google artifact registry const garURLSuffix = "-docker.pkg.dev" -func (g *Registry) CheckOptions(domain string, option types.RegistryOptions) error { +func (g *Registry) CheckOptions(domain string, option types.RegistryOptions) (intf.RegistryClient, error) { if domain != gcrURLDomain && !strings.HasSuffix(domain, gcrURLSuffix) && !strings.HasSuffix(domain, garURLSuffix) { - return xerrors.Errorf("Google registry: %w", types.InvalidURLPattern) + return nil, xerrors.Errorf("Google registry: %w", types.InvalidURLPattern) } - g.domain = domain + client := GoogleRegistryClient{domain: domain} if option.GCPCredPath != "" { - g.Store = store.NewGCRCredStore(option.GCPCredPath) + client.Store = store.NewGCRCredStore(option.GCPCredPath) } - return nil + return &client, nil } -func (g *Registry) GetCredential(_ context.Context) (username, password string, err error) { +func (g *GoogleRegistryClient) GetCredential(_ context.Context) (username, password string, err error) { var credStore store.GCRCredStore if g.Store == nil { credStore, err = store.DefaultGCRCredStore() diff --git a/pkg/fanal/image/registry/google/google_test.go b/pkg/fanal/image/registry/google/google_test.go index 2e4ba64d663e..1bce72897d46 100644 --- a/pkg/fanal/image/registry/google/google_test.go +++ b/pkg/fanal/image/registry/google/google_test.go @@ -14,7 +14,7 @@ func TestCheckOptions(t *testing.T) { var tests = map[string]struct { domain string opt types.RegistryOptions - gcr *Registry + grc *GoogleRegistryClient wantErr error }{ "InvalidURL": { @@ -27,12 +27,12 @@ func TestCheckOptions(t *testing.T) { }, "NoOption": { domain: "gcr.io", - gcr: &Registry{domain: "gcr.io"}, + grc: &GoogleRegistryClient{domain: "gcr.io"}, }, "CredOption": { domain: "gcr.io", opt: types.RegistryOptions{GCPCredPath: "/path/to/file.json"}, - gcr: &Registry{ + grc: &GoogleRegistryClient{ domain: "gcr.io", Store: store.NewGCRCredStore("/path/to/file.json"), }, @@ -41,7 +41,7 @@ func TestCheckOptions(t *testing.T) { for testname, v := range tests { g := &Registry{} - err := g.CheckOptions(v.domain, v.opt) + grc, err := g.CheckOptions(v.domain, v.opt) if v.wantErr != nil { if err == nil { t.Errorf("%s : expected error but no error", testname) @@ -52,8 +52,8 @@ func TestCheckOptions(t *testing.T) { } continue } - if !reflect.DeepEqual(v.gcr, g) { - t.Errorf("[%s]\nexpected : %v\nactual : %v", testname, v.gcr, g) + if !reflect.DeepEqual(v.grc, grc) { + t.Errorf("[%s]\nexpected : %v\nactual : %v", testname, v.grc, grc) } } } diff --git a/pkg/fanal/image/registry/intf/registry.go b/pkg/fanal/image/registry/intf/registry.go new file mode 100644 index 000000000000..da8c5d3c1789 --- /dev/null +++ b/pkg/fanal/image/registry/intf/registry.go @@ -0,0 +1,15 @@ +package intf + +import ( + "context" + + "github.com/aquasecurity/trivy/pkg/fanal/types" +) + +type RegistryClient interface { + GetCredential(ctx context.Context) (string, string, error) +} + +type Registry interface { + CheckOptions(domain string, option types.RegistryOptions) (RegistryClient, error) +} diff --git a/pkg/fanal/image/registry/token.go b/pkg/fanal/image/registry/token.go index b959c6cc7bbc..72c569890196 100644 --- a/pkg/fanal/image/registry/token.go +++ b/pkg/fanal/image/registry/token.go @@ -8,12 +8,13 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/image/registry/azure" "github.com/aquasecurity/trivy/pkg/fanal/image/registry/ecr" "github.com/aquasecurity/trivy/pkg/fanal/image/registry/google" + "github.com/aquasecurity/trivy/pkg/fanal/image/registry/intf" "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" ) var ( - registries []Registry + registries []intf.Registry ) func init() { @@ -22,23 +23,18 @@ func init() { RegisterRegistry(&azure.Registry{}) } -type Registry interface { - CheckOptions(domain string, option types.RegistryOptions) error - GetCredential(ctx context.Context) (string, string, error) -} - -func RegisterRegistry(registry Registry) { +func RegisterRegistry(registry intf.Registry) { registries = append(registries, registry) } func GetToken(ctx context.Context, domain string, opt types.RegistryOptions) (auth authn.Basic) { // check registry which particular to get credential for _, registry := range registries { - err := registry.CheckOptions(domain, opt) + client, err := registry.CheckOptions(domain, opt) if err != nil { continue } - username, password, err := registry.GetCredential(ctx) + username, password, err := client.GetCredential(ctx) if err != nil { // only skip check registry if error occurred log.Debug("Credential error", log.Err(err)) From c929290c3c0e4e91337264d69e75ccb60522bc65 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Mon, 2 Sep 2024 12:44:33 +0600 Subject: [PATCH 059/183] fix: logger initialization before flags parsing (#7372) Signed-off-by: knqyf263 Co-authored-by: knqyf263 --- pkg/log/deferred.go | 62 +++++++++++++++++++++++++++++++++++++++++++++ pkg/log/logger.go | 11 ++++++-- 2 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 pkg/log/deferred.go diff --git a/pkg/log/deferred.go b/pkg/log/deferred.go new file mode 100644 index 000000000000..9fbf81652f4d --- /dev/null +++ b/pkg/log/deferred.go @@ -0,0 +1,62 @@ +package log + +import ( + "context" + "log/slog" + "slices" +) + +func init() { + // Set the default logger so that logs are buffered until the logger is initialized. + slog.SetDefault(New(&DeferredHandler{records: new([]deferredRecord)})) +} + +// DeferredHandler is needed to save logs and print them after calling `PrintLogs()` command. +// For example, this may be necessary when the logger is not yet initialized, but messages need to be transmitted. +// In this case, the messages are saved and printed when the logger is initialized. +type DeferredHandler struct { + attrs []slog.Attr + + // Shared with all instances of the handler. + // NOTE: non-thread safe + records *[]deferredRecord +} + +type deferredRecord struct { + ctx context.Context + slog.Record +} + +func (*DeferredHandler) Enabled(context.Context, slog.Level) bool { + return true +} + +func (d *DeferredHandler) Handle(ctx context.Context, record slog.Record) error { + record.AddAttrs(d.attrs...) + *d.records = append(*d.records, deferredRecord{ + ctx: ctx, + Record: record, + }) + return nil +} + +func (d *DeferredHandler) WithAttrs(attrs []slog.Attr) slog.Handler { + h := *d + h.attrs = slices.Clip(d.attrs) + h.attrs = append(h.attrs, attrs...) + return &h +} + +func (*DeferredHandler) WithGroup(_ string) slog.Handler { + panic("WithGroup is not implemented") +} + +func (d *DeferredHandler) Flush(h slog.Handler) { + for _, record := range *d.records { + if !h.Enabled(record.ctx, record.Level) { + continue + } + _ = h.Handle(record.ctx, record.Record) + } + d.records = nil +} diff --git a/pkg/log/logger.go b/pkg/log/logger.go index 73c4231fd4af..ac629d211157 100644 --- a/pkg/log/logger.go +++ b/pkg/log/logger.go @@ -33,11 +33,18 @@ func New(h slog.Handler) *Logger { return slog.New(h) } -// InitLogger initialize the logger variable +// InitLogger initializes the logger variable and flushes the buffered logs if needed. func InitLogger(debug, disable bool) { level := lo.Ternary(debug, slog.LevelDebug, slog.LevelInfo) out := lo.Ternary(disable, io.Discard, io.Writer(os.Stderr)) - slog.SetDefault(New(NewHandler(out, &Options{Level: level}))) + h := NewHandler(out, &Options{Level: level}) + + // Flush the buffered logs if needed. + if d, ok := slog.Default().Handler().(*DeferredHandler); ok { + d.Flush(h) + } + + slog.SetDefault(New(h)) } var ( From fd9ed3a330bc66e229bcbdc262dc296a3bf01f54 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Mon, 2 Sep 2024 13:19:01 +0600 Subject: [PATCH 060/183] fix(nodejs): check all `importers` to detect dev deps from pnpm-lock.yaml file (#7387) --- pkg/dependency/parser/nodejs/pnpm/parse.go | 22 +++++++++++++------ .../parser/nodejs/pnpm/parse_test.go | 6 ----- .../parser/nodejs/pnpm/parse_testcase.go | 13 +++++++++++ .../nodejs/pnpm/testdata/pnpm-lock_v9.yaml | 21 ++++++++++++++++++ 4 files changed, 49 insertions(+), 13 deletions(-) diff --git a/pkg/dependency/parser/nodejs/pnpm/parse.go b/pkg/dependency/parser/nodejs/pnpm/parse.go index 8ccf9de0ae9a..6f85411f40d0 100644 --- a/pkg/dependency/parser/nodejs/pnpm/parse.go +++ b/pkg/dependency/parser/nodejs/pnpm/parse.go @@ -37,15 +37,11 @@ type LockFile struct { Packages map[string]PackageInfo `yaml:"packages,omitempty"` // V9 - Importers Importer `yaml:"importers,omitempty"` + Importers map[string]Importer `yaml:"importers,omitempty"` Snapshots map[string]Snapshot `yaml:"snapshots,omitempty"` } type Importer struct { - Root RootImporter `yaml:".,omitempty"` -} - -type RootImporter struct { Dependencies map[string]ImporterDepVersion `yaml:"dependencies,omitempty"` DevDependencies map[string]ImporterDepVersion `yaml:"devDependencies,omitempty"` } @@ -167,6 +163,18 @@ func (p *Parser) parseV9(lockFile LockFile) ([]ftypes.Package, []ftypes.Dependen } + // Parse `Importers` to find all direct dependencies + devDeps := make(map[string]string) + deps := make(map[string]string) + for _, importer := range lockFile.Importers { + for n, v := range importer.DevDependencies { + devDeps[n] = v.Version + } + for n, v := range importer.Dependencies { + deps[n] = v.Version + } + } + for depPath, pkgInfo := range lockFile.Packages { name, ver, ref := p.parseDepPath(depPath, lockVer) parsedVer := p.parseVersion(depPath, ver, lockVer) @@ -179,10 +187,10 @@ func (p *Parser) parseV9(lockFile LockFile) ([]ftypes.Package, []ftypes.Dependen // We will update `Dev` field later. dev := true relationship := ftypes.RelationshipIndirect - if dep, ok := lockFile.Importers.Root.DevDependencies[name]; ok && dep.Version == ver { + if v, ok := devDeps[name]; ok && p.trimPeerDeps(v, lockVer) == ver { relationship = ftypes.RelationshipDirect } - if dep, ok := lockFile.Importers.Root.Dependencies[name]; ok && p.trimPeerDeps(dep.Version, lockVer) == ver { + if v, ok := deps[name]; ok && p.trimPeerDeps(v, lockVer) == ver { relationship = ftypes.RelationshipDirect dev = false // mark root direct deps to update `dev` field of their child deps. } diff --git a/pkg/dependency/parser/nodejs/pnpm/parse_test.go b/pkg/dependency/parser/nodejs/pnpm/parse_test.go index ec869d6ff492..ebdfe0e2442f 100644 --- a/pkg/dependency/parser/nodejs/pnpm/parse_test.go +++ b/pkg/dependency/parser/nodejs/pnpm/parse_test.go @@ -59,12 +59,6 @@ func TestParse(t *testing.T) { want: pnpmV9, wantDeps: pnpmV9Deps, }, - { - name: "v9", - file: "testdata/pnpm-lock_v9.yaml", - want: pnpmV9, - wantDeps: pnpmV9Deps, - }, { name: "v9 with cyclic dependencies import", file: "testdata/pnpm-lock_v9_cyclic_import.yaml", diff --git a/pkg/dependency/parser/nodejs/pnpm/parse_testcase.go b/pkg/dependency/parser/nodejs/pnpm/parse_testcase.go index 3c9383bd1e25..5649a9325559 100644 --- a/pkg/dependency/parser/nodejs/pnpm/parse_testcase.go +++ b/pkg/dependency/parser/nodejs/pnpm/parse_testcase.go @@ -752,6 +752,13 @@ var ( Version: "0.4.0", Relationship: ftypes.RelationshipIndirect, }, + { + ID: "await-sleep@0.0.1", + Name: "await-sleep", + Version: "0.0.1", + Dev: true, + Relationship: ftypes.RelationshipDirect, + }, { ID: "debug@4.3.4", Name: "debug", @@ -843,6 +850,12 @@ var ( Version: "8.1.0", Relationship: ftypes.RelationshipDirect, }, + { + ID: "sleep-utils@1.0.3", + Name: "sleep-utils", + Version: "1.0.3", + Relationship: ftypes.RelationshipDirect, + }, { ID: "statuses@1.4.0", Name: "statuses", diff --git a/pkg/dependency/parser/nodejs/pnpm/testdata/pnpm-lock_v9.yaml b/pkg/dependency/parser/nodejs/pnpm/testdata/pnpm-lock_v9.yaml index 12a61f02b79a..ef8a229a3c88 100644 --- a/pkg/dependency/parser/nodejs/pnpm/testdata/pnpm-lock_v9.yaml +++ b/pkg/dependency/parser/nodejs/pnpm/testdata/pnpm-lock_v9.yaml @@ -40,6 +40,17 @@ importers: specifier: 2.0.0 version: 2.0.0 + subdir: + dependencies: + sleep-utils: + specifier: 1.0.3 + version: 1.0.3 + + devDependencies: + await-sleep: + specifier: ^0.0.1 + version: 0.0.1 + packages: '@babel/helper-string-parser@7.24.1': @@ -52,6 +63,9 @@ packages: asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + await-sleep@0.0.1: + resolution: {integrity: sha512-H3X3eAxwGpeNIk/yvFOs8g7500Q1YvzrxjSC9TNgLGtjrMFxPwhDdcT34QNs2iGWpZ+5WKkMJdjDoYs+Sw+TaA==} + debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -117,6 +131,9 @@ packages: promise@8.1.0: resolution: {integrity: sha512-W04AqnILOL/sPRXziNicCjSNRruLAuIHEOVBazepu0545DDNGYHz7ar9ZgZ1fMU8/MA4mVxp5rkBWRi6OXIy3Q==} + sleep-utils@1.0.3: + resolution: {integrity: sha512-uJW7WDHISE1zJIdvoIewcdmis3pBvJhM30rni2gH7fHhV1NkTWLKw3J6CPRFdg3h+rFChFHzAgbkCKUErd4s8Q==} + statuses@1.4.0: resolution: {integrity: sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==} engines: {node: '>= 0.6'} @@ -134,6 +151,8 @@ snapshots: asynckit@0.4.0: {} + await-sleep@0.0.1: {} + debug@4.3.4(supports-color@8.1.1): dependencies: ms: 2.0.0 @@ -186,6 +205,8 @@ snapshots: optionalDependencies: asap: 2.0.6 + sleep-utils@1.0.3: {} + statuses@1.4.0: {} unpipe@1.0.0: {} From 1a6295c5e5a97415728c51feff3af6967fcb39e3 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Mon, 2 Sep 2024 13:49:33 +0600 Subject: [PATCH 061/183] test: add integration plugin tests (#7299) --- integration/plugin_test.go | 111 ++++++++++++++++++ ...t-0.1.0-plugin-with-before-flag.txt.golden | 5 + .../testdata/count-0.2.0-plugin.txt.golden | 5 + 3 files changed, 121 insertions(+) create mode 100644 integration/plugin_test.go create mode 100644 integration/testdata/count-0.1.0-plugin-with-before-flag.txt.golden create mode 100644 integration/testdata/count-0.2.0-plugin.txt.golden diff --git a/integration/plugin_test.go b/integration/plugin_test.go new file mode 100644 index 000000000000..e4a6bf4d0014 --- /dev/null +++ b/integration/plugin_test.go @@ -0,0 +1,111 @@ +//go:build integration + +package integration + +import ( + "io" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/aquasecurity/trivy/pkg/utils/fsutils" +) + +func TestPlugin(t *testing.T) { + tests := []struct { + name string + plugin string + pluginArgs string + golden string + }{ + { + name: "count plugin installed from `index`", + plugin: "count@v0.2.0", + golden: "testdata/count-0.2.0-plugin.txt.golden", + }, + { + name: "count plugin installed from github archive", + plugin: "https://github.com/aquasecurity/trivy-plugin-count/archive/refs/tags/v0.1.0.zip", + pluginArgs: "--published-before=2020-01-01", + golden: "testdata/count-0.1.0-plugin-with-before-flag.txt.golden", + }, + } + + // Set up testing DB + cacheDir := initDB(t) + tempStdOut := setTempStdout(t) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // We can overwrite stdout for `_default_Manager` only once. + // So we need to clear the temporary stdout file before each test case. + clearFile(t, tempStdOut) + + t.Setenv("XDG_DATA_HOME", t.TempDir()) + + // Install plugin + err := execute([]string{ + "plugin", + "install", + tt.plugin, + }) + require.NoError(t, err) + + // Get list of plugins + err = execute([]string{ + "plugin", + "list", + }) + require.NoError(t, err) + + // Run Trivy with plugin as output + args := []string{ + "--cache-dir", + cacheDir, + "fs", + "-f", + "json", + "-o", + "plugin=count", + "testdata/fixtures/repo/pip", + } + + if tt.pluginArgs != "" { + args = append(args, "--output-plugin-arg", tt.pluginArgs) + } + + err = execute(args) + + if *update { + fsutils.CopyFile(tempStdOut.Name(), tt.golden) + } + + compareRawFiles(t, tt.golden, tempStdOut.Name()) + }) + } +} + +func setTempStdout(t *testing.T) *os.File { + tmpFile := filepath.Join(t.TempDir(), "output.txt") + f, err := os.Create(tmpFile) + require.NoError(t, err) + + // Overwrite Stdout to get output of plugin + defaultStdout := os.Stdout + os.Stdout = f + t.Cleanup(func() { + os.Stdout = defaultStdout + f.Close() + }) + return f +} + +func clearFile(t *testing.T, file *os.File) { + _, err := file.Seek(0, io.SeekStart) + require.NoError(t, err) + + _, err = file.Write([]byte{}) + require.NoError(t, err) +} diff --git a/integration/testdata/count-0.1.0-plugin-with-before-flag.txt.golden b/integration/testdata/count-0.1.0-plugin-with-before-flag.txt.golden new file mode 100644 index 000000000000..4c9d2bbaeb41 --- /dev/null +++ b/integration/testdata/count-0.1.0-plugin-with-before-flag.txt.golden @@ -0,0 +1,5 @@ +Installed Plugins: + Name: count + Version: 0.1.0 + +Number of vulnerabilities: 1 diff --git a/integration/testdata/count-0.2.0-plugin.txt.golden b/integration/testdata/count-0.2.0-plugin.txt.golden new file mode 100644 index 000000000000..9f86fc48e6dd --- /dev/null +++ b/integration/testdata/count-0.2.0-plugin.txt.golden @@ -0,0 +1,5 @@ +Installed Plugins: + Name: count + Version: 0.2.0 + +Number of vulnerabilities: 2 From af1d257730422d238871beb674767f8f83c5d06a Mon Sep 17 00:00:00 2001 From: Bob Callaway Date: Tue, 3 Sep 2024 01:47:21 -0400 Subject: [PATCH 062/183] feat(sbom): set User-Agent header on requests to Rekor (#7396) Signed-off-by: Bob Callaway --- go.mod | 4 ++-- pkg/rekor/client.go | 15 +++++---------- pkg/rekor/client_test.go | 7 +++++++ 3 files changed, 14 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 844135ff79f8..2e8f5c7ad25c 100644 --- a/go.mod +++ b/go.mod @@ -47,8 +47,8 @@ require ( github.com/docker/go-connections v0.5.0 github.com/fatih/color v1.17.0 github.com/go-git/go-git/v5 v5.12.0 - github.com/go-openapi/runtime v0.28.0 - github.com/go-openapi/strfmt v0.23.0 + github.com/go-openapi/runtime v0.28.0 // indirect + github.com/go-openapi/strfmt v0.23.0 // indirect github.com/go-redis/redis/v8 v8.11.5 github.com/golang-jwt/jwt/v5 v5.2.1 github.com/google/go-containerregistry v0.20.2 diff --git a/pkg/rekor/client.go b/pkg/rekor/client.go index d748166d6d7f..c6390f9679db 100644 --- a/pkg/rekor/client.go +++ b/pkg/rekor/client.go @@ -2,11 +2,10 @@ package rekor import ( "context" - "net/url" + "fmt" "slices" - httptransport "github.com/go-openapi/runtime/client" - "github.com/go-openapi/strfmt" + pkgclient "github.com/sigstore/rekor/pkg/client" "github.com/sigstore/rekor/pkg/generated/client" eclient "github.com/sigstore/rekor/pkg/generated/client/entries" "github.com/sigstore/rekor/pkg/generated/client/index" @@ -14,6 +13,7 @@ import ( "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/log" + "github.com/aquasecurity/trivy/pkg/version/app" ) const ( @@ -64,15 +64,10 @@ type Client struct { } func NewClient(rekorURL string) (*Client, error) { - u, err := url.Parse(rekorURL) + c, err := pkgclient.GetRekorClient(rekorURL, pkgclient.WithUserAgent(fmt.Sprintf("trivy/%s", app.Version()))) if err != nil { - return nil, xerrors.Errorf("failed to parse url: %w", err) + return nil, xerrors.Errorf("failed to create rekor client: %w", err) } - - c := client.New( - httptransport.New(u.Host, client.DefaultBasePath, []string{u.Scheme}), - strfmt.Default, - ) return &Client{Rekor: c}, nil } diff --git a/pkg/rekor/client_test.go b/pkg/rekor/client_test.go index 9ea48d657cc5..f9390122fbf0 100644 --- a/pkg/rekor/client_test.go +++ b/pkg/rekor/client_test.go @@ -4,6 +4,7 @@ import ( "context" "net/http" "net/http/httptest" + "strings" "testing" "github.com/stretchr/testify/assert" @@ -56,6 +57,9 @@ func TestClient_Search(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if !strings.HasPrefix(r.UserAgent(), "trivy/") { + t.Fatalf("User-Agent header was not specified") + } http.ServeFile(w, r, tt.mockResponseFile) return })) @@ -148,6 +152,9 @@ func TestClient_GetEntries(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if !strings.HasPrefix(r.UserAgent(), "trivy/") { + t.Fatalf("User-Agent header was not specified") + } http.ServeFile(w, r, tt.mockResponseFile) return })) From da4ebfa1a741f3f8b0b43289b4028afe763f7d43 Mon Sep 17 00:00:00 2001 From: vhash <29121316+LucasVanHaaren@users.noreply.github.com> Date: Tue, 3 Sep 2024 07:48:12 +0200 Subject: [PATCH 063/183] fix(helm): explicitly define `kind` and `apiVersion` of `volumeClaimTemplate` element (#7362) --- helm/trivy/templates/statefulset.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/helm/trivy/templates/statefulset.yaml b/helm/trivy/templates/statefulset.yaml index efb90274fe2c..4a931d2ac0b0 100644 --- a/helm/trivy/templates/statefulset.yaml +++ b/helm/trivy/templates/statefulset.yaml @@ -17,7 +17,9 @@ spec: app.kubernetes.io/instance: {{ .Release.Name }} {{- if .Values.persistence.enabled }} volumeClaimTemplates: - - metadata: + - apiVersion: v1 + kind: PersistentVolumeClaim + metadata: name: data spec: resources: From 870523d384add914cb4edf6271393986da7d69c9 Mon Sep 17 00:00:00 2001 From: simar7 <1254783+simar7@users.noreply.github.com> Date: Tue, 3 Sep 2024 00:31:17 -0600 Subject: [PATCH 064/183] chore(deps): Bump trivy-checks and pin OPA (#7427) Signed-off-by: nikpivkin Co-authored-by: nikpivkin --- .../configuration/cli/trivy_config.md | 2 +- .../configuration/cli/trivy_filesystem.md | 2 +- .../configuration/cli/trivy_image.md | 2 +- .../configuration/cli/trivy_kubernetes.md | 2 +- .../configuration/cli/trivy_repository.md | 2 +- .../configuration/cli/trivy_rootfs.md | 2 +- .../references/configuration/config-file.md | 2 +- go.mod | 18 ++++++---- go.sum | 34 ++++++++++--------- pkg/flag/rego_flags.go | 1 + pkg/iac/scanners/cloudformation/scanner.go | 4 +-- 11 files changed, 39 insertions(+), 32 deletions(-) diff --git a/docs/docs/references/configuration/cli/trivy_config.md b/docs/docs/references/configuration/cli/trivy_config.md index b32e74c1c752..91cd64292ea8 100644 --- a/docs/docs/references/configuration/cli/trivy_config.md +++ b/docs/docs/references/configuration/cli/trivy_config.md @@ -31,7 +31,7 @@ trivy config [flags] DIR -h, --help help for config --ignore-policy string specify the Rego file path to evaluate each vulnerability --ignorefile string specify .trivyignore file (default ".trivyignore") - --include-deprecated-checks include deprecated checks + --include-deprecated-checks include deprecated checks (default true) --include-non-failures include successes and exceptions, available with '--scanners misconfig' --k8s-version string specify k8s version to validate outdated api by it (example: 1.21.0) --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index 16c5909549e3..e907c5d4f9d5 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -53,7 +53,7 @@ trivy filesystem [flags] PATH --ignore-unfixed display only fixed vulnerabilities --ignored-licenses strings specify a list of license to ignore --ignorefile string specify .trivyignore file (default ".trivyignore") - --include-deprecated-checks include deprecated checks + --include-deprecated-checks include deprecated checks (default true) --include-dev-deps include development dependencies in the report (supported: npm, yarn) --include-non-failures include successes and exceptions, available with '--scanners misconfig' --java-db-repository string OCI repository to retrieve trivy-java-db from (default "ghcr.io/aquasecurity/trivy-java-db:1") diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index bbd75e690cfc..156582f047ad 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -71,7 +71,7 @@ trivy image [flags] IMAGE_NAME --ignorefile string specify .trivyignore file (default ".trivyignore") --image-config-scanners strings comma-separated list of what security issues to detect on container image configurations (misconfig,secret) --image-src strings image source(s) to use, in priority order (docker,containerd,podman,remote) (default [docker,containerd,podman,remote]) - --include-deprecated-checks include deprecated checks + --include-deprecated-checks include deprecated checks (default true) --include-non-failures include successes and exceptions, available with '--scanners misconfig' --input string input file path instead of image name --java-db-repository string OCI repository to retrieve trivy-java-db from (default "ghcr.io/aquasecurity/trivy-java-db:1") diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 2bc84e905282..b7c626a7d476 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -66,7 +66,7 @@ trivy kubernetes [flags] [CONTEXT] --ignore-unfixed display only fixed vulnerabilities --ignorefile string specify .trivyignore file (default ".trivyignore") --image-src strings image source(s) to use, in priority order (docker,containerd,podman,remote) (default [docker,containerd,podman,remote]) - --include-deprecated-checks include deprecated checks + --include-deprecated-checks include deprecated checks (default true) --include-kinds strings indicate the kinds included in scanning (example: node) --include-namespaces strings indicate the namespaces included in scanning (example: kube-system) --include-non-failures include successes and exceptions, available with '--scanners misconfig' diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index eeef161725a8..04f3f26e919a 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -53,7 +53,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --ignore-unfixed display only fixed vulnerabilities --ignored-licenses strings specify a list of license to ignore --ignorefile string specify .trivyignore file (default ".trivyignore") - --include-deprecated-checks include deprecated checks + --include-deprecated-checks include deprecated checks (default true) --include-dev-deps include development dependencies in the report (supported: npm, yarn) --include-non-failures include successes and exceptions, available with '--scanners misconfig' --java-db-repository string OCI repository to retrieve trivy-java-db from (default "ghcr.io/aquasecurity/trivy-java-db:1") diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index 88f5bd197779..0e0dfa54d448 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -56,7 +56,7 @@ trivy rootfs [flags] ROOTDIR --ignore-unfixed display only fixed vulnerabilities --ignored-licenses strings specify a list of license to ignore --ignorefile string specify .trivyignore file (default ".trivyignore") - --include-deprecated-checks include deprecated checks + --include-deprecated-checks include deprecated checks (default true) --include-non-failures include successes and exceptions, available with '--scanners misconfig' --java-db-repository string OCI repository to retrieve trivy-java-db from (default "ghcr.io/aquasecurity/trivy-java-db:1") --license-confidence-level float specify license classifier's confidence level (default 0.9) diff --git a/docs/docs/references/configuration/config-file.md b/docs/docs/references/configuration/config-file.md index 6a54b8e27bdc..b2b25e47689e 100644 --- a/docs/docs/references/configuration/config-file.md +++ b/docs/docs/references/configuration/config-file.md @@ -477,7 +477,7 @@ rego: data: [] # Same as '--include-deprecated-checks' - include-deprecated-checks: false + include-deprecated-checks: true # Same as '--check-namespaces' namespaces: [] diff --git a/go.mod b/go.mod index 2e8f5c7ad25c..62c3dd5a6f18 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/aquasecurity/table v1.8.0 github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8 github.com/aquasecurity/tml v0.6.1 - github.com/aquasecurity/trivy-checks v0.13.1-0.20240830035934-7761a83288cd + github.com/aquasecurity/trivy-checks v0.13.1-0.20240830230553-53ddbbade784 github.com/aquasecurity/trivy-db v0.0.0-20240718084044-d23a6ca8ba04 github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20240707095038-0300bc49b68b @@ -41,7 +41,7 @@ require ( github.com/bmatcuk/doublestar/v4 v4.6.1 github.com/cenkalti/backoff/v4 v4.3.0 github.com/cheggaaa/pb/v3 v3.1.5 - github.com/containerd/containerd v1.7.20 + github.com/containerd/containerd v1.7.21 github.com/csaf-poc/csaf_distribution/v3 v3.0.0 github.com/docker/docker v27.1.1+incompatible github.com/docker/go-connections v0.5.0 @@ -301,7 +301,8 @@ require ( github.com/moby/sys/mountinfo v0.7.1 // indirect github.com/moby/sys/sequential v0.5.0 // indirect github.com/moby/sys/signal v0.7.0 // indirect - github.com/moby/sys/user v0.1.0 // indirect + github.com/moby/sys/user v0.3.0 // indirect + github.com/moby/sys/userns v0.1.0 // indirect github.com/moby/term v0.5.0 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/reflect2 v1.0.2 // indirect @@ -322,9 +323,9 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_golang v1.20.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.51.1 // indirect + github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect @@ -377,10 +378,10 @@ require ( go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/oauth2 v0.20.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect golang.org/x/sys v0.23.0 // indirect golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 // indirect - golang.org/x/time v0.5.0 // indirect + golang.org/x/time v0.6.0 // indirect golang.org/x/tools v0.23.0 // indirect google.golang.org/api v0.172.0 // indirect google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 // indirect @@ -418,3 +419,6 @@ require ( // cf. https://github.com/openvex/discovery/pull/40 replace github.com/openvex/discovery => github.com/knqyf263/discovery v0.1.1-0.20240726113521-97873005fd03 + +// see https://github.com/open-policy-agent/opa/pull/6970 +replace github.com/open-policy-agent/opa => github.com/nikpivkin/opa v0.0.0-20240829080621-16999fcb5464 diff --git a/go.sum b/go.sum index e760459b4d51..fdb1c5a2dcd6 100644 --- a/go.sum +++ b/go.sum @@ -348,8 +348,8 @@ github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8 h1:b43UVqY github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8/go.mod h1:wXA9k3uuaxY3yu7gxrxZDPo/04FEMJtwyecdAlYrEIo= github.com/aquasecurity/tml v0.6.1 h1:y2ZlGSfrhnn7t4ZJ/0rotuH+v5Jgv6BDDO5jB6A9gwo= github.com/aquasecurity/tml v0.6.1/go.mod h1:OnYMWY5lvI9ejU7yH9LCberWaaTBW7hBFsITiIMY2yY= -github.com/aquasecurity/trivy-checks v0.13.1-0.20240830035934-7761a83288cd h1:/6sPLCU4JICPPYAmY2iUsLGpgYBXUH6M/0fy57AhNWY= -github.com/aquasecurity/trivy-checks v0.13.1-0.20240830035934-7761a83288cd/go.mod h1:zLBeXaTJkAvPZqKiRACAsP49ZywCEXFEjXMLa8kmc8Q= +github.com/aquasecurity/trivy-checks v0.13.1-0.20240830230553-53ddbbade784 h1:1rvPiCK8uQd3sarOuZ60nwksHpxsNdrvptz4eDW/V14= +github.com/aquasecurity/trivy-checks v0.13.1-0.20240830230553-53ddbbade784/go.mod h1:Ralz7PWmR3LirHlXxVtUXc+7CFmWE82jbLk7+TPvV/0= github.com/aquasecurity/trivy-db v0.0.0-20240718084044-d23a6ca8ba04 h1:6/T8sFdNVG/AwOGoK6X55h7hF7LYqK8bsuPz8iEz8jM= github.com/aquasecurity/trivy-db v0.0.0-20240718084044-d23a6ca8ba04/go.mod h1:0T6oy2t1Iedt+yi3Ml5cpOYp5FZT4MI1/mx+3p+PIs8= github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 h1:JVgBIuIYbwG+ekC5lUHUpGJboPYiCcxiz06RCtz8neI= @@ -479,8 +479,8 @@ github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= github.com/containerd/cgroups/v3 v3.0.2 h1:f5WFqIVSgo5IZmtTT3qVBo6TzI1ON6sycSBKkymb9L0= github.com/containerd/cgroups/v3 v3.0.2/go.mod h1:JUgITrzdFqp42uI2ryGA+ge0ap/nxzYgkGmIcetmErE= -github.com/containerd/containerd v1.7.20 h1:Sl6jQYk3TRavaU83h66QMbI2Nqg9Jm6qzwX57Vsn1SQ= -github.com/containerd/containerd v1.7.20/go.mod h1:52GsS5CwquuqPuLncsXwG0t2CiUce+KsNHJZQJvAgR0= +github.com/containerd/containerd v1.7.21 h1:USGXRK1eOC/SX0L195YgxTHb0a00anxajOzgfN0qrCA= +github.com/containerd/containerd v1.7.21/go.mod h1:e3Jz1rYRUZ2Lt51YrH9Rz0zPyJBOlSvB3ghr2jbVD8g= github.com/containerd/containerd/api v1.7.19 h1:VWbJL+8Ap4Ju2mx9c9qS1uFSB1OVYr5JJrW2yT5vFoA= github.com/containerd/containerd/api v1.7.19/go.mod h1:fwGavl3LNwAV5ilJ0sbrABL44AQxmNjDRcwheXDb6Ig= github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= @@ -1096,8 +1096,10 @@ github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5 github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI= github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= -github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg= -github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU= +github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= +github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= +github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -1120,6 +1122,8 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= 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/nikpivkin/opa v0.0.0-20240829080621-16999fcb5464 h1:jhZ8nLVxOAslgzmPdKTyctfDJkMfRgksCypFriHzf4E= +github.com/nikpivkin/opa v0.0.0-20240829080621-16999fcb5464/go.mod h1:cvSIxY0dexL39hOPqXSZKdBYFNx2Rv8Fu5n3MmTjqtE= 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= @@ -1143,8 +1147,6 @@ 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.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE= github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk= -github.com/open-policy-agent/opa v0.67.1 h1:rzy26J6g1X+CKknAcx0Vfbt41KqjuSzx4E0A8DAZf3E= -github.com/open-policy-agent/opa v0.67.1/go.mod h1:aqKlHc8E2VAAylYE9x09zJYr/fYzGX+JKne89UGqFzk= 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.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -1190,8 +1192,8 @@ github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjz github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_golang v1.20.1 h1:IMJXHOD6eARkQpxo8KkhgEVFlBNm+nkrFUyGlIu7Na8= +github.com/prometheus/client_golang v1.20.1/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1199,8 +1201,8 @@ github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= -github.com/prometheus/common v0.51.1 h1:eIjN50Bwglz6a/c3hAgSMcofL3nD+nFQkV6Dd4DsQCw= -github.com/prometheus/common v0.51.1/go.mod h1:lrWtQx+iDfn2mbH5GUzlH9TSHyfZpHkSiG1W7y3sF2Q= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= @@ -1605,8 +1607,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= -golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo= -golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= 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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1751,8 +1753,8 @@ golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= -golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= diff --git a/pkg/flag/rego_flags.go b/pkg/flag/rego_flags.go index 4b291f0a5eb3..5e856f30062e 100644 --- a/pkg/flag/rego_flags.go +++ b/pkg/flag/rego_flags.go @@ -11,6 +11,7 @@ var ( Name: "include-deprecated-checks", ConfigName: "rego.include-deprecated-checks", Usage: "include deprecated checks", + Default: true, } SkipCheckUpdateFlag = Flag[bool]{ Name: "skip-check-update", diff --git a/pkg/iac/scanners/cloudformation/scanner.go b/pkg/iac/scanners/cloudformation/scanner.go index e7677926944d..dc4deab0aff5 100644 --- a/pkg/iac/scanners/cloudformation/scanner.go +++ b/pkg/iac/scanners/cloudformation/scanner.go @@ -64,8 +64,8 @@ type Scanner struct { includeDeprecatedChecks bool } -func (s *Scanner) SetIncludeDeprecatedChecks(bool) { - s.includeDeprecatedChecks = true +func (s *Scanner) SetIncludeDeprecatedChecks(b bool) { + s.includeDeprecatedChecks = b } func (s *Scanner) SetCustomSchemas(map[string][]byte) {} From 2d97700d10665142d2f66d7910202bec82116209 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:28:49 +0600 Subject: [PATCH 065/183] feat(java): add `test` scope support for `pom.xml` files (#7414) --- docs/docs/coverage/language/java.md | 18 ++++++++---- pkg/dependency/parser/java/pom/artifact.go | 1 + pkg/dependency/parser/java/pom/parse.go | 4 ++- pkg/dependency/parser/java/pom/parse_test.go | 28 +++++++++++++++++++ pkg/dependency/parser/java/pom/pom.go | 1 + .../parser/java/pom/testdata/happy/pom.xml | 6 ++++ 6 files changed, 51 insertions(+), 7 deletions(-) diff --git a/docs/docs/coverage/language/java.md b/docs/docs/coverage/language/java.md index 67cd8c135b9d..26bad288e552 100644 --- a/docs/docs/coverage/language/java.md +++ b/docs/docs/coverage/language/java.md @@ -12,12 +12,12 @@ Each artifact supports the following scanners: The following table provides an outline of the features Trivy offers. -| Artifact | Internet access | Dev dependencies | [Dependency graph][dependency-graph] | Position | [Detection Priority][detection-priority] | -|------------------|:---------------------:|:----------------:|:------------------------------------:|:--------:|:----------------------------------------:| -| JAR/WAR/PAR/EAR | Trivy Java DB | Include | - | - | Not needed | -| pom.xml | Maven repository [^1] | Exclude | ✓ | ✓[^7] | - | -| *gradle.lockfile | - | Exclude | ✓ | ✓ | Not needed | -| *.sbt.lock | - | Exclude | - | ✓ | Not needed | +| Artifact | Internet access | Dev dependencies | [Dependency graph][dependency-graph] | Position | [Detection Priority][detection-priority] | +|------------------|:---------------------:|:------------------:|:------------------------------------:|:--------:|:----------------------------------------:| +| JAR/WAR/PAR/EAR | Trivy Java DB | Include | - | - | Not needed | +| pom.xml | Maven repository [^1] | [Exclude](#scopes) | ✓ | ✓[^7] | - | +| *gradle.lockfile | - | Exclude | ✓ | ✓ | Not needed | +| *.sbt.lock | - | Exclude | - | ✓ | Not needed | These may be enabled or disabled depending on the target. See [here](./index.md) for the detail. @@ -69,6 +69,11 @@ The vulnerability database will be downloaded anyway. !!! Warning Trivy may skip some dependencies (that were not found on your local machine) when the `--offline-scan` flag is passed. +### scopes +Trivy supports `runtime`, `compile`, `test` and `import` (for `dependencyManagement`) [dependency scopes][dependency-scopes]. +Dependencies without scope are also detected. + +By default, Trivy doesn't report dependencies with `test` scope. Use the `--include-dev-deps` flag to include them. ### maven-invoker-plugin Typically, the integration tests directory (`**/[src|target]/it/*/pom.xml`) of [maven-invoker-plugin][maven-invoker-plugin] doesn't contain actual `pom.xml` files and should be skipped to avoid noise. @@ -120,3 +125,4 @@ Make sure that you have cache[^8] directory to find licenses from `*.pom` depend [maven-pom-repos]: https://maven.apache.org/settings.html#repositories [sbt-dependency-lock]: https://stringbean.github.io/sbt-dependency-lock [detection-priority]: ../../scanner/vulnerability.md#detection-priority +[dependency-scopes]: https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope diff --git a/pkg/dependency/parser/java/pom/artifact.go b/pkg/dependency/parser/java/pom/artifact.go index b2e97efb229b..f691afac5ebd 100644 --- a/pkg/dependency/parser/java/pom/artifact.go +++ b/pkg/dependency/parser/java/pom/artifact.go @@ -27,6 +27,7 @@ type artifact struct { Module bool Relationship ftypes.Relationship + Test bool Locations ftypes.Locations } diff --git a/pkg/dependency/parser/java/pom/parse.go b/pkg/dependency/parser/java/pom/parse.go index cbd7bf47db17..57f41a1d32f4 100644 --- a/pkg/dependency/parser/java/pom/parse.go +++ b/pkg/dependency/parser/java/pom/parse.go @@ -214,6 +214,7 @@ func (p *Parser) parseRoot(root artifact, uniqModules map[string]struct{}) ([]ft Licenses: result.artifact.Licenses, Relationship: art.Relationship, Locations: art.Locations, + Test: art.Test, } // save only dependency names @@ -234,6 +235,7 @@ func (p *Parser) parseRoot(root artifact, uniqModules map[string]struct{}) ([]ft Licenses: art.Licenses, Relationship: art.Relationship, Locations: art.Locations, + Dev: art.Test, } pkgs = append(pkgs, pkg) @@ -400,7 +402,7 @@ func (p *Parser) parseDependencies(deps []pomDependency, props map[string]string // Resolve dependencies d = d.Resolve(props, depManagement, rootDepManagement) - if (d.Scope != "" && d.Scope != "compile" && d.Scope != "runtime") || d.Optional { + if (d.Scope != "" && d.Scope != "compile" && d.Scope != "runtime" && d.Scope != "test") || d.Optional { continue } diff --git a/pkg/dependency/parser/java/pom/parse_test.go b/pkg/dependency/parser/java/pom/parse_test.go index 934085d5d536..77a47b5ecdac 100644 --- a/pkg/dependency/parser/java/pom/parse_test.go +++ b/pkg/dependency/parser/java/pom/parse_test.go @@ -61,6 +61,19 @@ func TestPom_Parse(t *testing.T) { }, }, }, + { + ID: "org.example:example-test:2.0.0", + Name: "org.example:example-test", + Version: "2.0.0", + Relationship: ftypes.RelationshipDirect, + Dev: true, + Locations: ftypes.Locations{ + { + StartLine: 49, + EndLine: 54, + }, + }, + }, }, wantDeps: []ftypes.Dependency{ { @@ -68,6 +81,7 @@ func TestPom_Parse(t *testing.T) { DependsOn: []string{ "org.example:example-api:1.7.30", "org.example:example-runtime:1.0.0", + "org.example:example-test:2.0.0", }, }, }, @@ -109,6 +123,19 @@ func TestPom_Parse(t *testing.T) { }, }, }, + { + ID: "org.example:example-test:2.0.0", + Name: "org.example:example-test", + Version: "2.0.0", + Relationship: ftypes.RelationshipDirect, + Dev: true, + Locations: ftypes.Locations{ + { + StartLine: 49, + EndLine: 54, + }, + }, + }, }, wantDeps: []ftypes.Dependency{ { @@ -116,6 +143,7 @@ func TestPom_Parse(t *testing.T) { DependsOn: []string{ "org.example:example-api:1.7.30", "org.example:example-runtime:1.0.0", + "org.example:example-test:2.0.0", }, }, }, diff --git a/pkg/dependency/parser/java/pom/pom.go b/pkg/dependency/parser/java/pom/pom.go index 889d107c3c6c..d27f995217d6 100644 --- a/pkg/dependency/parser/java/pom/pom.go +++ b/pkg/dependency/parser/java/pom/pom.go @@ -303,6 +303,7 @@ func (d pomDependency) ToArtifact(opts analysisOptions) artifact { Exclusions: exclusions, Locations: locations, Relationship: ftypes.RelationshipIndirect, // default + Test: d.Scope == "test", } } diff --git a/pkg/dependency/parser/java/pom/testdata/happy/pom.xml b/pkg/dependency/parser/java/pom/testdata/happy/pom.xml index 1f3c9697a17d..9dfc1c75bd65 100644 --- a/pkg/dependency/parser/java/pom/testdata/happy/pom.xml +++ b/pkg/dependency/parser/java/pom/testdata/happy/pom.xml @@ -46,5 +46,11 @@ 999 provided + + org.example + example-test + 2.0.0 + test + From f80183c1139b21bb95bc64e216358f4a76001a65 Mon Sep 17 00:00:00 2001 From: psibre Date: Tue, 3 Sep 2024 10:31:55 +0200 Subject: [PATCH 066/183] fix(license): add license handling to JUnit template (#7409) --- contrib/junit.tpl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/contrib/junit.tpl b/contrib/junit.tpl index 08e649b9eb00..b01bb9fd22dd 100644 --- a/contrib/junit.tpl +++ b/contrib/junit.tpl @@ -33,5 +33,16 @@ {{- end }} + +{{- if .Licenses }} + {{- $licenses := len .Licenses }} + {{ range .Licenses }} + + + + {{- end }} + +{{- end }} + {{- end }} From 2d80769c34b118851640411fff9dac0b3e353e82 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Tue, 3 Sep 2024 14:42:41 +0600 Subject: [PATCH 067/183] feat(go): use `toolchain` as `stdlib` version for `go.mod` files (#7163) --- docs/docs/coverage/language/golang.md | 21 +++- pkg/dependency/parser/golang/mod/parse.go | 81 +++++++++++-- .../parser/golang/mod/parse_test.go | 108 +++++++++++++++++- .../parser/golang/mod/parse_testcase.go | 62 ++++++++-- .../parser/golang/mod/testdata/normal/go.mod | 12 +- .../parser/golang/mod/testdata/normal/go.sum | 74 ++---------- .../parser/golang/mod/testdata/normal/main.go | 4 +- pkg/fanal/analyzer/language/golang/mod/mod.go | 4 +- 8 files changed, 270 insertions(+), 96 deletions(-) diff --git a/docs/docs/coverage/language/golang.md b/docs/docs/coverage/language/golang.md index cf3e160a608b..f2cbff03255a 100644 --- a/docs/docs/coverage/language/golang.md +++ b/docs/docs/coverage/language/golang.md @@ -18,7 +18,7 @@ The table below provides an outline of the features Trivy offers. | Artifact | Offline[^1] | Dev dependencies | [Dependency graph][dependency-graph] | Stdlib | [Detection Priority][detection-priority] | |----------|:-----------:|:-----------------|:------------------------------------:|:------:|:----------------------------------------:| -| Modules | ✅ | Include | ✅[^2] | - | - | +| Modules | ✅ | Include | ✅[^2] | ✅[^6] | [✅](#stdlib) | | Binaries | ✅ | Exclude | - | ✅[^4] | Not needed | !!! note @@ -65,6 +65,23 @@ To identify licenses and dependency relationships, you need to download modules such as `go mod download`, `go mod tidy`, etc. Trivy traverses `$GOPATH/pkg/mod` and collects those extra information. +#### stdlib +If [--detection-priority comprehensive][detection-priority] is passed, Trivy determines the minimum version of `Go` and saves it as a `stdlib` dependency. + +By default, `Go` selects the higher version from of `toolchan` or local version of `Go`. +See [toolchain] for more details. + +To obtain reproducible scan results Trivy doesn't check the local version of `Go`. +Trivy shows the minimum required version for the `go.mod` file, obtained from `toolchain` line (or from the `go` line, if `toolchain` line is omitted). + +!!! note + Trivy detects `stdlib` only for `Go` 1.21 or higher. + + The version from the `go` line (for `Go` 1.20 or early) is not a minimum required version. + For details, see [this](https://go.googlesource.com/proposal/+/master/design/57001-gotoolchain.md). + + + ### Go binaries Trivy scans binaries built by Go, which include [module information](https://tip.golang.org/doc/go1.18#go-version). If there is a Go binary in your container image, Trivy automatically finds and scans it. @@ -93,6 +110,8 @@ empty if it cannot do so[^5]. For the second case, the version of such packages [^3]: See https://github.com/aquasecurity/trivy/issues/1837#issuecomment-1832523477 [^4]: Identify the Go version used to compile the binary and detect its vulnerabilities [^5]: See https://github.com/golang/go/issues/63432#issuecomment-1751610604 +[^6]: Only available if `toolchain` directive exists [dependency-graph]: ../../configuration/reporting.md#show-origins-of-vulnerable-dependencies +[toolchain]: https://go.dev/doc/toolchain [detection-priority]: ../../scanner/vulnerability.md#detection-priority diff --git a/pkg/dependency/parser/golang/mod/parse.go b/pkg/dependency/parser/golang/mod/parse.go index 508da6911521..bbf42926a766 100644 --- a/pkg/dependency/parser/golang/mod/parse.go +++ b/pkg/dependency/parser/golang/mod/parse.go @@ -29,12 +29,14 @@ var ( ) type Parser struct { - replace bool // 'replace' represents if the 'replace' directive should be taken into account. + replace bool // 'replace' represents if the 'replace' directive should be taken into account. + useMinVersion bool } -func NewParser(replace bool) *Parser { +func NewParser(replace, useMinVersion bool) *Parser { return &Parser{ - replace: replace, + replace: replace, + useMinVersion: useMinVersion, } } @@ -80,7 +82,20 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc skipIndirect := true if modFileParsed.Go != nil { // Old go.mod file may not include the go version. Go version for these files is less than 1.17 - skipIndirect = lessThan117(modFileParsed.Go.Version) + skipIndirect = lessThan(modFileParsed.Go.Version, 1, 17) + } + + // Use minimal required go version from `toolchain` line (or from `go` line if `toolchain` is omitted) as `stdlib`. + // Show `stdlib` only with `useMinVersion` flag. + if p.useMinVersion { + if toolchainVer := toolchainVersion(modFileParsed.Toolchain, modFileParsed.Go); toolchainVer != "" { + pkgs["stdlib"] = ftypes.Package{ + ID: packageID("stdlib", toolchainVer), + Name: "stdlib", + Version: toolchainVer, + Relationship: ftypes.RelationshipDirect, // Considered a direct dependency as the main module depends on the standard packages. + } + } } // Main module @@ -150,8 +165,12 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc return lo.Values(pkgs), nil, nil } -// Check if the Go version is less than 1.17 -func lessThan117(ver string) bool { +// lessThan checks if the Go version is less than `.` +func lessThan(ver string, majorVer, minorVer int) bool { + if ver == "" { + return false + } + ss := strings.Split(ver, ".") if len(ss) != 2 { return false @@ -165,7 +184,55 @@ func lessThan117(ver string) bool { return false } - return major <= 1 && minor < 17 + return major <= majorVer && minor < minorVer +} + +// toolchainVersion returns version from `toolchain`. +// If `toolchain` is omitted - return version from `go` line (if it is version in toolchain format) +// cf. https://go.dev/doc/toolchain +func toolchainVersion(toolchain *modfile.Toolchain, goVer *modfile.Go) string { + if toolchain != nil && toolchain.Name != "" { + // cf. https://go.dev/doc/toolchain#name + // `dropping the initial go and discarding off any suffix beginning with -` + // e.g. `go1.22.5-custom` => `1.22.5` + name, _, _ := strings.Cut(toolchain.Name, "-") + return strings.TrimPrefix(name, "go") + } + + if goVer != nil { + return toolchainVersionFromGoLine(goVer.Version) + } + return "" +} + +// toolchainVersionFromGoLine detects Go version from `go` line if `toolchain` line is omitted. +// `go` line supports the following formats: +// cf. https://go.dev/doc/toolchain#version +// - `1.N.P`. e.g. `1.22.0` +// - `1.N`. e.g. `1.22` +// - `1.NrcR`. e.g. `1.22rc1` +// - `1.NbetaR`. e.g. `1.18beta1` - only for Go 1.20 or earlier +func toolchainVersionFromGoLine(ver string) string { + var majorMinorVer string + + if ss := strings.Split(ver, "."); len(ss) > 2 { // `1.N.P` + majorMinorVer = strings.Join(ss[:2], ".") + } else if v, _, rcFound := strings.Cut(ver, "rc"); rcFound { // `1.NrcR` + majorMinorVer = v + } else { // `1.N` + majorMinorVer = ver + // Add `.0` suffix to avoid user confusing. + // See https://github.com/aquasecurity/trivy/pull/7163#discussion_r1682424315 + ver = v + ".0" + } + + // `toolchain` has been added in go 1.21. + // So we need to check that Go version is 1.21 or higher. + // cf. https://github.com/aquasecurity/trivy/pull/7163#discussion_r1682424315 + if lessThan(majorMinorVer, 1, 21) { + return "" + } + return ver } func packageID(name, version string) string { diff --git a/pkg/dependency/parser/golang/mod/parse_test.go b/pkg/dependency/parser/golang/mod/parse_test.go index 598cb3fe70f3..10bda7f01144 100644 --- a/pkg/dependency/parser/golang/mod/parse_test.go +++ b/pkg/dependency/parser/golang/mod/parse_test.go @@ -7,22 +7,31 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "golang.org/x/mod/modfile" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) func TestParse(t *testing.T) { tests := []struct { - name string - file string - replace bool - want []ftypes.Package + name string + file string + replace bool + useMinVersion bool + want []ftypes.Package }{ + { + name: "normal with stdlib", + file: "testdata/normal/go.mod", + replace: true, + useMinVersion: true, + want: GoModNormal, + }, { name: "normal", file: "testdata/normal/go.mod", replace: true, - want: GoModNormal, + want: GoModNormalWithoutStdlib, }, { name: "without go version", @@ -85,7 +94,7 @@ func TestParse(t *testing.T) { f, err := os.Open(tt.file) require.NoError(t, err) - got, _, err := NewParser(tt.replace).Parse(f) + got, _, err := NewParser(tt.replace, tt.useMinVersion).Parse(f) require.NoError(t, err) sort.Sort(ftypes.Packages(got)) @@ -95,3 +104,90 @@ func TestParse(t *testing.T) { }) } } + +func TestToolchainVersion(t *testing.T) { + tests := []struct { + name string + modFile modfile.File + want string + }{ + { + name: "version from toolchain line", + modFile: modfile.File{ + Toolchain: &modfile.Toolchain{ + Name: "1.21.1", + }, + }, + want: "1.21.1", + }, + { + name: "version from toolchain line with suffix", + modFile: modfile.File{ + Toolchain: &modfile.Toolchain{ + Name: "1.21.1-custom", + }, + }, + want: "1.21.1", + }, + { + name: "'1.18rc1' from go line", + modFile: modfile.File{ + Go: &modfile.Go{ + Version: "1.18rc1", + }, + }, + want: "", + }, + { + name: "'1.18.1' from go line", + modFile: modfile.File{ + Go: &modfile.Go{ + Version: "1.18.1", + }, + }, + want: "", + }, + { + name: "'1.20' from go line", + modFile: modfile.File{ + Go: &modfile.Go{ + Version: "1.20", + }, + }, + want: "", + }, + { + name: "'1.21' from go line", + modFile: modfile.File{ + Go: &modfile.Go{ + Version: "1.21", + }, + }, + want: "1.21.0", + }, + { + name: "'1.21rc1' from go line", + modFile: modfile.File{ + Go: &modfile.Go{ + Version: "1.21rc1", + }, + }, + want: "1.21rc1", + }, + { + name: "'1.21.2' from go line", + modFile: modfile.File{ + Go: &modfile.Go{ + Version: "1.21.2", + }, + }, + want: "1.21.2", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + require.Equal(t, tt.want, toolchainVersion(tt.modFile.Toolchain, tt.modFile.Go)) + }) + } +} diff --git a/pkg/dependency/parser/golang/mod/parse_testcase.go b/pkg/dependency/parser/golang/mod/parse_testcase.go index 5a07b939c549..4671ef3e6854 100644 --- a/pkg/dependency/parser/golang/mod/parse_testcase.go +++ b/pkg/dependency/parser/golang/mod/parse_testcase.go @@ -1,6 +1,10 @@ package mod -import ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" +import ( + "slices" + + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" +) var ( // execute go mod tidy in normal folder @@ -17,37 +21,71 @@ var ( }, }, { - ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20211224170007-df43bca6b6ff", - Name: "github.com/aquasecurity/go-dep-parser", - Version: "0.0.0-20211224170007-df43bca6b6ff", + ID: "stdlib@v1.22.5", + Name: "stdlib", + Version: "1.22.5", + Relationship: ftypes.RelationshipDirect, + }, + { + ID: "github.com/aquasecurity/go-version@v0.0.0-20240603093900-cf8a8d29271d", + Name: "github.com/aquasecurity/go-version", + Version: "0.0.0-20240603093900-cf8a8d29271d", Relationship: ftypes.RelationshipDirect, ExternalReferences: []ftypes.ExternalRef{ { Type: ftypes.RefVCS, - URL: "https://github.com/aquasecurity/go-dep-parser", + URL: "https://github.com/aquasecurity/go-version", }, }, }, { - ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", - Name: "golang.org/x/xerrors", - Version: "0.0.0-20200804184101-5ec99f83aff1", + ID: "github.com/davecgh/go-spew@v1.1.2-0.20180830191138-d8f796af33cc", + Name: "github.com/davecgh/go-spew", + Version: "1.1.2-0.20180830191138-d8f796af33cc", + Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ + { + Type: ftypes.RefVCS, + URL: "https://github.com/davecgh/go-spew", + }, + }, + }, + { + ID: "github.com/pmezard/go-difflib@v1.0.1-0.20181226105442-5d4384ee4fb2", + Name: "github.com/pmezard/go-difflib", + Version: "1.0.1-0.20181226105442-5d4384ee4fb2", Relationship: ftypes.RelationshipIndirect, + ExternalReferences: []ftypes.ExternalRef{ + { + Type: ftypes.RefVCS, + URL: "https://github.com/pmezard/go-difflib", + }, + }, }, { - ID: "gopkg.in/yaml.v3@v3.0.0-20210107192922-496545a6307b", - Name: "gopkg.in/yaml.v3", - Version: "3.0.0-20210107192922-496545a6307b", + ID: "github.com/stretchr/testify@v1.9.0", + Name: "github.com/stretchr/testify", + Version: "1.9.0", Relationship: ftypes.RelationshipIndirect, ExternalReferences: []ftypes.ExternalRef{ { Type: ftypes.RefVCS, - URL: "https://github.com/go-yaml/yaml", + URL: "https://github.com/stretchr/testify", }, }, }, + { + ID: "golang.org/x/xerrors@v0.0.0-20231012003039-104605ab7028", + Name: "golang.org/x/xerrors", + Version: "0.0.0-20231012003039-104605ab7028", + Relationship: ftypes.RelationshipIndirect, + }, } + GoModNormalWithoutStdlib = slices.DeleteFunc(slices.Clone(GoModNormal), func(f ftypes.Package) bool { + return f.Name == "stdlib" + }) + // execute go mod tidy in replaced folder GoModReplaced = []ftypes.Package{ { diff --git a/pkg/dependency/parser/golang/mod/testdata/normal/go.mod b/pkg/dependency/parser/golang/mod/testdata/normal/go.mod index 9d48b25e0079..564414c10583 100644 --- a/pkg/dependency/parser/golang/mod/testdata/normal/go.mod +++ b/pkg/dependency/parser/golang/mod/testdata/normal/go.mod @@ -1,10 +1,14 @@ module github.com/org/repo -go 1.17 +go 1.22.0 -require github.com/aquasecurity/go-dep-parser v0.0.0-20211224170007-df43bca6b6ff +toolchain go1.22.5 + +require github.com/aquasecurity/go-version v0.0.0-20240603093900-cf8a8d29271d require ( - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect - gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/stretchr/testify v1.9.0 // indirect + golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // indirect ) diff --git a/pkg/dependency/parser/golang/mod/testdata/normal/go.sum b/pkg/dependency/parser/golang/mod/testdata/normal/go.sum index 032bb4727cfe..eefc0690f47d 100644 --- a/pkg/dependency/parser/golang/mod/testdata/normal/go.sum +++ b/pkg/dependency/parser/golang/mod/testdata/normal/go.sum @@ -1,62 +1,12 @@ -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/aquasecurity/go-dep-parser v0.0.0-20211224170007-df43bca6b6ff h1:JCKEV3TgUNh9fn+8hXyIdsF9yErA0rUbCkgt2flRKt4= -github.com/aquasecurity/go-dep-parser v0.0.0-20211224170007-df43bca6b6ff/go.mod h1:8fJ//Ob6/03lxbn4xa1F+G/giVtiVLxnZNpBp5xOxNk= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= -github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= -github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= -github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ= -github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= -github.com/hashicorp/go-retryablehttp v0.7.0/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.16.0/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +github.com/aquasecurity/go-version v0.0.0-20240603093900-cf8a8d29271d h1:4zour5Sh9chOg+IqIinIcJ3qtr3cIf8FdFY6aArlXBw= +github.com/aquasecurity/go-version v0.0.0-20240603093900-cf8a8d29271d/go.mod h1:1cPOp4BaQZ1G2F5fnw4dFz6pkOyXJI9KTuak8ghIl3U= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU= +golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/dependency/parser/golang/mod/testdata/normal/main.go b/pkg/dependency/parser/golang/mod/testdata/normal/main.go index 0b51fb861f32..fe31e68d5da8 100644 --- a/pkg/dependency/parser/golang/mod/testdata/normal/main.go +++ b/pkg/dependency/parser/golang/mod/testdata/normal/main.go @@ -3,11 +3,11 @@ package main import ( "log" - "github.com/aquasecurity/trivy/pkg/dependency/parser/golang/mod" + "github.com/aquasecurity/go-version/pkg/version" ) func main() { - if _, err := mod.Parse(nil); err != nil { + if _, err := version.Parse("v0.1.2"); err != nil { log.Fatal(err) } } diff --git a/pkg/fanal/analyzer/language/golang/mod/mod.go b/pkg/fanal/analyzer/language/golang/mod/mod.go index 96d40ba1c954..398511fdc63c 100644 --- a/pkg/fanal/analyzer/language/golang/mod/mod.go +++ b/pkg/fanal/analyzer/language/golang/mod/mod.go @@ -56,9 +56,9 @@ type gomodAnalyzer struct { func newGoModAnalyzer(opt analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { return &gomodAnalyzer{ - modParser: mod.NewParser(true), // Only the root module should replace + modParser: mod.NewParser(true, opt.DetectionPriority == types.PriorityComprehensive), // Only the root module should replace sumParser: sum.NewParser(), - leafModParser: mod.NewParser(false), + leafModParser: mod.NewParser(false, false), // Don't detect stdlib for non-root go.mod files licenseClassifierConfidenceLevel: opt.LicenseScannerOption.ClassifierConfidenceLevel, logger: log.WithPrefix("golang"), }, nil From 7a1e8b85b4acf912c6748bf23fee71dda002129d Mon Sep 17 00:00:00 2001 From: Aqua Security automated builds <54269356+aqua-bot@users.noreply.github.com> Date: Wed, 4 Sep 2024 02:51:23 +0300 Subject: [PATCH 068/183] release: v0.55.0 [main] (#7271) --- .release-please-manifest.json | 2 +- CHANGELOG.md | 65 +++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 8f1dfd40939e..aeec62f4b8cc 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1 +1 @@ -{".":"0.54.0"} +{".":"0.55.0"} diff --git a/CHANGELOG.md b/CHANGELOG.md index 04a57a25147e..19df5eb64851 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,70 @@ # Changelog +## [0.55.0](https://github.com/aquasecurity/trivy/compare/v0.54.0...v0.55.0) (2024-09-03) + + +### ⚠ BREAKING CHANGES + +* **cli:** delete deprecated SBOM flags ([#7266](https://github.com/aquasecurity/trivy/issues/7266)) + +### Features + +* **cli:** delete deprecated SBOM flags ([#7266](https://github.com/aquasecurity/trivy/issues/7266)) ([7024572](https://github.com/aquasecurity/trivy/commit/70245721372720027b7089bd61c693df48add865)) +* **go:** use `toolchain` as `stdlib` version for `go.mod` files ([#7163](https://github.com/aquasecurity/trivy/issues/7163)) ([2d80769](https://github.com/aquasecurity/trivy/commit/2d80769c34b118851640411fff9dac0b3e353e82)) +* **java:** add `test` scope support for `pom.xml` files ([#7414](https://github.com/aquasecurity/trivy/issues/7414)) ([2d97700](https://github.com/aquasecurity/trivy/commit/2d97700d10665142d2f66d7910202bec82116209)) +* **misconf:** Add support for using spec from on-disk bundle ([#7179](https://github.com/aquasecurity/trivy/issues/7179)) ([be86126](https://github.com/aquasecurity/trivy/commit/be861265cafc89787fda09c59b2ef175e3d04204)) +* **misconf:** ignore duplicate checks ([#7317](https://github.com/aquasecurity/trivy/issues/7317)) ([9ef05fc](https://github.com/aquasecurity/trivy/commit/9ef05fc6b171a264516a025b0b0bcbbc8cff10bc)) +* **misconf:** iterator argument support for dynamic blocks ([#7236](https://github.com/aquasecurity/trivy/issues/7236)) ([fe92072](https://github.com/aquasecurity/trivy/commit/fe9207255a4f7f984ec1447f8a9219ae60e560c4)) +* **misconf:** port and protocol support for EC2 networks ([#7146](https://github.com/aquasecurity/trivy/issues/7146)) ([98e136e](https://github.com/aquasecurity/trivy/commit/98e136eb7baa2b66f4233d96875c1490144e1594)) +* **misconf:** scanning support for YAML and JSON ([#7311](https://github.com/aquasecurity/trivy/issues/7311)) ([efdbd8f](https://github.com/aquasecurity/trivy/commit/efdbd8f19ab0ab0c3b48293d43e51c81b7b03b89)) +* **misconf:** support for ignore by nested attributes ([#7205](https://github.com/aquasecurity/trivy/issues/7205)) ([44e4686](https://github.com/aquasecurity/trivy/commit/44e468603d44b077cc4606327fb3e7d7ca435e05)) +* **misconf:** support for policy and bucket grants ([#7284](https://github.com/aquasecurity/trivy/issues/7284)) ([a817fae](https://github.com/aquasecurity/trivy/commit/a817fae85b7272b391b737ec86673a7cab722bae)) +* **misconf:** variable support for Terraform Plan ([#7228](https://github.com/aquasecurity/trivy/issues/7228)) ([db2c955](https://github.com/aquasecurity/trivy/commit/db2c95598da098ca610825089eb4ab63b789b215)) +* **python:** use minimum version for pip packages ([#7348](https://github.com/aquasecurity/trivy/issues/7348)) ([e9b43f8](https://github.com/aquasecurity/trivy/commit/e9b43f81e67789b067352fcb6aa55bc9478bc518)) +* **report:** export modified findings in JSON ([#7383](https://github.com/aquasecurity/trivy/issues/7383)) ([7aea79d](https://github.com/aquasecurity/trivy/commit/7aea79dd93cfb61453766dbbb2e3fc0fbd317852)) +* **sbom:** set User-Agent header on requests to Rekor ([#7396](https://github.com/aquasecurity/trivy/issues/7396)) ([af1d257](https://github.com/aquasecurity/trivy/commit/af1d257730422d238871beb674767f8f83c5d06a)) +* **server:** add internal `--path-prefix` flag for client/server mode ([#7321](https://github.com/aquasecurity/trivy/issues/7321)) ([24a4563](https://github.com/aquasecurity/trivy/commit/24a45636867b893ff54c5ce07197f3b5c6db1d9b)) +* **server:** Make Trivy Server Multiplexer Exported ([#7389](https://github.com/aquasecurity/trivy/issues/7389)) ([4c6e8ca](https://github.com/aquasecurity/trivy/commit/4c6e8ca9cc9591799907cc73075f2d740e303b8f)) +* **vm:** Support direct filesystem ([#7058](https://github.com/aquasecurity/trivy/issues/7058)) ([45b3f34](https://github.com/aquasecurity/trivy/commit/45b3f344042bcd90ca63ab696b69bff0e9ab4e36)) +* **vm:** support the Ext2/Ext3 filesystems ([#6983](https://github.com/aquasecurity/trivy/issues/6983)) ([35c60f0](https://github.com/aquasecurity/trivy/commit/35c60f030fa48de8d8e57958e5ba379814126831)) +* **vuln:** Add `--detection-priority` flag for accuracy tuning ([#7288](https://github.com/aquasecurity/trivy/issues/7288)) ([fd8348d](https://github.com/aquasecurity/trivy/commit/fd8348d610f20c6c33da81cd7b0e7d5504ce26be)) + + +### Bug Fixes + +* **aws:** handle ECR repositories in different regions ([#6217](https://github.com/aquasecurity/trivy/issues/6217)) ([feaef96](https://github.com/aquasecurity/trivy/commit/feaef9699df5d8ca399770e701a59d7c0ff979a3)) +* **flag:** incorrect behavior for deprected flag `--clear-cache` ([#7281](https://github.com/aquasecurity/trivy/issues/7281)) ([2a0e529](https://github.com/aquasecurity/trivy/commit/2a0e529c36057b572119815af59c28e4790034ca)) +* **helm:** explicitly define `kind` and `apiVersion` of `volumeClaimTemplate` element ([#7362](https://github.com/aquasecurity/trivy/issues/7362)) ([da4ebfa](https://github.com/aquasecurity/trivy/commit/da4ebfa1a741f3f8b0b43289b4028afe763f7d43)) +* **java:** Return error when trying to find a remote pom to avoid segfault ([#7275](https://github.com/aquasecurity/trivy/issues/7275)) ([49d5270](https://github.com/aquasecurity/trivy/commit/49d5270163e305f88fedcf50412973736e69dc69)) +* **license:** add license handling to JUnit template ([#7409](https://github.com/aquasecurity/trivy/issues/7409)) ([f80183c](https://github.com/aquasecurity/trivy/commit/f80183c1139b21bb95bc64e216358f4a76001a65)) +* logger initialization before flags parsing ([#7372](https://github.com/aquasecurity/trivy/issues/7372)) ([c929290](https://github.com/aquasecurity/trivy/commit/c929290c3c0e4e91337264d69e75ccb60522bc65)) +* **misconf:** change default TLS values for the Azure storage account ([#7345](https://github.com/aquasecurity/trivy/issues/7345)) ([aadb090](https://github.com/aquasecurity/trivy/commit/aadb09078843250c66087f46db9a2aa48094a118)) +* **misconf:** do not filter Terraform plan JSON by name ([#7406](https://github.com/aquasecurity/trivy/issues/7406)) ([9d7264a](https://github.com/aquasecurity/trivy/commit/9d7264af8e85bcc0dba600b8366d0470d455251c)) +* **misconf:** do not recreate filesystem map ([#7416](https://github.com/aquasecurity/trivy/issues/7416)) ([3a5d091](https://github.com/aquasecurity/trivy/commit/3a5d091759564496992a83fb2015a21c84a22213)) +* **misconf:** do not register Rego libs in checks registry ([#7420](https://github.com/aquasecurity/trivy/issues/7420)) ([a5aa63e](https://github.com/aquasecurity/trivy/commit/a5aa63eff7e229744090f9ad300c1bec3259397e)) +* **misconf:** do not set default value for default_cache_behavior ([#7234](https://github.com/aquasecurity/trivy/issues/7234)) ([f0ed5e4](https://github.com/aquasecurity/trivy/commit/f0ed5e4ced7e60af35c88d5d084aa4b7237f4973)) +* **misconf:** fix infer type for null value ([#7424](https://github.com/aquasecurity/trivy/issues/7424)) ([0cac3ac](https://github.com/aquasecurity/trivy/commit/0cac3ac7075017628a21a7990941df04cbc16dbe)) +* **misconf:** init frameworks before updating them ([#7376](https://github.com/aquasecurity/trivy/issues/7376)) ([b65b32d](https://github.com/aquasecurity/trivy/commit/b65b32ddfa6fc62ac81ad9fa580e1f5a327864f5)) +* **misconf:** load only submodule if it is specified in source ([#7112](https://github.com/aquasecurity/trivy/issues/7112)) ([a4180bd](https://github.com/aquasecurity/trivy/commit/a4180bddd43d86e479edf0afe0c362021d071482)) +* **misconf:** support deprecating for Go checks ([#7377](https://github.com/aquasecurity/trivy/issues/7377)) ([2a6c7ab](https://github.com/aquasecurity/trivy/commit/2a6c7ab3b338ce4a8f99d6ac3508c2531dcbe812)) +* **misconf:** use module to log when metadata retrieval fails ([#7405](https://github.com/aquasecurity/trivy/issues/7405)) ([0799770](https://github.com/aquasecurity/trivy/commit/0799770b8827a8276ad0d6d9ac7e0381c286757c)) +* **misconf:** wrap Azure PortRange in iac types ([#7357](https://github.com/aquasecurity/trivy/issues/7357)) ([c5c62d5](https://github.com/aquasecurity/trivy/commit/c5c62d5ff05420321f9cdbfb93e2591e0866a342)) +* **nodejs:** check all `importers` to detect dev deps from pnpm-lock.yaml file ([#7387](https://github.com/aquasecurity/trivy/issues/7387)) ([fd9ed3a](https://github.com/aquasecurity/trivy/commit/fd9ed3a330bc66e229bcbdc262dc296a3bf01f54)) +* **plugin:** do not call GitHub content API for releases and tags ([#7274](https://github.com/aquasecurity/trivy/issues/7274)) ([b3ee6da](https://github.com/aquasecurity/trivy/commit/b3ee6dac269bd7847674f3ce985a5ff7f8f0ba38)) +* **report:** escape `Message` field in `asff.tpl` template ([#7401](https://github.com/aquasecurity/trivy/issues/7401)) ([dd9733e](https://github.com/aquasecurity/trivy/commit/dd9733e950d3127aa2ac90c45ec7e2b88a2b47ca)) +* safely check if the directory exists ([#7353](https://github.com/aquasecurity/trivy/issues/7353)) ([05a8297](https://github.com/aquasecurity/trivy/commit/05a829715f99cd90b122c64cd2f40157854e467b)) +* **sbom:** use `NOASSERTION` for licenses fields in SPDX formats ([#7403](https://github.com/aquasecurity/trivy/issues/7403)) ([c96dcdd](https://github.com/aquasecurity/trivy/commit/c96dcdd440a14cdd1b01ac473b2c15e4698e387b)) +* **secret:** use `.eyJ` keyword for JWT secret ([#7410](https://github.com/aquasecurity/trivy/issues/7410)) ([bf64003](https://github.com/aquasecurity/trivy/commit/bf64003ac8b209f34b88f228918a96d4f9dac5e0)) +* **secret:** use only line with secret for long secret lines ([#7412](https://github.com/aquasecurity/trivy/issues/7412)) ([391448a](https://github.com/aquasecurity/trivy/commit/391448aba9fcb0a4138225e5ab305e4e6707c603)) +* **terraform:** add aws_region name to presets ([#7184](https://github.com/aquasecurity/trivy/issues/7184)) ([bb2e26a](https://github.com/aquasecurity/trivy/commit/bb2e26a0ab707b718f6a890cbc87e2492298b6e5)) + + +### Performance Improvements + +* **misconf:** do not convert contents of a YAML file to string ([#7292](https://github.com/aquasecurity/trivy/issues/7292)) ([85dadf5](https://github.com/aquasecurity/trivy/commit/85dadf56265647c000191561db10b08a4948c140)) +* **misconf:** optimize work with context ([#6968](https://github.com/aquasecurity/trivy/issues/6968)) ([2b6d8d9](https://github.com/aquasecurity/trivy/commit/2b6d8d9227fb6ecc9386a14333964c23c0370a52)) +* **misconf:** use json.Valid to check validity of JSON ([#7308](https://github.com/aquasecurity/trivy/issues/7308)) ([c766831](https://github.com/aquasecurity/trivy/commit/c766831069e188226efafeec184e41498685ed85)) + ## [0.54.0](https://github.com/aquasecurity/trivy/compare/v0.53.0...v0.54.0) (2024-07-30) From 4926da79de901fba73819d71845ec0355b68ae0f Mon Sep 17 00:00:00 2001 From: afdesk Date: Thu, 5 Sep 2024 16:20:29 +0600 Subject: [PATCH 069/183] fix(license): stop spliting a long license text (#7336) Signed-off-by: knqyf263 Co-authored-by: knqyf263 --- .../parser/python/packaging/parse.go | 2 +- .../language/python/packaging/packaging.go | 4 +- pkg/licensing/normalize.go | 45 +++++++ pkg/licensing/normalize_test.go | 7 ++ pkg/rpc/convert.go | 2 + pkg/rpc/convert_test.go | 4 + pkg/scanner/local/scan.go | 48 +++++--- pkg/scanner/local/scan_test.go | 38 ++++++ pkg/types/license.go | 3 + rpc/common/service.pb.go | 110 ++++++++++-------- rpc/common/service.proto | 1 + 11 files changed, 192 insertions(+), 72 deletions(-) diff --git a/pkg/dependency/parser/python/packaging/parse.go b/pkg/dependency/parser/python/packaging/parse.go index fa1758308860..58ecac200db5 100644 --- a/pkg/dependency/parser/python/packaging/parse.go +++ b/pkg/dependency/parser/python/packaging/parse.go @@ -80,7 +80,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc } if license == "" && h.Get("License-File") != "" { - license = "file://" + h.Get("License-File") + license = licensing.LicenseFilePrefix + h.Get("License-File") } return []ftypes.Package{ diff --git a/pkg/fanal/analyzer/language/python/packaging/packaging.go b/pkg/fanal/analyzer/language/python/packaging/packaging.go index 51fd585d8a6c..73e5f446bc40 100644 --- a/pkg/fanal/analyzer/language/python/packaging/packaging.go +++ b/pkg/fanal/analyzer/language/python/packaging/packaging.go @@ -122,11 +122,11 @@ func (a packagingAnalyzer) fillAdditionalData(fsys fs.FS, app *types.Application // Parser adds `file://` prefix to filepath from `License-File` field // We need to read this file to find licenses // Otherwise, this is the name of the license - if !strings.HasPrefix(lic, "file://") { + if !strings.HasPrefix(lic, licensing.LicenseFilePrefix) { licenses = append(licenses, lic) continue } - licenseFilePath := path.Base(strings.TrimPrefix(lic, "file://")) + licenseFilePath := path.Base(strings.TrimPrefix(lic, licensing.LicenseFilePrefix)) findings, err := classifyLicense(app.FilePath, licenseFilePath, a.licenseClassifierConfidenceLevel, fsys) if err != nil { diff --git a/pkg/licensing/normalize.go b/pkg/licensing/normalize.go index 07105e329357..4ca8eab00030 100644 --- a/pkg/licensing/normalize.go +++ b/pkg/licensing/normalize.go @@ -159,6 +159,12 @@ var mapping = map[string]string{ "PUBLIC DOMAIN": Unlicense, } +const ( + LicenseTextPrefix = "text://" + LicenseFilePrefix = "file://" + CustomLicensePrefix = "CUSTOM License" +) + // pythonLicenseExceptions contains licenses that we cannot separate correctly using our logic. // first word after separator (or/and) => license name var pythonLicenseExceptions = map[string]string{ @@ -179,6 +185,39 @@ var pythonLicenseExceptions = map[string]string{ var licenseSplitRegexp = regexp.MustCompile("(,?[_ ]+(?:or|and)[_ ]+)|(,[ ]*)") +// Typical keywords for license texts +var licenseTextKeywords = []string{ + "http://", + "https://", + "(c)", + "as-is", + ";", + "hereby", + "permission to use", + "permission is", + "use in source", + "use, copy, modify", + "using", +} + +func isLicenseText(str string) bool { + for _, keyword := range licenseTextKeywords { + if strings.Contains(str, keyword) { + return true + } + } + return false +} + +func TrimLicenseText(text string) string { + s := strings.Split(text, " ") + n := len(s) + if n > 3 { + n = 3 + } + return strings.Join(s[:n], " ") + "..." +} + func Normalize(name string) string { name = strings.TrimSpace(name) if l, ok := mapping[strings.ToUpper(name)]; ok { @@ -191,6 +230,12 @@ func SplitLicenses(str string) []string { if str == "" { return nil } + if isLicenseText(strings.ToLower(str)) { + return []string{ + LicenseTextPrefix + str, + } + } + var licenses []string for _, maybeLic := range licenseSplitRegexp.Split(str, -1) { lower := strings.ToLower(maybeLic) diff --git a/pkg/licensing/normalize_test.go b/pkg/licensing/normalize_test.go index 28934f4f2340..16fa9eac6250 100644 --- a/pkg/licensing/normalize_test.go +++ b/pkg/licensing/normalize_test.go @@ -97,6 +97,13 @@ func TestSplitLicenses(t *testing.T) { "Historical Permission Notice and Disclaimer (HPND)", }, }, + { + name: "License text", + license: "* Permission to use this software in any way is granted without", + licenses: []string{ + "text://* Permission to use this software in any way is granted without", + }, + }, } for _, tt := range tests { diff --git a/pkg/rpc/convert.go b/pkg/rpc/convert.go index dcd81ce85ded..1662877bd597 100644 --- a/pkg/rpc/convert.go +++ b/pkg/rpc/convert.go @@ -436,6 +436,7 @@ func ConvertFromRPCDetectedLicenses(rpcLicenses []*common.DetectedLicense) []typ PkgName: l.PkgName, FilePath: l.FilePath, Name: l.Name, + Text: l.Text, Confidence: float64(l.Confidence), Link: l.Link, }) @@ -983,6 +984,7 @@ func ConvertToRPCLicenses(licenses []types.DetectedLicense) []*common.DetectedLi PkgName: l.PkgName, FilePath: l.FilePath, Name: l.Name, + Text: l.Text, Confidence: float32(l.Confidence), Link: l.Link, }) diff --git a/pkg/rpc/convert_test.go b/pkg/rpc/convert_test.go index f7c7b3d36d86..6f90c3b5cc8e 100644 --- a/pkg/rpc/convert_test.go +++ b/pkg/rpc/convert_test.go @@ -760,6 +760,7 @@ func TestConvertFromRPCLicenses(t *testing.T) { PkgName: "alpine-baselayout", FilePath: "some-path", Name: "GPL-2.0", + Text: "text://* Permission to use this software in any way is granted without", Confidence: 1, Link: "https://some-link", }, @@ -771,6 +772,7 @@ func TestConvertFromRPCLicenses(t *testing.T) { PkgName: "alpine-baselayout", FilePath: "some-path", Name: "GPL-2.0", + Text: "text://* Permission to use this software in any way is granted without", Confidence: 1, Link: "https://some-link", }, @@ -806,6 +808,7 @@ func TestConvertToRPCLicenses(t *testing.T) { PkgName: "alpine-baselayout", FilePath: "some-path", Name: "GPL-2.0", + Text: "text://* Permission to use this software in any way is granted without", Confidence: 1, Link: "https://some-link", }, @@ -817,6 +820,7 @@ func TestConvertToRPCLicenses(t *testing.T) { PkgName: "alpine-baselayout", FilePath: "some-path", Name: "GPL-2.0", + Text: "text://* Permission to use this software in any way is granted without", Confidence: 1, Link: "https://some-link", }, diff --git a/pkg/scanner/local/scan.go b/pkg/scanner/local/scan.go index 3b0c719721e2..f34723058e06 100644 --- a/pkg/scanner/local/scan.go +++ b/pkg/scanner/local/scan.go @@ -261,14 +261,7 @@ func (s Scanner) scanLicenses(target types.ScanTarget, options types.ScanOptions var osPkgLicenses []types.DetectedLicense for _, pkg := range target.Packages { for _, license := range pkg.Licenses { - category, severity := scanner.Scan(license) - osPkgLicenses = append(osPkgLicenses, types.DetectedLicense{ - Severity: severity, - Category: category, - PkgName: pkg.Name, - Name: license, - Confidence: 1.0, - }) + osPkgLicenses = append(osPkgLicenses, toDetectedLicense(scanner, license, pkg.Name, "")) } } results = append(results, types.Result{ @@ -282,17 +275,11 @@ func (s Scanner) scanLicenses(target types.ScanTarget, options types.ScanOptions var langLicenses []types.DetectedLicense for _, lib := range app.Packages { for _, license := range lib.Licenses { - category, severity := scanner.Scan(license) - langLicenses = append(langLicenses, types.DetectedLicense{ - Severity: severity, - Category: category, - PkgName: lib.Name, - Name: license, - // Lock files use app.FilePath - https://github.com/aquasecurity/trivy/blob/6ccc0a554b07b05fd049f882a1825a0e1e0aabe1/pkg/fanal/types/artifact.go#L245-L246 - // Applications use lib.FilePath - https://github.com/aquasecurity/trivy/blob/6ccc0a554b07b05fd049f882a1825a0e1e0aabe1/pkg/fanal/types/artifact.go#L93-L94 - FilePath: lo.Ternary(lib.FilePath != "", lib.FilePath, app.FilePath), - Confidence: 1.0, - }) + // Lock files use app.FilePath - https://github.com/aquasecurity/trivy/blob/6ccc0a554b07b05fd049f882a1825a0e1e0aabe1/pkg/fanal/types/artifact.go#L245-L246 + // Applications use lib.FilePath - https://github.com/aquasecurity/trivy/blob/6ccc0a554b07b05fd049f882a1825a0e1e0aabe1/pkg/fanal/types/artifact.go#L93-L94 + filePath := lo.Ternary(lib.FilePath != "", lib.FilePath, app.FilePath) + + langLicenses = append(langLicenses, toDetectedLicense(scanner, license, lib.Name, filePath)) } } @@ -390,6 +377,29 @@ func toDetectedMisconfiguration(res ftypes.MisconfResult, defaultSeverity dbType } } +func toDetectedLicense(scanner licensing.Scanner, license, pkgName, filePath string) types.DetectedLicense { + var category ftypes.LicenseCategory + var severity, licenseText string + if strings.HasPrefix(license, licensing.LicenseTextPrefix) { // License text + licenseText = strings.TrimPrefix(license, licensing.LicenseTextPrefix) + category = ftypes.CategoryUnknown + severity = dbTypes.SeverityUnknown.String() + license = licensing.CustomLicensePrefix + ": " + licensing.TrimLicenseText(licenseText) + } else { // License name + category, severity = scanner.Scan(license) + } + + return types.DetectedLicense{ + Severity: severity, + Category: category, + PkgName: pkgName, + FilePath: filePath, + Name: license, + Text: licenseText, + Confidence: 1.0, + } +} + func ShouldScanMisconfigOrRbac(scanners types.Scanners) bool { return scanners.AnyEnabled(types.MisconfigScanner, types.RBACScanner) } diff --git a/pkg/scanner/local/scan_test.go b/pkg/scanner/local/scan_test.go index 7d60697fa23a..f3e6cac5d3fa 100644 --- a/pkg/scanner/local/scan_test.go +++ b/pkg/scanner/local/scan_test.go @@ -64,6 +64,25 @@ var ( }, Licenses: []string{"MIT"}, } + python39min = ftypes.Package{ + Name: "python3.9-minimal", + Version: "3.9.1", + FilePath: "/usr/lib/python/site-packages/python3.9-minimal/METADATA", + Layer: ftypes.Layer{ + DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33", + }, + Licenses: []string{"text://Redistribution and use in source and binary forms, with or without"}, + } + menuinstPkg = ftypes.Package{ + Name: "menuinst", + Version: "2.0.2", + FilePath: "opt/conda/lib/python3.11/site-packages/menuinst-2.0.2.dist-info/METADATA", + Layer: ftypes.Layer{ + DiffID: "sha256:0ea33a93585cf1917ba522b2304634c3073654062d5282c1346322967790ef33", + }, + Licenses: []string{"text://(c) 2016 Continuum Analytics, Inc. / http://continuum.io All Rights Reserved"}, + } + laravelPkg = ftypes.Package{ Name: "laravel/framework", Version: "6.0.0", @@ -225,6 +244,7 @@ func TestScanner_Scan(t *testing.T) { }, Packages: []ftypes.Package{ muslPkg, + python39min, }, Applications: []ftypes.Application{ { @@ -239,6 +259,7 @@ func TestScanner_Scan(t *testing.T) { FilePath: "", Packages: []ftypes.Package{ urllib3Pkg, + menuinstPkg, }, }, }, @@ -257,6 +278,14 @@ func TestScanner_Scan(t *testing.T) { Name: "MIT", Confidence: 1, }, + { + Severity: "UNKNOWN", + Category: "unknown", + PkgName: python39min.Name, + Name: "CUSTOM License: Redistribution and use...", + Text: "Redistribution and use in source and binary forms, with or without", + Confidence: 1, + }, }, }, { @@ -286,6 +315,15 @@ func TestScanner_Scan(t *testing.T) { Name: "MIT", Confidence: 1, }, + { + Severity: "UNKNOWN", + Category: "unknown", + PkgName: menuinstPkg.Name, + FilePath: "opt/conda/lib/python3.11/site-packages/menuinst-2.0.2.dist-info/METADATA", + Name: "CUSTOM License: (c) 2016 Continuum...", + Text: "(c) 2016 Continuum Analytics, Inc. / http://continuum.io All Rights Reserved", + Confidence: 1, + }, }, }, { diff --git a/pkg/types/license.go b/pkg/types/license.go index baca0328a457..22dd6bcb2040 100644 --- a/pkg/types/license.go +++ b/pkg/types/license.go @@ -22,6 +22,9 @@ type DetectedLicense struct { // Name holds a detected license name Name string + // Text holds a long license text if Trivy detects a license name as a license text + Text string + // Confidence is level of the match. The confidence level is between 0.0 and 1.0, with 1.0 indicating an // exact match and 0.0 indicating a complete mismatch Confidence float64 diff --git a/rpc/common/service.pb.go b/rpc/common/service.pb.go index c8d829762956..4c7f0af79464 100644 --- a/rpc/common/service.pb.go +++ b/rpc/common/service.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.34.0 -// protoc v5.26.1 +// protoc v3.19.4 // source: rpc/common/service.proto package common @@ -2084,6 +2084,7 @@ type DetectedLicense struct { Name string `protobuf:"bytes,5,opt,name=name,proto3" json:"name,omitempty"` Confidence float32 `protobuf:"fixed32,6,opt,name=confidence,proto3" json:"confidence,omitempty"` Link string `protobuf:"bytes,7,opt,name=link,proto3" json:"link,omitempty"` + Text string `protobuf:"bytes,8,opt,name=text,proto3" json:"text,omitempty"` } func (x *DetectedLicense) Reset() { @@ -2167,6 +2168,13 @@ func (x *DetectedLicense) GetLink() string { return "" } +func (x *DetectedLicense) GetText() string { + if x != nil { + return x.Text + } + return "" +} + type LicenseFile struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2718,7 +2726,7 @@ var file_rpc_common_service_proto_rawDesc = []byte{ 0x64, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x08, 0x66, 0x69, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x73, 0x22, 0x85, 0x02, 0x0a, 0x0f, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4c, + 0x67, 0x73, 0x22, 0x99, 0x02, 0x0a, 0x0f, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, @@ -2734,54 +2742,56 @@ var file_rpc_common_service_proto_rawDesc = []byte{ 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0xed, 0x01, 0x0a, 0x0b, 0x4c, - 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x6c, 0x69, - 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x1e, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x2e, 0x45, 0x6e, 0x75, 0x6d, - 0x52, 0x0b, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, - 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6b, - 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, - 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x69, 0x6e, 0x67, 0x69, 0x6e, 0x67, - 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x46, 0x69, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x08, 0x66, 0x69, 0x6e, 0x67, 0x69, 0x6e, 0x67, 0x73, 0x12, - 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, - 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, - 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x22, 0x98, 0x01, 0x0a, 0x0e, 0x4c, - 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x3e, 0x0a, - 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x22, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, - 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x2e, 0x45, - 0x6e, 0x75, 0x6d, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0x95, 0x01, 0x0a, 0x0f, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, - 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, 0x81, 0x01, 0x0a, 0x04, 0x45, 0x6e, - 0x75, 0x6d, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, - 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x42, 0x49, 0x44, 0x44, 0x45, 0x4e, - 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x53, 0x54, 0x52, 0x49, 0x43, 0x54, 0x45, 0x44, - 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x43, 0x49, 0x50, 0x52, 0x4f, 0x43, 0x41, 0x4c, - 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x54, 0x49, 0x43, 0x45, 0x10, 0x04, 0x12, 0x0e, - 0x0a, 0x0a, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x56, 0x45, 0x10, 0x05, 0x12, 0x10, - 0x0a, 0x0c, 0x55, 0x4e, 0x45, 0x4e, 0x43, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x45, 0x44, 0x10, 0x06, - 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x07, 0x22, 0x4e, 0x0a, - 0x0b, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3f, 0x0a, 0x04, - 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, - 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x50, 0x4b, 0x47, 0x10, 0x01, 0x12, - 0x0a, 0x0a, 0x06, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x4c, - 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x03, 0x2a, 0x44, 0x0a, - 0x08, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, - 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4c, 0x4f, 0x57, 0x10, 0x01, 0x12, - 0x0a, 0x0a, 0x06, 0x4d, 0x45, 0x44, 0x49, 0x55, 0x4d, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x48, - 0x49, 0x47, 0x48, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x52, 0x49, 0x54, 0x49, 0x43, 0x41, - 0x4c, 0x10, 0x04, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, - 0x6d, 0x2f, 0x61, 0x71, 0x75, 0x61, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, - 0x72, 0x69, 0x76, 0x79, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x3b, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, + 0x78, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x22, 0xed, + 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x41, + 0x0a, 0x0c, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x2e, + 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x0b, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, + 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x69, 0x6e, + 0x67, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x72, + 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, + 0x73, 0x65, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x08, 0x66, 0x69, 0x6e, 0x67, 0x69, + 0x6e, 0x67, 0x73, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x22, 0x98, + 0x01, 0x0a, 0x0e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x12, 0x3e, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, + 0x72, 0x79, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, + 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, + 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0x95, 0x01, 0x0a, 0x0f, 0x4c, 0x69, + 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, 0x81, 0x01, + 0x0a, 0x04, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x42, 0x49, + 0x44, 0x44, 0x45, 0x4e, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x53, 0x54, 0x52, 0x49, + 0x43, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x43, 0x49, 0x50, 0x52, + 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x54, 0x49, 0x43, 0x45, + 0x10, 0x04, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x56, 0x45, + 0x10, 0x05, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x45, 0x4e, 0x43, 0x55, 0x4d, 0x42, 0x45, 0x52, + 0x45, 0x44, 0x10, 0x06, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, + 0x07, 0x22, 0x4e, 0x0a, 0x0b, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, + 0x22, 0x3f, 0x0a, 0x04, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x50, 0x4b, + 0x47, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x10, 0x02, 0x12, + 0x10, 0x0a, 0x0c, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, + 0x03, 0x2a, 0x44, 0x0a, 0x08, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x0b, 0x0a, + 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4c, 0x4f, + 0x57, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x45, 0x44, 0x49, 0x55, 0x4d, 0x10, 0x02, 0x12, + 0x08, 0x0a, 0x04, 0x48, 0x49, 0x47, 0x48, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x52, 0x49, + 0x54, 0x49, 0x43, 0x41, 0x4c, 0x10, 0x04, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x71, 0x75, 0x61, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, + 0x74, 0x79, 0x2f, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( diff --git a/rpc/common/service.proto b/rpc/common/service.proto index 91ed89dd534f..d80bf57e3b86 100644 --- a/rpc/common/service.proto +++ b/rpc/common/service.proto @@ -226,6 +226,7 @@ message DetectedLicense { string name = 5; float confidence = 6; string link = 7; + string text = 8; } message LicenseFile { From 412fb764f0464c206fc2e546f208c8a245c782f3 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Fri, 6 Sep 2024 12:55:51 +0600 Subject: [PATCH 070/183] refactor(java): add error/statusCode for logs when we can't get pom.xml/maven-metadata.xml from remote repo (#7451) --- pkg/dependency/parser/java/pom/parse.go | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/pkg/dependency/parser/java/pom/parse.go b/pkg/dependency/parser/java/pom/parse.go index 57f41a1d32f4..46c859538529 100644 --- a/pkg/dependency/parser/java/pom/parse.go +++ b/pkg/dependency/parser/java/pom/parse.go @@ -714,8 +714,11 @@ func (p *Parser) fetchPomFileNameFromMavenMetadata(repo string, paths []string) client := &http.Client{} resp, err := client.Do(req) - if err != nil || resp.StatusCode != http.StatusOK { - p.logger.Debug("Failed to fetch", log.String("url", req.URL.String())) + if err != nil { + p.logger.Debug("Failed to fetch", log.String("url", req.URL.String()), log.Err(err)) + return "", nil + } else if resp.StatusCode != http.StatusOK { + p.logger.Debug("Failed to fetch", log.String("url", req.URL.String()), log.Int("statusCode", resp.StatusCode)) return "", nil } defer resp.Body.Close() @@ -745,8 +748,11 @@ func (p *Parser) fetchPOMFromRemoteRepository(repo string, paths []string) (*pom client := &http.Client{} resp, err := client.Do(req) - if err != nil || resp.StatusCode != http.StatusOK { - p.logger.Debug("Failed to fetch", log.String("url", req.URL.String())) + if err != nil { + p.logger.Debug("Failed to fetch", log.String("url", req.URL.String()), log.Err(err)) + return nil, nil + } else if resp.StatusCode != http.StatusOK { + p.logger.Debug("Failed to fetch", log.String("url", req.URL.String()), log.Int("statusCode", resp.StatusCode)) return nil, nil } defer resp.Body.Close() From e2118e8dfa977f22de336df230628139bff79757 Mon Sep 17 00:00:00 2001 From: afdesk Date: Fri, 6 Sep 2024 13:19:33 +0600 Subject: [PATCH 071/183] chore(helm): bump up Trivy Helm chart (#7441) --- helm/trivy/Chart.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/helm/trivy/Chart.yaml b/helm/trivy/Chart.yaml index 3fc94a4b4968..3695c704a2e8 100644 --- a/helm/trivy/Chart.yaml +++ b/helm/trivy/Chart.yaml @@ -1,7 +1,7 @@ apiVersion: v2 name: trivy -version: 0.7.0 -appVersion: 0.37.2 +version: 0.8.0 +appVersion: 0.55.0 description: Trivy helm chart keywords: - scanner From 5375cd27ad1d455504aba69a33a6c9d2989027bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 6 Sep 2024 07:44:35 +0000 Subject: [PATCH 072/183] chore(deps): bump the common group across 1 directory with 19 updates (#7436) Signed-off-by: dependabot[bot] Signed-off-by: knqyf263 Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: knqyf263 --- go.mod | 66 ++++++++++++------------ go.sum | 155 +++++++++++++++++++++++++++------------------------------ 2 files changed, 108 insertions(+), 113 deletions(-) diff --git a/go.mod b/go.mod index 62c3dd5a6f18..e2191c3c2800 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/BurntSushi/toml v1.4.0 github.com/CycloneDX/cyclonedx-go v0.9.0 github.com/GoogleCloudPlatform/docker-credential-gcr v2.0.5+incompatible - github.com/Masterminds/sprig/v3 v3.2.3 + github.com/Masterminds/sprig/v3 v3.3.0 github.com/NYTimes/gziphandler v1.1.1 github.com/alecthomas/chroma v0.10.0 github.com/alicebob/miniredis/v2 v2.33.0 @@ -30,12 +30,12 @@ require ( github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20240707095038-0300bc49b68b github.com/aws/aws-sdk-go-v2 v1.30.4 - github.com/aws/aws-sdk-go-v2/config v1.27.28 - github.com/aws/aws-sdk-go-v2/credentials v1.17.28 - github.com/aws/aws-sdk-go-v2/service/ec2 v1.175.1 - github.com/aws/aws-sdk-go-v2/service/ecr v1.32.1 - github.com/aws/aws-sdk-go-v2/service/s3 v1.59.0 - github.com/aws/aws-sdk-go-v2/service/sts v1.30.4 // indirect + github.com/aws/aws-sdk-go-v2/config v1.27.31 + github.com/aws/aws-sdk-go-v2/credentials v1.17.30 + github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.0 + github.com/aws/aws-sdk-go-v2/service/ecr v1.32.2 + github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0 + github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 // indirect github.com/aws/smithy-go v1.20.4 github.com/bitnami/go-version v0.0.0-20231130084017-bb00604d650c github.com/bmatcuk/doublestar/v4 v4.6.1 @@ -43,7 +43,7 @@ require ( github.com/cheggaaa/pb/v3 v3.1.5 github.com/containerd/containerd v1.7.21 github.com/csaf-poc/csaf_distribution/v3 v3.0.0 - github.com/docker/docker v27.1.1+incompatible + github.com/docker/docker v27.2.0+incompatible github.com/docker/go-connections v0.5.0 github.com/fatih/color v1.17.0 github.com/go-git/go-git/v5 v5.12.0 @@ -56,14 +56,14 @@ require ( github.com/google/licenseclassifier/v2 v2.0.0 github.com/google/uuid v1.6.0 github.com/google/wire v0.6.0 - github.com/hashicorp/go-getter v1.7.5 + github.com/hashicorp/go-getter v1.7.6 github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-retryablehttp v0.7.7 github.com/hashicorp/go-uuid v1.0.3 github.com/hashicorp/go-version v1.7.0 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/hashicorp/hc-install v0.8.0 - github.com/hashicorp/hcl/v2 v2.21.0 + github.com/hashicorp/hcl/v2 v2.22.0 github.com/hashicorp/terraform-exec v0.21.0 github.com/in-toto/in-toto-golang v0.9.0 github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f @@ -87,17 +87,17 @@ require ( github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/mitchellh/mapstructure v1.5.0 - github.com/moby/buildkit v0.15.1 + github.com/moby/buildkit v0.15.2 github.com/open-policy-agent/opa v0.67.1 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 github.com/openvex/discovery v0.1.0 github.com/openvex/go-vex v0.2.5 github.com/owenrumney/go-sarif/v2 v2.3.3 - github.com/owenrumney/squealer v1.2.3 + github.com/owenrumney/squealer v1.2.4 github.com/package-url/packageurl-go v0.1.3 github.com/quasilyte/go-ruleguard/dsl v0.3.22 - github.com/samber/lo v1.46.0 + github.com/samber/lo v1.47.0 github.com/secure-systems-lab/go-securesystemslib v0.8.0 github.com/sigstore/rekor v1.3.6 github.com/sirupsen/logrus v1.9.3 @@ -108,15 +108,15 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 - github.com/testcontainers/testcontainers-go v0.32.0 - github.com/testcontainers/testcontainers-go/modules/localstack v0.32.0 - github.com/tetratelabs/wazero v1.7.3 + github.com/testcontainers/testcontainers-go v0.33.0 + github.com/testcontainers/testcontainers-go/modules/localstack v0.33.0 + github.com/tetratelabs/wazero v1.8.0 github.com/twitchtv/twirp v8.1.3+incompatible github.com/xeipuuv/gojsonschema v1.2.0 github.com/xlab/treeprint v1.2.0 github.com/zclconf/go-cty v1.15.0 github.com/zclconf/go-cty-yaml v1.0.3 - go.etcd.io/bbolt v1.3.10 + go.etcd.io/bbolt v1.3.11 golang.org/x/crypto v0.26.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect golang.org/x/mod v0.20.0 @@ -128,9 +128,9 @@ require ( golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v3 v3.0.1 - helm.sh/helm/v3 v3.15.3 + helm.sh/helm/v3 v3.15.4 k8s.io/api v0.30.3 - k8s.io/utils v0.0.0-20231127182322-b307cd553661 + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 modernc.org/sqlite v1.32.0 sigs.k8s.io/yaml v1.4.0 ) @@ -140,7 +140,7 @@ require ( cloud.google.com/go/compute/metadata v0.3.0 // indirect cloud.google.com/go/iam v1.1.6 // indirect cloud.google.com/go/storage v1.39.1 // indirect - dario.cat/mergo v1.0.0 // indirect + dario.cat/mergo v1.0.1 // indirect github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect @@ -156,7 +156,7 @@ require ( github.com/Intevation/jsonpath v0.2.1 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect - github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/Masterminds/semver/v3 v3.3.0 // indirect github.com/Masterminds/squirrel v1.5.4 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/Microsoft/hcsshim v0.12.0 // indirect @@ -222,6 +222,7 @@ require ( github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-chi/chi v4.1.2+incompatible // indirect github.com/go-errors/errors v1.4.2 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect @@ -267,7 +268,7 @@ require ( github.com/hashicorp/golang-lru v0.6.0 // indirect github.com/hashicorp/hcl v1.0.1-vault-5 // indirect github.com/hashicorp/terraform-json v0.22.1 // indirect - github.com/huandu/xstrings v1.4.0 // indirect + github.com/huandu/xstrings v1.5.0 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect @@ -297,7 +298,7 @@ require ( github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/locker v1.0.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect - github.com/moby/spdystream v0.2.0 // indirect + github.com/moby/spdystream v0.4.0 // indirect github.com/moby/sys/mountinfo v0.7.1 // indirect github.com/moby/sys/sequential v0.5.0 // indirect github.com/moby/sys/signal v0.7.0 // indirect @@ -340,7 +341,7 @@ require ( github.com/shibumi/go-pathspec v1.3.0 // indirect github.com/shirou/gopsutil/v3 v3.24.2 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect - github.com/shopspring/decimal v1.3.1 // indirect + github.com/shopspring/decimal v1.4.0 // indirect github.com/sigstore/cosign/v2 v2.2.4 // indirect github.com/sigstore/sigstore v1.8.3 // indirect github.com/sigstore/timestamp-authority v1.2.2 // indirect @@ -361,6 +362,7 @@ require ( github.com/vbatts/tar-split v0.11.5 // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect + github.com/x448/float16 v0.8.4 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect @@ -394,15 +396,15 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/apiextensions-apiserver v0.30.0 // indirect - k8s.io/apimachinery v0.30.3 // indirect - k8s.io/apiserver v0.30.0 // indirect - k8s.io/cli-runtime v0.30.2 // indirect - k8s.io/client-go v0.30.2 // indirect - k8s.io/component-base v0.30.1 // indirect - k8s.io/klog/v2 v2.120.1 // indirect + k8s.io/apiextensions-apiserver v0.30.3 // indirect + k8s.io/apimachinery v0.31.0 // indirect + k8s.io/apiserver v0.30.3 // indirect + k8s.io/cli-runtime v0.30.3 // indirect + k8s.io/client-go v0.30.3 // indirect + k8s.io/component-base v0.30.3 // indirect + k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - k8s.io/kubectl v0.30.1 // indirect + k8s.io/kubectl v0.30.3 // indirect modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect modernc.org/libc v1.55.3 // indirect modernc.org/mathutil v1.6.0 // indirect diff --git a/go.sum b/go.sum index fdb1c5a2dcd6..d51f8099be1c 100644 --- a/go.sum +++ b/go.sum @@ -188,8 +188,8 @@ cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e h1:GwCVItFUPxw cuelabs.dev/go/oci/ociregistry v0.0.0-20240314152124-224736b49f2e/go.mod h1:ApHceQLLwcOkCEXM1+DyCXTHEJhNGDpJ2kmV6axsx24= cuelang.org/go v0.8.1 h1:VFYsxIFSPY5KgSaH1jQ2GxHOrbu6Ga3kEI70yCZwnOg= cuelang.org/go v0.8.1/go.mod h1:CoDbYolfMms4BhWUlhD+t5ORnihR7wvjcfgyO9lL5FI= -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= @@ -255,11 +255,10 @@ github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= -github.com/Masterminds/semver/v3 v3.2.0/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= -github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= -github.com/Masterminds/sprig/v3 v3.2.3 h1:eL2fZNezLomi0uOLqjQoN6BfsDD+fyLtgbJMAj9n6YA= -github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBaRMhvYXJNkGuM= +github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= +github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= +github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs= +github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0= github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM= github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10= github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= @@ -367,10 +366,10 @@ github.com/aws/aws-sdk-go v1.54.6 h1:HEYUib3yTt8E6vxjMWM3yAq5b+qjj/6aKA62mkgux9g github.com/aws/aws-sdk-go v1.54.6/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDagTk8= github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= -github.com/aws/aws-sdk-go-v2/config v1.27.28 h1:OTxWGW/91C61QlneCtnD62NLb4W616/NM1jA8LhJqbg= -github.com/aws/aws-sdk-go-v2/config v1.27.28/go.mod h1:uzVRVtJSU5EFv6Fu82AoVFKozJi2ZCY6WRCXj06rbvs= -github.com/aws/aws-sdk-go-v2/credentials v1.17.28 h1:m8+AHY/ND8CMHJnPoH7PJIRakWGa4gbfbxuY9TGTUXM= -github.com/aws/aws-sdk-go-v2/credentials v1.17.28/go.mod h1:6TF7dSc78ehD1SL6KpRIPKMA1GyyWflIkjqg+qmf4+c= +github.com/aws/aws-sdk-go-v2/config v1.27.31 h1:kxBoRsjhT3pq0cKthgj6RU6bXTm/2SgdoUMyrVw0rAI= +github.com/aws/aws-sdk-go-v2/config v1.27.31/go.mod h1:z04nZdSWFPaDwK3DdJOG2r+scLQzMYuJeW0CujEm9FM= +github.com/aws/aws-sdk-go-v2/credentials v1.17.30 h1:aau/oYFtibVovr2rDt8FHlU17BTicFEMAi29V1U+L5Q= +github.com/aws/aws-sdk-go-v2/credentials v1.17.30/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 h1:yjwoSyDZF8Jth+mUk5lSPJCkMC0lMy6FaCD51jm6ayE= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12/go.mod h1:fuR57fAgMk7ot3WcNQfb6rSEn+SUffl7ri+aa8uKysI= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 h1:TNyt/+X43KJ9IJJMjKfa3bNTiZbUP7DeCxfbTROESwY= @@ -381,10 +380,10 @@ github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvK github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7 h1:CRzzXjmgx9p362yO39D6hbZULdMI23gaKqSxijJCXHM= github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7/go.mod h1:wnsHqpi3RgDwklS5SPHUgjcUUpontGPKJ+GJYOdV7pY= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.175.1 h1:7B5ppg4i5N2B6t+aH77WLbAu8sD98MLlzruWzq5scyY= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.175.1/go.mod h1:ISODge3zgdwOEa4Ou6WM9PKbxJWJ15DYKnr2bfmCAIA= -github.com/aws/aws-sdk-go-v2/service/ecr v1.32.1 h1:PxM8EHsv1sd9eWGamMQCvqBEjxytK5kAwjrxlfG3tac= -github.com/aws/aws-sdk-go-v2/service/ecr v1.32.1/go.mod h1:kdk+WJbHcGVbIlRQfSrKyuKkbWDdD8I9NScyS5vZ8eQ= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.0 h1:LAdDRIj5BEZM9fLDTUWUyPzWvv5A++nCEps/RGmZNOo= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.0/go.mod h1:ISODge3zgdwOEa4Ou6WM9PKbxJWJ15DYKnr2bfmCAIA= +github.com/aws/aws-sdk-go-v2/service/ecr v1.32.2 h1:2RjzMZp/8PXJUMqiKkDSp7RVj6inF5DpVel35THjV+I= +github.com/aws/aws-sdk-go-v2/service/ecr v1.32.2/go.mod h1:kdk+WJbHcGVbIlRQfSrKyuKkbWDdD8I9NScyS5vZ8eQ= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2 h1:PpbXaecV3sLAS6rjQiaKw4/jyq3Z8gNzmoJupHAoBp0= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2/go.mod h1:fUHpGXr4DrXkEDpGAjClPsviWf+Bszeb0daKE0blxv8= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI= @@ -393,14 +392,14 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 h1:tJ5RnkHC github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18/go.mod h1:++NHzT+nAF7ZPrHPsA+ENvsXkOO8wEu+C6RXltAG4/c= github.com/aws/aws-sdk-go-v2/service/kms v1.30.0 h1:yS0JkEdV6h9JOo8sy2JSpjX+i7vsKifU8SIeHrqiDhU= github.com/aws/aws-sdk-go-v2/service/kms v1.30.0/go.mod h1:+I8VUUSVD4p5ISQtzpgSva4I8cJ4SQ4b1dcBcof7O+g= -github.com/aws/aws-sdk-go-v2/service/s3 v1.59.0 h1:Cso4Ev/XauMVsbwdhYEoxg8rxZWw43CFqqaPB5w3W2c= -github.com/aws/aws-sdk-go-v2/service/s3 v1.59.0/go.mod h1:BSPI0EfnYUuNHPS0uqIo5VrRwzie+Fp+YhQOUs16sKI= +github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0 h1:Wb544Wh+xfSXqJ/j3R4aX9wrKUoZsJNmilBYZb3mKQ4= +github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0/go.mod h1:BSPI0EfnYUuNHPS0uqIo5VrRwzie+Fp+YhQOUs16sKI= github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 h1:zCsFCKvbj25i7p1u94imVoO447I/sFv8qq+lGJhRN0c= github.com/aws/aws-sdk-go-v2/service/sso v1.22.5/go.mod h1:ZeDX1SnKsVlejeuz41GiajjZpRSWR7/42q/EyA/QEiM= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 h1:SKvPgvdvmiTWoi0GAJ7AsJfOz3ngVkD/ERbs5pUnHNI= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5/go.mod h1:20sz31hv/WsPa3HhU3hfrIet2kxM4Pe0r20eBZ20Tac= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.4 h1:iAckBT2OeEK/kBDyN/jDtpEExhjeeA/Im2q4X0rJZT8= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.4/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 h1:OMsEmCyz2i89XwRwPouAJvhj81wINh+4UK+k/0Yo/q8= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.5/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0= github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 h1:SoFYaT9UyGkR0+nogNyD/Lj+bsixB+SNuAS4ABlEs6M= @@ -546,8 +545,8 @@ github.com/docker/cli v27.1.1+incompatible h1:goaZxOqs4QKxznZjjBWKONQci/MywhtRv2 github.com/docker/cli v27.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v27.1.1+incompatible h1:hO/M4MtV36kzKldqnA37IWhebRA+LnqqcqDja6kVaKY= -github.com/docker/docker v27.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.2.0+incompatible h1:Rk9nIVdfH3+Vz4cyI/uhbINhEZ/oLmc+CBXmH6fbNk4= +github.com/docker/docker v27.2.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo= github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= @@ -605,6 +604,8 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -686,7 +687,8 @@ github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqw github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU= @@ -817,8 +819,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= -github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg= -github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= @@ -829,7 +831,6 @@ github.com/google/tink/go v1.7.0 h1:6Eox8zONGebBFcCBqkVmt60LaWZa6xg1cl/DwAh/J1w= github.com/google/tink/go v1.7.0/go.mod h1:GAUOd+QE3pgj9q8VKIGTCP33c/B7eb4NhxLcgTJZStM= github.com/google/trillian v1.6.0 h1:jMBeDBIkINFvS2n6oV5maDqfRlxREAc6CW9QYWQ0qT4= github.com/google/trillian v1.6.0/go.mod h1:Yu3nIMITzNhhMJEHjAtp6xKiu+H/iHu2Oq5FjV2mCWI= -github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -857,7 +858,6 @@ github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH github.com/gorilla/handlers v1.5.1/go.mod h1:t8XrUpc4KVXb7HGyJ4/cEnwQiaxrX/hz1Zv/4g96P1Q= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosuri/uitable v0.0.4 h1:IG2xLKRvErL3uhY6e1BylFzG+aJiwQviDDTfOKeKTpY= @@ -873,8 +873,8 @@ github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= -github.com/hashicorp/go-getter v1.7.5 h1:dT58k9hQ/vbxNMwoI5+xFYAJuv6152UNvdHokfI5wE4= -github.com/hashicorp/go-getter v1.7.5/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= +github.com/hashicorp/go-getter v1.7.6 h1:5jHuM+aH373XNtXl9TNTUH5Qd69Trve11tHIrB+6yj4= +github.com/hashicorp/go-getter v1.7.6/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744= github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= @@ -906,8 +906,8 @@ github.com/hashicorp/hc-install v0.8.0 h1:LdpZeXkZYMQhoKPCecJHlKvUkQFixN/nvyR1Cd github.com/hashicorp/hc-install v0.8.0/go.mod h1:+MwJYjDfCruSD/udvBmRB22Nlkwwkwf5sAB6uTIhSaU= github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= -github.com/hashicorp/hcl/v2 v2.21.0 h1:lve4q/o/2rqwYOgUg3y3V2YPyD1/zkCLGjIV74Jit14= -github.com/hashicorp/hcl/v2 v2.21.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA= +github.com/hashicorp/hcl/v2 v2.22.0 h1:hkZ3nCtqeJsDhPRFz5EA9iwcG1hNWGePOTw6oyul12M= +github.com/hashicorp/hcl/v2 v2.22.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA= github.com/hashicorp/terraform-exec v0.21.0 h1:uNkLAe95ey5Uux6KJdua6+cv8asgILFVWkd/RG0D2XQ= github.com/hashicorp/terraform-exec v0.21.0/go.mod h1:1PPeMYou+KDUSSeRE9szMZ/oHf4fYUmB923Wzbq1ICg= github.com/hashicorp/terraform-json v0.22.1 h1:xft84GZR0QzjPVWs4lRUwvTcPnegqlyS7orfb5Ltvec= @@ -917,12 +917,10 @@ github.com/hashicorp/vault/api v1.12.2/go.mod h1:LSGf1NGT1BnvFFnKVtnvcaLBM2Lz+gJ github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef h1:A9HsByNhogrvm9cWb28sjiS3i7tcKCkflWFEkHfuAgM= github.com/howeyc/gopass v0.0.0-20210920133722-c8aef6fb66ef/go.mod h1:lADxMC39cJJqL93Duh1xhAs4I2Zs8mKS89XWXFGp9cs= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= -github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= -github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= +github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA= github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/in-toto/in-toto-golang v0.9.0 h1:tHny7ac4KgtsfrG6ybU8gVOZux2H8jN05AXJ9EBM1XU= @@ -1064,7 +1062,6 @@ github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= github.com/miekg/pkcs11 v1.1.1 h1:Ugu9pdy6vAYku5DEpVWVFPYnzV+bxB+iRdbuFSu7TvU= github.com/miekg/pkcs11 v1.1.1/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= -github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= @@ -1077,19 +1074,18 @@ github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4 github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= -github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/buildkit v0.15.1 h1:J6wrew7hphKqlq1wuu6yaUb/1Ra7gEzDAovylGztAKM= -github.com/moby/buildkit v0.15.1/go.mod h1:Yis8ZMUJTHX9XhH9zVyK2igqSHV3sxi3UN0uztZocZk= +github.com/moby/buildkit v0.15.2 h1:DnONr0AoceTWyv+plsQ7IhkSaj+6o0WyoaxYPyTFIxs= +github.com/moby/buildkit v0.15.2/go.mod h1:Yis8ZMUJTHX9XhH9zVyK2igqSHV3sxi3UN0uztZocZk= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= -github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= -github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= +github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= +github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/moby/sys/mountinfo v0.7.1 h1:/tTvQaSJRr2FshkhXiIpux6fQ2Zvc4j7tAhMTStAG2g= github.com/moby/sys/mountinfo v0.7.1/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= @@ -1139,8 +1135,8 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= -github.com/onsi/ginkgo/v2 v2.15.0 h1:79HwNRBAZHOEwrczrgSOPy+eFTTlIGELKy5as+ClttY= -github.com/onsi/ginkgo/v2 v2.15.0/go.mod h1:HlxMHtYF57y6Dpf+mc5529KKmSq9h2FpCF+/ZkwUxKM= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= @@ -1162,8 +1158,8 @@ github.com/openvex/go-vex v0.2.5/go.mod h1:j+oadBxSUELkrKh4NfNb+BPo77U3q7gdKME88 github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U= github.com/owenrumney/go-sarif/v2 v2.3.3 h1:ubWDJcF5i3L/EIOER+ZyQ03IfplbSU1BLOE26uKQIIU= github.com/owenrumney/go-sarif/v2 v2.3.3/go.mod h1:MSqMMx9WqlBSY7pXoOZWgEsVB4FDNfhcaXDA1j6Sr+w= -github.com/owenrumney/squealer v1.2.3 h1:7v2BGNReEHYGyopOpjnurbnowk5WWagpN/u9KEu0uUU= -github.com/owenrumney/squealer v1.2.3/go.mod h1:F3PF/UaTAzaexT/cvvMYCSRHLRPBCiUcPClz3SZ6618= +github.com/owenrumney/squealer v1.2.4 h1:77CEDP10mgvFLWHzUIBTfFIj9RkJ5h36YQhZ48GtjsQ= +github.com/owenrumney/squealer v1.2.4/go.mod h1:F3PF/UaTAzaexT/cvvMYCSRHLRPBCiUcPClz3SZ6618= github.com/package-url/packageurl-go v0.1.3 h1:4juMED3hHiz0set3Vq3KeQ75KD1avthoXLtmE3I0PLs= github.com/package-url/packageurl-go v0.1.3/go.mod h1:nKAWB8E6uk1MHqiS/lQb9pYBGH2+mdJ2PJc2s50dQY0= github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= @@ -1234,8 +1230,8 @@ github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6ke github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= -github.com/samber/lo v1.46.0 h1:w8G+oaCPgz1PoCJztqymCFaKwXt+5cCXn51uPxExFfQ= -github.com/samber/lo v1.46.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= +github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= +github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= github.com/sassoftware/relic v7.2.1+incompatible h1:Pwyh1F3I0r4clFJXkSI8bOyJINGqpgjJU3DYAZeI05A= @@ -1257,9 +1253,9 @@ github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFt github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8= github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= +github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= +github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= github.com/sigstore/cosign/v2 v2.2.4 h1:iY4vtEacmu2hkNj1Fh+8EBqBwKs2DHM27/lbNWDFJro= github.com/sigstore/cosign/v2 v2.2.4/go.mod h1:JZlRD2uaEjVAvZ1XJ3QkkZJhTqSDVtLaet+C/TMR81Y= @@ -1297,7 +1293,6 @@ github.com/spdx/tools-golang v0.5.5 h1:61c0KLfAcNqAjlg6UNMdkwpMernhw3zVRwDZ2x9XO github.com/spdx/tools-golang v0.5.5/go.mod h1:MVIsXx8ZZzaRWNQpUDhC4Dud34edUYJYecciXgrw5vE= github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= -github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= @@ -1336,12 +1331,12 @@ github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BG github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uRtcvYAPLCF15qguo= github.com/terminalstatic/go-xsd-validate v0.1.5/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw= -github.com/testcontainers/testcontainers-go v0.32.0 h1:ug1aK08L3gCHdhknlTTwWjPHPS+/alvLJU/DRxTD/ME= -github.com/testcontainers/testcontainers-go v0.32.0/go.mod h1:CRHrzHLQhlXUsa5gXjTOfqIEJcrK5+xMDmBr/WMI88E= -github.com/testcontainers/testcontainers-go/modules/localstack v0.32.0 h1:FITjE+DSDD136HQho7ThA6cEtUouZzDf7FvMBL2Muog= -github.com/testcontainers/testcontainers-go/modules/localstack v0.32.0/go.mod h1:JasdXHmUT8MTDYfyJza3JjO/k+QA3m8K2GQfnFQM++g= -github.com/tetratelabs/wazero v1.7.3 h1:PBH5KVahrt3S2AHgEjKu4u+LlDbbk+nsGE3KLucy6Rw= -github.com/tetratelabs/wazero v1.7.3/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y= +github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw= +github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8= +github.com/testcontainers/testcontainers-go/modules/localstack v0.33.0 h1:AhbUGUjneEnMyTV5aTsPYzDiAWrba1duPtiV+Z9CKdY= +github.com/testcontainers/testcontainers-go/modules/localstack v0.33.0/go.mod h1:J5vMq1fXXiTfwcJplMClHhn+j8+MbIMv7Lic4d9E8qU= +github.com/tetratelabs/wazero v1.8.0 h1:iEKu0d4c2Pd+QSRieYbnQC9yiFlMS9D+Jr0LsRmcF4g= +github.com/tetratelabs/wazero v1.8.0/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg= github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU= github.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qvs5LdxRWqRI= @@ -1375,6 +1370,8 @@ github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/xanzy/go-gitlab v0.102.0 h1:ExHuJ1OTQ2yt25zBMMj0G96ChBirGYv8U7HyUiYkZ+4= github.com/xanzy/go-gitlab v0.102.0/go.mod h1:ETg8tcj4OhrB84UEgeE8dSuV/0h4BBL1uOV/qK0vlyI= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= @@ -1418,8 +1415,8 @@ github.com/zclconf/go-cty-yaml v1.0.3/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JApr github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs= github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= -go.etcd.io/bbolt v1.3.10 h1:+BqfJTcCzTItrop8mq/lbzL8wSGtj94UO/3U31shqG0= -go.etcd.io/bbolt v1.3.10/go.mod h1:bK3UQLPJZly7IlNmV7uVHJDxfe5aK9Ll93e/74Y9oEQ= +go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0= +go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I= go.mongodb.org/mongo-driver v1.14.0 h1:P98w8egYRjYe3XDjxhYJagTokP/H6HzlsnojRgZRd80= go.mongodb.org/mongo-driver v1.14.0/go.mod h1:Vzb0Mk/pa7e6cWw85R4F/endUC3u0U9jGcNU603k65c= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= @@ -1472,7 +1469,6 @@ golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= @@ -1574,7 +1570,6 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.0.0-20220909164309-bea034e7d591/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.0.0-20221014081412-f15817d10f9b/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= @@ -1711,7 +1706,6 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1727,7 +1721,6 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= @@ -2082,8 +2075,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= -helm.sh/helm/v3 v3.15.3 h1:HcZDaVFe9uHa6hpsR54mJjYyRy4uz/pc6csg27nxFOc= -helm.sh/helm/v3 v3.15.3/go.mod h1:FzSIP8jDQaa6WAVg9F+OkKz7J0ZmAga4MABtTbsb9WQ= +helm.sh/helm/v3 v3.15.4 h1:UFHd6oZ1IN3FsUZ7XNhOQDyQ2QYknBNWRHH57e9cbHY= +helm.sh/helm/v3 v3.15.4/go.mod h1:phOwlxqGSgppCY/ysWBNRhG3MtnpsttOzxaTK+Mt40E= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -2093,26 +2086,26 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ= k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04= -k8s.io/apiextensions-apiserver v0.30.0 h1:jcZFKMqnICJfRxTgnC4E+Hpcq8UEhT8B2lhBcQ+6uAs= -k8s.io/apiextensions-apiserver v0.30.0/go.mod h1:N9ogQFGcrbWqAY9p2mUAL5mGxsLqwgtUce127VtRX5Y= -k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc= -k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= -k8s.io/apiserver v0.30.0 h1:QCec+U72tMQ+9tR6A0sMBB5Vh6ImCEkoKkTDRABWq6M= -k8s.io/apiserver v0.30.0/go.mod h1:smOIBq8t0MbKZi7O7SyIpjPsiKJ8qa+llcFCluKyqiY= -k8s.io/cli-runtime v0.30.2 h1:ooM40eEJusbgHNEqnHziN9ZpLN5U4WcQGsdLKVxpkKE= -k8s.io/cli-runtime v0.30.2/go.mod h1:Y4g/2XezFyTATQUbvV5WaChoUGhojv/jZAtdp5Zkm0A= -k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50= -k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs= -k8s.io/component-base v0.30.1 h1:bvAtlPh1UrdaZL20D9+sWxsJljMi0QZ3Lmw+kmZAaxQ= -k8s.io/component-base v0.30.1/go.mod h1:e/X9kDiOebwlI41AvBHuWdqFriSRrX50CdwA9TFaHLI= -k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= -k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/apiextensions-apiserver v0.30.3 h1:oChu5li2vsZHx2IvnGP3ah8Nj3KyqG3kRSaKmijhB9U= +k8s.io/apiextensions-apiserver v0.30.3/go.mod h1:uhXxYDkMAvl6CJw4lrDN4CPbONkF3+XL9cacCT44kV4= +k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc= +k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/apiserver v0.30.3 h1:QZJndA9k2MjFqpnyYv/PH+9PE0SHhx3hBho4X0vE65g= +k8s.io/apiserver v0.30.3/go.mod h1:6Oa88y1CZqnzetd2JdepO0UXzQX4ZnOekx2/PtEjrOg= +k8s.io/cli-runtime v0.30.3 h1:aG69oRzJuP2Q4o8dm+f5WJIX4ZBEwrvdID0+MXyUY6k= +k8s.io/cli-runtime v0.30.3/go.mod h1:hwrrRdd9P84CXSKzhHxrOivAR9BRnkMt0OeP5mj7X30= +k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k= +k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U= +k8s.io/component-base v0.30.3 h1:Ci0UqKWf4oiwy8hr1+E3dsnliKnkMLZMVbWzeorlk7s= +k8s.io/component-base v0.30.3/go.mod h1:C1SshT3rGPCuNtBs14RmVD2xW0EhRSeLvBh7AGk1quA= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/kubectl v0.30.1 h1:sHFIRI3oP0FFZmBAVEE8ErjnTyXDPkBcvO88mH9RjuY= -k8s.io/kubectl v0.30.1/go.mod h1:7j+L0Cc38RYEcx+WH3y44jRBe1Q1jxdGPKkX0h4iDq0= -k8s.io/utils v0.0.0-20231127182322-b307cd553661 h1:FepOBzJ0GXm8t0su67ln2wAZjbQ6RxQGZDnzuLcrUTI= -k8s.io/utils v0.0.0-20231127182322-b307cd553661/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/kubectl v0.30.3 h1:YIBBvMdTW0xcDpmrOBzcpUVsn+zOgjMYIu7kAq+yqiI= +k8s.io/kubectl v0.30.3/go.mod h1:IcR0I9RN2+zzTRUa1BzZCm4oM0NLOawE6RzlDvd1Fpo= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ= modernc.org/ccgo/v4 v4.19.2 h1:lwQZgvboKD0jBwdaeVCTouxhxAyN6iawF3STraAal8Y= From 3642fe16c923b7042b4fe1e6e4c3bf93e50b1255 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Sep 2024 10:59:34 +0400 Subject: [PATCH 073/183] chore(deps): bump the aws group with 6 updates (#7468) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 26 +++++++++++++------------- go.sum | 52 ++++++++++++++++++++++++++-------------------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/go.mod b/go.mod index e2191c3c2800..23f7771452a8 100644 --- a/go.mod +++ b/go.mod @@ -29,13 +29,13 @@ require ( github.com/aquasecurity/trivy-db v0.0.0-20240718084044-d23a6ca8ba04 github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20240707095038-0300bc49b68b - github.com/aws/aws-sdk-go-v2 v1.30.4 - github.com/aws/aws-sdk-go-v2/config v1.27.31 - github.com/aws/aws-sdk-go-v2/credentials v1.17.30 - github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.0 - github.com/aws/aws-sdk-go-v2/service/ecr v1.32.2 - github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0 - github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 // indirect + github.com/aws/aws-sdk-go-v2 v1.30.5 + github.com/aws/aws-sdk-go-v2/config v1.27.33 + github.com/aws/aws-sdk-go-v2/credentials v1.17.32 + github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.2 + github.com/aws/aws-sdk-go-v2/service/ecr v1.32.4 + github.com/aws/aws-sdk-go-v2/service/s3 v1.61.2 + github.com/aws/aws-sdk-go-v2/service/sts v1.30.7 // indirect github.com/aws/smithy-go v1.20.4 github.com/bitnami/go-version v0.0.0-20231130084017-bb00604d650c github.com/bmatcuk/doublestar/v4 v4.6.1 @@ -171,15 +171,15 @@ require ( github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go v1.54.6 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.22.7 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/blang/semver v3.5.1+incompatible // indirect diff --git a/go.sum b/go.sum index d51f8099be1c..80827c8b4ffb 100644 --- a/go.sum +++ b/go.sum @@ -364,42 +364,42 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:W github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.54.6 h1:HEYUib3yTt8E6vxjMWM3yAq5b+qjj/6aKA62mkgux9g= github.com/aws/aws-sdk-go v1.54.6/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.30.4 h1:frhcagrVNrzmT95RJImMHgabt99vkXGslubDaDagTk8= -github.com/aws/aws-sdk-go-v2 v1.30.4/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= -github.com/aws/aws-sdk-go-v2/config v1.27.31 h1:kxBoRsjhT3pq0cKthgj6RU6bXTm/2SgdoUMyrVw0rAI= -github.com/aws/aws-sdk-go-v2/config v1.27.31/go.mod h1:z04nZdSWFPaDwK3DdJOG2r+scLQzMYuJeW0CujEm9FM= -github.com/aws/aws-sdk-go-v2/credentials v1.17.30 h1:aau/oYFtibVovr2rDt8FHlU17BTicFEMAi29V1U+L5Q= -github.com/aws/aws-sdk-go-v2/credentials v1.17.30/go.mod h1:BPJ/yXV92ZVq6G8uYvbU0gSl8q94UB63nMT5ctNO38g= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12 h1:yjwoSyDZF8Jth+mUk5lSPJCkMC0lMy6FaCD51jm6ayE= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.12/go.mod h1:fuR57fAgMk7ot3WcNQfb6rSEn+SUffl7ri+aa8uKysI= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16 h1:TNyt/+X43KJ9IJJMjKfa3bNTiZbUP7DeCxfbTROESwY= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.16/go.mod h1:2DwJF39FlNAUiX5pAc0UNeiz16lK2t7IaFcm0LFHEgc= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16 h1:jYfy8UPmd+6kJW5YhY0L1/KftReOGxI/4NtVSTh9O/I= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.16/go.mod h1:7ZfEPZxkW42Afq4uQB8H2E2e6ebh6mXTueEpYzjCzcs= +github.com/aws/aws-sdk-go-v2 v1.30.5 h1:mWSRTwQAb0aLE17dSzztCVJWI9+cRMgqebndjwDyK0g= +github.com/aws/aws-sdk-go-v2 v1.30.5/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= +github.com/aws/aws-sdk-go-v2/config v1.27.33 h1:Nof9o/MsmH4oa0s2q9a0k7tMz5x/Yj5k06lDODWz3BU= +github.com/aws/aws-sdk-go-v2/config v1.27.33/go.mod h1:kEqdYzRb8dd8Sy2pOdEbExTTF5v7ozEXX0McgPE7xks= +github.com/aws/aws-sdk-go-v2/credentials v1.17.32 h1:7Cxhp/BnT2RcGy4VisJ9miUPecY+lyE9I8JvcZofn9I= +github.com/aws/aws-sdk-go-v2/credentials v1.17.32/go.mod h1:P5/QMF3/DCHbXGEGkdbilXHsyTBX5D3HSwcrSc9p20I= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 h1:pfQ2sqNpMVK6xz2RbqLEL0GH87JOwSxPV2rzm8Zsb74= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13/go.mod h1:NG7RXPUlqfsCLLFfi0+IpKN4sCB9D9fw/qTaSB+xRoU= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 h1:pI7Bzt0BJtYA0N/JEC6B8fJ4RBrEMi1LBrkMdFYNSnQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17/go.mod h1:Dh5zzJYMtxfIjYW+/evjQ8uj2OyR/ve2KROHGHlSFqE= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 h1:Mqr/V5gvrhA2gvgnF42Zh5iMiQNcOYthFYwCyrnuWlc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17/go.mod h1:aLJpZlCmjE+V+KtN1q1uyZkfnUWpQGpbsn89XPKyzfU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7 h1:CRzzXjmgx9p362yO39D6hbZULdMI23gaKqSxijJCXHM= github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7/go.mod h1:wnsHqpi3RgDwklS5SPHUgjcUUpontGPKJ+GJYOdV7pY= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.0 h1:LAdDRIj5BEZM9fLDTUWUyPzWvv5A++nCEps/RGmZNOo= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.0/go.mod h1:ISODge3zgdwOEa4Ou6WM9PKbxJWJ15DYKnr2bfmCAIA= -github.com/aws/aws-sdk-go-v2/service/ecr v1.32.2 h1:2RjzMZp/8PXJUMqiKkDSp7RVj6inF5DpVel35THjV+I= -github.com/aws/aws-sdk-go-v2/service/ecr v1.32.2/go.mod h1:kdk+WJbHcGVbIlRQfSrKyuKkbWDdD8I9NScyS5vZ8eQ= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.2 h1:QUUvxEs9q1DsYCaWaRrV8i7n82Adm34jrHb6OPjXPqc= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.2/go.mod h1:TFSALWR7Xs7+KyMM87ZAYxncKFBvzEt2rpK/BJCH2ps= +github.com/aws/aws-sdk-go-v2/service/ecr v1.32.4 h1:nQAU2Yr+afkAvIV39mg7LrNYFNQP7ShwbmiJqx2fUKA= +github.com/aws/aws-sdk-go-v2/service/ecr v1.32.4/go.mod h1:keOS9j4fv5ASh7dV29lIpGw2QgoJwGFAyMU0uPvfax4= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2 h1:PpbXaecV3sLAS6rjQiaKw4/jyq3Z8gNzmoJupHAoBp0= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2/go.mod h1:fUHpGXr4DrXkEDpGAjClPsviWf+Bszeb0daKE0blxv8= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4/go.mod h1:Vz1JQXliGcQktFTN/LN6uGppAIRoLBR2bMvIMP0gOjc= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18 h1:tJ5RnkHCiSH0jyd6gROjlJtNwov0eGYNz8s8nFcR0jQ= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.18/go.mod h1:++NHzT+nAF7ZPrHPsA+ENvsXkOO8wEu+C6RXltAG4/c= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 h1:rfprUlsdzgl7ZL2KlXiUAoJnI/VxfHCvDFr2QDFj6u4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19/go.mod h1:SCWkEdRq8/7EK60NcvvQ6NXKuTcchAD4ROAsC37VEZE= github.com/aws/aws-sdk-go-v2/service/kms v1.30.0 h1:yS0JkEdV6h9JOo8sy2JSpjX+i7vsKifU8SIeHrqiDhU= github.com/aws/aws-sdk-go-v2/service/kms v1.30.0/go.mod h1:+I8VUUSVD4p5ISQtzpgSva4I8cJ4SQ4b1dcBcof7O+g= -github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0 h1:Wb544Wh+xfSXqJ/j3R4aX9wrKUoZsJNmilBYZb3mKQ4= -github.com/aws/aws-sdk-go-v2/service/s3 v1.61.0/go.mod h1:BSPI0EfnYUuNHPS0uqIo5VrRwzie+Fp+YhQOUs16sKI= -github.com/aws/aws-sdk-go-v2/service/sso v1.22.5 h1:zCsFCKvbj25i7p1u94imVoO447I/sFv8qq+lGJhRN0c= -github.com/aws/aws-sdk-go-v2/service/sso v1.22.5/go.mod h1:ZeDX1SnKsVlejeuz41GiajjZpRSWR7/42q/EyA/QEiM= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5 h1:SKvPgvdvmiTWoi0GAJ7AsJfOz3ngVkD/ERbs5pUnHNI= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.5/go.mod h1:20sz31hv/WsPa3HhU3hfrIet2kxM4Pe0r20eBZ20Tac= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.5 h1:OMsEmCyz2i89XwRwPouAJvhj81wINh+4UK+k/0Yo/q8= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.5/go.mod h1:vmSqFK+BVIwVpDAGZB3CoCXHzurt4qBE8lf+I/kRTh0= +github.com/aws/aws-sdk-go-v2/service/s3 v1.61.2 h1:Kp6PWAlXwP1UvIflkIP6MFZYBNDCa4mFCGtxrpICVOg= +github.com/aws/aws-sdk-go-v2/service/s3 v1.61.2/go.mod h1:5FmD/Dqq57gP+XwaUnd5WFPipAuzrf0HmupX27Gvjvc= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.7 h1:pIaGg+08llrP7Q5aiz9ICWbY8cqhTkyy+0SHvfzQpTc= +github.com/aws/aws-sdk-go-v2/service/sso v1.22.7/go.mod h1:eEygMHnTKH/3kNp9Jr1n3PdejuSNcgwLe1dWgQtO0VQ= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7 h1:/Cfdu0XV3mONYKaOt1Gr0k1KvQzkzPyiKUdlWJqy+J4= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7/go.mod h1:bCbAxKDqNvkHxRaIMnyVPXPo+OaPRwvmgzMxbz1VKSA= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.7 h1:NKTa1eqZYw8tiHSRGpP0VtTdub/8KNk8sDkNPFaOKDE= +github.com/aws/aws-sdk-go-v2/service/sts v1.30.7/go.mod h1:NXi1dIAGteSaRLqYgarlhP/Ij0cFT+qmCwiJqWh/U5o= github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 h1:SoFYaT9UyGkR0+nogNyD/Lj+bsixB+SNuAS4ABlEs6M= From dd0a64a1cf0cd76e6f81e3ff55fa6ccb95ce3c3d Mon Sep 17 00:00:00 2001 From: s-reddy1498 <41355782+s-reddy1498@users.noreply.github.com> Date: Tue, 10 Sep 2024 20:32:43 +0530 Subject: [PATCH 074/183] fix(oracle): Update EOL date for Oracle 7 (#7480) --- pkg/detector/ospkg/oracle/oracle.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/detector/ospkg/oracle/oracle.go b/pkg/detector/ospkg/oracle/oracle.go index 2b234698e38a..dd66c11a3cf1 100644 --- a/pkg/detector/ospkg/oracle/oracle.go +++ b/pkg/detector/ospkg/oracle/oracle.go @@ -25,7 +25,7 @@ var ( "4": time.Date(2013, 12, 31, 23, 59, 59, 0, time.UTC), "5": time.Date(2017, 12, 31, 23, 59, 59, 0, time.UTC), "6": time.Date(2021, 3, 21, 23, 59, 59, 0, time.UTC), - "7": time.Date(2024, 7, 23, 23, 59, 59, 0, time.UTC), + "7": time.Date(2024, 12, 31, 23, 59, 59, 0, time.UTC), "8": time.Date(2029, 7, 18, 23, 59, 59, 0, time.UTC), "9": time.Date(2032, 7, 18, 23, 59, 59, 0, time.UTC), } From 927c6e0c9d4d4a3f1be00f0f661c1d18325d9440 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Wed, 11 Sep 2024 08:39:09 +0400 Subject: [PATCH 075/183] fix(report): change a receiver of MarshalJSON (#7483) Signed-off-by: knqyf263 --- go.mod | 4 ++-- go.sum | 8 ++++---- pkg/fanal/types/package.go | 4 ++-- pkg/report/template_test.go | 29 +++++++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 23f7771452a8..2ef18dc1cc7a 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8 github.com/aquasecurity/tml v0.6.1 github.com/aquasecurity/trivy-checks v0.13.1-0.20240830230553-53ddbbade784 - github.com/aquasecurity/trivy-db v0.0.0-20240718084044-d23a6ca8ba04 + github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1 github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20240707095038-0300bc49b68b github.com/aws/aws-sdk-go-v2 v1.30.5 @@ -384,7 +384,7 @@ require ( golang.org/x/sys v0.23.0 // indirect golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 // indirect golang.org/x/time v0.6.0 // indirect - golang.org/x/tools v0.23.0 // indirect + golang.org/x/tools v0.24.0 // indirect google.golang.org/api v0.172.0 // indirect google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect diff --git a/go.sum b/go.sum index 80827c8b4ffb..daaa23dc6559 100644 --- a/go.sum +++ b/go.sum @@ -349,8 +349,8 @@ github.com/aquasecurity/tml v0.6.1 h1:y2ZlGSfrhnn7t4ZJ/0rotuH+v5Jgv6BDDO5jB6A9gw github.com/aquasecurity/tml v0.6.1/go.mod h1:OnYMWY5lvI9ejU7yH9LCberWaaTBW7hBFsITiIMY2yY= github.com/aquasecurity/trivy-checks v0.13.1-0.20240830230553-53ddbbade784 h1:1rvPiCK8uQd3sarOuZ60nwksHpxsNdrvptz4eDW/V14= github.com/aquasecurity/trivy-checks v0.13.1-0.20240830230553-53ddbbade784/go.mod h1:Ralz7PWmR3LirHlXxVtUXc+7CFmWE82jbLk7+TPvV/0= -github.com/aquasecurity/trivy-db v0.0.0-20240718084044-d23a6ca8ba04 h1:6/T8sFdNVG/AwOGoK6X55h7hF7LYqK8bsuPz8iEz8jM= -github.com/aquasecurity/trivy-db v0.0.0-20240718084044-d23a6ca8ba04/go.mod h1:0T6oy2t1Iedt+yi3Ml5cpOYp5FZT4MI1/mx+3p+PIs8= +github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1 h1:G0gnacAORRUqz2Tm5MqivSpldY2GZ74ijhJcMsae+sA= +github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1/go.mod h1:PYkSRx4dlgFATEt+okGwibvbxVEtqsOdH+vX/saACYE= github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 h1:JVgBIuIYbwG+ekC5lUHUpGJboPYiCcxiz06RCtz8neI= github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48/go.mod h1:Ldya37FLi0e/5Cjq2T5Bty7cFkzUDwTcPeQua+2M8i8= github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20240707095038-0300bc49b68b h1:h7gsIzHyrxpQnayOuQI0kX7+8rVcqhV6G5bM3KVFyJU= @@ -1806,8 +1806,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= -golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= -golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= +golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= golang.org/x/vuln v1.1.3 h1:NPGnvPOTgnjBc9HTaUx+nj+EaUYxl5SJOWqaDYGaFYw= golang.org/x/vuln v1.1.3/go.mod h1:7Le6Fadm5FOqE9C926BCD0g12NWyhg7cxV4BwcPFuNY= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/fanal/types/package.go b/pkg/fanal/types/package.go index 822291e61c29..2726aa8ad8c8 100644 --- a/pkg/fanal/types/package.go +++ b/pkg/fanal/types/package.go @@ -78,7 +78,7 @@ type PkgIdentifier struct { } // MarshalJSON customizes the JSON encoding of PkgIdentifier. -func (id *PkgIdentifier) MarshalJSON() ([]byte, error) { +func (id PkgIdentifier) MarshalJSON() ([]byte, error) { var p string if id.PURL != nil { p = id.PURL.String() @@ -90,7 +90,7 @@ func (id *PkgIdentifier) MarshalJSON() ([]byte, error) { *Alias }{ PURL: p, - Alias: (*Alias)(id), + Alias: (*Alias)(&id), }) } diff --git a/pkg/report/template_test.go b/pkg/report/template_test.go index 56a2d6df7610..bf2e04b7473e 100644 --- a/pkg/report/template_test.go +++ b/pkg/report/template_test.go @@ -6,11 +6,13 @@ import ( "testing" "time" + "github.com/package-url/packageurl-go" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" "github.com/aquasecurity/trivy/pkg/clock" + ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/report" "github.com/aquasecurity/trivy/pkg/types" ) @@ -156,6 +158,33 @@ func TestReportWriter_Template(t *testing.T) { template: `{{ $high := 0 }}{{ $critical := 0 }}{{ range . }}{{ range .Vulnerabilities}}{{ if eq .Severity "HIGH" }}{{ $high = add $high 1 }}{{ end }}{{ if eq .Severity "CRITICAL" }}{{ $critical = add $critical 1 }}{{ end }}{{ end }}Critical: {{ $critical }}, High: {{ $high }}{{ end }}`, expected: `Critical: 2, High: 1`, }, + { + name: "custom JSON marshaler", + detectedVulns: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2019-0000", + PkgName: "foo", + Status: dbTypes.StatusAffected, + PkgIdentifier: ftypes.PkgIdentifier{ + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeNPM, + Name: "foobar", + Version: "1.2.3", + }, + }, + }, + }, + template: `{{ range . }}{{ range .Vulnerabilities}}{{ toPrettyJson . }}{{ end }}{{ end }}`, + expected: `{ + "VulnerabilityID": "CVE-2019-0000", + "PkgName": "foo", + "PkgIdentifier": { + "PURL": "pkg:npm/foobar@1.2.3" + }, + "Status": "affected", + "Layer": {} +}`, + }, { name: "happy path: env var parsing", detectedVulns: []types.DetectedVulnerability{}, From 7ff9aff2739b2eee4a98175b98914795e4077060 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Wed, 11 Sep 2024 12:16:51 +0600 Subject: [PATCH 076/183] fix(report): fix error with unmarshal of `ExperimentalModifiedFindings` (#7463) Signed-off-by: knqyf263 Co-authored-by: knqyf263 --- integration/convert_test.go | 26 ++- .../convert/npm-with-suppressed.json.golden | 195 ++++++++++++++++++ pkg/types/finding.go | 47 +++++ 3 files changed, 265 insertions(+), 3 deletions(-) create mode 100644 integration/testdata/fixtures/convert/npm-with-suppressed.json.golden diff --git a/integration/convert_test.go b/integration/convert_test.go index 803ba538dcba..e7d2a5f5e6fe 100644 --- a/integration/convert_test.go +++ b/integration/convert_test.go @@ -11,9 +11,11 @@ import ( func TestConvert(t *testing.T) { type args struct { - input string - format string - scanners string + input string + format string + scanners string + showSuppressed bool + listAllPkgs bool } tests := []struct { name string @@ -37,6 +39,16 @@ func TestConvert(t *testing.T) { }, golden: "testdata/npm-cyclonedx.json.golden", }, + { + name: "npm with suppressed vulnerability", + args: args{ + input: "testdata/fixtures/convert/npm-with-suppressed.json.golden", + format: "json", + showSuppressed: true, + listAllPkgs: true, + }, + golden: "testdata/fixtures/convert/npm-with-suppressed.json.golden", + }, } for _, tt := range tests { @@ -50,6 +62,14 @@ func TestConvert(t *testing.T) { tt.args.format, } + if tt.args.showSuppressed { + osArgs = append(osArgs, "--show-suppressed") + } + + if tt.args.listAllPkgs { + osArgs = append(osArgs, "--list-all-pkgs") + } + // Set up the output file outputFile := filepath.Join(t.TempDir(), "output.json") if *update { diff --git a/integration/testdata/fixtures/convert/npm-with-suppressed.json.golden b/integration/testdata/fixtures/convert/npm-with-suppressed.json.golden new file mode 100644 index 000000000000..0ce14e33545b --- /dev/null +++ b/integration/testdata/fixtures/convert/npm-with-suppressed.json.golden @@ -0,0 +1,195 @@ +{ + "SchemaVersion": 2, + "CreatedAt": "2024-09-09T13:21:09.230231+06:00", + "ArtifactName": "package-lock.json", + "ArtifactType": "filesystem", + "Metadata": { + "ImageConfig": { + "architecture": "", + "created": "0001-01-01T00:00:00Z", + "os": "", + "rootfs": { + "type": "", + "diff_ids": null + }, + "config": {} + } + }, + "Results": [ + { + "Target": "package-lock.json", + "Class": "lang-pkgs", + "Type": "npm", + "Packages": [ + { + "ID": "debug@3.0.1", + "Name": "debug", + "Identifier": { + "PURL": "pkg:npm/debug@3.0.1", + "UID": "45acc377fa09cc3" + }, + "Version": "3.0.1", + "Relationship": "direct", + "DependsOn": [ + "ms@2.0.0" + ], + "Layer": {}, + "Locations": [ + { + "StartLine": 11, + "EndLine": 19 + } + ] + }, + { + "ID": "ms@2.0.0", + "Name": "ms", + "Identifier": { + "PURL": "pkg:npm/ms@2.0.0", + "UID": "f51af0181daf2ced" + }, + "Version": "2.0.0", + "Indirect": true, + "Relationship": "indirect", + "Layer": {}, + "Locations": [ + { + "StartLine": 20, + "EndLine": 25 + } + ] + } + ], + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2017-20165", + "PkgID": "debug@3.0.1", + "PkgName": "debug", + "PkgIdentifier": { + "PURL": "pkg:npm/debug@3.0.1", + "UID": "45acc377fa09cc3" + }, + "InstalledVersion": "3.0.1", + "FixedVersion": "3.1.0, 2.6.9", + "Status": "fixed", + "Layer": {}, + "SeveritySource": "ghsa", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2017-20165", + "DataSource": { + "ID": "ghsa", + "Name": "GitHub Security Advisory npm", + "URL": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Anpm" + }, + "Title": "A vulnerability classified as problematic has been found in debug-js d ...", + "Description": "A vulnerability classified as problematic has been found in debug-js debug up to 3.0.x. This affects the function useColors of the file src/node.js. The manipulation of the argument str leads to inefficient regular expression complexity. Upgrading to version 3.1.0 is able to address this issue. The identifier of the patch is c38a0166c266a679c8de012d4eaccec3f944e685. It is recommended to upgrade the affected component. The identifier VDB-217665 was assigned to this vulnerability.", + "Severity": "HIGH", + "CweIDs": [ + "CWE-1333" + ], + "VendorSeverity": { + "ghsa": 3, + "nvd": 3 + }, + "CVSS": { + "ghsa": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + }, + "nvd": { + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H", + "V3Score": 7.5 + } + }, + "References": [ + "https://github.com/debug-js/debug", + "https://github.com/debug-js/debug/commit/c38a0166c266a679c8de012d4eaccec3f944e685", + "https://github.com/debug-js/debug/commit/f53962e944a87e6ca9bb622a2a12dffc22a9bb5a", + "https://github.com/debug-js/debug/pull/504", + "https://github.com/debug-js/debug/releases/tag/2.6.9", + "https://github.com/debug-js/debug/releases/tag/3.1.0", + "https://nvd.nist.gov/vuln/detail/CVE-2017-20165", + "https://vuldb.com/?ctiid.217665", + "https://vuldb.com/?id.217665" + ], + "PublishedDate": "2023-01-09T10:15:10.447Z", + "LastModifiedDate": "2024-05-17T01:17:24.28Z" + } + ], + "ExperimentalModifiedFindings": [ + { + "Type": "vulnerability", + "Status": "not_affected", + "Statement": "vulnerable_code_not_in_execute_path", + "Source": "./vex.json", + "Finding": { + "VulnerabilityID": "CVE-2017-16137", + "PkgID": "debug@3.0.1", + "PkgName": "debug", + "PkgIdentifier": { + "PURL": "pkg:npm/debug@3.0.1", + "UID": "45acc377fa09cc3" + }, + "InstalledVersion": "3.0.1", + "FixedVersion": "2.6.9, 3.1.0, 3.2.7, 4.3.1", + "Status": "fixed", + "Layer": {}, + "SeveritySource": "ghsa", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2017-16137", + "DataSource": { + "ID": "ghsa", + "Name": "GitHub Security Advisory npm", + "URL": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Anpm" + }, + "Title": "nodejs-debug: Regular expression Denial of Service", + "Description": "The debug module is vulnerable to regular expression denial of service when untrusted user input is passed into the o formatter. It takes around 50k characters to block for 2 seconds making this a low severity issue.", + "Severity": "LOW", + "CweIDs": [ + "CWE-400" + ], + "VendorSeverity": { + "ghsa": 1, + "nvd": 2, + "redhat": 2 + }, + "CVSS": { + "ghsa": { + "V3Vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:L", + "V3Score": 3.7 + }, + "nvd": { + "V2Vector": "AV:N/AC:L/Au:N/C:N/I:N/A:P", + "V3Vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", + "V2Score": 5, + "V3Score": 5.3 + }, + "redhat": { + "V3Vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L", + "V3Score": 5.3 + } + }, + "References": [ + "https://access.redhat.com/security/cve/CVE-2017-16137", + "https://github.com/debug-js/debug/commit/4e2150207c568adb9ead8f4c4528016081c88020", + "https://github.com/debug-js/debug/commit/71169065b5262f9858ac78cc0b688c84a438f290", + "https://github.com/debug-js/debug/commit/b6d12fdbc63b483e5c969da33ea6adc09946b5ac", + "https://github.com/debug-js/debug/commit/f53962e944a87e6ca9bb622a2a12dffc22a9bb5a", + "https://github.com/debug-js/debug/issues/797", + "https://github.com/visionmedia/debug", + "https://github.com/visionmedia/debug/issues/501", + "https://github.com/visionmedia/debug/pull/504", + "https://lists.apache.org/thread.html/r8ba4c628fba7181af58817d452119481adce4ba92e889c643e4c7dd3%40%3Ccommits.netbeans.apache.org%3E", + "https://lists.apache.org/thread.html/r8ba4c628fba7181af58817d452119481adce4ba92e889c643e4c7dd3@%3Ccommits.netbeans.apache.org%3E", + "https://lists.apache.org/thread.html/rb5ac16fad337d1f3bb7079549f97d8166d0ef3082629417c39f12d63%40%3Cnotifications.netbeans.apache.org%3E", + "https://lists.apache.org/thread.html/rb5ac16fad337d1f3bb7079549f97d8166d0ef3082629417c39f12d63@%3Cnotifications.netbeans.apache.org%3E", + "https://nodesecurity.io/advisories/534", + "https://nvd.nist.gov/vuln/detail/CVE-2017-16137", + "https://www.cve.org/CVERecord?id=CVE-2017-16137" + ], + "PublishedDate": "2018-06-07T02:29:03.817Z", + "LastModifiedDate": "2023-11-07T02:40:28.13Z" + } + } + ] + } + ] +} diff --git a/pkg/types/finding.go b/pkg/types/finding.go index 9e194b8e6b74..65bc4b930fc9 100644 --- a/pkg/types/finding.go +++ b/pkg/types/finding.go @@ -1,5 +1,11 @@ package types +import ( + "encoding/json" + + "golang.org/x/xerrors" +) + type FindingType string type FindingStatus string @@ -45,3 +51,44 @@ func NewModifiedFinding(f finding, status FindingStatus, statement, source strin Finding: f, } } + +// UnmarshalJSON unmarshals ModifiedFinding given the type and `UnmarshalJSON` functions of struct fields +func (m *ModifiedFinding) UnmarshalJSON(data []byte) error { + type Alias ModifiedFinding + aux := &struct { + Finding json.RawMessage `json:"Finding"` + *Alias + }{ + Alias: (*Alias)(m), + } + + if err := json.Unmarshal(data, &aux); err != nil { + return err + } + + // Select struct by m.Type to avoid errors with Unmarshal + var err error + switch m.Type { + case FindingTypeVulnerability: + m.Finding, err = unmarshalFinding[DetectedVulnerability](aux.Finding) + case FindingTypeMisconfiguration: + m.Finding, err = unmarshalFinding[DetectedMisconfiguration](aux.Finding) + case FindingTypeSecret: + m.Finding, err = unmarshalFinding[DetectedSecret](aux.Finding) + case FindingTypeLicense: + m.Finding, err = unmarshalFinding[DetectedLicense](aux.Finding) + default: + return xerrors.Errorf("invalid Finding type: %s", m.Type) + } + + if err != nil { + return xerrors.Errorf("unable to unmarshal %q type: %w", m.Type, err) + } + return nil +} + +func unmarshalFinding[T finding](data []byte) (T, error) { + var f T + err := json.Unmarshal(data, &f) + return f, err +} From d589856fdd38f2e9dfb4bbde3759cc3b57202146 Mon Sep 17 00:00:00 2001 From: Squiddim <82903357+Squiddim@users.noreply.github.com> Date: Wed, 11 Sep 2024 08:32:57 +0200 Subject: [PATCH 077/183] docs(oci): Add a note About the expected Media Type for the Trivy-DB OCI Artifact (#7449) --- docs/docs/configuration/db.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/docs/configuration/db.md b/docs/docs/configuration/db.md index f6525fb61568..5fa4046668a9 100644 --- a/docs/docs/configuration/db.md +++ b/docs/docs/configuration/db.md @@ -53,12 +53,16 @@ $ trivy image --download-db-only ``` $ trivy image --db-repository registry.gitlab.com/gitlab-org/security-products/dependencies/trivy-db ``` - !!!note Trivy automatically adds the `trivy-db` schema version as a tag if the tag is not used: `trivy-db-registry:latest` => `trivy-db-registry:latest`, but `trivy-db-registry` => `trivy-db-registry:2`. +!!!note + Trivy expects the OCI Artifacts to have a Specific media type: + - Vulnerability DB `application/vnd.aquasec.trivy.db.layer.v1.tar+gzip` + - Java DB `application/vnd.aquasec.trivy.javadb.layer.v1.tar+gzip` + ## Java Index Database The same options are also available for the Java index DB, which is used for scanning Java applications. Skipping an update can be done by using the `--skip-java-db-update` option, while `--download-java-db-only` can be used to only download the Java index DB. @@ -84,4 +88,4 @@ $ trivy image --java-db-repository registry.gitlab.com/gitlab-org/security-produ $ trivy clean --vuln-db --java-db 2024-06-24T11:42:31+06:00 INFO Removing vulnerability database... 2024-06-24T11:42:31+06:00 INFO Removing Java database... -``` \ No newline at end of file +``` From 6472e3c9da2a8e7ba41598a45c80df8f18e57d4c Mon Sep 17 00:00:00 2001 From: Pierre Baumard Date: Wed, 11 Sep 2024 08:47:50 +0200 Subject: [PATCH 078/183] feat(license): improve license normalization (#7131) Signed-off-by: knqyf263 Co-authored-by: DmitriyLewen Co-authored-by: knqyf263 --- .../alpine-39-high-critical.json.golden | 2 +- integration/testdata/alpine-39.json.golden | 2 +- .../testdata/alpine-distroless.json.golden | 2 +- ...fluentd-multiple-lockfiles.cdx.json.golden | 836 +++++++++++++----- .../testdata/license-cyclonedx.json.golden | 4 +- .../testdata/ubi-7-comprehensive.json.golden | 2 +- .../python/packaging/packaging_test.go | 10 +- pkg/fanal/analyzer/pkg/apk/apk.go | 22 +- pkg/fanal/analyzer/pkg/apk/apk_test.go | 21 +- pkg/fanal/analyzer/pkg/dpkg/copyright_test.go | 9 +- pkg/fanal/artifact/image/image_test.go | 25 +- .../goldens/packages/alpine-310.json.golden | 28 +- .../goldens/packages/vulnimage.json.golden | 76 +- pkg/flag/license_flags.go | 14 +- pkg/licensing/{ => expression}/category.go | 24 +- pkg/licensing/expression/expression.go | 12 +- pkg/licensing/expression/expression_test.go | 2 +- pkg/licensing/expression/parser.go.y | 6 +- pkg/licensing/expression/parser_gen.go | 6 +- pkg/licensing/expression/parser_test.go | 34 +- pkg/licensing/expression/types.go | 40 +- pkg/licensing/normalize.go | 786 ++++++++++++---- pkg/licensing/normalize_private_test.go | 18 + pkg/licensing/normalize_test.go | 239 +++++ pkg/licensing/scanner.go | 3 +- pkg/licensing/scanner_test.go | 17 +- pkg/sbom/spdx/marshal.go | 2 +- pkg/sbom/spdx/marshal_test.go | 6 +- 28 files changed, 1702 insertions(+), 546 deletions(-) rename pkg/licensing/{ => expression}/category.go (96%) create mode 100644 pkg/licensing/normalize_private_test.go diff --git a/integration/testdata/alpine-39-high-critical.json.golden b/integration/testdata/alpine-39-high-critical.json.golden index 408cd11d4988..26931273fd01 100644 --- a/integration/testdata/alpine-39-high-critical.json.golden +++ b/integration/testdata/alpine-39-high-critical.json.golden @@ -106,7 +106,7 @@ "PkgName": "musl-utils", "PkgIdentifier": { "PURL": "pkg:apk/alpine/musl-utils@1.1.20-r4?arch=x86_64\u0026distro=3.9.4", - "UID": "8c341199f4077fc8" + "UID": "a35dd6cab4aabdf1" }, "InstalledVersion": "1.1.20-r4", "FixedVersion": "1.1.20-r5", diff --git a/integration/testdata/alpine-39.json.golden b/integration/testdata/alpine-39.json.golden index 3e1089f3e7cb..35d3e2a5c1b7 100644 --- a/integration/testdata/alpine-39.json.golden +++ b/integration/testdata/alpine-39.json.golden @@ -418,7 +418,7 @@ "PkgName": "musl-utils", "PkgIdentifier": { "PURL": "pkg:apk/alpine/musl-utils@1.1.20-r4?arch=x86_64\u0026distro=3.9.4", - "UID": "8c341199f4077fc8" + "UID": "a35dd6cab4aabdf1" }, "InstalledVersion": "1.1.20-r4", "FixedVersion": "1.1.20-r5", diff --git a/integration/testdata/alpine-distroless.json.golden b/integration/testdata/alpine-distroless.json.golden index 4ba010f0eea0..da03075d0cd5 100644 --- a/integration/testdata/alpine-distroless.json.golden +++ b/integration/testdata/alpine-distroless.json.golden @@ -55,7 +55,7 @@ "PkgName": "git", "PkgIdentifier": { "PURL": "pkg:apk/alpine/git@2.35.1-r2?arch=x86_64\u0026distro=3.16", - "UID": "d44ac4666246b919" + "UID": "2999d822f6cae40c" }, "InstalledVersion": "2.35.1-r2", "FixedVersion": "2.35.2-r0", diff --git a/integration/testdata/fluentd-multiple-lockfiles.cdx.json.golden b/integration/testdata/fluentd-multiple-lockfiles.cdx.json.golden index cc442e7d881d..65fc78e6c66f 100644 --- a/integration/testdata/fluentd-multiple-lockfiles.cdx.json.golden +++ b/integration/testdata/fluentd-multiple-lockfiles.cdx.json.golden @@ -81,7 +81,7 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -121,7 +121,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } } ], @@ -161,7 +166,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -201,7 +206,7 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { @@ -246,7 +251,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } } ], @@ -290,7 +295,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -320,22 +330,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-or-later" + } + }, + { + "license": { + "name": "LGPL-3.0-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-only" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.0-only" } }, { "license": { - "name": "GPL-3.0" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-only" } } ], @@ -379,7 +409,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -424,7 +459,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } } ], @@ -468,7 +503,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -552,7 +587,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -592,7 +627,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -632,12 +667,12 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } }, { "license": { - "name": "GFDL" + "name": "GFDL-1.3-or-later" } } ], @@ -685,7 +720,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -740,12 +780,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-only" } } ], @@ -789,7 +829,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -819,22 +864,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-only" + } + }, + { + "license": { + "name": "LGPL-2.0-only" + } + }, + { + "license": { + "name": "LGPL-2.1-only" + } + }, + { + "license": { + "name": "LGPL-3.0-only" } } ], @@ -878,12 +943,12 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "GFDL-1.3" + "name": "GFDL-1.3-only" } } ], @@ -927,27 +992,32 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-only" } }, { "license": { - "name": "GFDL-1.2" + "name": "GFDL-1.2-only" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "Artistic" + "name": "Artistic-2.0" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.0-or-later" } } ], @@ -991,7 +1061,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" } }, { @@ -1001,12 +1071,12 @@ }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-or-later" } }, { "license": { - "name": "Expat" + "name": "MIT" } }, { @@ -1016,7 +1086,7 @@ }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-or-later" } }, { @@ -1033,6 +1103,21 @@ "license": { "name": "CC0-1.0" } + }, + { + "license": { + "name": "GPL-3.0-only" + } + }, + { + "license": { + "name": "LGPL-3.0-only" + } + }, + { + "license": { + "name": "LGPL-2.1-only" + } } ], "purl": "pkg:deb/debian/gpgv@2.2.12-1%2Bdeb10u1?arch=amd64&distro=debian-10.2", @@ -1075,7 +1160,12 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-only" } } ], @@ -1119,7 +1209,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -1163,7 +1253,7 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -1208,7 +1298,12 @@ }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } } ], @@ -1248,17 +1343,22 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } } ], @@ -1302,7 +1402,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } } ], @@ -1342,17 +1447,22 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" } }, { "license": { - "name": "LGPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-only" } } ], @@ -1400,17 +1510,17 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "GPL-1.0" + "name": "GPL-1.0-only" } } ], @@ -1458,17 +1568,17 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "GPL-1.0" + "name": "GPL-1.0-only" } } ], @@ -1516,7 +1626,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -1546,22 +1661,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-only" + } + }, + { + "license": { + "name": "LGPL-2.0-only" + } + }, + { + "license": { + "name": "LGPL-2.1-only" + } + }, + { + "license": { + "name": "LGPL-3.0-only" } } ], @@ -1605,12 +1740,12 @@ "licenses": [ { "license": { - "name": "BSD-variant" + "name": "BSD-3-Clause" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -1654,12 +1789,12 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -1703,12 +1838,12 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -1752,17 +1887,17 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } } ], @@ -1913,12 +2048,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-only" } } ], @@ -1962,7 +2097,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -1992,22 +2132,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-3.0-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.0-only" + } + }, + { + "license": { + "name": "LGPL-2.1-only" + } + }, + { + "license": { + "name": "LGPL-3.0-only" } } ], @@ -2051,7 +2211,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -2132,12 +2292,12 @@ "licenses": [ { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -2181,17 +2341,27 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-or-later" } }, { "license": { - "name": "GPL-2.0" + "name": "GFDL-1.3-no-invariants-or-later" } }, { "license": { - "name": "GFDL-NIV-1.3+" + "name": "GPL-3.0-only" + } + }, + { + "license": { + "name": "GPL-2.0-only" } } ], @@ -2235,17 +2405,27 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GFDL-1.3-no-invariants-or-later" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "GFDL-NIV-1.3+" + "name": "GPL-2.0-only" } } ], @@ -2289,17 +2469,22 @@ "licenses": [ { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-only" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -2347,43 +2532,58 @@ "licenses": [ { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "GPL-3.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "GFDL-1.3" + "name": "LGPL-3.0-only" } }, { "license": { - "name": "CC0" + "name": "GPL-2.0-or-later" } }, { "license": { - "name": "The MIT License" + "name": "GPL-3.0-only" } }, { "license": { - "name": "LGPLv3+" + "name": "GFDL-1.3-only" } }, { "license": { - "name": "GPL-2.0" + "name": "CC0-1.0" + } + }, + { + "license": { + "name": "MIT" + } + }, + { + "license": { + "name": "LGPL-3.0-or-later" } }, { "license": { "name": "Apache-2.0" } + }, + { + "license": { + "name": "GPL-3.0-or-later" + } } ], "purl": "pkg:deb/debian/libgnutls30@3.6.7-4?arch=amd64&distro=debian-10.2", @@ -2426,7 +2626,7 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-or-later" } }, { @@ -2441,7 +2641,17 @@ }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-only" + } + }, + { + "license": { + "name": "GPL-3.0-only" } } ], @@ -2522,23 +2732,38 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-or-later" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" } }, { "license": { "name": "Unicode" } + }, + { + "license": { + "name": "GPL-3.0-only" + } + }, + { + "license": { + "name": "GPL-2.0-only" + } + }, + { + "license": { + "name": "LGPL-3.0-only" + } } ], "purl": "pkg:deb/debian/libidn2-0@2.0.5-1?arch=amd64&distro=debian-10.2", @@ -2596,7 +2821,7 @@ }, { "license": { - "name": "Expat" + "name": "MIT" } }, { @@ -2655,7 +2880,12 @@ }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } } ], @@ -2709,12 +2939,12 @@ }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-or-later" } }, { @@ -2732,6 +2962,11 @@ "name": "permissive-nowarranty" } }, + { + "license": { + "name": "GPL-2.0-only" + } + }, { "license": { "name": "none" @@ -2744,7 +2979,12 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-only" + } + }, + { + "license": { + "name": "LGPL-2.1-only" } }, { @@ -2759,7 +2999,7 @@ }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } } ], @@ -2803,7 +3043,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -2833,22 +3078,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-3.0-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.0-only" + } + }, + { + "license": { + "name": "LGPL-2.1-only" + } + }, + { + "license": { + "name": "LGPL-3.0-only" } } ], @@ -2966,47 +3231,47 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-or-later" } }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "other" + "name": "LGPL-2.0-only" } }, { "license": { - "name": "GPL-2.0" + "name": "other" } }, { "license": { - "name": "GPL-2.0-with-autoconf-exception" + "name": "GPL-2.0-or-later" } }, { "license": { - "name": "public-domain" + "name": "GPL-2.0-with-autoconf-exception+" } }, { "license": { - "name": "GAP" + "name": "public-domain" } }, { "license": { - "name": "LGPL-3.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "GPL-3.0" + "name": "GAP" } } ], @@ -3114,7 +3379,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -3158,7 +3423,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -3202,7 +3467,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -3246,7 +3511,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -3331,12 +3596,12 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "GFDL" + "name": "GFDL-1.3-or-later" } } ], @@ -3390,12 +3655,12 @@ }, { "license": { - "name": "Expat" + "name": "MIT" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" } }, { @@ -3440,27 +3705,27 @@ }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "Artistic" + "name": "Artistic-2.0" } }, { "license": { - "name": "zlib/libpng" + "name": "zlib-acknowledgement" } }, { "license": { - "name": "GPL-1.0" + "name": "GPL-1.0-or-later" } }, { "license": { - "name": "CC0" + "name": "CC0-1.0" } }, { @@ -3472,6 +3737,16 @@ "license": { "name": "Permissive" } + }, + { + "license": { + "name": "GPL-1.0-only" + } + }, + { + "license": { + "name": "GPL-3.0-only" + } } ], "purl": "pkg:deb/debian/libruby2.5@2.5.5-3%2Bdeb10u1?arch=amd64&distro=debian-10.2", @@ -3514,7 +3789,7 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } } ], @@ -3558,12 +3833,12 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -3607,12 +3882,12 @@ "licenses": [ { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -3656,12 +3931,12 @@ "licenses": [ { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -3705,12 +3980,12 @@ "licenses": [ { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -3754,7 +4029,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -3784,22 +4064,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "GPL-3.0-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "LGPL-3.0-or-later" } }, { "license": { - "name": "LGPL-3.0" + "name": "GPL-3.0-only" + } + }, + { + "license": { + "name": "LGPL-2.0-only" + } + }, + { + "license": { + "name": "LGPL-2.1-only" + } + }, + { + "license": { + "name": "LGPL-3.0-only" } } ], @@ -3954,7 +4254,7 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-or-later" } }, { @@ -3964,18 +4264,28 @@ }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" + } + }, + { + "license": { + "name": "GPL-2.0-or-later" } }, { "license": { - "name": "Expat" + "name": "MIT" } }, { "license": { "name": "public-domain" } + }, + { + "license": { + "name": "LGPL-2.1-only" + } } ], "purl": "pkg:deb/debian/libsystemd0@241-7~deb10u2?arch=amd64&distro=debian-10.2", @@ -4018,22 +4328,22 @@ "licenses": [ { "license": { - "name": "LGPL-3.0" + "name": "LGPL-2.0-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "GFDL-1.3" + "name": "GFDL-1.3-only" } } ], @@ -4114,7 +4424,7 @@ "licenses": [ { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-or-later" } }, { @@ -4124,18 +4434,28 @@ }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" + } + }, + { + "license": { + "name": "GPL-2.0-or-later" } }, { "license": { - "name": "Expat" + "name": "MIT" } }, { "license": { "name": "public-domain" } + }, + { + "license": { + "name": "LGPL-2.1-only" + } } ], "purl": "pkg:deb/debian/libudev1@241-7~deb10u2?arch=amd64&distro=debian-10.2", @@ -4178,12 +4498,12 @@ "licenses": [ { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-or-later" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" } }, { @@ -4198,12 +4518,12 @@ }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" } }, { "license": { - "name": "GFDL-1.2+" + "name": "GFDL-1.2-or-later" } }, { @@ -4213,7 +4533,22 @@ }, { "license": { - "name": "GFDL-1.2" + "name": "LGPL-3.0-only" + } + }, + { + "license": { + "name": "GPL-3.0-only" + } + }, + { + "license": { + "name": "GPL-2.0-only" + } + }, + { + "license": { + "name": "GFDL-1.2-only" } } ], @@ -4257,7 +4592,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -4287,22 +4627,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-or-later" + } + }, + { + "license": { + "name": "LGPL-3.0-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-only" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.0-only" } }, { "license": { - "name": "GPL-3.0" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-only" } } ], @@ -4346,7 +4706,7 @@ "licenses": [ { "license": { - "name": "Expat" + "name": "MIT" } }, { @@ -4400,7 +4760,7 @@ }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { @@ -4410,7 +4770,12 @@ }, { "license": { - "name": "Expat" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "MIT" } } ], @@ -4454,7 +4819,7 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -4502,7 +4867,7 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -4546,7 +4911,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -4576,22 +4946,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-or-later" + } + }, + { + "license": { + "name": "LGPL-3.0-or-later" + } + }, + { + "license": { + "name": "GPL-3.0-only" } }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.0-only" } }, { "license": { - "name": "GPL-3.0" + "name": "LGPL-2.1-only" } }, { "license": { - "name": "LGPL-3.0" + "name": "LGPL-3.0-only" } } ], @@ -4746,7 +5136,7 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -4831,7 +5221,7 @@ "licenses": [ { "license": { - "name": "Expat" + "name": "MIT" } } ], @@ -4875,12 +5265,12 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "GFDL" + "name": "GFDL-1.3-or-later" } } ], @@ -4924,7 +5314,7 @@ "licenses": [ { "license": { - "name": "Expat" + "name": "MIT" } } ], @@ -4968,7 +5358,7 @@ "licenses": [ { "license": { - "name": "Expat" + "name": "MIT" } } ], @@ -5120,7 +5510,7 @@ }, { "license": { - "name": "LGPL-2.1" + "name": "LGPL-2.1-only" } } ], @@ -5218,12 +5608,12 @@ }, { "license": { - "name": "Expat" + "name": "MIT" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-or-later" } }, { @@ -5268,27 +5658,27 @@ }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } }, { "license": { - "name": "Artistic" + "name": "Artistic-2.0" } }, { "license": { - "name": "zlib/libpng" + "name": "zlib-acknowledgement" } }, { "license": { - "name": "GPL-1.0" + "name": "GPL-1.0-or-later" } }, { "license": { - "name": "CC0" + "name": "CC0-1.0" } }, { @@ -5300,6 +5690,16 @@ "license": { "name": "Permissive" } + }, + { + "license": { + "name": "GPL-1.0-only" + } + }, + { + "license": { + "name": "GPL-3.0-only" + } } ], "purl": "pkg:deb/debian/ruby2.5@2.5.5-3%2Bdeb10u1?arch=amd64&distro=debian-10.2", @@ -5342,12 +5742,12 @@ "licenses": [ { "license": { - "name": "RubyLicense" + "name": "Ruby" } }, { "license": { - "name": "GPL-3.0" + "name": "GPL-2.0-or-later" } } ], @@ -5391,7 +5791,7 @@ "licenses": [ { "license": { - "name": "Expat" + "name": "MIT" } } ], @@ -5431,7 +5831,7 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } } ], @@ -5475,7 +5875,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } } ], @@ -5519,12 +5924,12 @@ "licenses": [ { "license": { - "name": "GPL-3.0" + "name": "GPL-3.0-only" } }, { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-only" } } ], @@ -5605,7 +6010,12 @@ "licenses": [ { "license": { - "name": "GPL-2.0" + "name": "GPL-2.0-or-later" + } + }, + { + "license": { + "name": "GPL-2.0-only" } }, { @@ -5635,22 +6045,42 @@ }, { "license": { - "name": "LGPL-2.0" + "name": "LGPL-2.0-or-later" + } + }, + { + "license": { + "name": "LGPL-2.1-or-later" } }, { "license": { - "name": "LGPL-2.1" + "name": "GPL-3.0-or-later" } }, { "license": { - "name": "GPL-3.0" + "name": "LGPL-3.0-or-later" } }, { "license": { - "name": "LGPL-3.0" + "name": "GPL-3.0-only" + } + }, + { + "license": { + "name": "LGPL-2.0-only" + } + }, + { + "license": { + "name": "LGPL-2.1-only" + } + }, + { + "license": { + "name": "LGPL-3.0-only" } } ], @@ -6289,7 +6719,7 @@ "licenses": [ { "license": { - "name": "Apache License (2.0)" + "name": "Apache-2.0" } } ], @@ -7370,7 +7800,7 @@ "licenses": [ { "license": { - "name": "2-clause BSDL" + "name": "BSD-2-Clause" } } ], diff --git a/integration/testdata/license-cyclonedx.json.golden b/integration/testdata/license-cyclonedx.json.golden index cf69da9756ed..95f8acd896b1 100644 --- a/integration/testdata/license-cyclonedx.json.golden +++ b/integration/testdata/license-cyclonedx.json.golden @@ -47,8 +47,8 @@ "Link": "" }, { - "Severity": "UNKNOWN", - "Category": "unknown", + "Severity": "LOW", + "Category": "notice", "PkgName": "org.slf4j:slf4j-api", "FilePath": "", "Name": "MIT License", diff --git a/integration/testdata/ubi-7-comprehensive.json.golden b/integration/testdata/ubi-7-comprehensive.json.golden index 6df4b8241456..b500dc5d4bc5 100644 --- a/integration/testdata/ubi-7-comprehensive.json.golden +++ b/integration/testdata/ubi-7-comprehensive.json.golden @@ -147,7 +147,7 @@ "PkgPath": "usr/lib/python2.7/site-packages/setuptools-0.9.8-py2.7.egg-info/PKG-INFO", "PkgIdentifier": { "PURL": "pkg:pypi/setuptools@0.9.8", - "UID": "3f4c89bf681c1d7a" + "UID": "13d32ebdc7bda1b4" }, "InstalledVersion": "0.9.8", "FixedVersion": "65.5.1", diff --git a/pkg/fanal/analyzer/language/python/packaging/packaging_test.go b/pkg/fanal/analyzer/language/python/packaging/packaging_test.go index c3a89ad0cd19..960a92dfec2b 100644 --- a/pkg/fanal/analyzer/language/python/packaging/packaging_test.go +++ b/pkg/fanal/analyzer/language/python/packaging/packaging_test.go @@ -33,7 +33,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { Name: "kitchen", Version: "1.2.6", Licenses: []string{ - "GNU Library or Lesser General Public License (LGPL)", + "LGPL-2.1-only", }, FilePath: "kitchen-1.2.6-py2.7.egg", }, @@ -55,7 +55,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { { Name: "distlib", Version: "0.3.1", - Licenses: []string{"Python license"}, + Licenses: []string{"Python-2.0"}, FilePath: "distlib-0.3.1.egg-info/PKG-INFO", Digest: "sha1:d9d89d8ed3b2b683767c96814c9c5d3e57ef2e1b", }, @@ -76,7 +76,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { { Name: "setuptools", Version: "51.3.3", - Licenses: []string{"MIT License"}, + Licenses: []string{"MIT"}, FilePath: "setuptools-51.3.3.egg-info/PKG-INFO", }, }, @@ -96,7 +96,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { { Name: "setuptools", Version: "51.3.3", - Licenses: []string{"MIT License"}, + Licenses: []string{"MIT"}, FilePath: "setuptools-51.3.3.dist-info/METADATA", }, }, @@ -116,7 +116,7 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { { Name: "distlib", Version: "0.3.1", - Licenses: []string{"Python license"}, + Licenses: []string{"Python-2.0"}, FilePath: "distlib-0.3.1.dist-info/METADATA", }, }, diff --git a/pkg/fanal/analyzer/pkg/apk/apk.go b/pkg/fanal/analyzer/pkg/apk/apk.go index 9ce13e4b013d..962398600fc5 100644 --- a/pkg/fanal/analyzer/pkg/apk/apk.go +++ b/pkg/fanal/analyzer/pkg/apk/apk.go @@ -142,26 +142,8 @@ func (a alpinePkgAnalyzer) trimRequirement(s string) string { } func (a alpinePkgAnalyzer) parseLicense(line string) []string { - line = line[2:] // Remove "L:" - if line == "" { - return nil - } - var licenses []string - // e.g. MPL 2.0 GPL2+ => {"MPL2.0", "GPL2+"} - for i, s := range strings.Fields(line) { - s = strings.Trim(s, "()") - switch { - case s == "": - continue - case s == "AND" || s == "OR": - continue - case i > 0 && (s == "1.0" || s == "2.0" || s == "3.0"): - licenses[i-1] = licensing.Normalize(licenses[i-1] + s) - default: - licenses = append(licenses, licensing.Normalize(s)) - } - } - return licenses + // Remove "L:" before split + return licensing.LaxSplitLicenses(line[2:]) } func (a alpinePkgAnalyzer) parseProvides(line, pkgID string, provides map[string]string) { diff --git a/pkg/fanal/analyzer/pkg/apk/apk_test.go b/pkg/fanal/analyzer/pkg/apk/apk_test.go index 08a5d302d324..0491ed57c0d2 100644 --- a/pkg/fanal/analyzer/pkg/apk/apk_test.go +++ b/pkg/fanal/analyzer/pkg/apk/apk_test.go @@ -33,7 +33,7 @@ var pkgs = []types.Package{ Version: "1.24.2-r9", SrcName: "busybox", SrcVersion: "1.24.2-r9", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, DependsOn: []string{"musl@1.1.14-r10"}, Arch: "x86_64", Digest: "sha1:ca124719267cd0bedc2f4cb850a286ac13f0ad44", @@ -51,7 +51,7 @@ var pkgs = []types.Package{ Version: "3.0.3-r0", SrcName: "alpine-baselayout", SrcVersion: "3.0.3-r0", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, DependsOn: []string{ "busybox@1.24.2-r9", "musl@1.1.14-r10", @@ -92,7 +92,7 @@ var pkgs = []types.Package{ Version: "1.1-r0", SrcName: "alpine-keys", SrcVersion: "1.1-r0", - Licenses: []string{"GPL-3.0"}, + Licenses: []string{"GPL-2.0-or-later"}, Arch: "x86_64", Digest: "sha1:4def7ffaee6aeba700c1d62570326f75cbb8fa25", InstalledFiles: []string{ @@ -124,7 +124,7 @@ var pkgs = []types.Package{ Version: "1.0.2h-r1", SrcName: "openssl", SrcVersion: "1.0.2h-r1", - Licenses: []string{"openssl"}, + Licenses: []string{"OpenSSL"}, DependsOn: []string{ "musl@1.1.14-r10", "zlib@1.2.8-r2", @@ -155,7 +155,7 @@ var pkgs = []types.Package{ Version: "1.0.2h-r1", SrcName: "openssl", SrcVersion: "1.0.2h-r1", - Licenses: []string{"openssl"}, + Licenses: []string{"OpenSSL"}, Digest: "sha1:7120f337e93b2b4c44e0f5f31a15b60dc678ca14", DependsOn: []string{ "libcrypto1.0@1.0.2h-r1", @@ -173,7 +173,7 @@ var pkgs = []types.Package{ Version: "2.6.7-r0", SrcName: "apk-tools", SrcVersion: "2.6.7-r0", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, Digest: "sha1:0990c0acd62b4175818c3a4cc60ed11f14e23bd8", DependsOn: []string{ "libcrypto1.0@1.0.2h-r1", @@ -192,7 +192,7 @@ var pkgs = []types.Package{ Version: "1.1.6-r0", SrcName: "pax-utils", SrcVersion: "1.1.6-r0", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, Digest: "sha1:f9bab817c5ad93e92a6218bc0f7596b657c02d90", DependsOn: []string{"musl@1.1.14-r10"}, Arch: "x86_64", @@ -209,7 +209,7 @@ var pkgs = []types.Package{ Licenses: []string{ "MIT", "BSD-3-Clause", - "GPL-2.0", + "GPL-2.0-or-later", }, Digest: "sha1:608aa1dd39eff7bc6615d3e5e33383750f8f5ecc", DependsOn: []string{ @@ -231,7 +231,7 @@ var pkgs = []types.Package{ Version: "0.7-r0", SrcName: "libc-dev", SrcVersion: "0.7-r0", - Licenses: []string{"GPL-3.0"}, + Licenses: []string{"GPL-2.0-or-later"}, Digest: "sha1:9055bc7afd76cf2672198042f72fc4a5ed4fa961", DependsOn: []string{"musl-utils@1.1.14-r10"}, Arch: "x86_64", @@ -255,7 +255,6 @@ var pkgs = []types.Package{ "usr/share/aclocal/pkg.m4", }, }, - { ID: "sqlite-libs@3.26.0-r3", Name: "sqlite-libs", @@ -271,7 +270,6 @@ var pkgs = []types.Package{ "usr/lib/libsqlite3.so.0.8.6", }, }, - { ID: "test@2.9.11_pre20061021-r2", Name: "test", @@ -292,7 +290,6 @@ var pkgs = []types.Package{ "usr/include/sqlite3.h", }, }, - { ID: "ada-libs@2.7.4-r0", Name: "ada-libs", diff --git a/pkg/fanal/analyzer/pkg/dpkg/copyright_test.go b/pkg/fanal/analyzer/pkg/dpkg/copyright_test.go index d44899e4362e..2c6c1e2c50ee 100644 --- a/pkg/fanal/analyzer/pkg/dpkg/copyright_test.go +++ b/pkg/fanal/analyzer/pkg/dpkg/copyright_test.go @@ -29,8 +29,8 @@ func Test_dpkgLicenseAnalyzer_Analyze(t *testing.T) { Type: types.LicenseTypeDpkg, FilePath: "usr/share/doc/zlib1g/copyright", Findings: []types.LicenseFinding{ - {Name: "GPL-1.0"}, - {Name: "Artistic"}, + {Name: "GPL-1.0-or-later"}, + {Name: "Artistic-2.0"}, {Name: "BSD-4-clause-POWERDOG"}, {Name: "Zlib"}, }, @@ -49,7 +49,7 @@ func Test_dpkgLicenseAnalyzer_Analyze(t *testing.T) { Type: types.LicenseTypeDpkg, FilePath: "usr/share/doc/adduser/copyright", Findings: []types.LicenseFinding{ - {Name: "GPL-2.0"}, + {Name: "GPL-2.0-only"}, }, PkgName: "adduser", }, @@ -66,7 +66,8 @@ func Test_dpkgLicenseAnalyzer_Analyze(t *testing.T) { Type: types.LicenseTypeDpkg, FilePath: "usr/share/doc/apt/copyright", Findings: []types.LicenseFinding{ - {Name: "GPL-2.0"}, + {Name: "GPL-2.0-or-later"}, + {Name: "GPL-2.0-only"}, }, PkgName: "apt", }, diff --git a/pkg/fanal/artifact/image/image_test.go b/pkg/fanal/artifact/image/image_test.go index a69ab03708e2..f7e80e3cf578 100644 --- a/pkg/fanal/artifact/image/image_test.go +++ b/pkg/fanal/artifact/image/image_test.go @@ -40,7 +40,7 @@ func TestArtifact_Inspect(t *testing.T) { Version: "3.2.0-r3", SrcName: "alpine-baselayout", SrcVersion: "3.2.0-r3", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, Digest: "sha1:8f373f5b329c3aaf136eb30c63a387661ee0f3d0", DependsOn: []string{ "busybox@1.31.1-r9", @@ -113,7 +113,7 @@ func TestArtifact_Inspect(t *testing.T) { Version: "2.10.4-r3", SrcName: "apk-tools", SrcVersion: "2.10.4-r3", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, Digest: "sha1:b15ad0c90e4493dfdc948d6b90a8e020da8936ef", DependsOn: []string{ "libcrypto1.1@1.1.1d-r3", @@ -132,7 +132,7 @@ func TestArtifact_Inspect(t *testing.T) { Version: "1.31.1-r9", SrcName: "busybox", SrcVersion: "1.31.1-r9", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, Digest: "sha1:a457703d71654811ea28d8d27a5cfc49ece27b34", DependsOn: []string{ "musl@1.1.24-r2", @@ -156,7 +156,7 @@ func TestArtifact_Inspect(t *testing.T) { SrcVersion: "20191127-r1", Licenses: []string{ "MPL-2.0", - "GPL-2.0", + "GPL-2.0-or-later", }, Arch: "x86_64", Digest: "sha1:3aeb8a90d7179d2a187782e980a964494e08c5fb", @@ -265,7 +265,7 @@ func TestArtifact_Inspect(t *testing.T) { Licenses: []string{ "MIT", "BSD-3-Clause", - "GPL-2.0", + "GPL-2.0-or-later", }, Digest: "sha1:6d3b45e79dbab444ca7cbfa59e2833203be6fb6a", DependsOn: []string{ @@ -287,7 +287,7 @@ func TestArtifact_Inspect(t *testing.T) { Version: "1.2.4-r0", SrcName: "pax-utils", SrcVersion: "1.2.4-r0", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, Digest: "sha1:d6147beb32bff803b5d9f83a3bec7ab319087185", DependsOn: []string{ "musl@1.1.24-r2", @@ -303,7 +303,7 @@ func TestArtifact_Inspect(t *testing.T) { Version: "1.31.1-r9", SrcName: "busybox", SrcVersion: "1.31.1-r9", - Licenses: []string{"GPL-2.0"}, + Licenses: []string{"GPL-2.0-only"}, Digest: "sha1:3b685152af320120ae8941c740d3376b54e43c10", DependsOn: []string{ "libtls-standalone@2.9.1-r0", @@ -567,7 +567,7 @@ func TestArtifact_Inspect(t *testing.T) { Type: types.LicenseTypeDpkg, FilePath: "usr/share/doc/base-files/copyright", Findings: []types.LicenseFinding{ - {Name: "GPL-3.0"}, + {Name: "GPL-2.0-or-later"}, }, PkgName: "base-files", }, @@ -575,7 +575,8 @@ func TestArtifact_Inspect(t *testing.T) { Type: types.LicenseTypeDpkg, FilePath: "usr/share/doc/ca-certificates/copyright", Findings: []types.LicenseFinding{ - {Name: "GPL-2.0"}, + {Name: "GPL-2.0-or-later"}, + {Name: "GPL-2.0-only"}, {Name: "MPL-2.0"}, }, PkgName: "ca-certificates", @@ -584,7 +585,7 @@ func TestArtifact_Inspect(t *testing.T) { Type: types.LicenseTypeDpkg, FilePath: "usr/share/doc/netbase/copyright", Findings: []types.LicenseFinding{ - {Name: "GPL-2.0"}, + {Name: "GPL-2.0-only"}, }, PkgName: "netbase", }, @@ -655,8 +656,8 @@ func TestArtifact_Inspect(t *testing.T) { Type: types.LicenseTypeDpkg, FilePath: "usr/share/doc/libc6/copyright", Findings: []types.LicenseFinding{ - {Name: "LGPL-2.1"}, - {Name: "GPL-2.0"}, + {Name: "LGPL-2.1-only"}, + {Name: "GPL-2.0-only"}, }, PkgName: "libc6", }, diff --git a/pkg/fanal/test/integration/testdata/goldens/packages/alpine-310.json.golden b/pkg/fanal/test/integration/testdata/goldens/packages/alpine-310.json.golden index 32513f398b9f..17d3941a620e 100644 --- a/pkg/fanal/test/integration/testdata/goldens/packages/alpine-310.json.golden +++ b/pkg/fanal/test/integration/testdata/goldens/packages/alpine-310.json.golden @@ -4,14 +4,14 @@ "Name": "alpine-baselayout", "Identifier": { "PURL": "pkg:apk/alpine/alpine-baselayout@3.1.2-r0?arch=x86_64\u0026distro=3.10.2", - "UID": "3ca42aecf84bfa9" + "UID": "2d19d30821e01d2c" }, "Version": "3.1.2-r0", "Arch": "x86_64", "SrcName": "alpine-baselayout", "SrcVersion": "3.1.2-r0", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "busybox@1.30.1-r2", @@ -95,14 +95,14 @@ "Name": "apk-tools", "Identifier": { "PURL": "pkg:apk/alpine/apk-tools@2.10.4-r2?arch=x86_64\u0026distro=3.10.2", - "UID": "fa7ca40ce236844e" + "UID": "e967fd57e4033819" }, "Version": "2.10.4-r2", "Arch": "x86_64", "SrcName": "apk-tools", "SrcVersion": "2.10.4-r2", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "libcrypto1.1@1.1.1c-r0", @@ -124,14 +124,14 @@ "Name": "busybox", "Identifier": { "PURL": "pkg:apk/alpine/busybox@1.30.1-r2?arch=x86_64\u0026distro=3.10.2", - "UID": "1941d9acbebe7f44" + "UID": "f3002aff2b6b251d" }, "Version": "1.30.1-r2", "Arch": "x86_64", "SrcName": "busybox", "SrcVersion": "1.30.1-r2", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "musl@1.1.22-r3" @@ -155,7 +155,7 @@ "Name": "ca-certificates-cacert", "Identifier": { "PURL": "pkg:apk/alpine/ca-certificates-cacert@20190108-r0?arch=x86_64\u0026distro=3.10.2", - "UID": "9b1db91ad655d76c" + "UID": "1d3125ae903daa3c" }, "Version": "20190108-r0", "Arch": "x86_64", @@ -163,7 +163,7 @@ "SrcVersion": "20190108-r0", "Licenses": [ "MPL-2.0", - "GPL-2.0" + "GPL-2.0-or-later" ], "Layer": { "Digest": "sha256:9d48c3bd43c520dc2784e868a780e976b207cbf493eaff8c6596eb871cbd9609", @@ -321,7 +321,7 @@ "Name": "musl-utils", "Identifier": { "PURL": "pkg:apk/alpine/musl-utils@1.1.22-r3?arch=x86_64\u0026distro=3.10.2", - "UID": "40edadcb74964baa" + "UID": "112ed00987ba9c7d" }, "Version": "1.1.22-r3", "Arch": "x86_64", @@ -330,7 +330,7 @@ "Licenses": [ "MIT", "BSD-3-Clause", - "GPL-2.0" + "GPL-2.0-or-later" ], "DependsOn": [ "musl@1.1.22-r3", @@ -354,14 +354,14 @@ "Name": "scanelf", "Identifier": { "PURL": "pkg:apk/alpine/scanelf@1.2.3-r0?arch=x86_64\u0026distro=3.10.2", - "UID": "6e5cf642f47e44d0" + "UID": "3ae1856359a8e719" }, "Version": "1.2.3-r0", "Arch": "x86_64", "SrcName": "pax-utils", "SrcVersion": "1.2.3-r0", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "musl@1.1.22-r3" @@ -380,14 +380,14 @@ "Name": "ssl_client", "Identifier": { "PURL": "pkg:apk/alpine/ssl_client@1.30.1-r2?arch=x86_64\u0026distro=3.10.2", - "UID": "3338164dd993d2c8" + "UID": "92ce33a8acb582f6" }, "Version": "1.30.1-r2", "Arch": "x86_64", "SrcName": "busybox", "SrcVersion": "1.30.1-r2", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "libtls-standalone@2.9.1-r0", diff --git a/pkg/fanal/test/integration/testdata/goldens/packages/vulnimage.json.golden b/pkg/fanal/test/integration/testdata/goldens/packages/vulnimage.json.golden index 4bfbb16a3dff..b4a8d982d9f7 100644 --- a/pkg/fanal/test/integration/testdata/goldens/packages/vulnimage.json.golden +++ b/pkg/fanal/test/integration/testdata/goldens/packages/vulnimage.json.golden @@ -71,14 +71,14 @@ "Name": "alpine-baselayout", "Identifier": { "PURL": "pkg:apk/alpine/alpine-baselayout@3.0.5-r2?arch=x86_64\u0026distro=3.7.1", - "UID": "fb3e0109c30ad75d" + "UID": "1fd865bbd91dfad4" }, "Version": "3.0.5-r2", "Arch": "x86_64", "SrcName": "alpine-baselayout", "SrcVersion": "3.0.5-r2", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "busybox@1.27.2-r11", @@ -163,14 +163,14 @@ "Name": "apk-tools", "Identifier": { "PURL": "pkg:apk/alpine/apk-tools@2.10.1-r0?arch=x86_64\u0026distro=3.7.1", - "UID": "44e4204bb4dc2b2a" + "UID": "78262f2dc70b3ede" }, "Version": "2.10.1-r0", "Arch": "x86_64", "SrcName": "apk-tools", "SrcVersion": "2.10.1-r0", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "libressl2.6-libcrypto@2.6.5-r0", @@ -192,14 +192,14 @@ "Name": "apr", "Identifier": { "PURL": "pkg:apk/alpine/apr@1.6.3-r0?arch=x86_64\u0026distro=3.7.1", - "UID": "715dd499dcec48f9" + "UID": "64f7de29e73c4636" }, "Version": "1.6.3-r0", "Arch": "x86_64", "SrcName": "apr", "SrcVersion": "1.6.3-r0", "Licenses": [ - "ASL2.0" + "Apache-2.0" ], "DependsOn": [ "libuuid@2.31-r0", @@ -221,14 +221,14 @@ "Name": "apr-util", "Identifier": { "PURL": "pkg:apk/alpine/apr-util@1.6.1-r1?arch=x86_64\u0026distro=3.7.1", - "UID": "2aa1dd25c68a60eb" + "UID": "2d3f23b8b61a097c" }, "Version": "1.6.1-r1", "Arch": "x86_64", "SrcName": "apr-util", "SrcVersion": "1.6.1-r1", "Licenses": [ - "ASL2.0" + "Apache-2.0" ], "DependsOn": [ "apr@1.6.3-r0", @@ -253,14 +253,14 @@ "Name": "bash", "Identifier": { "PURL": "pkg:apk/alpine/bash@4.4.19-r1?arch=x86_64\u0026distro=3.7.1", - "UID": "32e82b55d6afc293" + "UID": "c7841dcc19f73c7e" }, "Version": "4.4.19-r1", "Arch": "x86_64", "SrcName": "bash", "SrcVersion": "4.4.19-r1", "Licenses": [ - "GPL-3.0" + "GPL-3.0-or-later" ], "DependsOn": [ "busybox@1.27.2-r11", @@ -368,14 +368,14 @@ "Name": "busybox", "Identifier": { "PURL": "pkg:apk/alpine/busybox@1.27.2-r11?arch=x86_64\u0026distro=3.7.1", - "UID": "e32c8aeae1daa385" + "UID": "d936440f5fd65b0a" }, "Version": "1.27.2-r11", "Arch": "x86_64", "SrcName": "busybox", "SrcVersion": "1.27.2-r11", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "musl@1.1.18-r3" @@ -399,7 +399,7 @@ "Name": "ca-certificates", "Identifier": { "PURL": "pkg:apk/alpine/ca-certificates@20171114-r0?arch=x86_64\u0026distro=3.7.1", - "UID": "fc49474e56f2cdca" + "UID": "88fab2304b2bb95" }, "Version": "20171114-r0", "Arch": "x86_64", @@ -407,7 +407,7 @@ "SrcVersion": "20171114-r0", "Licenses": [ "MPL-2.0", - "GPL-2.0" + "GPL-2.0-or-later" ], "DependsOn": [ "busybox@1.27.2-r11", @@ -666,14 +666,14 @@ "Name": "gdbm", "Identifier": { "PURL": "pkg:apk/alpine/gdbm@1.13-r1?arch=x86_64\u0026distro=3.7.1", - "UID": "eb4b3efac8d4d73f" + "UID": "1bbe6ee4fe37c0c5" }, "Version": "1.13-r1", "Arch": "x86_64", "SrcName": "gdbm", "SrcVersion": "1.13-r1", "Licenses": [ - "GPL-3.0" + "GPL-2.0-or-later" ], "DependsOn": [ "musl@1.1.18-r3" @@ -698,14 +698,14 @@ "Name": "git", "Identifier": { "PURL": "pkg:apk/alpine/git@2.15.2-r0?arch=x86_64\u0026distro=3.7.1", - "UID": "845b6214d48ea80e" + "UID": "8f0a9684f6888b5b" }, "Version": "2.15.2-r0", "Arch": "x86_64", "SrcName": "git", "SrcVersion": "2.15.2-r0", "Licenses": [ - "GPL-2.0" + "GPL-2.0-or-later" ], "DependsOn": [ "expat@2.2.5-r0", @@ -1271,16 +1271,16 @@ "Name": "libuuid", "Identifier": { "PURL": "pkg:apk/alpine/libuuid@2.31-r0?arch=x86_64\u0026distro=3.7.1", - "UID": "ec8a9d1580eb93d7" + "UID": "39de02f4a8b5e0c" }, "Version": "2.31-r0", "Arch": "x86_64", "SrcName": "util-linux", "SrcVersion": "2.31-r0", "Licenses": [ - "GPL-2.0", - "GPL-2.0", - "LGPL-2.0", + "GPL-2.0-only", + "GPL-2.0-or-later", + "LGPL-2.0-or-later", "BSD-3-Clause", "Public", "Domain" @@ -1331,14 +1331,14 @@ "Name": "mercurial", "Identifier": { "PURL": "pkg:apk/alpine/mercurial@4.5.2-r0?arch=x86_64\u0026distro=3.7.1", - "UID": "28d12c554475942a" + "UID": "6148e64298851c1b" }, "Version": "4.5.2-r0", "Arch": "x86_64", "SrcName": "mercurial", "SrcVersion": "4.5.2-r0", "Licenses": [ - "GPL-2.0" + "GPL-2.0-or-later" ], "DependsOn": [ "musl@1.1.18-r3", @@ -2100,7 +2100,7 @@ "Name": "musl-utils", "Identifier": { "PURL": "pkg:apk/alpine/musl-utils@1.1.18-r3?arch=x86_64\u0026distro=3.7.1", - "UID": "c2765ad0d8dd83f9" + "UID": "dc61f5453717063a" }, "Version": "1.1.18-r3", "Arch": "x86_64", @@ -2109,7 +2109,7 @@ "Licenses": [ "MIT", "BSD-3-Clause", - "GPL-2.0" + "GPL-2.0-or-later" ], "DependsOn": [ "musl@1.1.18-r3", @@ -5136,14 +5136,14 @@ "Name": "patch", "Identifier": { "PURL": "pkg:apk/alpine/patch@2.7.5-r2?arch=x86_64\u0026distro=3.7.1", - "UID": "c3945b28493e2842" + "UID": "be58b1df7c42f71e" }, "Version": "2.7.5-r2", "Arch": "x86_64", "SrcName": "patch", "SrcVersion": "2.7.5-r2", "Licenses": [ - "GPL-3.0" + "GPL-2.0-or-later" ], "DependsOn": [ "musl@1.1.18-r3" @@ -7667,14 +7667,14 @@ "Name": "readline", "Identifier": { "PURL": "pkg:apk/alpine/readline@7.0.003-r0?arch=x86_64\u0026distro=3.7.1", - "UID": "2cb2c7047f5911f5" + "UID": "f3dc1d91dea8744d" }, "Version": "7.0.003-r0", "Arch": "x86_64", "SrcName": "readline", "SrcVersion": "7.0.003-r0", "Licenses": [ - "GPL-3.0" + "GPL-2.0-or-later" ], "DependsOn": [ "musl@1.1.18-r3", @@ -7695,14 +7695,14 @@ "Name": "scanelf", "Identifier": { "PURL": "pkg:apk/alpine/scanelf@1.2.2-r1?arch=x86_64\u0026distro=3.7.1", - "UID": "88086fdb5a997cfd" + "UID": "8520c35436819" }, "Version": "1.2.2-r1", "Arch": "x86_64", "SrcName": "pax-utils", "SrcVersion": "1.2.2-r1", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "musl@1.1.18-r3" @@ -7721,14 +7721,14 @@ "Name": "serf", "Identifier": { "PURL": "pkg:apk/alpine/serf@1.3.9-r3?arch=x86_64\u0026distro=3.7.1", - "UID": "34d5052ef0071707" + "UID": "e052e8031c85839d" }, "Version": "1.3.9-r3", "Arch": "x86_64", "SrcName": "serf", "SrcVersion": "1.3.9-r3", "Licenses": [ - "ASL2.0" + "Apache-2.0" ], "DependsOn": [ "apr-util@1.6.1-r1", @@ -7780,14 +7780,14 @@ "Name": "ssl_client", "Identifier": { "PURL": "pkg:apk/alpine/ssl_client@1.27.2-r11?arch=x86_64\u0026distro=3.7.1", - "UID": "eab2a79208d922b" + "UID": "740ce998f526d2c2" }, "Version": "1.27.2-r11", "Arch": "x86_64", "SrcName": "busybox", "SrcVersion": "1.27.2-r11", "Licenses": [ - "GPL-2.0" + "GPL-2.0-only" ], "DependsOn": [ "libressl2.6-libtls@2.6.5-r0", @@ -7930,14 +7930,14 @@ "Name": "tar", "Identifier": { "PURL": "pkg:apk/alpine/tar@1.29-r1?arch=x86_64\u0026distro=3.7.1", - "UID": "636f4bd512a19da9" + "UID": "35fcd0737165df45" }, "Version": "1.29-r1", "Arch": "x86_64", "SrcName": "tar", "SrcVersion": "1.29-r1", "Licenses": [ - "GPL-3.0" + "GPL-2.0-or-later" ], "DependsOn": [ "musl@1.1.18-r3" diff --git a/pkg/flag/license_flags.go b/pkg/flag/license_flags.go index 5f4e148af5b2..5ff4c912e2a9 100644 --- a/pkg/flag/license_flags.go +++ b/pkg/flag/license_flags.go @@ -2,7 +2,7 @@ package flag import ( "github.com/aquasecurity/trivy/pkg/fanal/types" - "github.com/aquasecurity/trivy/pkg/licensing" + "github.com/aquasecurity/trivy/pkg/licensing/expression" ) var ( @@ -26,37 +26,37 @@ var ( // LicenseForbidden is an option only in a config file LicenseForbidden = Flag[[]string]{ ConfigName: "license.forbidden", - Default: licensing.ForbiddenLicenses, + Default: expression.ForbiddenLicenses, Usage: "forbidden licenses", } // LicenseRestricted is an option only in a config file LicenseRestricted = Flag[[]string]{ ConfigName: "license.restricted", - Default: licensing.RestrictedLicenses, + Default: expression.RestrictedLicenses, Usage: "restricted licenses", } // LicenseReciprocal is an option only in a config file LicenseReciprocal = Flag[[]string]{ ConfigName: "license.reciprocal", - Default: licensing.ReciprocalLicenses, + Default: expression.ReciprocalLicenses, Usage: "reciprocal licenses", } // LicenseNotice is an option only in a config file LicenseNotice = Flag[[]string]{ ConfigName: "license.notice", - Default: licensing.NoticeLicenses, + Default: expression.NoticeLicenses, Usage: "notice licenses", } // LicensePermissive is an option only in a config file LicensePermissive = Flag[[]string]{ ConfigName: "license.permissive", - Default: licensing.PermissiveLicenses, + Default: expression.PermissiveLicenses, Usage: "permissive licenses", } // LicenseUnencumbered is an option only in a config file LicenseUnencumbered = Flag[[]string]{ ConfigName: "license.unencumbered", - Default: licensing.UnencumberedLicenses, + Default: expression.UnencumberedLicenses, Usage: "unencumbered licenses", } ) diff --git a/pkg/licensing/category.go b/pkg/licensing/expression/category.go similarity index 96% rename from pkg/licensing/category.go rename to pkg/licensing/expression/category.go index f99ccdc52af4..c32f228c07d8 100644 --- a/pkg/licensing/category.go +++ b/pkg/licensing/expression/category.go @@ -1,4 +1,4 @@ -package licensing +package expression // Canonical names of the licenses. // ported from https://github.com/google/licenseclassifier/blob/7c62d6fe8d3aa2f39c4affb58c9781d9dc951a2d/license_type.go#L24-L177 @@ -165,6 +165,28 @@ const ( ZPL21 = "ZPL-2.1" ) +// GNU licenses always use either the suffix “-only“ or the suffix “-or-later“ +// https://spdx.dev/learn/handling-license-info/ +var GnuLicenses = []string{ + AGPL10, + AGPL30, + GFDL11WithInvariants, + GFDL11NoInvariants, + GFDL11, + GFDL12WithInvariants, + GFDL12NoInvariants, + GFDL12, + GFDL13WithInvariants, + GFDL13NoInvariants, + GFDL13, + GPL10, + GPL20, + GPL30, + LGPL20, + LGPL21, + LGPL30, +} + var ( // ForbiddenLicenses - Licenses that are forbidden to be used. // ported from https://github.com/google/licenseclassifier/blob/7c62d6fe8d3aa2f39c4affb58c9781d9dc951a2d/license_type.go#L340-L364 diff --git a/pkg/licensing/expression/expression.go b/pkg/licensing/expression/expression.go index 59848e57eef7..6f3c0054f929 100644 --- a/pkg/licensing/expression/expression.go +++ b/pkg/licensing/expression/expression.go @@ -11,7 +11,7 @@ var ( ErrInvalidExpression = xerrors.New("invalid expression error") ) -type NormalizeFunc func(license string) string +type NormalizeFunc func(license string) SimpleExpr func parse(license string) (Expression, error) { l := NewLexer(strings.NewReader(license)) @@ -38,7 +38,9 @@ func normalize(expr Expression, fn ...NormalizeFunc) Expression { switch e := expr.(type) { case SimpleExpr: for _, f := range fn { - e.license = f(e.license) + normalized := f(e.License) + e.License = normalized.License + e.HasPlus = e.HasPlus || normalized.HasPlus } return e case CompoundExpr: @@ -52,10 +54,10 @@ func normalize(expr Expression, fn ...NormalizeFunc) Expression { } // NormalizeForSPDX replaces ' ' to '-' in license-id. -// SPDX license MUST NOT be white space between a license-id. +// SPDX license MUST NOT have white space between a license-id. // There MUST be white space on either side of the operator "WITH". // ref: https://spdx.github.io/spdx-spec/v2.3/SPDX-license-expressions -func NormalizeForSPDX(s string) string { +func NormalizeForSPDX(s string) SimpleExpr { var b strings.Builder for _, c := range s { switch { @@ -70,7 +72,7 @@ func NormalizeForSPDX(s string) string { _, _ = b.WriteRune('-') } } - return b.String() + return SimpleExpr{License: b.String(), HasPlus: false} } func isAlphabet(r rune) bool { diff --git a/pkg/licensing/expression/expression_test.go b/pkg/licensing/expression/expression_test.go index 0e3eaa7ae7cc..12b715e7ad30 100644 --- a/pkg/licensing/expression/expression_test.go +++ b/pkg/licensing/expression/expression_test.go @@ -37,7 +37,7 @@ func TestNormalize(t *testing.T) { { name: "upper", license: "LGPL-2.1-only OR MIT", - fn: strings.ToUpper, + fn: func(license string) SimpleExpr { return SimpleExpr{strings.ToUpper(license), false} }, want: "LGPL-2.1-ONLY OR MIT", }, } diff --git a/pkg/licensing/expression/parser.go.y b/pkg/licensing/expression/parser.go.y index 82bd11028619..85a90a5a73ce 100644 --- a/pkg/licensing/expression/parser.go.y +++ b/pkg/licensing/expression/parser.go.y @@ -32,17 +32,17 @@ license simple : IDENT { - $$ = SimpleExpr{license: $1.literal} + $$ = SimpleExpr{License: $1.literal} } | simple IDENT /* e.g. Public Domain */ { - $$ = SimpleExpr{license: $1.String() + " " + $2.literal} + $$ = SimpleExpr{License: $1.String() + " " + $2.literal} } plus : simple '+' { - $$ = SimpleExpr{license: $1.String(), hasPlus: true} + $$ = SimpleExpr{License: $1.String(), HasPlus: true} } compound diff --git a/pkg/licensing/expression/parser_gen.go b/pkg/licensing/expression/parser_gen.go index 32f65276374e..57c51b320e5d 100644 --- a/pkg/licensing/expression/parser_gen.go +++ b/pkg/licensing/expression/parser_gen.go @@ -452,19 +452,19 @@ yydefault: yyDollar = yyS[yypt-1 : yypt+1] //line parser.go.y:34 { - yyVAL.expr = SimpleExpr{license: yyDollar[1].token.literal} + yyVAL.expr = SimpleExpr{License: yyDollar[1].token.literal} } case 3: yyDollar = yyS[yypt-2 : yypt+1] //line parser.go.y:38 { - yyVAL.expr = SimpleExpr{license: yyDollar[1].expr.String() + " " + yyDollar[2].token.literal} + yyVAL.expr = SimpleExpr{License: yyDollar[1].expr.String() + " " + yyDollar[2].token.literal} } case 4: yyDollar = yyS[yypt-2 : yypt+1] //line parser.go.y:44 { - yyVAL.expr = SimpleExpr{license: yyDollar[1].expr.String(), hasPlus: true} + yyVAL.expr = SimpleExpr{License: yyDollar[1].expr.String(), HasPlus: true} } case 5: yyDollar = yyS[yypt-1 : yypt+1] diff --git a/pkg/licensing/expression/parser_test.go b/pkg/licensing/expression/parser_test.go index 522777085b5b..acbc09a53545 100644 --- a/pkg/licensing/expression/parser_test.go +++ b/pkg/licensing/expression/parser_test.go @@ -20,7 +20,7 @@ func TestParse(t *testing.T) { name: "single license", input: "Public Domain", want: SimpleExpr{ - license: "Public Domain", + License: "Public Domain", }, wantStr: "Public Domain", }, @@ -28,7 +28,7 @@ func TestParse(t *testing.T) { name: "tag:value license", input: "DocumentRef-spdx-tool-1.2:LicenseRef-MIT-Style-2", want: SimpleExpr{ - license: "DocumentRef-spdx-tool-1.2:LicenseRef-MIT-Style-2", + License: "DocumentRef-spdx-tool-1.2:LicenseRef-MIT-Style-2", }, wantStr: "DocumentRef-spdx-tool-1.2:LicenseRef-MIT-Style-2", }, @@ -36,8 +36,8 @@ func TestParse(t *testing.T) { name: "symbols", input: "Public ._-+", want: SimpleExpr{ - license: "Public ._-", - hasPlus: true, + License: "Public ._-", + HasPlus: true, }, wantStr: "Public ._-+", }, @@ -47,7 +47,7 @@ func TestParse(t *testing.T) { want: CompoundExpr{ left: CompoundExpr{ left: SimpleExpr{ - license: "Public Domain", + License: "Public Domain", }, conjunction: Token{ token: AND, @@ -55,15 +55,15 @@ func TestParse(t *testing.T) { }, right: CompoundExpr{ left: SimpleExpr{ - license: "GPLv2", - hasPlus: true, + License: "GPLv2", + HasPlus: true, }, conjunction: Token{ token: OR, literal: "or", }, right: SimpleExpr{ - license: "AFL", + License: "AFL", }, }, }, @@ -73,15 +73,15 @@ func TestParse(t *testing.T) { }, right: CompoundExpr{ left: SimpleExpr{ - license: "LGPLv2", - hasPlus: true, + License: "LGPLv2", + HasPlus: true, }, conjunction: Token{ token: WITH, literal: "with", }, right: SimpleExpr{ - license: "distribution exceptions", + License: "distribution exceptions", }, }, }, @@ -92,7 +92,7 @@ func TestParse(t *testing.T) { input: "Public Domain AND ( GPLv2+ or AFL AND ( CC0 or LGPL1.0) )", want: CompoundExpr{ left: SimpleExpr{ - license: "Public Domain", + License: "Public Domain", }, conjunction: Token{ token: AND, @@ -100,8 +100,8 @@ func TestParse(t *testing.T) { }, right: CompoundExpr{ left: SimpleExpr{ - license: "GPLv2", - hasPlus: true, + License: "GPLv2", + HasPlus: true, }, conjunction: Token{ token: OR, @@ -109,7 +109,7 @@ func TestParse(t *testing.T) { }, right: CompoundExpr{ left: SimpleExpr{ - license: "AFL", + License: "AFL", }, conjunction: Token{ token: AND, @@ -117,14 +117,14 @@ func TestParse(t *testing.T) { }, right: CompoundExpr{ left: SimpleExpr{ - license: "CC0", + License: "CC0", }, conjunction: Token{ token: OR, literal: "or", }, right: SimpleExpr{ - license: "LGPL1.0", + License: "LGPL1.0", }, }, }, diff --git a/pkg/licensing/expression/types.go b/pkg/licensing/expression/types.go index f344c610ab4d..acf2473ed4e8 100644 --- a/pkg/licensing/expression/types.go +++ b/pkg/licensing/expression/types.go @@ -3,30 +3,8 @@ package expression import ( "fmt" "slices" - - "github.com/aquasecurity/trivy/pkg/licensing" ) -var versioned = []string{ - licensing.AGPL10, - licensing.AGPL30, - licensing.GFDL11WithInvariants, - licensing.GFDL11NoInvariants, - licensing.GFDL11, - licensing.GFDL12WithInvariants, - licensing.GFDL12NoInvariants, - licensing.GFDL12, - licensing.GFDL13WithInvariants, - licensing.GFDL13NoInvariants, - licensing.GFDL13, - licensing.GPL10, - licensing.GPL20, - licensing.GPL30, - licensing.LGPL20, - licensing.LGPL21, - licensing.LGPL30, -} - type Expression interface { String() string } @@ -37,24 +15,24 @@ type Token struct { } type SimpleExpr struct { - license string - hasPlus bool + License string + HasPlus bool } func (s SimpleExpr) String() string { - if slices.Contains(versioned, s.license) { - if s.hasPlus { + if slices.Contains(GnuLicenses, s.License) { + if s.HasPlus { // e.g. AGPL-1.0-or-later - return s.license + "-or-later" + return s.License + "-or-later" } // e.g. GPL-1.0-only - return s.license + "-only" + return s.License + "-only" } - if s.hasPlus { - return s.license + "+" + if s.HasPlus { + return s.License + "+" } - return s.license + return s.License } type CompoundExpr struct { diff --git a/pkg/licensing/normalize.go b/pkg/licensing/normalize.go index 4ca8eab00030..4ce294275214 100644 --- a/pkg/licensing/normalize.go +++ b/pkg/licensing/normalize.go @@ -3,160 +3,569 @@ package licensing import ( "regexp" "strings" -) - -var mapping = map[string]string{ - // GPL - "GPL-1": GPL10, - "GPL-1+": GPL10, - "GPL 1.0": GPL10, - "GPL 1": GPL10, - "GPL2": GPL20, - "GPL 2.0": GPL20, - "GPL 2": GPL20, - "GPL-2": GPL20, - "GPL-2.0-ONLY": GPL20, - "GPL2+": GPL20, - "GPLV2": GPL20, - "GPLV2+": GPL20, - "GPL-2+": GPL20, - "GPL-2.0+": GPL20, - "GPL-2.0-OR-LATER": GPL20, - "GPL-2+ WITH AUTOCONF EXCEPTION": GPL20withautoconfexception, - "GPL-2+-with-bison-exception": GPL20withbisonexception, - "GPL3": GPL30, - "GPL 3.0": GPL30, - "GPL 3": GPL30, - "GPLV3": GPL30, - "GPLV3+": GPL30, - "GPL-3": GPL30, - "GPL-3.0-ONLY": GPL30, - "GPL3+": GPL30, - "GPL-3+": GPL30, - "GPL-3.0-OR-LATER": GPL30, - "GPL-3+ WITH AUTOCONF EXCEPTION": GPL30withautoconfexception, - "GPL-3+-WITH-BISON-EXCEPTION": GPL20withbisonexception, - "GPL": GPL30, // 2? 3? - - // LGPL - "LGPL2": LGPL20, - "LGPL 2": LGPL20, - "LGPL 2.0": LGPL20, - "LGPL-2": LGPL20, - "LGPL2+": LGPL20, - "LGPL-2+": LGPL20, - "LGPL-2.0+": LGPL20, - "LGPL-2.1": LGPL21, - "LGPL 2.1": LGPL21, - "LGPL-2.1+": LGPL21, - "LGPLV2.1+": LGPL21, - "LGPL-3": LGPL30, - "LGPL 3": LGPL30, - "LGPL-3+": LGPL30, - "LGPL": LGPL30, // 2? 3? - "GNU LESSER": LGPL30, // 2? 3? - - // MPL - "MPL1.0": MPL10, - "MPL1": MPL10, - "MPL 1.0": MPL10, - "MPL 1": MPL10, - "MPL2.0": MPL20, - "MPL 2.0": MPL20, - "MPL2": MPL20, - "MPL 2": MPL20, - - // BSD - "BSD": BSD3Clause, // 2? 3? - "BSD-2-CLAUSE": BSD2Clause, - "BSD-3-CLAUSE": BSD3Clause, - "BSD-4-CLAUSE": BSD4Clause, - "BSD 2 CLAUSE": BSD2Clause, - "BSD 2-CLAUSE": BSD2Clause, - "BSD 2-CLAUSE LICENSE": BSD2Clause, - "THE BSD 2-CLAUSE LICENSE": BSD2Clause, - "THE 2-CLAUSE BSD LICENSE": BSD2Clause, - "TWO-CLAUSE BSD-STYLE LICENSE": BSD2Clause, - "BSD 3 CLAUSE": BSD3Clause, - "BSD 3-CLAUSE": BSD3Clause, - "BSD 3-CLAUSE LICENSE": BSD3Clause, - "THE BSD 3-CLAUSE LICENSE": BSD3Clause, - "BSD 3-CLAUSE \"NEW\" OR \"REVISED\" LICENSE (BSD-3-CLAUSE)": BSD3Clause, - "ECLIPSE DISTRIBUTION LICENSE (NEW BSD LICENSE)": BSD3Clause, - "NEW BSD LICENSE": BSD3Clause, - "MODIFIED BSD LICENSE": BSD3Clause, - "REVISED BSD": BSD3Clause, - "REVISED BSD LICENSE": BSD3Clause, - "THE NEW BSD LICENSE": BSD3Clause, - "3-CLAUSE BSD LICENSE": BSD3Clause, - "BSD 3-CLAUSE NEW LICENSE": BSD3Clause, - "BSD LICENSE": BSD3Clause, - "EDL 1.0": BSD3Clause, - "ECLIPSE DISTRIBUTION LICENSE - V 1.0": BSD3Clause, - "ECLIPSE DISTRIBUTION LICENSE V. 1.0": BSD3Clause, - "ECLIPSE DISTRIBUTION LICENSE V1.0": BSD3Clause, - "THE BSD LICENSE": BSD4Clause, - // APACHE - "APACHE LICENSE": Apache10, - "APACHE SOFTWARE LICENSES": Apache10, - "APACHE": Apache20, // 1? 2? - "APACHE 2.0": Apache20, - "APACHE 2": Apache20, - "APACHE V2": Apache20, - "APACHE 2.0 LICENSE": Apache20, - "APACHE SOFTWARE LICENSE, VERSION 2.0": Apache20, - "THE APACHE SOFTWARE LICENSE, VERSION 2.0": Apache20, - "APACHE LICENSE (V2.0)": Apache20, - "APACHE LICENSE 2.0": Apache20, - "APACHE LICENSE V2.0": Apache20, - "APACHE LICENSE VERSION 2.0": Apache20, - "APACHE LICENSE, VERSION 2.0": Apache20, - "APACHE PUBLIC LICENSE 2.0": Apache20, - "APACHE SOFTWARE LICENSE - VERSION 2.0": Apache20, - "THE APACHE LICENSE, VERSION 2.0": Apache20, - "APACHE-2.0 LICENSE": Apache20, - "APACHE 2 STYLE LICENSE": Apache20, - "ASF 2.0": Apache20, + expr "github.com/aquasecurity/trivy/pkg/licensing/expression" +) - // CC0-1.0 - "CC0 1.0 UNIVERSAL": CC010, - "PUBLIC DOMAIN, PER CREATIVE COMMONS CC0": CC010, +func licence(name string, hasPlus bool) expr.SimpleExpr { + return expr.SimpleExpr{License: name, HasPlus: hasPlus} +} - // CDDL 1.0 - "CDDL 1.0": CDDL10, - "CDDL LICENSE": CDDL10, - "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) VERSION 1.0": CDDL10, - "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) V1.0": CDDL10, +var mapping = map[string]expr.SimpleExpr{ + // Simple mappings (i.e. that could be parsed by SpdxExpression.parse, at least without space) + // modified from https://github.com/oss-review-toolkit/ort/blob/fc5389c2cfd9c8b009794c8a11f5c91321b7a730/utils/spdx/src/main/resources/simple-license-mapping.yml - // CDDL 1.1 - "CDDL 1.1": CDDL11, - "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) VERSION 1.1": CDDL11, - "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) V1.1": CDDL11, + // Ambiguous simple mappings (mapping reason not obvious without additional information) + "AFL": licence(expr.AFL30, false), + "AGPL": licence(expr.AGPL30, false), + "AL-2": licence(expr.Apache20, false), + "AL-2.0": licence(expr.Apache20, false), + "APACHE": licence(expr.Apache20, false), + "APACHE-STYLE": licence(expr.Apache20, false), + "ARTISTIC": licence(expr.Artistic20, false), + "ASL": licence(expr.Apache20, false), + "BSD": licence(expr.BSD3Clause, false), + "BSD*": licence(expr.BSD3Clause, false), + "BSD-LIKE": licence(expr.BSD3Clause, false), + "BSD-STYLE": licence(expr.BSD3Clause, false), + "BSD-VARIANT": licence(expr.BSD3Clause, false), + "CDDL": licence(expr.CDDL10, false), + "ECLIPSE": licence(expr.EPL10, false), + "EPL": licence(expr.EPL10, false), + "EUPL": licence(expr.EUPL10, false), + "FDL": licence(expr.GFDL13, true), + "GFDL": licence(expr.GFDL13, true), + "GPL": licence(expr.GPL20, true), + "LGPL": licence(expr.LGPL20, true), + "MPL": licence(expr.MPL20, false), + "NETSCAPE": licence(expr.NPL11, false), + "PYTHON": licence(expr.Python20, false), + "ZOPE": licence(expr.ZPL21, false), - // EPL 1.0 - "ECLIPSE PUBLIC LICENSE - VERSION 1.0": EPL10, - "ECLIPSE PUBLIC LICENSE (EPL) 1.0": EPL10, - "ECLIPSE PUBLIC LICENSE V1.0": EPL10, - "ECLIPSE PUBLIC LICENSE, VERSION 1.0": EPL10, - "ECLIPSE PUBLIC LICENSE - V 1.0": EPL10, - "ECLIPSE PUBLIC LICENSE - V1.0": EPL10, - "ECLIPSE PUBLIC LICENSE (EPL), VERSION 1.0": EPL10, + // Non-ambiguous simple mappings + "0BSD": licence(expr.ZeroBSD, false), + "AFL-1.1": licence(expr.AFL11, false), + "AFL-1.2": licence(expr.AFL12, false), + "AFL-2": licence(expr.AFL20, false), + "AFL-2.0": licence(expr.AFL20, false), + "AFL-2.1": licence(expr.AFL21, false), + "AFL-3.0": licence(expr.AFL30, false), + "AGPL-1.0": licence(expr.AGPL10, false), + "AGPL-3.0": licence(expr.AGPL30, false), + "APACHE-1": licence(expr.Apache10, false), + "APACHE-1.0": licence(expr.Apache10, false), + "APACHE-1.1": licence(expr.Apache11, false), + "APACHE-2": licence(expr.Apache20, false), + "APACHE-2.0": licence(expr.Apache20, false), + "APL-2": licence(expr.Apache20, false), + "APL-2.0": licence(expr.Apache20, false), + "APSL-1.0": licence(expr.APSL10, false), + "APSL-1.1": licence(expr.APSL11, false), + "APSL-1.2": licence(expr.APSL12, false), + "APSL-2.0": licence(expr.APSL20, false), + "ARTISTIC-1.0": licence(expr.Artistic10, false), + "ARTISTIC-1.0-CL-8": licence(expr.Artistic10cl8, false), + "ARTISTIC-1.0-PERL": licence(expr.Artistic10Perl, false), + "ARTISTIC-2.0": licence(expr.Artistic20, false), + "ASF-1": licence(expr.Apache10, false), + "ASF-1.0": licence(expr.Apache10, false), + "ASF-1.1": licence(expr.Apache11, false), + "ASF-2": licence(expr.Apache20, false), + "ASF-2.0": licence(expr.Apache20, false), + "ASL-1": licence(expr.Apache10, false), + "ASL-1.0": licence(expr.Apache10, false), + "ASL-1.1": licence(expr.Apache11, false), + "ASL-2": licence(expr.Apache20, false), + "ASL-2.0": licence(expr.Apache20, false), + "BCL": licence(expr.BCL, false), + "BEERWARE": licence(expr.Beerware, false), + "BOOST": licence(expr.BSL10, false), + "BOOST-1.0": licence(expr.BSL10, false), + "BOUNCY": licence(expr.MIT, false), + "BSD-2": licence(expr.BSD2Clause, false), + "BSD-2-CLAUSE": licence(expr.BSD2Clause, false), + "BSD-2-CLAUSE-FREEBSD": licence(expr.BSD2ClauseFreeBSD, false), + "BSD-2-CLAUSE-NETBSD": licence(expr.BSD2ClauseNetBSD, false), + "BSD-3": licence(expr.BSD3Clause, false), + "BSD-3-CLAUSE": licence(expr.BSD3Clause, false), + "BSD-3-CLAUSE-ATTRIBUTION": licence(expr.BSD3ClauseAttribution, false), + "BSD-3-CLAUSE-CLEAR": licence(expr.BSD3ClauseClear, false), + "BSD-3-CLAUSE-LBNL": licence(expr.BSD3ClauseLBNL, false), + "BSD-4": licence(expr.BSD4Clause, false), + "BSD-4-CLAUSE": licence(expr.BSD4Clause, false), + "BSD-4-CLAUSE-UC": licence(expr.BSD4ClauseUC, false), + "BSD-PROTECTION": licence(expr.BSDProtection, false), + "BSL": licence(expr.BSL10, false), + "BSL-1.0": licence(expr.BSL10, false), + "CC-BY-1.0": licence(expr.CCBY10, false), + "CC-BY-2.0": licence(expr.CCBY20, false), + "CC-BY-2.5": licence(expr.CCBY25, false), + "CC-BY-3.0": licence(expr.CCBY30, false), + "CC-BY-4.0": licence(expr.CCBY40, false), + "CC-BY-NC-1.0": licence(expr.CCBYNC10, false), + "CC-BY-NC-2.0": licence(expr.CCBYNC20, false), + "CC-BY-NC-2.5": licence(expr.CCBYNC25, false), + "CC-BY-NC-3.0": licence(expr.CCBYNC30, false), + "CC-BY-NC-4.0": licence(expr.CCBYNC40, false), + "CC-BY-NC-ND-1.0": licence(expr.CCBYNCND10, false), + "CC-BY-NC-ND-2.0": licence(expr.CCBYNCND20, false), + "CC-BY-NC-ND-2.5": licence(expr.CCBYNCND25, false), + "CC-BY-NC-ND-3.0": licence(expr.CCBYNCND30, false), + "CC-BY-NC-ND-4.0": licence(expr.CCBYNCND40, false), + "CC-BY-NC-SA-1.0": licence(expr.CCBYNCSA10, false), + "CC-BY-NC-SA-2.0": licence(expr.CCBYNCSA20, false), + "CC-BY-NC-SA-2.5": licence(expr.CCBYNCSA25, false), + "CC-BY-NC-SA-3.0": licence(expr.CCBYNCSA30, false), + "CC-BY-NC-SA-4.0": licence(expr.CCBYNCSA40, false), + "CC-BY-ND-1.0": licence(expr.CCBYND10, false), + "CC-BY-ND-2.0": licence(expr.CCBYND20, false), + "CC-BY-ND-2.5": licence(expr.CCBYND25, false), + "CC-BY-ND-3.0": licence(expr.CCBYND30, false), + "CC-BY-ND-4.0": licence(expr.CCBYND40, false), + "CC-BY-SA-1.0": licence(expr.CCBYSA10, false), + "CC-BY-SA-2.0": licence(expr.CCBYSA20, false), + "CC-BY-SA-2.5": licence(expr.CCBYSA25, false), + "CC-BY-SA-3.0": licence(expr.CCBYSA30, false), + "CC-BY-SA-4.0": licence(expr.CCBYSA40, false), + "CC0": licence(expr.CC010, false), + "CC0-1.0": licence(expr.CC010, false), + "CDDL-1": licence(expr.CDDL10, false), + "CDDL-1.0": licence(expr.CDDL10, false), + "CDDL-1.1": licence(expr.CDDL11, false), + "COMMONS-CLAUSE": licence(expr.CommonsClause, false), + "CPAL": licence(expr.CPAL10, false), + "CPAL-1.0": licence(expr.CPAL10, false), + "CPL": licence(expr.CPL10, false), + "CPL-1.0": licence(expr.CPL10, false), + "ECLIPSE-1.0": licence(expr.EPL10, false), + "ECLIPSE-2.0": licence(expr.EPL20, false), + "EDL-1.0": licence(expr.BSD3Clause, false), + "EGENIX": licence(expr.EGenix, false), + "EPL-1.0": licence(expr.EPL10, false), + "EPL-2.0": licence(expr.EPL20, false), + "EUPL-1.0": licence(expr.EUPL10, false), + "EUPL-1.1": licence(expr.EUPL11, false), + "EXPAT": licence(expr.MIT, false), + "FACEBOOK-2-CLAUSE": licence(expr.Facebook2Clause, false), + "FACEBOOK-3-CLAUSE": licence(expr.Facebook3Clause, false), + "FACEBOOK-EXAMPLES": licence(expr.FacebookExamples, false), + "FREEIMAGE": licence(expr.FreeImage, false), + "FTL": licence(expr.FTL, false), + "GFDL-1.1": licence(expr.GFDL11, false), + "GFDL-1.1-INVARIANTS": licence(expr.GFDL11WithInvariants, false), + "GFDL-1.1-NO-INVARIANTS": licence(expr.GFDL11NoInvariants, false), + "GFDL-1.2": licence(expr.GFDL12, false), + "GFDL-1.2-INVARIANTS": licence(expr.GFDL12WithInvariants, false), + "GFDL-1.2-NO-INVARIANTS": licence(expr.GFDL12NoInvariants, false), + "GFDL-1.3": licence(expr.GFDL13, false), + "GFDL-1.3-INVARIANTS": licence(expr.GFDL13WithInvariants, false), + "GFDL-1.3-NO-INVARIANTS": licence(expr.GFDL13NoInvariants, false), + "GFDL-NIV-1.3": licence(expr.GFDL13NoInvariants, false), + "GO": licence(expr.BSD3Clause, false), + "GPL-1": licence(expr.GPL10, false), + "GPL-1.0": licence(expr.GPL10, false), + "GPL-2": licence(expr.GPL20, false), + "GPL-2+-WITH-BISON-EXCEPTION": licence(expr.GPL20withbisonexception, true), + "GPL-2.0": licence(expr.GPL20, false), + "GPL-2.0-WITH-AUTOCONF-EXCEPTION": licence(expr.GPL20withautoconfexception, false), + "GPL-2.0-WITH-BISON-EXCEPTION": licence(expr.GPL20withbisonexception, false), + "GPL-2.0-WITH-CLASSPATH-EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GPL-2.0-WITH-FONT-EXCEPTION": licence(expr.GPL20withfontexception, false), + "GPL-2.0-WITH-GCC-EXCEPTION": licence(expr.GPL20withGCCexception, false), + "GPL-3": licence(expr.GPL30, false), + "GPL-3+-WITH-BISON-EXCEPTION": licence(expr.GPL20withbisonexception, true), + "GPL-3.0": licence(expr.GPL30, false), + "GPL-3.0-WITH-AUTOCONF-EXCEPTION": licence(expr.GPL30withautoconfexception, false), + "GPL-3.0-WITH-GCC-EXCEPTION": licence(expr.GPL30withGCCexception, false), + "GPLV2+CE": licence(expr.GPL20withclasspathexception, true), + "GUST-FONT": licence(expr.GUSTFont, false), + "HSQLDB": licence(expr.BSD3Clause, false), + "IMAGEMAGICK": licence(expr.ImageMagick, false), + "IPL-1.0": licence(expr.IPL10, false), + "ISC": licence(expr.ISC, false), + "ISCL": licence(expr.ISC, false), + "JQUERY": licence(expr.MIT, false), + "LGPL-2": licence(expr.LGPL20, false), + "LGPL-2.0": licence(expr.LGPL20, false), + "LGPL-2.1": licence(expr.LGPL21, false), + "LGPL-3": licence(expr.LGPL30, false), + "LGPL-3.0": licence(expr.LGPL30, false), + "LGPLLR": licence(expr.LGPLLR, false), + "LIBPNG": licence(expr.Libpng, false), + "LIL-1.0": licence(expr.Lil10, false), + "LINUX-OPENIB": licence(expr.LinuxOpenIB, false), + "LPL-1.0": licence(expr.LPL10, false), + "LPL-1.02": licence(expr.LPL102, false), + "LPPL-1.3C": licence(expr.LPPL13c, false), + "MIT": licence(expr.MIT, false), + // MIT No Attribution (MIT-0) is not yet supported by google/licenseclassifier + "MIT-0": licence(expr.MIT, false), + "MIT-LIKE": licence(expr.MIT, false), + "MIT-STYLE": licence(expr.MIT, false), + "MPL-1": licence(expr.MPL10, false), + "MPL-1.0": licence(expr.MPL10, false), + "MPL-1.1": licence(expr.MPL11, false), + "MPL-2": licence(expr.MPL20, false), + "MPL-2.0": licence(expr.MPL20, false), + "MS-PL": licence(expr.MSPL, false), + "NCSA": licence(expr.NCSA, false), + "NPL-1.0": licence(expr.NPL10, false), + "NPL-1.1": licence(expr.NPL11, false), + "OFL-1.1": licence(expr.OFL11, false), + "OPENSSL": licence(expr.OpenSSL, false), + "OPENVISION": licence(expr.OpenVision, false), + "OSL-1": licence(expr.OSL10, false), + "OSL-1.0": licence(expr.OSL10, false), + "OSL-1.1": licence(expr.OSL11, false), + "OSL-2": licence(expr.OSL20, false), + "OSL-2.0": licence(expr.OSL20, false), + "OSL-2.1": licence(expr.OSL21, false), + "OSL-3": licence(expr.OSL30, false), + "OSL-3.0": licence(expr.OSL30, false), + "PHP-3.0": licence(expr.PHP30, false), + "PHP-3.01": licence(expr.PHP301, false), + "PIL": licence(expr.PIL, false), + "POSTGRESQL": licence(expr.PostgreSQL, false), + "PYTHON-2": licence(expr.Python20, false), + "PYTHON-2.0": licence(expr.Python20, false), + "PYTHON-2.0-COMPLETE": licence(expr.Python20complete, false), + "QPL-1": licence(expr.QPL10, false), + "QPL-1.0": licence(expr.QPL10, false), + "RUBY": licence(expr.Ruby, false), + "SGI-B-1.0": licence(expr.SGIB10, false), + "SGI-B-1.1": licence(expr.SGIB11, false), + "SGI-B-2.0": licence(expr.SGIB20, false), + "SISSL": licence(expr.SISSL, false), + "SISSL-1.2": licence(expr.SISSL12, false), + "SLEEPYCAT": licence(expr.Sleepycat, false), + "UNICODE-DFS-2015": licence(expr.UnicodeDFS2015, false), + "UNICODE-DFS-2016": licence(expr.UnicodeDFS2016, false), + "UNICODE-TOU": licence(expr.UnicodeTOU, false), + "UNLICENSE": licence(expr.Unlicense, false), + "UNLICENSED": licence(expr.Unlicense, false), + "UPL-1": licence(expr.UPL10, false), + "UPL-1.0": licence(expr.UPL10, false), + "W3C": licence(expr.W3C, false), + "W3C-19980720": licence(expr.W3C19980720, false), + "W3C-20150513": licence(expr.W3C20150513, false), + "W3CL": licence(expr.W3C, false), + "WTF": licence(expr.WTFPL, false), + "WTFPL": licence(expr.WTFPL, false), + "X11": licence(expr.X11, false), + "XNET": licence(expr.Xnet, false), + "ZEND-2": licence(expr.Zend20, false), + "ZEND-2.0": licence(expr.Zend20, false), + "ZLIB": licence(expr.Zlib, false), + "ZLIB-ACKNOWLEDGEMENT": licence(expr.ZlibAcknowledgement, false), + "ZOPE-1.1": licence(expr.ZPL11, false), + "ZOPE-2.0": licence(expr.ZPL20, false), + "ZOPE-2.1": licence(expr.ZPL21, false), + "ZPL-1.1": licence(expr.ZPL11, false), + "ZPL-2.0": licence(expr.ZPL20, false), + "ZPL-2.1": licence(expr.ZPL21, false), - // EPL 2.0 - "ECLIPSE PUBLIC LICENSE - VERSION 2.0": EPL20, - "EPL 2.0": EPL20, - "ECLIPSE PUBLIC LICENSE - V 2.0": EPL20, - "ECLIPSE PUBLIC LICENSE V2.0": EPL20, - "ECLIPSE PUBLIC LICENSE, VERSION 2.0": EPL20, - "THE ECLIPSE PUBLIC LICENSE VERSION 2.0": EPL20, - "ECLIPSE PUBLIC LICENSE V. 2.0": EPL20, + // Non simple declared mappings + // modified from https://github.com/oss-review-toolkit/ort/blob/fc5389c2cfd9c8b009794c8a11f5c91321b7a730/utils/spdx/src/main/resources/declared-license-mapping.yml - "RUBY": Ruby, - "ZLIB": Zlib, + // Ambiguous declared mappings (mapping reason not obvious without additional information) + "ACADEMIC FREE LICENSE (AFL)": licence(expr.AFL21, false), + "APACHE SOFTWARE LICENSES": licence(expr.Apache20, false), + "APACHE SOFTWARE": licence(expr.Apache20, false), + "APPLE PUBLIC SOURCE": licence(expr.APSL10, false), + "BSD SOFTWARE": licence(expr.BSD2Clause, false), + "BSD STYLE": licence(expr.BSD3Clause, false), + "COMMON DEVELOPMENT AND DISTRIBUTION": licence(expr.CDDL10, false), + "CREATIVE COMMONS - BY": licence(expr.CCBY30, false), + "CREATIVE COMMONS ATTRIBUTION": licence(expr.CCBY30, false), + "CREATIVE COMMONS": licence(expr.CCBY30, false), + "ECLIPSE PUBLIC LICENSE (EPL)": licence(expr.EPL10, false), + "GENERAL PUBLIC LICENSE (GPL)": licence(expr.GPL20, true), + "GNU FREE DOCUMENTATION LICENSE (FDL)": licence(expr.GFDL13, true), + "GNU GENERAL PUBLIC LIBRARY": licence(expr.GPL30, true), + "GNU GENERAL PUBLIC LICENSE (GPL)": licence(expr.GPL30, true), + "GNU GPL": licence(expr.GPL20, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL)": licence(expr.LGPL21, false), + "GNU LESSER GENERAL PUBLIC": licence(expr.LGPL21, false), + "GNU LESSER PUBLIC": licence(expr.LGPL21, false), + "GNU LESSER": licence(expr.LGPL21, false), + "GNU LGPL": licence(expr.LGPL21, false), + "GNU LIBRARY OR LESSER GENERAL PUBLIC LICENSE (LGPL)": licence(expr.LGPL21, false), + "GNU PUBLIC": licence(expr.GPL20, true), + "GPL (WITH DUAL LICENSING OPTION)": licence(expr.GPL20, false), + "GPLV2 WITH EXCEPTIONS": licence(expr.GPL20withclasspathexception, false), + "INDIVIDUAL BSD": licence(expr.BSD3Clause, false), + "LESSER GENERAL PUBLIC LICENSE (LGPL)": licence(expr.LGPL21, true), + "LGPL WITH EXCEPTIONS": licence(expr.LGPL30, false), + "LPGL, SEE LICENSE FILE.": licence(expr.LGPL30, true), + "MOZILLA PUBLIC": licence(expr.MPL20, false), + "ZOPE PUBLIC": licence(expr.ZPL21, false), - // Public Domain - "PUBLIC DOMAIN": Unlicense, + // Non-ambiguous declared mappings + "(NEW) BSD": licence(expr.BSD3Clause, false), + "2-CLAUSE BSD": licence(expr.BSD2Clause, false), + "2-CLAUSE BSDL": licence(expr.BSD2Clause, false), + "3-CLAUSE BDSL": licence(expr.BSD3Clause, false), + "3-CLAUSE BSD": licence(expr.BSD3Clause, false), + "ACADEMIC FREE LICENSE (AFL-2.1": licence(expr.AFL21, false), + "AFFERO GENERAL PUBLIC LICENSE (AGPL-3": licence(expr.AGPL30, false), + "APACHE 2 STYLE": licence(expr.Apache20, false), + "APACHE LICENSE, ASL-2.0": licence(expr.Apache20, false), + "APACHE LICENSE, VERSION 2.0 (HTTP://WWW.APACHE.ORG/LICENSES/LICENSE-2.0": licence(expr.Apache20, false), + "APACHE PUBLIC-1.1": licence(expr.Apache11, false), + "APACHE PUBLIC-2": licence(expr.Apache20, false), + "APACHE PUBLIC-2.0": licence(expr.Apache20, false), + "APACHE SOFTWARE LICENSE (APACHE-2": licence(expr.Apache20, false), + "APACHE SOFTWARE LICENSE (APACHE-2.0": licence(expr.Apache20, false), + "APACHE SOFTWARE-1.1": licence(expr.Apache11, false), + "APACHE SOFTWARE-2": licence(expr.Apache20, false), + "APACHE SOFTWARE-2.0": licence(expr.Apache20, false), + "APACHE VERSION 2.0, JANUARY 2004": licence(expr.Apache20, false), + "APACHE-2.0 */ ' " =END --": licence(expr.Apache20, false), + "BERKELEY SOFTWARE DISTRIBUTION (BSD)": licence(expr.BSD2Clause, false), + "BOOST SOFTWARE LICENSE 1.0 (BSL-1.0": licence(expr.BSL10, false), + "BOOST SOFTWARE": licence(expr.BSL10, false), + "BOUNCY CASTLE": licence(expr.MIT, false), + "BSD (3-CLAUSE)": licence(expr.BSD3Clause, false), + "BSD - SEE NDG/HTTPSCLIENT/LICENSE FILE FOR DETAILS": licence(expr.BSD3Clause, false), + "BSD 2 CLAUSE": licence(expr.BSD2Clause, false), + "BSD 2-CLAUSE": licence(expr.BSD2Clause, false), + "BSD 3 CLAUSE": licence(expr.BSD3Clause, false), + "BSD 3-CLAUSE NEW": licence(expr.BSD3Clause, false), + "BSD 3-CLAUSE \"NEW\" OR \"REVISED\" LICENSE (BSD-3-CLAUSE)": licence(expr.BSD3Clause, false), + "BSD 3-CLAUSE": licence(expr.BSD3Clause, false), + "BSD 4 CLAUSE": licence(expr.BSD4Clause, false), + "BSD 4-CLAUSE": licence(expr.BSD4Clause, false), + "BSD FOUR CLAUSE": licence(expr.BSD4Clause, false), + "BSD LICENSE FOR HSQL": licence(expr.BSD3Clause, false), + "BSD NEW": licence(expr.BSD3Clause, false), + "BSD THREE CLAUSE": licence(expr.BSD3Clause, false), + "BSD TWO CLAUSE": licence(expr.BSD2Clause, false), + "BSD-3 CLAUSE": licence(expr.BSD3Clause, false), + "BSD-STYLE + ATTRIBUTION": licence(expr.BSD3ClauseAttribution, false), + "CC BY-NC-SA-2.0": licence(expr.CCBYNCSA20, false), + "CC BY-NC-SA-2.5": licence(expr.CCBYNCSA25, false), + "CC BY-NC-SA-3.0": licence(expr.CCBYNCSA30, false), + "CC BY-NC-SA-4.0": licence(expr.CCBYNCSA40, false), + "CC BY-SA-2.0": licence(expr.CCBYSA20, false), + "CC BY-SA-2.5": licence(expr.CCBYSA25, false), + "CC BY-SA-3.0": licence(expr.CCBYSA30, false), + "CC BY-SA-4.0": licence(expr.CCBYSA40, false), + "CC0 1.0 UNIVERSAL (CC0 1.0) PUBLIC DOMAIN DEDICATION": licence(expr.CC010, false), + "CC0 1.0 UNIVERSAL": licence(expr.CC010, false), + "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL)-1.0": licence(expr.CDDL10, false), + "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL)-1.1": licence(expr.CDDL11, false), + "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE 1.0 (CDDL-1.0": licence(expr.CDDL10, false), + "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE 1.1 (CDDL-1.1": licence(expr.CDDL11, false), + "COMMON PUBLIC": licence(expr.CPL10, false), + "COMMON PUBLIC-1.0": licence(expr.CPL10, false), + "CREATIVE COMMONS - ATTRIBUTION 4.0 INTERNATIONAL": licence(expr.CCBY40, false), + "CREATIVE COMMONS 3.0 BY-SA": licence(expr.CCBYSA30, false), + "CREATIVE COMMONS ATTRIBUTION 3.0 UNPORTED (CC BY-3.0": licence(expr.CCBY30, false), + "CREATIVE COMMONS ATTRIBUTION 4.0 INTERNATIONAL (CC BY-4.0": licence(expr.CCBY40, false), + "CREATIVE COMMONS ATTRIBUTION 4.0 INTERNATIONAL PUBLIC": licence(expr.CCBY40, false), + "CREATIVE COMMONS ATTRIBUTION-1.0": licence(expr.CCBY10, false), + "CREATIVE COMMONS ATTRIBUTION-2.5": licence(expr.CCBY25, false), + "CREATIVE COMMONS ATTRIBUTION-3.0": licence(expr.CCBY30, false), + "CREATIVE COMMONS ATTRIBUTION-4.0": licence(expr.CCBY40, false), + "CREATIVE COMMONS ATTRIBUTION-NONCOMMERCIAL 4.0 INTERNATIONAL": licence(expr.CCBYNC40, false), + "CREATIVE COMMONS ATTRIBUTION-NONCOMMERCIAL-NODERIVATIVES 4.0 INTERNATIONAL": licence(expr.CCBYNCND40, false), + "CREATIVE COMMONS ATTRIBUTION-NONCOMMERCIAL-SHAREALIKE 3.0 UNPORTED (CC BY-NC-SA-3.0": licence(expr.CCBYNCSA30, false), + "CREATIVE COMMONS ATTRIBUTION-NONCOMMERCIAL-SHAREALIKE 4.0 INTERNATIONAL PUBLIC": licence(expr.CCBYNCSA40, false), + "CREATIVE COMMONS CC0": licence(expr.CC010, false), + "CREATIVE COMMONS GNU LGPL-2.1": licence(expr.LGPL21, false), + "CREATIVE COMMONS LICENSE ATTRIBUTION-NODERIVS 3.0 UNPORTED": licence(expr.CCBYNCND30, false), + "CREATIVE COMMONS LICENSE ATTRIBUTION-NONCOMMERCIAL-SHAREALIKE 3.0 UNPORTED": licence(expr.CCBYNCSA30, false), + "CREATIVE COMMONS ZERO": licence(expr.CC010, false), + "CREATIVE COMMONS-3.0": licence(expr.CCBY30, false), + "ECLIPSE DISTRIBUTION LICENSE (EDL)-1.0": licence(expr.BSD3Clause, false), + "ECLIPSE DISTRIBUTION LICENSE (NEW BSD LICENSE)": licence(expr.BSD3Clause, false), + "ECLIPSE DISTRIBUTION-1.0": licence(expr.BSD3Clause, false), + "ECLIPSE PUBLIC LICENSE (EPL)-1.0": licence(expr.EPL10, false), + "ECLIPSE PUBLIC LICENSE (EPL)-2.0": licence(expr.EPL20, false), + "ECLIPSE PUBLIC LICENSE 1.0 (EPL-1.0": licence(expr.EPL10, false), + "ECLIPSE PUBLIC LICENSE 2.0 (EPL-2.0": licence(expr.EPL20, false), + "ECLIPSE PUBLIC": licence(expr.EPL10, false), + "ECLIPSE PUBLIC-1.0": licence(expr.EPL10, false), + "ECLIPSE PUBLIC-2.0": licence(expr.EPL20, false), + "ECLIPSE PUBLISH-1.0": licence(expr.EPL10, false), + "EPL (ECLIPSE PUBLIC LICENSE)-1.0": licence(expr.EPL10, false), + "EU PUBLIC LICENSE 1.0 (EUPL-1.0": licence(expr.EUPL10, false), + "EU PUBLIC LICENSE 1.1 (EUPL-1.1": licence(expr.EUPL11, false), + "EUROPEAN UNION PUBLIC LICENSE (EUPL-1.0": licence(expr.EUPL10, false), + "EUROPEAN UNION PUBLIC LICENSE (EUPL-1.1": licence(expr.EUPL11, false), + "EUROPEAN UNION PUBLIC LICENSE 1.0 (EUPL-1.0": licence(expr.EUPL10, false), + "EUROPEAN UNION PUBLIC LICENSE 1.1 (EUPL-1.1": licence(expr.EUPL11, false), + "EUROPEAN UNION PUBLIC-1.0": licence(expr.EUPL10, false), + "EUROPEAN UNION PUBLIC-1.1": licence(expr.EUPL11, false), + "EXPAT (MIT/X11)": licence(expr.MIT, false), + "GENERAL PUBLIC LICENSE 2.0 (GPL)": licence(expr.GPL20, false), + "GNU AFFERO GENERAL PUBLIC LICENSE V3 (AGPL-3": licence(expr.AGPL30, false), + "GNU AFFERO GENERAL PUBLIC LICENSE V3 (AGPL-3.0": licence(expr.AGPL30, false), + "GNU AFFERO GENERAL PUBLIC LICENSE V3 OR LATER (AGPL3+)": licence(expr.AGPL30, true), + "GNU AFFERO GENERAL PUBLIC LICENSE V3 OR LATER (AGPLV3+)": licence(expr.AGPL30, true), + "GNU AFFERO GENERAL PUBLIC-3": licence(expr.AGPL30, false), + "GNU FREE DOCUMENTATION LICENSE (GFDL-1.3": licence(expr.GFDL13, false), + "GNU GENERAL LESSER PUBLIC LICENSE (LGPL)-2.1": licence(expr.LGPL21, false), + "GNU GENERAL LESSER PUBLIC LICENSE (LGPL)-3.0": licence(expr.LGPL30, false), + "GNU GENERAL PUBLIC LICENSE (GPL), VERSION 2, WITH CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GNU GENERAL PUBLIC LICENSE (GPL), VERSION 2, WITH THE CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GNU GENERAL PUBLIC LICENSE (GPL)-2": licence(expr.GPL20, false), + "GNU GENERAL PUBLIC LICENSE (GPL)-3": licence(expr.GPL30, false), + "GNU GENERAL PUBLIC LICENSE V2 (GPL-2": licence(expr.GPL20, false), + "GNU GENERAL PUBLIC LICENSE V2 OR LATER (GPLV2+)": licence(expr.GPL20, true), + "GNU GENERAL PUBLIC LICENSE V2.0 ONLY, WITH CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GNU GENERAL PUBLIC LICENSE V3 (GPL-3": licence(expr.GPL30, false), + "GNU GENERAL PUBLIC LICENSE V3 OR LATER (GPLV3+)": licence(expr.GPL30, true), + "GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL-2": licence(expr.GPL20, false), + "GNU GENERAL PUBLIC LICENSE VERSION 2, JUNE 1991": licence(expr.GPL20, false), + "GNU GENERAL PUBLIC LICENSE VERSION 3 (GPL-3": licence(expr.GPL30, false), + "GNU GENERAL PUBLIC LICENSE, VERSION 2 (GPL2), WITH THE CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GNU GENERAL PUBLIC LICENSE, VERSION 2 WITH THE CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GNU GENERAL PUBLIC LICENSE, VERSION 2 WITH THE GNU CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GNU GENERAL PUBLIC LICENSE, VERSION 2, WITH THE CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GNU GENERAL PUBLIC-2": licence(expr.GPL20, false), + "GNU GENERAL PUBLIC-3": licence(expr.GPL30, false), + "GNU GPL-2": licence(expr.GPL20, false), + "GNU GPL-3": licence(expr.GPL30, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL)-2": licence(expr.LGPL20, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL)-2.0": licence(expr.LGPL20, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL)-2.1": licence(expr.LGPL21, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL)-3": licence(expr.LGPL30, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL)-3.0": licence(expr.LGPL30, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL-2": licence(expr.LGPL20, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL-2.0": licence(expr.LGPL20, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL-2.1": licence(expr.LGPL21, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL-3": licence(expr.LGPL30, false), + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL-3.0": licence(expr.LGPL30, false), + "GNU LESSER GENERAL PUBLIC LICENSE V2 (LGPL-2": licence(expr.LGPL20, false), + "GNU LESSER GENERAL PUBLIC LICENSE V2 OR LATER (LGPLV2+)": licence(expr.LGPL20, true), + "GNU LESSER GENERAL PUBLIC LICENSE V3 (LGPL-3": licence(expr.LGPL30, false), + "GNU LESSER GENERAL PUBLIC LICENSE V3 OR LATER (LGPLV3+)": licence(expr.LGPL30, true), + "GNU LESSER GENERAL PUBLIC LICENSE VERSION 2.1 (LGPL-2.1": licence(expr.LGPL21, false), + "GNU LESSER GENERAL PUBLIC LICENSE VERSION 2.1, FEBRUARY 1999": licence(expr.LGPL21, false), + "GNU LESSER GENERAL PUBLIC LICENSE, VERSION 2.1, FEBRUARY 1999": licence(expr.LGPL21, false), + "GNU LESSER GENERAL PUBLIC-2": licence(expr.LGPL20, false), + "GNU LESSER GENERAL PUBLIC-2.0": licence(expr.LGPL20, false), + "GNU LESSER GENERAL PUBLIC-2.1": licence(expr.LGPL21, false), + "GNU LESSER GENERAL PUBLIC-3": licence(expr.LGPL30, false), + "GNU LESSER GENERAL PUBLIC-3.0": licence(expr.LGPL30, false), + "GNU LGP (GNU GENERAL PUBLIC LICENSE)-2": licence(expr.LGPL20, false), + "GNU LGPL (GNU LESSER GENERAL PUBLIC LICENSE)-2.1": licence(expr.LGPL21, false), + "GNU LGPL-2": licence(expr.LGPL20, false), + "GNU LGPL-2.0": licence(expr.LGPL20, false), + "GNU LGPL-2.1": licence(expr.LGPL21, false), + "GNU LGPL-3": licence(expr.LGPL30, false), + "GNU LGPL-3.0": licence(expr.LGPL30, false), + "GNU LIBRARY GENERAL PUBLIC-2.0": licence(expr.LGPL20, false), + "GNU LIBRARY GENERAL PUBLIC-2.1": licence(expr.LGPL21, false), + "GNU LIBRARY OR LESSER GENERAL PUBLIC LICENSE VERSION 2.0 (LGPL-2": licence(expr.LGPL20, false), + "GNU LIBRARY OR LESSER GENERAL PUBLIC LICENSE VERSION 3.0 (LGPL-3": licence(expr.LGPL30, false), + "GPL (≥ 3)": licence(expr.GPL30, true), + "GPL 2 WITH CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GPL V2 WITH CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GPL-2+ WITH AUTOCONF EXCEPTION": licence(expr.GPL20withautoconfexception, true), + "GPL-3+ WITH AUTOCONF EXCEPTION": licence(expr.GPL30withautoconfexception, true), + "GPL2 W/ CPE": licence(expr.GPL20withclasspathexception, false), + "GPLV2 LICENSE, INCLUDES THE CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "GPLV2 WITH CLASSPATH EXCEPTION": licence(expr.GPL20withclasspathexception, false), + "HSQLDB LICENSE, A BSD OPEN SOURCE": licence(expr.BSD3Clause, false), + "HTTP://ANT-CONTRIB.SOURCEFORGE.NET/TASKS/LICENSE.TXT": licence(expr.Apache11, false), + "HTTP://ASM.OW2.ORG/LICENSE.HTML": licence(expr.BSD3Clause, false), + "HTTP://CREATIVECOMMONS.ORG/PUBLICDOMAIN/ZERO/1.0/LEGALCODE": licence(expr.CC010, false), + "HTTP://EN.WIKIPEDIA.ORG/WIKI/ZLIB_LICENSE": licence(expr.Zlib, false), + "HTTP://JSON.CODEPLEX.COM/LICENSE": licence(expr.MIT, false), + "HTTP://POLYMER.GITHUB.IO/LICENSE.TXT": licence(expr.BSD3Clause, false), + "HTTP://WWW.APACHE.ORG/LICENSES/LICENSE-2.0": licence(expr.Apache20, false), + "HTTP://WWW.APACHE.ORG/LICENSES/LICENSE-2.0.HTML": licence(expr.Apache20, false), + "HTTP://WWW.APACHE.ORG/LICENSES/LICENSE-2.0.TXT": licence(expr.Apache20, false), + "HTTP://WWW.GNU.ORG/COPYLEFT/LESSER.HTML": licence(expr.LGPL30, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-ND/1.0": licence(expr.CCBYNCND10, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-ND/2.0": licence(expr.CCBYNCND20, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-ND/2.5": licence(expr.CCBYNCND25, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-ND/3.0": licence(expr.CCBYNCND30, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-ND/4.0": licence(expr.CCBYNCND40, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-SA/1.0": licence(expr.CCBYNCSA10, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-SA/2.0": licence(expr.CCBYNCSA20, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-SA/2.5": licence(expr.CCBYNCSA25, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-SA/3.0": licence(expr.CCBYNCSA30, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-NC-SA/4.0": licence(expr.CCBYNCSA40, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-ND/1.0": licence(expr.CCBYND10, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-ND/2.0": licence(expr.CCBYND20, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-ND/2.5": licence(expr.CCBYND25, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-ND/3.0": licence(expr.CCBYND30, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-ND/4.0": licence(expr.CCBYND40, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-SA/1.0": licence(expr.CCBYSA10, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-SA/2.0": licence(expr.CCBYSA20, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-SA/2.5": licence(expr.CCBYSA25, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-SA/3.0": licence(expr.CCBYSA30, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY-SA/4.0": licence(expr.CCBYSA40, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY/1.0": licence(expr.CCBY10, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY/2.0": licence(expr.CCBY20, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY/2.5": licence(expr.CCBY25, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY/3.0": licence(expr.CCBY30, false), + "HTTPS://CREATIVECOMMONS.ORG/LICENSES/BY/4.0": licence(expr.CCBY40, false), + "HTTPS://CREATIVECOMMONS.ORG/PUBLICDOMAIN/ZERO/1.0/": licence(expr.CC010, false), + "HTTPS://GITHUB.COM/DOTNET/CORE-SETUP/BLOB/MASTER/LICENSE.TXT": licence(expr.MIT, false), + "HTTPS://GITHUB.COM/DOTNET/COREFX/BLOB/MASTER/LICENSE.TXT": licence(expr.MIT, false), + "HTTPS://RAW.GITHUB.COM/RDFLIB/RDFLIB/MASTER/LICENSE": licence(expr.BSD3Clause, false), + "HTTPS://RAW.GITHUBUSERCONTENT.COM/ASPNET/ASPNETCORE/2.0.0/LICENSE.TXT": licence(expr.Apache20, false), + "HTTPS://RAW.GITHUBUSERCONTENT.COM/ASPNET/HOME/2.0.0/LICENSE.TXT": licence(expr.Apache20, false), + "HTTPS://RAW.GITHUBUSERCONTENT.COM/NUGET/NUGET.CLIENT/DEV/LICENSE.TXT": licence(expr.Apache20, false), + "HTTPS://WWW.APACHE.ORG/LICENSES/LICENSE-2.0": licence(expr.Apache20, false), + "HTTPS://WWW.ECLIPSE.ORG/LEGAL/EPL-V10.HTML": licence(expr.EPL10, false), + "HTTPS://WWW.ECLIPSE.ORG/LEGAL/EPL-V20.HTML": licence(expr.EPL20, false), + "IBM PUBLIC": licence(expr.IPL10, false), + "ISC LICENSE (ISCL)": licence(expr.ISC, false), + "JYTHON SOFTWARE": licence(expr.Python20, false), + "KIRKK.COM BSD": licence(expr.BSD3Clause, false), + "LESSER GENERAL PUBLIC LICENSE, VERSION 3 OR GREATER": licence(expr.LGPL30, true), + "LICENSE AGREEMENT FOR OPEN SOURCE COMPUTER VISION LIBRARY (3-CLAUSE BSD LICENSE)": licence(expr.BSD3Clause, false), + "MIT (HTTP://MOOTOOLS.NET/LICENSE.TXT)": licence(expr.MIT, false), + "MIT / HTTP://REM.MIT-LICENSE.ORG": licence(expr.MIT, false), + "MIT LICENSE (HTTP://OPENSOURCE.ORG/LICENSES/MIT)": licence(expr.MIT, false), + "MIT LICENSE (MIT)": licence(expr.MIT, false), + "MIT LICENSE(MIT)": licence(expr.MIT, false), + "MIT LICENSED. HTTP://WWW.OPENSOURCE.ORG/LICENSES/MIT-LICENSE.PHP": licence(expr.MIT, false), + "MIT/EXPAT": licence(expr.MIT, false), + "MOCKRUNNER LICENSE, BASED ON APACHE SOFTWARE-1.1": licence(expr.Apache11, false), + "MODIFIED BSD": licence(expr.BSD3Clause, false), + "MOZILLA PUBLIC LICENSE 1.0 (MPL)": licence(expr.MPL10, false), + "MOZILLA PUBLIC LICENSE 1.1 (MPL-1.1": licence(expr.MPL11, false), + "MOZILLA PUBLIC LICENSE 2.0 (MPL-2.0": licence(expr.MPL20, false), + "MOZILLA PUBLIC-1.0": licence(expr.MPL10, false), + "MOZILLA PUBLIC-1.1": licence(expr.MPL11, false), + "MOZILLA PUBLIC-2.0": licence(expr.MPL20, false), + "NCSA OPEN SOURCE": licence(expr.NCSA, false), + "NETSCAPE PUBLIC LICENSE (NPL)": licence(expr.NPL10, false), + "NETSCAPE PUBLIC": licence(expr.NPL10, false), + "NEW BSD": licence(expr.BSD3Clause, false), + "OPEN SOFTWARE LICENSE 3.0 (OSL-3.0": licence(expr.OSL30, false), + "OPEN SOFTWARE-3.0": licence(expr.OSL30, false), + "PERL ARTISTIC-2": licence(expr.Artistic10Perl, false), + // Note: public domain without a specific license should not be mapped + // see https://wiki.spdx.org/view/Legal_Team/Decisions/Dealing_with_Public_Domain_within_SPDX_Files + // and https://opensource.google/documentation/reference/thirdparty/licenses#unencumbered + "PUBLIC DOMAIN (CC0-1.0)": licence(expr.CC010, false), + "PUBLIC DOMAIN, PER CREATIVE COMMONS CC0": licence(expr.CC010, false), + "QT PUBLIC LICENSE (QPL)": licence(expr.QPL10, false), + "QT PUBLIC": licence(expr.QPL10, false), + "REVISED BSD": licence(expr.BSD3Clause, false), + "RUBY'S": licence(expr.Ruby, false), + "SEQUENCE LIBRARY LICENSE (BSD-LIKE)": licence(expr.BSD3Clause, false), + "SIL OPEN FONT LICENSE 1.1 (OFL-1.1": licence(expr.OFL11, false), + "SIL OPEN FONT-1.1": licence(expr.OFL11, false), + "SIMPLIFIED BSD LISCENCE": licence(expr.BSD2Clause, false), + "SIMPLIFIED BSD": licence(expr.BSD2Clause, false), + "SUN INDUSTRY STANDARDS SOURCE LICENSE (SISSL)": licence(expr.SISSL, false), + "THREE-CLAUSE BSD-STYLE": licence(expr.BSD3Clause, false), + "TWO-CLAUSE BSD-STYLE": licence(expr.BSD2Clause, false), + "UNIVERSAL PERMISSIVE LICENSE (UPL)": licence(expr.UPL10, false), + "UNIVERSAL PERMISSIVE-1.0": licence(expr.UPL10, false), + "UNLICENSE (UNLICENSE)": licence(expr.Unlicense, false), + "W3C SOFTWARE": licence(expr.W3C, false), + "ZLIB / LIBPNG": licence(expr.ZlibAcknowledgement, false), + "ZLIB/LIBPNG": licence(expr.ZlibAcknowledgement, false), + "['MIT']": licence(expr.MIT, false), } const ( @@ -181,8 +590,6 @@ var pythonLicenseExceptions = map[string]string{ // 'BSD-3-CLAUSE and GPL-2' => {"BSD-3-CLAUSE", "GPL-2"} // 'GPL-1+ or Artistic, and BSD-4-clause-POWERDOG' => {"GPL-1+", "Artistic", "BSD-4-clause-POWERDOG"} // 'BSD 3-Clause License or Apache License, Version 2.0' => {"BSD 3-Clause License", "Apache License, Version 2.0"} -// var LicenseSplitRegexp = regexp.MustCompile("(,?[_ ]+or[_ ]+)|(,?[_ ]+and[_ ])|(,[ ]*)") - var licenseSplitRegexp = regexp.MustCompile("(,?[_ ]+(?:or|and)[_ ]+)|(,[ ]*)") // Typical keywords for license texts @@ -218,12 +625,65 @@ func TrimLicenseText(text string) string { return strings.Join(s[:n], " ") + "..." } -func Normalize(name string) string { +// version number match +var versionRegexpString = "([A-UW-Z)]{2,})( LICENSE)?\\s*[,(-]?\\s*(V|V\\.|VER|VER\\.|VERSION|VERSION-|-)?\\s*([1-9](\\.\\d)*)[)]?" + +// case insensitive version match anywhere in string +var versionRegexp = regexp.MustCompile("(?i)" + versionRegexpString) + +// version suffix match +var versionSuffixRegexp = regexp.MustCompile(versionRegexpString + "$") + +// suffixes from https://spdx.dev/learn/handling-license-info/ +var onlySuffixes = [2]string{"-ONLY", " ONLY"} +var plusSuffixes = [3]string{"+", "-OR-LATER", " OR LATER"} + +func standardizeKeyAndSuffix(name string) expr.SimpleExpr { + // Standardize space, including newline + name = strings.Join(strings.Fields(name), " ") name = strings.TrimSpace(name) - if l, ok := mapping[strings.ToUpper(name)]; ok { - return l + name = strings.ToUpper(name) + // Do not perform any further normalization for URLs + if strings.HasPrefix(name, "HTTP") { + return expr.SimpleExpr{License: name, HasPlus: false} + } + name = strings.ReplaceAll(name, "LICENCE", "LICENSE") + name = strings.TrimPrefix(name, "THE ") + name = strings.TrimSuffix(name, " LICENSE") + name = strings.TrimSuffix(name, " LICENSED") + name = strings.TrimSuffix(name, "-LICENSE") + name = strings.TrimSuffix(name, "-LICENSED") + // Remove License and Licensed suffixes except for licenses already containing those suffixes such as Unlicense + if name != "UNLICENSE" { + name = strings.TrimSuffix(name, "LICENSE") + } + if name != "UNLICENSED" { + name = strings.TrimSuffix(name, "LICENSED") + } + hasPlus := false + for _, s := range plusSuffixes { + if strings.HasSuffix(name, s) { + name = strings.TrimSuffix(name, s) + hasPlus = true + } } - return name + for _, s := range onlySuffixes { + name = strings.TrimSuffix(name, s) + } + name = versionSuffixRegexp.ReplaceAllString(name, "$1-$4") + return expr.SimpleExpr{License: name, HasPlus: hasPlus} +} + +func Normalize(name string) string { + return NormalizeLicense(name).String() +} + +func NormalizeLicense(name string) expr.SimpleExpr { + normalized := standardizeKeyAndSuffix(name) + if found, ok := mapping[normalized.License]; ok { + return expr.SimpleExpr{License: found.License, HasPlus: found.HasPlus || normalized.HasPlus} + } + return expr.SimpleExpr{License: name, HasPlus: false} } func SplitLicenses(str string) []string { @@ -261,3 +721,25 @@ func SplitLicenses(str string) []string { } return licenses } + +// Split license string considering spaces as separator +// e.g. MPL 2.0 GPL2+ => {"MPL2.0", "GPL2+"} +func LaxSplitLicenses(str string) []string { + if str == "" { + return nil + } + var licenses []string + str = versionRegexp.ReplaceAllString(str, "$1-$4") + for _, s := range strings.Fields(str) { + s = strings.Trim(s, "()") + switch { + case s == "": + continue + case s == "AND" || s == "OR": + continue + default: + licenses = append(licenses, Normalize(s)) + } + } + return licenses +} diff --git a/pkg/licensing/normalize_private_test.go b/pkg/licensing/normalize_private_test.go new file mode 100644 index 000000000000..68d62f241944 --- /dev/null +++ b/pkg/licensing/normalize_private_test.go @@ -0,0 +1,18 @@ +package licensing + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// All map keys must be standardized to be matched +// (uppercase, no common suffixes, standardized version, etc.) +func TestMap(t *testing.T) { + for key := range mapping { + t.Run(key, func(t *testing.T) { + standardized := standardizeKeyAndSuffix(key) + assert.Equal(t, standardized.License, key) + }) + } +} diff --git a/pkg/licensing/normalize_test.go b/pkg/licensing/normalize_test.go index 16fa9eac6250..9b47fd923f29 100644 --- a/pkg/licensing/normalize_test.go +++ b/pkg/licensing/normalize_test.go @@ -8,6 +8,220 @@ import ( "github.com/aquasecurity/trivy/pkg/licensing" ) +func TestNormalize(t *testing.T) { + tests := []struct { + licenses []string + normalized string + normalizedKey string + }{ + { + licenses: []string{ + " the apache license ", + " the\tapache \r\nlicense \r\n ", + " apache ", + "ApacheLicence", + "ApacheLicense", + "al-2", + "al-v2", + "al2", + "alv2", + "apache - v 2.0", + "apache - v. 2.0", + "apache - ver 2.0", + "apache - version 2.0", + "apache 2", + "apache 2.0", + "apache license (2.0)", + "apache license (v. 2)", + "apache license (v. 2.0)", + "apache license (v2)", + "apache license (v2.0)", + "apache license (version 2.0)", + "apache license 2", + "apache license 2.0", + "apache license v2", + "apache license v2.0", + "apache license version 2", + "apache license version 2.0", + "apache license", + "apache license, 2.0", + "apache license, asl version 2.0", + "apache license, version 2", + "apache license, version 2.0 (http://www.apache.org/licenses/license-2.0)", + "apache license, version 2.0", + "apache license,version 2.0", + "apache license,version-2.0", + "apache license-2.0", + "apache public 2.0", + "apache public license 2.0", + "apache public license-2.0", + "apache public-2", + "apache public-2.0", + "apache software license (apache-2.0)", + "apache software license - version 2.0", + "apache software license 2.0", + "apache software license, version 2", + "apache software license, version 2.0", + "apache software-2.0", + "apache v 2.0", + "apache v. 2.0", + "apache v2", + "apache v2.0", + "apache ver 2.0", + "apache ver. 2.0", + "apache version 2.0", + "apache version 2.0, january 2004", + "apache version-2", + "apache version-2.0", + "apache", + "apache, 2", + "apache, v2.0", + "apache, version 2", + "apache, version 2.0", + "apache-2", + "apache-2.0", + "apache-licence", + "apache-license", + "apache-licensed", + "apache-licensed", + "asf 2.0", + "asl 2", + "asl, version 2", + "asl2.0", + "the apache license", + "the apache license", + }, + normalized: "Apache-2.0", + normalizedKey: "Apache-2.0", + }, + { + licenses: []string{ + "Apache+", + }, + normalized: "Apache-2.0+", + normalizedKey: "Apache-2.0", + }, + { + licenses: []string{ + "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) V1.1", + "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) VERSION 1.1", + "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL), VERSION 1.1", + "COMMON DEVELOPMENT AND DISTRIBUTION LICENSE 1.1 (CDDL-1.1)", + }, + normalized: "CDDL-1.1", + normalizedKey: "CDDL-1.1", + }, + { + licenses: []string{ + "ECLIPSE PUBLIC LICENSE (EPL) 1.0", + "ECLIPSE PUBLIC LICENSE (EPL), VERSION 1.0", + "ECLIPSE PUBLIC LICENSE - V 1.0", + "ECLIPSE PUBLIC LICENSE - V1.0", + "ECLIPSE PUBLIC LICENSE - VERSION 1.0", + "ECLIPSE PUBLIC LICENSE 1.0 (EPL-1.0)", + "ECLIPSE PUBLIC LICENSE 1.0", + "ECLIPSE PUBLIC LICENSE V. 1.0", + "ECLIPSE PUBLIC LICENSE V1.0", + "ECLIPSE PUBLIC LICENSE VERSION 1.0", + "ECLIPSE PUBLIC LICENSE, VERSION 1.0", + "ECLIPSE PUBLIC", + }, + normalized: "EPL-1.0", + normalizedKey: "EPL-1.0", + }, + { + licenses: []string{ + "EUROPEAN UNION PUBLIC LICENSE (EUPL V.1.1)", + "EUROPEAN UNION PUBLIC LICENSE 1.1 (EUPL 1.1)", + "EUROPEAN UNION PUBLIC LICENSE 1.1", + "EUROPEAN UNION PUBLIC LICENSE, VERSION 1.1", + }, + normalized: "EUPL-1.1", + normalizedKey: "EUPL-1.1", + }, + { + licenses: []string{ + "GPL-or-later", + "GPL+", + "GPL-2.0-only+", + }, + normalized: "GPL-2.0-or-later", + normalizedKey: "GPL-2.0", + }, + { + licenses: []string{ + "GPL (≥ 3)", + "GPL3+", + "GPL3-or-later", + "GPL3 or later licence", + }, + normalized: "GPL-3.0-or-later", + normalizedKey: "GPL-3.0", + }, + { + licenses: []string{ + "GNU GENERAL PUBLIC LICENSE 3", + "GNU GENERAL PUBLIC LICENSE (GPL) V. 3", + "GNU GENERAL PUBLIC LICENSE VERSION 3 (GPL V3)", + }, + normalized: "GPL-3.0-only", + normalizedKey: "GPL-3.0", + }, + + { + licenses: []string{ + "LGPL LICENSE-3", + "GNU LESSER GENERAL PUBLIC LICENSE V3", + "GNU LESSER GENERAL PUBLIC LICENSE V3.0", + "GNU LESSER GENERAL PUBLIC LICENSE VERSION 3", + "GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0", + "GNU LESSER GENERAL PUBLIC LICENSE, VERSION 3.0", + "GNU LIBRARY OR LESSER GENERAL PUBLIC LICENSE VERSION 3.0 (LGPLV3)", + "GNU GENERAL LESSER PUBLIC LICENSE (LGPL) VERSION 3.0", + "GNU LESSER GENERAL PUBLIC LICENSE (LGPL), VERSION 3", + }, + normalized: "LGPL-3.0-only", + normalizedKey: "LGPL-3.0", + }, + { + licenses: []string{ + "The Unlicense", + "Unlicense", + "Unlicensed", + "UNLICENSE", + "UNLICENSED", + }, + normalized: "Unlicense", + normalizedKey: "Unlicense", + }, + { + licenses: []string{ + "MIT License", + "http://json.codeplex.com/license", + }, + normalized: "MIT", + normalizedKey: "MIT", + }, + { + licenses: []string{ + " The unmapped license ", + }, + normalized: " The unmapped license ", + normalizedKey: " The unmapped license ", + }, + } + for _, tt := range tests { + t.Run(tt.normalized, func(t *testing.T) { + for _, ll := range tt.licenses { + normalized := licensing.Normalize(ll) + normalizedKey := licensing.NormalizeLicense(ll).License + assert.Equal(t, tt.normalized, normalized) + assert.Equal(t, tt.normalizedKey, normalizedKey) + } + }) + } +} + func TestSplitLicenses(t *testing.T) { tests := []struct { name string @@ -113,3 +327,28 @@ func TestSplitLicenses(t *testing.T) { }) } } + +func TestLaxSplitLicense(t *testing.T) { + var tests = []struct { + license string + wantLicenses []string + }{ + { + license: "ASL 2.0", + wantLicenses: []string{"Apache-2.0"}, + }, + { + license: "MPL 2.0 GPL2+", + wantLicenses: []string{ + "MPL-2.0", + "GPL-2.0-or-later", + }, + }, + } + for _, tt := range tests { + t.Run(tt.license, func(t *testing.T) { + parsed := licensing.LaxSplitLicenses(tt.license) + assert.Equal(t, tt.wantLicenses, parsed) + }) + } +} diff --git a/pkg/licensing/scanner.go b/pkg/licensing/scanner.go index 100358a5af6c..1a8ed8e1d9f0 100644 --- a/pkg/licensing/scanner.go +++ b/pkg/licensing/scanner.go @@ -21,8 +21,9 @@ func NewScanner(categories map[types.LicenseCategory][]string) Scanner { } func (s *Scanner) Scan(licenseName string) (types.LicenseCategory, string) { + license := NormalizeLicense(licenseName) for category, names := range s.categories { - if slices.Contains(names, licenseName) { + if slices.Contains(names, license.License) { return category, categoryToSeverity(category).String() } } diff --git a/pkg/licensing/scanner_test.go b/pkg/licensing/scanner_test.go index fce93f3c5337..992992e48f9a 100644 --- a/pkg/licensing/scanner_test.go +++ b/pkg/licensing/scanner_test.go @@ -7,6 +7,7 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/licensing" + "github.com/aquasecurity/trivy/pkg/licensing/expression" ) func TestScanner_Scan(t *testing.T) { @@ -21,11 +22,11 @@ func TestScanner_Scan(t *testing.T) { name: "forbidden", categories: map[types.LicenseCategory][]string{ types.CategoryForbidden: { - licensing.BSD3Clause, - licensing.Apache20, + expression.BSD3Clause, + expression.Apache20, }, }, - licenseName: licensing.Apache20, + licenseName: expression.Apache20, wantCategory: types.CategoryForbidden, wantSeverity: "CRITICAL", }, @@ -33,21 +34,21 @@ func TestScanner_Scan(t *testing.T) { name: "restricted", categories: map[types.LicenseCategory][]string{ types.CategoryForbidden: { - licensing.GPL30, + expression.GPL30, }, types.CategoryRestricted: { - licensing.BSD3Clause, - licensing.Apache20, + expression.BSD3Clause, + expression.Apache20, }, }, - licenseName: licensing.BSD3Clause, + licenseName: expression.BSD3Clause, wantCategory: types.CategoryRestricted, wantSeverity: "HIGH", }, { name: "unknown", categories: make(map[types.LicenseCategory][]string), - licenseName: licensing.BSD3Clause, + licenseName: expression.BSD3Clause, wantCategory: types.CategoryUnknown, wantSeverity: "UNKNOWN", }, diff --git a/pkg/sbom/spdx/marshal.go b/pkg/sbom/spdx/marshal.go index 33952ab41441..809ce95d7e4c 100644 --- a/pkg/sbom/spdx/marshal.go +++ b/pkg/sbom/spdx/marshal.go @@ -547,7 +547,7 @@ func NormalizeLicense(licenses []string) string { return fmt.Sprintf("(%s)", license) }), " AND ") - s, err := expression.Normalize(license, licensing.Normalize, expression.NormalizeForSPDX) + s, err := expression.Normalize(license, licensing.NormalizeLicense, expression.NormalizeForSPDX) if err != nil { // Not fail on the invalid license log.Warn("Unable to marshal SPDX licenses", log.String("license", license)) diff --git a/pkg/sbom/spdx/marshal_test.go b/pkg/sbom/spdx/marshal_test.go index ef64cf4651d5..74e9bee0a45d 100644 --- a/pkg/sbom/spdx/marshal_test.go +++ b/pkg/sbom/spdx/marshal_test.go @@ -11,6 +11,7 @@ import ( "github.com/package-url/packageurl-go" "github.com/spdx/tools-golang/spdx" "github.com/spdx/tools-golang/spdx/v2/common" + "github.com/spdx/tools-golang/spdxlib" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -1329,6 +1330,7 @@ func TestMarshaler_Marshal(t *testing.T) { spdxDoc, err := marshaler.MarshalReport(ctx, tc.inputReport) require.NoError(t, err) + assert.NoError(t, spdxlib.ValidateDocument(spdxDoc)) assert.Equal(t, tc.wantSBOM, spdxDoc) }) } @@ -1361,7 +1363,7 @@ func Test_GetLicense(t *testing.T) { "GPLv2+", "LGPL 2.0 or GNU LESSER", }, - want: "GPL-2.0-or-later AND (LGPL-2.0-only OR LGPL-3.0-only)", + want: "GPL-2.0-or-later AND (LGPL-2.0-only OR LGPL-2.1-only)", }, { name: "happy path with AND operator", @@ -1369,7 +1371,7 @@ func Test_GetLicense(t *testing.T) { "GPLv2+", "LGPL 2.0 and GNU LESSER", }, - want: "GPL-2.0-or-later AND LGPL-2.0-only AND LGPL-3.0-only", + want: "GPL-2.0-or-later AND LGPL-2.0-only AND LGPL-2.1-only", }, { name: "happy path with WITH operator", From 8876e7065554648a6a85def697559933d9a55706 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Wed, 11 Sep 2024 12:52:01 +0400 Subject: [PATCH 079/183] docs(db): add a manifest example (#7485) Signed-off-by: knqyf263 --- docs/docs/configuration/db.md | 43 +++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/docs/docs/configuration/db.md b/docs/docs/configuration/db.md index 5fa4046668a9..ccffae1e5302 100644 --- a/docs/docs/configuration/db.md +++ b/docs/docs/configuration/db.md @@ -53,15 +53,44 @@ $ trivy image --download-db-only ``` $ trivy image --db-repository registry.gitlab.com/gitlab-org/security-products/dependencies/trivy-db ``` + +The media type of the OCI layer must be `application/vnd.aquasec.trivy.db.layer.v1.tar+gzip`. +You can reference the OCI manifest of [trivy-db]. + +
+Manifest + +```shell +{ + "schemaVersion": 2, + "mediaType": "application/vnd.oci.image.manifest.v1+json", + "config": { + "mediaType": "application/vnd.aquasec.trivy.config.v1+json", + "digest": "sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a", + "size": 2 + }, + "layers": [ + { + "mediaType": "application/vnd.aquasec.trivy.db.layer.v1.tar+gzip", + "digest": "sha256:29ad6505b8957c7cd4c367e7c705c641a9020d2be256812c5f4cc2fc099f4f02", + "size": 55474933, + "annotations": { + "org.opencontainers.image.title": "db.tar.gz" + } + } + ], + "annotations": { + "org.opencontainers.image.created": "2024-09-11T06:14:51Z" + } +} +``` +
+ !!!note Trivy automatically adds the `trivy-db` schema version as a tag if the tag is not used: `trivy-db-registry:latest` => `trivy-db-registry:latest`, but `trivy-db-registry` => `trivy-db-registry:2`. -!!!note - Trivy expects the OCI Artifacts to have a Specific media type: - - Vulnerability DB `application/vnd.aquasec.trivy.db.layer.v1.tar+gzip` - - Java DB `application/vnd.aquasec.trivy.javadb.layer.v1.tar+gzip` ## Java Index Database The same options are also available for the Java index DB, which is used for scanning Java applications. @@ -76,6 +105,9 @@ Downloading the Java index DB from an external OCI registry can be done by using $ trivy image --java-db-repository registry.gitlab.com/gitlab-org/security-products/dependencies/trivy-java-db --download-java-db-only ``` +The media type of the OCI layer must be `application/vnd.aquasec.trivy.javadb.layer.v1.tar+gzip`. +You can reference the OCI manifest of [trivy-java-db]. + !!!note Trivy automatically adds the `trivy-java-db` schema version as a tag if the tag is not used: @@ -89,3 +121,6 @@ $ trivy clean --vuln-db --java-db 2024-06-24T11:42:31+06:00 INFO Removing vulnerability database... 2024-06-24T11:42:31+06:00 INFO Removing Java database... ``` + +[trivy-db]: https://github.com/aquasecurity/trivy-db/pkgs/container/trivy-db +[trivy-java-db]: https://github.com/aquasecurity/trivy-java-db/pkgs/container/trivy-java-db \ No newline at end of file From b0222feeb586ec59904bb321fda8f3f22496d07b Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Thu, 12 Sep 2024 11:10:13 +0600 Subject: [PATCH 080/183] revert(java): stop supporting of `test` scope for `pom.xml` files (#7488) --- docs/docs/coverage/language/java.md | 18 ++++-------- pkg/dependency/parser/java/pom/artifact.go | 1 - pkg/dependency/parser/java/pom/parse.go | 4 +-- pkg/dependency/parser/java/pom/parse_test.go | 28 ------------------- pkg/dependency/parser/java/pom/pom.go | 1 - .../parser/java/pom/testdata/happy/pom.xml | 6 ---- 6 files changed, 7 insertions(+), 51 deletions(-) diff --git a/docs/docs/coverage/language/java.md b/docs/docs/coverage/language/java.md index 26bad288e552..67cd8c135b9d 100644 --- a/docs/docs/coverage/language/java.md +++ b/docs/docs/coverage/language/java.md @@ -12,12 +12,12 @@ Each artifact supports the following scanners: The following table provides an outline of the features Trivy offers. -| Artifact | Internet access | Dev dependencies | [Dependency graph][dependency-graph] | Position | [Detection Priority][detection-priority] | -|------------------|:---------------------:|:------------------:|:------------------------------------:|:--------:|:----------------------------------------:| -| JAR/WAR/PAR/EAR | Trivy Java DB | Include | - | - | Not needed | -| pom.xml | Maven repository [^1] | [Exclude](#scopes) | ✓ | ✓[^7] | - | -| *gradle.lockfile | - | Exclude | ✓ | ✓ | Not needed | -| *.sbt.lock | - | Exclude | - | ✓ | Not needed | +| Artifact | Internet access | Dev dependencies | [Dependency graph][dependency-graph] | Position | [Detection Priority][detection-priority] | +|------------------|:---------------------:|:----------------:|:------------------------------------:|:--------:|:----------------------------------------:| +| JAR/WAR/PAR/EAR | Trivy Java DB | Include | - | - | Not needed | +| pom.xml | Maven repository [^1] | Exclude | ✓ | ✓[^7] | - | +| *gradle.lockfile | - | Exclude | ✓ | ✓ | Not needed | +| *.sbt.lock | - | Exclude | - | ✓ | Not needed | These may be enabled or disabled depending on the target. See [here](./index.md) for the detail. @@ -69,11 +69,6 @@ The vulnerability database will be downloaded anyway. !!! Warning Trivy may skip some dependencies (that were not found on your local machine) when the `--offline-scan` flag is passed. -### scopes -Trivy supports `runtime`, `compile`, `test` and `import` (for `dependencyManagement`) [dependency scopes][dependency-scopes]. -Dependencies without scope are also detected. - -By default, Trivy doesn't report dependencies with `test` scope. Use the `--include-dev-deps` flag to include them. ### maven-invoker-plugin Typically, the integration tests directory (`**/[src|target]/it/*/pom.xml`) of [maven-invoker-plugin][maven-invoker-plugin] doesn't contain actual `pom.xml` files and should be skipped to avoid noise. @@ -125,4 +120,3 @@ Make sure that you have cache[^8] directory to find licenses from `*.pom` depend [maven-pom-repos]: https://maven.apache.org/settings.html#repositories [sbt-dependency-lock]: https://stringbean.github.io/sbt-dependency-lock [detection-priority]: ../../scanner/vulnerability.md#detection-priority -[dependency-scopes]: https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope diff --git a/pkg/dependency/parser/java/pom/artifact.go b/pkg/dependency/parser/java/pom/artifact.go index f691afac5ebd..b2e97efb229b 100644 --- a/pkg/dependency/parser/java/pom/artifact.go +++ b/pkg/dependency/parser/java/pom/artifact.go @@ -27,7 +27,6 @@ type artifact struct { Module bool Relationship ftypes.Relationship - Test bool Locations ftypes.Locations } diff --git a/pkg/dependency/parser/java/pom/parse.go b/pkg/dependency/parser/java/pom/parse.go index 46c859538529..1add19a4b53b 100644 --- a/pkg/dependency/parser/java/pom/parse.go +++ b/pkg/dependency/parser/java/pom/parse.go @@ -214,7 +214,6 @@ func (p *Parser) parseRoot(root artifact, uniqModules map[string]struct{}) ([]ft Licenses: result.artifact.Licenses, Relationship: art.Relationship, Locations: art.Locations, - Test: art.Test, } // save only dependency names @@ -235,7 +234,6 @@ func (p *Parser) parseRoot(root artifact, uniqModules map[string]struct{}) ([]ft Licenses: art.Licenses, Relationship: art.Relationship, Locations: art.Locations, - Dev: art.Test, } pkgs = append(pkgs, pkg) @@ -402,7 +400,7 @@ func (p *Parser) parseDependencies(deps []pomDependency, props map[string]string // Resolve dependencies d = d.Resolve(props, depManagement, rootDepManagement) - if (d.Scope != "" && d.Scope != "compile" && d.Scope != "runtime" && d.Scope != "test") || d.Optional { + if (d.Scope != "" && d.Scope != "compile" && d.Scope != "runtime") || d.Optional { continue } diff --git a/pkg/dependency/parser/java/pom/parse_test.go b/pkg/dependency/parser/java/pom/parse_test.go index 77a47b5ecdac..934085d5d536 100644 --- a/pkg/dependency/parser/java/pom/parse_test.go +++ b/pkg/dependency/parser/java/pom/parse_test.go @@ -61,19 +61,6 @@ func TestPom_Parse(t *testing.T) { }, }, }, - { - ID: "org.example:example-test:2.0.0", - Name: "org.example:example-test", - Version: "2.0.0", - Relationship: ftypes.RelationshipDirect, - Dev: true, - Locations: ftypes.Locations{ - { - StartLine: 49, - EndLine: 54, - }, - }, - }, }, wantDeps: []ftypes.Dependency{ { @@ -81,7 +68,6 @@ func TestPom_Parse(t *testing.T) { DependsOn: []string{ "org.example:example-api:1.7.30", "org.example:example-runtime:1.0.0", - "org.example:example-test:2.0.0", }, }, }, @@ -123,19 +109,6 @@ func TestPom_Parse(t *testing.T) { }, }, }, - { - ID: "org.example:example-test:2.0.0", - Name: "org.example:example-test", - Version: "2.0.0", - Relationship: ftypes.RelationshipDirect, - Dev: true, - Locations: ftypes.Locations{ - { - StartLine: 49, - EndLine: 54, - }, - }, - }, }, wantDeps: []ftypes.Dependency{ { @@ -143,7 +116,6 @@ func TestPom_Parse(t *testing.T) { DependsOn: []string{ "org.example:example-api:1.7.30", "org.example:example-runtime:1.0.0", - "org.example:example-test:2.0.0", }, }, }, diff --git a/pkg/dependency/parser/java/pom/pom.go b/pkg/dependency/parser/java/pom/pom.go index d27f995217d6..889d107c3c6c 100644 --- a/pkg/dependency/parser/java/pom/pom.go +++ b/pkg/dependency/parser/java/pom/pom.go @@ -303,7 +303,6 @@ func (d pomDependency) ToArtifact(opts analysisOptions) artifact { Exclusions: exclusions, Locations: locations, Relationship: ftypes.RelationshipIndirect, // default - Test: d.Scope == "test", } } diff --git a/pkg/dependency/parser/java/pom/testdata/happy/pom.xml b/pkg/dependency/parser/java/pom/testdata/happy/pom.xml index 9dfc1c75bd65..1f3c9697a17d 100644 --- a/pkg/dependency/parser/java/pom/testdata/happy/pom.xml +++ b/pkg/dependency/parser/java/pom/testdata/happy/pom.xml @@ -46,11 +46,5 @@ 999 provided - - org.example - example-test - 2.0.0 - test - From 04a854c3373952cc555bb4c2877d7cb0c4eb8335 Mon Sep 17 00:00:00 2001 From: Itay Shakury Date: Thu, 12 Sep 2024 10:10:23 +0300 Subject: [PATCH 081/183] docs: refine go docs (#7442) Signed-off-by: knqyf263 Co-authored-by: knqyf263 --- docs/docs/coverage/language/golang.md | 109 +++++++++++++++----------- 1 file changed, 62 insertions(+), 47 deletions(-) diff --git a/docs/docs/coverage/language/golang.md b/docs/docs/coverage/language/golang.md index f2cbff03255a..cd1a30c53e9c 100644 --- a/docs/docs/coverage/language/golang.md +++ b/docs/docs/coverage/language/golang.md @@ -1,32 +1,31 @@ # Go -## Data Sources -The data sources are listed [here](../../scanner/vulnerability.md#data-sources-1). -Trivy uses Go Vulnerability Database for standard packages, such as `net/http`, and uses GitHub Advisory Database for third-party packages. - -## Features +## Overview Trivy supports two types of Go scanning, Go Modules and binaries built by Go. The following scanners are supported. -| Artifact | SBOM | Vulnerability | License | -| -------- | :---: | :-----------: | :-----: | -| Modules | ✓ | ✓ | ✓[^2] | -| Binaries | ✓ | ✓ | - | +| Artifact | SBOM | Vulnerability | License | +|----------|:----:|:-------------:|:-------------:| +| Modules | ✓ | ✓ | [✓](#license) | +| Binaries | ✓ | ✓ | - | The table below provides an outline of the features Trivy offers. -| Artifact | Offline[^1] | Dev dependencies | [Dependency graph][dependency-graph] | Stdlib | [Detection Priority][detection-priority] | -|----------|:-----------:|:-----------------|:------------------------------------:|:------:|:----------------------------------------:| -| Modules | ✅ | Include | ✅[^2] | ✅[^6] | [✅](#stdlib) | -| Binaries | ✅ | Exclude | - | ✅[^4] | Not needed | +| Artifact | Offline[^1] | Dev dependencies | [Dependency graph][dependency-graph] | Stdlib | [Detection Priority][detection-priority] | +|----------|:-----------:|:-----------------|:------------------------------------:|:------------------------:|:----------------------------------------:| +| Modules | ✅ | Include | [✅](#dependency-graph) | [✅](#standard-library) | [✅](#standard-library) | +| Binaries | ✅ | Exclude | - | [✅](#standard-library-1) | Not needed | !!! note - Trivy scans only dependencies of the Go project. - Let's say you scan the Docker binary, Trivy doesn't detect vulnerabilities of Docker itself. - Also, when you scan go.mod in Kubernetes, the Kubernetes vulnerabilities will not be found. + When scanning Go projects (go.mod or binaries built with Go), Trivy scans only dependencies of the project, and does not detect vulnerabilities of application itself. + For example, when scanning the Docker project (Docker's source code with go.mod or the Docker binary), Trivy might find vulnerabilities in Go modules that Docker depends on, but won't find vulnerabilities of Docker itself. Moreover, when scanning the Trivy project, which happens to use Docker, Docker's vulnerabilities might be detected as dependencies of Trivy. -### Go Modules +## Data Sources +The data sources are listed [here](../../scanner/vulnerability.md#data-sources-1). +Trivy uses Go Vulnerability Database for [standard library](https://pkg.go.dev/std) and uses GitHub Advisory Database for other Go modules. + +## Go Module Depending on Go versions, the required files are different. | Version | Required files | Offline | @@ -42,7 +41,7 @@ Go 1.17+ holds actually needed indirect dependencies in `go.mod`, and it reduces If you want to have better detection, please consider updating the Go version in your project. !!! note - The Go version doesn't mean your CLI version, but the Go version in your go.mod. + The Go version doesn't mean your Go tool version, but the Go version in your go.mod. ``` module github.com/aquasecurity/trivy @@ -61,32 +60,37 @@ If you want to have better detection, please consider updating the Go version in $ go mod tidy -go=1.18 ``` -To identify licenses and dependency relationships, you need to download modules to local cache beforehand, -such as `go mod download`, `go mod tidy`, etc. -Trivy traverses `$GOPATH/pkg/mod` and collects those extra information. - -#### stdlib -If [--detection-priority comprehensive][detection-priority] is passed, Trivy determines the minimum version of `Go` and saves it as a `stdlib` dependency. - -By default, `Go` selects the higher version from of `toolchan` or local version of `Go`. -See [toolchain] for more details. +### Main Module +Trivy scans only dependencies of the project, and does not detect vulnerabilities of the main module. +For example, when scanning the Docker project (Docker's source code with go.mod), Trivy might find vulnerabilities in Go modules that Docker depends on, but won't find vulnerabilities of Docker itself. +Moreover, when scanning the Trivy project, which happens to use Docker, Docker's vulnerabilities might be detected as dependencies of Trivy. -To obtain reproducible scan results Trivy doesn't check the local version of `Go`. -Trivy shows the minimum required version for the `go.mod` file, obtained from `toolchain` line (or from the `go` line, if `toolchain` line is omitted). +### Standard Library +Detecting the version of Go used in the project can be tricky. +The go.mod file include hints that allows Trivy to guess the Go version but it eventually depends on the Go tool version in the build environment. +Since this strategy is not fully deterministic and accurate, it is enabled only in [--detection-priority comprehensive][detection-priority] mode. +When enabled, Trivy detects stdlib version as the minimum between the `go` and the `toolchain` directives in the `go.mod` file. +To obtain reproducible scan results Trivy doesn't check the locally installed version of `Go`. !!! note Trivy detects `stdlib` only for `Go` 1.21 or higher. The version from the `go` line (for `Go` 1.20 or early) is not a minimum required version. For details, see [this](https://go.googlesource.com/proposal/+/master/design/57001-gotoolchain.md). - - -### Go binaries -Trivy scans binaries built by Go, which include [module information](https://tip.golang.org/doc/go1.18#go-version). -If there is a Go binary in your container image, Trivy automatically finds and scans it. +It possibly produces false positives. +See [the caveat](#stdlib-vulnerabilities) for details. + +### License +To identify licenses, you need to download modules to local cache beforehand, such as `go mod download`, `go mod tidy`, etc. +Trivy traverses `$GOPATH/pkg/mod` and collects those extra information. + +### Dependency Graph +Same as licenses, you need to download modules to local cache beforehand. -Also, you can scan your local binaries. +## Go Binary +Trivy scans Go binaries when it encounters them during scans such as container images or file systems. +When scanning binaries built by Go, Trivy finds dependencies and Go version information as [embedded in the binary by Go tool at build time](https://tip.golang.org/doc/go1.18#go-version). ``` $ trivy rootfs ./your_binary @@ -95,22 +99,33 @@ $ trivy rootfs ./your_binary !!! note It doesn't work with UPX-compressed binaries. -#### Empty versions -There are times when Go uses the `(devel)` version for modules/dependencies. +### Main Module +Go binaries installed using the `go install` command contains correct (semver) version for the main module and therefor are detected by Trivy. +In other cases, Go uses the `(devel)` version[^2]. +In this case, Trivy will attempt to parse any `-ldflags` as it's a common practice to pass versions this way. +If unsuccessful, the version will be empty[^3]. + +### Standard Library +Trivy detects the Go version used to compile the binary and detects its vulnerabilities in the standard libraries. +It possibly produces false positives. +See [the caveat](#stdlib-vulnerabilities) for details. + +## Caveats + +### Stdlib Vulnerabilities +Trivy does not know if or how you use stdlib functions, therefore it is possible that stdlib vulnerabilities are not applicable to your use case. +There are a few ways to mitigate this: -- Only Go binaries installed using the `go install` command contain correct (semver) version for the main module. - In other cases, Go uses the `(devel)` version[^3]. -- Dependencies replaced with local ones use the `(devel)` versions. +1. Analyze vulnerability reachability using a tool such as [govulncheck](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck). This will ensure that reported vulnerabilities are applicable to your project. +2. Suppress non-applicable vulnerabilities using either [ignore file](../../configuration/filtering.md) for self-use or [VEX Hub](../../supply-chain/vex/repo.md) for public use. -In the first case, Trivy will attempt to parse any `-ldflags` as a secondary source, and will leave the version -empty if it cannot do so[^5]. For the second case, the version of such packages is empty. +### Empty Version +As described in the [Main Module](#main-module-1) section, the main module of Go binaries might have an empty version. +Also, dependencies replaced with local ones will have an empty version. [^1]: It doesn't require the Internet access. -[^2]: Need to download modules to local cache beforehand -[^3]: See https://github.com/aquasecurity/trivy/issues/1837#issuecomment-1832523477 -[^4]: Identify the Go version used to compile the binary and detect its vulnerabilities -[^5]: See https://github.com/golang/go/issues/63432#issuecomment-1751610604 -[^6]: Only available if `toolchain` directive exists +[^2]: See https://github.com/aquasecurity/trivy/issues/1837#issuecomment-1832523477 +[^3]: See https://github.com/golang/go/issues/63432#issuecomment-1751610604 [dependency-graph]: ../../configuration/reporting.md#show-origins-of-vulnerable-dependencies [toolchain]: https://go.dev/doc/toolchain From 42748c40372863a7f233be75f7cd21d9947a52aa Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Mon, 16 Sep 2024 09:50:52 +0400 Subject: [PATCH 082/183] chore(vex): suppress openssl vulnerabilities (#7500) Signed-off-by: knqyf263 --- .vex/oci.openvex.json | 99 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/.vex/oci.openvex.json b/.vex/oci.openvex.json index b689d43afac1..f1ec8a32df48 100644 --- a/.vex/oci.openvex.json +++ b/.vex/oci.openvex.json @@ -140,6 +140,105 @@ "status": "not_affected", "justification": "vulnerable_code_cannot_be_controlled_by_adversary", "impact_statement": "awk is not used" + }, + { + "vulnerability": { + "name": "CVE-2024-4741" + }, + "products": [ + { + "@id": "pkg:oci/trivy?repository_url=index.docker.io%2Faquasec%2Ftrivy", + "subcomponents": [ + {"@id": "pkg:apk/alpine/libcrypto3"}, + {"@id": "pkg:apk/alpine/libssl3"}, + {"@id": "pkg:apk/alpine/ssl_client"} + ] + }, + { + "@id": "pkg:oci/trivy?repository_url=public.ecr.aws%2Faquasecurity%2Ftrivy", + "subcomponents": [ + {"@id": "pkg:apk/alpine/libcrypto3"}, + {"@id": "pkg:apk/alpine/libssl3"}, + {"@id": "pkg:apk/alpine/ssl_client"} + ] + }, + { + "@id": "pkg:oci/trivy?repository_url=ghcr.io/aquasecurity/trivy", + "subcomponents": [ + {"@id": "pkg:apk/alpine/libcrypto3"}, + {"@id": "pkg:apk/alpine/libssl3"}, + {"@id": "pkg:apk/alpine/ssl_client"} + ] + } + ], + "status": "not_affected", + "justification": "vulnerable_code_cannot_be_controlled_by_adversary", + "impact_statement": "openssl is not used" + }, + { + "vulnerability": { + "name": "CVE-2024-5535" + }, + "products": [ + { + "@id": "pkg:oci/trivy?repository_url=index.docker.io%2Faquasec%2Ftrivy", + "subcomponents": [ + {"@id": "pkg:apk/alpine/libcrypto3"}, + {"@id": "pkg:apk/alpine/libssl3"}, + {"@id": "pkg:apk/alpine/ssl_client"} + ] + }, + { + "@id": "pkg:oci/trivy?repository_url=public.ecr.aws%2Faquasecurity%2Ftrivy", + "subcomponents": [ + {"@id": "pkg:apk/alpine/libcrypto3"}, + {"@id": "pkg:apk/alpine/libssl3"}, + {"@id": "pkg:apk/alpine/ssl_client"} + ] + }, + { + "@id": "pkg:oci/trivy?repository_url=ghcr.io/aquasecurity/trivy", + "subcomponents": [ + {"@id": "pkg:apk/alpine/libcrypto3"}, + {"@id": "pkg:apk/alpine/libssl3"}, + {"@id": "pkg:apk/alpine/ssl_client"} + ] + } + ], + "status": "not_affected", + "justification": "vulnerable_code_cannot_be_controlled_by_adversary", + "impact_statement": "openssl is not used" + }, + { + "vulnerability": { + "name": "CVE-2024-6119" + }, + "products": [ + { + "@id": "pkg:oci/trivy?repository_url=index.docker.io%2Faquasec%2Ftrivy", + "subcomponents": [ + {"@id": "pkg:apk/alpine/libcrypto3"}, + {"@id": "pkg:apk/alpine/libssl3"} + ] + }, + { + "@id": "pkg:oci/trivy?repository_url=public.ecr.aws%2Faquasecurity%2Ftrivy", + "subcomponents": [ + {"@id": "pkg:apk/alpine/libcrypto3"}, + {"@id": "pkg:apk/alpine/libssl3"} + ] + }, + { + "@id": "pkg:oci/trivy?repository_url=ghcr.io/aquasecurity/trivy", + "subcomponents": [ + {"@id": "pkg:apk/alpine/libcrypto3"}, + {"@id": "pkg:apk/alpine/libssl3"} + ] + } + ], + "status": "not_affected", + "justification": "vulnerable_code_cannot_be_controlled_by_adversary", + "impact_statement": "openssl is not used" } ] } From 701dbdaa5d20dbd1911a4c62f7b2f41d218028fe Mon Sep 17 00:00:00 2001 From: Lior Kaplan Date: Mon, 16 Sep 2024 09:29:55 +0300 Subject: [PATCH 083/183] chore(deps): bump alpine from 3.20.0 to 3.20.3 (#7508) --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 9e4dfe3b1dbe..1113c80aa9d5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:3.20.0 +FROM alpine:3.20.3 RUN apk --no-cache add ca-certificates git COPY trivy /usr/local/bin/trivy COPY contrib/*.tpl contrib/ From 0efd2027244aacde4380c47f579bfb5b5cb6997f Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Mon, 16 Sep 2024 13:44:56 +0600 Subject: [PATCH 084/183] chore(vex): add `CVE-2024-34155`, `CVE-2024-34156` and `CVE-2024-34158` in `trivy.openvex.json` (#7510) --- .vex/trivy.openvex.json | 87 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/.vex/trivy.openvex.json b/.vex/trivy.openvex.json index 21af61db7d76..2dd1629ecc89 100644 --- a/.vex/trivy.openvex.json +++ b/.vex/trivy.openvex.json @@ -453,6 +453,93 @@ "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-2024-3105", + "name": "GO-2024-3105", + "description": "Stack exhaustion in all Parse functions in go/parser", + "aliases": [ + "CVE-2024-34155" + ] + }, + "products": [ + { + "@id": "pkg:golang/github.com/aquasecurity/trivy", + "identifiers": { + "purl": "pkg:golang/github.com/aquasecurity/trivy" + }, + "subcomponents": [ + { + "@id": "pkg:golang/stdlib", + "identifiers": { + "purl": "pkg:golang/stdlib" + } + } + ] + } + ], + "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-2024-3106", + "name": "GO-2024-3106", + "description": "Stack exhaustion in Decoder.Decode in encoding/gob", + "aliases": [ + "CVE-2024-34156" + ] + }, + "products": [ + { + "@id": "pkg:golang/github.com/aquasecurity/trivy", + "identifiers": { + "purl": "pkg:golang/github.com/aquasecurity/trivy" + }, + "subcomponents": [ + { + "@id": "pkg:golang/stdlib", + "identifiers": { + "purl": "pkg:golang/stdlib" + } + } + ] + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_in_execute_path", + "impact_statement": "Govulncheck incorrectly marks this vulnerability as affected. The vulnerable code isn't called. See https://github.com/aquasecurity/trivy/issues/7478" + }, + { + "vulnerability": { + "@id": "https://pkg.go.dev/vuln/GO-2024-3107", + "name": "GO-2024-3107", + "description": "Stack exhaustion in Parse in go/build/constraint", + "aliases": [ + "CVE-2024-34158" + ] + }, + "products": [ + { + "@id": "pkg:golang/github.com/aquasecurity/trivy", + "identifiers": { + "purl": "pkg:golang/github.com/aquasecurity/trivy" + }, + "subcomponents": [ + { + "@id": "pkg:golang/stdlib", + "identifiers": { + "purl": "pkg:golang/stdlib" + } + } + ] + } + ], + "status": "not_affected", + "justification": "vulnerable_code_not_in_execute_path", + "impact_statement": "Govulncheck determined that the vulnerable code isn't called" } ] } From 54429497e7d6a87eac236771d4efb8a5a7faaac5 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Mon, 16 Sep 2024 17:14:28 +0600 Subject: [PATCH 085/183] fix(java): use `dependencyManagement` from root/child pom's for dependencies from parents (#7497) --- pkg/dependency/parser/java/pom/parse.go | 20 +++- pkg/dependency/parser/java/pom/parse_test.go | 96 +++++++++++++++++++ .../2.0.0/example-dependency-2.0.0.pom | 26 +++++ .../3.0.0/example-parent-3.0.0.pom | 32 +++++++ .../pom.xml | 21 ++++ .../use-root-dep-management-in-parent/pom.xml | 31 ++++++ 6 files changed, 223 insertions(+), 3 deletions(-) create mode 100644 pkg/dependency/parser/java/pom/testdata/repository/org/example/example-dependency/2.0.0/example-dependency-2.0.0.pom create mode 100644 pkg/dependency/parser/java/pom/testdata/repository/org/example/example-parent/3.0.0/example-parent-3.0.0.pom create mode 100644 pkg/dependency/parser/java/pom/testdata/use-dep-management-from-child-in-parent/pom.xml create mode 100644 pkg/dependency/parser/java/pom/testdata/use-root-dep-management-in-parent/pom.xml diff --git a/pkg/dependency/parser/java/pom/parse.go b/pkg/dependency/parser/java/pom/parse.go index 1add19a4b53b..76ca37f2dd05 100644 --- a/pkg/dependency/parser/java/pom/parse.go +++ b/pkg/dependency/parser/java/pom/parse.go @@ -335,8 +335,20 @@ func (p *Parser) analyze(pom *pom, opts analysisOptions) (analysisResult, error) p.releaseRemoteRepos = lo.Uniq(append(pomReleaseRemoteRepos, p.releaseRemoteRepos...)) p.snapshotRemoteRepos = lo.Uniq(append(pomSnapshotRemoteRepos, p.snapshotRemoteRepos...)) + // We need to forward dependencyManagements from current and root pom to Parent, + // to use them for dependencies in parent. + // For better understanding see the following tests: + // - `dependency from parent uses version from child pom depManagement` + // - `dependency from parent uses version from root pom depManagement` + // + // depManagements from root pom has higher priority than depManagements from current pom. + depManagementForParent := lo.UniqBy(append(opts.depManagement, pom.content.DependencyManagement.Dependencies.Dependency...), + func(dep pomDependency) string { + return dep.Name() + }) + // Parent - parent, err := p.parseParent(pom.filePath, pom.content.Parent) + parent, err := p.parseParent(pom.filePath, pom.content.Parent, depManagementForParent) if err != nil { return analysisResult{}, xerrors.Errorf("parent error: %w", err) } @@ -477,7 +489,7 @@ func excludeDep(exclusions map[string]struct{}, art artifact) bool { return false } -func (p *Parser) parseParent(currentPath string, parent pomParent) (analysisResult, error) { +func (p *Parser) parseParent(currentPath string, parent pomParent, rootDepManagement []pomDependency) (analysisResult, error) { // Pass nil properties so that variables in are not evaluated. target := newArtifact(parent.GroupId, parent.ArtifactId, parent.Version, nil, nil) // if version is property (e.g. ${revision}) - we still need to parse this pom @@ -499,7 +511,9 @@ func (p *Parser) parseParent(currentPath string, parent pomParent) (analysisResu logger.Debug("Parent POM not found", log.Err(err)) } - result, err := p.analyze(parentPOM, analysisOptions{}) + result, err := p.analyze(parentPOM, analysisOptions{ + depManagement: rootDepManagement, + }) if err != nil { return analysisResult{}, xerrors.Errorf("analyze error: %w", err) } diff --git a/pkg/dependency/parser/java/pom/parse_test.go b/pkg/dependency/parser/java/pom/parse_test.go index 934085d5d536..9fa97ffd3672 100644 --- a/pkg/dependency/parser/java/pom/parse_test.go +++ b/pkg/dependency/parser/java/pom/parse_test.go @@ -1499,6 +1499,102 @@ func TestPom_Parse(t *testing.T) { }, }, }, + // [INFO] com.example:root-depManagement-in-parent:jar:1.0.0 + // [INFO] \- org.example:example-dependency:jar:2.0.0:compile + // [INFO] \- org.example:example-api:jar:1.0.1:compile + { + name: "dependency from parent uses version from root pom depManagement", + inputFile: filepath.Join("testdata", "use-root-dep-management-in-parent", "pom.xml"), + local: true, + want: []ftypes.Package{ + { + ID: "com.example:root-depManagement-in-parent:1.0.0", + Name: "com.example:root-depManagement-in-parent", + Version: "1.0.0", + Relationship: ftypes.RelationshipRoot, + }, + { + ID: "org.example:example-dependency:2.0.0", + Name: "org.example:example-dependency", + Version: "2.0.0", + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ + { + StartLine: 25, + EndLine: 29, + }, + }, + }, + { + ID: "org.example:example-api:1.0.1", + Name: "org.example:example-api", + Version: "1.0.1", + Relationship: ftypes.RelationshipIndirect, + }, + }, + wantDeps: []ftypes.Dependency{ + { + ID: "com.example:root-depManagement-in-parent:1.0.0", + DependsOn: []string{ + "org.example:example-dependency:2.0.0", + }, + }, + { + ID: "org.example:example-dependency:2.0.0", + DependsOn: []string{ + "org.example:example-api:1.0.1", + }, + }, + }, + }, + // [INFO] com.example:root-depManagement-in-parent:jar:1.0.0 + // [INFO] \- org.example:example-dependency:jar:2.0.0:compile + // [INFO] \- org.example:example-api:jar:2.0.1:compile + { + name: "dependency from parent uses version from child pom depManagement", + inputFile: filepath.Join("testdata", "use-dep-management-from-child-in-parent", "pom.xml"), + local: true, + want: []ftypes.Package{ + { + ID: "com.example:root-depManagement-in-parent:1.0.0", + Name: "com.example:root-depManagement-in-parent", + Version: "1.0.0", + Relationship: ftypes.RelationshipRoot, + }, + { + ID: "org.example:example-dependency:2.0.0", + Name: "org.example:example-dependency", + Version: "2.0.0", + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ + { + StartLine: 15, + EndLine: 19, + }, + }, + }, + { + ID: "org.example:example-api:2.0.1", + Name: "org.example:example-api", + Version: "2.0.1", + Relationship: ftypes.RelationshipIndirect, + }, + }, + wantDeps: []ftypes.Dependency{ + { + ID: "com.example:root-depManagement-in-parent:1.0.0", + DependsOn: []string{ + "org.example:example-dependency:2.0.0", + }, + }, + { + ID: "org.example:example-dependency:2.0.0", + DependsOn: []string{ + "org.example:example-api:2.0.1", + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-dependency/2.0.0/example-dependency-2.0.0.pom b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-dependency/2.0.0/example-dependency-2.0.0.pom new file mode 100644 index 000000000000..3f236cdf314e --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-dependency/2.0.0/example-dependency-2.0.0.pom @@ -0,0 +1,26 @@ + + + 4.0.0 + + + org.example + example-parent + 3.0.0 + + + org.example + example-dependency + 2.0.0 + + + + + org.example + example-api + 2.0.1 + + + + + \ No newline at end of file diff --git a/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-parent/3.0.0/example-parent-3.0.0.pom b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-parent/3.0.0/example-parent-3.0.0.pom new file mode 100644 index 000000000000..917908d53d7b --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-parent/3.0.0/example-parent-3.0.0.pom @@ -0,0 +1,32 @@ + + + + 4.0.0 + + org.example + example-parent + 3.0.0 + pom + + + 3.0.1 + + + + + + org.example + example-api + ${api.version} + + + + + + + org.example + example-api + + + \ No newline at end of file diff --git a/pkg/dependency/parser/java/pom/testdata/use-dep-management-from-child-in-parent/pom.xml b/pkg/dependency/parser/java/pom/testdata/use-dep-management-from-child-in-parent/pom.xml new file mode 100644 index 000000000000..5d062242161d --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/use-dep-management-from-child-in-parent/pom.xml @@ -0,0 +1,21 @@ + + 4.0.0 + + com.example + root-depManagement-in-parent + 1.0.0 + + + + 1.0.1 + + + + + org.example + example-dependency + 2.0.0 + + + diff --git a/pkg/dependency/parser/java/pom/testdata/use-root-dep-management-in-parent/pom.xml b/pkg/dependency/parser/java/pom/testdata/use-root-dep-management-in-parent/pom.xml new file mode 100644 index 000000000000..685a7fc7caf3 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/use-root-dep-management-in-parent/pom.xml @@ -0,0 +1,31 @@ + + 4.0.0 + + com.example + root-depManagement-in-parent + 1.0.0 + + + + 1.0.1 + + + + + + org.example + example-api + ${api.version} + + + + + + + org.example + example-dependency + 2.0.0 + + + From e6f45cd48f2c436336f3bc70c6b1b565ddff7707 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Mon, 16 Sep 2024 17:23:41 +0600 Subject: [PATCH 086/183] refactor: split `.egg` and `packaging` analyzers (#7514) --- pkg/fanal/analyzer/const.go | 9 +- .../analyzer/language/python/packaging/egg.go | 126 +++++++++++++++ .../language/python/packaging/egg_test.go | 146 ++++++++++++++++++ .../language/python/packaging/packaging.go | 111 ++++--------- .../python/packaging/packaging_test.go | 27 ---- .../sample_package.egg | Bin 0 -> 1135 bytes 6 files changed, 311 insertions(+), 108 deletions(-) create mode 100644 pkg/fanal/analyzer/language/python/packaging/egg.go create mode 100644 pkg/fanal/analyzer/language/python/packaging/egg_test.go create mode 100644 pkg/fanal/analyzer/language/python/packaging/testdata/egg-zip-with-license-file/sample_package.egg diff --git a/pkg/fanal/analyzer/const.go b/pkg/fanal/analyzer/const.go index ea2108e89281..197c0033296e 100644 --- a/pkg/fanal/analyzer/const.go +++ b/pkg/fanal/analyzer/const.go @@ -75,10 +75,11 @@ const ( TypeCondaEnv Type = "conda-environment" // Python - TypePythonPkg Type = "python-pkg" - TypePip Type = "pip" - TypePipenv Type = "pipenv" - TypePoetry Type = "poetry" + TypePythonPkg Type = "python-pkg" + TypePythonPkgEgg Type = "python-egg" + TypePip Type = "pip" + TypePipenv Type = "pipenv" + TypePoetry Type = "poetry" // Go TypeGoBinary Type = "gobinary" diff --git a/pkg/fanal/analyzer/language/python/packaging/egg.go b/pkg/fanal/analyzer/language/python/packaging/egg.go new file mode 100644 index 000000000000..1de53980260e --- /dev/null +++ b/pkg/fanal/analyzer/language/python/packaging/egg.go @@ -0,0 +1,126 @@ +package packaging + +import ( + "archive/zip" + "context" + "io" + "os" + "path" + "path/filepath" + + "github.com/samber/lo" + "golang.org/x/xerrors" + + "github.com/aquasecurity/trivy/pkg/dependency/parser/python/packaging" + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" + "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" + "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/log" + xio "github.com/aquasecurity/trivy/pkg/x/io" +) + +func init() { + analyzer.RegisterAnalyzer(&eggAnalyzer{}) +} + +const ( + eggAnalyzerVersion = 1 + eggExt = ".egg" +) + +type eggAnalyzer struct { + logger *log.Logger + licenseClassifierConfidenceLevel float64 +} + +func (a *eggAnalyzer) Init(opt analyzer.AnalyzerOptions) error { + a.logger = log.WithPrefix("python") + a.licenseClassifierConfidenceLevel = opt.LicenseScannerOption.ClassifierConfidenceLevel + return nil +} + +// Analyze analyzes egg archive files +func (a *eggAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) { + // .egg file is zip format and PKG-INFO needs to be extracted from the zip file. + pkginfoInZip, err := findFileInZip(input.Content, input.Info.Size(), isEggFile) + if err != nil { + return nil, xerrors.Errorf("unable to open `.egg` archive: %w", err) + } + + // Egg archive may not contain required files, then we will get nil. Skip this archives + if pkginfoInZip == nil { + return nil, nil + } + + rsa, err := xio.NewReadSeekerAt(pkginfoInZip) + if err != nil { + return nil, xerrors.Errorf("unable to convert PKG-INFO reader: %w", err) + } + + app, err := language.ParsePackage(types.PythonPkg, input.FilePath, rsa, packaging.NewParser(), input.Options.FileChecksum) + if err != nil { + return nil, xerrors.Errorf("parse error: %w", err) + } else if app == nil { + return nil, nil + } + + opener := func(licPath string) (io.ReadCloser, error) { + required := func(filePath string) bool { + return path.Base(filePath) == licPath + } + + f, err := findFileInZip(input.Content, input.Info.Size(), required) + if err != nil { + return nil, xerrors.Errorf("unable to find license file in `*.egg` file: %w", err) + } else if f == nil { // zip doesn't contain license file + return nil, nil + } + + return f, nil + } + + if err = fillAdditionalData(opener, app, a.licenseClassifierConfidenceLevel); err != nil { + a.logger.Warn("Unable to collect additional info", log.Err(err)) + } + + return &analyzer.AnalysisResult{ + Applications: []types.Application{*app}, + }, nil +} + +func findFileInZip(r xio.ReadSeekerAt, zipSize int64, required func(filePath string) bool) (io.ReadCloser, error) { + if _, err := r.Seek(0, io.SeekStart); err != nil { + return nil, xerrors.Errorf("file seek error: %w", err) + } + + zr, err := zip.NewReader(r, zipSize) + if err != nil { + return nil, xerrors.Errorf("zip reader error: %w", err) + } + + found, ok := lo.Find(zr.File, func(f *zip.File) bool { + return required(f.Name) + }) + if !ok { + return nil, nil + } + + f, err := found.Open() + if err != nil { + return nil, xerrors.Errorf("unable to open file in zip: %w", err) + } + + return f, nil +} + +func (a *eggAnalyzer) Required(filePath string, _ os.FileInfo) bool { + return filepath.Ext(filePath) == eggExt +} + +func (a *eggAnalyzer) Type() analyzer.Type { + return analyzer.TypePythonPkgEgg +} + +func (a *eggAnalyzer) Version() int { + return eggAnalyzerVersion +} diff --git a/pkg/fanal/analyzer/language/python/packaging/egg_test.go b/pkg/fanal/analyzer/language/python/packaging/egg_test.go new file mode 100644 index 000000000000..615dffb4b0cc --- /dev/null +++ b/pkg/fanal/analyzer/language/python/packaging/egg_test.go @@ -0,0 +1,146 @@ +package packaging + +import ( + "context" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" + "github.com/aquasecurity/trivy/pkg/fanal/types" +) + +func Test_eggAnalyzer_Analyze(t *testing.T) { + tests := []struct { + name string + inputFile string + includeChecksum bool + want *analyzer.AnalysisResult + wantErr string + }{ + { + name: "egg zip", + inputFile: "testdata/egg-zip/kitchen-1.2.6-py2.7.egg", + want: &analyzer.AnalysisResult{ + Applications: []types.Application{ + { + Type: types.PythonPkg, + FilePath: "testdata/egg-zip/kitchen-1.2.6-py2.7.egg", + Packages: types.Packages{ + { + Name: "kitchen", + Version: "1.2.6", + Licenses: []string{ + "LGPL-2.1-only", + }, + FilePath: "testdata/egg-zip/kitchen-1.2.6-py2.7.egg", + }, + }, + }, + }, + }, + }, + { + name: "egg zip with checksum", + inputFile: "testdata/egg-zip/kitchen-1.2.6-py2.7.egg", + includeChecksum: true, + want: &analyzer.AnalysisResult{ + Applications: []types.Application{ + { + Type: types.PythonPkg, + FilePath: "testdata/egg-zip/kitchen-1.2.6-py2.7.egg", + Packages: types.Packages{ + { + Name: "kitchen", + Version: "1.2.6", + Licenses: []string{ + "LGPL-2.1-only", + }, + FilePath: "testdata/egg-zip/kitchen-1.2.6-py2.7.egg", + Digest: "sha1:4e13b6e379966771e896ee43cf8e240bf6083dca", + }, + }, + }, + }, + }, + }, + { + name: "egg zip with license file", + inputFile: "testdata/egg-zip-with-license-file/sample_package.egg", + want: &analyzer.AnalysisResult{ + Applications: []types.Application{ + { + Type: types.PythonPkg, + FilePath: "testdata/egg-zip-with-license-file/sample_package.egg", + Packages: types.Packages{ + { + Name: "sample_package", + Version: "0.1", + Licenses: []string{ + "MIT", + }, + FilePath: "testdata/egg-zip-with-license-file/sample_package.egg", + }, + }, + }, + }, + }, + }, + { + name: "egg zip doesn't contain required files", + inputFile: "testdata/no-req-files/no-required-files.egg", + want: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + f, err := os.Open(tt.inputFile) + require.NoError(t, err) + defer f.Close() + fileInfo, err := os.Lstat(tt.inputFile) + require.NoError(t, err) + + a := &eggAnalyzer{} + got, err := a.Analyze(context.Background(), analyzer.AnalysisInput{ + Content: f, + FilePath: tt.inputFile, + Info: fileInfo, + Options: analyzer.AnalysisOptions{ + FileChecksum: tt.includeChecksum, + }, + }) + + require.NoError(t, err) + assert.Equal(t, tt.want, got) + }) + } + +} + +func Test_eggAnalyzer_Required(t *testing.T) { + tests := []struct { + name string + filePath string + want bool + }{ + { + name: "egg zip", + filePath: "python2.7/site-packages/cssutils-1.0-py2.7.egg", + want: true, + }, + { + name: "egg-info PKG-INFO", + filePath: "python3.8/site-packages/wrapt-1.12.1.egg-info/PKG-INFO", + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := eggAnalyzer{} + got := a.Required(tt.filePath, nil) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/pkg/fanal/analyzer/language/python/packaging/packaging.go b/pkg/fanal/analyzer/language/python/packaging/packaging.go index 73e5f446bc40..944a5abde331 100644 --- a/pkg/fanal/analyzer/language/python/packaging/packaging.go +++ b/pkg/fanal/analyzer/language/python/packaging/packaging.go @@ -1,8 +1,6 @@ package packaging import ( - "archive/zip" - "bytes" "context" "errors" "io" @@ -29,7 +27,7 @@ func init() { analyzer.RegisterPostAnalyzer(analyzer.TypePythonPkg, newPackagingAnalyzer) } -const version = 1 +const version = 2 func newPackagingAnalyzer(opt analyzer.AnalyzerOptions) (analyzer.PostAnalyzer, error) { return &packagingAnalyzer{ @@ -43,7 +41,7 @@ var ( eggFiles = []string{ // .egg format // https://setuptools.readthedocs.io/en/latest/deprecated/python_eggs.html#eggs-and-their-formats - ".egg", // zip format + // ".egg" is zip format. We check it in `eggAnalyzer`. "EGG-INFO/PKG-INFO", // .egg-info format: .egg-info can be a file or directory @@ -68,38 +66,32 @@ func (a packagingAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAna return filepath.Base(path) == "METADATA" || isEggFile(path) } - err := fsutils.WalkDir(input.FS, ".", required, func(path string, d fs.DirEntry, r io.Reader) error { + err := fsutils.WalkDir(input.FS, ".", required, func(filePath string, d fs.DirEntry, r io.Reader) error { rsa, ok := r.(xio.ReadSeekerAt) if !ok { return xerrors.New("invalid reader") } - // .egg file is zip format and PKG-INFO needs to be extracted from the zip file. - if strings.HasSuffix(path, ".egg") { - info, err := d.Info() - if err != nil { - return xerrors.Errorf("egg file error: %w", err) - } - pkginfoInZip, err := a.analyzeEggZip(rsa, info.Size()) - if err != nil { - return xerrors.Errorf("egg analysis error: %w", err) - } - - // Egg archive may not contain required files, then we will get nil. Skip this archives - if pkginfoInZip == nil { - return nil - } - rsa = pkginfoInZip - } - - app, err := a.parse(path, rsa, input.Options.FileChecksum) + app, err := a.parse(filePath, rsa, input.Options.FileChecksum) if err != nil { return xerrors.Errorf("parse error: %w", err) } else if app == nil { return nil } - if err := a.fillAdditionalData(input.FS, app); err != nil { + opener := func(licPath string) (io.ReadCloser, error) { + // Note that fs.FS is always slashed regardless of the platform, + // and path.Join should be used rather than filepath.Join. + f, err := input.FS.Open(path.Join(path.Dir(filePath), licPath)) + if errors.Is(err, fs.ErrNotExist) { + return nil, nil + } else if err != nil { + return nil, xerrors.Errorf("file open error: %w", err) + } + return f, nil + } + + if err = fillAdditionalData(opener, app, a.licenseClassifierConfidenceLevel); err != nil { a.logger.Warn("Unable to collect additional info", log.Err(err)) } @@ -115,7 +107,9 @@ func (a packagingAnalyzer) PostAnalyze(_ context.Context, input analyzer.PostAna }, nil } -func (a packagingAnalyzer) fillAdditionalData(fsys fs.FS, app *types.Application) error { +type fileOpener func(filePath string) (io.ReadCloser, error) + +func fillAdditionalData(opener fileOpener, app *types.Application, licenseClassifierConfidenceLevel float64) error { for i, pkg := range app.Packages { var licenses []string for _, lic := range pkg.Licenses { @@ -126,19 +120,12 @@ func (a packagingAnalyzer) fillAdditionalData(fsys fs.FS, app *types.Application licenses = append(licenses, lic) continue } - licenseFilePath := path.Base(strings.TrimPrefix(lic, licensing.LicenseFilePrefix)) + licensePath := path.Base(strings.TrimPrefix(lic, licensing.LicenseFilePrefix)) - findings, err := classifyLicense(app.FilePath, licenseFilePath, a.licenseClassifierConfidenceLevel, fsys) + foundLicenses, err := classifyLicenses(opener, licensePath, licenseClassifierConfidenceLevel) if err != nil { - return err - } else if len(findings) == 0 { - continue + return xerrors.Errorf("unable to classify licenses: %w", err) } - - // License found - foundLicenses := lo.Map(findings, func(finding types.LicenseFinding, _ int) string { - return finding.Name - }) licenses = append(licenses, foundLicenses...) } app.Packages[i].Licenses = licenses @@ -147,62 +134,32 @@ func (a packagingAnalyzer) fillAdditionalData(fsys fs.FS, app *types.Application return nil } -func classifyLicense(dir, licPath string, classifierConfidenceLevel float64, fsys fs.FS) (types.LicenseFindings, error) { - // Note that fs.FS is always slashed regardless of the platform, - // and path.Join should be used rather than filepath.Join. - f, err := fsys.Open(path.Join(path.Dir(dir), licPath)) - if errors.Is(err, fs.ErrNotExist) { +func classifyLicenses(opener fileOpener, licPath string, licenseClassifierConfidenceLevel float64) ([]string, error) { + f, err := opener(licPath) + if err != nil { + return nil, xerrors.Errorf("unable to open license file: %w", err) + } else if f == nil { // File doesn't exist return nil, nil - } else if err != nil { - return nil, xerrors.Errorf("file open error: %w", err) } defer f.Close() - l, err := licensing.Classify(licPath, f, classifierConfidenceLevel) + l, err := licensing.Classify("", f, licenseClassifierConfidenceLevel) if err != nil { return nil, xerrors.Errorf("license classify error: %w", err) - } else if l == nil { + } else if l == nil { // No licenses found return nil, nil } - return l.Findings, nil + // License found + return lo.Map(l.Findings, func(finding types.LicenseFinding, _ int) string { + return finding.Name + }), nil } func (a packagingAnalyzer) parse(filePath string, r xio.ReadSeekerAt, checksum bool) (*types.Application, error) { return language.ParsePackage(types.PythonPkg, filePath, r, a.pkgParser, checksum) } -func (a packagingAnalyzer) analyzeEggZip(r io.ReaderAt, size int64) (xio.ReadSeekerAt, error) { - zr, err := zip.NewReader(r, size) - if err != nil { - return nil, xerrors.Errorf("zip reader error: %w", err) - } - - found, ok := lo.Find(zr.File, func(f *zip.File) bool { - return isEggFile(f.Name) - }) - if !ok { - return nil, nil - } - return a.open(found) -} - -// open reads the file content in the zip archive to make it seekable. -func (a packagingAnalyzer) open(file *zip.File) (xio.ReadSeekerAt, error) { - f, err := file.Open() - if err != nil { - return nil, err - } - defer f.Close() - - b, err := io.ReadAll(f) - if err != nil { - return nil, xerrors.Errorf("file %s open error: %w", file.Name, err) - } - - return bytes.NewReader(b), nil -} - func (a packagingAnalyzer) Required(filePath string, _ os.FileInfo) bool { return strings.Contains(filePath, ".dist-info") || isEggFile(filePath) } diff --git a/pkg/fanal/analyzer/language/python/packaging/packaging_test.go b/pkg/fanal/analyzer/language/python/packaging/packaging_test.go index 960a92dfec2b..47a9cca901b6 100644 --- a/pkg/fanal/analyzer/language/python/packaging/packaging_test.go +++ b/pkg/fanal/analyzer/language/python/packaging/packaging_test.go @@ -20,28 +20,6 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { want *analyzer.AnalysisResult wantErr string }{ - { - name: "egg zip", - dir: "testdata/egg-zip", - want: &analyzer.AnalysisResult{ - Applications: []types.Application{ - { - Type: types.PythonPkg, - FilePath: "kitchen-1.2.6-py2.7.egg", - Packages: types.Packages{ - { - Name: "kitchen", - Version: "1.2.6", - Licenses: []string{ - "LGPL-2.1-only", - }, - FilePath: "kitchen-1.2.6-py2.7.egg", - }, - }, - }, - }, - }, - }, { name: "egg-info", dir: "testdata/happy-egg", @@ -124,11 +102,6 @@ func Test_packagingAnalyzer_Analyze(t *testing.T) { }, }, }, - { - name: "egg zip doesn't contain required files", - dir: "testdata/no-req-files", - want: &analyzer.AnalysisResult{}, - }, { name: "license file in dist.info", dir: "testdata/license-file-dist", diff --git a/pkg/fanal/analyzer/language/python/packaging/testdata/egg-zip-with-license-file/sample_package.egg b/pkg/fanal/analyzer/language/python/packaging/testdata/egg-zip-with-license-file/sample_package.egg new file mode 100644 index 0000000000000000000000000000000000000000..91d67dc5947b71b0d541924d68430e56d2aaa360 GIT binary patch literal 1135 zcmWIWW@Zs#VBlb2C`?t3WIzI(K(?#9yRN67o4YrYdt0HtLZ85jgn zl|j_|_MOdRGURD_U&*!KVN=0bPM7JrS}ju-yxq8|X}7fLO_$Dz58g^IeB1w|+4gg# z3478Wg~c_CV`Ao*=v;M@;90UT!DF7C&@Fu#k3T}(TSb;XlTK#0Giy&o&U)_dL9( zC`)zA-tW&?(l>HRNTy$w;hgcH>jB4Xx8LurA1}Ro*K6X1J^Q8ybMWrWJ^SQrTJX%D zX?wTlF}+SS*t~Pkq0+o%3A-QsK<@5^-1(RlBnyJzJ1@2HxTZMrNfm2vm) zRI|ek2KT-`ym*Ffx^>2$^0m1F{8rcX%#B;s1mg4EA3yY#;K_OYHR-qMq>^Ql2mKs2 z?^mw4VX#B>Ku*n!TyF_Zy{(TgO>Eo$_~N}cryQPd-phAT_{F1(j4yp2JhQre`MOK= z_oqft_9_=5oA&82&Ym~RaA`|TO|fx>abHV9VELC{>-63UoSw_Xo9#03yWx)8>FN@J z`_Bjm&8oO;*`s6h&nR~R-`ekaGIyKTY|VS6WBKX6xpeR1XOHS;zfir^e3Es_FSSOw z2mk)9dVPYQH*5b4Q-dc*D`xYTr7il-D1R^MTe-RWzW=#)iuK19PGhf4>S|uGFzA!( z5}Q`t)f?}r6$n{PcIVx(FkFuPkc4s7mzf+tkvqN0yf-oV0m*<4$47u` Date: Mon, 16 Sep 2024 21:57:10 -0600 Subject: [PATCH 087/183] feat(misconf): Register checks only when needed (#7435) --- pkg/iac/rego/embed.go | 6 +++--- pkg/iac/rego/embed_test.go | 1 + pkg/iac/rego/scanner.go | 2 ++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/pkg/iac/rego/embed.go b/pkg/iac/rego/embed.go index fddc069d9283..4679102033c2 100644 --- a/pkg/iac/rego/embed.go +++ b/pkg/iac/rego/embed.go @@ -6,6 +6,7 @@ import ( "io/fs" "path/filepath" "strings" + "sync" "github.com/open-policy-agent/opa/ast" @@ -14,8 +15,7 @@ import ( "github.com/aquasecurity/trivy/pkg/log" ) -func init() { - +var LoadAndRegister = sync.OnceFunc(func() { modules, err := LoadEmbeddedPolicies() if err != nil { // we should panic as the policies were not embedded properly @@ -30,7 +30,7 @@ func init() { } RegisterRegoRules(modules) -} +}) func RegisterRegoRules(modules map[string]*ast.Module) { ctx := context.TODO() diff --git a/pkg/iac/rego/embed_test.go b/pkg/iac/rego/embed_test.go index 5b6368dec2eb..9ed0b00747ed 100644 --- a/pkg/iac/rego/embed_test.go +++ b/pkg/iac/rego/embed_test.go @@ -15,6 +15,7 @@ import ( ) func Test_EmbeddedLoading(t *testing.T) { + LoadAndRegister() frameworkRules := rules.GetRegistered() var found bool diff --git a/pkg/iac/rego/scanner.go b/pkg/iac/rego/scanner.go index 23a1e04bc2b8..f6c7cabcb369 100644 --- a/pkg/iac/rego/scanner.go +++ b/pkg/iac/rego/scanner.go @@ -152,6 +152,8 @@ type DynamicMetadata struct { } func NewScanner(source types.Source, opts ...options.ScannerOption) *Scanner { + LoadAndRegister() + schema, ok := schemas.SchemaMap[source] if !ok { schema = schemas.Anything From 56db43c24f4f6be92891be85faaf9492cad516ac Mon Sep 17 00:00:00 2001 From: simar7 <1254783+simar7@users.noreply.github.com> Date: Mon, 16 Sep 2024 22:49:30 -0600 Subject: [PATCH 088/183] fix(misconf): Fix logging typo (#7473) --- pkg/iac/rego/scanner.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/iac/rego/scanner.go b/pkg/iac/rego/scanner.go index f6c7cabcb369..f6108ffefd66 100644 --- a/pkg/iac/rego/scanner.go +++ b/pkg/iac/rego/scanner.go @@ -242,7 +242,7 @@ func GetInputsContents(inputs []Input) []any { func (s *Scanner) ScanInput(ctx context.Context, inputs ...Input) (scan.Results, error) { - s.logger.Debug("Scannning inputs", "count", len(inputs)) + s.logger.Debug("Scanning inputs", "count", len(inputs)) var results scan.Results From d1d713288f868330dd5a8d2fd8b65cd165d4859a Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Wed, 18 Sep 2024 12:02:15 +0600 Subject: [PATCH 089/183] chore(deps): bump go-ebs-file (#7513) Signed-off-by: nikpivkin --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 2ef18dc1cc7a..483b97ee9acc 100644 --- a/go.mod +++ b/go.mod @@ -77,7 +77,7 @@ require ( github.com/liamg/memoryfs v1.6.0 github.com/magefile/mage v1.15.0 github.com/masahiro331/go-disk v0.0.0-20240625071113-56c933208fee - github.com/masahiro331/go-ebs-file v0.0.0-20240112135404-d5fbb1d46323 + github.com/masahiro331/go-ebs-file v0.0.0-20240917043618-e6d2bea5c32e github.com/masahiro331/go-ext4-filesystem v0.0.0-20240620024024-ca14e6327bbd github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 github.com/masahiro331/go-vmdk-parser v0.0.0-20221225061455-612096e4bbbd @@ -175,7 +175,7 @@ require ( github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect - github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7 // indirect + github.com/aws/aws-sdk-go-v2/service/ebs v1.22.1 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.22.7 // indirect diff --git a/go.sum b/go.sum index daaa23dc6559..6ff7fca55e3b 100644 --- a/go.sum +++ b/go.sum @@ -378,8 +378,8 @@ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 h1:Mqr/V5gvrhA2gvgnF4 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17/go.mod h1:aLJpZlCmjE+V+KtN1q1uyZkfnUWpQGpbsn89XPKyzfU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= -github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7 h1:CRzzXjmgx9p362yO39D6hbZULdMI23gaKqSxijJCXHM= -github.com/aws/aws-sdk-go-v2/service/ebs v1.21.7/go.mod h1:wnsHqpi3RgDwklS5SPHUgjcUUpontGPKJ+GJYOdV7pY= +github.com/aws/aws-sdk-go-v2/service/ebs v1.22.1 h1:SeDJWG4pmye+/aO6k+zt9clPTUy1MXqUmkW8rbAddQg= +github.com/aws/aws-sdk-go-v2/service/ebs v1.22.1/go.mod h1:wRzaW0v9GGQS0h//wpsVDw3Hah5gs5UP+NxoyGeZIGM= github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.2 h1:QUUvxEs9q1DsYCaWaRrV8i7n82Adm34jrHb6OPjXPqc= github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.2/go.mod h1:TFSALWR7Xs7+KyMM87ZAYxncKFBvzEt2rpK/BJCH2ps= github.com/aws/aws-sdk-go-v2/service/ecr v1.32.4 h1:nQAU2Yr+afkAvIV39mg7LrNYFNQP7ShwbmiJqx2fUKA= @@ -1023,8 +1023,8 @@ github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/masahiro331/go-disk v0.0.0-20240625071113-56c933208fee h1:cgm8mE25x5XXX2oyvJDlyJ72K+rDu/4ZCYce2worNb8= github.com/masahiro331/go-disk v0.0.0-20240625071113-56c933208fee/go.mod h1:rojbW5tVhH1cuVYFKZS+QX+VGXK45JVsRO+jW92kkKM= -github.com/masahiro331/go-ebs-file v0.0.0-20240112135404-d5fbb1d46323 h1:uQubA711SeYStvStohMLrdvRTTohdPHrEPFzerLcY9I= -github.com/masahiro331/go-ebs-file v0.0.0-20240112135404-d5fbb1d46323/go.mod h1:OdtzwqTtu49Gh5RFkNEU1SbcihIuVTtUipwHflqxckE= +github.com/masahiro331/go-ebs-file v0.0.0-20240917043618-e6d2bea5c32e h1:nCgF1JEYIS8KNuJtIeUrmjjhktIMKWNmASZqwK2ynu0= +github.com/masahiro331/go-ebs-file v0.0.0-20240917043618-e6d2bea5c32e/go.mod h1:XFWPTlAcEL733RUjbr0QBybdt6oK2DH7LZk8id2qtd4= github.com/masahiro331/go-ext4-filesystem v0.0.0-20240620024024-ca14e6327bbd h1:JEIW94K3spsvBI5Xb9PGhKSIza9/jxO1lF30tPCAJlA= github.com/masahiro331/go-ext4-filesystem v0.0.0-20240620024024-ca14e6327bbd/go.mod h1:3XMMY1M486mWGTD13WPItg6FsgflQR72ZMAkd+gsyoQ= github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08 h1:AevUBW4cc99rAF8q8vmddIP8qd/0J5s/UyltGbp66dg= From aeb7039d7ce090e243d29f0bf16c9e4e24252a01 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Wed, 18 Sep 2024 12:08:12 +0600 Subject: [PATCH 090/183] fix(sbom): parse type `framework` as `library` when unmarshalling `CycloneDX` files (#7527) --- pkg/sbom/cyclonedx/testdata/happy/third-party-bom.json | 2 +- pkg/sbom/cyclonedx/unmarshal.go | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/pkg/sbom/cyclonedx/testdata/happy/third-party-bom.json b/pkg/sbom/cyclonedx/testdata/happy/third-party-bom.json index d8b5068f5cc0..281d3c4fcc30 100644 --- a/pkg/sbom/cyclonedx/testdata/happy/third-party-bom.json +++ b/pkg/sbom/cyclonedx/testdata/happy/third-party-bom.json @@ -46,7 +46,7 @@ }, { "bom-ref": "pkg:composer/pear/pear_exception@v1.0.0", - "type": "library", + "type": "framework", "name": "pear/pear_exception", "version": "v1.0.0", "purl": "pkg:composer/pear/pear_exception@v1.0.0" diff --git a/pkg/sbom/cyclonedx/unmarshal.go b/pkg/sbom/cyclonedx/unmarshal.go index 71a0ee27b640..de410d008794 100644 --- a/pkg/sbom/cyclonedx/unmarshal.go +++ b/pkg/sbom/cyclonedx/unmarshal.go @@ -166,7 +166,10 @@ func (b *BOM) unmarshalType(t cdx.ComponentType) (core.ComponentType, error) { ctype = core.TypeContainerImage case cdx.ComponentTypeApplication: ctype = core.TypeApplication - case cdx.ComponentTypeLibrary: + // There are not many differences between a `library` and a `framework` components, and sometimes it is difficult to choose the right type. + // That is why some users choose `framework` type. + // So we should parse and scan `framework` components as libraries. + case cdx.ComponentTypeLibrary, cdx.ComponentTypeFramework: ctype = core.TypeLibrary case cdx.ComponentTypeOS: ctype = core.TypeOS From dbd2dd60604fbcb5456a864a37d9c1b5a9e6f231 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Wed, 18 Sep 2024 23:41:38 +0600 Subject: [PATCH 091/183] refactor(misconf): pass options to Rego scanner as is (#7529) Signed-off-by: nikpivkin --- pkg/iac/rego/load.go | 18 +- pkg/iac/rego/load_test.go | 49 ++- pkg/iac/rego/options.go | 108 ++++++ pkg/iac/rego/scanner.go | 93 ++---- pkg/iac/rego/scanner_test.go | 311 +++++++++--------- pkg/iac/scanners/azure/arm/scanner.go | 43 +-- pkg/iac/scanners/cloudformation/scanner.go | 44 +-- .../scanners/cloudformation/scanner_test.go | 9 +- .../cloudformation/test/cf_scanning_test.go | 6 +- pkg/iac/scanners/dockerfile/scanner.go | 79 +---- pkg/iac/scanners/dockerfile/scanner_test.go | 12 +- pkg/iac/scanners/helm/scanner.go | 75 +---- pkg/iac/scanners/helm/test/scanner_test.go | 32 +- pkg/iac/scanners/json/scanner.go | 69 +--- pkg/iac/scanners/json/scanner_test.go | 4 +- pkg/iac/scanners/kubernetes/scanner.go | 68 +--- pkg/iac/scanners/kubernetes/scanner_test.go | 40 +-- pkg/iac/scanners/options/scanner.go | 102 +----- pkg/iac/scanners/terraform/fs_test.go | 6 +- pkg/iac/scanners/terraform/ignore_test.go | 9 +- pkg/iac/scanners/terraform/scanner.go | 72 +--- .../terraform/scanner_integration_test.go | 35 +- pkg/iac/scanners/terraform/scanner_test.go | 85 ++--- pkg/iac/scanners/terraform/setup_test.go | 5 +- .../terraformplan/snapshot/scanner_test.go | 25 +- .../scanners/terraformplan/tfjson/scanner.go | 85 +---- .../terraformplan/tfjson/scanner_test.go | 17 +- .../terraformplan/tfjson/test/scanner_test.go | 6 +- pkg/iac/scanners/toml/scanner.go | 65 +--- pkg/iac/scanners/toml/scanner_test.go | 4 +- pkg/iac/scanners/yaml/scanner.go | 64 +--- pkg/iac/scanners/yaml/scanner_test.go | 4 +- pkg/misconf/scanner.go | 21 +- 33 files changed, 570 insertions(+), 1095 deletions(-) create mode 100644 pkg/iac/rego/options.go diff --git a/pkg/iac/rego/load.go b/pkg/iac/rego/load.go index 26a6c9e6f2d1..a1c29d163fae 100644 --- a/pkg/iac/rego/load.go +++ b/pkg/iac/rego/load.go @@ -75,7 +75,7 @@ func (s *Scanner) loadEmbedded() error { return nil } -func (s *Scanner) LoadPolicies(enableEmbeddedLibraries, enableEmbeddedPolicies bool, srcFS fs.FS, paths []string, readers []io.Reader) error { +func (s *Scanner) LoadPolicies(srcFS fs.FS) error { if s.policies == nil { s.policies = make(map[string]*ast.Module) @@ -90,19 +90,19 @@ func (s *Scanner) LoadPolicies(enableEmbeddedLibraries, enableEmbeddedPolicies b return err } - if enableEmbeddedPolicies { + if s.includeEmbeddedPolicies { s.policies = lo.Assign(s.policies, s.embeddedChecks) } - if enableEmbeddedLibraries { + if s.includeEmbeddedLibraries { s.policies = lo.Assign(s.policies, s.embeddedLibs) } var err error - if len(paths) > 0 { - loaded, err := LoadPoliciesFromDirs(srcFS, paths...) + if len(s.policyDirs) > 0 { + loaded, err := LoadPoliciesFromDirs(srcFS, s.policyDirs...) if err != nil { - return fmt.Errorf("failed to load rego checks from %s: %w", paths, err) + return fmt.Errorf("failed to load rego checks from %s: %w", s.policyDirs, err) } for name, policy := range loaded { s.policies[name] = policy @@ -110,8 +110,8 @@ func (s *Scanner) LoadPolicies(enableEmbeddedLibraries, enableEmbeddedPolicies b s.logger.Debug("Checks from disk are loaded", log.Int("count", len(loaded))) } - if len(readers) > 0 { - loaded, err := s.loadPoliciesFromReaders(readers) + if len(s.policyReaders) > 0 { + loaded, err := s.loadPoliciesFromReaders(s.policyReaders) if err != nil { return fmt.Errorf("failed to load rego checks from reader(s): %w", err) } @@ -143,7 +143,7 @@ func (s *Scanner) LoadPolicies(enableEmbeddedLibraries, enableEmbeddedPolicies b } s.store = store - return s.compilePolicies(srcFS, paths) + return s.compilePolicies(srcFS, s.policyDirs) } func (s *Scanner) fallbackChecks(compiler *ast.Compiler) { diff --git a/pkg/iac/rego/load_test.go b/pkg/iac/rego/load_test.go index e0c136562d45..174cbc732525 100644 --- a/pkg/iac/rego/load_test.go +++ b/pkg/iac/rego/load_test.go @@ -4,7 +4,6 @@ import ( "bytes" "embed" "fmt" - "io" "log/slog" "strings" "testing" @@ -16,7 +15,6 @@ import ( checks "github.com/aquasecurity/trivy-checks" "github.com/aquasecurity/trivy/pkg/iac/rego" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/types" "github.com/aquasecurity/trivy/pkg/log" ) @@ -33,10 +31,11 @@ func Test_RegoScanning_WithSomeInvalidPolicies(t *testing.T) { slog.SetDefault(log.New(log.NewHandler(&debugBuf, nil))) scanner := rego.NewScanner( types.SourceDockerfile, - options.ScannerWithRegoErrorLimits(0), + rego.WithRegoErrorLimits(0), + rego.WithPolicyDirs("."), ) - err := scanner.LoadPolicies(false, false, testEmbedFS, []string{"."}, nil) + err := scanner.LoadPolicies(testEmbedFS) require.ErrorContains(t, err, `want (one of): ["Cmd" "EndLine" "Flags" "JSON" "Original" "Path" "Stage" "StartLine" "SubCmd" "Value"]`) assert.Contains(t, debugBuf.String(), "Error(s) occurred while loading checks") }) @@ -46,10 +45,11 @@ func Test_RegoScanning_WithSomeInvalidPolicies(t *testing.T) { slog.SetDefault(log.New(log.NewHandler(&debugBuf, nil))) scanner := rego.NewScanner( types.SourceDockerfile, - options.ScannerWithRegoErrorLimits(1), + rego.WithRegoErrorLimits(1), + rego.WithPolicyDirs("."), ) - err := scanner.LoadPolicies(false, false, testEmbedFS, []string{"."}, nil) + err := scanner.LoadPolicies(testEmbedFS) require.NoError(t, err) assert.Contains(t, debugBuf.String(), "Error occurred while parsing\tfile_path=\"testdata/policies/invalid.rego\" err=\"testdata/policies/invalid.rego:7") @@ -64,9 +64,13 @@ package mypackage deny { input.evil == "foo bar" }` - scanner := rego.NewScanner(types.SourceJSON) + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("."), + rego.WithPolicyReader(strings.NewReader(check)), + ) - err := scanner.LoadPolicies(false, false, fstest.MapFS{}, []string{"."}, []io.Reader{strings.NewReader(check)}) + err := scanner.LoadPolicies(fstest.MapFS{}) assert.ErrorContains(t, err, "could not find schema \"fooschema\"") }) @@ -79,7 +83,11 @@ package mypackage deny { input.evil == "foo bar" }` - scanner := rego.NewScanner(types.SourceJSON) + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("."), + rego.WithPolicyReader(strings.NewReader(check)), + ) fsys := fstest.MapFS{ "schemas/fooschema.json": &fstest.MapFile{ @@ -87,7 +95,7 @@ deny { }, } - err := scanner.LoadPolicies(false, false, fsys, []string{"."}, []io.Reader{strings.NewReader(check)}) + err := scanner.LoadPolicies(fsys) assert.ErrorContains(t, err, "could not parse schema \"fooschema\"") }) @@ -97,8 +105,12 @@ deny { deny { input.evil == "foo bar" }` - scanner := rego.NewScanner(types.SourceJSON) - err := scanner.LoadPolicies(false, false, fstest.MapFS{}, []string{"."}, []io.Reader{strings.NewReader(check)}) + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("."), + rego.WithPolicyReader(strings.NewReader(check)), + ) + err := scanner.LoadPolicies(fstest.MapFS{}) require.NoError(t, err) }) @@ -184,8 +196,9 @@ deny { t.Run(tt.name, func(t *testing.T) { scanner := rego.NewScanner( types.SourceDockerfile, - options.ScannerWithRegoErrorLimits(0), - options.ScannerWithEmbeddedPolicies(false), + rego.WithRegoErrorLimits(0), + rego.WithEmbeddedPolicies(false), + rego.WithPolicyDirs("."), ) tt.files["schemas/fooschema.json"] = &fstest.MapFile{ @@ -200,9 +213,8 @@ deny { }`), } - fsys := fstest.MapFS(tt.files) checks.EmbeddedPolicyFileSystem = embeddedChecksFS - err := scanner.LoadPolicies(false, false, fsys, []string{"."}, nil) + err := scanner.LoadPolicies(fstest.MapFS(tt.files)) if tt.expectedErr != "" { assert.ErrorContains(t, err, tt.expectedErr) @@ -244,8 +256,9 @@ deny { scanner := rego.NewScanner( types.SourceDockerfile, - options.ScannerWithEmbeddedPolicies(false), + rego.WithEmbeddedPolicies(false), + rego.WithPolicyDirs("."), ) - err := scanner.LoadPolicies(false, false, fsys, []string{"."}, nil) + err := scanner.LoadPolicies(fsys) require.Error(t, err) } diff --git a/pkg/iac/rego/options.go b/pkg/iac/rego/options.go new file mode 100644 index 000000000000..d4b622a68c16 --- /dev/null +++ b/pkg/iac/rego/options.go @@ -0,0 +1,108 @@ +package rego + +import ( + "io" + "io/fs" + + "github.com/aquasecurity/trivy/pkg/iac/scanners/options" +) + +func WithPolicyReader(readers ...io.Reader) options.ScannerOption { + return func(s options.ConfigurableScanner) { + if ss, ok := s.(*Scanner); ok { + ss.policyReaders = readers + } + } +} + +func WithEmbeddedPolicies(include bool) options.ScannerOption { + return func(s options.ConfigurableScanner) { + if ss, ok := s.(*Scanner); ok { + ss.includeEmbeddedPolicies = include + } + } +} + +func WithEmbeddedLibraries(include bool) options.ScannerOption { + return func(s options.ConfigurableScanner) { + if ss, ok := s.(*Scanner); ok { + ss.includeEmbeddedLibraries = include + } + } +} + +// WithTrace specifies an io.Writer for trace logs (mainly rego tracing) - if not set, they are discarded +func WithTrace(w io.Writer) options.ScannerOption { + return func(s options.ConfigurableScanner) { + if ss, ok := s.(*Scanner); ok { + ss.traceWriter = w + } + } +} + +func WithPerResultTracing(enabled bool) options.ScannerOption { + return func(s options.ConfigurableScanner) { + if ss, ok := s.(*Scanner); ok { + ss.tracePerResult = enabled + } + } +} + +func WithPolicyDirs(paths ...string) options.ScannerOption { + return func(s options.ConfigurableScanner) { + if ss, ok := s.(*Scanner); ok { + ss.policyDirs = paths + } + } +} + +func WithDataDirs(paths ...string) options.ScannerOption { + return func(s options.ConfigurableScanner) { + if ss, ok := s.(*Scanner); ok { + ss.dataDirs = paths + } + } +} + +// WithPolicyNamespaces - namespaces which indicate rego policies containing enforced rules +func WithPolicyNamespaces(namespaces ...string) options.ScannerOption { + return func(s options.ConfigurableScanner) { + if ss, ok := s.(*Scanner); ok { + for _, namespace := range namespaces { + ss.ruleNamespaces[namespace] = struct{}{} + } + } + } +} + +func WithPolicyFilesystem(fsys fs.FS) options.ScannerOption { + return func(s options.ConfigurableScanner) { + if ss, ok := s.(*Scanner); ok { + ss.policyFS = fsys + } + } +} + +func WithDataFilesystem(fsys fs.FS) options.ScannerOption { + return func(s options.ConfigurableScanner) { + if ss, ok := s.(*Scanner); ok { + ss.dataFS = fsys + } + } +} + +func WithRegoErrorLimits(limit int) options.ScannerOption { + return func(s options.ConfigurableScanner) { + if ss, ok := s.(*Scanner); ok { + ss.regoErrorLimit = limit + } + } +} + +func WithCustomSchemas(schemas map[string][]byte) options.ScannerOption { + return func(s options.ConfigurableScanner) { + if ss, ok := s.(*Scanner); ok { + ss.customSchemas = schemas + } + } +} diff --git a/pkg/iac/rego/scanner.go b/pkg/iac/rego/scanner.go index f6108ffefd66..a8e1caf525b3 100644 --- a/pkg/iac/rego/scanner.go +++ b/pkg/iac/rego/scanner.go @@ -44,24 +44,27 @@ func makeSupportedProviders() map[string]struct{} { var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { - ruleNamespaces map[string]struct{} - policies map[string]*ast.Module - store storage.Store - dataDirs []string - runtimeValues *ast.Term - compiler *ast.Compiler - regoErrorLimit int - logger *log.Logger - traceWriter io.Writer - tracePerResult bool - retriever *MetadataRetriever - policyFS fs.FS - dataFS fs.FS - frameworks []framework.Framework - spec string - inputSchema any // unmarshalled into this from a json schema document - sourceType types.Source - includeDeprecatedChecks bool + ruleNamespaces map[string]struct{} + policies map[string]*ast.Module + store storage.Store + runtimeValues *ast.Term + compiler *ast.Compiler + regoErrorLimit int + logger *log.Logger + traceWriter io.Writer + tracePerResult bool + retriever *MetadataRetriever + policyFS fs.FS + policyDirs []string + policyReaders []io.Reader + dataFS fs.FS + dataDirs []string + frameworks []framework.Framework + inputSchema any // unmarshalled into this from a json schema document + sourceType types.Source + includeDeprecatedChecks bool + includeEmbeddedPolicies bool + includeEmbeddedLibraries bool embeddedLibs map[string]*ast.Module embeddedChecks map[string]*ast.Module @@ -72,24 +75,12 @@ func (s *Scanner) SetIncludeDeprecatedChecks(b bool) { s.includeDeprecatedChecks = b } -func (s *Scanner) SetUseEmbeddedLibraries(b bool) { - // handled externally -} - -func (s *Scanner) SetSpec(spec string) { - s.spec = spec -} - func (s *Scanner) SetRegoOnly(bool) {} func (s *Scanner) SetFrameworks(frameworks []framework.Framework) { s.frameworks = frameworks } -func (s *Scanner) SetUseEmbeddedPolicies(b bool) { - // handled externally -} - func (s *Scanner) trace(heading string, input any) { if s.traceWriter == nil { return @@ -101,48 +92,6 @@ func (s *Scanner) trace(heading string, input any) { _, _ = fmt.Fprintf(s.traceWriter, "REGO %[1]s:\n%s\nEND REGO %[1]s\n\n", heading, string(data)) } -func (s *Scanner) SetPolicyFilesystem(fsys fs.FS) { - s.policyFS = fsys -} - -func (s *Scanner) SetDataFilesystem(fsys fs.FS) { - s.dataFS = fsys -} - -func (s *Scanner) SetPolicyReaders(_ []io.Reader) { - // NOTE: Policy readers option not applicable for rego, policies are loaded on-demand by other scanners. -} - -func (s *Scanner) SetTraceWriter(writer io.Writer) { - s.traceWriter = writer -} - -func (s *Scanner) SetPerResultTracingEnabled(b bool) { - s.tracePerResult = b -} - -func (s *Scanner) SetPolicyDirs(_ ...string) { - // NOTE: Policy dirs option not applicable for rego, policies are loaded on-demand by other scanners. -} - -func (s *Scanner) SetDataDirs(dirs ...string) { - s.dataDirs = dirs -} - -func (s *Scanner) SetPolicyNamespaces(namespaces ...string) { - for _, namespace := range namespaces { - s.ruleNamespaces[namespace] = struct{}{} - } -} - -func (s *Scanner) SetRegoErrorLimit(limit int) { - s.regoErrorLimit = limit -} - -func (s *Scanner) SetCustomSchemas(v map[string][]byte) { - s.customSchemas = v -} - type DynamicMetadata struct { Warning bool Filepath string diff --git a/pkg/iac/rego/scanner_test.go b/pkg/iac/rego/scanner_test.go index c453cc984b1c..73ef55223f14 100644 --- a/pkg/iac/rego/scanner_test.go +++ b/pkg/iac/rego/scanner_test.go @@ -1,9 +1,8 @@ -package rego +package rego_test import ( "bytes" "context" - "io" "io/fs" "os" "path/filepath" @@ -15,7 +14,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" + "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/severity" "github.com/aquasecurity/trivy/pkg/iac/types" ) @@ -44,13 +43,13 @@ deny { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": true, @@ -79,13 +78,13 @@ deny { srcFS := os.DirFS(tmp) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"/policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": true, @@ -114,13 +113,13 @@ warn { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": true, @@ -146,13 +145,13 @@ deny { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": false, @@ -189,13 +188,13 @@ exception[ns] { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": true, @@ -237,13 +236,13 @@ exception[ns] { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": true, @@ -274,13 +273,13 @@ exception[rules] { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": true, @@ -310,13 +309,13 @@ exception[rules] { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": true, @@ -344,13 +343,13 @@ deny_evil { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": true, @@ -375,13 +374,13 @@ deny[msg] { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": true, @@ -413,13 +412,13 @@ deny[res] { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": true, @@ -455,13 +454,13 @@ deny[res] { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": true, @@ -509,13 +508,13 @@ deny[res] { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": true, @@ -558,13 +557,13 @@ deny { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": true, @@ -592,13 +591,13 @@ deny { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": true, @@ -623,13 +622,13 @@ deny { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": true, @@ -658,13 +657,14 @@ deny { traceBuffer := bytes.NewBuffer([]byte{}) - scanner := NewScanner(types.SourceJSON, options.ScannerWithTrace(traceBuffer)) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithTrace(traceBuffer), + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": true, @@ -692,13 +692,14 @@ deny { `, }) - scanner := NewScanner(types.SourceJSON, options.ScannerWithPerResultTracing(true)) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPerResultTracing(true), + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "evil": true, @@ -730,13 +731,13 @@ deny { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "text": "dynamic", @@ -763,13 +764,13 @@ deny { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "text": "test", @@ -810,13 +811,14 @@ deny { `, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithPerResultTracing(true), + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "text": "test", @@ -848,13 +850,11 @@ deny { `, }) - scanner := NewScanner(types.SourceDockerfile) - scanner.SetRegoErrorLimit(0) // override to not allow any errors - assert.ErrorContains( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), - "undefined ref: input.evil", + scanner := rego.NewScanner( + types.SourceDockerfile, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) } func Test_RegoScanning_WithValidInputSchema(t *testing.T) { @@ -871,11 +871,11 @@ deny { `, }) - scanner := NewScanner(types.SourceDockerfile) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceDockerfile, + rego.WithPolicyDirs("policies"), ) + require.NoError(t, scanner.LoadPolicies(srcFS)) } func Test_RegoScanning_WithFilepathToSchema(t *testing.T) { @@ -890,11 +890,16 @@ deny { } `, }) - scanner := NewScanner(types.SourceJSON) - scanner.SetRegoErrorLimit(0) // override to not allow any errors + + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithRegoErrorLimits(0), + rego.WithPolicyDirs("policies"), + ) + assert.ErrorContains( t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner.LoadPolicies(srcFS), "undefined ref: input.evil", ) } @@ -922,16 +927,16 @@ deny { "data/junk.txt": "this file should be ignored", }) - scanner := NewScanner(types.SourceJSON) - scanner.SetDataFilesystem(dataFS) - scanner.SetDataDirs(".") - - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithDataFilesystem(dataFS), + rego.WithDataDirs("."), + rego.WithPolicyDirs("policies"), ) - results, err := scanner.ScanInput(context.TODO(), Input{}) + require.NoError(t, scanner.LoadPolicies(srcFS)) + + results, err := scanner.ScanInput(context.TODO(), rego.Input{}) require.NoError(t, err) assert.Len(t, results.GetFailed(), 1) @@ -962,16 +967,16 @@ deny { "data/junk.txt": "this file should be ignored", }) - scanner := NewScanner(types.SourceJSON) - scanner.SetDataFilesystem(dataFS) - scanner.SetDataDirs("X://") - - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), + scanner := rego.NewScanner( + types.SourceJSON, + rego.WithDataFilesystem(dataFS), + rego.WithDataDirs("X://"), + rego.WithPolicyDirs("policies"), ) - results, err := scanner.ScanInput(context.TODO(), Input{}) + require.NoError(t, scanner.LoadPolicies(srcFS)) + + results, err := scanner.ScanInput(context.TODO(), rego.Input{}) require.NoError(t, err) assert.Len(t, results.GetFailed(), 1) @@ -998,14 +1003,12 @@ deny { }, } - scanner := NewScanner( + scanner := rego.NewScanner( types.SourceYAML, + rego.WithPolicyDirs("checks"), ) - require.NoError( - t, - scanner.LoadPolicies(false, false, fsys, []string{"checks"}, nil), - ) - _, err := scanner.ScanInput(context.TODO(), Input{}) + require.NoError(t, scanner.LoadPolicies(fsys)) + _, err := scanner.ScanInput(context.TODO(), rego.Input{}) require.NoError(t, err) } @@ -1066,13 +1069,10 @@ deny { "policies/test.rego": tc.policy, }) - scanner := NewScanner(types.SourceJSON) - require.NoError( - t, - scanner.LoadPolicies(false, false, srcFS, []string{"policies"}, nil), - ) + scanner := rego.NewScanner(types.SourceJSON, rego.WithPolicyDirs("policies")) + require.NoError(t, scanner.LoadPolicies(srcFS)) - results, err := scanner.ScanInput(context.TODO(), Input{ + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "/evil.lol", Contents: map[string]any{ "text": "test", @@ -1133,17 +1133,18 @@ deny { for _, tc := range tests { t.Run(tc.name, func(t *testing.T) { - scanner := NewScanner( + scanner := rego.NewScanner( types.SourceYAML, - options.ScannerWithCustomSchemas(map[string][]byte{ + rego.WithCustomSchemas(map[string][]byte{ "test": []byte(schema), }), - options.ScannerWithPolicyNamespaces("user"), + rego.WithPolicyNamespaces("user"), + rego.WithPolicyReader(strings.NewReader(tc.check)), ) - err := scanner.LoadPolicies(false, false, nil, nil, []io.Reader{strings.NewReader(tc.check)}) - require.NoError(t, err) - results, err := scanner.ScanInput(context.TODO(), Input{ + require.NoError(t, scanner.LoadPolicies(nil)) + + results, err := scanner.ScanInput(context.TODO(), rego.Input{ Path: "test.yaml", Contents: map[string]any{"service": "test"}, }) diff --git a/pkg/iac/scanners/azure/arm/scanner.go b/pkg/iac/scanners/azure/arm/scanner.go index e4b3258f823f..410ccd6d18df 100644 --- a/pkg/iac/scanners/azure/arm/scanner.go +++ b/pkg/iac/scanners/azure/arm/scanner.go @@ -3,7 +3,6 @@ package arm import ( "context" "fmt" - "io" "io/fs" "sync" @@ -30,12 +29,7 @@ type Scanner struct { logger *log.Logger frameworks []framework.Framework regoOnly bool - loadEmbeddedPolicies bool - loadEmbeddedLibraries bool - policyDirs []string - policyReaders []io.Reader regoScanner *rego.Scanner - spec string includeDeprecatedChecks bool } @@ -43,12 +37,6 @@ func (s *Scanner) SetIncludeDeprecatedChecks(b bool) { s.includeDeprecatedChecks = b } -func (s *Scanner) SetCustomSchemas(map[string][]byte) {} - -func (s *Scanner) SetSpec(spec string) { - s.spec = spec -} - func (s *Scanner) SetRegoOnly(regoOnly bool) { s.regoOnly = regoOnly } @@ -68,39 +56,10 @@ func (s *Scanner) Name() string { return "Azure ARM" } -func (s *Scanner) SetPolicyDirs(dirs ...string) { - s.policyDirs = dirs -} - -func (s *Scanner) SetPolicyReaders(readers []io.Reader) { - s.policyReaders = readers -} - -func (s *Scanner) SetPolicyFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} -func (s *Scanner) SetDataFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} - -func (s *Scanner) SetUseEmbeddedPolicies(b bool) { - s.loadEmbeddedPolicies = b -} - -func (s *Scanner) SetUseEmbeddedLibraries(b bool) { - s.loadEmbeddedLibraries = b -} - func (s *Scanner) SetFrameworks(frameworks []framework.Framework) { s.frameworks = frameworks } -func (s *Scanner) SetTraceWriter(io.Writer) {} -func (s *Scanner) SetPerResultTracingEnabled(bool) {} -func (s *Scanner) SetDataDirs(...string) {} -func (s *Scanner) SetPolicyNamespaces(...string) {} -func (s *Scanner) SetRegoErrorLimit(_ int) {} - func (s *Scanner) initRegoScanner(srcFS fs.FS) error { s.mu.Lock() defer s.mu.Unlock() @@ -108,7 +67,7 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) error { return nil } regoScanner := rego.NewScanner(types.SourceCloud, s.scannerOptions...) - if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { + if err := regoScanner.LoadPolicies(srcFS); err != nil { return err } s.regoScanner = regoScanner diff --git a/pkg/iac/scanners/cloudformation/scanner.go b/pkg/iac/scanners/cloudformation/scanner.go index dc4deab0aff5..4497a807506c 100644 --- a/pkg/iac/scanners/cloudformation/scanner.go +++ b/pkg/iac/scanners/cloudformation/scanner.go @@ -3,7 +3,6 @@ package cloudformation import ( "context" "fmt" - "io" "io/fs" "sort" "sync" @@ -50,17 +49,12 @@ var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { mu sync.Mutex logger *log.Logger - policyDirs []string - policyReaders []io.Reader parser *parser.Parser regoScanner *rego.Scanner regoOnly bool - loadEmbeddedPolicies bool - loadEmbeddedLibraries bool options []options.ScannerOption parserOptions []parser.Option frameworks []framework.Framework - spec string includeDeprecatedChecks bool } @@ -68,8 +62,6 @@ func (s *Scanner) SetIncludeDeprecatedChecks(b bool) { s.includeDeprecatedChecks = b } -func (s *Scanner) SetCustomSchemas(map[string][]byte) {} - func (s *Scanner) addParserOption(opt parser.Option) { s.parserOptions = append(s.parserOptions, opt) } @@ -78,18 +70,6 @@ func (s *Scanner) SetFrameworks(frameworks []framework.Framework) { s.frameworks = frameworks } -func (s *Scanner) SetSpec(spec string) { - s.spec = spec -} - -func (s *Scanner) SetUseEmbeddedPolicies(b bool) { - s.loadEmbeddedPolicies = b -} - -func (s *Scanner) SetUseEmbeddedLibraries(b bool) { - s.loadEmbeddedLibraries = b -} - func (s *Scanner) SetRegoOnly(regoOnly bool) { s.regoOnly = regoOnly } @@ -98,28 +78,6 @@ func (s *Scanner) Name() string { return "CloudFormation" } -func (s *Scanner) SetPolicyReaders(readers []io.Reader) { - s.policyReaders = readers -} - -func (s *Scanner) SetPolicyDirs(dirs ...string) { - s.policyDirs = dirs -} - -func (s *Scanner) SetPolicyFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} - -func (s *Scanner) SetDataFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} -func (s *Scanner) SetRegoErrorLimit(_ int) {} - -func (s *Scanner) SetTraceWriter(_ io.Writer) {} -func (s *Scanner) SetPerResultTracingEnabled(_ bool) {} -func (s *Scanner) SetDataDirs(_ ...string) {} -func (s *Scanner) SetPolicyNamespaces(_ ...string) {} - // New creates a new Scanner func New(opts ...options.ScannerOption) *Scanner { s := &Scanner{ @@ -140,7 +98,7 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { return s.regoScanner, nil } regoScanner := rego.NewScanner(types.SourceCloud, s.options...) - if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { + if err := regoScanner.LoadPolicies(srcFS); err != nil { return nil, err } s.regoScanner = regoScanner diff --git a/pkg/iac/scanners/cloudformation/scanner_test.go b/pkg/iac/scanners/cloudformation/scanner_test.go index 21d185c5ec06..67ee92cf69c3 100644 --- a/pkg/iac/scanners/cloudformation/scanner_test.go +++ b/pkg/iac/scanners/cloudformation/scanner_test.go @@ -10,6 +10,7 @@ import ( "github.com/aquasecurity/trivy/internal/testutil" "github.com/aquasecurity/trivy/pkg/iac/framework" + "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) @@ -57,7 +58,7 @@ deny[res] { `, }) - scanner := New(options.ScannerWithPolicyDirs("rules"), options.ScannerWithRegoOnly(true)) + scanner := New(rego.WithPolicyDirs("rules"), options.ScannerWithRegoOnly(true)) results, err := scanner.ScanFS(context.TODO(), fs, "code") require.NoError(t, err) @@ -215,9 +216,9 @@ Resources: scanner := New( options.ScannerWithRegoOnly(true), - options.ScannerWithEmbeddedPolicies(false), - options.ScannerWithPolicyReader(strings.NewReader(bucketNameCheck)), - options.ScannerWithPolicyNamespaces("user"), + rego.WithEmbeddedPolicies(false), + rego.WithPolicyReader(strings.NewReader(bucketNameCheck)), + rego.WithPolicyNamespaces("user"), ) results, err := scanner.ScanFS(context.TODO(), fsys, "code") diff --git a/pkg/iac/scanners/cloudformation/test/cf_scanning_test.go b/pkg/iac/scanners/cloudformation/test/cf_scanning_test.go index 396963447ca9..46eed857a75f 100644 --- a/pkg/iac/scanners/cloudformation/test/cf_scanning_test.go +++ b/pkg/iac/scanners/cloudformation/test/cf_scanning_test.go @@ -8,12 +8,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) func Test_basic_cloudformation_scanning(t *testing.T) { - cfScanner := cloudformation.New(options.ScannerWithEmbeddedPolicies(true), options.ScannerWithEmbeddedLibraries(true)) + cfScanner := cloudformation.New(rego.WithEmbeddedPolicies(true), rego.WithEmbeddedLibraries(true)) results, err := cfScanner.ScanFS(context.TODO(), os.DirFS("./examples/bucket"), ".") require.NoError(t, err) @@ -22,7 +22,7 @@ func Test_basic_cloudformation_scanning(t *testing.T) { } func Test_cloudformation_scanning_has_expected_errors(t *testing.T) { - cfScanner := cloudformation.New(options.ScannerWithEmbeddedPolicies(true), options.ScannerWithEmbeddedLibraries(true)) + cfScanner := cloudformation.New(rego.WithEmbeddedPolicies(true), rego.WithEmbeddedLibraries(true)) results, err := cfScanner.ScanFS(context.TODO(), os.DirFS("./examples/bucket"), ".") require.NoError(t, err) diff --git a/pkg/iac/scanners/dockerfile/scanner.go b/pkg/iac/scanners/dockerfile/scanner.go index e0d6ebd9ebde..1694f28d814a 100644 --- a/pkg/iac/scanners/dockerfile/scanner.go +++ b/pkg/iac/scanners/dockerfile/scanner.go @@ -2,7 +2,6 @@ package dockerfile import ( "context" - "io" "io/fs" "sync" @@ -20,81 +19,21 @@ var _ scanners.FSScanner = (*Scanner)(nil) var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { - mu sync.Mutex - logger *log.Logger - policyDirs []string - policyReaders []io.Reader - parser *parser.Parser - regoScanner *rego.Scanner - options []options.ScannerOption - frameworks []framework.Framework - spec string - loadEmbeddedLibraries bool - loadEmbeddedPolicies bool + mu sync.Mutex + logger *log.Logger + parser *parser.Parser + regoScanner *rego.Scanner + options []options.ScannerOption } -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} -func (s *Scanner) SetCustomSchemas(map[string][]byte) {} - -func (s *Scanner) SetSpec(spec string) { - s.spec = spec -} - -func (s *Scanner) SetRegoOnly(bool) { -} - -func (s *Scanner) SetFrameworks(frameworks []framework.Framework) { - s.frameworks = frameworks -} - -func (s *Scanner) SetUseEmbeddedPolicies(b bool) { - s.loadEmbeddedPolicies = b -} - -func (s *Scanner) SetUseEmbeddedLibraries(b bool) { - s.loadEmbeddedLibraries = b -} +func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetRegoOnly(bool) {} +func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {} func (s *Scanner) Name() string { return "Dockerfile" } -func (s *Scanner) SetPolicyReaders(readers []io.Reader) { - s.policyReaders = readers -} - -func (s *Scanner) SetTraceWriter(_ io.Writer) { - // handled by rego later - nothing to do for now... -} - -func (s *Scanner) SetPerResultTracingEnabled(_ bool) { - // handled by rego later - nothing to do for now... -} - -func (s *Scanner) SetPolicyDirs(dirs ...string) { - s.policyDirs = dirs -} - -func (s *Scanner) SetDataDirs(_ ...string) { - // handled by rego later - nothing to do for now... -} - -func (s *Scanner) SetPolicyNamespaces(_ ...string) { - // handled by rego later - nothing to do for now... -} - -func (s *Scanner) SetPolicyFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} - -func (s *Scanner) SetDataFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} - -func (s *Scanner) SetRegoErrorLimit(_ int) { - // handled by rego when option is passed on -} - func NewScanner(opts ...options.ScannerOption) *Scanner { s := &Scanner{ options: opts, @@ -154,7 +93,7 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { } regoScanner := rego.NewScanner(types.SourceDockerfile, s.options...) - if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { + if err := regoScanner.LoadPolicies(srcFS); err != nil { return nil, err } s.regoScanner = regoScanner diff --git a/pkg/iac/scanners/dockerfile/scanner_test.go b/pkg/iac/scanners/dockerfile/scanner_test.go index 4cbd86667a17..2872df1e4ef6 100644 --- a/pkg/iac/scanners/dockerfile/scanner_test.go +++ b/pkg/iac/scanners/dockerfile/scanner_test.go @@ -10,9 +10,9 @@ import ( "github.com/aquasecurity/trivy/internal/testutil" "github.com/aquasecurity/trivy/pkg/iac/framework" + "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/rego/schemas" "github.com/aquasecurity/trivy/pkg/iac/scan" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) const DS006PolicyWithDockerfileSchema = `# METADATA @@ -219,7 +219,7 @@ USER root "/rules/rule.rego": DS006LegacyWithOldStyleMetadata, }) - scanner := NewScanner(options.ScannerWithPolicyDirs("rules")) + scanner := NewScanner(rego.WithPolicyDirs("rules")) results, err := scanner.ScanFS(context.TODO(), fs, "code") require.NoError(t, err) @@ -564,10 +564,10 @@ COPY --from=dep /binary /` var traceBuf bytes.Buffer scanner := NewScanner( - options.ScannerWithPolicyDirs("rules"), - options.ScannerWithEmbeddedLibraries(true), - options.ScannerWithTrace(&traceBuf), - options.ScannerWithRegoErrorLimits(0), + rego.WithPolicyDirs("rules"), + rego.WithEmbeddedLibraries(true), + rego.WithTrace(&traceBuf), + rego.WithRegoErrorLimits(0), ) results, err := scanner.ScanFS(context.TODO(), fsys, "code") diff --git a/pkg/iac/scanners/helm/scanner.go b/pkg/iac/scanners/helm/scanner.go index 305a116b56b7..bfa63a5d2c00 100644 --- a/pkg/iac/scanners/helm/scanner.go +++ b/pkg/iac/scanners/helm/scanner.go @@ -27,34 +27,16 @@ var _ scanners.FSScanner = (*Scanner)(nil) var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { - policyDirs []string - dataDirs []string - logger *log.Logger - options []options.ScannerOption - parserOptions []parser.Option - policyReaders []io.Reader - loadEmbeddedLibraries bool - loadEmbeddedPolicies bool - policyFS fs.FS - frameworks []framework.Framework - spec string - regoScanner *rego.Scanner - mu sync.Mutex + mu sync.Mutex + logger *log.Logger + options []options.ScannerOption + parserOptions []parser.Option + regoScanner *rego.Scanner } -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} -func (s *Scanner) SetCustomSchemas(map[string][]byte) {} - -func (s *Scanner) SetSpec(spec string) { - s.spec = spec -} - -func (s *Scanner) SetRegoOnly(bool) { -} - -func (s *Scanner) SetFrameworks(frameworks []framework.Framework) { - s.frameworks = frameworks -} +func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetRegoOnly(bool) {} +func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {} // New creates a new Scanner func New(opts ...options.ScannerOption) *Scanner { @@ -73,49 +55,10 @@ func (s *Scanner) addParserOptions(opts ...parser.Option) { s.parserOptions = append(s.parserOptions, opts...) } -func (s *Scanner) SetUseEmbeddedPolicies(b bool) { - s.loadEmbeddedPolicies = b -} - -func (s *Scanner) SetUseEmbeddedLibraries(b bool) { - s.loadEmbeddedLibraries = b -} - func (s *Scanner) Name() string { return "Helm" } -func (s *Scanner) SetPolicyReaders(readers []io.Reader) { - s.policyReaders = readers -} - -func (s *Scanner) SetTraceWriter(_ io.Writer) { - // handled by rego later - nothing to do for now... -} - -func (s *Scanner) SetPerResultTracingEnabled(_ bool) { - // handled by rego later - nothing to do for now... -} - -func (s *Scanner) SetPolicyDirs(dirs ...string) { - s.policyDirs = dirs -} - -func (s *Scanner) SetDataDirs(dirs ...string) { - s.dataDirs = dirs -} - -func (s *Scanner) SetPolicyNamespaces(namespaces ...string) { - // handled by rego later - nothing to do for now... -} - -func (s *Scanner) SetPolicyFilesystem(policyFS fs.FS) { - s.policyFS = policyFS -} - -func (s *Scanner) SetDataFilesystem(_ fs.FS) {} -func (s *Scanner) SetRegoErrorLimit(_ int) {} - func (s *Scanner) ScanFS(ctx context.Context, target fs.FS, path string) (scan.Results, error) { if err := s.initRegoScanner(target); err != nil { @@ -228,7 +171,7 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) error { return nil } regoScanner := rego.NewScanner(types.SourceKubernetes, s.options...) - if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { + if err := regoScanner.LoadPolicies(srcFS); err != nil { return err } s.regoScanner = regoScanner diff --git a/pkg/iac/scanners/helm/test/scanner_test.go b/pkg/iac/scanners/helm/test/scanner_test.go index 45a426762439..ef751ac2a7b8 100644 --- a/pkg/iac/scanners/helm/test/scanner_test.go +++ b/pkg/iac/scanners/helm/test/scanner_test.go @@ -13,8 +13,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scanners/helm" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) func Test_helm_scanner_with_archive(t *testing.T) { @@ -40,7 +40,7 @@ func Test_helm_scanner_with_archive(t *testing.T) { for _, test := range tests { t.Logf("Running test: %s", test.testName) - helmScanner := helm.New(options.ScannerWithEmbeddedPolicies(true), options.ScannerWithEmbeddedLibraries(true)) + helmScanner := helm.New(rego.WithEmbeddedPolicies(true), rego.WithEmbeddedLibraries(true)) testTemp := t.TempDir() testFileName := filepath.Join(testTemp, test.archiveName) @@ -96,7 +96,7 @@ func Test_helm_scanner_with_missing_name_can_recover(t *testing.T) { for _, test := range tests { t.Logf("Running test: %s", test.testName) - helmScanner := helm.New(options.ScannerWithEmbeddedPolicies(true), options.ScannerWithEmbeddedLibraries(true)) + helmScanner := helm.New(rego.WithEmbeddedPolicies(true), rego.WithEmbeddedLibraries(true)) testTemp := t.TempDir() testFileName := filepath.Join(testTemp, test.archiveName) @@ -128,7 +128,7 @@ func Test_helm_scanner_with_dir(t *testing.T) { t.Logf("Running test: %s", test.testName) - helmScanner := helm.New(options.ScannerWithEmbeddedPolicies(true), options.ScannerWithEmbeddedLibraries(true)) + helmScanner := helm.New(rego.WithEmbeddedPolicies(true), rego.WithEmbeddedLibraries(true)) testFs := os.DirFS(filepath.Join("testdata", test.chartName)) results, err := helmScanner.ScanFS(context.TODO(), testFs, ".") @@ -209,9 +209,9 @@ deny[res] { t.Run(test.testName, func(t *testing.T) { t.Logf("Running test: %s", test.testName) - helmScanner := helm.New(options.ScannerWithEmbeddedPolicies(true), options.ScannerWithEmbeddedLibraries(true), - options.ScannerWithPolicyDirs("rules"), - options.ScannerWithPolicyNamespaces("user")) + helmScanner := helm.New(rego.WithEmbeddedPolicies(true), rego.WithEmbeddedLibraries(true), + rego.WithPolicyDirs("rules"), + rego.WithPolicyNamespaces("user")) testTemp := t.TempDir() testFileName := filepath.Join(testTemp, test.archiveName) @@ -274,7 +274,7 @@ func copyArchive(src, dst string) error { } func Test_helm_chart_with_templated_name(t *testing.T) { - helmScanner := helm.New(options.ScannerWithEmbeddedPolicies(true), options.ScannerWithEmbeddedLibraries(true)) + helmScanner := helm.New(rego.WithEmbeddedPolicies(true), rego.WithEmbeddedLibraries(true)) testFs := os.DirFS(filepath.Join("testdata", "templated-name")) _, err := helmScanner.ScanFS(context.TODO(), testFs, ".") require.NoError(t, err) @@ -302,10 +302,10 @@ deny[res] { } ` helmScanner := helm.New( - options.ScannerWithEmbeddedPolicies(false), - options.ScannerWithEmbeddedLibraries(false), - options.ScannerWithPolicyNamespaces("user"), - options.ScannerWithPolicyReader(strings.NewReader(policy)), + rego.WithEmbeddedPolicies(false), + rego.WithEmbeddedLibraries(false), + rego.WithPolicyNamespaces("user"), + rego.WithPolicyReader(strings.NewReader(policy)), ) results, err := helmScanner.ScanFS(context.TODO(), os.DirFS("testdata/simmilar-templates"), ".") @@ -348,10 +348,10 @@ deny[res] { ` scanner := helm.New( - options.ScannerWithEmbeddedPolicies(false), - options.ScannerWithEmbeddedLibraries(true), - options.ScannerWithPolicyNamespaces("user"), - options.ScannerWithPolicyReader(strings.NewReader(check)), + rego.WithEmbeddedPolicies(false), + rego.WithEmbeddedLibraries(true), + rego.WithPolicyNamespaces("user"), + rego.WithPolicyReader(strings.NewReader(check)), ) results, err := scanner.ScanFS(context.TODO(), os.DirFS("testdata/with-subchart"), ".") diff --git a/pkg/iac/scanners/json/scanner.go b/pkg/iac/scanners/json/scanner.go index 8991120be26f..f46f9cc56bc9 100644 --- a/pkg/iac/scanners/json/scanner.go +++ b/pkg/iac/scanners/json/scanner.go @@ -2,7 +2,6 @@ package json import ( "context" - "io" "io/fs" "sync" @@ -20,66 +19,16 @@ var _ scanners.FSScanner = (*Scanner)(nil) var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { - mu sync.Mutex - logger *log.Logger - policyDirs []string - policyReaders []io.Reader - parser *parser.Parser - regoScanner *rego.Scanner - options []options.ScannerOption - frameworks []framework.Framework - spec string - loadEmbeddedPolicies bool - loadEmbeddedLibraries bool + mu sync.Mutex + logger *log.Logger + parser *parser.Parser + regoScanner *rego.Scanner + options []options.ScannerOption } -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} -func (s *Scanner) SetCustomSchemas(map[string][]byte) {} - -func (s *Scanner) SetRegoOnly(bool) { -} - -func (s *Scanner) SetFrameworks(frameworks []framework.Framework) { - s.frameworks = frameworks -} - -func (s *Scanner) SetSpec(spec string) { - s.spec = spec -} - -func (s *Scanner) SetUseEmbeddedPolicies(b bool) { - s.loadEmbeddedPolicies = b -} - -func (s *Scanner) SetUseEmbeddedLibraries(b bool) { - s.loadEmbeddedLibraries = b -} - -func (s *Scanner) SetPolicyReaders(readers []io.Reader) { - s.policyReaders = readers -} - -func (s *Scanner) SetTraceWriter(_ io.Writer) { -} - -func (s *Scanner) SetPerResultTracingEnabled(_ bool) { -} - -func (s *Scanner) SetPolicyDirs(dirs ...string) { - s.policyDirs = dirs -} - -func (s *Scanner) SetDataDirs(_ ...string) {} -func (s *Scanner) SetPolicyNamespaces(_ ...string) {} - -func (s *Scanner) SetPolicyFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} - -func (s *Scanner) SetDataFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} -func (s *Scanner) SetRegoErrorLimit(_ int) {} +func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetRegoOnly(bool) {} +func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {} func NewScanner(opts ...options.ScannerOption) *Scanner { s := &Scanner{ @@ -143,7 +92,7 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { return s.regoScanner, nil } regoScanner := rego.NewScanner(types.SourceJSON, s.options...) - if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { + if err := regoScanner.LoadPolicies(srcFS); err != nil { return nil, err } s.regoScanner = regoScanner diff --git a/pkg/iac/scanners/json/scanner_test.go b/pkg/iac/scanners/json/scanner_test.go index e126768e55d8..6656f70b2e25 100644 --- a/pkg/iac/scanners/json/scanner_test.go +++ b/pkg/iac/scanners/json/scanner_test.go @@ -9,8 +9,8 @@ import ( "github.com/aquasecurity/trivy/internal/testutil" "github.com/aquasecurity/trivy/pkg/iac/framework" + "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scan" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) func Test_BasicScan(t *testing.T) { @@ -48,7 +48,7 @@ deny[res] { `, }) - scanner := NewScanner(options.ScannerWithPolicyDirs("rules")) + scanner := NewScanner(rego.WithPolicyDirs("rules")) results, err := scanner.ScanFS(context.TODO(), fs, "code") require.NoError(t, err) diff --git a/pkg/iac/scanners/kubernetes/scanner.go b/pkg/iac/scanners/kubernetes/scanner.go index e9e9eacd73e8..dfd248cc8b1d 100644 --- a/pkg/iac/scanners/kubernetes/scanner.go +++ b/pkg/iac/scanners/kubernetes/scanner.go @@ -24,66 +24,16 @@ var _ scanners.FSScanner = (*Scanner)(nil) var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { - mu sync.Mutex - logger *log.Logger - options []options.ScannerOption - policyDirs []string - policyReaders []io.Reader - regoScanner *rego.Scanner - parser *parser.Parser - loadEmbeddedPolicies bool - frameworks []framework.Framework - spec string - loadEmbeddedLibraries bool + mu sync.Mutex + logger *log.Logger + options []options.ScannerOption + regoScanner *rego.Scanner + parser *parser.Parser } -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} -func (s *Scanner) SetCustomSchemas(map[string][]byte) {} - -func (s *Scanner) SetSpec(spec string) { - s.spec = spec -} - -func (s *Scanner) SetRegoOnly(bool) {} - -func (s *Scanner) SetFrameworks(frameworks []framework.Framework) { - s.frameworks = frameworks -} - -func (s *Scanner) SetUseEmbeddedPolicies(b bool) { - s.loadEmbeddedPolicies = b -} - -func (s *Scanner) SetUseEmbeddedLibraries(b bool) { - s.loadEmbeddedLibraries = b -} - -func (s *Scanner) SetPolicyReaders(readers []io.Reader) { - s.policyReaders = readers -} - -func (s *Scanner) SetTraceWriter(_ io.Writer) { -} - -func (s *Scanner) SetPerResultTracingEnabled(_ bool) { -} - -func (s *Scanner) SetPolicyDirs(dirs ...string) { - s.policyDirs = dirs -} - -func (s *Scanner) SetDataDirs(...string) {} -func (s *Scanner) SetPolicyNamespaces(_ ...string) { -} - -func (s *Scanner) SetPolicyFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} - -func (s *Scanner) SetDataFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} -func (s *Scanner) SetRegoErrorLimit(_ int) {} +func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetRegoOnly(bool) {} +func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {} func NewScanner(opts ...options.ScannerOption) *Scanner { s := &Scanner{ @@ -108,7 +58,7 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { return s.regoScanner, nil } regoScanner := rego.NewScanner(types.SourceKubernetes, s.options...) - if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { + if err := regoScanner.LoadPolicies(srcFS); err != nil { return nil, err } s.regoScanner = regoScanner diff --git a/pkg/iac/scanners/kubernetes/scanner_test.go b/pkg/iac/scanners/kubernetes/scanner_test.go index c981634a0ee6..ef1ac38560f4 100644 --- a/pkg/iac/scanners/kubernetes/scanner_test.go +++ b/pkg/iac/scanners/kubernetes/scanner_test.go @@ -11,8 +11,8 @@ import ( "github.com/aquasecurity/trivy/internal/testutil" "github.com/aquasecurity/trivy/pkg/iac/framework" + "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scan" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) func Test_BasicScan_YAML(t *testing.T) { @@ -94,8 +94,8 @@ deny[res] { }) scanner := NewScanner( - options.ScannerWithPolicyDirs("rules"), - options.ScannerWithEmbeddedLibraries(true), + rego.WithPolicyDirs("rules"), + rego.WithEmbeddedLibraries(true), ) results, err := scanner.ScanFS(context.TODO(), fs, "code") @@ -256,8 +256,8 @@ deny[res] { }) scanner := NewScanner( - options.ScannerWithPolicyDirs("rules"), - options.ScannerWithEmbeddedLibraries(true), + rego.WithPolicyDirs("rules"), + rego.WithEmbeddedLibraries(true), ) results, err := scanner.ScanFS(context.TODO(), fs, "code") @@ -330,7 +330,7 @@ deny[res] { func Test_FileScan(t *testing.T) { - results, err := NewScanner(options.ScannerWithEmbeddedPolicies(true), options.ScannerWithEmbeddedLibraries(true), options.ScannerWithEmbeddedLibraries(true)).ScanReader(context.TODO(), "k8s.yaml", strings.NewReader(` + results, err := NewScanner(rego.WithEmbeddedPolicies(true), rego.WithEmbeddedLibraries(true), rego.WithEmbeddedLibraries(true)).ScanReader(context.TODO(), "k8s.yaml", strings.NewReader(` apiVersion: v1 kind: Pod metadata: @@ -348,7 +348,7 @@ spec: func Test_FileScan_WithSeparator(t *testing.T) { - results, err := NewScanner(options.ScannerWithEmbeddedPolicies(true), options.ScannerWithEmbeddedLibraries(true)).ScanReader(context.TODO(), "k8s.yaml", strings.NewReader(` + results, err := NewScanner(rego.WithEmbeddedPolicies(true), rego.WithEmbeddedLibraries(true)).ScanReader(context.TODO(), "k8s.yaml", strings.NewReader(` --- --- apiVersion: v1 @@ -391,9 +391,9 @@ spec: ` results, err := NewScanner( - options.ScannerWithEmbeddedPolicies(true), - options.ScannerWithEmbeddedLibraries(true), - options.ScannerWithEmbeddedLibraries(true)).ScanReader(context.TODO(), "k8s.yaml", strings.NewReader(file)) + rego.WithEmbeddedPolicies(true), + rego.WithEmbeddedLibraries(true), + rego.WithEmbeddedLibraries(true)).ScanReader(context.TODO(), "k8s.yaml", strings.NewReader(file)) require.NoError(t, err) assert.Greater(t, len(results.GetFailed()), 1) @@ -411,7 +411,7 @@ spec: func Test_FileScanWithPolicyReader(t *testing.T) { - results, err := NewScanner(options.ScannerWithPolicyReader(strings.NewReader(`package defsec + results, err := NewScanner(rego.WithPolicyReader(strings.NewReader(`package defsec deny[msg] { msg = "fail" @@ -434,7 +434,7 @@ spec: func Test_FileScanJSON(t *testing.T) { - results, err := NewScanner(options.ScannerWithPolicyReader(strings.NewReader(`package defsec + results, err := NewScanner(rego.WithPolicyReader(strings.NewReader(`package defsec deny[msg] { input.kind == "Pod" @@ -490,8 +490,8 @@ deny[msg] { func Test_FileScanWithMetadata(t *testing.T) { results, err := NewScanner( - options.ScannerWithTrace(os.Stdout), - options.ScannerWithPolicyReader(strings.NewReader(`package defsec + rego.WithTrace(os.Stdout), + rego.WithPolicyReader(strings.NewReader(`package defsec deny[msg] { input.kind == "Pod" @@ -529,8 +529,8 @@ spec: func Test_FileScanExampleWithResultFunction(t *testing.T) { results, err := NewScanner( - options.ScannerWithEmbeddedPolicies(true), options.ScannerWithEmbeddedLibraries(true), - options.ScannerWithPolicyReader(strings.NewReader(`package defsec + rego.WithEmbeddedPolicies(true), rego.WithEmbeddedLibraries(true), + rego.WithPolicyReader(strings.NewReader(`package defsec import data.lib.kubernetes @@ -707,10 +707,10 @@ spec: }) scanner := NewScanner( - // options.ScannerWithEmbeddedPolicies(true), options.ScannerWithEmbeddedLibraries(true), - options.ScannerWithEmbeddedLibraries(true), - options.ScannerWithPolicyDirs("policies/"), - options.ScannerWithPolicyFilesystem(srcFS), + // rego.WithEmbeddedPolicies(true), rego.WithEmbeddedLibraries(true), + rego.WithEmbeddedLibraries(true), + rego.WithPolicyDirs("policies/"), + rego.WithPolicyFilesystem(srcFS), ) results, err := scanner.ScanFS(context.TODO(), srcFS, "test/KSV001") require.NoError(t, err) diff --git a/pkg/iac/scanners/options/scanner.go b/pkg/iac/scanners/options/scanner.go index 4f07c4d14b0a..a9561d95130a 100644 --- a/pkg/iac/scanners/options/scanner.go +++ b/pkg/iac/scanners/options/scanner.go @@ -1,61 +1,13 @@ package options import ( - "io" - "io/fs" - "github.com/aquasecurity/trivy/pkg/iac/framework" ) type ConfigurableScanner interface { - SetTraceWriter(io.Writer) - SetPerResultTracingEnabled(bool) - SetPolicyDirs(...string) - SetDataDirs(...string) - SetPolicyNamespaces(...string) - SetPolicyReaders([]io.Reader) - SetPolicyFilesystem(fs.FS) - SetDataFilesystem(fs.FS) - SetUseEmbeddedPolicies(bool) SetFrameworks(frameworks []framework.Framework) - SetSpec(spec string) SetRegoOnly(regoOnly bool) - SetRegoErrorLimit(limit int) - SetUseEmbeddedLibraries(bool) SetIncludeDeprecatedChecks(bool) - SetCustomSchemas(map[string][]byte) -} - -type ScannerOption func(s ConfigurableScanner) - -func ScannerWithFrameworks(frameworks ...framework.Framework) ScannerOption { - return func(s ConfigurableScanner) { - s.SetFrameworks(frameworks) - } -} - -func ScannerWithSpec(spec string) ScannerOption { - return func(s ConfigurableScanner) { - s.SetSpec(spec) - } -} - -func ScannerWithPolicyReader(readers ...io.Reader) ScannerOption { - return func(s ConfigurableScanner) { - s.SetPolicyReaders(readers) - } -} - -func ScannerWithEmbeddedPolicies(embedded bool) ScannerOption { - return func(s ConfigurableScanner) { - s.SetUseEmbeddedPolicies(embedded) - } -} - -func ScannerWithEmbeddedLibraries(enabled bool) ScannerOption { - return func(s ConfigurableScanner) { - s.SetUseEmbeddedLibraries(enabled) - } } func ScannerWithIncludeDeprecatedChecks(enabled bool) ScannerOption { @@ -64,47 +16,11 @@ func ScannerWithIncludeDeprecatedChecks(enabled bool) ScannerOption { } } -// ScannerWithTrace specifies an io.Writer for trace logs (mainly rego tracing) - if not set, they are discarded -func ScannerWithTrace(w io.Writer) ScannerOption { - return func(s ConfigurableScanner) { - s.SetTraceWriter(w) - } -} - -func ScannerWithPerResultTracing(enabled bool) ScannerOption { - return func(s ConfigurableScanner) { - s.SetPerResultTracingEnabled(enabled) - } -} - -func ScannerWithPolicyDirs(paths ...string) ScannerOption { - return func(s ConfigurableScanner) { - s.SetPolicyDirs(paths...) - } -} - -func ScannerWithDataDirs(paths ...string) ScannerOption { - return func(s ConfigurableScanner) { - s.SetDataDirs(paths...) - } -} - -// ScannerWithPolicyNamespaces - namespaces which indicate rego policies containing enforced rules -func ScannerWithPolicyNamespaces(namespaces ...string) ScannerOption { - return func(s ConfigurableScanner) { - s.SetPolicyNamespaces(namespaces...) - } -} - -func ScannerWithPolicyFilesystem(f fs.FS) ScannerOption { - return func(s ConfigurableScanner) { - s.SetPolicyFilesystem(f) - } -} +type ScannerOption func(s ConfigurableScanner) -func ScannerWithDataFilesystem(f fs.FS) ScannerOption { +func ScannerWithFrameworks(frameworks ...framework.Framework) ScannerOption { return func(s ConfigurableScanner) { - s.SetDataFilesystem(f) + s.SetFrameworks(frameworks) } } @@ -113,15 +29,3 @@ func ScannerWithRegoOnly(regoOnly bool) ScannerOption { s.SetRegoOnly(regoOnly) } } - -func ScannerWithRegoErrorLimits(limit int) ScannerOption { - return func(s ConfigurableScanner) { - s.SetRegoErrorLimit(limit) - } -} - -func ScannerWithCustomSchemas(schemas map[string][]byte) ScannerOption { - return func(s ConfigurableScanner) { - s.SetCustomSchemas(schemas) - } -} diff --git a/pkg/iac/scanners/terraform/fs_test.go b/pkg/iac/scanners/terraform/fs_test.go index 649062792514..fb5448873607 100644 --- a/pkg/iac/scanners/terraform/fs_test.go +++ b/pkg/iac/scanners/terraform/fs_test.go @@ -8,13 +8,13 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" + "github.com/aquasecurity/trivy/pkg/iac/rego" ) func Test_OS_FS(t *testing.T) { s := New( - options.ScannerWithEmbeddedPolicies(true), - options.ScannerWithEmbeddedLibraries(true), + rego.WithEmbeddedPolicies(true), + rego.WithEmbeddedLibraries(true), ) results, err := s.ScanFS(context.TODO(), os.DirFS("testdata"), "fail") require.NoError(t, err) diff --git a/pkg/iac/scanners/terraform/ignore_test.go b/pkg/iac/scanners/terraform/ignore_test.go index 4a2cbce14a86..a42abc323d31 100644 --- a/pkg/iac/scanners/terraform/ignore_test.go +++ b/pkg/iac/scanners/terraform/ignore_test.go @@ -11,6 +11,7 @@ import ( "github.com/aquasecurity/trivy/internal/testutil" "github.com/aquasecurity/trivy/pkg/iac/providers" + "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/rules" "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" @@ -956,11 +957,11 @@ deny[res] { }` localScanner := New( - options.ScannerWithEmbeddedPolicies(false), - options.ScannerWithEmbeddedLibraries(true), + rego.WithEmbeddedPolicies(false), + rego.WithEmbeddedLibraries(true), options.ScannerWithRegoOnly(true), - options.ScannerWithPolicyNamespaces("user"), - options.ScannerWithPolicyReader(strings.NewReader(check)), + rego.WithPolicyNamespaces("user"), + rego.WithPolicyReader(strings.NewReader(check)), ScannerWithDownloadsAllowed(false), ScannerWithSkipCachedModules(true), ) diff --git a/pkg/iac/scanners/terraform/scanner.go b/pkg/iac/scanners/terraform/scanner.go index d01afb8d962e..d574acdb2c4a 100644 --- a/pkg/iac/scanners/terraform/scanner.go +++ b/pkg/iac/scanners/terraform/scanner.go @@ -3,7 +3,6 @@ package terraform import ( "context" "fmt" - "io" "io/fs" "path" "path/filepath" @@ -28,48 +27,27 @@ var _ options.ConfigurableScanner = (*Scanner)(nil) var _ ConfigurableTerraformScanner = (*Scanner)(nil) type Scanner struct { - mu sync.Mutex - logger *log.Logger - options []options.ScannerOption - parserOpt []parser.Option - executorOpt []executor.Option - dirs map[string]struct{} - forceAllDirs bool - policyDirs []string - policyReaders []io.Reader - regoScanner *rego.Scanner - execLock sync.RWMutex - - frameworks []framework.Framework - spec string - loadEmbeddedLibraries bool - loadEmbeddedPolicies bool + mu sync.Mutex + logger *log.Logger + options []options.ScannerOption + parserOpt []parser.Option + executorOpt []executor.Option + dirs map[string]struct{} + forceAllDirs bool + regoScanner *rego.Scanner + execLock sync.RWMutex } func (s *Scanner) SetIncludeDeprecatedChecks(b bool) { s.executorOpt = append(s.executorOpt, executor.OptionWithIncludeDeprecatedChecks(b)) } -func (s *Scanner) SetCustomSchemas(map[string][]byte) {} - -func (s *Scanner) SetSpec(spec string) { - s.spec = spec -} - func (s *Scanner) SetRegoOnly(regoOnly bool) { s.executorOpt = append(s.executorOpt, executor.OptionWithRegoOnly(regoOnly)) } func (s *Scanner) SetFrameworks(frameworks []framework.Framework) { - s.frameworks = frameworks -} - -func (s *Scanner) SetUseEmbeddedPolicies(b bool) { - s.loadEmbeddedPolicies = b -} - -func (s *Scanner) SetUseEmbeddedLibraries(b bool) { - s.loadEmbeddedLibraries = b + s.executorOpt = append(s.executorOpt, executor.OptionWithFrameworks(frameworks...)) } func (s *Scanner) Name() string { @@ -88,32 +66,6 @@ func (s *Scanner) AddExecutorOptions(opts ...executor.Option) { s.executorOpt = append(s.executorOpt, opts...) } -func (s *Scanner) SetPolicyReaders(readers []io.Reader) { - s.policyReaders = readers -} - -func (s *Scanner) SetTraceWriter(_ io.Writer) { -} - -func (s *Scanner) SetPerResultTracingEnabled(_ bool) { -} - -func (s *Scanner) SetPolicyDirs(dirs ...string) { - s.policyDirs = dirs -} - -func (s *Scanner) SetDataDirs(_ ...string) {} -func (s *Scanner) SetPolicyNamespaces(_ ...string) {} - -func (s *Scanner) SetPolicyFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} - -func (s *Scanner) SetDataFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} -func (s *Scanner) SetRegoErrorLimit(_ int) {} - func New(opts ...options.ScannerOption) *Scanner { s := &Scanner{ dirs: make(map[string]struct{}), @@ -133,7 +85,7 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { return s.regoScanner, nil } regoScanner := rego.NewScanner(types.SourceCloud, s.options...) - if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { + if err := regoScanner.LoadPolicies(srcFS); err != nil { return nil, err } s.regoScanner = regoScanner @@ -166,7 +118,7 @@ func (s *Scanner) ScanFS(ctx context.Context, target fs.FS, dir string) (scan.Re } s.execLock.Lock() - s.executorOpt = append(s.executorOpt, executor.OptionWithRegoScanner(regoScanner), executor.OptionWithFrameworks(s.frameworks...)) + s.executorOpt = append(s.executorOpt, executor.OptionWithRegoScanner(regoScanner)) s.execLock.Unlock() var allResults scan.Results diff --git a/pkg/iac/scanners/terraform/scanner_integration_test.go b/pkg/iac/scanners/terraform/scanner_integration_test.go index 098d6a91d450..96c681e97553 100644 --- a/pkg/iac/scanners/terraform/scanner_integration_test.go +++ b/pkg/iac/scanners/terraform/scanner_integration_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/internal/testutil" + "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) @@ -44,10 +45,10 @@ deny[res] { }) scanner := New( - options.ScannerWithPolicyFilesystem(fs), - options.ScannerWithPolicyDirs("rules"), - options.ScannerWithEmbeddedPolicies(false), - options.ScannerWithEmbeddedLibraries(false), + rego.WithPolicyFilesystem(fs), + rego.WithPolicyDirs("rules"), + rego.WithEmbeddedPolicies(false), + rego.WithEmbeddedLibraries(false), options.ScannerWithRegoOnly(true), ScannerWithAllDirectories(true), ScannerWithSkipCachedModules(true), @@ -101,10 +102,10 @@ deny[res] { }) scanner := New( - options.ScannerWithPolicyFilesystem(fs), - options.ScannerWithPolicyDirs("rules"), - options.ScannerWithEmbeddedPolicies(false), - options.ScannerWithEmbeddedLibraries(false), + rego.WithPolicyFilesystem(fs), + rego.WithPolicyDirs("rules"), + rego.WithEmbeddedPolicies(false), + rego.WithEmbeddedLibraries(false), options.ScannerWithRegoOnly(true), ScannerWithAllDirectories(true), ScannerWithSkipCachedModules(true), @@ -147,10 +148,10 @@ deny[cause] { t.Run("without skip", func(t *testing.T) { scanner := New( ScannerWithSkipCachedModules(true), - options.ScannerWithPolicyDirs("rules"), + rego.WithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), - options.ScannerWithEmbeddedPolicies(false), - options.ScannerWithEmbeddedLibraries(true), + rego.WithEmbeddedPolicies(false), + rego.WithEmbeddedLibraries(true), ) results, err := scanner.ScanFS(context.TODO(), fs, "test") require.NoError(t, err) @@ -163,10 +164,10 @@ deny[cause] { scanner := New( ScannerWithSkipDownloaded(true), ScannerWithSkipCachedModules(true), - options.ScannerWithPolicyDirs("rules"), + rego.WithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), - options.ScannerWithEmbeddedPolicies(false), - options.ScannerWithEmbeddedLibraries(true), + rego.WithEmbeddedPolicies(false), + rego.WithEmbeddedLibraries(true), ) results, err := scanner.ScanFS(context.TODO(), fs, "test") require.NoError(t, err) @@ -217,10 +218,10 @@ deny[res] { scanner := New( ScannerWithSkipDownloaded(true), ScannerWithSkipCachedModules(true), - options.ScannerWithPolicyDirs("rules"), + rego.WithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), - options.ScannerWithEmbeddedLibraries(true), - options.ScannerWithEmbeddedPolicies(false), + rego.WithEmbeddedLibraries(true), + rego.WithEmbeddedPolicies(false), ) results, err := scanner.ScanFS(context.TODO(), fs, "test") require.NoError(t, err) diff --git a/pkg/iac/scanners/terraform/scanner_test.go b/pkg/iac/scanners/terraform/scanner_test.go index cd1663ec0eda..39ee35e81321 100644 --- a/pkg/iac/scanners/terraform/scanner_test.go +++ b/pkg/iac/scanners/terraform/scanner_test.go @@ -11,6 +11,7 @@ import ( "github.com/aquasecurity/trivy/internal/testutil" "github.com/aquasecurity/trivy/pkg/iac/providers" + "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/rules" "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" @@ -76,8 +77,8 @@ deny[cause] { }) scanner := New( - options.ScannerWithPolicyFilesystem(fs), - options.ScannerWithPolicyDirs("rules"), + rego.WithPolicyFilesystem(fs), + rego.WithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), ) @@ -213,8 +214,8 @@ cause := bucket.name }) scanner := New( - options.ScannerWithPolicyDirs("rules"), - options.ScannerWithPolicyNamespaces(test.includedNamespaces...), + rego.WithPolicyDirs("rules"), + rego.WithPolicyNamespaces(test.includedNamespaces...), ) results, err := scanner.ScanFS(context.TODO(), fs, "code") @@ -270,7 +271,7 @@ deny[cause] { }) scanner := New( - options.ScannerWithPolicyDirs("rules"), + rego.WithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), ) @@ -318,9 +319,9 @@ deny[res] { }) scanner := New( - options.ScannerWithPolicyDirs("rules"), + rego.WithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), - options.ScannerWithEmbeddedLibraries(true), + rego.WithEmbeddedLibraries(true), ) results, err := scanner.ScanFS(context.TODO(), fs, "code") @@ -386,9 +387,9 @@ deny[res] { }) scanner := New( - options.ScannerWithPolicyDirs("rules"), + rego.WithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), - options.ScannerWithEmbeddedLibraries(true), + rego.WithEmbeddedLibraries(true), ) results, err := scanner.ScanFS(context.TODO(), fs, "code") @@ -470,9 +471,9 @@ deny[res] { }) scanner := New( - options.ScannerWithPolicyDirs("rules"), + rego.WithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), - options.ScannerWithEmbeddedLibraries(true), + rego.WithEmbeddedLibraries(true), ) results, err := scanner.ScanFS(context.TODO(), fs, "code") @@ -643,8 +644,8 @@ deny[res] { }) scanner := New( - options.ScannerWithPolicyFilesystem(fs), - options.ScannerWithPolicyDirs("rules"), + rego.WithPolicyFilesystem(fs), + rego.WithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), ) @@ -718,11 +719,11 @@ bucket_name = "test" }) scanner := New( - options.ScannerWithPolicyDirs("rules"), - options.ScannerWithPolicyFilesystem(fs), + rego.WithPolicyDirs("rules"), + rego.WithPolicyFilesystem(fs), options.ScannerWithRegoOnly(true), - options.ScannerWithEmbeddedLibraries(false), - options.ScannerWithEmbeddedPolicies(false), + rego.WithEmbeddedLibraries(false), + rego.WithEmbeddedPolicies(false), ScannerWithAllDirectories(true), ScannerWithTFVarsPaths("main.tfvars"), ScannerWithConfigsFileSystem(configsFS), @@ -752,11 +753,11 @@ bucket_name = "test" }) scanner := New( - options.ScannerWithPolicyDirs("rules"), - options.ScannerWithPolicyFilesystem(fs), + rego.WithPolicyDirs("rules"), + rego.WithPolicyFilesystem(fs), options.ScannerWithRegoOnly(true), - options.ScannerWithEmbeddedLibraries(false), - options.ScannerWithEmbeddedPolicies(false), + rego.WithEmbeddedLibraries(false), + rego.WithEmbeddedPolicies(false), ScannerWithAllDirectories(true), ScannerWithTFVarsPaths("main.tfvars"), ScannerWithConfigsFileSystem(fs), @@ -845,10 +846,10 @@ deny[res] { }) scanner := New( - options.ScannerWithPolicyFilesystem(fs), - options.ScannerWithPolicyDirs("rules"), - options.ScannerWithEmbeddedPolicies(false), - options.ScannerWithEmbeddedLibraries(false), + rego.WithPolicyFilesystem(fs), + rego.WithPolicyDirs("rules"), + rego.WithEmbeddedPolicies(false), + rego.WithEmbeddedLibraries(false), options.ScannerWithRegoOnly(true), ScannerWithAllDirectories(true), ) @@ -915,11 +916,11 @@ deny[res] { }) scanner := New( - options.ScannerWithPolicyDirs("rules"), - options.ScannerWithPolicyFilesystem(fs), + rego.WithPolicyDirs("rules"), + rego.WithPolicyFilesystem(fs), options.ScannerWithRegoOnly(true), - options.ScannerWithEmbeddedLibraries(false), - options.ScannerWithEmbeddedPolicies(false), + rego.WithEmbeddedLibraries(false), + rego.WithEmbeddedPolicies(false), ScannerWithAllDirectories(true), ) @@ -984,11 +985,11 @@ deny[res] { }) scanner := New( - options.ScannerWithPolicyDirs("rules"), - options.ScannerWithPolicyFilesystem(fs), + rego.WithPolicyDirs("rules"), + rego.WithPolicyFilesystem(fs), options.ScannerWithRegoOnly(true), - options.ScannerWithEmbeddedLibraries(false), - options.ScannerWithEmbeddedPolicies(false), + rego.WithEmbeddedLibraries(false), + rego.WithEmbeddedPolicies(false), ScannerWithAllDirectories(true), ) @@ -1048,13 +1049,13 @@ deny[res] { }) scanner := New( - options.ScannerWithPolicyDirs("rules"), - options.ScannerWithPolicyFilesystem(fs), + rego.WithPolicyDirs("rules"), + rego.WithPolicyFilesystem(fs), options.ScannerWithRegoOnly(true), - options.ScannerWithPolicyNamespaces("user"), - options.ScannerWithEmbeddedLibraries(false), - options.ScannerWithEmbeddedPolicies(false), - options.ScannerWithRegoErrorLimits(0), + rego.WithPolicyNamespaces("user"), + rego.WithEmbeddedLibraries(false), + rego.WithEmbeddedPolicies(false), + rego.WithRegoErrorLimits(0), ScannerWithAllDirectories(true), ) @@ -1089,9 +1090,9 @@ func TestSkipDeprecatedGoChecks(t *testing.T) { }) scanner := New( - options.ScannerWithPolicyFilesystem(fsys), - options.ScannerWithEmbeddedLibraries(false), - options.ScannerWithEmbeddedPolicies(false), + rego.WithPolicyFilesystem(fsys), + rego.WithEmbeddedLibraries(false), + rego.WithEmbeddedPolicies(false), ScannerWithAllDirectories(true), ) diff --git a/pkg/iac/scanners/terraform/setup_test.go b/pkg/iac/scanners/terraform/setup_test.go index d7a8f0277a96..5b98c438f9c1 100644 --- a/pkg/iac/scanners/terraform/setup_test.go +++ b/pkg/iac/scanners/terraform/setup_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/internal/testutil" + "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/parser" @@ -39,7 +40,7 @@ func scanHCL(t *testing.T, source string, opts ...options.ScannerOption) scan.Re "main.tf": source, }) - localScanner := New(append(opts, options.ScannerWithEmbeddedPolicies(false))...) + localScanner := New(append(opts, rego.WithEmbeddedPolicies(false))...) results, err := localScanner.ScanFS(context.TODO(), fs, ".") require.NoError(t, err) return results @@ -51,7 +52,7 @@ func scanJSON(t *testing.T, source string) scan.Results { "main.tf.json": source, }) - s := New(options.ScannerWithEmbeddedPolicies(true), options.ScannerWithEmbeddedLibraries(true)) + s := New(rego.WithEmbeddedPolicies(true), rego.WithEmbeddedLibraries(true)) results, err := s.ScanFS(context.TODO(), fs, ".") require.NoError(t, err) return results diff --git a/pkg/iac/scanners/terraformplan/snapshot/scanner_test.go b/pkg/iac/scanners/terraformplan/snapshot/scanner_test.go index c7ad3a3b4e0b..992bed5af809 100644 --- a/pkg/iac/scanners/terraformplan/snapshot/scanner_test.go +++ b/pkg/iac/scanners/terraformplan/snapshot/scanner_test.go @@ -12,6 +12,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" tfscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform" @@ -19,12 +20,12 @@ import ( func initScanner(opts ...options.ScannerOption) *Scanner { defaultOpts := []options.ScannerOption{ - options.ScannerWithEmbeddedPolicies(false), - options.ScannerWithEmbeddedLibraries(true), - options.ScannerWithPolicyNamespaces("user"), - options.ScannerWithPolicyDirs("."), + rego.WithEmbeddedPolicies(false), + rego.WithEmbeddedLibraries(true), + rego.WithPolicyNamespaces("user"), + rego.WithPolicyDirs("."), options.ScannerWithRegoOnly(true), - options.ScannerWithRegoErrorLimits(0), + rego.WithRegoErrorLimits(0), tfscanner.ScannerWithSkipCachedModules(true), } @@ -59,7 +60,7 @@ func TestScanner_Scan(t *testing.T) { policyFS := os.DirFS(filepath.Join("testdata", tt.dir, "checks")) - s := initScanner(options.ScannerWithPolicyFilesystem(policyFS)) + s := initScanner(rego.WithPolicyFilesystem(policyFS)) result, err := s.Scan(context.TODO(), f) require.NoError(t, err) @@ -108,13 +109,13 @@ func Test_ScanFS(t *testing.T) { fs := os.DirFS("testdata") scanner := New( - options.ScannerWithPolicyDirs(path.Join(tc.dir, "checks")), - options.ScannerWithPolicyFilesystem(fs), + rego.WithPolicyDirs(path.Join(tc.dir, "checks")), + rego.WithPolicyFilesystem(fs), options.ScannerWithRegoOnly(true), - options.ScannerWithPolicyNamespaces("user"), - options.ScannerWithEmbeddedLibraries(false), - options.ScannerWithEmbeddedPolicies(false), - options.ScannerWithRegoErrorLimits(0), + rego.WithPolicyNamespaces("user"), + rego.WithEmbeddedLibraries(false), + rego.WithEmbeddedPolicies(false), + rego.WithRegoErrorLimits(0), tfscanner.ScannerWithSkipCachedModules(true), ) diff --git a/pkg/iac/scanners/terraformplan/tfjson/scanner.go b/pkg/iac/scanners/terraformplan/tfjson/scanner.go index 8b16ecb43116..b3e8725c42ae 100644 --- a/pkg/iac/scanners/terraformplan/tfjson/scanner.go +++ b/pkg/iac/scanners/terraformplan/tfjson/scanner.go @@ -6,82 +6,20 @@ import ( "io" "io/fs" - "github.com/aquasecurity/trivy/pkg/iac/framework" "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" - terraformScanner "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform" - "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform/executor" + "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform" "github.com/aquasecurity/trivy/pkg/iac/scanners/terraformplan/tfjson/parser" "github.com/aquasecurity/trivy/pkg/log" ) type Scanner struct { - parser *parser.Parser - logger *log.Logger - options []options.ScannerOption - spec string - executorOpt []executor.Option - frameworks []framework.Framework - loadEmbeddedPolicies bool - loadEmbeddedLibraries bool - enableEmbeddedLibraries bool - policyDirs []string - policyReaders []io.Reader + parser *parser.Parser + logger *log.Logger + options []options.ScannerOption + tfScanner *terraform.Scanner } -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} -func (s *Scanner) SetCustomSchemas(map[string][]byte) {} - -func (s *Scanner) SetUseEmbeddedLibraries(b bool) { - s.loadEmbeddedLibraries = b -} - -func (s *Scanner) SetSpec(spec string) { - s.spec = spec -} - -func (s *Scanner) SetRegoOnly(regoOnly bool) { - s.executorOpt = append(s.executorOpt, executor.OptionWithRegoOnly(regoOnly)) -} - -func (s *Scanner) SetFrameworks(frameworks []framework.Framework) { - s.frameworks = frameworks -} - -func (s *Scanner) SetUseEmbeddedPolicies(b bool) { - s.loadEmbeddedPolicies = b -} - -func (s *Scanner) SetEmbeddedLibrariesEnabled(enabled bool) { - s.enableEmbeddedLibraries = enabled -} - -func (s *Scanner) SetPolicyReaders(readers []io.Reader) { - s.policyReaders = readers -} - -func (s *Scanner) SetTraceWriter(_ io.Writer) { -} - -func (s *Scanner) SetPerResultTracingEnabled(_ bool) { -} - -func (s *Scanner) SetPolicyDirs(dirs ...string) { - s.policyDirs = dirs -} - -func (s *Scanner) SetDataDirs(_ ...string) {} -func (s *Scanner) SetPolicyNamespaces(_ ...string) {} - -func (s *Scanner) SetPolicyFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} - -func (s *Scanner) SetDataFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} -func (s *Scanner) SetRegoErrorLimit(_ int) {} - func (s *Scanner) Name() string { return "Terraform Plan JSON" } @@ -117,12 +55,10 @@ func (s *Scanner) ScanFS(ctx context.Context, fsys fs.FS, dir string) (scan.Resu func New(opts ...options.ScannerOption) *Scanner { scanner := &Scanner{ - options: opts, - logger: log.WithPrefix("tfjson scanner"), - parser: parser.New(), - } - for _, o := range opts { - o(scanner) + options: opts, + logger: log.WithPrefix("tfjson scanner"), + parser: parser.New(), + tfScanner: terraform.New(opts...), } return scanner @@ -151,6 +87,5 @@ func (s *Scanner) Scan(reader io.Reader) (scan.Results, error) { return nil, fmt.Errorf("failed to convert plan to FS: %w", err) } - scanner := terraformScanner.New(s.options...) - return scanner.ScanFS(context.TODO(), planFS, ".") + return s.tfScanner.ScanFS(context.TODO(), planFS, ".") } diff --git a/pkg/iac/scanners/terraformplan/tfjson/scanner_test.go b/pkg/iac/scanners/terraformplan/tfjson/scanner_test.go index 289147f482dd..9173c8046bb1 100644 --- a/pkg/iac/scanners/terraformplan/tfjson/scanner_test.go +++ b/pkg/iac/scanners/terraformplan/tfjson/scanner_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/aquasecurity/trivy/internal/testutil" + "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) @@ -51,7 +52,7 @@ func Test_TerraformScanner(t *testing.T) { inputFile: "test/testdata/plan.json", check: defaultCheck, options: []options.ScannerOption{ - options.ScannerWithPolicyDirs("rules"), + rego.WithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), }, }, @@ -60,9 +61,9 @@ func Test_TerraformScanner(t *testing.T) { inputFile: "test/testdata/plan.json", check: defaultCheck, options: []options.ScannerOption{ - options.ScannerWithPolicyDirs("rules"), + rego.WithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), - options.ScannerWithPolicyNamespaces("user"), + rego.WithPolicyNamespaces("user"), }, }, { @@ -90,9 +91,9 @@ deny[cause] { } `, options: []options.ScannerOption{ - options.ScannerWithPolicyDirs("rules"), + rego.WithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), - options.ScannerWithPolicyNamespaces("user"), + rego.WithPolicyNamespaces("user"), }, }, { @@ -100,9 +101,9 @@ deny[cause] { inputFile: "test/testdata/arbitrary_name.json", check: defaultCheck, options: []options.ScannerOption{ - options.ScannerWithPolicyDirs("rules"), + rego.WithPolicyDirs("rules"), options.ScannerWithRegoOnly(true), - options.ScannerWithPolicyNamespaces("user"), + rego.WithPolicyNamespaces("user"), }, }, } @@ -115,7 +116,7 @@ deny[cause] { "/rules/test.rego": tc.check, }) - so := append(tc.options, options.ScannerWithPolicyFilesystem(fs)) + so := append(tc.options, rego.WithPolicyFilesystem(fs)) scanner := New(so...) results, err := scanner.ScanFS(context.TODO(), fs, "code") diff --git a/pkg/iac/scanners/terraformplan/tfjson/test/scanner_test.go b/pkg/iac/scanners/terraformplan/tfjson/test/scanner_test.go index dd77c2d89f6e..1c0ac8234862 100644 --- a/pkg/iac/scanners/terraformplan/tfjson/test/scanner_test.go +++ b/pkg/iac/scanners/terraformplan/tfjson/test/scanner_test.go @@ -8,15 +8,15 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scan" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/scanners/terraformplan/tfjson" ) func Test_Scanning_Plan(t *testing.T) { scanner := tfjson.New( - options.ScannerWithEmbeddedPolicies(true), - options.ScannerWithEmbeddedLibraries(true), + rego.WithEmbeddedPolicies(true), + rego.WithEmbeddedLibraries(true), ) b, _ := os.ReadFile("testdata/plan.json") testFS := fstest.MapFS{ diff --git a/pkg/iac/scanners/toml/scanner.go b/pkg/iac/scanners/toml/scanner.go index 235cc65dada5..216d0b1f9697 100644 --- a/pkg/iac/scanners/toml/scanner.go +++ b/pkg/iac/scanners/toml/scanner.go @@ -2,7 +2,6 @@ package toml import ( "context" - "io" "io/fs" "sync" @@ -18,67 +17,21 @@ import ( var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { - mu sync.Mutex - logger *log.Logger - options []options.ScannerOption - policyDirs []string - policyReaders []io.Reader - parser *parser.Parser - regoScanner *rego.Scanner - frameworks []framework.Framework - spec string - loadEmbeddedPolicies bool - loadEmbeddedLibraries bool + mu sync.Mutex + logger *log.Logger + options []options.ScannerOption + parser *parser.Parser + regoScanner *rego.Scanner } -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} -func (s *Scanner) SetCustomSchemas(map[string][]byte) {} - -func (s *Scanner) SetRegoOnly(bool) {} - -func (s *Scanner) SetFrameworks(frameworks []framework.Framework) { - s.frameworks = frameworks -} - -func (s *Scanner) SetSpec(spec string) { - s.spec = spec -} - -func (s *Scanner) SetUseEmbeddedPolicies(b bool) { - s.loadEmbeddedPolicies = b -} - -func (s *Scanner) SetUseEmbeddedLibraries(b bool) { - s.loadEmbeddedLibraries = b -} +func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetRegoOnly(bool) {} +func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {} func (s *Scanner) Name() string { return "TOML" } -func (s *Scanner) SetPolicyReaders(readers []io.Reader) { - s.policyReaders = readers -} - -func (s *Scanner) SetTraceWriter(_ io.Writer) {} -func (s *Scanner) SetPerResultTracingEnabled(_ bool) {} - -func (s *Scanner) SetPolicyDirs(dirs ...string) { - s.policyDirs = dirs -} - -func (s *Scanner) SetDataDirs(_ ...string) {} -func (s *Scanner) SetPolicyNamespaces(_ ...string) {} - -func (s *Scanner) SetPolicyFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} - -func (s *Scanner) SetDataFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} -func (s *Scanner) SetRegoErrorLimit(_ int) {} - func NewScanner(opts ...options.ScannerOption) *Scanner { s := &Scanner{ options: opts, @@ -137,7 +90,7 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { return s.regoScanner, nil } regoScanner := rego.NewScanner(types.SourceTOML, s.options...) - if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { + if err := regoScanner.LoadPolicies(srcFS); err != nil { return nil, err } s.regoScanner = regoScanner diff --git a/pkg/iac/scanners/toml/scanner_test.go b/pkg/iac/scanners/toml/scanner_test.go index d3c4e51e3b63..ea5819448288 100644 --- a/pkg/iac/scanners/toml/scanner_test.go +++ b/pkg/iac/scanners/toml/scanner_test.go @@ -9,8 +9,8 @@ import ( "github.com/aquasecurity/trivy/internal/testutil" "github.com/aquasecurity/trivy/pkg/iac/framework" + "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scan" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) func Test_BasicScan(t *testing.T) { @@ -52,7 +52,7 @@ deny[res] { `, }) - scanner := NewScanner(options.ScannerWithPolicyDirs("rules")) + scanner := NewScanner(rego.WithPolicyDirs("rules")) results, err := scanner.ScanFS(context.TODO(), fs, "code") require.NoError(t, err) diff --git a/pkg/iac/scanners/yaml/scanner.go b/pkg/iac/scanners/yaml/scanner.go index 67b661ee5971..565d10df1f83 100644 --- a/pkg/iac/scanners/yaml/scanner.go +++ b/pkg/iac/scanners/yaml/scanner.go @@ -2,7 +2,6 @@ package yaml import ( "context" - "io" "io/fs" "sync" @@ -18,66 +17,21 @@ import ( var _ options.ConfigurableScanner = (*Scanner)(nil) type Scanner struct { - mu sync.Mutex - options []options.ScannerOption - logger *log.Logger - policyDirs []string - policyReaders []io.Reader - parser *parser.Parser - regoScanner *rego.Scanner - frameworks []framework.Framework - spec string - loadEmbeddedLibraries bool - loadEmbeddedPolicies bool + mu sync.Mutex + options []options.ScannerOption + logger *log.Logger + parser *parser.Parser + regoScanner *rego.Scanner } -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} -func (s *Scanner) SetCustomSchemas(map[string][]byte) {} - -func (s *Scanner) SetRegoOnly(bool) {} - -func (s *Scanner) SetFrameworks(frameworks []framework.Framework) { - s.frameworks = frameworks -} - -func (s *Scanner) SetSpec(spec string) { - s.spec = spec -} - -func (s *Scanner) SetUseEmbeddedPolicies(b bool) { - s.loadEmbeddedPolicies = b -} - -func (s *Scanner) SetUseEmbeddedLibraries(b bool) { - s.loadEmbeddedLibraries = b -} +func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} +func (s *Scanner) SetRegoOnly(bool) {} +func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {} func (s *Scanner) Name() string { return "YAML" } -func (s *Scanner) SetPolicyReaders(readers []io.Reader) { - s.policyReaders = readers -} - -func (s *Scanner) SetTraceWriter(_ io.Writer) {} -func (s *Scanner) SetPerResultTracingEnabled(_ bool) {} - -func (s *Scanner) SetPolicyDirs(dirs ...string) { - s.policyDirs = dirs -} - -func (s *Scanner) SetDataDirs(_ ...string) {} -func (s *Scanner) SetPolicyNamespaces(_ ...string) {} - -func (s *Scanner) SetPolicyFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} -func (s *Scanner) SetDataFilesystem(_ fs.FS) { - // handled by rego when option is passed on -} -func (s *Scanner) SetRegoErrorLimit(_ int) {} - func NewScanner(opts ...options.ScannerOption) *Scanner { s := &Scanner{ options: opts, @@ -138,7 +92,7 @@ func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { return s.regoScanner, nil } regoScanner := rego.NewScanner(types.SourceYAML, s.options...) - if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil { + if err := regoScanner.LoadPolicies(srcFS); err != nil { return nil, err } s.regoScanner = regoScanner diff --git a/pkg/iac/scanners/yaml/scanner_test.go b/pkg/iac/scanners/yaml/scanner_test.go index 02468158fcf9..b7c4ec623887 100644 --- a/pkg/iac/scanners/yaml/scanner_test.go +++ b/pkg/iac/scanners/yaml/scanner_test.go @@ -9,8 +9,8 @@ import ( "github.com/aquasecurity/trivy/internal/testutil" "github.com/aquasecurity/trivy/pkg/iac/framework" + "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scan" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" ) func Test_BasicScan(t *testing.T) { @@ -55,7 +55,7 @@ deny[res] { `, }) - scanner := NewScanner(options.ScannerWithPolicyDirs("rules")) + scanner := NewScanner(rego.WithPolicyDirs("rules")) results, err := scanner.ScanFS(context.TODO(), fs, "code") require.NoError(t, err) diff --git a/pkg/misconf/scanner.go b/pkg/misconf/scanner.go index 2e979caba5e9..db203364a3e4 100644 --- a/pkg/misconf/scanner.go +++ b/pkg/misconf/scanner.go @@ -17,6 +17,7 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/iac/detection" + "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scan" "github.com/aquasecurity/trivy/pkg/iac/scanners" "github.com/aquasecurity/trivy/pkg/iac/scanners/azure/arm" @@ -208,8 +209,8 @@ func (s *Scanner) filterFS(fsys fs.FS) (fs.FS, error) { func scannerOptions(t detection.FileType, opt ScannerOption) ([]options.ScannerOption, error) { opts := []options.ScannerOption{ - options.ScannerWithEmbeddedPolicies(!opt.DisableEmbeddedPolicies), - options.ScannerWithEmbeddedLibraries(!opt.DisableEmbeddedLibraries), + rego.WithEmbeddedPolicies(!opt.DisableEmbeddedPolicies), + rego.WithEmbeddedLibraries(!opt.DisableEmbeddedLibraries), options.ScannerWithIncludeDeprecatedChecks(opt.IncludeDeprecatedChecks), } @@ -218,7 +219,7 @@ func scannerOptions(t detection.FileType, opt ScannerOption) ([]options.ScannerO return nil, err } if policyFS != nil { - opts = append(opts, options.ScannerWithPolicyFilesystem(policyFS)) + opts = append(opts, rego.WithPolicyFilesystem(policyFS)) } dataFS, dataPaths, err := CreateDataFS(opt.DataPaths, opt.K8sVersion) @@ -231,13 +232,13 @@ func scannerOptions(t detection.FileType, opt ScannerOption) ([]options.ScannerO }) opts = append(opts, - options.ScannerWithDataDirs(dataPaths...), - options.ScannerWithDataFilesystem(dataFS), - options.ScannerWithCustomSchemas(schemas), + rego.WithDataDirs(dataPaths...), + rego.WithDataFilesystem(dataFS), + rego.WithCustomSchemas(schemas), ) if opt.Trace { - opts = append(opts, options.ScannerWithPerResultTracing(true)) + opts = append(opts, rego.WithPerResultTracing(true)) } if opt.RegoOnly { @@ -245,15 +246,15 @@ func scannerOptions(t detection.FileType, opt ScannerOption) ([]options.ScannerO } if len(policyPaths) > 0 { - opts = append(opts, options.ScannerWithPolicyDirs(policyPaths...)) + opts = append(opts, rego.WithPolicyDirs(policyPaths...)) } if len(opt.DataPaths) > 0 { - opts = append(opts, options.ScannerWithDataDirs(opt.DataPaths...)) + opts = append(opts, rego.WithDataDirs(opt.DataPaths...)) } if len(opt.Namespaces) > 0 { - opts = append(opts, options.ScannerWithPolicyNamespaces(opt.Namespaces...)) + opts = append(opts, rego.WithPolicyNamespaces(opt.Namespaces...)) } switch t { From 5dd94ebc1ffe3f1df511dee6381f92a5daefadf2 Mon Sep 17 00:00:00 2001 From: afdesk Date: Thu, 19 Sep 2024 11:17:42 +0600 Subject: [PATCH 092/183] fix(sbom): export bom-ref when converting a package to a component (#7340) Signed-off-by: knqyf263 Co-authored-by: amf Co-authored-by: knqyf263 --- integration/integration_test.go | 1 - integration/sbom_test.go | 12 + ...d-multiple-lockfiles-short.cdx.json.golden | 526 ++++++++++++++++++ pkg/sbom/cyclonedx/marshal_test.go | 4 +- pkg/sbom/cyclonedx/unmarshal.go | 17 +- pkg/sbom/io/encode.go | 26 +- 6 files changed, 571 insertions(+), 15 deletions(-) create mode 100644 integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden diff --git a/integration/integration_test.go b/integration/integration_test.go index c263ec2fc51e..96c8f54a67e9 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -186,7 +186,6 @@ func readCycloneDX(t *testing.T, filePath string) *cdx.BOM { return (*bom.Components)[i].Name < (*bom.Components)[j].Name }) for i := range *bom.Components { - (*bom.Components)[i].BOMRef = "" sort.Slice(*(*bom.Components)[i].Properties, func(ii, jj int) bool { return (*(*bom.Components)[i].Properties)[ii].Name < (*(*bom.Components)[i].Properties)[jj].Name }) diff --git a/integration/sbom_test.go b/integration/sbom_test.go index e3ee5b89cc3d..e887f1520e68 100644 --- a/integration/sbom_test.go +++ b/integration/sbom_test.go @@ -25,6 +25,7 @@ func TestSBOM(t *testing.T) { name string args args golden string + fakeUUID string override OverrideFunc }{ { @@ -57,6 +58,16 @@ func TestSBOM(t *testing.T) { }, golden: "testdata/fluentd-multiple-lockfiles.json.golden", }, + { + name: "scan SBOM into SBOM", + args: args{ + input: "testdata/fixtures/sbom/fluentd-multiple-lockfiles-cyclonedx.json", + format: "cyclonedx", + artifactType: "cyclonedx", + }, + fakeUUID: "3ff14136-e09f-4df9-80ea-%012d", + golden: "testdata/fluentd-multiple-lockfiles-short.cdx.json.golden", + }, { name: "minikube KBOM", args: args{ @@ -165,6 +176,7 @@ func TestSBOM(t *testing.T) { // Run "trivy sbom" runTest(t, osArgs, tt.golden, outputFile, types.Format(tt.args.format), runOptions{ override: overrideFuncs(overrideSBOMReport, overrideUID, tt.override), + fakeUUID: tt.fakeUUID, }) }) } diff --git a/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden b/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden new file mode 100644 index 000000000000..496ca8ae3110 --- /dev/null +++ b/integration/testdata/fluentd-multiple-lockfiles-short.cdx.json.golden @@ -0,0 +1,526 @@ +{ + "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json", + "bomFormat": "CycloneDX", + "specVersion": "1.6", + "serialNumber": "urn:uuid:3ff14136-e09f-4df9-80ea-000000000010", + "version": 1, + "metadata": { + "timestamp": "2021-08-25T12:20:30+00:00", + "tools": { + "components": [ + { + "type": "application", + "group": "aquasecurity", + "name": "trivy", + "version": "dev" + } + ] + }, + "component": { + "bom-ref": "95de56ee-980c-413d-8f68-6c674dc3e9d1", + "type": "container", + "name": "integration/testdata/fixtures/images/fluentd-multiple-lockfiles.tar.gz", + "properties": [ + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:02874b2b269dea8dde0f7edb4c9906904dfe38a09de1a214f20c650cfb15c60e" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:25165eb51d15842f870f97873e0a58409d5e860e6108e3dd829bd10e484c0065" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:3752e1f6fd759c795c13aff2c93c081529366e27635ba6621e849b0f9cfc77f0" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:75e43d55939745950bc3f8fad56c5834617c4339f0f54755e69a0dd5372624e9" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:788c00e2cfc8f2a018ae4344ccf0b2c226ebd756d7effd1ce50eea1a4252cd89" + }, + { + "name": "aquasecurity:trivy:DiffID", + "value": "sha256:831c5620387fb9efec59fc82a42b948546c6be601e3ab34a87108ecf852aa15f" + }, + { + "name": "aquasecurity:trivy:ImageID", + "value": "sha256:5a992077baba51b97f27591a10d54d2f2723dc9c81a3fe419e261023f2554933" + }, + { + "name": "aquasecurity:trivy:SchemaVersion", + "value": "2" + } + ] + } + }, + "components": [ + { + "bom-ref": "353f2470-9c8b-4647-9d0d-96d893838dc8", + "type": "operating-system", + "name": "debian", + "version": "10.2", + "properties": [ + { + "name": "aquasecurity:trivy:Class", + "value": "os-pkgs" + }, + { + "name": "aquasecurity:trivy:Type", + "value": "debian" + } + ] + }, + { + "bom-ref": "pkg:deb/debian/bash@5.0-4?distro=debian-10.2", + "type": "library", + "name": "bash", + "version": "5.0-4", + "purl": "pkg:deb/debian/bash@5.0-4?distro=debian-10.2", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "bash@5.0-4" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "debian" + }, + { + "name": "aquasecurity:trivy:SrcName", + "value": "bash" + }, + { + "name": "aquasecurity:trivy:SrcVersion", + "value": "5.0-4" + } + ] + }, + { + "bom-ref": "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2", + "type": "library", + "name": "libidn2-0", + "version": "2.0.5-1", + "purl": "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2", + "properties": [ + { + "name": "aquasecurity:trivy:PkgID", + "value": "libidn2-0@2.0.5-1" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "debian" + }, + { + "name": "aquasecurity:trivy:SrcName", + "value": "libidn2" + }, + { + "name": "aquasecurity:trivy:SrcVersion", + "value": "2.0.5-1" + } + ] + }, + { + "bom-ref": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec", + "type": "library", + "name": "activesupport", + "version": "6.0.2.1", + "licenses": [ + { + "license": { + "name": "MIT" + } + } + ], + "purl": "pkg:gem/activesupport@6.0.2.1", + "properties": [ + { + "name": "aquasecurity:trivy:FilePath", + "value": "var/lib/gems/2.5.0/specifications/activesupport-6.0.2.1.gemspec" + }, + { + "name": "aquasecurity:trivy:PkgID", + "value": "activesupport@6.0.2.1" + }, + { + "name": "aquasecurity:trivy:PkgType", + "value": "gemspec" + } + ] + } + ], + "dependencies": [ + { + "ref": "353f2470-9c8b-4647-9d0d-96d893838dc8", + "dependsOn": [ + "pkg:deb/debian/bash@5.0-4?distro=debian-10.2", + "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2" + ] + }, + { + "ref": "95de56ee-980c-413d-8f68-6c674dc3e9d1", + "dependsOn": [ + "353f2470-9c8b-4647-9d0d-96d893838dc8", + "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec" + ] + }, + { + "ref": "pkg:deb/debian/bash@5.0-4?distro=debian-10.2", + "dependsOn": [] + }, + { + "ref": "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2", + "dependsOn": [] + }, + { + "ref": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec", + "dependsOn": [] + } + ], + "vulnerabilities": [ + { + "id": "CVE-2019-18224", + "source": { + "name": "debian", + "url": "https://salsa.debian.org/security-tracker-team/security-tracker" + }, + "ratings": [ + { + "source": { + "name": "amazon" + }, + "severity": "medium" + }, + { + "source": { + "name": "nvd" + }, + "score": 7.5, + "severity": "high", + "method": "CVSSv2", + "vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P" + }, + { + "source": { + "name": "nvd" + }, + "score": 9.8, + "severity": "critical", + "method": "CVSSv31", + "vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + }, + { + "source": { + "name": "redhat" + }, + "score": 5.6, + "severity": "medium", + "method": "CVSSv3", + "vector": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L" + }, + { + "source": { + "name": "ubuntu" + }, + "severity": "medium" + } + ], + "cwes": [ + 787 + ], + "description": "idn2_to_ascii_4i in lib/lookup.c in GNU libidn2 before 2.1.1 has a heap-based buffer overflow via a long domain string.", + "recommendation": "Upgrade libidn2-0 to version 2.0.5-1+deb10u1", + "advisories": [ + { + "url": "https://avd.aquasec.com/nvd/cve-2019-18224" + }, + { + "url": "http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00008.html" + }, + { + "url": "http://lists.opensuse.org/opensuse-security-announce/2019-12/msg00009.html" + }, + { + "url": "https://access.redhat.com/security/cve/CVE-2019-18224" + }, + { + "url": "https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=12420" + }, + { + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18224" + }, + { + "url": "https://github.com/libidn/libidn2/commit/e4d1558aa2c1c04a05066ee8600f37603890ba8c" + }, + { + "url": "https://github.com/libidn/libidn2/compare/libidn2-2.1.0...libidn2-2.1.1" + }, + { + "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/JDQVQ2XPV5BTZUFINT7AFJSKNNBVURNJ/" + }, + { + "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/MINU5RKDFE6TKAFY5DRFN3WSFDS4DYVS/" + }, + { + "url": "https://seclists.org/bugtraq/2020/Feb/4" + }, + { + "url": "https://security.gentoo.org/glsa/202003-63" + }, + { + "url": "https://ubuntu.com/security/notices/USN-4168-1" + }, + { + "url": "https://usn.ubuntu.com/4168-1/" + }, + { + "url": "https://www.debian.org/security/2020/dsa-4613" + } + ], + "published": "2019-10-21T17:15:00+00:00", + "updated": "2019-10-29T19:15:00+00:00", + "affects": [ + { + "ref": "pkg:deb/debian/libidn2-0@2.0.5-1?distro=debian-10.2", + "versions": [ + { + "version": "2.0.5-1", + "status": "affected" + } + ] + } + ] + }, + { + "id": "CVE-2019-18276", + "source": { + "name": "debian", + "url": "https://salsa.debian.org/security-tracker-team/security-tracker" + }, + "ratings": [ + { + "source": { + "name": "cbl-mariner" + }, + "severity": "high" + }, + { + "source": { + "name": "debian" + }, + "severity": "low" + }, + { + "source": { + "name": "nvd" + }, + "score": 7.2, + "severity": "high", + "method": "CVSSv2", + "vector": "AV:L/AC:L/Au:N/C:C/I:C/A:C" + }, + { + "source": { + "name": "nvd" + }, + "score": 7.8, + "severity": "high", + "method": "CVSSv31", + "vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H" + }, + { + "source": { + "name": "oracle-oval" + }, + "severity": "low" + }, + { + "source": { + "name": "photon" + }, + "severity": "high" + }, + { + "source": { + "name": "redhat" + }, + "score": 7.8, + "severity": "low", + "method": "CVSSv31", + "vector": "CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H" + }, + { + "source": { + "name": "ubuntu" + }, + "severity": "low" + } + ], + "cwes": [ + 273 + ], + "description": "An issue was discovered in disable_priv_mode in shell.c in GNU Bash through 5.0 patch 11. By default, if Bash is run with its effective UID not equal to its real UID, it will drop privileges by setting its effective UID to its real UID. However, it does so incorrectly. On Linux and other systems that support \"saved UID\" functionality, the saved UID is not dropped. An attacker with command execution in the shell can use \"enable -f\" for runtime loading of a new builtin, which can be a shared object that calls setuid() and therefore regains privileges. However, binaries running with an effective UID of 0 are unaffected.", + "advisories": [ + { + "url": "https://avd.aquasec.com/nvd/cve-2019-18276" + }, + { + "url": "http://packetstormsecurity.com/files/155498/Bash-5.0-Patch-11-Privilege-Escalation.html" + }, + { + "url": "https://access.redhat.com/security/cve/CVE-2019-18276" + }, + { + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-18276" + }, + { + "url": "https://github.com/bminor/bash/commit/951bdaad7a18cc0dc1036bba86b18b90874d39ff" + }, + { + "url": "https://linux.oracle.com/cve/CVE-2019-18276.html" + }, + { + "url": "https://linux.oracle.com/errata/ELSA-2021-1679.html" + }, + { + "url": "https://lists.apache.org/thread.html/rf9fa47ab66495c78bb4120b0754dd9531ca2ff0430f6685ac9b07772@%3Cdev.mina.apache.org%3E" + }, + { + "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-18276" + }, + { + "url": "https://security.gentoo.org/glsa/202105-34" + }, + { + "url": "https://security.netapp.com/advisory/ntap-20200430-0003/" + }, + { + "url": "https://www.youtube.com/watch?v=-wGtxJ8opa8" + } + ], + "published": "2019-11-28T01:15:00+00:00", + "updated": "2021-05-26T12:15:00+00:00", + "affects": [ + { + "ref": "pkg:deb/debian/bash@5.0-4?distro=debian-10.2", + "versions": [ + { + "version": "5.0-4", + "status": "affected" + } + ] + } + ] + }, + { + "id": "CVE-2020-8165", + "source": { + "name": "ghsa", + "url": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Arubygems" + }, + "ratings": [ + { + "source": { + "name": "ghsa" + }, + "severity": "high" + }, + { + "source": { + "name": "nvd" + }, + "score": 7.5, + "severity": "high", + "method": "CVSSv2", + "vector": "AV:N/AC:L/Au:N/C:P/I:P/A:P" + }, + { + "source": { + "name": "nvd" + }, + "score": 9.8, + "severity": "critical", + "method": "CVSSv31", + "vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + }, + { + "source": { + "name": "redhat" + }, + "score": 9.8, + "severity": "high", + "method": "CVSSv31", + "vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H" + } + ], + "cwes": [ + 502 + ], + "description": "A deserialization of untrusted data vulnerability exists in rails < 5.2.4.3, rails < 6.0.3.1 that can allow an attacker to unmarshal user-provided objects in MemCacheStore and RedisCacheStore potentially resulting in an RCE.", + "recommendation": "Upgrade activesupport to version 6.0.3.1, 5.2.4.3", + "advisories": [ + { + "url": "https://avd.aquasec.com/nvd/cve-2020-8165" + }, + { + "url": "http://lists.opensuse.org/opensuse-security-announce/2020-10/msg00031.html" + }, + { + "url": "http://lists.opensuse.org/opensuse-security-announce/2020-10/msg00034.html" + }, + { + "url": "https://access.redhat.com/security/cve/CVE-2020-8165" + }, + { + "url": "https://github.com/advisories/GHSA-2p68-f74v-9wc6" + }, + { + "url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/activesupport/CVE-2020-8165.yml" + }, + { + "url": "https://groups.google.com/forum/#!msg/rubyonrails-security/bv6fW4S0Y1c/KnkEqM7AAQAJ" + }, + { + "url": "https://groups.google.com/forum/#!topic/rubyonrails-security/bv6fW4S0Y1c" + }, + { + "url": "https://groups.google.com/g/rubyonrails-security/c/bv6fW4S0Y1c" + }, + { + "url": "https://hackerone.com/reports/413388" + }, + { + "url": "https://lists.debian.org/debian-lts-announce/2020/06/msg00022.html" + }, + { + "url": "https://lists.debian.org/debian-lts-announce/2020/07/msg00013.html" + }, + { + "url": "https://nvd.nist.gov/vuln/detail/CVE-2020-8165" + }, + { + "url": "https://weblog.rubyonrails.org/2020/5/18/Rails-5-2-4-3-and-6-0-3-1-have-been-released/" + }, + { + "url": "https://www.debian.org/security/2020/dsa-4766" + } + ], + "published": "2020-06-19T18:15:00+00:00", + "updated": "2020-10-17T12:15:00+00:00", + "affects": [ + { + "ref": "pkg:gem/activesupport@6.0.2.1?file_path=var%2Flib%2Fgems%2F2.5.0%2Fspecifications%2Factivesupport-6.0.2.1.gemspec", + "versions": [ + { + "version": "6.0.2.1", + "status": "affected" + } + ] + } + ] + } + ] +} diff --git a/pkg/sbom/cyclonedx/marshal_test.go b/pkg/sbom/cyclonedx/marshal_test.go index e778b803619c..8b88c4ec762a 100644 --- a/pkg/sbom/cyclonedx/marshal_test.go +++ b/pkg/sbom/cyclonedx/marshal_test.go @@ -1462,7 +1462,7 @@ func TestMarshaler_MarshalReport(t *testing.T) { Name: "com.fasterxml.jackson.core:jackson-databind", Version: "2.13.4.1", Identifier: ftypes.PkgIdentifier{ - BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1?file_path=jackson-databind-2.13.4.1.jar", + BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", UID: "9A5066570222D04C", PURL: &packageurl.PackageURL{ Type: packageurl.TypeMaven, @@ -1480,7 +1480,7 @@ func TestMarshaler_MarshalReport(t *testing.T) { PkgName: "com.fasterxml.jackson.core:jackson-databind", PkgPath: "jackson-databind-2.13.4.1.jar", PkgIdentifier: ftypes.PkgIdentifier{ - BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1?file_path=jackson-databind-2.13.4.1.jar", + BOMRef: "pkg:maven/com.fasterxml.jackson.core/jackson-databind@2.13.4.1", UID: "9A5066570222D04C", PURL: &packageurl.PackageURL{ Type: packageurl.TypeMaven, diff --git a/pkg/sbom/cyclonedx/unmarshal.go b/pkg/sbom/cyclonedx/unmarshal.go index de410d008794..2a2456063670 100644 --- a/pkg/sbom/cyclonedx/unmarshal.go +++ b/pkg/sbom/cyclonedx/unmarshal.go @@ -128,13 +128,17 @@ func (b *BOM) parseComponent(c cdx.Component) (*core.Component, error) { return nil, xerrors.Errorf("failed to unmarshal component type: %w", err) } + identifier := ftypes.PkgIdentifier{ + BOMRef: c.BOMRef, + } + // Parse PURL - var purl packageurl.PackageURL if c.PackageURL != "" { - purl, err = packageurl.FromString(c.PackageURL) + purl, err := packageurl.FromString(c.PackageURL) if err != nil { return nil, xerrors.Errorf("failed to parse PURL: %w", err) } + identifier.PURL = &purl } component := &core.Component{ @@ -148,12 +152,9 @@ func (b *BOM) parseComponent(c cdx.Component) (*core.Component, error) { Digests: b.unmarshalHashes(c.Hashes), }, }, - PkgIdentifier: ftypes.PkgIdentifier{ - PURL: &purl, - BOMRef: c.BOMRef, - }, - Supplier: b.unmarshalSupplier(c.Supplier), - Properties: b.unmarshalProperties(c.Properties), + PkgIdentifier: identifier, + Supplier: b.unmarshalSupplier(c.Supplier), + Properties: b.unmarshalProperties(c.Properties), } return component, nil diff --git a/pkg/sbom/io/encode.go b/pkg/sbom/io/encode.go index 0be0bf361280..975b98d40b10 100644 --- a/pkg/sbom/io/encode.go +++ b/pkg/sbom/io/encode.go @@ -5,6 +5,7 @@ import ( "slices" "strconv" + "github.com/google/uuid" "github.com/package-url/packageurl-go" "github.com/samber/lo" "golang.org/x/xerrors" @@ -19,8 +20,9 @@ import ( ) type Encoder struct { - bom *core.BOM - opts core.Options + bom *core.BOM + opts core.Options + components map[uuid.UUID]*core.Component } func NewEncoder(opts core.Options) *Encoder { @@ -28,6 +30,9 @@ func NewEncoder(opts core.Options) *Encoder { } func (e *Encoder) Encode(report types.Report) (*core.BOM, error) { + if report.BOM != nil { + e.components = report.BOM.Components() + } // Metadata component root, err := e.rootComponent(report) if err != nil { @@ -257,6 +262,16 @@ func (e *Encoder) encodePackages(parent *core.Component, result types.Result) { } } +// existedPkgIdentifier tries to look for package identifier (BOM-ref, PURL) by component name and component type +func (e *Encoder) existedPkgIdentifier(name string, componentType core.ComponentType) ftypes.PkgIdentifier { + for _, c := range e.components { + if c.Name == name && c.Type == componentType { + return c.PkgIdentifier + } + } + return ftypes.PkgIdentifier{} +} + func (e *Encoder) resultComponent(root *core.Component, r types.Result, osFound *ftypes.OS) *core.Component { component := &core.Component{ Name: r.Target, @@ -279,8 +294,10 @@ func (e *Encoder) resultComponent(root *core.Component, r types.Result, osFound component.Version = osFound.Name } component.Type = core.TypeOS + component.PkgIdentifier = e.existedPkgIdentifier(component.Name, component.Type) case types.ClassLangPkg: component.Type = core.TypeApplication + component.PkgIdentifier = e.existedPkgIdentifier(component.Name, component.Type) } e.bom.AddRelationship(root, component, core.RelationshipContains) @@ -377,8 +394,9 @@ func (*Encoder) component(result types.Result, pkg ftypes.Package) *core.Compone SrcVersion: utils.FormatSrcVersion(pkg), SrcFile: srcFile, PkgIdentifier: ftypes.PkgIdentifier{ - UID: pkg.Identifier.UID, - PURL: pkg.Identifier.PURL, + UID: pkg.Identifier.UID, + PURL: pkg.Identifier.PURL, + BOMRef: pkg.Identifier.BOMRef, }, Supplier: pkg.Maintainer, Licenses: pkg.Licenses, From 1f9fc13da4a1e7c76c978e4f8e119bfd61a0480e Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 20 Sep 2024 10:50:12 +0600 Subject: [PATCH 093/183] perf(misconf): use port ranges instead of enumeration (#7549) Signed-off-by: nikpivkin --- .../terraform/google/compute/adapt_test.go | 4 +- .../terraform/google/compute/networks.go | 39 +++++++++++-------- .../terraform/google/compute/networks_test.go | 18 +++++++-- pkg/iac/providers/google/compute/firewall.go | 8 +++- pkg/iac/rego/schemas/cloud.json | 39 ++++++++++++++++++- 5 files changed, 84 insertions(+), 24 deletions(-) diff --git a/pkg/iac/adapters/terraform/google/compute/adapt_test.go b/pkg/iac/adapters/terraform/google/compute/adapt_test.go index a90c4315364a..d5bbe5a8f566 100644 --- a/pkg/iac/adapters/terraform/google/compute/adapt_test.go +++ b/pkg/iac/adapters/terraform/google/compute/adapt_test.go @@ -184,8 +184,8 @@ func TestLines(t *testing.T) { assert.Equal(t, 59, network.Firewall.IngressRules[0].Protocol.GetMetadata().Range().GetStartLine()) assert.Equal(t, 59, network.Firewall.IngressRules[0].Protocol.GetMetadata().Range().GetEndLine()) - assert.Equal(t, 60, network.Firewall.IngressRules[0].Ports[0].GetMetadata().Range().GetStartLine()) - assert.Equal(t, 60, network.Firewall.IngressRules[0].Ports[0].GetMetadata().Range().GetEndLine()) + assert.Equal(t, 60, network.Firewall.IngressRules[0].Ports[0].Metadata.Range().GetStartLine()) + assert.Equal(t, 60, network.Firewall.IngressRules[0].Ports[0].Metadata.Range().GetEndLine()) assert.Equal(t, 64, network.Subnetworks[0].Metadata.Range().GetStartLine()) assert.Equal(t, 72, network.Subnetworks[0].Metadata.Range().GetEndLine()) diff --git a/pkg/iac/adapters/terraform/google/compute/networks.go b/pkg/iac/adapters/terraform/google/compute/networks.go index ea3c9cb97a5f..5ea8753d1f7f 100644 --- a/pkg/iac/adapters/terraform/google/compute/networks.go +++ b/pkg/iac/adapters/terraform/google/compute/networks.go @@ -105,44 +105,51 @@ func adaptNetworks(modules terraform.Modules) (networks []compute.Network) { return networks } -func expandRange(ports string, attr *terraform.Attribute) []iacTypes.IntValue { +func expandRange(ports string, meta iacTypes.Metadata) (compute.PortRange, bool) { ports = strings.ReplaceAll(ports, " ", "") if !strings.Contains(ports, "-") { i, err := strconv.Atoi(ports) if err != nil { - return nil - } - return []iacTypes.IntValue{ - iacTypes.Int(i, attr.GetMetadata()), + return compute.PortRange{}, false } + return compute.PortRange{ + Metadata: meta, + Start: iacTypes.Int(i, meta), + End: iacTypes.Int(i, meta), + }, true } parts := strings.Split(ports, "-") if len(parts) != 2 { - return nil + return compute.PortRange{}, false } start, err := strconv.Atoi(parts[0]) if err != nil { - return nil + return compute.PortRange{}, false } end, err := strconv.Atoi(parts[1]) if err != nil { - return nil - } - var output []iacTypes.IntValue - for i := start; i <= end; i++ { - output = append(output, iacTypes.Int(i, attr.GetMetadata())) + return compute.PortRange{}, false } - return output + + return compute.PortRange{ + Metadata: meta, + Start: iacTypes.Int(start, meta), + End: iacTypes.Int(end, meta), + }, true } func adaptFirewallRule(firewall *compute.Firewall, firewallBlock, ruleBlock *terraform.Block, allow bool) { protocolAttr := ruleBlock.GetAttribute("protocol") portsAttr := ruleBlock.GetAttribute("ports") - var ports []iacTypes.IntValue + var rngs []compute.PortRange rawPorts := portsAttr.AsStringValues() for _, portStr := range rawPorts { - ports = append(ports, expandRange(portStr.Value(), portsAttr)...) + rng, ok := expandRange(portStr.Value(), portsAttr.GetMetadata()) + if !ok { + continue + } + rngs = append(rngs, rng) } // ingress by default @@ -153,7 +160,7 @@ func adaptFirewallRule(firewall *compute.Firewall, firewallBlock, ruleBlock *ter Enforced: iacTypes.BoolDefault(true, firewallBlock.GetMetadata()), IsAllow: iacTypes.Bool(allow, ruleBlock.GetMetadata()), Protocol: protocolAttr.AsStringValueOrDefault("tcp", ruleBlock), - Ports: ports, + Ports: rngs, } disabledAttr := firewallBlock.GetAttribute("disabled") diff --git a/pkg/iac/adapters/terraform/google/compute/networks_test.go b/pkg/iac/adapters/terraform/google/compute/networks_test.go index 32ad00bc5334..df1cef261e7d 100644 --- a/pkg/iac/adapters/terraform/google/compute/networks_test.go +++ b/pkg/iac/adapters/terraform/google/compute/networks_test.go @@ -39,7 +39,7 @@ func Test_adaptNetworks(t *testing.T) { source_ranges = ["1.2.3.4/32"] allow { protocol = "icmp" - ports = ["80", "8080"] + ports = ["80", "8080", "9090-9095"] } } `, @@ -57,9 +57,19 @@ func Test_adaptNetworks(t *testing.T) { IsAllow: iacTypes.Bool(true, iacTypes.NewTestMetadata()), Protocol: iacTypes.String("icmp", iacTypes.NewTestMetadata()), Enforced: iacTypes.Bool(true, iacTypes.NewTestMetadata()), - Ports: []iacTypes.IntValue{ - iacTypes.Int(80, iacTypes.NewTestMetadata()), - iacTypes.Int(8080, iacTypes.NewTestMetadata()), + Ports: []compute.PortRange{ + { + Start: iacTypes.IntTest(80), + End: iacTypes.IntTest(80), + }, + { + Start: iacTypes.IntTest(8080), + End: iacTypes.IntTest(8080), + }, + { + Start: iacTypes.IntTest(9090), + End: iacTypes.IntTest(9095), + }, }, }, SourceRanges: []iacTypes.StringValue{ diff --git a/pkg/iac/providers/google/compute/firewall.go b/pkg/iac/providers/google/compute/firewall.go index c122369d9954..19f4044cdb72 100755 --- a/pkg/iac/providers/google/compute/firewall.go +++ b/pkg/iac/providers/google/compute/firewall.go @@ -18,7 +18,13 @@ type FirewallRule struct { Enforced iacTypes.BoolValue IsAllow iacTypes.BoolValue Protocol iacTypes.StringValue - Ports []iacTypes.IntValue + Ports []PortRange +} + +type PortRange struct { + Metadata iacTypes.Metadata + Start iacTypes.IntValue + End iacTypes.IntValue } type IngressRule struct { diff --git a/pkg/iac/rego/schemas/cloud.json b/pkg/iac/rego/schemas/cloud.json index 530ba5bfaa1f..b034f24fa104 100644 --- a/pkg/iac/rego/schemas/cloud.json +++ b/pkg/iac/rego/schemas/cloud.json @@ -1615,10 +1615,18 @@ "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue" } }, + "fromport": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.IntValue" + }, "protocol": { "type": "object", "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue" }, + "toport": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.IntValue" + }, "type": { "type": "object", "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue" @@ -1677,6 +1685,18 @@ "description": { "type": "object", "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue" + }, + "fromport": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.IntValue" + }, + "protocol": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue" + }, + "toport": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.IntValue" } } }, @@ -6086,7 +6106,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.IntValue" + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.google.compute.PortRange" } }, "protocol": { @@ -6218,6 +6238,23 @@ } } }, + "github.com.aquasecurity.trivy.pkg.iac.providers.google.compute.PortRange": { + "type": "object", + "properties": { + "__defsec_metadata": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.Metadata" + }, + "end": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.IntValue" + }, + "start": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.IntValue" + } + } + }, "github.com.aquasecurity.trivy.pkg.iac.providers.google.compute.ProjectMetadata": { "type": "object", "properties": { From 37d549e5b86a1c5dce6710fbfd2310aec9abe949 Mon Sep 17 00:00:00 2001 From: bloomadcariad Date: Sun, 22 Sep 2024 23:00:51 -0700 Subject: [PATCH 094/183] fix(misconf): Fixed scope for China Cloud (#7560) --- pkg/fanal/image/registry/azure/azure.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fanal/image/registry/azure/azure.go b/pkg/fanal/image/registry/azure/azure.go index 67368c8bb3c8..d19392924a10 100644 --- a/pkg/fanal/image/registry/azure/azure.go +++ b/pkg/fanal/image/registry/azure/azure.go @@ -45,7 +45,7 @@ func (r *Registry) CheckOptions(domain string, _ types.RegistryOptions) (intf.Re } else if strings.HasSuffix(domain, chinaAzureURL) { return &RegistryClient{ domain: domain, - scope: scope, + scope: chinaScope, cloud: cloud.AzureChina, }, nil } From 8128ecc9a91e16ca6fc4590a2ded10458addefd0 Mon Sep 17 00:00:00 2001 From: simar7 <1254783+simar7@users.noreply.github.com> Date: Wed, 25 Sep 2024 23:11:33 -0600 Subject: [PATCH 095/183] docs(misconf): Add more info on how to use arbitrary JSON/YAML scan feat (#7458) --- docs/docs/scanner/misconfiguration/index.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/docs/scanner/misconfiguration/index.md b/docs/docs/scanner/misconfiguration/index.md index 9824936b8e53..368b4522b433 100644 --- a/docs/docs/scanner/misconfiguration/index.md +++ b/docs/docs/scanner/misconfiguration/index.md @@ -389,15 +389,27 @@ LOW: Service name "serverless-rest-api-with-pynamodb" is not allowed Ensure that Serverless Framework service names start with "aws-" ``` -You can also pass schemas using the `config-file-schemas` flag. Trivy will use these schemas for file filtering and type checking in Rego checks. If the file does not match any of the passed schemas, it will be ignored. +!!! note + In the case above, the custom check specified has a metadata annotation for the input schema `input: schema["serverless-schema"]`. This allows Trivy to type check the input IaC files provided. + +Optionally, you can also pass schemas using the `config-file-schemas` flag. Trivy will use these schemas for file filtering and type checking in Rego checks. !!! example ```bash $ trivy config --misconfig-scanners=json,yaml --config-check ./serverless.rego --check-namespaces user --config-file-schemas ./serverless-schema.json ./iac ``` +If the `--config-file-schemas` flag is specified Trivy ensures that each input IaC config file being scanned is type-checked against the schema. If the input file does not match any of the passed schemas, it will be ignored. + If the schema is specified in the check metadata and is in the directory specified in the `--config-check` argument, it will be automatically loaded as specified [here](./custom/schema.md#custom-checks-with-custom-schemas), and will only be used for type checking in Rego. +!!! note + If a user specifies the `--config-file-schemas` flag, all input IaC config files are ensured that they pass type-checking. It is not required to pass an input schema in case type checking is not required. This is helpful for scenarios where you simply want to write a Rego check and pass in IaC input for it. Such a use case could include scanning for a new service which Trivy might not support just yet. + +!!! tip + It is also possible to specify multiple input schemas with `--config-file-schema` flag as it can accept a comma seperated list of file paths or a directory as input. In the case of multiple schemas being specified, all of them will be evaluated against all the input files. + + ### Passing custom data You can pass directories including your custom data through `--data` option. This can be repeated for specifying multiple directories. From bbc8e1d8f3e27726ca3d413f7481e7f62814e7b8 Mon Sep 17 00:00:00 2001 From: Sylvain Baubeau Date: Thu, 26 Sep 2024 12:11:53 +0200 Subject: [PATCH 096/183] chore(deps): remove broken replaces for opa and discovery (#7600) --- go.mod | 14 ++++---------- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 483b97ee9acc..af0a26efc67d 100644 --- a/go.mod +++ b/go.mod @@ -88,10 +88,10 @@ require ( github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/mitchellh/mapstructure v1.5.0 github.com/moby/buildkit v0.15.2 - github.com/open-policy-agent/opa v0.67.1 + github.com/open-policy-agent/opa v0.68.1-0.20240903211041-76f7038ea2d1 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 - github.com/openvex/discovery v0.1.0 + github.com/openvex/discovery v0.1.1-0.20240802171711-7c54efc57553 github.com/openvex/go-vex v0.2.5 github.com/owenrumney/go-sarif/v2 v2.3.3 github.com/owenrumney/squealer v1.2.4 @@ -324,7 +324,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect - github.com/prometheus/client_golang v1.20.1 // indirect + github.com/prometheus/client_golang v1.20.2 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect @@ -389,7 +389,7 @@ require ( google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/grpc v1.65.0 // indirect + google.golang.org/grpc v1.66.0 // indirect gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect gopkg.in/inf.v0 v0.9.1 // indirect @@ -418,9 +418,3 @@ require ( sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) - -// cf. https://github.com/openvex/discovery/pull/40 -replace github.com/openvex/discovery => github.com/knqyf263/discovery v0.1.1-0.20240726113521-97873005fd03 - -// see https://github.com/open-policy-agent/opa/pull/6970 -replace github.com/open-policy-agent/opa => github.com/nikpivkin/opa v0.0.0-20240829080621-16999fcb5464 diff --git a/go.sum b/go.sum index 6ff7fca55e3b..da3862e7d75d 100644 --- a/go.sum +++ b/go.sum @@ -961,8 +961,6 @@ github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrD github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/knqyf263/discovery v0.1.1-0.20240726113521-97873005fd03 h1:fsWNAqGAbq2sz7q0agtKCq/esMjvReNd26bgWN8Lk6w= -github.com/knqyf263/discovery v0.1.1-0.20240726113521-97873005fd03/go.mod h1:z4b//Qi7p7zcM/c41ogeTy+/nqfMbbeYnfZ+EMCTCD0= github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f h1:GvCU5GXhHq+7LeOzx/haG7HSIZokl3/0GkoUFzsRJjg= github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f/go.mod h1:q59u9px8b7UTj0nIjEjvmTWekazka6xIt6Uogz5Dm+8= github.com/knqyf263/go-deb-version v0.0.0-20230223133812-3ed183d23422 h1:PPPlUUqPP6fLudIK4n0l0VU4KT2cQGnheW9x8pNiCHI= @@ -1118,8 +1116,6 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= 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/nikpivkin/opa v0.0.0-20240829080621-16999fcb5464 h1:jhZ8nLVxOAslgzmPdKTyctfDJkMfRgksCypFriHzf4E= -github.com/nikpivkin/opa v0.0.0-20240829080621-16999fcb5464/go.mod h1:cvSIxY0dexL39hOPqXSZKdBYFNx2Rv8Fu5n3MmTjqtE= 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= @@ -1143,6 +1139,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.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE= github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk= +github.com/open-policy-agent/opa v0.68.1-0.20240903211041-76f7038ea2d1 h1:GQrryTKpunLNDc2NdhNL1FzfrbuNvo45s76anGdqz9k= +github.com/open-policy-agent/opa v0.68.1-0.20240903211041-76f7038ea2d1/go.mod h1:5E5SvaPwTpwt2WM177I9Z3eT7qUpmOGjk1ZdHs+TZ4w= 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.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -1153,6 +1151,8 @@ github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaL github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= +github.com/openvex/discovery v0.1.1-0.20240802171711-7c54efc57553 h1:c4u0GIH0w2Q57Pm2Oldrq6EiHFnLCCnRs98A+ggj/YQ= +github.com/openvex/discovery v0.1.1-0.20240802171711-7c54efc57553/go.mod h1:z4b//Qi7p7zcM/c41ogeTy+/nqfMbbeYnfZ+EMCTCD0= github.com/openvex/go-vex v0.2.5 h1:41utdp2rHgAGCsG+UbjmfMG5CWQxs15nGqir1eRgSrQ= github.com/openvex/go-vex v0.2.5/go.mod h1:j+oadBxSUELkrKh4NfNb+BPo77U3q7gdKME88IO/0Wo= github.com/owenrumney/go-sarif v1.1.1/go.mod h1:dNDiPlF04ESR/6fHlPyq7gHKmrM0sHUvAGjsoh8ZH0U= @@ -1188,8 +1188,8 @@ github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjz github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.20.1 h1:IMJXHOD6eARkQpxo8KkhgEVFlBNm+nkrFUyGlIu7Na8= -github.com/prometheus/client_golang v1.20.1/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg= +github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -2019,8 +2019,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= +google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From fea7250f7f99a100d67391c0382edd501fa64539 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Thu, 26 Sep 2024 17:40:56 +0600 Subject: [PATCH 097/183] ci: cache test images for `integration`, `VM` and `module` tests (#7599) --- .github/workflows/test.yaml | 49 +++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 13f279b519b7..e26f35890c3d 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -82,6 +82,22 @@ jobs: with: aqua_version: v1.25.0 + - name: Generate image list digest + id: image-digest + run: | + IMAGE_LIST=$(skopeo list-tags docker://ghcr.io/aquasecurity/trivy-test-images) + DIGEST=$(echo "$IMAGE_LIST" | sha256sum | cut -d' ' -f1) + echo "digest=$DIGEST" >> $GITHUB_OUTPUT + + - name: Restore test images from cache + uses: actions/cache@v4 + id: restore-test-images + with: + path: integration/testdata/fixtures/images + key: cache-test-images-${{ steps.image-digest.outputs.digest }} + restore-keys: + cache-test-images- + - name: Run integration tests run: mage test:integration @@ -122,6 +138,22 @@ jobs: with: aqua_version: v1.25.0 + - name: Generate image list digest + id: image-digest + run: | + IMAGE_LIST=$(skopeo list-tags docker://ghcr.io/aquasecurity/trivy-test-images) + DIGEST=$(echo "$IMAGE_LIST" | sha256sum | cut -d' ' -f1) + echo "digest=$DIGEST" >> $GITHUB_OUTPUT + + - name: Restore test images from cache + uses: actions/cache@v4 + id: restore-test-images + with: + path: integration/testdata/fixtures/images + key: cache-test-images-${{ steps.image-digest.outputs.digest }} + restore-keys: + cache-test-images- + - name: Run module integration tests shell: bash run: | @@ -142,6 +174,23 @@ jobs: uses: aquaproj/aqua-installer@v3.0.1 with: aqua_version: v1.25.0 + + - name: Generate image list digest + id: image-digest + run: | + IMAGE_LIST=$(skopeo list-tags docker://ghcr.io/aquasecurity/trivy-test-vm-images) + DIGEST=$(echo "$IMAGE_LIST" | sha256sum | cut -d' ' -f1) + echo "digest=$DIGEST" >> $GITHUB_OUTPUT + + - name: Restore test VM images from cache + uses: actions/cache@v4 + id: restore-test-vm-images + with: + path: integration/testdata/fixtures/vm-images + key: cache-test-vm-images-${{ steps.image-digest.outputs.digest }} + restore-keys: + cache-test-vm-images- + - name: Run vm integration tests run: | mage test:vm From 1fdf30a54513e43e343c764f7dafb0721ee6bc83 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Thu, 26 Sep 2024 21:42:34 +0600 Subject: [PATCH 098/183] ci: add `workflow_dispatch` trigger for test workflow. (#7606) --- .github/workflows/test.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index e26f35890c3d..dc7d825af1c8 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -8,6 +8,8 @@ on: - 'LICENSE' - '.release-please-manifest.json' ## don't run tests for release-please PRs merge_group: + workflow_dispatch: + env: GO_VERSION: '1.22' jobs: From 3fa24e890e7657c59d3e88dd7a9b74ab07880a74 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 17:22:38 +0000 Subject: [PATCH 099/183] chore(deps): bump the common group across 1 directory with 20 updates (#7604) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: knqyf263 --- go.mod | 94 ++++++++++++------------- go.sum | 212 +++++++++++++++++++++++++++------------------------------ 2 files changed, 147 insertions(+), 159 deletions(-) diff --git a/go.mod b/go.mod index af0a26efc67d..8f5e151e6ef4 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 github.com/BurntSushi/toml v1.4.0 - github.com/CycloneDX/cyclonedx-go v0.9.0 + github.com/CycloneDX/cyclonedx-go v0.9.1 github.com/GoogleCloudPlatform/docker-credential-gcr v2.0.5+incompatible github.com/Masterminds/sprig/v3 v3.3.0 github.com/NYTimes/gziphandler v1.1.1 @@ -29,21 +29,21 @@ require ( github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1 github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20240707095038-0300bc49b68b - github.com/aws/aws-sdk-go-v2 v1.30.5 - github.com/aws/aws-sdk-go-v2/config v1.27.33 - github.com/aws/aws-sdk-go-v2/credentials v1.17.32 - github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.2 - github.com/aws/aws-sdk-go-v2/service/ecr v1.32.4 - github.com/aws/aws-sdk-go-v2/service/s3 v1.61.2 - github.com/aws/aws-sdk-go-v2/service/sts v1.30.7 // indirect - github.com/aws/smithy-go v1.20.4 + github.com/aws/aws-sdk-go-v2 v1.31.0 + github.com/aws/aws-sdk-go-v2/config v1.27.38 + github.com/aws/aws-sdk-go-v2/credentials v1.17.36 + github.com/aws/aws-sdk-go-v2/service/ec2 v1.179.1 + github.com/aws/aws-sdk-go-v2/service/ecr v1.35.2 + github.com/aws/aws-sdk-go-v2/service/s3 v1.63.2 + github.com/aws/aws-sdk-go-v2/service/sts v1.31.2 // indirect + github.com/aws/smithy-go v1.21.0 github.com/bitnami/go-version v0.0.0-20231130084017-bb00604d650c github.com/bmatcuk/doublestar/v4 v4.6.1 github.com/cenkalti/backoff/v4 v4.3.0 github.com/cheggaaa/pb/v3 v3.1.5 - github.com/containerd/containerd v1.7.21 + github.com/containerd/containerd v1.7.22 github.com/csaf-poc/csaf_distribution/v3 v3.0.0 - github.com/docker/docker v27.2.0+incompatible + github.com/docker/docker v27.3.1+incompatible github.com/docker/go-connections v0.5.0 github.com/fatih/color v1.17.0 github.com/go-git/go-git/v5 v5.12.0 @@ -62,7 +62,7 @@ require ( github.com/hashicorp/go-uuid v1.0.3 github.com/hashicorp/go-version v1.7.0 github.com/hashicorp/golang-lru/v2 v2.0.7 - github.com/hashicorp/hc-install v0.8.0 + github.com/hashicorp/hc-install v0.9.0 github.com/hashicorp/hcl/v2 v2.22.0 github.com/hashicorp/terraform-exec v0.21.0 github.com/in-toto/in-toto-golang v0.9.0 @@ -87,7 +87,7 @@ require ( github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/mitchellh/mapstructure v1.5.0 - github.com/moby/buildkit v0.15.2 + github.com/moby/buildkit v0.16.0 github.com/open-policy-agent/opa v0.68.1-0.20240903211041-76f7038ea2d1 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 @@ -117,21 +117,21 @@ require ( github.com/zclconf/go-cty v1.15.0 github.com/zclconf/go-cty-yaml v1.0.3 go.etcd.io/bbolt v1.3.11 - golang.org/x/crypto v0.26.0 + golang.org/x/crypto v0.27.0 golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect - golang.org/x/mod v0.20.0 - golang.org/x/net v0.28.0 + golang.org/x/mod v0.21.0 + golang.org/x/net v0.29.0 golang.org/x/sync v0.8.0 - golang.org/x/term v0.23.0 - golang.org/x/text v0.17.0 + golang.org/x/term v0.24.0 + golang.org/x/text v0.18.0 golang.org/x/vuln v1.1.3 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v3 v3.0.1 - helm.sh/helm/v3 v3.15.4 - k8s.io/api v0.30.3 + helm.sh/helm/v3 v3.16.1 + k8s.io/api v0.31.0 k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 - modernc.org/sqlite v1.32.0 + modernc.org/sqlite v1.33.1 sigs.k8s.io/yaml v1.4.0 ) @@ -171,18 +171,19 @@ require ( github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go v1.54.6 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect github.com/aws/aws-sdk-go-v2/service/ebs v1.22.1 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.22.7 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.20 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.23.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.2 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/blang/semver v3.5.1+incompatible // indirect + github.com/blang/semver/v4 v4.0.0 // indirect github.com/briandowns/spinner v1.23.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect @@ -196,18 +197,18 @@ require ( github.com/containerd/platforms v0.2.1 // indirect github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect github.com/containerd/ttrpc v1.2.5 // indirect - github.com/containerd/typeurl/v2 v2.1.1 // indirect + github.com/containerd/typeurl/v2 v2.2.0 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 // indirect - github.com/cyphar/filepath-securejoin v0.2.4 // indirect + github.com/cyphar/filepath-securejoin v0.3.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/dlclark/regexp2 v1.4.0 // indirect - github.com/docker/cli v27.1.1+incompatible // indirect + github.com/docker/cli v27.2.1+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.2 // indirect github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect @@ -218,7 +219,7 @@ require ( github.com/dustin/go-humanize v1.0.1 // indirect github.com/emicklei/go-restful/v3 v3.11.0 // indirect github.com/emirpasic/gods v1.18.1 // indirect - github.com/evanphx/json-patch v5.7.0+incompatible // indirect + github.com/evanphx/json-patch v5.9.0+incompatible // indirect github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect @@ -274,7 +275,7 @@ require ( github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/jedisct1/go-minisign v0.0.0-20230811132847-661be99b8267 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/jmoiron/sqlx v1.3.5 // indirect + github.com/jmoiron/sqlx v1.4.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect @@ -299,9 +300,9 @@ require ( github.com/moby/locker v1.0.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/spdystream v0.4.0 // indirect - github.com/moby/sys/mountinfo v0.7.1 // indirect + github.com/moby/sys/mountinfo v0.7.2 // indirect github.com/moby/sys/sequential v0.5.0 // indirect - github.com/moby/sys/signal v0.7.0 // indirect + github.com/moby/sys/signal v0.7.1 // indirect github.com/moby/sys/user v0.3.0 // indirect github.com/moby/sys/userns v0.1.0 // indirect github.com/moby/term v0.5.0 // indirect @@ -331,7 +332,7 @@ require ( github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/rivo/uniseg v0.4.4 // indirect - github.com/rubenv/sql-migrate v1.5.2 // indirect + github.com/rubenv/sql-migrate v1.7.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect @@ -371,7 +372,7 @@ require ( github.com/yusufpapurcu/wmi v1.2.4 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect go.opentelemetry.io/otel v1.28.0 // indirect go.opentelemetry.io/otel/metric v1.28.0 // indirect @@ -381,7 +382,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/sys v0.23.0 // indirect + golang.org/x/sys v0.25.0 // indirect golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 // indirect golang.org/x/time v0.6.0 // indirect golang.org/x/tools v0.24.0 // indirect @@ -391,20 +392,21 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect google.golang.org/grpc v1.66.0 // indirect gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect + gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/apiextensions-apiserver v0.30.3 // indirect + k8s.io/apiextensions-apiserver v0.31.0 // indirect k8s.io/apimachinery v0.31.0 // indirect - k8s.io/apiserver v0.30.3 // indirect - k8s.io/cli-runtime v0.30.3 // indirect - k8s.io/client-go v0.30.3 // indirect - k8s.io/component-base v0.30.3 // indirect + k8s.io/apiserver v0.31.0 // indirect + k8s.io/cli-runtime v0.31.0 // indirect + k8s.io/client-go v0.31.0 // indirect + k8s.io/component-base v0.31.0 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - k8s.io/kubectl v0.30.3 // indirect + k8s.io/kubectl v0.31.0 // indirect modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect modernc.org/libc v1.55.3 // indirect modernc.org/mathutil v1.6.0 // indirect @@ -414,7 +416,7 @@ require ( mvdan.cc/sh/v3 v3.8.0 // indirect oras.land/oras-go v1.2.5 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect - sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect - sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect + sigs.k8s.io/kustomize/api v0.17.2 // indirect + sigs.k8s.io/kustomize/kyaml v0.17.1 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) diff --git a/go.sum b/go.sum index da3862e7d75d..b284e23f5722 100644 --- a/go.sum +++ b/go.sum @@ -241,8 +241,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/CycloneDX/cyclonedx-go v0.9.0 h1:inaif7qD8bivyxp7XLgxUYtOXWtDez7+j72qKTMQTb8= -github.com/CycloneDX/cyclonedx-go v0.9.0/go.mod h1:NE/EWvzELOFlG6+ljX/QeMlVt9VKcTwu8u0ccsACEsw= +github.com/CycloneDX/cyclonedx-go v0.9.1 h1:yffaWOZsv77oTJa/SdVZYdgAgFioCeycBUKkqS2qzQM= +github.com/CycloneDX/cyclonedx-go v0.9.1/go.mod h1:NE/EWvzELOFlG6+ljX/QeMlVt9VKcTwu8u0ccsACEsw= github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= github.com/GoogleCloudPlatform/docker-credential-gcr v2.0.5+incompatible h1:juIaKLLVhqzP55d8x4cSVgwyQv76Z55/fRv/UBr2KkQ= @@ -364,44 +364,44 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:W github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.54.6 h1:HEYUib3yTt8E6vxjMWM3yAq5b+qjj/6aKA62mkgux9g= github.com/aws/aws-sdk-go v1.54.6/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.30.5 h1:mWSRTwQAb0aLE17dSzztCVJWI9+cRMgqebndjwDyK0g= -github.com/aws/aws-sdk-go-v2 v1.30.5/go.mod h1:CT+ZPWXbYrci8chcARI3OmI/qgd+f6WtuLOoaIA8PR0= -github.com/aws/aws-sdk-go-v2/config v1.27.33 h1:Nof9o/MsmH4oa0s2q9a0k7tMz5x/Yj5k06lDODWz3BU= -github.com/aws/aws-sdk-go-v2/config v1.27.33/go.mod h1:kEqdYzRb8dd8Sy2pOdEbExTTF5v7ozEXX0McgPE7xks= -github.com/aws/aws-sdk-go-v2/credentials v1.17.32 h1:7Cxhp/BnT2RcGy4VisJ9miUPecY+lyE9I8JvcZofn9I= -github.com/aws/aws-sdk-go-v2/credentials v1.17.32/go.mod h1:P5/QMF3/DCHbXGEGkdbilXHsyTBX5D3HSwcrSc9p20I= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13 h1:pfQ2sqNpMVK6xz2RbqLEL0GH87JOwSxPV2rzm8Zsb74= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.13/go.mod h1:NG7RXPUlqfsCLLFfi0+IpKN4sCB9D9fw/qTaSB+xRoU= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17 h1:pI7Bzt0BJtYA0N/JEC6B8fJ4RBrEMi1LBrkMdFYNSnQ= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.17/go.mod h1:Dh5zzJYMtxfIjYW+/evjQ8uj2OyR/ve2KROHGHlSFqE= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17 h1:Mqr/V5gvrhA2gvgnF42Zh5iMiQNcOYthFYwCyrnuWlc= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.17/go.mod h1:aLJpZlCmjE+V+KtN1q1uyZkfnUWpQGpbsn89XPKyzfU= +github.com/aws/aws-sdk-go-v2 v1.31.0 h1:3V05LbxTSItI5kUqNwhJrrrY1BAXxXt0sN0l72QmG5U= +github.com/aws/aws-sdk-go-v2 v1.31.0/go.mod h1:ztolYtaEUtdpf9Wftr31CJfLVjOnD/CVRkKOOYgF8hA= +github.com/aws/aws-sdk-go-v2/config v1.27.38 h1:mMVyJJuSUdbD4zKXoxDgWrgM60QwlFEg+JhihCq6wCw= +github.com/aws/aws-sdk-go-v2/config v1.27.38/go.mod h1:6xOiNEn58bj/64MPKx89r6G/el9JZn8pvVbquSqTKK4= +github.com/aws/aws-sdk-go-v2/credentials v1.17.36 h1:zwI5WrT+oWWfzSKoTNmSyeBKQhsFRJRv+PGW/UZW+Yk= +github.com/aws/aws-sdk-go-v2/credentials v1.17.36/go.mod h1:3AG/sY1rc9NJrNWcN/3KPU4SIDPGTrd/qegKB0TnFdE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 h1:C/d03NAmh8C4BZXhuRNboF/DqhBkBCeDiJDcaqIT5pA= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14/go.mod h1:7I0Ju7p9mCIdlrfS+JCgqcYD0VXz/N4yozsox+0o078= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18 h1:kYQ3H1u0ANr9KEKlGs/jTLrBFPo8P8NaH/w7A01NeeM= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18/go.mod h1:r506HmK5JDUh9+Mw4CfGJGSSoqIiLCndAuqXuhbv67Y= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18 h1:Z7IdFUONvTcvS7YuhtVxN99v2cCoHRXOS4mTr0B/pUc= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18/go.mod h1:DkKMmksZVVyat+Y+r1dEOgJEfUeA7UngIHWeKsi0yNc= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/service/ebs v1.22.1 h1:SeDJWG4pmye+/aO6k+zt9clPTUy1MXqUmkW8rbAddQg= github.com/aws/aws-sdk-go-v2/service/ebs v1.22.1/go.mod h1:wRzaW0v9GGQS0h//wpsVDw3Hah5gs5UP+NxoyGeZIGM= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.2 h1:QUUvxEs9q1DsYCaWaRrV8i7n82Adm34jrHb6OPjXPqc= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.177.2/go.mod h1:TFSALWR7Xs7+KyMM87ZAYxncKFBvzEt2rpK/BJCH2ps= -github.com/aws/aws-sdk-go-v2/service/ecr v1.32.4 h1:nQAU2Yr+afkAvIV39mg7LrNYFNQP7ShwbmiJqx2fUKA= -github.com/aws/aws-sdk-go-v2/service/ecr v1.32.4/go.mod h1:keOS9j4fv5ASh7dV29lIpGw2QgoJwGFAyMU0uPvfax4= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.179.1 h1:TwFjSwRn1kR1i1qeq5cQBRwRaZ80JQS8BHsJTb6QBk8= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.179.1/go.mod h1:W6sNzs5T4VpZn1Vy+FMKw8s24vt5k6zPJXcNOK0asBo= +github.com/aws/aws-sdk-go-v2/service/ecr v1.35.2 h1:bVNvja4oEB7v+VL1yP46hWthCPp+KYpZBLS2AifM5PY= +github.com/aws/aws-sdk-go-v2/service/ecr v1.35.2/go.mod h1:oRaGEExKI6Pqcow+Tt7wpJf73/Srcj/CUJv5Eb9QFhg= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2 h1:PpbXaecV3sLAS6rjQiaKw4/jyq3Z8gNzmoJupHAoBp0= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2/go.mod h1:fUHpGXr4DrXkEDpGAjClPsviWf+Bszeb0daKE0blxv8= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4 h1:KypMCbLPPHEmf9DgMGw51jMj77VfGPAN2Kv4cfhlfgI= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.4/go.mod h1:Vz1JQXliGcQktFTN/LN6uGppAIRoLBR2bMvIMP0gOjc= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19 h1:rfprUlsdzgl7ZL2KlXiUAoJnI/VxfHCvDFr2QDFj6u4= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.19/go.mod h1:SCWkEdRq8/7EK60NcvvQ6NXKuTcchAD4ROAsC37VEZE= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5 h1:QFASJGfT8wMXtuP3D5CRmMjARHv9ZmzFUMJznHDOY3w= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5/go.mod h1:QdZ3OmoIjSX+8D1OPAzPxDfjXASbBMDsz9qvtyIhtik= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.20 h1:Xbwbmk44URTiHNx6PNo0ujDE6ERlsCKJD3u1zfnzAPg= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.20/go.mod h1:oAfOFzUB14ltPZj1rWwRc3d/6OgD76R8KlvU3EqM9Fg= github.com/aws/aws-sdk-go-v2/service/kms v1.30.0 h1:yS0JkEdV6h9JOo8sy2JSpjX+i7vsKifU8SIeHrqiDhU= github.com/aws/aws-sdk-go-v2/service/kms v1.30.0/go.mod h1:+I8VUUSVD4p5ISQtzpgSva4I8cJ4SQ4b1dcBcof7O+g= -github.com/aws/aws-sdk-go-v2/service/s3 v1.61.2 h1:Kp6PWAlXwP1UvIflkIP6MFZYBNDCa4mFCGtxrpICVOg= -github.com/aws/aws-sdk-go-v2/service/s3 v1.61.2/go.mod h1:5FmD/Dqq57gP+XwaUnd5WFPipAuzrf0HmupX27Gvjvc= -github.com/aws/aws-sdk-go-v2/service/sso v1.22.7 h1:pIaGg+08llrP7Q5aiz9ICWbY8cqhTkyy+0SHvfzQpTc= -github.com/aws/aws-sdk-go-v2/service/sso v1.22.7/go.mod h1:eEygMHnTKH/3kNp9Jr1n3PdejuSNcgwLe1dWgQtO0VQ= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7 h1:/Cfdu0XV3mONYKaOt1Gr0k1KvQzkzPyiKUdlWJqy+J4= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.7/go.mod h1:bCbAxKDqNvkHxRaIMnyVPXPo+OaPRwvmgzMxbz1VKSA= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.7 h1:NKTa1eqZYw8tiHSRGpP0VtTdub/8KNk8sDkNPFaOKDE= -github.com/aws/aws-sdk-go-v2/service/sts v1.30.7/go.mod h1:NXi1dIAGteSaRLqYgarlhP/Ij0cFT+qmCwiJqWh/U5o= -github.com/aws/smithy-go v1.20.4 h1:2HK1zBdPgRbjFOHlfeQZfpC4r72MOb9bZkiFwggKO+4= -github.com/aws/smithy-go v1.20.4/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/aws/aws-sdk-go-v2/service/s3 v1.63.2 h1:1iXmXy8SJzQVMGvo40TSzBYS9ig6BSyXfRIMzLfmBfE= +github.com/aws/aws-sdk-go-v2/service/s3 v1.63.2/go.mod h1:NLTqRLe3pUNu3nTEHI6XlHLKYmc8fbHUdMxAB6+s41Q= +github.com/aws/aws-sdk-go-v2/service/sso v1.23.2 h1:yzi/y/vKlLyzOfG7pSu5ONNGRxHIgLeDrV4w2AMRCo0= +github.com/aws/aws-sdk-go-v2/service/sso v1.23.2/go.mod h1:XRlMvmad0ZNL+75C5FYdMvbbLkd6qiqz6foR1nA1PXY= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.2 h1:3gb6pYhYLjo8rB1h2Tqs61wpjRd3rQymYcVq/pp0yxI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.2/go.mod h1:FnvDM4sfa+isJ3kDXIzAB9GAwVSzFzSy97uZ3IsHo4E= +github.com/aws/aws-sdk-go-v2/service/sts v1.31.2 h1:O6tyji8mXmBGsHvTCB0VIhrDw19lGTUSbKIyjnw79s8= +github.com/aws/aws-sdk-go-v2/service/sts v1.31.2/go.mod h1:yMWe0F+XG0DkRZK5ODZhG7BEFYhLXi2dqGsv6tX0cgI= +github.com/aws/smithy-go v1.21.0 h1:H7L8dtDRk0P1Qm6y0ji7MCYMQObJ5R9CRpyPhRUkLYA= +github.com/aws/smithy-go v1.21.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 h1:SoFYaT9UyGkR0+nogNyD/Lj+bsixB+SNuAS4ABlEs6M= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8/go.mod h1:2JF49jcDOrLStIXN/j/K1EKRq8a8R2qRnlZA6/o/c7c= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -414,6 +414,8 @@ github.com/bitnami/go-version v0.0.0-20231130084017-bb00604d650c h1:C4UZIaS+HAw+ github.com/bitnami/go-version v0.0.0-20231130084017-bb00604d650c/go.mod h1:9iglf1GG4oNRJ39bZ5AZrjgAFD2RwQbXw6Qf7Cs47wo= github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= +github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= +github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I= github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M= @@ -478,8 +480,8 @@ github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= github.com/containerd/cgroups/v3 v3.0.2 h1:f5WFqIVSgo5IZmtTT3qVBo6TzI1ON6sycSBKkymb9L0= github.com/containerd/cgroups/v3 v3.0.2/go.mod h1:JUgITrzdFqp42uI2ryGA+ge0ap/nxzYgkGmIcetmErE= -github.com/containerd/containerd v1.7.21 h1:USGXRK1eOC/SX0L195YgxTHb0a00anxajOzgfN0qrCA= -github.com/containerd/containerd v1.7.21/go.mod h1:e3Jz1rYRUZ2Lt51YrH9Rz0zPyJBOlSvB3ghr2jbVD8g= +github.com/containerd/containerd v1.7.22 h1:nZuNnNRA6T6jB975rx2RRNqqH2k6ELYKDZfqTHqwyy0= +github.com/containerd/containerd v1.7.22/go.mod h1:e3Jz1rYRUZ2Lt51YrH9Rz0zPyJBOlSvB3ghr2jbVD8g= github.com/containerd/containerd/api v1.7.19 h1:VWbJL+8Ap4Ju2mx9c9qS1uFSB1OVYr5JJrW2yT5vFoA= github.com/containerd/containerd/api v1.7.19/go.mod h1:fwGavl3LNwAV5ilJ0sbrABL44AQxmNjDRcwheXDb6Ig= github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= @@ -496,8 +498,8 @@ github.com/containerd/stargz-snapshotter/estargz v0.15.1 h1:eXJjw9RbkLFgioVaTG+G github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk= github.com/containerd/ttrpc v1.2.5 h1:IFckT1EFQoFBMG4c3sMdT8EP3/aKfumK1msY+Ze4oLU= github.com/containerd/ttrpc v1.2.5/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o= -github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4= -github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= +github.com/containerd/typeurl/v2 v2.2.0 h1:6NBDbQzr7I5LHgp34xAXYF5DOTQDn05X58lsPEmzLso= +github.com/containerd/typeurl/v2 v2.2.0/go.mod h1:8XOOxnyatxSWuG8OfsZXVnAF4iZfedjS/8UHSPJnX4g= github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU= github.com/coreos/go-oidc/v3 v3.10.0/go.mod h1:5j11xcw0D3+SGxn6Z/WFADsgcWVMyNAlSQupk0KK3ac= @@ -512,8 +514,8 @@ github.com/csaf-poc/csaf_distribution/v3 v3.0.0 h1:ob9+Fmpff0YWgTP3dYaw7G2hKQ9ce github.com/csaf-poc/csaf_distribution/v3 v3.0.0/go.mod h1:uilCTiNKivq+6zrDvjtZaUeLk70oe21iwKivo6ILwlQ= github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 h1:2Dx4IHfC1yHWI12AxQDJM1QbRCDfk6M+blLzlZCXdrc= github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46/go.mod h1:uzvlm1mxhHkdfqitSA92i7Se+S9ksOn3a3qmv/kyOCw= -github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg= -github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/cyphar/filepath-securejoin v0.3.1 h1:1V7cHiaW+C+39wEfpH6XlLBQo3j/PciWFrgfCLS8XrE= +github.com/cyphar/filepath-securejoin v0.3.1/go.mod h1:F7i41x/9cBF7lzCrVsYs9fuzwRZm4NQsGTBdpp6mETc= github.com/danieljoos/wincred v1.2.1 h1:dl9cBrupW8+r5250DYkYxocLeZ1Y4vB1kxgtjxw8GQs= github.com/danieljoos/wincred v1.2.1/go.mod h1:uGaFL9fDn3OLTvzCGulzE+SzjEe5NGlh5FdCcyfPwps= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -541,12 +543,12 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/docker/cli v27.1.1+incompatible h1:goaZxOqs4QKxznZjjBWKONQci/MywhtRv2oNn0GkeZE= -github.com/docker/cli v27.1.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v27.2.1+incompatible h1:U5BPtiD0viUzjGAjV1p0MGB8eVA3L3cbIrnyWmSJI70= +github.com/docker/cli v27.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v27.2.0+incompatible h1:Rk9nIVdfH3+Vz4cyI/uhbINhEZ/oLmc+CBXmH6fbNk4= -github.com/docker/docker v27.2.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI= +github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo= github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= @@ -582,8 +584,8 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/evanphx/json-patch v5.7.0+incompatible h1:vgGkfT/9f8zE6tvSCe74nfpAVDQ2tG6yudJd8LBksgI= -github.com/evanphx/json-patch v5.7.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= +github.com/evanphx/json-patch v5.9.0+incompatible h1:fBXyNpNMuTTDdquAq/uisOr2lShz4oaXpDTX2bLe7ls= +github.com/evanphx/json-patch v5.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -681,22 +683,15 @@ github.com/go-playground/validator/v10 v10.18.0 h1:BvolUXjp4zuvkZ5YN5t7ebzbhlUtP github.com/go-playground/validator/v10 v10.18.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= -github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= -github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg= github.com/go-test/deep v1.1.0/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= -github.com/gobuffalo/logger v1.0.6 h1:nnZNpxYo0zx+Aj9RfMPBm+x9zAU2OayFh/xrAWi34HU= -github.com/gobuffalo/logger v1.0.6/go.mod h1:J31TBEHR1QLV2683OXTAItYIg8pv2JMHnF/quuAbMjs= -github.com/gobuffalo/packd v1.0.1 h1:U2wXfRr4E9DH8IdsDLlRFwTZTK7hLfq9qT/QHXGVe/0= -github.com/gobuffalo/packd v1.0.1/go.mod h1:PP2POP3p3RXGz7Jh6eYEf93S7vA2za6xM7QT85L4+VY= -github.com/gobuffalo/packr/v2 v2.8.3 h1:xE1yzvnO56cUC0sTpKR3DIbxZgB54AftTFMhB2XEWlY= -github.com/gobuffalo/packr/v2 v2.8.3/go.mod h1:0SahksCVcx4IMnigTjiFuyldmTrdTctXsOdiU5KwbKc= github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y= github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8= github.com/goccy/go-yaml v1.8.1/go.mod h1:wS4gNoLalDSJxo/SpngzPQ2BN4uuZVLCmbM4S3vd4+Y= @@ -902,8 +897,8 @@ github.com/hashicorp/golang-lru v0.6.0 h1:uL2shRDx7RTrOrTCUZEGP/wJUFiUI8QT6E7z5o github.com/hashicorp/golang-lru v0.6.0/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= -github.com/hashicorp/hc-install v0.8.0 h1:LdpZeXkZYMQhoKPCecJHlKvUkQFixN/nvyR1CdfOLjI= -github.com/hashicorp/hc-install v0.8.0/go.mod h1:+MwJYjDfCruSD/udvBmRB22Nlkwwkwf5sAB6uTIhSaU= +github.com/hashicorp/hc-install v0.9.0 h1:2dIk8LcvANwtv3QZLckxcjyF5w8KVtiMxu6G6eLhghE= +github.com/hashicorp/hc-install v0.9.0/go.mod h1:+6vOP+mf3tuGgMApVYtmsnDoKWMDcFXeTxCACYZ8SFg= github.com/hashicorp/hcl v1.0.1-vault-5 h1:kI3hhbbyzr4dldA8UdTb7ZlVVlI2DACdCfz31RPDgJM= github.com/hashicorp/hcl v1.0.1-vault-5/go.mod h1:XYhtn6ijBSAj6n4YqAaf7RBPS4I06AItNorpy+MoQNM= github.com/hashicorp/hcl/v2 v2.22.0 h1:hkZ3nCtqeJsDhPRFz5EA9iwcG1hNWGePOTw6oyul12M= @@ -939,8 +934,8 @@ github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGw github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmhodges/clock v1.2.0 h1:eq4kys+NI0PLngzaHEe7AmPT90XMGIEySD1JfV1PDIs= github.com/jmhodges/clock v1.2.0/go.mod h1:qKjhA7x7u/lQpPB1XAqX1b1lCI/w3/fNuYpI/ZjLynI= -github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= -github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= @@ -950,8 +945,6 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw= -github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -997,7 +990,6 @@ github.com/liamg/jfather v0.0.7 h1:Xf78zS263yfT+xr2VSo6+kyAy4ROlCacRqJG7s5jt4k= github.com/liamg/jfather v0.0.7/go.mod h1:xXBGiBoiZ6tmHhfy5Jzw8sugzajwYdi6VosIpB3/cPM= github.com/liamg/memoryfs v1.6.0 h1:jAFec2HI1PgMTem5gR7UT8zi9u4BfG5jorCRlLH06W8= github.com/liamg/memoryfs v1.6.0/go.mod h1:z7mfqXFQS8eSeBBsFjYLlxYRMRyiPktytvYCYTb3BSk= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= @@ -1013,12 +1005,6 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= -github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc= -github.com/markbates/oncer v1.0.0 h1:E83IaVAHygyndzPimgUYJjbshhDTALZyXxvk9FOlQRY= -github.com/markbates/oncer v1.0.0/go.mod h1:Z59JA581E9GP6w96jai+TGqafHPW+cPfRxz2aSZ0mcI= -github.com/markbates/safe v1.0.1 h1:yjZkbvRM6IzKj9tlu/zMJLS0n/V351OZWRnF3QfaUxI= -github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= github.com/masahiro331/go-disk v0.0.0-20240625071113-56c933208fee h1:cgm8mE25x5XXX2oyvJDlyJ72K+rDu/4ZCYce2worNb8= github.com/masahiro331/go-disk v0.0.0-20240625071113-56c933208fee/go.mod h1:rojbW5tVhH1cuVYFKZS+QX+VGXK45JVsRO+jW92kkKM= github.com/masahiro331/go-ebs-file v0.0.0-20240917043618-e6d2bea5c32e h1:nCgF1JEYIS8KNuJtIeUrmjjhktIMKWNmASZqwK2ynu0= @@ -1050,7 +1036,6 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= -github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -1074,8 +1059,8 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= -github.com/moby/buildkit v0.15.2 h1:DnONr0AoceTWyv+plsQ7IhkSaj+6o0WyoaxYPyTFIxs= -github.com/moby/buildkit v0.15.2/go.mod h1:Yis8ZMUJTHX9XhH9zVyK2igqSHV3sxi3UN0uztZocZk= +github.com/moby/buildkit v0.16.0 h1:wOVBj1o5YNVad/txPQNXUXdelm7Hs/i0PUFjzbK0VKE= +github.com/moby/buildkit v0.16.0/go.mod h1:Xqx/5GlrqE1yIRORk0NSCVDFpQAU1WjlT6KHYZdisIQ= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= @@ -1084,12 +1069,12 @@ github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkV github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8= github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= -github.com/moby/sys/mountinfo v0.7.1 h1:/tTvQaSJRr2FshkhXiIpux6fQ2Zvc4j7tAhMTStAG2g= -github.com/moby/sys/mountinfo v0.7.1/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= +github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= +github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= -github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI= -github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= +github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0= +github.com/moby/sys/signal v0.7.1/go.mod h1:Se1VGehYokAkrSQwL4tDzHvETwUZlnY7S5XtQ50mQp8= github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= @@ -1137,8 +1122,8 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= -github.com/onsi/gomega v1.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE= -github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/open-policy-agent/opa v0.68.1-0.20240903211041-76f7038ea2d1 h1:GQrryTKpunLNDc2NdhNL1FzfrbuNvo45s76anGdqz9k= github.com/open-policy-agent/opa v0.68.1-0.20240903211041-76f7038ea2d1/go.mod h1:5E5SvaPwTpwt2WM177I9Z3eT7qUpmOGjk1ZdHs+TZ4w= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -1219,8 +1204,8 @@ github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6L github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= -github.com/rubenv/sql-migrate v1.5.2 h1:bMDqOnrJVV/6JQgQ/MxOpU+AdO8uzYYA/TxFUBzFtS0= -github.com/rubenv/sql-migrate v1.5.2/go.mod h1:H38GW8Vqf8F0Su5XignRyaRcbXbJunSWxs+kmzlg0Is= +github.com/rubenv/sql-migrate v1.7.0 h1:HtQq1xyTN2ISmQDggnh0c9U3JlP8apWh8YO2jzlXpTI= +github.com/rubenv/sql-migrate v1.7.0/go.mod h1:S4wtDEG1CKn+0ShpTtzWhFpHHI5PvCUtiGI+C+Z2THE= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -1428,8 +1413,8 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0 h1:4Pp6oUg3+e/6M4C0A/3kJ2VYa++dsWVTtGgLVj5xtHg= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= @@ -1472,8 +1457,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= -golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= +golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= +golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1515,8 +1500,8 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= +golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1575,8 +1560,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= +golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= +golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1686,7 +1671,6 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1713,8 +1697,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= -golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= +golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 h1:FemxDzfMUcK2f3YY4H+05K9CDzbSVr2+q/JKN45pey0= golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1725,8 +1709,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1741,8 +1725,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= +golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -2049,6 +2033,8 @@ gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qS gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk= gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-jose/go-jose.v2 v2.6.3 h1:nt80fvSDlhKWQgSWyHyy5CfmlQr+asih51R8PTWNKKs= gopkg.in/go-jose/go-jose.v2 v2.6.3/go.mod h1:zzZDPkNNw/c9IE7Z9jr11mBZQhKQTMzoEEIoEdZlFBI= @@ -2075,8 +2061,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= -helm.sh/helm/v3 v3.15.4 h1:UFHd6oZ1IN3FsUZ7XNhOQDyQ2QYknBNWRHH57e9cbHY= -helm.sh/helm/v3 v3.15.4/go.mod h1:phOwlxqGSgppCY/ysWBNRhG3MtnpsttOzxaTK+Mt40E= +helm.sh/helm/v3 v3.16.1 h1:cER6tI/8PgUAsaJaQCVBUg3VI9KN4oVaZJgY60RIc0c= +helm.sh/helm/v3 v3.16.1/go.mod h1:r+xBHHP20qJeEqtvBXMf7W35QDJnzY/eiEBzt+TfHps= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -2084,26 +2070,26 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ= -k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04= -k8s.io/apiextensions-apiserver v0.30.3 h1:oChu5li2vsZHx2IvnGP3ah8Nj3KyqG3kRSaKmijhB9U= -k8s.io/apiextensions-apiserver v0.30.3/go.mod h1:uhXxYDkMAvl6CJw4lrDN4CPbONkF3+XL9cacCT44kV4= +k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo= +k8s.io/api v0.31.0/go.mod h1:0YiFF+JfFxMM6+1hQei8FY8M7s1Mth+z/q7eF1aJkTE= +k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= +k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc= k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/apiserver v0.30.3 h1:QZJndA9k2MjFqpnyYv/PH+9PE0SHhx3hBho4X0vE65g= -k8s.io/apiserver v0.30.3/go.mod h1:6Oa88y1CZqnzetd2JdepO0UXzQX4ZnOekx2/PtEjrOg= -k8s.io/cli-runtime v0.30.3 h1:aG69oRzJuP2Q4o8dm+f5WJIX4ZBEwrvdID0+MXyUY6k= -k8s.io/cli-runtime v0.30.3/go.mod h1:hwrrRdd9P84CXSKzhHxrOivAR9BRnkMt0OeP5mj7X30= -k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k= -k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U= -k8s.io/component-base v0.30.3 h1:Ci0UqKWf4oiwy8hr1+E3dsnliKnkMLZMVbWzeorlk7s= -k8s.io/component-base v0.30.3/go.mod h1:C1SshT3rGPCuNtBs14RmVD2xW0EhRSeLvBh7AGk1quA= +k8s.io/apiserver v0.31.0 h1:p+2dgJjy+bk+B1Csz+mc2wl5gHwvNkC9QJV+w55LVrY= +k8s.io/apiserver v0.31.0/go.mod h1:KI9ox5Yu902iBnnyMmy7ajonhKnkeZYJhTZ/YI+WEMk= +k8s.io/cli-runtime v0.31.0 h1:V2Q1gj1u3/WfhD475HBQrIYsoryg/LrhhK4RwpN+DhA= +k8s.io/cli-runtime v0.31.0/go.mod h1:vg3H94wsubuvWfSmStDbekvbla5vFGC+zLWqcf+bGDw= +k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8= +k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU= +k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs= +k8s.io/component-base v0.31.0/go.mod h1:TYVuzI1QmN4L5ItVdMSXKvH7/DtvIuas5/mm8YT3rTo= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/kubectl v0.30.3 h1:YIBBvMdTW0xcDpmrOBzcpUVsn+zOgjMYIu7kAq+yqiI= -k8s.io/kubectl v0.30.3/go.mod h1:IcR0I9RN2+zzTRUa1BzZCm4oM0NLOawE6RzlDvd1Fpo= +k8s.io/kubectl v0.31.0 h1:kANwAAPVY02r4U4jARP/C+Q1sssCcN/1p9Nk+7BQKVg= +k8s.io/kubectl v0.31.0/go.mod h1:pB47hhFypGsaHAPjlwrNbvhXgmuAr01ZBvAIIUaI8d4= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= @@ -2126,8 +2112,8 @@ modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4= modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc= modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss= -modernc.org/sqlite v1.32.0 h1:6BM4uGza7bWypsw4fdLRsLxut6bHe4c58VeqjRgST8s= -modernc.org/sqlite v1.32.0/go.mod h1:UqoylwmTb9F+IqXERT8bW9zzOWN8qwAIcLdzeBZs4hA= +modernc.org/sqlite v1.33.1 h1:trb6Z3YYoeM9eDL1O8do81kP+0ejv+YzgyFo+Gwy0nM= +modernc.org/sqlite v1.33.1/go.mod h1:pXV2xHxhzXZsgT/RtTFAPY6JJDEvOTcTdwADQCCWD4k= modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= @@ -2141,10 +2127,10 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= -sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 h1:XX3Ajgzov2RKUdc5jW3t5jwY7Bo7dcRm+tFxT+NfgY0= -sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3/go.mod h1:9n16EZKMhXBNSiUC5kSdFQJkdH3zbxS/JoO619G1VAY= -sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 h1:W6cLQc5pnqM7vh3b7HvGNfXrJ/xL6BDMS0v1V/HHg5U= -sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3/go.mod h1:JWP1Fj0VWGHyw3YUPjXSQnRnrwezrZSrApfX5S0nIag= +sigs.k8s.io/kustomize/api v0.17.2 h1:E7/Fjk7V5fboiuijoZHgs4aHuexi5Y2loXlVOAVAG5g= +sigs.k8s.io/kustomize/api v0.17.2/go.mod h1:UWTz9Ct+MvoeQsHcJ5e+vziRRkwimm3HytpZgIYqye0= +sigs.k8s.io/kustomize/kyaml v0.17.1 h1:TnxYQxFXzbmNG6gOINgGWQt09GghzgTP6mIurOgrLCQ= +sigs.k8s.io/kustomize/kyaml v0.17.1/go.mod h1:9V0mCjIEYjlXuCdYsSXvyoy2BTsLESH7TlGV81S282U= sigs.k8s.io/release-utils v0.7.7 h1:JKDOvhCk6zW8ipEOkpTGDH/mW3TI+XqtPp16aaQ79FU= sigs.k8s.io/release-utils v0.7.7/go.mod h1:iU7DGVNi3umZJ8q6aHyUFzsDUIaYwNnNKGHo3YE5E3s= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= From 13ef3e7d62ba2bcb3a04d7b44f79b1299674b480 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Thu, 26 Sep 2024 23:26:50 +0600 Subject: [PATCH 100/183] fix(db): check `DownloadedAt` for `trivy-java-db` (#7592) --- pkg/javadb/client.go | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/pkg/javadb/client.go b/pkg/javadb/client.go index ca055a0c333f..936c2d40c028 100644 --- a/pkg/javadb/client.go +++ b/pkg/javadb/client.go @@ -53,7 +53,7 @@ func (u *Updater) Update() error { } } - if (meta.Version != SchemaVersion || meta.NextUpdate.Before(time.Now().UTC())) && !u.skip { + if (meta.Version != SchemaVersion || !u.isNewDB(meta)) && !u.skip { // Download DB log.Info("Java DB Repository", log.Any("repository", u.repo)) log.Info("Downloading the Java DB...") @@ -85,6 +85,20 @@ func (u *Updater) Update() error { return nil } +func (u *Updater) isNewDB(meta db.Metadata) bool { + now := time.Now().UTC() + if now.Before(meta.NextUpdate) { + log.Debug("Java DB update was skipped because the local Java DB is the latest") + return true + } + + if now.Before(meta.DownloadedAt.Add(time.Hour * 24)) { // 1 day + log.Debug("Java DB update was skipped because the local Java DB was downloaded during the last day") + return true + } + return false +} + func Init(cacheDir string, javaDBRepository name.Reference, skip, quiet bool, registryOption ftypes.RegistryOptions) { updater = &Updater{ repo: javaDBRepository, From a8fbe46119adbd89f827a75c75b9e97d392f1842 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 27 Sep 2024 08:03:46 +0600 Subject: [PATCH 101/183] fix: allow access to '..' in mapfs (#7575) Signed-off-by: nikpivkin --- pkg/mapfs/fs.go | 12 ++++++++---- pkg/mapfs/fs_test.go | 23 +++++++++++++++++++++++ pkg/mapfs/testdata/subdir/..foo.txt | 0 pkg/mapfs/testdata/subdir/foo.txt | 0 4 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 pkg/mapfs/testdata/subdir/..foo.txt create mode 100644 pkg/mapfs/testdata/subdir/foo.txt diff --git a/pkg/mapfs/fs.go b/pkg/mapfs/fs.go index 4cba59263c37..5ce894b8101c 100644 --- a/pkg/mapfs/fs.go +++ b/pkg/mapfs/fs.go @@ -123,7 +123,7 @@ func (m *FS) CopyFilesUnder(dir string) error { // Stat returns a FileInfo describing the file. func (m *FS) Stat(name string) (fs.FileInfo, error) { - if strings.HasPrefix(name, "../") && m.underlyingRoot != "" { + if m.isPathAboveRoot(name) { return os.Stat(filepath.Join(m.underlyingRoot, name)) } @@ -145,7 +145,7 @@ func (m *FS) Stat(name string) (fs.FileInfo, error) { // ReadDir reads the named directory // and returns a list of directory entries sorted by filename. func (m *FS) ReadDir(name string) ([]fs.DirEntry, error) { - if strings.HasPrefix(name, "../") && m.underlyingRoot != "" { + if m.isPathAboveRoot(name) { return os.ReadDir(filepath.Join(m.underlyingRoot, name)) } return m.root.ReadDir(cleanPath(name)) @@ -153,7 +153,7 @@ func (m *FS) ReadDir(name string) ([]fs.DirEntry, error) { // Open opens the named file for reading. func (m *FS) Open(name string) (fs.File, error) { - if strings.HasPrefix(name, "../") && m.underlyingRoot != "" { + if m.isPathAboveRoot(name) { return os.Open(filepath.Join(m.underlyingRoot, name)) } return m.root.Open(cleanPath(name)) @@ -188,7 +188,7 @@ func (m *FS) MkdirAll(path string, perm fs.FileMode) error { // The caller is permitted to modify the returned byte slice. // This method should return a copy of the underlying data. func (m *FS) ReadFile(name string) ([]byte, error) { - if strings.HasPrefix(name, "../") && m.underlyingRoot != "" { + if m.isPathAboveRoot(name) { return os.ReadFile(filepath.Join(m.underlyingRoot, name)) } @@ -245,3 +245,7 @@ func cleanPath(path string) string { path = strings.TrimLeft(path, "/") // Remove the leading slash return path } + +func (m *FS) isPathAboveRoot(name string) bool { + return (name == ".." || strings.HasPrefix(name, "../")) && m.underlyingRoot != "" +} diff --git a/pkg/mapfs/fs_test.go b/pkg/mapfs/fs_test.go index 22b659d7f387..d00d5626a9a9 100644 --- a/pkg/mapfs/fs_test.go +++ b/pkg/mapfs/fs_test.go @@ -478,3 +478,26 @@ func TestFS_RemoveAll(t *testing.T) { require.ErrorIs(t, err, fs.ErrNotExist) }) } + +func TestFS_WithUnderlyingRoot(t *testing.T) { + root := "testdata/subdir" + fsys := mapfs.New(mapfs.WithUnderlyingRoot(root)) + require.NoError(t, fsys.WriteFile("foo.txt", root+"/foo.txt")) + require.NoError(t, fsys.WriteFile("..foo.txt", root+"/..foo.txt")) + + fi, err := fsys.Stat("..") + require.NoError(t, err) + assert.True(t, fi.IsDir()) + + fi, err = fsys.Stat("../hello.txt") + require.NoError(t, err) + assert.False(t, fi.IsDir()) + + fi, err = fsys.Stat("foo.txt") + require.NoError(t, err) + assert.False(t, fi.IsDir()) + + fi, err = fsys.Stat("..foo.txt") + require.NoError(t, err) + assert.False(t, fi.IsDir()) +} diff --git a/pkg/mapfs/testdata/subdir/..foo.txt b/pkg/mapfs/testdata/subdir/..foo.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/pkg/mapfs/testdata/subdir/foo.txt b/pkg/mapfs/testdata/subdir/foo.txt new file mode 100644 index 000000000000..e69de29bb2d1 From 9baf6589354cee490686ae636570dcaecf17ad6c Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Fri, 27 Sep 2024 14:32:46 +0400 Subject: [PATCH 102/183] test: use a local registry for remote scanning (#7607) Signed-off-by: knqyf263 --- integration/registry_test.go | 64 ++- .../testdata/alpine-310-registry.json.golden | 374 ------------------ pkg/fanal/test/integration/library_test.go | 48 --- 3 files changed, 47 insertions(+), 439 deletions(-) delete mode 100644 integration/testdata/alpine-310-registry.json.golden diff --git a/integration/registry_test.go b/integration/registry_test.go index 9a2570062e56..3831ea9a280e 100644 --- a/integration/registry_test.go +++ b/integration/registry_test.go @@ -10,7 +10,6 @@ import ( "crypto/x509" "encoding/json" "fmt" - "github.com/aquasecurity/trivy/pkg/types" "io" "net/http" "net/url" @@ -18,6 +17,8 @@ import ( "path/filepath" "testing" + "github.com/aquasecurity/trivy/pkg/types" + dockercontainer "github.com/docker/docker/api/types/container" "github.com/docker/go-connections/nat" "github.com/google/go-containerregistry/pkg/authn" @@ -152,32 +153,59 @@ func TestRegistry(t *testing.T) { name string imageName string imageFile string + os string option registryOption golden string wantErr string }{ { - name: "happy path with username/password", + name: "authenticate with username/password", imageName: "alpine:3.10", imageFile: "testdata/fixtures/images/alpine-310.tar.gz", + os: "alpine 3.10.2", option: registryOption{ AuthURL: authURL, Username: authUsername, Password: authPassword, }, - golden: "testdata/alpine-310-registry.json.golden", + golden: "testdata/alpine-310.json.golden", }, { - name: "happy path with registry token", + name: "authenticate with registry token", imageName: "alpine:3.10", imageFile: "testdata/fixtures/images/alpine-310.tar.gz", + os: "alpine 3.10.2", option: registryOption{ AuthURL: authURL, Username: authUsername, Password: authPassword, RegistryToken: true, }, - golden: "testdata/alpine-310-registry.json.golden", + golden: "testdata/alpine-310.json.golden", + }, + { + name: "amazonlinux 2", + imageName: "amazonlinux:2", + imageFile: "testdata/fixtures/images/amazon-2.tar.gz", + os: "amazon 2 (Karoo)", + option: registryOption{ + AuthURL: authURL, + Username: authUsername, + Password: authPassword, + }, + golden: "testdata/amazon-2.json.golden", + }, + { + name: "debian buster", + imageName: "debian:buster", + imageFile: "testdata/fixtures/images/debian-buster.tar.gz", + os: "debian 10.1", + option: registryOption{ + AuthURL: authURL, + Username: authUsername, + Password: authPassword, + }, + golden: "testdata/debian-buster.json.golden", }, { name: "sad path", @@ -187,25 +215,25 @@ func TestRegistry(t *testing.T) { }, } - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - s := fmt.Sprintf("%s/%s", registryURL.Host, tc.imageName) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + s := fmt.Sprintf("%s/%s", registryURL.Host, tt.imageName) imageRef, err := name.ParseReference(s) require.NoError(t, err) // Load a test image from the tar file, tag it and push to the test registry. - err = replicateImage(imageRef, tc.imageFile, auth) + err = replicateImage(imageRef, tt.imageFile, auth) require.NoError(t, err) - osArgs, err := scan(t, imageRef, baseDir, tc.golden, tc.option) + osArgs, err := scan(t, imageRef, baseDir, tt.option) // Run Trivy - runTest(t, osArgs, tc.golden, "", types.FormatJSON, runOptions{ - wantErr: tc.wantErr, - override: overrideFuncs(overrideUID, func(t *testing.T, _, got *types.Report) { - got.ArtifactName = tc.imageName - for i := range got.Results { - got.Results[i].Target = fmt.Sprintf("%s (alpine 3.10.2)", tc.imageName) + runTest(t, osArgs, tt.golden, "", types.FormatJSON, runOptions{ + wantErr: tt.wantErr, + override: overrideFuncs(overrideUID, func(t *testing.T, want, got *types.Report) { + want.ArtifactName = s + for i := range want.Results { + want.Results[i].Target = fmt.Sprintf("%s (%s)", s, tt.os) } }), }) @@ -213,7 +241,7 @@ func TestRegistry(t *testing.T) { } } -func scan(t *testing.T, imageRef name.Reference, baseDir, goldenFile string, opt registryOption) ([]string, error) { +func scan(t *testing.T, imageRef name.Reference, baseDir string, opt registryOption) ([]string, error) { // Set up testing DB cacheDir := initDB(t) @@ -232,6 +260,8 @@ func scan(t *testing.T, imageRef name.Reference, baseDir, goldenFile string, opt "image", "--format", "json", + "--image-src", + "remote", "--skip-update", imageRef.Name(), } diff --git a/integration/testdata/alpine-310-registry.json.golden b/integration/testdata/alpine-310-registry.json.golden deleted file mode 100644 index 51100d633f53..000000000000 --- a/integration/testdata/alpine-310-registry.json.golden +++ /dev/null @@ -1,374 +0,0 @@ -{ - "SchemaVersion": 2, - "CreatedAt": "2021-08-25T12:20:30.000000005Z", - "ArtifactName": "alpine:3.10", - "ArtifactType": "container_image", - "Metadata": { - "OS": { - "Family": "alpine", - "Name": "3.10.2", - "EOSL": true - }, - "ImageID": "sha256:961769676411f082461f9ef46626dd7a2d1e2b2a38e6a44364bcbecf51e66dd4", - "DiffIDs": [ - "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0" - ], - "RepoTags": [ - "alpine:3.10" - ], - "RepoDigests": [ - "alpine@sha256:b1c5a500182b21d0bfa5a584a8526b56d8be316f89e87d951be04abed2446e60" - ], - "ImageConfig": { - "architecture": "amd64", - "container": "0a80155a31551fcc1a36fccbbda79fcd3f0b1c7d270653d00310e6e2217c57e6", - "created": "2019-08-20T20:19:55.211423266Z", - "docker_version": "18.06.1-ce", - "history": [ - { - "created": "2019-08-20T20:19:55.062606894Z", - "created_by": "/bin/sh -c #(nop) ADD file:fe64057fbb83dccb960efabbf1cd8777920ef279a7fa8dbca0a8801c651bdf7c in / " - }, - { - "created": "2019-08-20T20:19:55.211423266Z", - "created_by": "/bin/sh -c #(nop) CMD [\"/bin/sh\"]", - "empty_layer": true - } - ], - "os": "linux", - "rootfs": { - "type": "layers", - "diff_ids": [ - "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0" - ] - }, - "config": { - "Cmd": [ - "/bin/sh" - ], - "Env": [ - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - ], - "Image": "sha256:06f4121dff4d0123ce11bd2e44f48da9ba9ddcd23ae376ea1f363f63ea0849b5", - "ArgsEscaped": true - } - } - }, - "Results": [ - { - "Target": "alpine:3.10 (alpine 3.10.2)", - "Class": "os-pkgs", - "Type": "alpine", - "Vulnerabilities": [ - { - "VulnerabilityID": "CVE-2019-1549", - "PkgID": "libcrypto1.1@1.1.1c-r0", - "PkgName": "libcrypto1.1", - "PkgIdentifier": { - "PURL": "pkg:apk/alpine/libcrypto1.1@1.1.1c-r0?arch=x86_64\u0026distro=3.10.2" - }, - "InstalledVersion": "1.1.1c-r0", - "FixedVersion": "1.1.1d-r0", - "Status": "fixed", - "Layer": { - "Digest": "sha256:9d48c3bd43c520dc2784e868a780e976b207cbf493eaff8c6596eb871cbd9609", - "DiffID": "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0" - }, - "SeveritySource": "nvd", - "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2019-1549", - "DataSource": { - "ID": "alpine", - "Name": "Alpine Secdb", - "URL": "https://secdb.alpinelinux.org/" - }, - "Title": "openssl: information disclosure in fork()", - "Description": "OpenSSL 1.1.1 introduced a rewritten random number generator (RNG). This was intended to include protection in the event of a fork() system call in order to ensure that the parent and child processes did not share the same RNG state. However this protection was not being used in the default case. A partial mitigation for this issue is that the output from a high precision timer is mixed into the RNG state so the likelihood of a parent and child process sharing state is significantly reduced. If an application already calls OPENSSL_init_crypto() explicitly using OPENSSL_INIT_ATFORK then this problem does not occur at all. Fixed in OpenSSL 1.1.1d (Affected 1.1.1-1.1.1c).", - "Severity": "MEDIUM", - "CweIDs": [ - "CWE-330" - ], - "VendorSeverity": { - "amazon": 2, - "nvd": 2, - "oracle-oval": 2, - "photon": 2, - "redhat": 1, - "ubuntu": 1 - }, - "CVSS": { - "nvd": { - "V2Vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N", - "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", - "V2Score": 5, - "V3Score": 5.3 - }, - "redhat": { - "V3Vector": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", - "V3Score": 4.8 - } - }, - "References": [ - "https://access.redhat.com/security/cve/CVE-2019-1549", - "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1549", - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=1b0fe00e2704b5e20334a16d3c9099d1ba2ef1be", - "https://linux.oracle.com/cve/CVE-2019-1549.html", - "https://linux.oracle.com/errata/ELSA-2020-1840.html", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GY6SNRJP2S7Y42GIIDO3HXPNMDYN2U3A/", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/ZN4VVQJ3JDCHGIHV4Y2YTXBYQZ6PWQ7E/", - "https://seclists.org/bugtraq/2019/Oct/1", - "https://security.netapp.com/advisory/ntap-20190919-0002/", - "https://support.f5.com/csp/article/K44070243", - "https://support.f5.com/csp/article/K44070243?utm_source=f5support\u0026amp;utm_medium=RSS", - "https://ubuntu.com/security/notices/USN-4376-1", - "https://usn.ubuntu.com/4376-1/", - "https://www.debian.org/security/2019/dsa-4539", - "https://www.openssl.org/news/secadv/20190910.txt", - "https://www.oracle.com/security-alerts/cpuapr2020.html", - "https://www.oracle.com/security-alerts/cpujan2020.html", - "https://www.oracle.com/security-alerts/cpujul2020.html", - "https://www.oracle.com/security-alerts/cpuoct2020.html", - "https://www.oracle.com/technetwork/security-advisory/cpuoct2019-5072832.html" - ], - "PublishedDate": "2019-09-10T17:15:00Z", - "LastModifiedDate": "2020-10-20T22:15:00Z" - }, - { - "VulnerabilityID": "CVE-2019-1551", - "PkgID": "libcrypto1.1@1.1.1c-r0", - "PkgName": "libcrypto1.1", - "PkgIdentifier": { - "PURL": "pkg:apk/alpine/libcrypto1.1@1.1.1c-r0?arch=x86_64\u0026distro=3.10.2" - }, - "InstalledVersion": "1.1.1c-r0", - "FixedVersion": "1.1.1d-r2", - "Status": "fixed", - "Layer": { - "Digest": "sha256:9d48c3bd43c520dc2784e868a780e976b207cbf493eaff8c6596eb871cbd9609", - "DiffID": "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0" - }, - "SeveritySource": "nvd", - "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2019-1551", - "DataSource": { - "ID": "alpine", - "Name": "Alpine Secdb", - "URL": "https://secdb.alpinelinux.org/" - }, - "Title": "openssl: Integer overflow in RSAZ modular exponentiation on x86_64", - "Description": "There is an overflow bug in the x64_64 Montgomery squaring procedure used in exponentiation with 512-bit moduli. No EC algorithms are affected. Analysis suggests that attacks against 2-prime RSA1024, 3-prime RSA1536, and DSA1024 as a result of this defect would be very difficult to perform and are not believed likely. Attacks against DH512 are considered just feasible. However, for an attack the target would have to re-use the DH512 private key, which is not recommended anyway. Also applications directly using the low level API BN_mod_exp may be affected if they use BN_FLG_CONSTTIME. Fixed in OpenSSL 1.1.1e (Affected 1.1.1-1.1.1d). Fixed in OpenSSL 1.0.2u (Affected 1.0.2-1.0.2t).", - "Severity": "MEDIUM", - "CweIDs": [ - "CWE-200" - ], - "VendorSeverity": { - "amazon": 1, - "nvd": 2, - "oracle-oval": 1, - "photon": 2, - "redhat": 1, - "ubuntu": 1 - }, - "CVSS": { - "nvd": { - "V2Vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N", - "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", - "V2Score": 5, - "V3Score": 5.3 - }, - "redhat": { - "V3Vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", - "V3Score": 4.8 - } - }, - "References": [ - "http://lists.opensuse.org/opensuse-security-announce/2020-01/msg00030.html", - "http://packetstormsecurity.com/files/155754/Slackware-Security-Advisory-openssl-Updates.html", - "https://access.redhat.com/security/cve/CVE-2019-1551", - "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1551", - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=419102400a2811582a7a3d4a4e317d72e5ce0a8f", - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=f1c5eea8a817075d31e43f5876993c6710238c98", - "https://github.com/openssl/openssl/pull/10575", - "https://linux.oracle.com/cve/CVE-2019-1551.html", - "https://linux.oracle.com/errata/ELSA-2020-4514.html", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/DDHOAATPWJCXRNFMJ2SASDBBNU5RJONY/", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/EXDDAOWSAIEFQNBHWYE6PPYFV4QXGMCD/", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/XVEP3LAK4JSPRXFO4QF4GG2IVXADV3SO/", - "https://seclists.org/bugtraq/2019/Dec/39", - "https://seclists.org/bugtraq/2019/Dec/46", - "https://security.gentoo.org/glsa/202004-10", - "https://security.netapp.com/advisory/ntap-20191210-0001/", - "https://ubuntu.com/security/notices/USN-4376-1", - "https://ubuntu.com/security/notices/USN-4504-1", - "https://usn.ubuntu.com/4376-1/", - "https://usn.ubuntu.com/4504-1/", - "https://www.debian.org/security/2019/dsa-4594", - "https://www.debian.org/security/2021/dsa-4855", - "https://www.openssl.org/news/secadv/20191206.txt", - "https://www.oracle.com/security-alerts/cpuApr2021.html", - "https://www.oracle.com/security-alerts/cpujan2021.html", - "https://www.oracle.com/security-alerts/cpujul2020.html", - "https://www.tenable.com/security/tns-2019-09", - "https://www.tenable.com/security/tns-2020-03", - "https://www.tenable.com/security/tns-2020-11", - "https://www.tenable.com/security/tns-2021-10" - ], - "PublishedDate": "2019-12-06T18:15:00Z", - "LastModifiedDate": "2021-07-21T11:39:00Z" - }, - { - "VulnerabilityID": "CVE-2019-1549", - "PkgID": "libssl1.1@1.1.1c-r0", - "PkgName": "libssl1.1", - "PkgIdentifier": { - "PURL": "pkg:apk/alpine/libssl1.1@1.1.1c-r0?arch=x86_64\u0026distro=3.10.2" - }, - "InstalledVersion": "1.1.1c-r0", - "FixedVersion": "1.1.1d-r0", - "Status": "fixed", - "Layer": { - "Digest": "sha256:9d48c3bd43c520dc2784e868a780e976b207cbf493eaff8c6596eb871cbd9609", - "DiffID": "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0" - }, - "SeveritySource": "nvd", - "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2019-1549", - "DataSource": { - "ID": "alpine", - "Name": "Alpine Secdb", - "URL": "https://secdb.alpinelinux.org/" - }, - "Title": "openssl: information disclosure in fork()", - "Description": "OpenSSL 1.1.1 introduced a rewritten random number generator (RNG). This was intended to include protection in the event of a fork() system call in order to ensure that the parent and child processes did not share the same RNG state. However this protection was not being used in the default case. A partial mitigation for this issue is that the output from a high precision timer is mixed into the RNG state so the likelihood of a parent and child process sharing state is significantly reduced. If an application already calls OPENSSL_init_crypto() explicitly using OPENSSL_INIT_ATFORK then this problem does not occur at all. Fixed in OpenSSL 1.1.1d (Affected 1.1.1-1.1.1c).", - "Severity": "MEDIUM", - "CweIDs": [ - "CWE-330" - ], - "VendorSeverity": { - "amazon": 2, - "nvd": 2, - "oracle-oval": 2, - "photon": 2, - "redhat": 1, - "ubuntu": 1 - }, - "CVSS": { - "nvd": { - "V2Vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N", - "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", - "V2Score": 5, - "V3Score": 5.3 - }, - "redhat": { - "V3Vector": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", - "V3Score": 4.8 - } - }, - "References": [ - "https://access.redhat.com/security/cve/CVE-2019-1549", - "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1549", - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=1b0fe00e2704b5e20334a16d3c9099d1ba2ef1be", - "https://linux.oracle.com/cve/CVE-2019-1549.html", - "https://linux.oracle.com/errata/ELSA-2020-1840.html", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/GY6SNRJP2S7Y42GIIDO3HXPNMDYN2U3A/", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/ZN4VVQJ3JDCHGIHV4Y2YTXBYQZ6PWQ7E/", - "https://seclists.org/bugtraq/2019/Oct/1", - "https://security.netapp.com/advisory/ntap-20190919-0002/", - "https://support.f5.com/csp/article/K44070243", - "https://support.f5.com/csp/article/K44070243?utm_source=f5support\u0026amp;utm_medium=RSS", - "https://ubuntu.com/security/notices/USN-4376-1", - "https://usn.ubuntu.com/4376-1/", - "https://www.debian.org/security/2019/dsa-4539", - "https://www.openssl.org/news/secadv/20190910.txt", - "https://www.oracle.com/security-alerts/cpuapr2020.html", - "https://www.oracle.com/security-alerts/cpujan2020.html", - "https://www.oracle.com/security-alerts/cpujul2020.html", - "https://www.oracle.com/security-alerts/cpuoct2020.html", - "https://www.oracle.com/technetwork/security-advisory/cpuoct2019-5072832.html" - ], - "PublishedDate": "2019-09-10T17:15:00Z", - "LastModifiedDate": "2020-10-20T22:15:00Z" - }, - { - "VulnerabilityID": "CVE-2019-1551", - "PkgID": "libssl1.1@1.1.1c-r0", - "PkgName": "libssl1.1", - "PkgIdentifier": { - "PURL": "pkg:apk/alpine/libssl1.1@1.1.1c-r0?arch=x86_64\u0026distro=3.10.2" - }, - "InstalledVersion": "1.1.1c-r0", - "FixedVersion": "1.1.1d-r2", - "Status": "fixed", - "Layer": { - "Digest": "sha256:9d48c3bd43c520dc2784e868a780e976b207cbf493eaff8c6596eb871cbd9609", - "DiffID": "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0" - }, - "SeveritySource": "nvd", - "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2019-1551", - "DataSource": { - "ID": "alpine", - "Name": "Alpine Secdb", - "URL": "https://secdb.alpinelinux.org/" - }, - "Title": "openssl: Integer overflow in RSAZ modular exponentiation on x86_64", - "Description": "There is an overflow bug in the x64_64 Montgomery squaring procedure used in exponentiation with 512-bit moduli. No EC algorithms are affected. Analysis suggests that attacks against 2-prime RSA1024, 3-prime RSA1536, and DSA1024 as a result of this defect would be very difficult to perform and are not believed likely. Attacks against DH512 are considered just feasible. However, for an attack the target would have to re-use the DH512 private key, which is not recommended anyway. Also applications directly using the low level API BN_mod_exp may be affected if they use BN_FLG_CONSTTIME. Fixed in OpenSSL 1.1.1e (Affected 1.1.1-1.1.1d). Fixed in OpenSSL 1.0.2u (Affected 1.0.2-1.0.2t).", - "Severity": "MEDIUM", - "CweIDs": [ - "CWE-200" - ], - "VendorSeverity": { - "amazon": 1, - "nvd": 2, - "oracle-oval": 1, - "photon": 2, - "redhat": 1, - "ubuntu": 1 - }, - "CVSS": { - "nvd": { - "V2Vector": "AV:N/AC:L/Au:N/C:P/I:N/A:N", - "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N", - "V2Score": 5, - "V3Score": 5.3 - }, - "redhat": { - "V3Vector": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:N", - "V3Score": 4.8 - } - }, - "References": [ - "http://lists.opensuse.org/opensuse-security-announce/2020-01/msg00030.html", - "http://packetstormsecurity.com/files/155754/Slackware-Security-Advisory-openssl-Updates.html", - "https://access.redhat.com/security/cve/CVE-2019-1551", - "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1551", - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=419102400a2811582a7a3d4a4e317d72e5ce0a8f", - "https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff;h=f1c5eea8a817075d31e43f5876993c6710238c98", - "https://github.com/openssl/openssl/pull/10575", - "https://linux.oracle.com/cve/CVE-2019-1551.html", - "https://linux.oracle.com/errata/ELSA-2020-4514.html", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/DDHOAATPWJCXRNFMJ2SASDBBNU5RJONY/", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/EXDDAOWSAIEFQNBHWYE6PPYFV4QXGMCD/", - "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/XVEP3LAK4JSPRXFO4QF4GG2IVXADV3SO/", - "https://seclists.org/bugtraq/2019/Dec/39", - "https://seclists.org/bugtraq/2019/Dec/46", - "https://security.gentoo.org/glsa/202004-10", - "https://security.netapp.com/advisory/ntap-20191210-0001/", - "https://ubuntu.com/security/notices/USN-4376-1", - "https://ubuntu.com/security/notices/USN-4504-1", - "https://usn.ubuntu.com/4376-1/", - "https://usn.ubuntu.com/4504-1/", - "https://www.debian.org/security/2019/dsa-4594", - "https://www.debian.org/security/2021/dsa-4855", - "https://www.openssl.org/news/secadv/20191206.txt", - "https://www.oracle.com/security-alerts/cpuApr2021.html", - "https://www.oracle.com/security-alerts/cpujan2021.html", - "https://www.oracle.com/security-alerts/cpujul2020.html", - "https://www.tenable.com/security/tns-2019-09", - "https://www.tenable.com/security/tns-2020-03", - "https://www.tenable.com/security/tns-2020-11", - "https://www.tenable.com/security/tns-2021-10" - ], - "PublishedDate": "2019-12-06T18:15:00Z", - "LastModifiedDate": "2021-07-21T11:39:00Z" - } - ] - } - ] -} diff --git a/pkg/fanal/test/integration/library_test.go b/pkg/fanal/test/integration/library_test.go index cf7ed95a1679..ea76c7965b3a 100644 --- a/pkg/fanal/test/integration/library_test.go +++ b/pkg/fanal/test/integration/library_test.go @@ -139,54 +139,6 @@ var tests = []testCase{ }, } -func TestFanal_Library_DockerLessMode(t *testing.T) { - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - t.Parallel() - ctx := context.Background() - d := t.TempDir() - - c, err := cache.NewFSCache(d) - require.NoError(t, err, tt.name) - - cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) - require.NoError(t, err) - - // remove existing Image if any - _, _ = cli.ImageRemove(ctx, tt.remoteImageName, dimage.RemoveOptions{ - Force: true, - PruneChildren: true, - }) - - // Enable only registry scanning - img, cleanup, err := image.NewContainerImage(ctx, tt.remoteImageName, types.ImageOptions{ - ImageSources: types.ImageSources{types.RemoteImageSource}, - }) - require.NoError(t, err) - defer cleanup() - - // don't scan licenses in the test - in parallel it will fail - ar, err := aimage.NewArtifact(img, c, artifact.Option{ - DisabledAnalyzers: []analyzer.Type{ - analyzer.TypeExecutable, - analyzer.TypeLicenseFile, - }, - }) - require.NoError(t, err) - - applier := applier.NewApplier(c) - - // run tests twice, one without cache and with cache - for i := 1; i <= 2; i++ { - runChecks(t, ctx, ar, applier, tt) - } - - // clear Cache - require.NoError(t, c.Clear()) - }) - } -} - func TestFanal_Library_DockerMode(t *testing.T) { // Disable updating golden files because local images don't have compressed layer digests, // and updating golden files in this function results in incomplete files. From ea0cf0379aff0348fde87356dab37947800fc1b6 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Sat, 28 Sep 2024 11:06:02 +0600 Subject: [PATCH 103/183] fix(misconf): escape all special sequences (#7558) Signed-off-by: nikpivkin --- pkg/iac/terraform/resource_block.go | 40 +++++++++++---- pkg/iac/terraform/resource_block_test.go | 62 ++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 10 deletions(-) create mode 100644 pkg/iac/terraform/resource_block_test.go diff --git a/pkg/iac/terraform/resource_block.go b/pkg/iac/terraform/resource_block.go index 339843423112..abce0fcb040e 100644 --- a/pkg/iac/terraform/resource_block.go +++ b/pkg/iac/terraform/resource_block.go @@ -3,7 +3,6 @@ package terraform import ( "bytes" "fmt" - "regexp" "strings" "text/template" ) @@ -106,19 +105,14 @@ func renderPrimitive(val any) string { func parseStringPrimitive(input string) string { // we must escape templating // ref: https://developer.hashicorp.com/terraform/language/expressions/strings#escape-sequences-1 - r := regexp.MustCompile(`((\$|\%)\{.+\})`) - ff := r.ReplaceAllStringFunc(input, func(s string) string { - s = strings.Replace(s, "$", "$$", 1) - s = strings.Replace(s, "%", "%%", 1) - return s - }) - if strings.Contains(ff, "\n") { + input = escapeSpecialSequences(input) + if strings.Contains(input, "\n") { return fmt.Sprintf(`< 0 && rune(input[i-1]) == r { + continue + } + + sb.WriteRune(r) + } else { + sb.WriteRune(r) + } + } + return sb.String() +} diff --git a/pkg/iac/terraform/resource_block_test.go b/pkg/iac/terraform/resource_block_test.go new file mode 100644 index 000000000000..37fb1d32fdcb --- /dev/null +++ b/pkg/iac/terraform/resource_block_test.go @@ -0,0 +1,62 @@ +package terraform + +import ( + "testing" + + "github.com/hashicorp/hcl/v2" + "github.com/hashicorp/hcl/v2/hclsyntax" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func Test_EscapeSpecialSequences(t *testing.T) { + tests := []struct { + name string + inp string + expected string + }{ + { + name: "without special sequences", + inp: `"hello world\\"`, + expected: `"hello world\\"`, + }, + { + name: "interpolation", + inp: `"Hello, ${var.name}!"`, + expected: `"Hello, $${var.name}!"`, + }, + { + name: "directive", + inp: `"Hello, %{ if true }foo%{ else }bar%{ endif }!"`, + expected: `"Hello, %%{ if true }foo%%{ else }bar%%{ endif }!"`, + }, + { + name: "interpolation already escaped", + inp: `"Hello, $${var.name}!"`, + expected: `"Hello, $${var.name}!"`, + }, + { + name: "start with special character", + inp: `${var.name}!"`, + expected: `$${var.name}!"`, + }, + { + name: "grok pattern", + inp: "# Grok Pattern Template\ngrok_pattern = \"%{TIMESTAMP_ISO8601:time} \\\\[%{NUMBER:pid}\\\\] %{GREEDYDATA:message}\"", + expected: "# Grok Pattern Template\ngrok_pattern = \"%%{TIMESTAMP_ISO8601:time} \\\\[%%{NUMBER:pid}\\\\] %%{GREEDYDATA:message}\"", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := escapeSpecialSequences(tt.inp) + assert.Equal(t, tt.expected, got) + + // We make sure that the characters are properly escaped + _, diag := hclsyntax.ParseTemplate([]byte(got), "", hcl.InitialPos) + if diag.HasErrors() { + require.NoError(t, diag) + } + }) + } +} From ef0a27d515ff80762bf1959d44a8bde017ae06ec Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Sat, 28 Sep 2024 12:31:53 +0600 Subject: [PATCH 104/183] feat(misconf): add ability to disable checks by ID (#7536) Signed-off-by: nikpivkin Co-authored-by: Simar --- pkg/iac/rego/load.go | 6 +++ pkg/iac/rego/options.go | 11 +++++ pkg/iac/rego/scanner.go | 15 ++++--- pkg/iac/rego/scanner_test.go | 84 ++++++++++++++++++++++++++++++++++++ 4 files changed, 110 insertions(+), 6 deletions(-) diff --git a/pkg/iac/rego/load.go b/pkg/iac/rego/load.go index a1c29d163fae..8f1033ecfa2d 100644 --- a/pkg/iac/rego/load.go +++ b/pkg/iac/rego/load.go @@ -295,6 +295,12 @@ func (s *Scanner) filterModules(retriever *MetadataRetriever) error { continue } + if IsBuiltinNamespace(getModuleNamespace(module)) { + if _, disabled := s.disabledCheckIDs[meta.ID]; disabled { // ignore builtin disabled checks + continue + } + } + if len(meta.InputOptions.Selectors) == 0 { s.logger.Warn( "Module has no input selectors - it will be loaded for all inputs!", diff --git a/pkg/iac/rego/options.go b/pkg/iac/rego/options.go index d4b622a68c16..5cc60284abdb 100644 --- a/pkg/iac/rego/options.go +++ b/pkg/iac/rego/options.go @@ -106,3 +106,14 @@ func WithCustomSchemas(schemas map[string][]byte) options.ScannerOption { } } } + +// WithDisabledCheckIDs disables checks by their ID (ID field in metadata) +func WithDisabledCheckIDs(ids ...string) options.ScannerOption { + return func(s options.ConfigurableScanner) { + if ss, ok := s.(*Scanner); ok { + for _, id := range ids { + ss.disabledCheckIDs[id] = struct{}{} + } + } + } +} diff --git a/pkg/iac/rego/scanner.go b/pkg/iac/rego/scanner.go index a8e1caf525b3..9cf80fc83da0 100644 --- a/pkg/iac/rego/scanner.go +++ b/pkg/iac/rego/scanner.go @@ -69,6 +69,8 @@ type Scanner struct { embeddedLibs map[string]*ast.Module embeddedChecks map[string]*ast.Module customSchemas map[string][]byte + + disabledCheckIDs map[string]struct{} } func (s *Scanner) SetIncludeDeprecatedChecks(b bool) { @@ -109,12 +111,13 @@ func NewScanner(source types.Source, opts ...options.ScannerOption) *Scanner { } s := &Scanner{ - regoErrorLimit: ast.CompileErrorLimitDefault, - sourceType: source, - ruleNamespaces: make(map[string]struct{}), - runtimeValues: addRuntimeValues(), - logger: log.WithPrefix("rego"), - customSchemas: make(map[string][]byte), + regoErrorLimit: ast.CompileErrorLimitDefault, + sourceType: source, + ruleNamespaces: make(map[string]struct{}), + runtimeValues: addRuntimeValues(), + logger: log.WithPrefix("rego"), + customSchemas: make(map[string][]byte), + disabledCheckIDs: make(map[string]struct{}), } maps.Copy(s.ruleNamespaces, builtinNamespaces) diff --git a/pkg/iac/rego/scanner_test.go b/pkg/iac/rego/scanner_test.go index 73ef55223f14..1310e56d2ec4 100644 --- a/pkg/iac/rego/scanner_test.go +++ b/pkg/iac/rego/scanner_test.go @@ -1153,3 +1153,87 @@ deny { }) } } + +func Test_RegoScanner_WithDisabledCheckIDs(t *testing.T) { + + check := `# METADATA +# custom: +# id: TEST-001 +# avd_id: AVD-TEST-001 +# severity: LOW +# provider: aws +# service: s3 +# short_code: test +package builtin.test + +deny { + true +} +` + + tests := []struct { + name string + disabledChecks []string + inputCheck string + expected bool + }{ + { + name: "no disabled checks", + expected: true, + inputCheck: check, + }, + { + name: "disable check by ID", + disabledChecks: []string{"TEST-001"}, + inputCheck: check, + }, + { + name: "disabling a non-existent check", + disabledChecks: []string{"FOO"}, + expected: true, + inputCheck: check, + }, + { + name: "one of the identifiers does not exist", + disabledChecks: []string{"FOO", "TEST-001"}, + inputCheck: check, + }, + { + name: "do not disable user checks with builtin IDs", + inputCheck: `# METADATA +# custom: +# id: TEST-001 +# avd_id: AVD-TEST-001 +# severity: LOW +# provider: aws +# service: s3 +# short_code: test +package user.test + +deny { + true +} +`, + disabledChecks: []string{"TEST-001"}, + expected: true, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + + scanner := rego.NewScanner( + types.SourceYAML, + rego.WithPolicyReader(strings.NewReader(tt.inputCheck)), + rego.WithDisabledCheckIDs(tt.disabledChecks...), + rego.WithPolicyNamespaces("user"), + ) + + require.NoError(t, scanner.LoadPolicies(nil)) + results, err := scanner.ScanInput(context.TODO(), rego.Input{}) + require.NoError(t, err) + + require.Equal(t, tt.expected, len(results.GetFailed()) > 0) + }) + } +} From efdb68d3b9ddf9dfaf45ea5855b31c43a4366bab Mon Sep 17 00:00:00 2001 From: Marcus Meissner Date: Sun, 29 Sep 2024 20:23:34 +0200 Subject: [PATCH 105/183] feat(suse): added SUSE Linux Enterprise Micro support (#7294) Signed-off-by: Marcus Meissner Signed-off-by: knqyf263 Co-authored-by: knqyf263 --- docs/docs/coverage/os/index.md | 3 +- docs/docs/coverage/os/suse.md | 3 +- integration/client_server_test.go | 7 + integration/docker_engine_test.go | 6 + integration/standalone_tar_test.go | 8 + integration/testdata/fixtures/db/suse.yaml | 19 ++ .../testdata/fixtures/db/vulnerability.yaml | 9 + .../testdata/opensuse-leap-151.json.golden | 4 +- .../testdata/opensuse-tumbleweed.json.golden | 2 +- .../testdata/sl-micro-rancher5.4.json.golden | 69 +++++ pkg/detector/ospkg/detect.go | 1 + pkg/detector/ospkg/suse/suse.go | 21 ++ pkg/detector/ospkg/suse/suse_test.go | 80 ++++++ .../suse/testdata/fixtures/data-source.yaml | 5 + .../ospkg/suse/testdata/fixtures/suse.yaml | 20 ++ pkg/fanal/analyzer/os/release/release.go | 5 + pkg/fanal/analyzer/os/release/release_test.go | 30 +++ .../analyzer/os/release/testdata/slemicro | 8 + .../os/release/testdata/slemicro-rancher | 13 + .../analyzer/os/release/testdata/slemicro6.0 | 10 + .../packages/opensuse-tumbleweed.json.golden | 252 +++++++++--------- pkg/fanal/types/const.go | 1 + pkg/purl/purl.go | 13 +- 23 files changed, 453 insertions(+), 136 deletions(-) create mode 100644 integration/testdata/fixtures/db/suse.yaml create mode 100644 integration/testdata/sl-micro-rancher5.4.json.golden create mode 100644 pkg/fanal/analyzer/os/release/testdata/slemicro create mode 100644 pkg/fanal/analyzer/os/release/testdata/slemicro-rancher create mode 100644 pkg/fanal/analyzer/os/release/testdata/slemicro6.0 diff --git a/docs/docs/coverage/os/index.md b/docs/docs/coverage/os/index.md index a28e113f07c9..a49793db8124 100644 --- a/docs/docs/coverage/os/index.md +++ b/docs/docs/coverage/os/index.md @@ -23,7 +23,8 @@ Trivy supports operating systems for | [Amazon Linux](amazon.md) | 1, 2, 2023 | dnf/yum/rpm | | [openSUSE Leap](suse.md) | 42, 15 | zypper/rpm | | [openSUSE Tumbleweed](suse.md) | (n/a) | zypper/rpm | -| [SUSE Enterprise Linux](suse.md) | 11, 12, 15 | zypper/rpm | +| [SUSE Linux Enterprise](suse.md) | 11, 12, 15 | zypper/rpm | +| [SUSE Linux Enterprise Micro](suse.md)| 5, 6 | zypper/rpm | | [Photon OS](photon.md) | 1.0, 2.0, 3.0, 4.0 | tndf/yum/rpm | | [Debian GNU/Linux](debian.md) | 7, 8, 9, 10, 11, 12 | apt/dpkg | | [Ubuntu](ubuntu.md) | All versions supported by Canonical | apt/dpkg | diff --git a/docs/docs/coverage/os/suse.md b/docs/docs/coverage/os/suse.md index 15cfb1e9379a..b28fed13425b 100644 --- a/docs/docs/coverage/os/suse.md +++ b/docs/docs/coverage/os/suse.md @@ -3,7 +3,8 @@ Trivy supports the following distributions: - openSUSE Leap - openSUSE Tumbleweed -- SUSE Enterprise Linux (SLE) +- SUSE Linux Enterprise (SLE) +- SUSE Linux Enterprise Micro Please see [here](index.md#supported-os) for supported versions. diff --git a/integration/client_server_test.go b/integration/client_server_test.go index adeab3f4c7b3..07a4f086200c 100644 --- a/integration/client_server_test.go +++ b/integration/client_server_test.go @@ -220,6 +220,13 @@ func TestClientServer(t *testing.T) { }, golden: "testdata/opensuse-tumbleweed.json.golden", }, + { + name: "sle micro rancher 5.4", + args: csArgs{ + Input: "testdata/fixtures/images/sle-micro-rancher-5.4_ndb.tar.gz", + }, + golden: "testdata/sl-micro-rancher5.4.json.golden", + }, { name: "photon 3.0", args: csArgs{ diff --git a/integration/docker_engine_test.go b/integration/docker_engine_test.go index 5b62d391eead..7f9a3119a156 100644 --- a/integration/docker_engine_test.go +++ b/integration/docker_engine_test.go @@ -198,6 +198,12 @@ func TestDockerEngine(t *testing.T) { input: "testdata/fixtures/images/opensuse-tumbleweed.tar.gz", golden: "testdata/opensuse-tumbleweed.json.golden", }, + { + name: "sle micro rancher 5.4", + imageTag: "ghcr.io/aquasecurity/trivy-test-images:sle-micro-rancher-5.4_ndb", + input: "testdata/fixtures/images/sle-micro-rancher-5.4_ndb.tar.gz", + golden: "testdata/sl-micro-rancher5.4.json.golden", + }, { name: "photon 3.0", imageTag: "ghcr.io/aquasecurity/trivy-test-images:photon-30", diff --git a/integration/standalone_tar_test.go b/integration/standalone_tar_test.go index dce852cf7f3c..039293cbfd56 100644 --- a/integration/standalone_tar_test.go +++ b/integration/standalone_tar_test.go @@ -341,6 +341,14 @@ func TestTar(t *testing.T) { }, golden: "testdata/opensuse-tumbleweed.json.golden", }, + { + name: "sle micro rancher 5.4", + args: args{ + Format: types.FormatJSON, + Input: "testdata/fixtures/images/sle-micro-rancher-5.4_ndb.tar.gz", + }, + golden: "testdata/sl-micro-rancher5.4.json.golden", + }, { name: "photon 3.0", args: args{ diff --git a/integration/testdata/fixtures/db/suse.yaml b/integration/testdata/fixtures/db/suse.yaml new file mode 100644 index 000000000000..690360c5de13 --- /dev/null +++ b/integration/testdata/fixtures/db/suse.yaml @@ -0,0 +1,19 @@ +- bucket: "SUSE Linux Enterprise 15-SP3" + pairs: + - bucket: libopenssl1_1 + pairs: + - key: "SUSE-SU-2022:2251-1" + value: + FixedVersion: 1.1.1d-150200.11.48.1 + - bucket: openssl-1_1 + pairs: + - key: "SUSE-SU-2022:2251-1" + value: + FixedVersion: 1.1.1d-150200.11.48.1 +- bucket: "SUSE Linux Enterprise Micro 5.3" + pairs: + - bucket: libopenssl1_1 + pairs: + - key: "SUSE-SU-2023:0311-1" + value: + FixedVersion: 1.1.1l-150400.7.22.1 diff --git a/integration/testdata/fixtures/db/vulnerability.yaml b/integration/testdata/fixtures/db/vulnerability.yaml index 6fcdcece75bd..e18d731a30c8 100644 --- a/integration/testdata/fixtures/db/vulnerability.yaml +++ b/integration/testdata/fixtures/db/vulnerability.yaml @@ -1349,6 +1349,15 @@ - "https://www.suse.com/security/cve/CVE-2023-2975/" - "https://www.suse.com/security/cve/CVE-2023-3446/" - "https://www.suse.com/support/security/rating/" + - key: SUSE-SU-2022:2251-1 + value: + Title: "Security update for openssl-1_1" + Description: "This update for openssl-1_1 fixes the following issues:\nCVE-2022-1292: Fixed command injection in c_rehash (bsc#1199166).\nCVE-2022-2068: Fixed more shell code injection issues in c_rehash. (bsc#1200550)" + Severity: MEDIUM + References: + - "https://www.suse.com/security/cve/CVE-2022-1292/" + - "https://www.suse.com/security/cve/CVE-2022-2068/" + - "https://www.suse.com/support/security/rating/" - key: CVE-2022-22965 value: Title: "spring-framework: RCE via Data Binding on JDK 9+" diff --git a/integration/testdata/opensuse-leap-151.json.golden b/integration/testdata/opensuse-leap-151.json.golden index 77b0148604bb..dadc7adcf600 100644 --- a/integration/testdata/opensuse-leap-151.json.golden +++ b/integration/testdata/opensuse-leap-151.json.golden @@ -66,7 +66,7 @@ "PkgID": "libopenssl1_1@1.1.0i-lp151.8.3.1.x86_64", "PkgName": "libopenssl1_1", "PkgIdentifier": { - "PURL": "pkg:rpm/opensuse.leap/libopenssl1_1@1.1.0i-lp151.8.3.1?arch=x86_64\u0026distro=opensuse.leap-15.1", + "PURL": "pkg:rpm/opensuse/libopenssl1_1@1.1.0i-lp151.8.3.1?arch=x86_64\u0026distro=opensuse.leap-15.1", "UID": "898b73ddd0412f57" }, "InstalledVersion": "1.1.0i-lp151.8.3.1", @@ -99,7 +99,7 @@ "PkgID": "openssl-1_1@1.1.0i-lp151.8.3.1.x86_64", "PkgName": "openssl-1_1", "PkgIdentifier": { - "PURL": "pkg:rpm/opensuse.leap/openssl-1_1@1.1.0i-lp151.8.3.1?arch=x86_64\u0026distro=opensuse.leap-15.1", + "PURL": "pkg:rpm/opensuse/openssl-1_1@1.1.0i-lp151.8.3.1?arch=x86_64\u0026distro=opensuse.leap-15.1", "UID": "58980d005de43f54" }, "InstalledVersion": "1.1.0i-lp151.8.3.1", diff --git a/integration/testdata/opensuse-tumbleweed.json.golden b/integration/testdata/opensuse-tumbleweed.json.golden index b3dc552bdfca..a15146616bc2 100644 --- a/integration/testdata/opensuse-tumbleweed.json.golden +++ b/integration/testdata/opensuse-tumbleweed.json.golden @@ -69,7 +69,7 @@ "PkgID": "libopenssl3@3.1.4-9.1.x86_64", "PkgName": "libopenssl3", "PkgIdentifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libopenssl3@3.1.4-9.1?arch=x86_64\u0026distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libopenssl3@3.1.4-9.1?arch=x86_64\u0026distro=opensuse.tumbleweed-20240607", "UID": "f051425f385d2b99" }, "InstalledVersion": "3.1.4-9.1", diff --git a/integration/testdata/sl-micro-rancher5.4.json.golden b/integration/testdata/sl-micro-rancher5.4.json.golden new file mode 100644 index 000000000000..99e2ad4ca599 --- /dev/null +++ b/integration/testdata/sl-micro-rancher5.4.json.golden @@ -0,0 +1,69 @@ +{ + "SchemaVersion": 2, + "CreatedAt": "2021-08-25T12:20:30.000000005Z", + "ArtifactName": "testdata/fixtures/images/sle-micro-rancher-5.4_ndb.tar.gz", + "ArtifactType": "container_image", + "Metadata": { + "OS": { + "Family": "suse linux enterprise micro", + "Name": "5.4" + }, + "ImageID": "sha256:c45ec974938acac29c893b5d273d73e4ebdd7e6a97b6fa861dfbd8dd430b9016", + "DiffIDs": [ + "sha256:7cdd3aec849d122d63dc83a5e1e2fb89b341c67b03e25979131ca335a463bb57" + ], + "ImageConfig": { + "architecture": "amd64", + "author": "SUSE LLC (https://www.suse.com/)", + "created": "2024-09-03T17:54:39Z", + "history": [ + { + "author": "SUSE LLC \u003chttps://www.suse.com/\u003e", + "created": "2024-09-03T17:54:39Z", + "created_by": "KIWI 9.24.43" + } + ], + "os": "linux", + "rootfs": { + "type": "layers", + "diff_ids": [ + "sha256:7cdd3aec849d122d63dc83a5e1e2fb89b341c67b03e25979131ca335a463bb57" + ] + }, + "config": { + "Cmd": [ + "/bin/bash" + ], + "Labels": { + "com.suse.eula": "sle-eula", + "com.suse.image-type": "sle-micro", + "com.suse.release-stage": "released", + "com.suse.sle.micro.rancher.created": "2024-09-03T17:53:32.129328086Z", + "com.suse.sle.micro.rancher.description": "Image containing a micro environment for containers based on the SLE Micro for Rancher.", + "com.suse.sle.micro.rancher.disturl": "obs://build.suse.de/SUSE:SLE-15-SP4:Update:Products:Micro54:Update:CR/images/fcaa3a91b132f1955fa900b902aef7f2-SLE-Micro-Rancher", + "com.suse.sle.micro.rancher.reference": "registry.suse.com/suse/sle-micro-rancher/5.4:%PKG_VERSION%-%RELEASE", + "com.suse.sle.micro.rancher.title": "SLE Micro for Rancher Base Container", + "com.suse.sle.micro.rancher.url": "https://www.suse.com/products/micro/", + "com.suse.sle.micro.rancher.vendor": "SUSE LLC", + "com.suse.sle.micro.rancher.version": "5.4", + "com.suse.supportlevel": "l3", + "org.openbuildservice.disturl": "obs://build.suse.de/SUSE:SLE-15-SP4:Update:Products:Micro54:Update:CR/images/fcaa3a91b132f1955fa900b902aef7f2-SLE-Micro-Rancher", + "org.opencontainers.image.created": "2024-09-03T17:53:32.129328086Z", + "org.opencontainers.image.description": "Image containing a micro environment for containers based on the SLE Micro for Rancher.", + "org.opencontainers.image.title": "SLE Micro for Rancher Base Container", + "org.opencontainers.image.url": "https://www.suse.com/products/micro/", + "org.opencontainers.image.vendor": "SUSE LLC", + "org.opencontainers.image.version": "5.4", + "org.suse.reference": "registry.suse.com/suse/sle-micro-rancher/5.4:%PKG_VERSION%-%RELEASE" + } + } + } + }, + "Results": [ + { + "Target": "testdata/fixtures/images/sle-micro-rancher-5.4_ndb.tar.gz (suse linux enterprise micro 5.4)", + "Class": "os-pkgs", + "Type": "suse linux enterprise micro" + } + ] +} diff --git a/pkg/detector/ospkg/detect.go b/pkg/detector/ospkg/detect.go index 0f4a1df2a9d3..fedc8d31c9c2 100644 --- a/pkg/detector/ospkg/detect.go +++ b/pkg/detector/ospkg/detect.go @@ -44,6 +44,7 @@ var ( ftypes.OpenSUSETumbleweed: suse.NewScanner(suse.OpenSUSETumbleweed), ftypes.OpenSUSELeap: suse.NewScanner(suse.OpenSUSE), ftypes.SLES: suse.NewScanner(suse.SUSEEnterpriseLinux), + ftypes.SLEMicro: suse.NewScanner(suse.SUSEEnterpriseLinuxMicro), ftypes.Photon: photon.NewScanner(), ftypes.Wolfi: wolfi.NewScanner(), ftypes.Chainguard: chainguard.NewScanner(), diff --git a/pkg/detector/ospkg/suse/suse.go b/pkg/detector/ospkg/suse/suse.go index b999e1dafb22..36a26b335a96 100644 --- a/pkg/detector/ospkg/suse/suse.go +++ b/pkg/detector/ospkg/suse/suse.go @@ -44,6 +44,18 @@ var ( // 6 months after SLES 15 SP7 release // "15.7": time.Date(2031, 7, 31, 23, 59, 59, 0, time.UTC), } + slemicroEolDates = map[string]time.Time{ + // Source: https://www.suse.com/lifecycle/ + "5.0": time.Date(2022, 3, 31, 23, 59, 59, 0, time.UTC), + "5.1": time.Date(2025, 10, 31, 23, 59, 59, 0, time.UTC), + "5.2": time.Date(2026, 4, 30, 23, 59, 59, 0, time.UTC), + "5.3": time.Date(2026, 10, 30, 23, 59, 59, 0, time.UTC), + "5.4": time.Date(2027, 4, 30, 23, 59, 59, 0, time.UTC), + "5.5": time.Date(2027, 10, 31, 23, 59, 59, 0, time.UTC), + "6.0": time.Date(2028, 6, 30, 23, 59, 59, 0, time.UTC), + // 6.1 will be released late 2024 + // "6.1": time.Date(2028, 11, 30, 23, 59, 59, 0, time.UTC), + } opensuseEolDates = map[string]time.Time{ // Source: https://en.opensuse.org/Lifetime @@ -66,6 +78,8 @@ type Type int const ( // SUSEEnterpriseLinux is Linux Enterprise version SUSEEnterpriseLinux Type = iota + // SUSE Linux Enterprise Micro is the micro series + SUSEEnterpriseLinuxMicro // OpenSUSE for open versions OpenSUSE OpenSUSETumbleweed @@ -83,6 +97,10 @@ func NewScanner(t Type) *Scanner { return &Scanner{ vs: susecvrf.NewVulnSrc(susecvrf.SUSEEnterpriseLinux), } + case SUSEEnterpriseLinuxMicro: + return &Scanner{ + vs: susecvrf.NewVulnSrc(susecvrf.SUSEEnterpriseLinuxMicro), + } case OpenSUSE: return &Scanner{ vs: susecvrf.NewVulnSrc(susecvrf.OpenSUSE), @@ -135,6 +153,9 @@ func (s *Scanner) IsSupportedVersion(ctx context.Context, osFamily ftypes.OSType if osFamily == ftypes.SLES { return osver.Supported(ctx, slesEolDates, osFamily, osVer) } + if osFamily == ftypes.SLEMicro { + return osver.Supported(ctx, slemicroEolDates, osFamily, osVer) + } // tumbleweed is a rolling release, it has no version and no eol if osFamily == ftypes.OpenSUSETumbleweed { return true diff --git a/pkg/detector/ospkg/suse/suse_test.go b/pkg/detector/ospkg/suse/suse_test.go index 4db052743e82..9d480f18b0ea 100644 --- a/pkg/detector/ospkg/suse/suse_test.go +++ b/pkg/detector/ospkg/suse/suse_test.go @@ -111,6 +111,86 @@ func TestScanner_Detect(t *testing.T) { }, }, }, + { + name: "happy path: suse sle 15sp3", + fixtures: []string{ + "testdata/fixtures/suse.yaml", + "testdata/fixtures/data-source.yaml", + }, + distribution: suse.SUSEEnterpriseLinux, + args: args{ + osVer: "15.3", + pkgs: []ftypes.Package{ + { + Name: "libopenssl1_1", + Version: "1.1.1d", + Release: "150200.11.47.1", + SrcName: "libopenssl1_1", + SrcVersion: "1.1.1d", + SrcRelease: "150200.11.47.1", + Layer: ftypes.Layer{ + DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02", + }, + }, + }, + }, + want: []types.DetectedVulnerability{ + { + PkgName: "libopenssl1_1", + VulnerabilityID: "SUSE-SU-2022:2251-1", + InstalledVersion: "1.1.1d-150200.11.47.1", + FixedVersion: "1.1.1d-150200.11.48.1", + Layer: ftypes.Layer{ + DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02", + }, + DataSource: &dbTypes.DataSource{ + ID: vulnerability.SuseCVRF, + Name: "SUSE CVRF", + URL: "https://ftp.suse.com/pub/projects/security/cvrf/", + }, + }, + }, + }, + { + name: "happy path: suse sle micro 15.3", + fixtures: []string{ + "testdata/fixtures/suse.yaml", + "testdata/fixtures/data-source.yaml", + }, + distribution: suse.SUSEEnterpriseLinuxMicro, + args: args{ + osVer: "5.3", + pkgs: []ftypes.Package{ + { + Name: "libopenssl1_1", + Version: "1.1.1l", + Release: "150400.7.21.1", + SrcName: "libopenssl1_1", + SrcVersion: "1.1.1l", + SrcRelease: "150400.7.21.1", + Layer: ftypes.Layer{ + DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02", + }, + }, + }, + }, + want: []types.DetectedVulnerability{ + { + PkgName: "libopenssl1_1", + VulnerabilityID: "SUSE-SU-2023:0311-1", + InstalledVersion: "1.1.1l-150400.7.21.1", + FixedVersion: "1.1.1l-150400.7.22.1", + Layer: ftypes.Layer{ + DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02", + }, + DataSource: &dbTypes.DataSource{ + ID: vulnerability.SuseCVRF, + Name: "SUSE CVRF", + URL: "https://ftp.suse.com/pub/projects/security/cvrf/", + }, + }, + }, + }, { name: "broken bucket", fixtures: []string{ diff --git a/pkg/detector/ospkg/suse/testdata/fixtures/data-source.yaml b/pkg/detector/ospkg/suse/testdata/fixtures/data-source.yaml index b917b7e19da1..4e9ddde802d5 100644 --- a/pkg/detector/ospkg/suse/testdata/fixtures/data-source.yaml +++ b/pkg/detector/ospkg/suse/testdata/fixtures/data-source.yaml @@ -15,3 +15,8 @@ ID: "suse-cvrf" Name: "SUSE CVRF" URL: "https://ftp.suse.com/pub/projects/security/cvrf/" + - key: SUSE Linux Enterprise Micro 5.3 + value: + ID: "suse-cvrf" + Name: "SUSE CVRF" + URL: "https://ftp.suse.com/pub/projects/security/cvrf/" diff --git a/pkg/detector/ospkg/suse/testdata/fixtures/suse.yaml b/pkg/detector/ospkg/suse/testdata/fixtures/suse.yaml index 6a17594af66c..027e56673d0e 100644 --- a/pkg/detector/ospkg/suse/testdata/fixtures/suse.yaml +++ b/pkg/detector/ospkg/suse/testdata/fixtures/suse.yaml @@ -8,3 +8,23 @@ - key: CVE-2021-0001 value: FixedVersion: "" +- bucket: SUSE Linux Enterprise 15.3 + pairs: + - bucket: libopenssl1_1 + pairs: + - key: "SUSE-SU-2022:2251-1" + value: + FixedVersion: 1.1.1d-150200.11.48.1 + - bucket: openssl-1_1 + pairs: + - key: "SUSE-SU-2022:2251-1" + value: + FixedVersion: 1.1.1d-150200.11.48.1 +- bucket: SUSE Linux Enterprise Micro 5.3 + pairs: + - bucket: libopenssl1_1 + pairs: + - key: "SUSE-SU-2023:0311-1" + value: + FixedVersion: 1.1.1l-150400.7.22.1 + diff --git a/pkg/fanal/analyzer/os/release/release.go b/pkg/fanal/analyzer/os/release/release.go index 8da24644d5f7..67a18714ac1a 100644 --- a/pkg/fanal/analyzer/os/release/release.go +++ b/pkg/fanal/analyzer/os/release/release.go @@ -55,6 +55,11 @@ func (a osReleaseAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInp family = types.OpenSUSELeap case "sles": family = types.SLES + // There are various rebrands of SLE Micro, there is also one brief (and reverted rebrand) + // for SLE Micro 6.0. which was called "SL Micro 6.0" until very short before release + // and there is a "SLE Micro for Rancher" rebrand, which is used by SUSEs K8S based offerings. + case "sle-micro", "sl-micro", "sle-micro-rancher": + family = types.SLEMicro case "photon": family = types.Photon case "wolfi": diff --git a/pkg/fanal/analyzer/os/release/release_test.go b/pkg/fanal/analyzer/os/release/release_test.go index 3b534ad7b14d..532e01d9efef 100644 --- a/pkg/fanal/analyzer/os/release/release_test.go +++ b/pkg/fanal/analyzer/os/release/release_test.go @@ -70,6 +70,36 @@ func Test_osReleaseAnalyzer_Analyze(t *testing.T) { }, }, }, + { + name: "SUSE Linux Enterprise Micro", + inputFile: "testdata/slemicro", + want: &analyzer.AnalysisResult{ + OS: types.OS{ + Family: types.SLEMicro, + Name: "5.3", + }, + }, + }, + { + name: "SUSE Linux Enterprise Micro 6.0", + inputFile: "testdata/slemicro6.0", + want: &analyzer.AnalysisResult{ + OS: types.OS{ + Family: types.SLEMicro, + Name: "6.0", + }, + }, + }, + { + name: "SUSE Linux Enterprise Micro 5.4 for Rancher", + inputFile: "testdata/slemicro-rancher", + want: &analyzer.AnalysisResult{ + OS: types.OS{ + Family: types.SLEMicro, + Name: "5.4", + }, + }, + }, { name: "Photon OS", inputFile: "testdata/photon", diff --git a/pkg/fanal/analyzer/os/release/testdata/slemicro b/pkg/fanal/analyzer/os/release/testdata/slemicro new file mode 100644 index 000000000000..3e3bdaa30de5 --- /dev/null +++ b/pkg/fanal/analyzer/os/release/testdata/slemicro @@ -0,0 +1,8 @@ +NAME="SLE Micro" +VERSION="5.3" +VERSION_ID="5.3" +PRETTY_NAME="SUSE Linux Enterprise Micro 5.3" +ID="sle-micro" +ID_LIKE="suse" +ANSI_COLOR="0;32" +CPE_NAME="cpe:/o:suse:sle-micro:5.3" diff --git a/pkg/fanal/analyzer/os/release/testdata/slemicro-rancher b/pkg/fanal/analyzer/os/release/testdata/slemicro-rancher new file mode 100644 index 000000000000..83ce34662c3d --- /dev/null +++ b/pkg/fanal/analyzer/os/release/testdata/slemicro-rancher @@ -0,0 +1,13 @@ +NAME="SLE Micro" +VERSION="5.4" +VERSION_ID="5.4" +PRETTY_NAME="SUSE Linux Enterprise Micro for Rancher 5.4" +ID="sle-micro-rancher" +ID_LIKE="suse" +ANSI_COLOR="0;32" +CPE_NAME="cpe:/o:suse:sle-micro-rancher:5.4" +IMAGE_REPO="registry.suse.com/rancher/elemental-teal/5.4" +IMAGE_TAG="1.2.3-3.2.153" +IMAGE="registry.suse.com/rancher/elemental-teal/5.4:1.2.3-3.2.153" +TIMESTAMP=20240419051540 +GRUB_ENTRY_NAME="Elemental" diff --git a/pkg/fanal/analyzer/os/release/testdata/slemicro6.0 b/pkg/fanal/analyzer/os/release/testdata/slemicro6.0 new file mode 100644 index 000000000000..a18632b128a6 --- /dev/null +++ b/pkg/fanal/analyzer/os/release/testdata/slemicro6.0 @@ -0,0 +1,10 @@ +NAME="SL-Micro" +VERSION="6.0" +VERSION_ID="6.0" +PRETTY_NAME="SUSE Linux Micro 6.0" +ID="sl-micro" +ID_LIKE="suse" +ANSI_COLOR="0;32" +CPE_NAME="cpe:/o:suse:sl-micro:6.0" +HOME_URL="https://www.suse.com/products/micro/" +DOCUMENTATION_URL="https://documentation.suse.com/sl-micro/6.0/" diff --git a/pkg/fanal/test/integration/testdata/goldens/packages/opensuse-tumbleweed.json.golden b/pkg/fanal/test/integration/testdata/goldens/packages/opensuse-tumbleweed.json.golden index a651f86e3862..fa00e70aa6e6 100644 --- a/pkg/fanal/test/integration/testdata/goldens/packages/opensuse-tumbleweed.json.golden +++ b/pkg/fanal/test/integration/testdata/goldens/packages/opensuse-tumbleweed.json.golden @@ -3,7 +3,7 @@ "ID": "aaa_base@84.87+git20240523.10a5692-1.1.x86_64", "Name": "aaa_base", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/aaa_base@84.87%2Bgit20240523.10a5692-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/aaa_base@84.87%2Bgit20240523.10a5692-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "fe755017155caefc" }, "Version": "84.87+git20240523.10a5692", @@ -34,7 +34,7 @@ "ID": "bash@5.2.26-12.1.x86_64", "Name": "bash", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/bash@5.2.26-12.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/bash@5.2.26-12.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "ce56393f87add219" }, "Version": "5.2.26", @@ -61,7 +61,7 @@ "ID": "bash-sh@5.2.26-12.1.noarch", "Name": "bash-sh", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/bash-sh@5.2.26-12.1?arch=noarch&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/bash-sh@5.2.26-12.1?arch=noarch&distro=opensuse.tumbleweed-20240607", "UID": "7363186d472571e0" }, "Version": "5.2.26", @@ -87,7 +87,7 @@ "ID": "boost-license1_85_0@1.85.0-1.2.noarch", "Name": "boost-license1_85_0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/boost-license1_85_0@1.85.0-1.2?arch=noarch&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/boost-license1_85_0@1.85.0-1.2?arch=noarch&distro=opensuse.tumbleweed-20240607", "UID": "2d87c856df6862ee" }, "Version": "1.85.0", @@ -110,7 +110,7 @@ "ID": "branding-openSUSE@84.87.20240405-1.2.noarch", "Name": "branding-openSUSE", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/branding-openSUSE@84.87.20240405-1.2?arch=noarch&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/branding-openSUSE@84.87.20240405-1.2?arch=noarch&distro=opensuse.tumbleweed-20240607", "UID": "acda90b5f91cb463" }, "Version": "84.87.20240405", @@ -133,7 +133,7 @@ "ID": "ca-certificates@2+git20240415.3fe9324-1.1.noarch", "Name": "ca-certificates", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/ca-certificates@2%2Bgit20240415.3fe9324-1.1?arch=noarch&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/ca-certificates@2%2Bgit20240415.3fe9324-1.1?arch=noarch&distro=opensuse.tumbleweed-20240607", "UID": "7a18ce239fe8c044" }, "Version": "2+git20240415.3fe9324", @@ -162,7 +162,7 @@ "ID": "ca-certificates-mozilla@2.66-1.2.noarch", "Name": "ca-certificates-mozilla", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/ca-certificates-mozilla@2.66-1.2?arch=noarch&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/ca-certificates-mozilla@2.66-1.2?arch=noarch&distro=opensuse.tumbleweed-20240607", "UID": "362f343aa3c5d416" }, "Version": "2.66", @@ -189,7 +189,7 @@ "ID": "coreutils@9.5-1.1.x86_64", "Name": "coreutils", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/coreutils@9.5-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/coreutils@9.5-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "9483aa372c47866d" }, "Version": "9.5", @@ -221,7 +221,7 @@ "ID": "cracklib-dict-small@2.9.11-1.4.x86_64", "Name": "cracklib-dict-small", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/cracklib-dict-small@2.9.11-1.4?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/cracklib-dict-small@2.9.11-1.4?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "cc38aea883124e41" }, "Version": "2.9.11", @@ -244,7 +244,7 @@ "ID": "crypto-policies@20230920.570ea89-3.2.noarch", "Name": "crypto-policies", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/crypto-policies@20230920.570ea89-3.2?arch=noarch&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/crypto-policies@20230920.570ea89-3.2?arch=noarch&distro=opensuse.tumbleweed-20240607", "UID": "ebef887879b412aa" }, "Version": "20230920.570ea89", @@ -267,7 +267,7 @@ "ID": "curl@8.8.0-1.1.x86_64", "Name": "curl", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/curl@8.8.0-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/curl@8.8.0-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "50b6514bae052e62" }, "Version": "8.8.0", @@ -295,7 +295,7 @@ "ID": "file-magic@5.45-2.2.noarch", "Name": "file-magic", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/file-magic@5.45-2.2?arch=noarch&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/file-magic@5.45-2.2?arch=noarch&distro=opensuse.tumbleweed-20240607", "UID": "9318efe3deebc83a" }, "Version": "5.45", @@ -318,7 +318,7 @@ "ID": "filesystem@84.87-15.3.x86_64", "Name": "filesystem", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/filesystem@84.87-15.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/filesystem@84.87-15.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "379508af5bc6bae5" }, "Version": "84.87", @@ -344,7 +344,7 @@ "ID": "fillup@1.42-281.1.x86_64", "Name": "fillup", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/fillup@1.42-281.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/fillup@1.42-281.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "7d48bfb3846c8056" }, "Version": "1.42", @@ -370,7 +370,7 @@ "ID": "glibc@2.39-9.1.x86_64", "Name": "glibc", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/glibc@2.39-9.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/glibc@2.39-9.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "77433316d747193b" }, "Version": "2.39", @@ -396,7 +396,7 @@ "ID": "glibc-locale-base@2.39-9.1.x86_64", "Name": "glibc-locale-base", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/glibc-locale-base@2.39-9.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/glibc-locale-base@2.39-9.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "7f6f8a5c2e27af75" }, "Version": "2.39", @@ -422,7 +422,7 @@ "ID": "gpg-pubkey@29b700a4-62b07e22.", "Name": "gpg-pubkey", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/gpg-pubkey@29b700a4-62b07e22?arch=None&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/gpg-pubkey@29b700a4-62b07e22?arch=None&distro=opensuse.tumbleweed-20240607", "UID": "562934f3f56669a5" }, "Version": "29b700a4", @@ -440,7 +440,7 @@ "ID": "gpg-pubkey@39db7c82-510a966b.", "Name": "gpg-pubkey", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/gpg-pubkey@39db7c82-510a966b?arch=None&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/gpg-pubkey@39db7c82-510a966b?arch=None&distro=opensuse.tumbleweed-20240607", "UID": "5e72dadde79df0d4" }, "Version": "39db7c82", @@ -458,7 +458,7 @@ "ID": "gpg2@2.4.5-1.1.x86_64", "Name": "gpg2", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/gpg2@2.4.5-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/gpg2@2.4.5-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "e95cc1c58ec7e824" }, "Version": "2.4.5", @@ -496,7 +496,7 @@ "ID": "grep@3.11-3.1.x86_64", "Name": "grep", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/grep@3.11-3.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/grep@3.11-3.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "7c3b5ec5d53fa9f9" }, "Version": "3.11", @@ -524,7 +524,7 @@ "ID": "gzip@1.13-3.1.x86_64", "Name": "gzip", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/gzip@1.13-3.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/gzip@1.13-3.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "f51af60e831e41e" }, "Version": "1.13", @@ -551,7 +551,7 @@ "ID": "krb5@1.21.2-5.1.x86_64", "Name": "krb5", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/krb5@1.21.2-5.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/krb5@1.21.2-5.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "f22a7694d8a232ac" }, "Version": "1.21.2", @@ -583,7 +583,7 @@ "ID": "libabsl_lite_2401_0_0@20240116.2-2.1.x86_64", "Name": "libabsl_lite_2401_0_0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libabsl_lite_2401_0_0@20240116.2-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libabsl_lite_2401_0_0@20240116.2-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "24307f175234d50" }, "Version": "20240116.2", @@ -611,7 +611,7 @@ "ID": "libacl1@2.3.2-2.1.x86_64", "Name": "libacl1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libacl1@2.3.2-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libacl1@2.3.2-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "6e55e249889869ed" }, "Version": "2.3.2", @@ -637,7 +637,7 @@ "ID": "libassuan0@2.5.7-1.1.x86_64", "Name": "libassuan0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libassuan0@2.5.7-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libassuan0@2.5.7-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "4a9f149fc3b4d802" }, "Version": "2.5.7", @@ -664,7 +664,7 @@ "ID": "libattr1@2.5.2-1.2.x86_64", "Name": "libattr1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libattr1@2.5.2-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libattr1@2.5.2-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "bf6e596e053cc667" }, "Version": "2.5.2", @@ -690,7 +690,7 @@ "ID": "libaudit1@3.1.1-1.6.x86_64", "Name": "libaudit1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libaudit1@3.1.1-1.6?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libaudit1@3.1.1-1.6?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "c2ab09cc3b09bf56" }, "Version": "3.1.1", @@ -716,7 +716,7 @@ "ID": "libaugeas0@1.14.1-1.3.x86_64", "Name": "libaugeas0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libaugeas0@1.14.1-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libaugeas0@1.14.1-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "bc9b541f623eec37" }, "Version": "1.14.1", @@ -744,7 +744,7 @@ "ID": "libblkid1@2.40.1-2.1.x86_64", "Name": "libblkid1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libblkid1@2.40.1-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libblkid1@2.40.1-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "bcf4491906d1eb4d" }, "Version": "2.40.1", @@ -771,7 +771,7 @@ "ID": "libboost_thread1_85_0@1.85.0-1.2.x86_64", "Name": "libboost_thread1_85_0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libboost_thread1_85_0@1.85.0-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libboost_thread1_85_0@1.85.0-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "b8612fd1d8aa51a7" }, "Version": "1.85.0", @@ -800,7 +800,7 @@ "ID": "libbrotlicommon1@1.1.0-1.3.x86_64", "Name": "libbrotlicommon1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libbrotlicommon1@1.1.0-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libbrotlicommon1@1.1.0-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "f1d7b84b18abde08" }, "Version": "1.1.0", @@ -826,7 +826,7 @@ "ID": "libbrotlidec1@1.1.0-1.3.x86_64", "Name": "libbrotlidec1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libbrotlidec1@1.1.0-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libbrotlidec1@1.1.0-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "5c297a82e6701a0d" }, "Version": "1.1.0", @@ -853,7 +853,7 @@ "ID": "libbz2-1@1.0.8-5.10.x86_64", "Name": "libbz2-1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libbz2-1@1.0.8-5.10?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libbz2-1@1.0.8-5.10?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "702f3dd378cba8f0" }, "Version": "1.0.8", @@ -879,7 +879,7 @@ "ID": "libcap-ng0@0.8.5-1.1.x86_64", "Name": "libcap-ng0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libcap-ng0@0.8.5-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libcap-ng0@0.8.5-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "b40d6fdd09912405" }, "Version": "0.8.5", @@ -905,7 +905,7 @@ "ID": "libcap2@2.70-1.1.x86_64", "Name": "libcap2", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libcap2@2.70-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libcap2@2.70-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "c33018bbf8c4bdfa" }, "Version": "2.70", @@ -931,7 +931,7 @@ "ID": "libcom_err2@1.47.0-4.2.x86_64", "Name": "libcom_err2", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libcom_err2@1.47.0-4.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libcom_err2@1.47.0-4.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "58b023020895cfea" }, "Version": "1.47.0", @@ -957,7 +957,7 @@ "ID": "libcrypt1@4.4.36-1.6.x86_64", "Name": "libcrypt1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libcrypt1@4.4.36-1.6?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libcrypt1@4.4.36-1.6?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "541be9a801034440" }, "Version": "4.4.36", @@ -983,7 +983,7 @@ "ID": "libcurl4@8.8.0-1.1.x86_64", "Name": "libcurl4", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libcurl4@8.8.0-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libcurl4@8.8.0-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "59c3c7a8962c110a" }, "Version": "8.8.0", @@ -1019,7 +1019,7 @@ "ID": "libeconf0@0.6.3-1.1.x86_64", "Name": "libeconf0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libeconf0@0.6.3-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libeconf0@0.6.3-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "9e3e97464bc6164b" }, "Version": "0.6.3", @@ -1045,7 +1045,7 @@ "ID": "libfa1@1.14.1-1.3.x86_64", "Name": "libfa1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libfa1@1.14.1-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libfa1@1.14.1-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "9df420b84b79a62" }, "Version": "1.14.1", @@ -1071,7 +1071,7 @@ "ID": "libfdisk1@2.40.1-2.1.x86_64", "Name": "libfdisk1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libfdisk1@2.40.1-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libfdisk1@2.40.1-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "ab47b44e7c45eab1" }, "Version": "2.40.1", @@ -1099,7 +1099,7 @@ "ID": "libffi8@3.4.6-1.1.x86_64", "Name": "libffi8", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libffi8@3.4.6-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libffi8@3.4.6-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "a569681a5276bde6" }, "Version": "3.4.6", @@ -1125,7 +1125,7 @@ "ID": "libgcc_s1@14.1.0+git10173-1.1.x86_64", "Name": "libgcc_s1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libgcc_s1@14.1.0%2Bgit10173-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libgcc_s1@14.1.0%2Bgit10173-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "3130b825fbc3a81e" }, "Version": "14.1.0+git10173", @@ -1151,7 +1151,7 @@ "ID": "libgcrypt20@1.10.3-3.3.x86_64", "Name": "libgcrypt20", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libgcrypt20@1.10.3-3.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libgcrypt20@1.10.3-3.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "ac38e6e75132d1c6" }, "Version": "1.10.3", @@ -1178,7 +1178,7 @@ "ID": "libglib-2_0-0@2.80.2-1.1.x86_64", "Name": "libglib-2_0-0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libglib-2_0-0@2.80.2-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libglib-2_0-0@2.80.2-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "e3dccc27a6f44a3d" }, "Version": "2.80.2", @@ -1205,7 +1205,7 @@ "ID": "libgmp10@6.3.0-3.2.x86_64", "Name": "libgmp10", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libgmp10@6.3.0-3.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libgmp10@6.3.0-3.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "fb3994e26d59ae4f" }, "Version": "6.3.0", @@ -1231,7 +1231,7 @@ "ID": "libgpg-error0@1.49-1.1.x86_64", "Name": "libgpg-error0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libgpg-error0@1.49-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libgpg-error0@1.49-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "a3b16ea69b05fe60" }, "Version": "1.49", @@ -1257,7 +1257,7 @@ "ID": "libgpgme11@1.23.2-4.2.x86_64", "Name": "libgpgme11", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libgpgme11@1.23.2-4.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libgpgme11@1.23.2-4.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "6d9271ab523fb009" }, "Version": "1.23.2", @@ -1286,7 +1286,7 @@ "ID": "libidn2-0@2.3.7-1.2.x86_64", "Name": "libidn2-0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libidn2-0@2.3.7-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libidn2-0@2.3.7-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "ae81c3e9fc0d0fc3" }, "Version": "2.3.7", @@ -1313,7 +1313,7 @@ "ID": "libkeyutils1@1.6.3-7.2.x86_64", "Name": "libkeyutils1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libkeyutils1@1.6.3-7.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libkeyutils1@1.6.3-7.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "f9f931edfe4b540c" }, "Version": "1.6.3", @@ -1339,7 +1339,7 @@ "ID": "libksba8@1.6.6-1.1.x86_64", "Name": "libksba8", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libksba8@1.6.6-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libksba8@1.6.6-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "c532eef98bb36938" }, "Version": "1.6.6", @@ -1366,7 +1366,7 @@ "ID": "libldap2@2.6.7-2.1.x86_64", "Name": "libldap2", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libldap2@2.6.7-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libldap2@2.6.7-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "55fa8e45be9ed78" }, "Version": "2.6.7", @@ -1394,7 +1394,7 @@ "ID": "liblua5_4-5@5.4.6-3.3.x86_64", "Name": "liblua5_4-5", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/liblua5_4-5@5.4.6-3.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/liblua5_4-5@5.4.6-3.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "98b4001b2f59f46" }, "Version": "5.4.6", @@ -1420,7 +1420,7 @@ "ID": "liblz4-1@1.9.4-2.8.x86_64", "Name": "liblz4-1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/liblz4-1@1.9.4-2.8?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/liblz4-1@1.9.4-2.8?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "267a6bfb140f0d45" }, "Version": "1.9.4", @@ -1446,7 +1446,7 @@ "ID": "liblzma5@5.6.2-1.1.x86_64", "Name": "liblzma5", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/liblzma5@5.6.2-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/liblzma5@5.6.2-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "304510f1f6669e2c" }, "Version": "5.6.2", @@ -1472,7 +1472,7 @@ "ID": "libmagic1@5.45-2.2.x86_64", "Name": "libmagic1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libmagic1@5.45-2.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libmagic1@5.45-2.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "d8fdc2934df34a83" }, "Version": "5.45", @@ -1503,7 +1503,7 @@ "ID": "libmount1@2.40.1-2.1.x86_64", "Name": "libmount1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libmount1@2.40.1-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libmount1@2.40.1-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "8386ec24a06557ea" }, "Version": "2.40.1", @@ -1531,7 +1531,7 @@ "ID": "libncurses6@6.5.20240601-38.1.x86_64", "Name": "libncurses6", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libncurses6@6.5.20240601-38.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libncurses6@6.5.20240601-38.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "9513bf16199cee6b" }, "Version": "6.5.20240601", @@ -1560,7 +1560,7 @@ "ID": "libnghttp2-14@1.61.0-1.1.x86_64", "Name": "libnghttp2-14", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libnghttp2-14@1.61.0-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libnghttp2-14@1.61.0-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "de28696676fc1ebd" }, "Version": "1.61.0", @@ -1586,7 +1586,7 @@ "ID": "libnpth0@1.7-1.1.x86_64", "Name": "libnpth0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libnpth0@1.7-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libnpth0@1.7-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "7bff27e583fb62b3" }, "Version": "1.7", @@ -1612,7 +1612,7 @@ "ID": "libnss_usrfiles2@2.27.1-1.2.x86_64", "Name": "libnss_usrfiles2", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libnss_usrfiles2@2.27.1-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libnss_usrfiles2@2.27.1-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "d3c8c8f840c86b12" }, "Version": "2.27.1", @@ -1638,7 +1638,7 @@ "ID": "libopenssl-3-fips-provider@3.1.4-9.1.x86_64", "Name": "libopenssl-3-fips-provider", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libopenssl-3-fips-provider@3.1.4-9.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libopenssl-3-fips-provider@3.1.4-9.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "65c56c2870042412" }, "Version": "3.1.4", @@ -1665,7 +1665,7 @@ "ID": "libopenssl3@3.1.4-9.1.x86_64", "Name": "libopenssl3", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libopenssl3@3.1.4-9.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libopenssl3@3.1.4-9.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "f051425f385d2b99" }, "Version": "3.1.4", @@ -1693,7 +1693,7 @@ "ID": "libp11-kit0@0.25.3-1.3.x86_64", "Name": "libp11-kit0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libp11-kit0@0.25.3-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libp11-kit0@0.25.3-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "fbca9a69218ce8e7" }, "Version": "0.25.3", @@ -1720,7 +1720,7 @@ "ID": "libpcre2-8-0@10.43-3.1.x86_64", "Name": "libpcre2-8-0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libpcre2-8-0@10.43-3.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libpcre2-8-0@10.43-3.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "dabdfbc56d214ae6" }, "Version": "10.43", @@ -1746,7 +1746,7 @@ "ID": "libpopt0@1.19-1.8.x86_64", "Name": "libpopt0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libpopt0@1.19-1.8?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libpopt0@1.19-1.8?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "98fa32fcd9ee1e39" }, "Version": "1.19", @@ -1772,7 +1772,7 @@ "ID": "libprocps8@3.3.17-17.1.x86_64", "Name": "libprocps8", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libprocps8@3.3.17-17.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libprocps8@3.3.17-17.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "f874f4997e1438be" }, "Version": "3.3.17", @@ -1799,7 +1799,7 @@ "ID": "libprotobuf-lite25_3_0@25.3-11.2.x86_64", "Name": "libprotobuf-lite25_3_0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libprotobuf-lite25_3_0@25.3-11.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libprotobuf-lite25_3_0@25.3-11.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "b306bfd6494e6405" }, "Version": "25.3", @@ -1828,7 +1828,7 @@ "ID": "libpsl5@0.21.5-1.2.x86_64", "Name": "libpsl5", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libpsl5@0.21.5-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libpsl5@0.21.5-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "5d2411f7ede68692" }, "Version": "0.21.5", @@ -1856,7 +1856,7 @@ "ID": "libreadline8@8.2.10-1.3.x86_64", "Name": "libreadline8", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libreadline8@8.2.10-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libreadline8@8.2.10-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "9271e2cd0119054c" }, "Version": "8.2.10", @@ -1883,7 +1883,7 @@ "ID": "libsasl2-3@2.1.28-8.1.x86_64", "Name": "libsasl2-3", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libsasl2-3@2.1.28-8.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libsasl2-3@2.1.28-8.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "fe2536ad8601f334" }, "Version": "2.1.28", @@ -1909,7 +1909,7 @@ "ID": "libselinux1@3.6-1.3.x86_64", "Name": "libselinux1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libselinux1@3.6-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libselinux1@3.6-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "6bc8fe60a073ba96" }, "Version": "3.6", @@ -1936,7 +1936,7 @@ "ID": "libsemanage-conf@3.6-2.1.x86_64", "Name": "libsemanage-conf", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libsemanage-conf@3.6-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libsemanage-conf@3.6-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "56c91988ca2e8ce5" }, "Version": "3.6", @@ -1959,7 +1959,7 @@ "ID": "libsemanage2@3.6-2.1.x86_64", "Name": "libsemanage2", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libsemanage2@3.6-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libsemanage2@3.6-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "d945b0271ed45cf5" }, "Version": "3.6", @@ -1990,7 +1990,7 @@ "ID": "libsepol2@3.6-1.3.x86_64", "Name": "libsepol2", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libsepol2@3.6-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libsepol2@3.6-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "f2aaf81754d3169d" }, "Version": "3.6", @@ -2016,7 +2016,7 @@ "ID": "libsigc-2_0-0@2.12.1-2.3.x86_64", "Name": "libsigc-2_0-0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libsigc-2_0-0@2.12.1-2.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libsigc-2_0-0@2.12.1-2.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "c4d52d6f33dee391" }, "Version": "2.12.1", @@ -2044,7 +2044,7 @@ "ID": "libsmartcols1@2.40.1-2.1.x86_64", "Name": "libsmartcols1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libsmartcols1@2.40.1-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libsmartcols1@2.40.1-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "5302abe63411170d" }, "Version": "2.40.1", @@ -2070,7 +2070,7 @@ "ID": "libsolv-tools-base@0.7.29-1.1.x86_64", "Name": "libsolv-tools-base", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libsolv-tools-base@0.7.29-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libsolv-tools-base@0.7.29-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "f2adb3efc201c696" }, "Version": "0.7.29", @@ -2102,7 +2102,7 @@ "ID": "libsqlite3-0@3.46.0-1.1.x86_64", "Name": "libsqlite3-0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libsqlite3-0@3.46.0-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libsqlite3-0@3.46.0-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "d9bf1a49d16f0c" }, "Version": "3.46.0", @@ -2128,7 +2128,7 @@ "ID": "libssh-config@0.10.6-2.1.x86_64", "Name": "libssh-config", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libssh-config@0.10.6-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libssh-config@0.10.6-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "8628d51e34c2f5b1" }, "Version": "0.10.6", @@ -2151,7 +2151,7 @@ "ID": "libssh4@0.10.6-2.1.x86_64", "Name": "libssh4", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libssh4@0.10.6-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libssh4@0.10.6-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "d07880785aee16c8" }, "Version": "0.10.6", @@ -2181,7 +2181,7 @@ "ID": "libstdc++6@14.1.0+git10173-1.1.x86_64", "Name": "libstdc++6", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libstdc%2B%2B6@14.1.0%2Bgit10173-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libstdc%2B%2B6@14.1.0%2Bgit10173-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "f3345c3d3261e7e9" }, "Version": "14.1.0+git10173", @@ -2208,7 +2208,7 @@ "ID": "libsubid4@4.15.1-1.2.x86_64", "Name": "libsubid4", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libsubid4@4.15.1-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libsubid4@4.15.1-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "e155b313aa6da812" }, "Version": "4.15.1", @@ -2236,7 +2236,7 @@ "ID": "libsystemd0@255.7-2.1.x86_64", "Name": "libsystemd0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libsystemd0@255.7-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libsystemd0@255.7-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "4fa3c2608f054287" }, "Version": "255.7", @@ -2267,7 +2267,7 @@ "ID": "libtasn1-6@4.19.0-1.7.x86_64", "Name": "libtasn1-6", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libtasn1-6@4.19.0-1.7?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libtasn1-6@4.19.0-1.7?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "35e287fcdf033bd1" }, "Version": "4.19.0", @@ -2293,7 +2293,7 @@ "ID": "libudev1@255.7-2.1.x86_64", "Name": "libudev1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libudev1@255.7-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libudev1@255.7-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "4ae1c62105f1f901" }, "Version": "255.7", @@ -2320,7 +2320,7 @@ "ID": "libunistring5@1.2-1.1.x86_64", "Name": "libunistring5", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libunistring5@1.2-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libunistring5@1.2-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "e8be56f8ad59a760" }, "Version": "1.2", @@ -2346,7 +2346,7 @@ "ID": "libusb-1_0-0@1.0.27-1.2.x86_64", "Name": "libusb-1_0-0", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libusb-1_0-0@1.0.27-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libusb-1_0-0@1.0.27-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "dab90c8d517b4ee4" }, "Version": "1.0.27", @@ -2373,7 +2373,7 @@ "ID": "libuuid1@2.40.1-2.1.x86_64", "Name": "libuuid1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libuuid1@2.40.1-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libuuid1@2.40.1-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "bc5c46e1650d4a95" }, "Version": "2.40.1", @@ -2399,7 +2399,7 @@ "ID": "libverto1@0.3.2-3.3.x86_64", "Name": "libverto1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libverto1@0.3.2-3.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libverto1@0.3.2-3.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "8c13b7ac8ed99616" }, "Version": "0.3.2", @@ -2425,7 +2425,7 @@ "ID": "libxml2-2@2.12.7-1.1.x86_64", "Name": "libxml2-2", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libxml2-2@2.12.7-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libxml2-2@2.12.7-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "1285499ab636c5d9" }, "Version": "2.12.7", @@ -2453,7 +2453,7 @@ "ID": "libyaml-cpp0_8@0.8.0-1.3.x86_64", "Name": "libyaml-cpp0_8", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libyaml-cpp0_8@0.8.0-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libyaml-cpp0_8@0.8.0-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "d743795a2d65f87b" }, "Version": "0.8.0", @@ -2481,7 +2481,7 @@ "ID": "libz1@1.3.1-1.1.x86_64", "Name": "libz1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libz1@1.3.1-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libz1@1.3.1-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "f09857fffac622a" }, "Version": "1.3.1", @@ -2507,7 +2507,7 @@ "ID": "libzck1@1.4.0-2.1.x86_64", "Name": "libzck1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libzck1@1.4.0-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libzck1@1.4.0-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "76b3d8e58402a974" }, "Version": "1.4.0", @@ -2535,7 +2535,7 @@ "ID": "libzstd1@1.5.6-1.1.x86_64", "Name": "libzstd1", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libzstd1@1.5.6-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libzstd1@1.5.6-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "4edc1117cd2019eb" }, "Version": "1.5.6", @@ -2561,7 +2561,7 @@ "ID": "libzypp@17.34.1-1.1.x86_64", "Name": "libzypp", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/libzypp@17.34.1-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/libzypp@17.34.1-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "3545239e91f3bd9" }, "Version": "17.34.1", @@ -2606,7 +2606,7 @@ "ID": "login_defs@4.15.1-1.2.noarch", "Name": "login_defs", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/login_defs@4.15.1-1.2?arch=noarch&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/login_defs@4.15.1-1.2?arch=noarch&distro=opensuse.tumbleweed-20240607", "UID": "1695371f9551a301" }, "Version": "4.15.1", @@ -2632,7 +2632,7 @@ "ID": "lsb-release@3.3-1.3.noarch", "Name": "lsb-release", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/lsb-release@3.3-1.3?arch=noarch&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/lsb-release@3.3-1.3?arch=noarch&distro=opensuse.tumbleweed-20240607", "UID": "8c82a3a248c52a13" }, "Version": "3.3", @@ -2659,7 +2659,7 @@ "ID": "ncurses-utils@6.5.20240601-38.1.x86_64", "Name": "ncurses-utils", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/ncurses-utils@6.5.20240601-38.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/ncurses-utils@6.5.20240601-38.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "90d23a67ceb37784" }, "Version": "6.5.20240601", @@ -2686,7 +2686,7 @@ "ID": "netcfg@11.6-13.3.noarch", "Name": "netcfg", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/netcfg@11.6-13.3?arch=noarch&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/netcfg@11.6-13.3?arch=noarch&distro=opensuse.tumbleweed-20240607", "UID": "c32526003d9c5528" }, "Version": "11.6", @@ -2712,7 +2712,7 @@ "ID": "openSUSE-build-key@1.0-53.1.x86_64", "Name": "openSUSE-build-key", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/openSUSE-build-key@1.0-53.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/openSUSE-build-key@1.0-53.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "ed8309d0e84993e4" }, "Version": "1.0", @@ -2739,7 +2739,7 @@ "ID": "openSUSE-release@20240607-2943.1.x86_64", "Name": "openSUSE-release", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/openSUSE-release@20240607-2943.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/openSUSE-release@20240607-2943.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "ad908712f8c8e5ab" }, "Version": "20240607", @@ -2766,7 +2766,7 @@ "ID": "openSUSE-release-appliance-docker@20240607-2943.1.x86_64", "Name": "openSUSE-release-appliance-docker", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/openSUSE-release-appliance-docker@20240607-2943.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/openSUSE-release-appliance-docker@20240607-2943.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "46f06026407817a0" }, "Version": "20240607", @@ -2789,7 +2789,7 @@ "ID": "openssl@3.1.4-3.2.noarch", "Name": "openssl", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/openssl@3.1.4-3.2?arch=noarch&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/openssl@3.1.4-3.2?arch=noarch&distro=opensuse.tumbleweed-20240607", "UID": "cd2ead77021cf857" }, "Version": "3.1.4", @@ -2815,7 +2815,7 @@ "ID": "openssl-3@3.1.4-9.1.x86_64", "Name": "openssl-3", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/openssl-3@3.1.4-9.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/openssl-3@3.1.4-9.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "da148866e5ba5d92" }, "Version": "3.1.4", @@ -2846,7 +2846,7 @@ "ID": "p11-kit@0.25.3-1.3.x86_64", "Name": "p11-kit", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/p11-kit@0.25.3-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/p11-kit@0.25.3-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "7da38dbf3cd84149" }, "Version": "0.25.3", @@ -2874,7 +2874,7 @@ "ID": "p11-kit-tools@0.25.3-1.3.x86_64", "Name": "p11-kit-tools", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/p11-kit-tools@0.25.3-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/p11-kit-tools@0.25.3-1.3?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "fb534863cc7b3050" }, "Version": "0.25.3", @@ -2902,7 +2902,7 @@ "ID": "pam@1.6.1-1.1.x86_64", "Name": "pam", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/pam@1.6.1-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/pam@1.6.1-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "2cc82a7c85091dc0" }, "Version": "1.6.1", @@ -2935,7 +2935,7 @@ "ID": "patterns-base-fips@20200505-51.1.x86_64", "Name": "patterns-base-fips", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/patterns-base-fips@20200505-51.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/patterns-base-fips@20200505-51.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "70a74594ade38509" }, "Version": "20200505", @@ -2958,7 +2958,7 @@ "ID": "patterns-base-minimal_base@20200505-51.1.x86_64", "Name": "patterns-base-minimal_base", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/patterns-base-minimal_base@20200505-51.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/patterns-base-minimal_base@20200505-51.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "22550c4b68de6581" }, "Version": "20200505", @@ -2987,7 +2987,7 @@ "ID": "permctl@1699_20240522-1.1.x86_64", "Name": "permctl", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/permctl@1699_20240522-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/permctl@1699_20240522-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "cfcd9931dafbea39" }, "Version": "1699_20240522", @@ -3016,7 +3016,7 @@ "ID": "permissions@1699_20240522-1.1.x86_64", "Name": "permissions", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/permissions@1699_20240522-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/permissions@1699_20240522-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "971d93fae8da6b23" }, "Version": "1699_20240522", @@ -3043,7 +3043,7 @@ "ID": "permissions-config@1699_20240522-1.1.noarch", "Name": "permissions-config", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/permissions-config@1699_20240522-1.1?arch=noarch&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/permissions-config@1699_20240522-1.1?arch=noarch&distro=opensuse.tumbleweed-20240607", "UID": "8bd3994be34b3e73" }, "Version": "1699_20240522", @@ -3072,7 +3072,7 @@ "ID": "pinentry@1.2.1-3.5.x86_64", "Name": "pinentry", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/pinentry@1.2.1-3.5?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/pinentry@1.2.1-3.5?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "90686edea2822ef8" }, "Version": "1.2.1", @@ -3102,7 +3102,7 @@ "ID": "procps@3.3.17-17.1.x86_64", "Name": "procps", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/procps@3.3.17-17.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/procps@3.3.17-17.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "41a25e357a85fe17" }, "Version": "3.3.17", @@ -3131,7 +3131,7 @@ "ID": "rpm@4.19.1.1-3.2.x86_64", "Name": "rpm", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/rpm@4.19.1.1-3.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/rpm@4.19.1.1-3.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "6385ed7e7827135a" }, "Version": "4.19.1.1", @@ -3170,7 +3170,7 @@ "ID": "rpm-config-SUSE@20240214-1.2.noarch", "Name": "rpm-config-SUSE", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/rpm-config-SUSE@20240214-1.2?arch=noarch&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/rpm-config-SUSE@20240214-1.2?arch=noarch&distro=opensuse.tumbleweed-20240607", "UID": "b0a53b3b9cd8de6e" }, "Version": "20240214", @@ -3198,7 +3198,7 @@ "ID": "sed@4.9-2.6.x86_64", "Name": "sed", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/sed@4.9-2.6?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/sed@4.9-2.6?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "465c6c9c97824acd" }, "Version": "4.9", @@ -3226,7 +3226,7 @@ "ID": "shadow@4.15.1-1.2.x86_64", "Name": "shadow", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/shadow@4.15.1-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/shadow@4.15.1-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "7fefaa914168ef4f" }, "Version": "4.15.1", @@ -3265,7 +3265,7 @@ "ID": "system-user-root@20190513-2.16.noarch", "Name": "system-user-root", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/system-user-root@20190513-2.16?arch=noarch&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/system-user-root@20190513-2.16?arch=noarch&distro=opensuse.tumbleweed-20240607", "UID": "cc450033801f0db5" }, "Version": "20190513", @@ -3288,7 +3288,7 @@ "ID": "tar@1.35-2.2.x86_64", "Name": "tar", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/tar@1.35-2.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/tar@1.35-2.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "6f7d60b91f9b815f" }, "Version": "1.35", @@ -3316,7 +3316,7 @@ "ID": "terminfo-base@6.5.20240601-38.1.x86_64", "Name": "terminfo-base", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/terminfo-base@6.5.20240601-38.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/terminfo-base@6.5.20240601-38.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "ba53240ca965e6c0" }, "Version": "6.5.20240601", @@ -3342,7 +3342,7 @@ "ID": "timezone@2024a-3.2.x86_64", "Name": "timezone", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/timezone@2024a-3.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/timezone@2024a-3.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "aa7fc225c615b895" }, "Version": "2024a", @@ -3369,7 +3369,7 @@ "ID": "util-linux@2.40.1-2.1.x86_64", "Name": "util-linux", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/util-linux@2.40.1-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/util-linux@2.40.1-2.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "1440e3eb3dfc6c5" }, "Version": "2.40.1", @@ -3412,7 +3412,7 @@ "ID": "xz@5.6.2-1.1.x86_64", "Name": "xz", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/xz@5.6.2-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/xz@5.6.2-1.1?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "1c46963e750a4a9" }, "Version": "5.6.2", @@ -3440,7 +3440,7 @@ "ID": "zypper@1.14.73-1.2.x86_64", "Name": "zypper", "Identifier": { - "PURL": "pkg:rpm/opensuse.tumbleweed/zypper@1.14.73-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", + "PURL": "pkg:rpm/opensuse/zypper@1.14.73-1.2?arch=x86_64&distro=opensuse.tumbleweed-20240607", "UID": "9d7cafcab0f1fed2" }, "Version": "1.14.73", diff --git a/pkg/fanal/types/const.go b/pkg/fanal/types/const.go index ffe1e0718764..c304f40bac5f 100644 --- a/pkg/fanal/types/const.go +++ b/pkg/fanal/types/const.go @@ -37,6 +37,7 @@ const ( Photon OSType = "photon" RedHat OSType = "redhat" Rocky OSType = "rocky" + SLEMicro OSType = "suse linux enterprise micro" SLES OSType = "suse linux enterprise server" Ubuntu OSType = "ubuntu" Wolfi OSType = "wolfi" diff --git a/pkg/purl/purl.go b/pkg/purl/purl.go index d9bff7b11e15..a7b1cb9181f0 100644 --- a/pkg/purl/purl.go +++ b/pkg/purl/purl.go @@ -358,16 +358,19 @@ func parseRPM(fos *ftypes.OS, modularityLabel string) (ftypes.OSType, packageurl return "", packageurl.Qualifiers{} } - // SLES string has whitespace family := fos.Family - if fos.Family == ftypes.SLES { - family = "sles" + // SLES string has whitespace, also highlevel family is not the same as distro + if fos.Family == ftypes.SLES || fos.Family == ftypes.SLEMicro { + family = "suse" + } + if fos.Family == ftypes.OpenSUSETumbleweed || fos.Family == ftypes.OpenSUSELeap { + family = "opensuse" } qualifiers := packageurl.Qualifiers{ { Key: "distro", - Value: fmt.Sprintf("%s-%s", family, fos.Name), + Value: fmt.Sprintf("%s-%s", fos.Family, fos.Name), }, } @@ -476,7 +479,7 @@ func purlType(t ftypes.TargetType) string { return packageurl.TypeDebian case ftypes.RedHat, ftypes.CentOS, ftypes.Rocky, ftypes.Alma, ftypes.Amazon, ftypes.Fedora, ftypes.Oracle, ftypes.OpenSUSE, - ftypes.OpenSUSELeap, ftypes.OpenSUSETumbleweed, ftypes.SLES, ftypes.Photon, + ftypes.OpenSUSELeap, ftypes.OpenSUSETumbleweed, ftypes.SLES, ftypes.SLEMicro, ftypes.Photon, ftypes.Azure, ftypes.CBLMariner: return packageurl.TypeRPM case TypeOCI: From de40df9408d6d856a3ad384ec9f086edce3aa382 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Mon, 30 Sep 2024 10:50:53 +0600 Subject: [PATCH 106/183] fix(misconf): disable DS016 check for image history analyzer (#7540) Signed-off-by: nikpivkin --- .../analyzer/imgconf/dockerfile/dockerfile.go | 5 +++ .../imgconf/dockerfile/dockerfile_test.go | 41 +++++++++++++++++++ pkg/misconf/scanner.go | 3 ++ 3 files changed, 49 insertions(+) diff --git a/pkg/fanal/analyzer/imgconf/dockerfile/dockerfile.go b/pkg/fanal/analyzer/imgconf/dockerfile/dockerfile.go index 5a974a8dd1d1..c79a81f54c61 100644 --- a/pkg/fanal/analyzer/imgconf/dockerfile/dockerfile.go +++ b/pkg/fanal/analyzer/imgconf/dockerfile/dockerfile.go @@ -16,6 +16,10 @@ import ( "github.com/aquasecurity/trivy/pkg/misconf" ) +var disabledChecks = []string{ + "DS016", // See https://github.com/aquasecurity/trivy/issues/7368 +} + const analyzerVersion = 1 func init() { @@ -27,6 +31,7 @@ type historyAnalyzer struct { } func newHistoryAnalyzer(opts analyzer.ConfigAnalyzerOptions) (analyzer.ConfigAnalyzer, error) { + opts.MisconfScannerOption.DisabledCheckIDs = append(opts.MisconfScannerOption.DisabledCheckIDs, disabledChecks...) s, err := misconf.NewScanner(detection.FileTypeDockerfile, opts.MisconfScannerOption) if err != nil { return nil, xerrors.Errorf("misconfiguration scanner error: %w", err) diff --git a/pkg/fanal/analyzer/imgconf/dockerfile/dockerfile_test.go b/pkg/fanal/analyzer/imgconf/dockerfile/dockerfile_test.go index 1ee81016ac8c..c454de8ba3d4 100644 --- a/pkg/fanal/analyzer/imgconf/dockerfile/dockerfile_test.go +++ b/pkg/fanal/analyzer/imgconf/dockerfile/dockerfile_test.go @@ -284,6 +284,47 @@ func Test_historyAnalyzer_Analyze(t *testing.T) { Config: nil, }, }, + { + name: "DS016 check not detected", + input: analyzer.ConfigAnalysisInput{ + Config: &v1.ConfigFile{ + Config: v1.Config{ + Healthcheck: &v1.HealthConfig{ + Test: []string{"CMD-SHELL", "curl --fail http://localhost:3000 || exit 1"}, + Interval: time.Second * 10, + Timeout: time.Second * 3, + }, + }, + History: []v1.History{ + { + // duplicate command from another layer + CreatedBy: `/bin/sh -c #(nop) CMD [\"/bin/bash\"]`, + EmptyLayer: true, + }, + { + CreatedBy: "/bin/sh -c #(nop) ADD file:e4d600fc4c9c293efe360be7b30ee96579925d1b4634c94332e2ec73f7d8eca1 in /", + }, + { + CreatedBy: `HEALTHCHECK &{["CMD-SHELL" "curl --fail http://localhost:3000 || exit 1"] "10s" "3s" "0s" '\x00'}`, + }, + { + CreatedBy: `USER user`, + EmptyLayer: true, + }, + { + CreatedBy: `/bin/sh -c #(nop) CMD [\"/bin/sh\"]`, + EmptyLayer: true, + }, + }, + }, + }, + want: &analyzer.ConfigAnalysisResult{ + Misconfiguration: &types.Misconfiguration{ + FileType: types.Dockerfile, + FilePath: "Dockerfile", + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/misconf/scanner.go b/pkg/misconf/scanner.go index db203364a3e4..78f4f4bdb158 100644 --- a/pkg/misconf/scanner.go +++ b/pkg/misconf/scanner.go @@ -74,6 +74,8 @@ type ScannerOption struct { FilePatterns []string ConfigFileSchemas []*ConfigFileSchema + + DisabledCheckIDs []string } func (o *ScannerOption) Sort() { @@ -212,6 +214,7 @@ func scannerOptions(t detection.FileType, opt ScannerOption) ([]options.ScannerO rego.WithEmbeddedPolicies(!opt.DisableEmbeddedPolicies), rego.WithEmbeddedLibraries(!opt.DisableEmbeddedLibraries), options.ScannerWithIncludeDeprecatedChecks(opt.IncludeDeprecatedChecks), + rego.WithDisabledCheckIDs(opt.DisabledCheckIDs...), } policyFS, policyPaths, err := CreatePolicyFS(opt.PolicyPaths) From cb16d43b696284e7256adc4fff1ff108d1c7bff3 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Mon, 30 Sep 2024 16:42:12 +0600 Subject: [PATCH 107/183] ci: split `save` and `restore` cache actions (#7614) --- .github/workflows/cache-test-images.yaml | 84 ++++++++++++++++++++++++ .github/workflows/test.yaml | 9 +-- 2 files changed, 87 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/cache-test-images.yaml diff --git a/.github/workflows/cache-test-images.yaml b/.github/workflows/cache-test-images.yaml new file mode 100644 index 000000000000..da8aff10cfd2 --- /dev/null +++ b/.github/workflows/cache-test-images.yaml @@ -0,0 +1,84 @@ +name: Cache test images +on: + schedule: + - cron: "0 0 * * *" # Run this workflow every day at 00:00 to avoid cache deletion. + workflow_dispatch: + +jobs: + test-images: + name: Cache test images + runs-on: ubuntu-latest + steps: + - name: Check out code into the Go module directory + uses: actions/checkout@v4.1.6 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Install tools + uses: aquaproj/aqua-installer@v3.0.1 + with: + aqua_version: v1.25.0 + + - name: Generate image list digest + if: github.ref_name == 'main' + id: image-digest + run: | + IMAGE_LIST=$(skopeo list-tags docker://ghcr.io/aquasecurity/trivy-test-images) + DIGEST=$(echo "$IMAGE_LIST" | sha256sum | cut -d' ' -f1) + echo "digest=$DIGEST" >> $GITHUB_OUTPUT + + ## We need to work with test image cache only for main branch + - name: Restore and save test images cache + if: github.ref_name == 'main' + uses: actions/cache@v4 + with: + path: integration/testdata/fixtures/images + key: cache-test-images-${{ steps.image-digest.outputs.digest }} + restore-keys: + cache-test-images- + + - name: Download test images + if: github.ref_name == 'main' + run: mage test:fixtureContainerImages + + test-vm-images: + name: Cache test VM images + runs-on: ubuntu-latest + steps: + - name: Check out code into the Go module directory + uses: actions/checkout@v4.1.6 + + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Install tools + uses: aquaproj/aqua-installer@v3.0.1 + with: + aqua_version: v1.25.0 + + - name: Generate image list digest + if: github.ref_name == 'main' + id: image-digest + run: | + IMAGE_LIST=$(skopeo list-tags docker://ghcr.io/aquasecurity/trivy-test-vm-images) + DIGEST=$(echo "$IMAGE_LIST" | sha256sum | cut -d' ' -f1) + echo "digest=$DIGEST" >> $GITHUB_OUTPUT + + ## We need to work with test VM image cache only for main branch + - name: Restore and save test VM images cache + if: github.ref_name == 'main' + uses: actions/cache@v4 + with: + path: integration/testdata/fixtures/vm-images + key: cache-test-vm-images-${{ steps.image-digest.outputs.digest }} + restore-keys: + cache-test-vm-images- + + - name: Download test VM images + if: github.ref_name == 'main' + run: mage test:fixtureVMImages \ No newline at end of file diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index dc7d825af1c8..b423b61699fb 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -92,8 +92,7 @@ jobs: echo "digest=$DIGEST" >> $GITHUB_OUTPUT - name: Restore test images from cache - uses: actions/cache@v4 - id: restore-test-images + uses: actions/cache/restore@v4 with: path: integration/testdata/fixtures/images key: cache-test-images-${{ steps.image-digest.outputs.digest }} @@ -148,8 +147,7 @@ jobs: echo "digest=$DIGEST" >> $GITHUB_OUTPUT - name: Restore test images from cache - uses: actions/cache@v4 - id: restore-test-images + uses: actions/cache/restore@v4 with: path: integration/testdata/fixtures/images key: cache-test-images-${{ steps.image-digest.outputs.digest }} @@ -185,8 +183,7 @@ jobs: echo "digest=$DIGEST" >> $GITHUB_OUTPUT - name: Restore test VM images from cache - uses: actions/cache@v4 - id: restore-test-vm-images + uses: actions/cache/restore@v4 with: path: integration/testdata/fixtures/vm-images key: cache-test-vm-images-${{ steps.image-digest.outputs.digest }} From 9d1be410c4ba4150f04dddb85b51aef747e9bf75 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Mon, 30 Sep 2024 15:22:59 +0400 Subject: [PATCH 108/183] refactor: fix auth error handling (#7615) Signed-off-by: knqyf263 --- internal/dbtest/fake.go | 5 +-- pkg/db/db.go | 43 ++++++++++--------------- pkg/fanal/artifact/image/remote_sbom.go | 5 +-- pkg/javadb/client.go | 7 ++-- pkg/module/command.go | 8 ++--- pkg/oci/artifact.go | 4 +-- pkg/oci/artifact_test.go | 4 +-- pkg/policy/policy.go | 18 +++-------- pkg/policy/policy_test.go | 12 ++----- 9 files changed, 33 insertions(+), 73 deletions(-) diff --git a/internal/dbtest/fake.go b/internal/dbtest/fake.go index 9f2484bbf94a..7943c72273e2 100644 --- a/internal/dbtest/fake.go +++ b/internal/dbtest/fake.go @@ -62,10 +62,7 @@ func NewFakeDB(t *testing.T, dbPath string, opts FakeDBOptions) *oci.Artifact { opt := ftypes.RegistryOptions{ Insecure: false, } - art, err := oci.NewArtifact("dummy", true, opt, oci.WithImage(img)) - require.NoError(t, err) - - return art + return oci.NewArtifact("dummy", true, opt, oci.WithImage(img)) } func ArchiveDir(t *testing.T, dir string) string { diff --git a/pkg/db/db.go b/pkg/db/db.go index e4af60d092c6..344b21b86e44 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -153,16 +153,23 @@ func (c *Client) Download(ctx context.Context, dst string, opt types.RegistryOpt log.Debug("No metadata file") } - art, err := c.initOCIArtifact(opt) - if err != nil { - return xerrors.Errorf("OCI artifact error: %w", err) - } - - if err = art.Download(ctx, dst, oci.DownloadOption{MediaType: dbMediaType}); err != nil { + art := c.initOCIArtifact(opt) + if err := art.Download(ctx, dst, oci.DownloadOption{MediaType: dbMediaType}); err != nil { + var terr *transport.Error + if errors.As(err, &terr) { + for _, diagnostic := range terr.Errors { + // For better user experience + if diagnostic.Code == transport.DeniedErrorCode || diagnostic.Code == transport.UnauthorizedErrorCode { + // e.g. https://aquasecurity.github.io/trivy/latest/docs/references/troubleshooting/#db + log.Warnf("See %s", doc.URL("/docs/references/troubleshooting/", "db")) + break + } + } + } return xerrors.Errorf("database download error: %w", err) } - if err = c.updateDownloadedAt(ctx, dst); err != nil { + if err := c.updateDownloadedAt(ctx, dst); err != nil { return xerrors.Errorf("failed to update downloaded_at: %w", err) } return nil @@ -194,27 +201,11 @@ func (c *Client) updateDownloadedAt(ctx context.Context, dbDir string) error { return nil } -func (c *Client) initOCIArtifact(opt types.RegistryOptions) (*oci.Artifact, error) { +func (c *Client) initOCIArtifact(opt types.RegistryOptions) *oci.Artifact { if c.artifact != nil { - return c.artifact, nil - } - - art, err := oci.NewArtifact(c.dbRepository.String(), c.quiet, opt) - if err != nil { - var terr *transport.Error - if errors.As(err, &terr) { - for _, diagnostic := range terr.Errors { - // For better user experience - if diagnostic.Code == transport.DeniedErrorCode || diagnostic.Code == transport.UnauthorizedErrorCode { - // e.g. https://aquasecurity.github.io/trivy/latest/docs/references/troubleshooting/#db - log.Warnf("See %s", doc.URL("/docs/references/troubleshooting/", "db")) - break - } - } - } - return nil, xerrors.Errorf("OCI artifact error: %w", err) + return c.artifact } - return art, nil + return oci.NewArtifact(c.dbRepository.String(), c.quiet, opt) } func (c *Client) ShowInfo() error { diff --git a/pkg/fanal/artifact/image/remote_sbom.go b/pkg/fanal/artifact/image/remote_sbom.go index 37303a9f7b05..e95fef23140c 100644 --- a/pkg/fanal/artifact/image/remote_sbom.go +++ b/pkg/fanal/artifact/image/remote_sbom.go @@ -87,10 +87,6 @@ func (a Artifact) inspectOCIReferrerSBOM(ctx context.Context) (artifact.Referenc func (a Artifact) parseReferrer(ctx context.Context, repo string, desc v1.Descriptor) (artifact.Reference, error) { const fileName string = "referrer.sbom" repoName := fmt.Sprintf("%s@%s", repo, desc.Digest) - referrer, err := oci.NewArtifact(repoName, true, a.artifactOption.ImageOption.RegistryOptions) - if err != nil { - return artifact.Reference{}, xerrors.Errorf("OCI error: %w", err) - } tmpDir, err := os.MkdirTemp("", "trivy-sbom-*") if err != nil { @@ -99,6 +95,7 @@ func (a Artifact) parseReferrer(ctx context.Context, repo string, desc v1.Descri defer os.RemoveAll(tmpDir) // Download SBOM to local filesystem + referrer := oci.NewArtifact(repoName, true, a.artifactOption.ImageOption.RegistryOptions) if err = referrer.Download(ctx, tmpDir, oci.DownloadOption{ MediaType: desc.ArtifactType, Filename: fileName, diff --git a/pkg/javadb/client.go b/pkg/javadb/client.go index 936c2d40c028..9f90a37ba231 100644 --- a/pkg/javadb/client.go +++ b/pkg/javadb/client.go @@ -59,11 +59,8 @@ func (u *Updater) Update() error { log.Info("Downloading the Java DB...") // TODO: support remote options - var a *oci.Artifact - if a, err = oci.NewArtifact(u.repo.String(), u.quiet, u.registryOption); err != nil { - return xerrors.Errorf("oci error: %w", err) - } - if err = a.Download(context.Background(), dbDir, oci.DownloadOption{MediaType: mediaType}); err != nil { + art := oci.NewArtifact(u.repo.String(), u.quiet, u.registryOption) + if err = art.Download(context.Background(), dbDir, oci.DownloadOption{MediaType: mediaType}); err != nil { return xerrors.Errorf("DB download error: %w", err) } diff --git a/pkg/module/command.go b/pkg/module/command.go index 87a87e5d6209..2dd955aa0e4b 100644 --- a/pkg/module/command.go +++ b/pkg/module/command.go @@ -23,15 +23,11 @@ func Install(ctx context.Context, dir, repo string, quiet bool, opt types.Regist } log.Info("Installing the module from the repository...", log.String("repo", repo)) - artifact, err := oci.NewArtifact(repo, quiet, opt) - if err != nil { - return xerrors.Errorf("module initialize error: %w", err) - } + art := oci.NewArtifact(repo, quiet, opt) dst := filepath.Join(dir, ref.Context().Name()) log.Debug("Installing the module...", log.String("dst", dst)) - - if err = artifact.Download(ctx, dst, oci.DownloadOption{MediaType: mediaType}); err != nil { + if err = art.Download(ctx, dst, oci.DownloadOption{MediaType: mediaType}); err != nil { return xerrors.Errorf("module download error: %w", err) } diff --git a/pkg/oci/artifact.go b/pkg/oci/artifact.go index 04d62ee15d36..d8474941b3f5 100644 --- a/pkg/oci/artifact.go +++ b/pkg/oci/artifact.go @@ -57,7 +57,7 @@ type Artifact struct { } // NewArtifact returns a new artifact -func NewArtifact(repo string, quiet bool, registryOpt types.RegistryOptions, opts ...Option) (*Artifact, error) { +func NewArtifact(repo string, quiet bool, registryOpt types.RegistryOptions, opts ...Option) *Artifact { art := &Artifact{ repository: repo, quiet: quiet, @@ -67,7 +67,7 @@ func NewArtifact(repo string, quiet bool, registryOpt types.RegistryOptions, opt for _, o := range opts { o(art) } - return art, nil + return art } func (a *Artifact) populate(ctx context.Context, opt types.RegistryOptions) error { diff --git a/pkg/oci/artifact_test.go b/pkg/oci/artifact_test.go index ddfe0304cc63..7cc8cd19d3c1 100644 --- a/pkg/oci/artifact_test.go +++ b/pkg/oci/artifact_test.go @@ -116,9 +116,7 @@ func TestArtifact_Download(t *testing.T) { }, }, nil) - artifact, err := oci.NewArtifact("repo", true, ftypes.RegistryOptions{}, oci.WithImage(img)) - require.NoError(t, err) - + artifact := oci.NewArtifact("repo", true, ftypes.RegistryOptions{}, oci.WithImage(img)) err = artifact.Download(context.Background(), tempDir, oci.DownloadOption{ MediaType: tt.mediaType, }) diff --git a/pkg/policy/policy.go b/pkg/policy/policy.go index 88af220d3cf6..c8c05cf067c7 100644 --- a/pkg/policy/policy.go +++ b/pkg/policy/policy.go @@ -89,23 +89,16 @@ func NewClient(cacheDir string, quiet bool, checkBundleRepo string, opts ...Opti }, nil } -func (c *Client) populateOCIArtifact(registryOpts types.RegistryOptions) error { +func (c *Client) populateOCIArtifact(registryOpts types.RegistryOptions) { if c.artifact == nil { log.Debug("Loading check bundle", log.String("repository", c.checkBundleRepo)) - art, err := oci.NewArtifact(c.checkBundleRepo, c.quiet, registryOpts) - if err != nil { - return xerrors.Errorf("OCI artifact error: %w", err) - } - c.artifact = art + c.artifact = oci.NewArtifact(c.checkBundleRepo, c.quiet, registryOpts) } - return nil } // DownloadBuiltinPolicies download default policies from GitHub Pages func (c *Client) DownloadBuiltinPolicies(ctx context.Context, registryOpts types.RegistryOptions) error { - if err := c.populateOCIArtifact(registryOpts); err != nil { - return xerrors.Errorf("OPA bundle error: %w", err) - } + c.populateOCIArtifact(registryOpts) dst := c.contentDir() if err := c.artifact.Download(ctx, dst, oci.DownloadOption{MediaType: policyMediaType}); err != nil { @@ -165,10 +158,7 @@ func (c *Client) NeedsUpdate(ctx context.Context, registryOpts types.RegistryOpt return false, nil } - if err = c.populateOCIArtifact(registryOpts); err != nil { - return false, xerrors.Errorf("OPA bundle error: %w", err) - } - + c.populateOCIArtifact(registryOpts) digest, err := c.artifact.Digest(ctx) if err != nil { return false, xerrors.Errorf("digest error: %w", err) diff --git a/pkg/policy/policy_test.go b/pkg/policy/policy_test.go index 8e1b175da483..4dbd6b9a7558 100644 --- a/pkg/policy/policy_test.go +++ b/pkg/policy/policy_test.go @@ -116,9 +116,7 @@ func TestClient_LoadBuiltinPolicies(t *testing.T) { }, nil) // Mock OCI artifact - art, err := oci.NewArtifact("repo", true, ftypes.RegistryOptions{}, oci.WithImage(img)) - require.NoError(t, err) - + art := oci.NewArtifact("repo", true, ftypes.RegistryOptions{}, oci.WithImage(img)) c, err := policy.NewClient(tt.cacheDir, true, "", policy.WithOCIArtifact(art)) require.NoError(t, err) @@ -257,9 +255,7 @@ func TestClient_NeedsUpdate(t *testing.T) { require.NoError(t, err) } - art, err := oci.NewArtifact("repo", true, ftypes.RegistryOptions{}, oci.WithImage(img)) - require.NoError(t, err) - + art := oci.NewArtifact("repo", true, ftypes.RegistryOptions{}, oci.WithImage(img)) c, err := policy.NewClient(tmpDir, true, "", policy.WithOCIArtifact(art), policy.WithClock(tt.clock)) require.NoError(t, err) @@ -361,9 +357,7 @@ func TestClient_DownloadBuiltinPolicies(t *testing.T) { }, nil) // Mock OCI artifact - art, err := oci.NewArtifact("repo", true, ftypes.RegistryOptions{}, oci.WithImage(img)) - require.NoError(t, err) - + art := oci.NewArtifact("repo", true, ftypes.RegistryOptions{}, oci.WithImage(img)) c, err := policy.NewClient(tempDir, true, "", policy.WithClock(tt.clock), policy.WithOCIArtifact(art)) require.NoError(t, err) From 60725f879ba014c5c57583db6afc290b78facae8 Mon Sep 17 00:00:00 2001 From: afdesk Date: Mon, 30 Sep 2024 18:42:46 +0600 Subject: [PATCH 109/183] feat(secret): enhance secret scanning for python binary files (#7223) Signed-off-by: knqyf263 Co-authored-by: knqyf263 --- docs/docs/scanner/secret.md | 4 +- pkg/fanal/analyzer/secret/secret.go | 28 ++++++++++--- pkg/fanal/analyzer/secret/secret_test.go | 25 ++++++++++++ .../secret/testdata/secret.cpython-310.pyc | Bin 0 -> 226 bytes pkg/fanal/secret/scanner.go | 10 ++++- pkg/fanal/utils/utils.go | 38 ++++++++++++++++++ 6 files changed, 96 insertions(+), 9 deletions(-) create mode 100755 pkg/fanal/analyzer/secret/testdata/secret.cpython-310.pyc diff --git a/docs/docs/scanner/secret.md b/docs/docs/scanner/secret.md index 49d8c8488ece..ea74ae64c930 100644 --- a/docs/docs/scanner/secret.md +++ b/docs/docs/scanner/secret.md @@ -3,7 +3,9 @@ Trivy scans any container image, filesystem and git repository to detect exposed secrets like passwords, api keys, and tokens. Secret scanning is enabled by default. -Trivy will scan every plaintext file, according to builtin rules or configuration. There are plenty of builtin rules: +Trivy will scan every plaintext file, according to builtin rules or configuration. Also, Trivy can detect secrets in compiled Python files (`.pyc`). + +There are plenty of builtin rules: - AWS access key - GCP service account diff --git a/pkg/fanal/analyzer/secret/secret.go b/pkg/fanal/analyzer/secret/secret.go index d2627a840c1b..bdb3e96d1428 100644 --- a/pkg/fanal/analyzer/secret/secret.go +++ b/pkg/fanal/analyzer/secret/secret.go @@ -54,6 +54,9 @@ var ( ".gz", ".gzip", ".tar", + } + + allowedBinaries = []string{ ".pyc", } ) @@ -63,6 +66,10 @@ func init() { analyzer.RegisterAnalyzer(NewSecretAnalyzer(secret.Scanner{}, "")) } +func allowedBinary(filename string) bool { + return slices.Contains(allowedBinaries, filepath.Ext(filename)) +} + // SecretAnalyzer is an analyzer for secrets type SecretAnalyzer struct { scanner secret.Scanner @@ -96,7 +103,7 @@ func (a *SecretAnalyzer) Init(opt analyzer.AnalyzerOptions) error { func (a *SecretAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) { // Do not scan binaries binary, err := utils.IsBinary(input.Content, input.Info.Size()) - if binary || err != nil { + if err != nil || (binary && !allowedBinary(input.FilePath)) { return nil, nil } @@ -104,12 +111,20 @@ func (a *SecretAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput log.WithPrefix("secret").Warn("The size of the scanned file is too large. It is recommended to use `--skip-files` for this file to avoid high memory consumption.", log.FilePath(input.FilePath), log.Int64("size (MB)", size/1048576)) } - content, err := io.ReadAll(input.Content) - if err != nil { - return nil, xerrors.Errorf("read error %s: %w", input.FilePath, err) - } + var content []byte - content = bytes.ReplaceAll(content, []byte("\r"), []byte("")) + if !binary { + content, err = io.ReadAll(input.Content) + if err != nil { + return nil, xerrors.Errorf("read error %s: %w", input.FilePath, err) + } + content = bytes.ReplaceAll(content, []byte("\r"), []byte("")) + } else { + content, err = utils.ExtractPrintableBytes(input.Content) + if err != nil { + return nil, xerrors.Errorf("binary read error %s: %w", input.FilePath, err) + } + } filePath := input.FilePath // Files extracted from the image have an empty input.Dir. @@ -122,6 +137,7 @@ func (a *SecretAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput result := a.scanner.Scan(secret.ScanArgs{ FilePath: filePath, Content: content, + Binary: binary, }) if len(result.Findings) == 0 { diff --git a/pkg/fanal/analyzer/secret/secret_test.go b/pkg/fanal/analyzer/secret/secret_test.go index 7cba1d137e8f..5187ebc341bf 100644 --- a/pkg/fanal/analyzer/secret/secret_test.go +++ b/pkg/fanal/analyzer/secret/secret_test.go @@ -95,6 +95,16 @@ func TestSecretAnalyzer(t *testing.T) { }, }, } + wantFindingGH_PAT := types.SecretFinding{ + RuleID: "github-fine-grained-pat", + Category: "GitHub", + Title: "GitHub Fine-grained personal access tokens", + Severity: "CRITICAL", + StartLine: 1, + EndLine: 1, + Match: "Binary file \"/testdata/secret.cpython-310.pyc\" matches a rule \"GitHub Fine-grained personal access tokens\"", + } + tests := []struct { name string configPath string @@ -153,6 +163,21 @@ func TestSecretAnalyzer(t *testing.T) { filePath: "testdata/binaryfile", want: nil, }, + { + name: "python binary file", + configPath: "testdata/skip-tests-config.yaml", + filePath: "testdata/secret.cpython-310.pyc", + want: &analyzer.AnalysisResult{ + Secrets: []types.Secret{ + { + FilePath: "/testdata/secret.cpython-310.pyc", + Findings: []types.SecretFinding{ + wantFindingGH_PAT, + }, + }, + }, + }, + }, } for _, tt := range tests { diff --git a/pkg/fanal/analyzer/secret/testdata/secret.cpython-310.pyc b/pkg/fanal/analyzer/secret/testdata/secret.cpython-310.pyc new file mode 100755 index 0000000000000000000000000000000000000000..2bb659e7eb21abd1fed3da8d1f085600619d6f4b GIT binary patch literal 226 zcmd1j<>g`kf~l#i(<*@UV-N=!FabFZKwK;UBvKfn7*ZKi8JZax8B!R788n%0#inPL zWRxbw7bKR%8yY&fxVreddm0qydZb1gR(g7bC%VKZd6tJ1dsQZeB)a>Ag{D`fx>Xh# zI;KWsS45O#Mmjr(W*3&arFy3MmPa}Hc!rvIxca9?IfeN+R+jkzZD21>O)g3;F}%fE tP?VWhvXY^Q1?Uto@rzqeA0n$)P minLength { + // add a newline between printable lines to separate them + _ = currentPrintableLine.WriteByte('\n') + result = append(result, currentPrintableLine.Bytes()...) + } + currentPrintableLine.Reset() + } + if currentPrintableLine.Len() > minLength { + // add a newline between printable lines to separate them + _ = currentPrintableLine.WriteByte('\n') + result = append(result, currentPrintableLine.Bytes()...) + } + return result, nil +} From b8362321adb2af220830c5de31c29978423d47da Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Mon, 30 Sep 2024 20:47:51 +0600 Subject: [PATCH 110/183] feat(java): add empty versions if `pom.xml` dependency versions can't be detected (#7520) Co-authored-by: Teppei Fukuda --- docs/docs/coverage/language/java.md | 11 ++++++ pkg/dependency/parser/java/pom/artifact.go | 21 +++++++++-- pkg/dependency/parser/java/pom/parse.go | 8 +++++ pkg/dependency/parser/java/pom/parse_test.go | 35 +++++++++++++++++++ .../pom/testdata/dep-without-version/pom.xml | 24 +++++++++++++ .../analyzer/language/java/pom/pom_test.go | 11 ++++++ 6 files changed, 108 insertions(+), 2 deletions(-) create mode 100644 pkg/dependency/parser/java/pom/testdata/dep-without-version/pom.xml diff --git a/docs/docs/coverage/language/java.md b/docs/docs/coverage/language/java.md index 67cd8c135b9d..0ee39bbd3155 100644 --- a/docs/docs/coverage/language/java.md +++ b/docs/docs/coverage/language/java.md @@ -69,6 +69,16 @@ The vulnerability database will be downloaded anyway. !!! Warning Trivy may skip some dependencies (that were not found on your local machine) when the `--offline-scan` flag is passed. +### empty dependency version +There are cases when Trivy cannot determine the version of dependencies: + +- Unable to determine the version from the parent because the parent is not reachable; +- The dependency uses a [hard requirement][version-requirement] with more than one version. + +In these cases, Trivy uses an empty version for the dependency. + +!!! Warning + Trivy doesn't detect child dependencies for dependencies without a version. ### maven-invoker-plugin Typically, the integration tests directory (`**/[src|target]/it/*/pom.xml`) of [maven-invoker-plugin][maven-invoker-plugin] doesn't contain actual `pom.xml` files and should be skipped to avoid noise. @@ -120,3 +130,4 @@ Make sure that you have cache[^8] directory to find licenses from `*.pom` depend [maven-pom-repos]: https://maven.apache.org/settings.html#repositories [sbt-dependency-lock]: https://stringbean.github.io/sbt-dependency-lock [detection-priority]: ../../scanner/vulnerability.md#detection-priority +[version-requirement]: https://maven.apache.org/pom.html#dependency-version-requirement-specification diff --git a/pkg/dependency/parser/java/pom/artifact.go b/pkg/dependency/parser/java/pom/artifact.go index b2e97efb229b..73ebe6b21407 100644 --- a/pkg/dependency/parser/java/pom/artifact.go +++ b/pkg/dependency/parser/java/pom/artifact.go @@ -6,15 +6,22 @@ import ( "regexp" "slices" "strings" + "sync" "github.com/samber/lo" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" + "github.com/aquasecurity/trivy/pkg/version/doc" ) var ( - varRegexp = regexp.MustCompile(`\${(\S+?)}`) + varRegexp = regexp.MustCompile(`\${(\S+?)}`) + emptyVersionWarn = sync.OnceFunc(func() { + log.WithPrefix("pom").Warn("Dependency version cannot be determined. Child dependencies will not be found.", + // e.g. https://aquasecurity.github.io/trivy/latest/docs/coverage/language/java/#empty-dependency-version + log.String("details", doc.URL("/docs/coverage/language/java/", "empty-dependency-version"))) + }) ) type artifact struct { @@ -42,7 +49,17 @@ func newArtifact(groupID, artifactID, version string, licenses []string, props m } func (a artifact) IsEmpty() bool { - return a.GroupID == "" || a.ArtifactID == "" || a.Version.String() == "" + if a.GroupID == "" || a.ArtifactID == "" { + return true + } + if a.Version.String() == "" { + emptyVersionWarn() + log.WithPrefix("pom").Debug("Dependency version cannot be determined.", + log.String("GroupID", a.GroupID), + log.String("ArtifactID", a.ArtifactID), + ) + } + return false } func (a artifact) Equal(o artifact) bool { diff --git a/pkg/dependency/parser/java/pom/parse.go b/pkg/dependency/parser/java/pom/parse.go index 76ca37f2dd05..542abcac3c8a 100644 --- a/pkg/dependency/parser/java/pom/parse.go +++ b/pkg/dependency/parser/java/pom/parse.go @@ -292,6 +292,14 @@ func (p *Parser) resolve(art artifact, rootDepManagement []pomDependency) (analy return *result, nil } + // We can't resolve a dependency without a version. + // So let's just keep this dependency. + if art.Version.String() == "" { + return analysisResult{ + artifact: art, + }, nil + } + p.logger.Debug("Resolving...", log.String("group_id", art.GroupID), log.String("artifact_id", art.ArtifactID), log.String("version", art.Version.String())) pomContent, err := p.tryRepository(art.GroupID, art.ArtifactID, art.Version.String()) diff --git a/pkg/dependency/parser/java/pom/parse_test.go b/pkg/dependency/parser/java/pom/parse_test.go index 9fa97ffd3672..82604846a4f3 100644 --- a/pkg/dependency/parser/java/pom/parse_test.go +++ b/pkg/dependency/parser/java/pom/parse_test.go @@ -809,6 +809,17 @@ func TestPom_Parse(t *testing.T) { Licenses: []string{"Apache 2.0"}, Relationship: ftypes.RelationshipRoot, }, + { + ID: "org.example:example-api", + Name: "org.example:example-api", + Relationship: ftypes.RelationshipDirect, + Locations: []ftypes.Location{ + { + StartLine: 28, + EndLine: 32, + }, + }, + }, }, }, { @@ -1499,6 +1510,30 @@ func TestPom_Parse(t *testing.T) { }, }, }, + { + name: "dependency without version", + inputFile: filepath.Join("testdata", "dep-without-version", "pom.xml"), + local: true, + want: []ftypes.Package{ + { + ID: "com.example:dep-without-version:1.0.0", + Name: "com.example:dep-without-version", + Version: "1.0.0", + Relationship: ftypes.RelationshipRoot, + }, + { + ID: "org.example:example-api", + Name: "org.example:example-api", + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ + { + StartLine: 19, + EndLine: 22, + }, + }, + }, + }, + }, // [INFO] com.example:root-depManagement-in-parent:jar:1.0.0 // [INFO] \- org.example:example-dependency:jar:2.0.0:compile // [INFO] \- org.example:example-api:jar:1.0.1:compile diff --git a/pkg/dependency/parser/java/pom/testdata/dep-without-version/pom.xml b/pkg/dependency/parser/java/pom/testdata/dep-without-version/pom.xml new file mode 100644 index 000000000000..d7da70dd4735 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/dep-without-version/pom.xml @@ -0,0 +1,24 @@ + + 4.0.0 + + no-parent + Parent not found + + + com.example + wrong-parent + 1.0.0 + + + com.example + dep-without-version + 1.0.0 + + + + org.example + example-api + + + diff --git a/pkg/fanal/analyzer/language/java/pom/pom_test.go b/pkg/fanal/analyzer/language/java/pom/pom_test.go index b3aaf43a82cf..ea147a4d1141 100644 --- a/pkg/fanal/analyzer/language/java/pom/pom_test.go +++ b/pkg/fanal/analyzer/language/java/pom/pom_test.go @@ -147,6 +147,17 @@ func Test_pomAnalyzer_Analyze(t *testing.T) { Licenses: []string{"Apache-2.0"}, Relationship: types.RelationshipRoot, }, + { + ID: "org.example:example-api", + Name: "org.example:example-api", + Relationship: types.RelationshipDirect, + Locations: []types.Location{ + { + StartLine: 21, + EndLine: 25, + }, + }, + }, }, }, }, From d4edeb5d62be55e01ab02387dd5f2206ffceb424 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Tue, 1 Oct 2024 08:27:02 +0400 Subject: [PATCH 111/183] test: use loaded image names (#7617) Signed-off-by: knqyf263 --- integration/docker_engine_test.go | 209 ++++++++------------- internal/testutil/docker.go | 57 ++++++ pkg/fanal/test/integration/library_test.go | 100 ++++------ 3 files changed, 178 insertions(+), 188 deletions(-) create mode 100644 internal/testutil/docker.go diff --git a/integration/docker_engine_test.go b/integration/docker_engine_test.go index 7f9a3119a156..a543d22e466f 100644 --- a/integration/docker_engine_test.go +++ b/integration/docker_engine_test.go @@ -1,19 +1,16 @@ //go:build integration -// +build integration package integration import ( "context" - "io" "os" "strings" "testing" + "github.com/aquasecurity/trivy/internal/testutil" "github.com/aquasecurity/trivy/pkg/types" - "github.com/docker/docker/api/types/image" - "github.com/docker/docker/client" "github.com/stretchr/testify/require" ) @@ -23,7 +20,6 @@ func TestDockerEngine(t *testing.T) { } tests := []struct { name string - imageTag string invalidImage bool ignoreUnfixed bool ignoreStatus []string @@ -34,10 +30,9 @@ func TestDockerEngine(t *testing.T) { wantErr string }{ { - name: "alpine:3.9", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:alpine-39", - input: "testdata/fixtures/images/alpine-39.tar.gz", - golden: "testdata/alpine-39.json.golden", + name: "alpine:3.9", + input: "testdata/fixtures/images/alpine-39.tar.gz", + golden: "testdata/alpine-39.json.golden", }, { name: "alpine:3.9, with high and critical severity", @@ -45,13 +40,11 @@ func TestDockerEngine(t *testing.T) { "HIGH", "CRITICAL", }, - imageTag: "ghcr.io/aquasecurity/trivy-test-images:alpine-39", - input: "testdata/fixtures/images/alpine-39.tar.gz", - golden: "testdata/alpine-39-high-critical.json.golden", + input: "testdata/fixtures/images/alpine-39.tar.gz", + golden: "testdata/alpine-39-high-critical.json.golden", }, { - name: "alpine:3.9, with .trivyignore", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:alpine-39", + name: "alpine:3.9, with .trivyignore", ignoreIDs: []string{ "CVE-2019-1549", "CVE-2019-14697", @@ -60,167 +53,141 @@ func TestDockerEngine(t *testing.T) { golden: "testdata/alpine-39-ignore-cveids.json.golden", }, { - name: "alpine:3.10", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:alpine-310", - input: "testdata/fixtures/images/alpine-310.tar.gz", - golden: "testdata/alpine-310.json.golden", + name: "alpine:3.10", + input: "testdata/fixtures/images/alpine-310.tar.gz", + golden: "testdata/alpine-310.json.golden", }, { - name: "amazonlinux:1", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:amazon-1", - input: "testdata/fixtures/images/amazon-1.tar.gz", - golden: "testdata/amazon-1.json.golden", + name: "amazonlinux:1", + input: "testdata/fixtures/images/amazon-1.tar.gz", + golden: "testdata/amazon-1.json.golden", }, { - name: "amazonlinux:2", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:amazon-2", - input: "testdata/fixtures/images/amazon-2.tar.gz", - golden: "testdata/amazon-2.json.golden", + name: "amazonlinux:2", + input: "testdata/fixtures/images/amazon-2.tar.gz", + golden: "testdata/amazon-2.json.golden", }, { - name: "almalinux 8", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:almalinux-8", - input: "testdata/fixtures/images/almalinux-8.tar.gz", - golden: "testdata/almalinux-8.json.golden", + name: "almalinux 8", + input: "testdata/fixtures/images/almalinux-8.tar.gz", + golden: "testdata/almalinux-8.json.golden", }, { - name: "rocky linux 8", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:rockylinux-8", - input: "testdata/fixtures/images/rockylinux-8.tar.gz", - golden: "testdata/rockylinux-8.json.golden", + name: "rocky linux 8", + input: "testdata/fixtures/images/rockylinux-8.tar.gz", + golden: "testdata/rockylinux-8.json.golden", }, { - name: "centos 6", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:centos-6", - input: "testdata/fixtures/images/centos-6.tar.gz", - golden: "testdata/centos-6.json.golden", + name: "centos 6", + input: "testdata/fixtures/images/centos-6.tar.gz", + golden: "testdata/centos-6.json.golden", }, { - name: "centos 7", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:centos-7", - input: "testdata/fixtures/images/centos-7.tar.gz", - golden: "testdata/centos-7.json.golden", + name: "centos 7", + input: "testdata/fixtures/images/centos-7.tar.gz", + golden: "testdata/centos-7.json.golden", }, { name: "centos 7, with --ignore-unfixed option", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:centos-7", ignoreUnfixed: true, input: "testdata/fixtures/images/centos-7.tar.gz", golden: "testdata/centos-7-ignore-unfixed.json.golden", }, { name: "centos 7, with --ignore-status option", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:centos-7", ignoreStatus: []string{"will_not_fix"}, input: "testdata/fixtures/images/centos-7.tar.gz", golden: "testdata/centos-7-ignore-unfixed.json.golden", }, { name: "centos 7, with --ignore-unfixed option, with medium severity", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:centos-7", ignoreUnfixed: true, severity: []string{"MEDIUM"}, input: "testdata/fixtures/images/centos-7.tar.gz", golden: "testdata/centos-7-medium.json.golden", }, { - name: "registry.redhat.io/ubi7", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:ubi-7", - input: "testdata/fixtures/images/ubi-7.tar.gz", - golden: "testdata/ubi-7.json.golden", + name: "registry.redhat.io/ubi7", + input: "testdata/fixtures/images/ubi-7.tar.gz", + golden: "testdata/ubi-7.json.golden", }, { - name: "debian buster/10", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:debian-buster", - input: "testdata/fixtures/images/debian-buster.tar.gz", - golden: "testdata/debian-buster.json.golden", + name: "debian buster/10", + input: "testdata/fixtures/images/debian-buster.tar.gz", + golden: "testdata/debian-buster.json.golden", }, { name: "debian buster/10, with --ignore-unfixed option", ignoreUnfixed: true, - imageTag: "ghcr.io/aquasecurity/trivy-test-images:debian-buster", input: "testdata/fixtures/images/debian-buster.tar.gz", golden: "testdata/debian-buster-ignore-unfixed.json.golden", }, { name: "debian buster/10, with --ignore-status option", ignoreStatus: []string{"affected"}, - imageTag: "ghcr.io/aquasecurity/trivy-test-images:debian-buster", input: "testdata/fixtures/images/debian-buster.tar.gz", golden: "testdata/debian-buster-ignore-unfixed.json.golden", }, { - name: "debian stretch/9", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:debian-stretch", - input: "testdata/fixtures/images/debian-stretch.tar.gz", - golden: "testdata/debian-stretch.json.golden", + name: "debian stretch/9", + input: "testdata/fixtures/images/debian-stretch.tar.gz", + golden: "testdata/debian-stretch.json.golden", }, { - name: "distroless base", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:distroless-base", - input: "testdata/fixtures/images/distroless-base.tar.gz", - golden: "testdata/distroless-base.json.golden", + name: "distroless base", + input: "testdata/fixtures/images/distroless-base.tar.gz", + golden: "testdata/distroless-base.json.golden", }, { - name: "distroless python2.7", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:distroless-python27", - input: "testdata/fixtures/images/distroless-python27.tar.gz", - golden: "testdata/distroless-python27.json.golden", + name: "distroless python2.7", + input: "testdata/fixtures/images/distroless-python27.tar.gz", + golden: "testdata/distroless-python27.json.golden", }, { - name: "oracle linux 8", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:oraclelinux-8", - input: "testdata/fixtures/images/oraclelinux-8.tar.gz", - golden: "testdata/oraclelinux-8.json.golden", + name: "oracle linux 8", + input: "testdata/fixtures/images/oraclelinux-8.tar.gz", + golden: "testdata/oraclelinux-8.json.golden", }, { - name: "ubuntu 18.04", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:ubuntu-1804", - input: "testdata/fixtures/images/ubuntu-1804.tar.gz", - golden: "testdata/ubuntu-1804.json.golden", + name: "ubuntu 18.04", + input: "testdata/fixtures/images/ubuntu-1804.tar.gz", + golden: "testdata/ubuntu-1804.json.golden", }, { name: "ubuntu 18.04, with --ignore-unfixed option", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:ubuntu-1804", ignoreUnfixed: true, input: "testdata/fixtures/images/ubuntu-1804.tar.gz", golden: "testdata/ubuntu-1804-ignore-unfixed.json.golden", }, { - name: "opensuse leap 15.1", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:opensuse-leap-151", - input: "testdata/fixtures/images/opensuse-leap-151.tar.gz", - golden: "testdata/opensuse-leap-151.json.golden", + name: "opensuse leap 15.1", + input: "testdata/fixtures/images/opensuse-leap-151.tar.gz", + golden: "testdata/opensuse-leap-151.json.golden", }, { - name: "opensuse tumbleweed", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:opensuse-tumbleweed", - input: "testdata/fixtures/images/opensuse-tumbleweed.tar.gz", - golden: "testdata/opensuse-tumbleweed.json.golden", + name: "opensuse tumbleweed", + input: "testdata/fixtures/images/opensuse-tumbleweed.tar.gz", + golden: "testdata/opensuse-tumbleweed.json.golden", }, { - name: "sle micro rancher 5.4", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:sle-micro-rancher-5.4_ndb", - input: "testdata/fixtures/images/sle-micro-rancher-5.4_ndb.tar.gz", - golden: "testdata/sl-micro-rancher5.4.json.golden", + name: "sle micro rancher 5.4", + input: "testdata/fixtures/images/sle-micro-rancher-5.4_ndb.tar.gz", + golden: "testdata/sl-micro-rancher5.4.json.golden", }, { - name: "photon 3.0", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:photon-30", - input: "testdata/fixtures/images/photon-30.tar.gz", - golden: "testdata/photon-30.json.golden", + name: "photon 3.0", + input: "testdata/fixtures/images/photon-30.tar.gz", + golden: "testdata/photon-30.json.golden", }, { - name: "CBL-Mariner 1.0", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:mariner-1.0", - input: "testdata/fixtures/images/mariner-1.0.tar.gz", - golden: "testdata/mariner-1.0.json.golden", + name: "CBL-Mariner 1.0", + input: "testdata/fixtures/images/mariner-1.0.tar.gz", + golden: "testdata/mariner-1.0.json.golden", }, { - name: "busybox with Cargo.lock", - imageTag: "ghcr.io/aquasecurity/trivy-test-images:busybox-with-lockfile", - input: "testdata/fixtures/images/busybox-with-lockfile.tar.gz", - golden: "testdata/busybox-with-lockfile.json.golden", + name: "busybox with Cargo.lock", + input: "testdata/fixtures/images/busybox-with-lockfile.tar.gz", + golden: "testdata/busybox-with-lockfile.json.golden", }, { name: "sad path, invalid image", @@ -239,44 +206,27 @@ func TestDockerEngine(t *testing.T) { ctx := context.Background() defer ctx.Done() - cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) - require.NoError(t, err) + cli := testutil.NewDockerClient(t) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if !tt.invalidImage { testfile, err := os.Open(tt.input) require.NoError(t, err, tt.name) + defer testfile.Close() - // ensure image doesnt already exists - _, _ = cli.ImageRemove(ctx, tt.input, image.RemoveOptions{ - Force: true, - PruneChildren: true, - }) + // Ensure image doesn't already exist + cli.ImageRemove(t, ctx, tt.input) - // load image into docker engine - res, err := cli.ImageLoad(ctx, testfile, true) - require.NoError(t, err, tt.name) - if _, err := io.Copy(io.Discard, res.Body); err != nil { - require.NoError(t, err, tt.name) - } - defer res.Body.Close() + // Load image into docker engine + loadedImage := cli.ImageLoad(t, ctx, tt.input) - // tag our image to something unique - err = cli.ImageTag(ctx, tt.imageTag, tt.input) + // Tag our image to something unique + err = cli.ImageTag(ctx, loadedImage, tt.input) require.NoError(t, err, tt.name) - // cleanup - t.Cleanup(func() { - _, _ = cli.ImageRemove(ctx, tt.input, image.RemoveOptions{ - Force: true, - PruneChildren: true, - }) - _, _ = cli.ImageRemove(ctx, tt.imageTag, image.RemoveOptions{ - Force: true, - PruneChildren: true, - }) - }) + // Cleanup + t.Cleanup(func() { cli.ImageRemove(t, ctx, tt.input) }) } osArgs := []string{ @@ -309,7 +259,7 @@ func TestDockerEngine(t *testing.T) { } if len(tt.ignoreIDs) != 0 { trivyIgnore := ".trivyignore" - err = os.WriteFile(trivyIgnore, []byte(strings.Join(tt.ignoreIDs, "\n")), 0444) + err := os.WriteFile(trivyIgnore, []byte(strings.Join(tt.ignoreIDs, "\n")), 0444) require.NoError(t, err, "failed to write .trivyignore") defer os.Remove(trivyIgnore) } @@ -320,7 +270,8 @@ func TestDockerEngine(t *testing.T) { wantErr: tt.wantErr, // Container field was removed in Docker Engine v26.0 // cf. https://github.com/docker/cli/blob/v26.1.3/docs/deprecated.md#container-and-containerconfig-fields-in-image-inspect - override: overrideFuncs(overrideUID, func(t *testing.T, want, _ *types.Report) { + override: overrideFuncs(overrideUID, func(t *testing.T, want, got *types.Report) { + got.Metadata.ImageConfig.Container = "" want.Metadata.ImageConfig.Container = "" }), }) diff --git a/internal/testutil/docker.go b/internal/testutil/docker.go new file mode 100644 index 000000000000..60e1bb3ab668 --- /dev/null +++ b/internal/testutil/docker.go @@ -0,0 +1,57 @@ +package testutil + +import ( + "context" + "encoding/json" + "os" + "strings" + "testing" + + "github.com/docker/docker/api/types/image" + "github.com/docker/docker/client" + "github.com/stretchr/testify/require" +) + +type DockerClient struct { + *client.Client +} + +func NewDockerClient(t *testing.T) *DockerClient { + cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) + require.NoError(t, err) + return &DockerClient{Client: cli} +} + +func (c *DockerClient) ImageLoad(t *testing.T, ctx context.Context, imageFile string) string { + t.Helper() + testfile, err := os.Open(imageFile) + require.NoError(t, err) + defer testfile.Close() + + // Load image into docker engine + res, err := c.Client.ImageLoad(ctx, testfile, true) + require.NoError(t, err) + defer res.Body.Close() + + // Parse the response and extract the loaded image name + var data struct { + Stream string `json:"stream"` + } + err = json.NewDecoder(res.Body).Decode(&data) + require.NoError(t, err) + loadedImage := strings.TrimPrefix(data.Stream, "Loaded image: ") + loadedImage = strings.TrimSpace(loadedImage) + require.NotEmpty(t, loadedImage, data.Stream) + + t.Cleanup(func() { c.ImageRemove(t, ctx, loadedImage) }) + + return loadedImage +} + +func (c *DockerClient) ImageRemove(t *testing.T, ctx context.Context, imageID string) { + t.Helper() + _, _ = c.Client.ImageRemove(ctx, imageID, image.RemoveOptions{ + Force: true, + PruneChildren: true, + }) +} diff --git a/pkg/fanal/test/integration/library_test.go b/pkg/fanal/test/integration/library_test.go index ea76c7965b3a..ebe17d6e2188 100644 --- a/pkg/fanal/test/integration/library_test.go +++ b/pkg/fanal/test/integration/library_test.go @@ -7,20 +7,13 @@ import ( "encoding/json" "flag" "fmt" - "io" "os" "sort" - "strings" "testing" - dimage "github.com/docker/docker/api/types/image" - "github.com/docker/docker/client" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/aquasecurity/trivy/pkg/fanal/analyzer" - + "github.com/aquasecurity/trivy/internal/testutil" "github.com/aquasecurity/trivy/pkg/cache" + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/all" "github.com/aquasecurity/trivy/pkg/fanal/applier" "github.com/aquasecurity/trivy/pkg/fanal/artifact" @@ -29,6 +22,9 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/image" "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + _ "modernc.org/sqlite" ) @@ -36,7 +32,7 @@ var update = flag.Bool("update", false, "update golden files") type testCase struct { name string - remoteImageName string + imageTag string imageFile string wantOS types.OS wantPkgsFromCmds string @@ -45,63 +41,63 @@ type testCase struct { var tests = []testCase{ { - name: "happy path, alpine:3.10", - remoteImageName: "ghcr.io/aquasecurity/trivy-test-images:alpine-310", - imageFile: "../../../../integration/testdata/fixtures/images/alpine-310.tar.gz", + name: "happy path, alpine:3.10", + imageTag: "alpine-310", + imageFile: "../../../../integration/testdata/fixtures/images/alpine-310.tar.gz", wantOS: types.OS{ Name: "3.10.2", Family: "alpine", }, }, { - name: "happy path, amazonlinux:2", - remoteImageName: "ghcr.io/aquasecurity/trivy-test-images:amazon-2", - imageFile: "../../../../integration/testdata/fixtures/images/amazon-2.tar.gz", + name: "happy path, amazonlinux:2", + imageTag: "amazon-2", + imageFile: "../../../../integration/testdata/fixtures/images/amazon-2.tar.gz", wantOS: types.OS{ Name: "2 (Karoo)", Family: "amazon", }, }, { - name: "happy path, debian:buster", - remoteImageName: "ghcr.io/aquasecurity/trivy-test-images:debian-buster", - imageFile: "../../../../integration/testdata/fixtures/images/debian-buster.tar.gz", + name: "happy path, debian:buster", + imageTag: "debian-buster", + imageFile: "../../../../integration/testdata/fixtures/images/debian-buster.tar.gz", wantOS: types.OS{ Name: "10.1", Family: "debian", }, }, { - name: "happy path, photon:3.0", - remoteImageName: "ghcr.io/aquasecurity/trivy-test-images:photon-30", - imageFile: "../../../../integration/testdata/fixtures/images/photon-30.tar.gz", + name: "happy path, photon:3.0", + imageTag: "photon-30", + imageFile: "../../../../integration/testdata/fixtures/images/photon-30.tar.gz", wantOS: types.OS{ Name: "3.0", Family: "photon", }, }, { - name: "happy path, registry.redhat.io/ubi7", - remoteImageName: "ghcr.io/aquasecurity/trivy-test-images:ubi-7", - imageFile: "../../../../integration/testdata/fixtures/images/ubi-7.tar.gz", + name: "happy path, registry.redhat.io/ubi7", + imageTag: "ubi-7", + imageFile: "../../../../integration/testdata/fixtures/images/ubi-7.tar.gz", wantOS: types.OS{ Name: "7.7", Family: "redhat", }, }, { - name: "happy path, opensuse leap 15.1", - remoteImageName: "ghcr.io/aquasecurity/trivy-test-images:opensuse-leap-151", - imageFile: "../../../../integration/testdata/fixtures/images/opensuse-leap-151.tar.gz", + name: "happy path, opensuse leap 15.1", + imageTag: "opensuse-leap-151", + imageFile: "../../../../integration/testdata/fixtures/images/opensuse-leap-151.tar.gz", wantOS: types.OS{ Name: "15.1", Family: "opensuse.leap", }, }, { - name: "happy path, opensuse tumbleweed", - remoteImageName: "ghcr.io/aquasecurity/trivy-test-images:opensuse-tumbleweed", - imageFile: "../../../../integration/testdata/fixtures/images/opensuse-tumbleweed.tar.gz", + name: "happy path, opensuse tumbleweed", + imageTag: "opensuse-tumbleweed", + imageFile: "../../../../integration/testdata/fixtures/images/opensuse-tumbleweed.tar.gz", wantOS: types.OS{ Name: "20240607", Family: "opensuse.tumbleweed", @@ -109,27 +105,27 @@ var tests = []testCase{ }, { // from registry.suse.com/suse/sle15:15.3.17.8.16 - name: "happy path, suse 15.3 (NDB)", - remoteImageName: "ghcr.io/aquasecurity/trivy-test-images:suse-15.3_ndb", - imageFile: "../../../../integration/testdata/fixtures/images/suse-15.3_ndb.tar.gz", + name: "happy path, suse 15.3 (NDB)", + imageTag: "suse-15.3_ndb", + imageFile: "../../../../integration/testdata/fixtures/images/suse-15.3_ndb.tar.gz", wantOS: types.OS{ Name: "15.3", Family: "suse linux enterprise server", }, }, { - name: "happy path, Fedora 35", - remoteImageName: "ghcr.io/aquasecurity/trivy-test-images:fedora-35", - imageFile: "../../../../integration/testdata/fixtures/images/fedora-35.tar.gz", + name: "happy path, Fedora 35", + imageTag: "fedora-35", + imageFile: "../../../../integration/testdata/fixtures/images/fedora-35.tar.gz", wantOS: types.OS{ Name: "35", Family: "fedora", }, }, { - name: "happy path, vulnimage with lock files", - remoteImageName: "ghcr.io/aquasecurity/trivy-test-images:vulnimage", - imageFile: "../../../../integration/testdata/fixtures/images/vulnimage.tar.gz", + name: "happy path, vulnimage with lock files", + imageTag: "vulnimage", + imageFile: "../../../../integration/testdata/fixtures/images/vulnimage.tar.gz", wantOS: types.OS{ Name: "3.7.1", Family: "alpine", @@ -145,6 +141,8 @@ func TestFanal_Library_DockerMode(t *testing.T) { if *update { t.Skipf("This test creates wrong golden file") } + + cli := testutil.NewDockerClient(t) for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ctx := context.Background() @@ -153,20 +151,10 @@ func TestFanal_Library_DockerMode(t *testing.T) { c, err := cache.NewFSCache(d) require.NoError(t, err) - cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation()) - require.NoError(t, err, tt.name) - - testfile, err := os.Open(tt.imageFile) - require.NoError(t, err) - - // load image into docker engine - resp, err := cli.ImageLoad(ctx, testfile, true) - require.NoError(t, err, tt.name) - _, err = io.Copy(io.Discard, resp.Body) - require.NoError(t, err, tt.name) + loadedImage := cli.ImageLoad(t, ctx, tt.imageFile) // Enable only dockerd scanning - img, cleanup, err := image.NewContainerImage(ctx, tt.remoteImageName, types.ImageOptions{ + img, cleanup, err := image.NewContainerImage(ctx, loadedImage, types.ImageOptions{ ImageSources: types.ImageSources{types.DockerImageSource}, }) require.NoError(t, err, tt.name) @@ -190,11 +178,6 @@ func TestFanal_Library_DockerMode(t *testing.T) { // clear Cache require.NoError(t, c.Clear(), tt.name) - - _, _ = cli.ImageRemove(ctx, tt.remoteImageName, dimage.RemoveOptions{ - Force: true, - PruneChildren: true, - }) }) } } @@ -249,8 +232,7 @@ func checkOSPackages(t *testing.T, detail types.ArtifactDetail, tc testCase) { // Sort OS packages for consistency sort.Sort(detail.Packages) - splitted := strings.Split(tc.remoteImageName, ":") - goldenFile := fmt.Sprintf("testdata/goldens/packages/%s.json.golden", splitted[len(splitted)-1]) + goldenFile := fmt.Sprintf("testdata/goldens/packages/%s.json.golden", tc.imageTag) if *update { b, err := json.MarshalIndent(detail.Packages, "", " ") From 7602d14654c2a4cca445439da7b93bfab4b6d872 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Tue, 1 Oct 2024 13:40:20 +0600 Subject: [PATCH 112/183] ci: don't use cache for `setup-go` (#7622) --- .github/workflows/auto-update-labels.yaml | 1 + .github/workflows/cache-test-images.yaml | 2 ++ .github/workflows/test.yaml | 8 ++++++++ 3 files changed, 11 insertions(+) diff --git a/.github/workflows/auto-update-labels.yaml b/.github/workflows/auto-update-labels.yaml index 941e7b5db9df..0de6e41438b9 100644 --- a/.github/workflows/auto-update-labels.yaml +++ b/.github/workflows/auto-update-labels.yaml @@ -20,6 +20,7 @@ jobs: with: # cf. https://github.com/aquasecurity/trivy/pull/6711 go-version: ${{ env.GO_VERSION }} + cache: false - name: Install aqua tools uses: aquaproj/aqua-installer@v3.0.1 diff --git a/.github/workflows/cache-test-images.yaml b/.github/workflows/cache-test-images.yaml index da8aff10cfd2..a03dc683e3ae 100644 --- a/.github/workflows/cache-test-images.yaml +++ b/.github/workflows/cache-test-images.yaml @@ -16,6 +16,7 @@ jobs: uses: actions/setup-go@v5 with: go-version-file: go.mod + cache: false - name: Install tools uses: aquaproj/aqua-installer@v3.0.1 @@ -55,6 +56,7 @@ jobs: uses: actions/setup-go@v5 with: go-version-file: go.mod + cache: false - name: Install tools uses: aquaproj/aqua-installer@v3.0.1 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index b423b61699fb..74b0933c6ef6 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -26,6 +26,8 @@ jobs: uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} + cache: false + - name: go mod tidy run: | go mod tidy @@ -78,6 +80,7 @@ jobs: uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} + cache: false - name: Install tools uses: aquaproj/aqua-installer@v3.0.1 @@ -113,6 +116,7 @@ jobs: uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} + cache: false - name: Install tools uses: aquaproj/aqua-installer@v3.0.1 @@ -133,6 +137,7 @@ jobs: uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} + cache: false - name: Install tools uses: aquaproj/aqua-installer@v3.0.1 @@ -170,6 +175,8 @@ jobs: uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} + cache: false + - name: Install tools uses: aquaproj/aqua-installer@v3.0.1 with: @@ -210,6 +217,7 @@ jobs: uses: actions/setup-go@v5 with: go-version: ${{ env.GO_VERSION }} + cache: false - name: Determine GoReleaser ID id: goreleaser_id From 3562529ddfb26d301311ed450c192e17011353df Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Tue, 1 Oct 2024 19:16:06 +0600 Subject: [PATCH 113/183] feat: support multiple DB repositories for vulnerability and Java DB (#7605) Signed-off-by: nikpivkin --- .../configuration/cli/trivy_filesystem.md | 4 +- .../configuration/cli/trivy_image.md | 4 +- .../configuration/cli/trivy_kubernetes.md | 4 +- .../configuration/cli/trivy_repository.md | 4 +- .../configuration/cli/trivy_rootfs.md | 4 +- .../configuration/cli/trivy_sbom.md | 96 +++++++++---------- .../configuration/cli/trivy_server.md | 2 +- .../references/configuration/cli/trivy_vm.md | 4 +- .../references/configuration/config-file.md | 6 +- internal/dbtest/fake.go | 2 +- pkg/commands/app.go | 2 +- pkg/commands/artifact/run.go | 4 +- pkg/commands/operation/operation.go | 5 +- pkg/commands/server/run.go | 4 +- pkg/db/db.go | 52 +++++----- pkg/db/db_test.go | 2 +- pkg/fanal/analyzer/analyzer_test.go | 4 +- .../analyzer/language/java/jar/jar_test.go | 4 +- pkg/fanal/artifact/image/remote_sbom.go | 3 +- pkg/flag/db_flags.go | 80 +++++++++------- pkg/flag/db_flags_test.go | 72 +++++++++----- pkg/javadb/client.go | 34 ++++--- pkg/module/command.go | 4 +- pkg/oci/artifact.go | 67 +++++++++++-- pkg/oci/artifact_test.go | 3 +- pkg/policy/policy.go | 6 +- pkg/policy/policy_test.go | 6 +- pkg/rpc/server/listen.go | 22 ++--- 28 files changed, 301 insertions(+), 203 deletions(-) diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index e907c5d4f9d5..9944a2d618ff 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -29,7 +29,7 @@ trivy filesystem [flags] PATH --config-data strings specify paths from which data for the Rego checks will be recursively loaded --config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking --custom-headers strings custom headers in client mode - --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") + --db-repository strings OCI repository(ies) to retrieve trivy-db in order of priority (default [ghcr.io/aquasecurity/trivy-db:2]) --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages --detection-priority string specify the detection priority: - "precise": Prioritizes precise by minimizing false positives. @@ -56,7 +56,7 @@ trivy filesystem [flags] PATH --include-deprecated-checks include deprecated checks (default true) --include-dev-deps include development dependencies in the report (supported: npm, yarn) --include-non-failures include successes and exceptions, available with '--scanners misconfig' - --java-db-repository string OCI repository to retrieve trivy-java-db from (default "ghcr.io/aquasecurity/trivy-java-db:1") + --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [ghcr.io/aquasecurity/trivy-java-db:1]) --license-confidence-level float specify license classifier's confidence level (default 0.9) --license-full eagerly look for licenses in source code headers and license files --list-all-pkgs output all packages in the JSON report regardless of vulnerability diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index 156582f047ad..b63daffbf4ad 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -43,7 +43,7 @@ trivy image [flags] IMAGE_NAME --config-data strings specify paths from which data for the Rego checks will be recursively loaded --config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking --custom-headers strings custom headers in client mode - --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") + --db-repository strings OCI repository(ies) to retrieve trivy-db in order of priority (default [ghcr.io/aquasecurity/trivy-db:2]) --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages --detection-priority string specify the detection priority: - "precise": Prioritizes precise by minimizing false positives. @@ -74,7 +74,7 @@ trivy image [flags] IMAGE_NAME --include-deprecated-checks include deprecated checks (default true) --include-non-failures include successes and exceptions, available with '--scanners misconfig' --input string input file path instead of image name - --java-db-repository string OCI repository to retrieve trivy-java-db from (default "ghcr.io/aquasecurity/trivy-java-db:1") + --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [ghcr.io/aquasecurity/trivy-java-db:1]) --license-confidence-level float specify license classifier's confidence level (default 0.9) --license-full eagerly look for licenses in source code headers and license files --list-all-pkgs output all packages in the JSON report regardless of vulnerability diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index b7c626a7d476..35190b1b82b5 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -38,7 +38,7 @@ trivy kubernetes [flags] [CONTEXT] --config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files --config-data strings specify paths from which data for the Rego checks will be recursively loaded --config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking - --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") + --db-repository strings OCI repository(ies) to retrieve trivy-db in order of priority (default [ghcr.io/aquasecurity/trivy-db:2]) --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages --detection-priority string specify the detection priority: - "precise": Prioritizes precise by minimizing false positives. @@ -70,7 +70,7 @@ trivy kubernetes [flags] [CONTEXT] --include-kinds strings indicate the kinds included in scanning (example: node) --include-namespaces strings indicate the namespaces included in scanning (example: kube-system) --include-non-failures include successes and exceptions, available with '--scanners misconfig' - --java-db-repository string OCI repository to retrieve trivy-java-db from (default "ghcr.io/aquasecurity/trivy-java-db:1") + --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [ghcr.io/aquasecurity/trivy-java-db:1]) --k8s-version string specify k8s version to validate outdated api by it (example: 1.21.0) --kubeconfig string specify the kubeconfig file path to use --list-all-pkgs output all packages in the JSON report regardless of vulnerability diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index 04f3f26e919a..59e4f2c08cb0 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -29,7 +29,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --config-data strings specify paths from which data for the Rego checks will be recursively loaded --config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking --custom-headers strings custom headers in client mode - --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") + --db-repository strings OCI repository(ies) to retrieve trivy-db in order of priority (default [ghcr.io/aquasecurity/trivy-db:2]) --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages --detection-priority string specify the detection priority: - "precise": Prioritizes precise by minimizing false positives. @@ -56,7 +56,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --include-deprecated-checks include deprecated checks (default true) --include-dev-deps include development dependencies in the report (supported: npm, yarn) --include-non-failures include successes and exceptions, available with '--scanners misconfig' - --java-db-repository string OCI repository to retrieve trivy-java-db from (default "ghcr.io/aquasecurity/trivy-java-db:1") + --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [ghcr.io/aquasecurity/trivy-java-db:1]) --license-confidence-level float specify license classifier's confidence level (default 0.9) --license-full eagerly look for licenses in source code headers and license files --list-all-pkgs output all packages in the JSON report regardless of vulnerability diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index 0e0dfa54d448..6022f4589446 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -31,7 +31,7 @@ trivy rootfs [flags] ROOTDIR --config-data strings specify paths from which data for the Rego checks will be recursively loaded --config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking --custom-headers strings custom headers in client mode - --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") + --db-repository strings OCI repository(ies) to retrieve trivy-db in order of priority (default [ghcr.io/aquasecurity/trivy-db:2]) --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages --detection-priority string specify the detection priority: - "precise": Prioritizes precise by minimizing false positives. @@ -58,7 +58,7 @@ trivy rootfs [flags] ROOTDIR --ignorefile string specify .trivyignore file (default ".trivyignore") --include-deprecated-checks include deprecated checks (default true) --include-non-failures include successes and exceptions, available with '--scanners misconfig' - --java-db-repository string OCI repository to retrieve trivy-java-db from (default "ghcr.io/aquasecurity/trivy-java-db:1") + --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [ghcr.io/aquasecurity/trivy-java-db:1]) --license-confidence-level float specify license classifier's confidence level (default 0.9) --license-full eagerly look for licenses in source code headers and license files --list-all-pkgs output all packages in the JSON report regardless of vulnerability diff --git a/docs/docs/references/configuration/cli/trivy_sbom.md b/docs/docs/references/configuration/cli/trivy_sbom.md index 1b0df922c7fc..f09453845518 100644 --- a/docs/docs/references/configuration/cli/trivy_sbom.md +++ b/docs/docs/references/configuration/cli/trivy_sbom.md @@ -20,54 +20,54 @@ trivy sbom [flags] SBOM_PATH ### Options ``` - --cache-backend string [EXPERIMENTAL] cache backend (e.g. redis://localhost:6379) (default "memory") - --cache-ttl duration cache TTL when using redis as cache backend - --compliance string compliance report to generate - --custom-headers strings custom headers in client mode - --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") - --detection-priority string specify the detection priority: - - "precise": Prioritizes precise by minimizing false positives. - - "comprehensive": Aims to detect more security findings at the cost of potential false positives. - (precise,comprehensive) (default "precise") - --download-db-only download/update vulnerability database but don't run a scan - --download-java-db-only download/update Java index database but don't run a scan - --exit-code int specify exit code when any security issues are found - --exit-on-eol int exit with the specified code when the OS reaches end of service/life - --file-patterns strings specify config file patterns - -f, --format string format (table,json,template,sarif,cyclonedx,spdx,spdx-json,github,cosign-vuln) (default "table") - -h, --help help for sbom - --ignore-policy string specify the Rego file path to evaluate each vulnerability - --ignore-status strings comma-separated list of vulnerability status to ignore (unknown,not_affected,affected,fixed,under_investigation,will_not_fix,fix_deferred,end_of_life) - --ignore-unfixed display only fixed vulnerabilities - --ignored-licenses strings specify a list of license to ignore - --ignorefile string specify .trivyignore file (default ".trivyignore") - --java-db-repository string OCI repository to retrieve trivy-java-db from (default "ghcr.io/aquasecurity/trivy-java-db:1") - --list-all-pkgs output all packages in the JSON report regardless of vulnerability - --no-progress suppress progress bar - --offline-scan do not issue API requests to identify dependencies - -o, --output string output file name - --output-plugin-arg string [EXPERIMENTAL] output plugin arguments - --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) - --pkg-types strings list of package types (os,library) (default [os,library]) - --redis-ca string redis ca file location, if using redis as cache backend - --redis-cert string redis certificate file location, if using redis as cache backend - --redis-key string redis key file location, if using redis as cache backend - --redis-tls enable redis TLS with public certificates, if using redis as cache backend - --rekor-url string [EXPERIMENTAL] address of rekor STL server (default "https://rekor.sigstore.dev") - --sbom-sources strings [EXPERIMENTAL] try to retrieve SBOM from the specified sources (oci,rekor) - --scanners strings comma-separated list of what security issues to detect (vuln,license) (default [vuln]) - --server string server address in client mode - -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) - --show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities - --skip-db-update skip updating vulnerability database - --skip-dirs strings specify the directories or glob patterns to skip - --skip-files strings specify the files or glob patterns to skip - --skip-java-db-update skip updating Java index database - --skip-vex-repo-update [EXPERIMENTAL] Skip VEX Repository update - -t, --template string output template - --token string for authentication in client/server mode - --token-header string specify a header name for token in client/server mode (default "Trivy-Token") - --vex strings [EXPERIMENTAL] VEX sources ("repo", "oci" or file path) + --cache-backend string [EXPERIMENTAL] cache backend (e.g. redis://localhost:6379) (default "memory") + --cache-ttl duration cache TTL when using redis as cache backend + --compliance string compliance report to generate + --custom-headers strings custom headers in client mode + --db-repository strings OCI repository(ies) to retrieve trivy-db in order of priority (default [ghcr.io/aquasecurity/trivy-db:2]) + --detection-priority string specify the detection priority: + - "precise": Prioritizes precise by minimizing false positives. + - "comprehensive": Aims to detect more security findings at the cost of potential false positives. + (precise,comprehensive) (default "precise") + --download-db-only download/update vulnerability database but don't run a scan + --download-java-db-only download/update Java index database but don't run a scan + --exit-code int specify exit code when any security issues are found + --exit-on-eol int exit with the specified code when the OS reaches end of service/life + --file-patterns strings specify config file patterns + -f, --format string format (table,json,template,sarif,cyclonedx,spdx,spdx-json,github,cosign-vuln) (default "table") + -h, --help help for sbom + --ignore-policy string specify the Rego file path to evaluate each vulnerability + --ignore-status strings comma-separated list of vulnerability status to ignore (unknown,not_affected,affected,fixed,under_investigation,will_not_fix,fix_deferred,end_of_life) + --ignore-unfixed display only fixed vulnerabilities + --ignored-licenses strings specify a list of license to ignore + --ignorefile string specify .trivyignore file (default ".trivyignore") + --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [ghcr.io/aquasecurity/trivy-java-db:1]) + --list-all-pkgs output all packages in the JSON report regardless of vulnerability + --no-progress suppress progress bar + --offline-scan do not issue API requests to identify dependencies + -o, --output string output file name + --output-plugin-arg string [EXPERIMENTAL] output plugin arguments + --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) + --pkg-types strings list of package types (os,library) (default [os,library]) + --redis-ca string redis ca file location, if using redis as cache backend + --redis-cert string redis certificate file location, if using redis as cache backend + --redis-key string redis key file location, if using redis as cache backend + --redis-tls enable redis TLS with public certificates, if using redis as cache backend + --rekor-url string [EXPERIMENTAL] address of rekor STL server (default "https://rekor.sigstore.dev") + --sbom-sources strings [EXPERIMENTAL] try to retrieve SBOM from the specified sources (oci,rekor) + --scanners strings comma-separated list of what security issues to detect (vuln,license) (default [vuln]) + --server string server address in client mode + -s, --severity strings severities of security issues to be displayed (UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL) (default [UNKNOWN,LOW,MEDIUM,HIGH,CRITICAL]) + --show-suppressed [EXPERIMENTAL] show suppressed vulnerabilities + --skip-db-update skip updating vulnerability database + --skip-dirs strings specify the directories or glob patterns to skip + --skip-files strings specify the files or glob patterns to skip + --skip-java-db-update skip updating Java index database + --skip-vex-repo-update [EXPERIMENTAL] Skip VEX Repository update + -t, --template string output template + --token string for authentication in client/server mode + --token-header string specify a header name for token in client/server mode (default "Trivy-Token") + --vex strings [EXPERIMENTAL] VEX sources ("repo", "oci" or file path) ``` ### Options inherited from parent commands diff --git a/docs/docs/references/configuration/cli/trivy_server.md b/docs/docs/references/configuration/cli/trivy_server.md index 4291496e34f1..b7ada8f2c19b 100644 --- a/docs/docs/references/configuration/cli/trivy_server.md +++ b/docs/docs/references/configuration/cli/trivy_server.md @@ -22,7 +22,7 @@ trivy server [flags] ``` --cache-backend string [EXPERIMENTAL] cache backend (e.g. redis://localhost:6379) (default "fs") --cache-ttl duration cache TTL when using redis as cache backend - --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") + --db-repository strings OCI repository(ies) to retrieve trivy-db in order of priority (default [ghcr.io/aquasecurity/trivy-db:2]) --download-db-only download/update vulnerability database but don't run a scan --enable-modules strings [EXPERIMENTAL] module names to enable -h, --help help for server diff --git a/docs/docs/references/configuration/cli/trivy_vm.md b/docs/docs/references/configuration/cli/trivy_vm.md index fef17624222d..9b7f6a6fef43 100644 --- a/docs/docs/references/configuration/cli/trivy_vm.md +++ b/docs/docs/references/configuration/cli/trivy_vm.md @@ -27,7 +27,7 @@ trivy vm [flags] VM_IMAGE --compliance string compliance report to generate --config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking --custom-headers strings custom headers in client mode - --db-repository string OCI repository to retrieve trivy-db from (default "ghcr.io/aquasecurity/trivy-db:2") + --db-repository strings OCI repository(ies) to retrieve trivy-db in order of priority (default [ghcr.io/aquasecurity/trivy-db:2]) --dependency-tree [EXPERIMENTAL] show dependency origin tree of vulnerable packages --detection-priority string specify the detection priority: - "precise": Prioritizes precise by minimizing false positives. @@ -52,7 +52,7 @@ trivy vm [flags] VM_IMAGE --ignore-unfixed display only fixed vulnerabilities --ignorefile string specify .trivyignore file (default ".trivyignore") --include-non-failures include successes and exceptions, available with '--scanners misconfig' - --java-db-repository string OCI repository to retrieve trivy-java-db from (default "ghcr.io/aquasecurity/trivy-java-db:1") + --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [ghcr.io/aquasecurity/trivy-java-db:1]) --list-all-pkgs output all packages in the JSON report regardless of vulnerability --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") diff --git a/docs/docs/references/configuration/config-file.md b/docs/docs/references/configuration/config-file.md index b2b25e47689e..ae3a017fda05 100644 --- a/docs/docs/references/configuration/config-file.md +++ b/docs/docs/references/configuration/config-file.md @@ -104,7 +104,8 @@ db: download-only: false # Same as '--java-db-repository' - java-repository: "ghcr.io/aquasecurity/trivy-java-db:1" + java-repository: + - ghcr.io/aquasecurity/trivy-java-db:1 # Same as '--skip-java-db-update' java-skip-update: false @@ -113,7 +114,8 @@ db: no-progress: false # Same as '--db-repository' - repository: "ghcr.io/aquasecurity/trivy-db:2" + repository: + - ghcr.io/aquasecurity/trivy-db:2 # Same as '--skip-db-update' skip-update: false diff --git a/internal/dbtest/fake.go b/internal/dbtest/fake.go index 7943c72273e2..528c549bda7f 100644 --- a/internal/dbtest/fake.go +++ b/internal/dbtest/fake.go @@ -62,7 +62,7 @@ func NewFakeDB(t *testing.T, dbPath string, opts FakeDBOptions) *oci.Artifact { opt := ftypes.RegistryOptions{ Insecure: false, } - return oci.NewArtifact("dummy", true, opt, oci.WithImage(img)) + return oci.NewArtifact("dummy", opt, oci.WithImage(img)) } func ArchiveDir(t *testing.T, dir string) string { diff --git a/pkg/commands/app.go b/pkg/commands/app.go index a3fb6df353d9..23b44fdec553 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -624,7 +624,7 @@ func NewServerCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { // java-db only works on client side. serverFlags.DBFlagGroup.DownloadJavaDBOnly = nil // disable '--download-java-db-only' serverFlags.DBFlagGroup.SkipJavaDBUpdate = nil // disable '--skip-java-db-update' - serverFlags.DBFlagGroup.JavaDBRepository = nil // disable '--java-db-repository' + serverFlags.DBFlagGroup.JavaDBRepositories = nil // disable '--java-db-repository' cmd := &cobra.Command{ Use: "server [flags]", diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index fa454c0cd276..11c6ef6a3090 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -291,7 +291,7 @@ func (r *runner) initDB(ctx context.Context, opts flag.Options) error { // download the database file noProgress := opts.Quiet || opts.NoProgress - if err := operation.DownloadDB(ctx, opts.AppVersion, opts.CacheDir, opts.DBRepository, noProgress, opts.SkipDBUpdate, opts.RegistryOpts()); err != nil { + if err := operation.DownloadDB(ctx, opts.AppVersion, opts.CacheDir, opts.DBRepositories, noProgress, opts.SkipDBUpdate, opts.RegistryOpts()); err != nil { return err } @@ -321,7 +321,7 @@ func (r *runner) initJavaDB(opts flag.Options) error { // Update the Java DB noProgress := opts.Quiet || opts.NoProgress - javadb.Init(opts.CacheDir, opts.JavaDBRepository, opts.SkipJavaDBUpdate, noProgress, opts.RegistryOpts()) + javadb.Init(opts.CacheDir, opts.JavaDBRepositories, opts.SkipJavaDBUpdate, noProgress, opts.RegistryOpts()) if opts.DownloadJavaDBOnly { if err := javadb.Update(); err != nil { return xerrors.Errorf("Java DB error: %w", err) diff --git a/pkg/commands/operation/operation.go b/pkg/commands/operation/operation.go index 16aa72085949..7570c4393b69 100644 --- a/pkg/commands/operation/operation.go +++ b/pkg/commands/operation/operation.go @@ -21,14 +21,14 @@ import ( var mu sync.Mutex // DownloadDB downloads the DB -func DownloadDB(ctx context.Context, appVersion, cacheDir string, dbRepository name.Reference, quiet, skipUpdate bool, +func DownloadDB(ctx context.Context, appVersion, cacheDir string, dbRepositories []name.Reference, quiet, skipUpdate bool, opt ftypes.RegistryOptions) error { mu.Lock() defer mu.Unlock() ctx = log.WithContextPrefix(ctx, "db") dbDir := db.Dir(cacheDir) - client := db.NewClient(dbDir, quiet, db.WithDBRepository(dbRepository)) + client := db.NewClient(dbDir, quiet, db.WithDBRepository(dbRepositories)) needsUpdate, err := client.NeedsUpdate(ctx, appVersion, skipUpdate) if err != nil { return xerrors.Errorf("database error: %w", err) @@ -36,7 +36,6 @@ func DownloadDB(ctx context.Context, appVersion, cacheDir string, dbRepository n if needsUpdate { log.InfoContext(ctx, "Need to update DB") - log.InfoContext(ctx, "Downloading DB...", log.String("repository", dbRepository.String())) if err = client.Download(ctx, dbDir, opt); err != nil { return xerrors.Errorf("failed to download vulnerability DB: %w", err) } diff --git a/pkg/commands/server/run.go b/pkg/commands/server/run.go index 6c5316d7465a..e9187b3442f5 100644 --- a/pkg/commands/server/run.go +++ b/pkg/commands/server/run.go @@ -26,7 +26,7 @@ func Run(ctx context.Context, opts flag.Options) (err error) { defer cleanup() // download the database file - if err = operation.DownloadDB(ctx, opts.AppVersion, opts.CacheDir, opts.DBRepository, + if err = operation.DownloadDB(ctx, opts.AppVersion, opts.CacheDir, opts.DBRepositories, true, opts.SkipDBUpdate, opts.RegistryOpts()); err != nil { return err } @@ -50,6 +50,6 @@ func Run(ctx context.Context, opts flag.Options) (err error) { m.Register() server := rpcServer.NewServer(opts.AppVersion, opts.Listen, opts.CacheDir, opts.Token, opts.TokenHeader, - opts.PathPrefix, opts.DBRepository, opts.RegistryOpts()) + opts.PathPrefix, opts.DBRepositories, opts.RegistryOpts()) return server.ListenAndServe(ctx, cacheClient, opts.SkipDBUpdate) } diff --git a/pkg/db/db.go b/pkg/db/db.go index 344b21b86e44..f7ceb09af4c9 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -2,14 +2,13 @@ package db import ( "context" - "errors" "fmt" "os" "path/filepath" "time" "github.com/google/go-containerregistry/pkg/name" - "github.com/google/go-containerregistry/pkg/v1/remote/transport" + "github.com/samber/lo" "golang.org/x/xerrors" "github.com/aquasecurity/trivy-db/pkg/db" @@ -18,7 +17,6 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/types" "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/oci" - "github.com/aquasecurity/trivy/pkg/version/doc" ) const ( @@ -27,8 +25,9 @@ const ( ) var ( - DefaultRepository = fmt.Sprintf("%s:%d", "ghcr.io/aquasecurity/trivy-db", db.SchemaVersion) - defaultRepository, _ = name.NewTag(DefaultRepository) + // GitHub Container Registry + DefaultGHCRRepository = fmt.Sprintf("%s:%d", "ghcr.io/aquasecurity/trivy-db", db.SchemaVersion) + defaultGHCRRepository = lo.Must(name.NewTag(DefaultGHCRRepository)) Init = db.Init Close = db.Close @@ -36,8 +35,8 @@ var ( ) type options struct { - artifact *oci.Artifact - dbRepository name.Reference + artifact *oci.Artifact + dbRepositories []name.Reference } // Option is a functional option @@ -51,9 +50,9 @@ func WithOCIArtifact(art *oci.Artifact) Option { } // WithDBRepository takes a dbRepository -func WithDBRepository(dbRepository name.Reference) Option { +func WithDBRepository(dbRepository []name.Reference) Option { return func(opts *options) { - opts.dbRepository = dbRepository + opts.dbRepositories = dbRepository } } @@ -73,7 +72,9 @@ func Dir(cacheDir string) string { // NewClient is the factory method for DB client func NewClient(dbDir string, quiet bool, opts ...Option) *Client { o := &options{ - dbRepository: defaultRepository, + dbRepositories: []name.Reference{ + defaultGHCRRepository, + }, } for _, opt := range opts { @@ -153,20 +154,8 @@ func (c *Client) Download(ctx context.Context, dst string, opt types.RegistryOpt log.Debug("No metadata file") } - art := c.initOCIArtifact(opt) - if err := art.Download(ctx, dst, oci.DownloadOption{MediaType: dbMediaType}); err != nil { - var terr *transport.Error - if errors.As(err, &terr) { - for _, diagnostic := range terr.Errors { - // For better user experience - if diagnostic.Code == transport.DeniedErrorCode || diagnostic.Code == transport.UnauthorizedErrorCode { - // e.g. https://aquasecurity.github.io/trivy/latest/docs/references/troubleshooting/#db - log.Warnf("See %s", doc.URL("/docs/references/troubleshooting/", "db")) - break - } - } - } - return xerrors.Errorf("database download error: %w", err) + if err := c.downloadDB(ctx, opt, dst); err != nil { + return xerrors.Errorf("OCI artifact error: %w", err) } if err := c.updateDownloadedAt(ctx, dst); err != nil { @@ -201,11 +190,20 @@ func (c *Client) updateDownloadedAt(ctx context.Context, dbDir string) error { return nil } -func (c *Client) initOCIArtifact(opt types.RegistryOptions) *oci.Artifact { +func (c *Client) initArtifacts(opt types.RegistryOptions) oci.Artifacts { if c.artifact != nil { - return c.artifact + return oci.Artifacts{c.artifact} } - return oci.NewArtifact(c.dbRepository.String(), c.quiet, opt) + return oci.NewArtifacts(c.dbRepositories, opt) +} + +func (c *Client) downloadDB(ctx context.Context, opt types.RegistryOptions, dst string) error { + log.Info("Downloading vulnerability DB...") + downloadOpt := oci.DownloadOption{MediaType: dbMediaType, Quiet: c.quiet} + if err := c.initArtifacts(opt).Download(ctx, dst, downloadOpt); err != nil { + return xerrors.Errorf("failed to download vulnerability DB: %w", err) + } + return nil } func (c *Client) ShowInfo() error { diff --git a/pkg/db/db_test.go b/pkg/db/db_test.go index ff5e36e2b194..f64c0dc4a5c6 100644 --- a/pkg/db/db_test.go +++ b/pkg/db/db_test.go @@ -159,7 +159,7 @@ func TestClient_Download(t *testing.T) { { name: "invalid gzip", input: "testdata/trivy.db", - wantErr: "unexpected EOF", + wantErr: "OCI artifact error: failed to download vulnerability DB", }, } diff --git a/pkg/fanal/analyzer/analyzer_test.go b/pkg/fanal/analyzer/analyzer_test.go index 313fccda7e94..d8f93c0aa420 100644 --- a/pkg/fanal/analyzer/analyzer_test.go +++ b/pkg/fanal/analyzer/analyzer_test.go @@ -623,9 +623,9 @@ func TestAnalyzerGroup_PostAnalyze(t *testing.T) { if tt.analyzerType == analyzer.TypeJar { // init java-trivy-db with skip update - repo, err := name.NewTag(javadb.DefaultRepository) + repo, err := name.NewTag(javadb.DefaultGHCRRepository) require.NoError(t, err) - javadb.Init("./language/java/jar/testdata", repo, true, false, types.RegistryOptions{Insecure: false}) + javadb.Init("./language/java/jar/testdata", []name.Reference{repo}, true, false, types.RegistryOptions{Insecure: false}) } ctx := context.Background() diff --git a/pkg/fanal/analyzer/language/java/jar/jar_test.go b/pkg/fanal/analyzer/language/java/jar/jar_test.go index 225737166c81..146b60c1bbd6 100644 --- a/pkg/fanal/analyzer/language/java/jar/jar_test.go +++ b/pkg/fanal/analyzer/language/java/jar/jar_test.go @@ -132,9 +132,9 @@ func Test_javaLibraryAnalyzer_Analyze(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { // init java-trivy-db with skip update - repo, err := name.NewTag(javadb.DefaultRepository) + repo, err := name.NewTag(javadb.DefaultGHCRRepository) require.NoError(t, err) - javadb.Init("testdata", repo, true, false, types.RegistryOptions{Insecure: false}) + javadb.Init("testdata", []name.Reference{repo}, true, false, types.RegistryOptions{Insecure: false}) a := javaLibraryAnalyzer{} ctx := context.Background() diff --git a/pkg/fanal/artifact/image/remote_sbom.go b/pkg/fanal/artifact/image/remote_sbom.go index e95fef23140c..d07d9cafe3ac 100644 --- a/pkg/fanal/artifact/image/remote_sbom.go +++ b/pkg/fanal/artifact/image/remote_sbom.go @@ -95,10 +95,11 @@ func (a Artifact) parseReferrer(ctx context.Context, repo string, desc v1.Descri defer os.RemoveAll(tmpDir) // Download SBOM to local filesystem - referrer := oci.NewArtifact(repoName, true, a.artifactOption.ImageOption.RegistryOptions) + referrer := oci.NewArtifact(repoName, a.artifactOption.ImageOption.RegistryOptions) if err = referrer.Download(ctx, tmpDir, oci.DownloadOption{ MediaType: desc.ArtifactType, Filename: fileName, + Quiet: true, }); err != nil { return artifact.Reference{}, xerrors.Errorf("SBOM download error: %w", err) } diff --git a/pkg/flag/db_flags.go b/pkg/flag/db_flags.go index 352a0094be7c..df0d6c6f5194 100644 --- a/pkg/flag/db_flags.go +++ b/pkg/flag/db_flags.go @@ -50,17 +50,17 @@ var ( ConfigName: "db.no-progress", Usage: "suppress progress bar", } - DBRepositoryFlag = Flag[string]{ + DBRepositoryFlag = Flag[[]string]{ Name: "db-repository", ConfigName: "db.repository", - Default: db.DefaultRepository, - Usage: "OCI repository to retrieve trivy-db from", + Default: []string{db.DefaultGHCRRepository}, + Usage: "OCI repository(ies) to retrieve trivy-db in order of priority", } - JavaDBRepositoryFlag = Flag[string]{ + JavaDBRepositoryFlag = Flag[[]string]{ Name: "java-db-repository", ConfigName: "db.java-repository", - Default: javadb.DefaultRepository, - Usage: "OCI repository to retrieve trivy-java-db from", + Default: []string{javadb.DefaultGHCRRepository}, + Usage: "OCI repository(ies) to retrieve trivy-java-db in order of priority", } LightFlag = Flag[bool]{ Name: "light", @@ -78,8 +78,8 @@ type DBFlagGroup struct { DownloadJavaDBOnly *Flag[bool] SkipJavaDBUpdate *Flag[bool] NoProgress *Flag[bool] - DBRepository *Flag[string] - JavaDBRepository *Flag[string] + DBRepositories *Flag[[]string] + JavaDBRepositories *Flag[[]string] Light *Flag[bool] // deprecated } @@ -90,8 +90,8 @@ type DBOptions struct { DownloadJavaDBOnly bool SkipJavaDBUpdate bool NoProgress bool - DBRepository name.Reference - JavaDBRepository name.Reference + DBRepositories []name.Reference + JavaDBRepositories []name.Reference } // NewDBFlagGroup returns a default DBFlagGroup @@ -104,8 +104,8 @@ func NewDBFlagGroup() *DBFlagGroup { SkipJavaDBUpdate: SkipJavaDBUpdateFlag.Clone(), Light: LightFlag.Clone(), NoProgress: NoProgressFlag.Clone(), - DBRepository: DBRepositoryFlag.Clone(), - JavaDBRepository: JavaDBRepositoryFlag.Clone(), + DBRepositories: DBRepositoryFlag.Clone(), + JavaDBRepositories: JavaDBRepositoryFlag.Clone(), } } @@ -121,8 +121,8 @@ func (f *DBFlagGroup) Flags() []Flagger { f.DownloadJavaDBOnly, f.SkipJavaDBUpdate, f.NoProgress, - f.DBRepository, - f.JavaDBRepository, + f.DBRepositories, + f.JavaDBRepositories, f.Light, } } @@ -147,30 +147,21 @@ func (f *DBFlagGroup) ToOptions() (DBOptions, error) { return DBOptions{}, xerrors.New("--skip-java-db-update and --download-java-db-only options can not be specified both") } - var dbRepository, javaDBRepository name.Reference - var err error - if f.DBRepository != nil { - if dbRepository, err = name.ParseReference(f.DBRepository.Value(), name.WithDefaultTag("")); err != nil { - return DBOptions{}, xerrors.Errorf("invalid db repository: %w", err) - } - // Add the schema version if the tag is not specified for backward compatibility. - if t, ok := dbRepository.(name.Tag); ok && t.TagStr() == "" { - dbRepository = t.Tag(fmt.Sprint(db.SchemaVersion)) - log.Info("Adding schema version to the DB repository for backward compatibility", - log.String("repository", dbRepository.String())) + var dbRepositories, javaDBRepositories []name.Reference + for _, repo := range f.DBRepositories.Value() { + ref, err := parseRepository(repo, db.SchemaVersion) + if err != nil { + return DBOptions{}, xerrors.Errorf("invalid DB repository: %w", err) } + dbRepositories = append(dbRepositories, ref) } - if f.JavaDBRepository != nil { - if javaDBRepository, err = name.ParseReference(f.JavaDBRepository.Value(), name.WithDefaultTag("")); err != nil { + for _, repo := range f.JavaDBRepositories.Value() { + ref, err := parseRepository(repo, javadb.SchemaVersion) + if err != nil { return DBOptions{}, xerrors.Errorf("invalid javadb repository: %w", err) } - // Add the schema version if the tag is not specified for backward compatibility. - if t, ok := javaDBRepository.(name.Tag); ok && t.TagStr() == "" { - javaDBRepository = t.Tag(fmt.Sprint(javadb.SchemaVersion)) - log.Info("Adding schema version to the Java DB repository for backward compatibility", - log.String("repository", javaDBRepository.String())) - } + javaDBRepositories = append(javaDBRepositories, ref) } return DBOptions{ @@ -180,7 +171,26 @@ func (f *DBFlagGroup) ToOptions() (DBOptions, error) { DownloadJavaDBOnly: downloadJavaDBOnly, SkipJavaDBUpdate: skipJavaDBUpdate, NoProgress: f.NoProgress.Value(), - DBRepository: dbRepository, - JavaDBRepository: javaDBRepository, + DBRepositories: dbRepositories, + JavaDBRepositories: javaDBRepositories, }, nil } + +func parseRepository(repo string, dbSchemaVersion int) (name.Reference, error) { + dbRepository, err := name.ParseReference(repo, name.WithDefaultTag("")) + if err != nil { + return nil, err + } + + // Add the schema version if the tag is not specified for backward compatibility. + t, ok := dbRepository.(name.Tag) + if !ok || t.TagStr() != "" { + return dbRepository, nil + } + + dbRepository = t.Tag(fmt.Sprint(dbSchemaVersion)) + log.Info("Adding schema version to the DB repository for backward compatibility", + log.String("repository", dbRepository.String())) + + return dbRepository, nil +} diff --git a/pkg/flag/db_flags_test.go b/pkg/flag/db_flags_test.go index 2bbd5b00198c..4f742e74ed68 100644 --- a/pkg/flag/db_flags_test.go +++ b/pkg/flag/db_flags_test.go @@ -17,31 +17,34 @@ func TestDBFlagGroup_ToOptions(t *testing.T) { SkipDBUpdate bool DownloadDBOnly bool Light bool - DBRepository string - JavaDBRepository string + DBRepository []string + JavaDBRepository []string } tests := []struct { - name string - fields fields - want flag.DBOptions - wantLogs []string - assertion require.ErrorAssertionFunc + name string + fields fields + want flag.DBOptions + wantLogs []string + wantErr string }{ { name: "happy", fields: fields{ SkipDBUpdate: true, DownloadDBOnly: false, - DBRepository: "ghcr.io/aquasecurity/trivy-db", - JavaDBRepository: "ghcr.io/aquasecurity/trivy-java-db", + DBRepository: []string{"ghcr.io/aquasecurity/trivy-db"}, + JavaDBRepository: []string{"ghcr.io/aquasecurity/trivy-java-db"}, }, want: flag.DBOptions{ - SkipDBUpdate: true, - DownloadDBOnly: false, - DBRepository: name.Tag{}, // All fields are unexported - JavaDBRepository: name.Tag{}, // All fields are unexported + SkipDBUpdate: true, + DownloadDBOnly: false, + DBRepositories: []name.Reference{name.Tag{}}, // All fields are unexported + JavaDBRepositories: []name.Reference{name.Tag{}}, // All fields are unexported + }, + wantLogs: []string{ + `Adding schema version to the DB repository for backward compatibility repository="ghcr.io/aquasecurity/trivy-db:2"`, + `Adding schema version to the DB repository for backward compatibility repository="ghcr.io/aquasecurity/trivy-java-db:1"`, }, - assertion: require.NoError, }, { name: "sad", @@ -49,25 +52,36 @@ func TestDBFlagGroup_ToOptions(t *testing.T) { SkipDBUpdate: true, DownloadDBOnly: true, }, - assertion: func(t require.TestingT, err error, msgs ...any) { - require.ErrorContains(t, err, "--skip-db-update and --download-db-only options can not be specified both") - }, + wantErr: "--skip-db-update and --download-db-only options can not be specified both", }, { name: "invalid repo", fields: fields{ SkipDBUpdate: true, DownloadDBOnly: false, - DBRepository: "foo:bar:baz", + DBRepository: []string{"foo:bar:baz"}, }, - assertion: func(t require.TestingT, err error, msgs ...any) { - require.ErrorContains(t, err, "invalid db repository") + wantErr: "invalid DB repository", + }, + { + name: "multiple repos", + fields: fields{ + SkipDBUpdate: true, + DownloadDBOnly: false, + DBRepository: []string{"ghcr.io/aquasecurity/trivy-db:2", "gallery.ecr.aws/aquasecurity/trivy-db:2"}, + JavaDBRepository: []string{"ghcr.io/aquasecurity/trivy-java-db:1", "gallery.ecr.aws/aquasecurity/trivy-java-db:1"}, + }, + want: flag.DBOptions{ + SkipDBUpdate: true, + DownloadDBOnly: false, + DBRepositories: []name.Reference{name.Tag{}, name.Tag{}}, // All fields are unexported + JavaDBRepositories: []name.Reference{name.Tag{}, name.Tag{}}, // All fields are unexported }, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - out := newLogger(log.LevelWarn) + out := newLogger(log.LevelInfo) viper.Set(flag.SkipDBUpdateFlag.ConfigName, tt.fields.SkipDBUpdate) viper.Set(flag.DownloadDBOnlyFlag.ConfigName, tt.fields.DownloadDBOnly) @@ -76,13 +90,19 @@ func TestDBFlagGroup_ToOptions(t *testing.T) { // Assert options f := &flag.DBFlagGroup{ - DownloadDBOnly: flag.DownloadDBOnlyFlag.Clone(), - SkipDBUpdate: flag.SkipDBUpdateFlag.Clone(), - DBRepository: flag.DBRepositoryFlag.Clone(), - JavaDBRepository: flag.JavaDBRepositoryFlag.Clone(), + DownloadDBOnly: flag.DownloadDBOnlyFlag.Clone(), + SkipDBUpdate: flag.SkipDBUpdateFlag.Clone(), + DBRepositories: flag.DBRepositoryFlag.Clone(), + JavaDBRepositories: flag.JavaDBRepositoryFlag.Clone(), } got, err := f.ToOptions() - tt.assertion(t, err) + if tt.wantErr != "" { + require.Error(t, err) + assert.ErrorContains(t, err, tt.wantErr) + return + } + require.NoError(t, err) + assert.EqualExportedValues(t, tt.want, got) // Assert log messages diff --git a/pkg/javadb/client.go b/pkg/javadb/client.go index 9f90a37ba231..8c7aa81df9a3 100644 --- a/pkg/javadb/client.go +++ b/pkg/javadb/client.go @@ -26,12 +26,15 @@ const ( mediaType = "application/vnd.aquasec.trivy.javadb.layer.v1.tar+gzip" ) -var DefaultRepository = fmt.Sprintf("%s:%d", "ghcr.io/aquasecurity/trivy-java-db", SchemaVersion) +var ( + // GitHub Container Registry + DefaultGHCRRepository = fmt.Sprintf("%s:%d", "ghcr.io/aquasecurity/trivy-java-db", SchemaVersion) +) var updater *Updater type Updater struct { - repo name.Reference + repos []name.Reference dbDir string skip bool quiet bool @@ -40,8 +43,7 @@ type Updater struct { } func (u *Updater) Update() error { - dbDir := u.dbDir - metac := db.NewMetadata(dbDir) + metac := db.NewMetadata(u.dbDir) meta, err := metac.Get() if err != nil { @@ -55,13 +57,9 @@ func (u *Updater) Update() error { if (meta.Version != SchemaVersion || !u.isNewDB(meta)) && !u.skip { // Download DB - log.Info("Java DB Repository", log.Any("repository", u.repo)) - log.Info("Downloading the Java DB...") - // TODO: support remote options - art := oci.NewArtifact(u.repo.String(), u.quiet, u.registryOption) - if err = art.Download(context.Background(), dbDir, oci.DownloadOption{MediaType: mediaType}); err != nil { - return xerrors.Errorf("DB download error: %w", err) + if err := u.downloadDB(); err != nil { + return xerrors.Errorf("OCI artifact error: %w", err) } // Parse the newly downloaded metadata.json @@ -96,9 +94,21 @@ func (u *Updater) isNewDB(meta db.Metadata) bool { return false } -func Init(cacheDir string, javaDBRepository name.Reference, skip, quiet bool, registryOption ftypes.RegistryOptions) { +func (u *Updater) downloadDB() error { + log.Info("Downloading Java DB...") + + artifacts := oci.NewArtifacts(u.repos, u.registryOption) + downloadOpt := oci.DownloadOption{MediaType: mediaType, Quiet: u.quiet} + if err := artifacts.Download(context.Background(), u.dbDir, downloadOpt); err != nil { + return xerrors.Errorf("failed to download vulnerability DB: %w", err) + } + + return xerrors.New("failed to download Java DB from any source") +} + +func Init(cacheDir string, javaDBRepositories []name.Reference, skip, quiet bool, registryOption ftypes.RegistryOptions) { updater = &Updater{ - repo: javaDBRepository, + repos: javaDBRepositories, dbDir: dbDir(cacheDir), skip: skip, quiet: quiet, diff --git a/pkg/module/command.go b/pkg/module/command.go index 2dd955aa0e4b..a74da8384c3f 100644 --- a/pkg/module/command.go +++ b/pkg/module/command.go @@ -23,11 +23,11 @@ func Install(ctx context.Context, dir, repo string, quiet bool, opt types.Regist } log.Info("Installing the module from the repository...", log.String("repo", repo)) - art := oci.NewArtifact(repo, quiet, opt) + art := oci.NewArtifact(repo, opt) dst := filepath.Join(dir, ref.Context().Name()) log.Debug("Installing the module...", log.String("dst", dst)) - if err = art.Download(ctx, dst, oci.DownloadOption{MediaType: mediaType}); err != nil { + if err = art.Download(ctx, dst, oci.DownloadOption{MediaType: mediaType, Quiet: quiet}); err != nil { return xerrors.Errorf("module download error: %w", err) } diff --git a/pkg/oci/artifact.go b/pkg/oci/artifact.go index d8474941b3f5..345149892a4e 100644 --- a/pkg/oci/artifact.go +++ b/pkg/oci/artifact.go @@ -2,6 +2,7 @@ package oci import ( "context" + "errors" "io" "os" "path/filepath" @@ -10,11 +11,15 @@ import ( "github.com/cheggaaa/pb/v3" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/remote/transport" + "github.com/samber/lo" "golang.org/x/xerrors" "github.com/aquasecurity/trivy/pkg/downloader" "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/remote" + "github.com/aquasecurity/trivy/pkg/version/doc" ) const ( @@ -48,7 +53,6 @@ func WithImage(img v1.Image) Option { type Artifact struct { m sync.Mutex repository string - quiet bool // For OCI registries types.RegistryOptions @@ -57,10 +61,9 @@ type Artifact struct { } // NewArtifact returns a new artifact -func NewArtifact(repo string, quiet bool, registryOpt types.RegistryOptions, opts ...Option) *Artifact { +func NewArtifact(repo string, registryOpt types.RegistryOptions, opts ...Option) *Artifact { art := &Artifact{ repository: repo, - quiet: quiet, RegistryOptions: registryOpt, } @@ -98,6 +101,7 @@ func (a *Artifact) populate(ctx context.Context, opt types.RegistryOptions) erro type DownloadOption struct { MediaType string // Accept any media type if not specified Filename string // Use the annotation if not specified + Quiet bool } func (a *Artifact) Download(ctx context.Context, dir string, opt DownloadOption) error { @@ -140,14 +144,14 @@ func (a *Artifact) Download(ctx context.Context, dir string, opt DownloadOption) return xerrors.Errorf("unacceptable media type: %s", string(layerMediaType)) } - if err = a.download(ctx, layer, fileName, dir); err != nil { + if err = a.download(ctx, layer, fileName, dir, opt.Quiet); err != nil { return xerrors.Errorf("oci download error: %w", err) } return nil } -func (a *Artifact) download(ctx context.Context, layer v1.Layer, fileName, dir string) error { +func (a *Artifact) download(ctx context.Context, layer v1.Layer, fileName, dir string, quiet bool) error { size, err := layer.Size() if err != nil { return xerrors.Errorf("size error: %w", err) @@ -161,7 +165,7 @@ func (a *Artifact) download(ctx context.Context, layer v1.Layer, fileName, dir s // Show progress bar bar := pb.Full.Start64(size) - if a.quiet { + if quiet { bar.SetWriter(io.Discard) } pr := bar.NewProxyReader(rc) @@ -207,3 +211,54 @@ func (a *Artifact) Digest(ctx context.Context) (string, error) { } return digest.String(), nil } + +type Artifacts []*Artifact + +// NewArtifacts returns a slice of artifacts. +func NewArtifacts(repos []name.Reference, opt types.RegistryOptions, opts ...Option) Artifacts { + return lo.Map(repos, func(r name.Reference, _ int) *Artifact { + return NewArtifact(r.String(), opt, opts...) + }) +} + +// Download downloads artifacts until one of them succeeds. +// Attempts to download next artifact if the first one fails due to a temporary error. +func (a Artifacts) Download(ctx context.Context, dst string, opt DownloadOption) error { + for i, art := range a { + log.Info("Downloading artifact...", log.String("repo", art.repository)) + err := art.Download(ctx, dst, opt) + if err == nil { + log.Info("Artifact successfully downloaded", log.String("repo", art.repository)) + return nil + } + + if !shouldTryOtherRepo(err) { + return xerrors.Errorf("failed to download artifact from %s: %w", art.repository, err) + } + log.Error("Failed to download artifact", log.String("repo", art.repository), log.Err(err)) + if i < len(a)-1 { + log.Info("Trying to download artifact from other repository...") + } + } + + return xerrors.New("failed to download artifact from any source") +} + +func shouldTryOtherRepo(err error) bool { + var terr *transport.Error + if !errors.As(err, &terr) { + return false + } + + for _, diagnostic := range terr.Errors { + // For better user experience + if diagnostic.Code == transport.DeniedErrorCode || diagnostic.Code == transport.UnauthorizedErrorCode { + // e.g. https://aquasecurity.github.io/trivy/latest/docs/references/troubleshooting/#db + log.Warnf("See %s", doc.URL("/docs/references/troubleshooting/", "db")) + break + } + } + + // try the following artifact only if a temporary error occurs + return terr.Temporary() +} diff --git a/pkg/oci/artifact_test.go b/pkg/oci/artifact_test.go index 7cc8cd19d3c1..a8ce6e542641 100644 --- a/pkg/oci/artifact_test.go +++ b/pkg/oci/artifact_test.go @@ -116,9 +116,10 @@ func TestArtifact_Download(t *testing.T) { }, }, nil) - artifact := oci.NewArtifact("repo", true, ftypes.RegistryOptions{}, oci.WithImage(img)) + artifact := oci.NewArtifact("repo", ftypes.RegistryOptions{}, oci.WithImage(img)) err = artifact.Download(context.Background(), tempDir, oci.DownloadOption{ MediaType: tt.mediaType, + Quiet: true, }) if tt.wantErr != "" { assert.ErrorContains(t, err, tt.wantErr) diff --git a/pkg/policy/policy.go b/pkg/policy/policy.go index c8c05cf067c7..2dbe2fc1b89a 100644 --- a/pkg/policy/policy.go +++ b/pkg/policy/policy.go @@ -92,7 +92,7 @@ func NewClient(cacheDir string, quiet bool, checkBundleRepo string, opts ...Opti func (c *Client) populateOCIArtifact(registryOpts types.RegistryOptions) { if c.artifact == nil { log.Debug("Loading check bundle", log.String("repository", c.checkBundleRepo)) - c.artifact = oci.NewArtifact(c.checkBundleRepo, c.quiet, registryOpts) + c.artifact = oci.NewArtifact(c.checkBundleRepo, registryOpts) } } @@ -101,7 +101,9 @@ func (c *Client) DownloadBuiltinPolicies(ctx context.Context, registryOpts types c.populateOCIArtifact(registryOpts) dst := c.contentDir() - if err := c.artifact.Download(ctx, dst, oci.DownloadOption{MediaType: policyMediaType}); err != nil { + if err := c.artifact.Download(ctx, dst, + oci.DownloadOption{MediaType: policyMediaType, Quiet: c.quiet}, + ); err != nil { return xerrors.Errorf("download error: %w", err) } diff --git a/pkg/policy/policy_test.go b/pkg/policy/policy_test.go index 4dbd6b9a7558..f6875eb1c9cb 100644 --- a/pkg/policy/policy_test.go +++ b/pkg/policy/policy_test.go @@ -116,7 +116,7 @@ func TestClient_LoadBuiltinPolicies(t *testing.T) { }, nil) // Mock OCI artifact - art := oci.NewArtifact("repo", true, ftypes.RegistryOptions{}, oci.WithImage(img)) + art := oci.NewArtifact("repo", ftypes.RegistryOptions{}, oci.WithImage(img)) c, err := policy.NewClient(tt.cacheDir, true, "", policy.WithOCIArtifact(art)) require.NoError(t, err) @@ -255,7 +255,7 @@ func TestClient_NeedsUpdate(t *testing.T) { require.NoError(t, err) } - art := oci.NewArtifact("repo", true, ftypes.RegistryOptions{}, oci.WithImage(img)) + art := oci.NewArtifact("repo", ftypes.RegistryOptions{}, oci.WithImage(img)) c, err := policy.NewClient(tmpDir, true, "", policy.WithOCIArtifact(art), policy.WithClock(tt.clock)) require.NoError(t, err) @@ -357,7 +357,7 @@ func TestClient_DownloadBuiltinPolicies(t *testing.T) { }, nil) // Mock OCI artifact - art := oci.NewArtifact("repo", true, ftypes.RegistryOptions{}, oci.WithImage(img)) + art := oci.NewArtifact("repo", ftypes.RegistryOptions{}, oci.WithImage(img)) c, err := policy.NewClient(tempDir, true, "", policy.WithClock(tt.clock), policy.WithOCIArtifact(art)) require.NoError(t, err) diff --git a/pkg/rpc/server/listen.go b/pkg/rpc/server/listen.go index f1e39fa1b2f0..c1bc5033530c 100644 --- a/pkg/rpc/server/listen.go +++ b/pkg/rpc/server/listen.go @@ -29,21 +29,21 @@ const updateInterval = 1 * time.Hour // Server represents Trivy server type Server struct { - appVersion string - addr string - cacheDir string - dbDir string - token string - tokenHeader string - pathPrefix string - dbRepository name.Reference + appVersion string + addr string + cacheDir string + dbDir string + token string + tokenHeader string + pathPrefix string + dbRepositories []name.Reference // For OCI registries types.RegistryOptions } // NewServer returns an instance of Server -func NewServer(appVersion, addr, cacheDir, token, tokenHeader, pathPrefix string, dbRepository name.Reference, opt types.RegistryOptions) Server { +func NewServer(appVersion, addr, cacheDir, token, tokenHeader, pathPrefix string, dbRepositories []name.Reference, opt types.RegistryOptions) Server { return Server{ appVersion: appVersion, addr: addr, @@ -52,7 +52,7 @@ func NewServer(appVersion, addr, cacheDir, token, tokenHeader, pathPrefix string token: token, tokenHeader: tokenHeader, pathPrefix: pathPrefix, - dbRepository: dbRepository, + dbRepositories: dbRepositories, RegistryOptions: opt, } } @@ -63,7 +63,7 @@ func (s Server) ListenAndServe(ctx context.Context, serverCache cache.Cache, ski dbUpdateWg := &sync.WaitGroup{} go func() { - worker := newDBWorker(db.NewClient(s.dbDir, true, db.WithDBRepository(s.dbRepository))) + worker := newDBWorker(db.NewClient(s.dbDir, true, db.WithDBRepository(s.dbRepositories))) for { time.Sleep(updateInterval) if err := worker.update(ctx, s.appVersion, s.dbDir, skipDBUpdate, dbUpdateWg, requestWg, s.RegistryOptions); err != nil { From c0e8da3828e9d3a0b30d1f6568037db8dc827765 Mon Sep 17 00:00:00 2001 From: simar7 <1254783+simar7@users.noreply.github.com> Date: Tue, 1 Oct 2024 23:20:03 -0600 Subject: [PATCH 114/183] feat(misconf): Support `--skip-*` for all included modules (#7579) Signed-off-by: nikpivkin Co-authored-by: nikpivkin --- pkg/commands/artifact/run.go | 2 + pkg/fanal/utils/utils.go | 27 ++++++ pkg/fanal/walker/fs.go | 7 +- pkg/fanal/walker/tar.go | 8 +- pkg/fanal/walker/vm.go | 5 +- pkg/fanal/walker/walk.go | 29 ------ pkg/fanal/walker/walk_test.go | 6 +- pkg/iac/scanners/terraform/options.go | 16 ++++ pkg/iac/scanners/terraform/parser/option.go | 12 +++ pkg/iac/scanners/terraform/parser/parser.go | 7 ++ pkg/iac/scanners/terraform/scanner_test.go | 99 +++++++++++++++++++++ pkg/misconf/scanner.go | 4 + 12 files changed, 181 insertions(+), 41 deletions(-) diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index 11c6ef6a3090..6f926519b91a 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -659,5 +659,7 @@ func initMisconfScannerOption(opts flag.Options) (misconf.ScannerOption, error) TfExcludeDownloaded: opts.TfExcludeDownloaded, FilePatterns: opts.FilePatterns, ConfigFileSchemas: configSchemas, + SkipFiles: opts.SkipFiles, + SkipDirs: opts.SkipDirs, }, nil } diff --git a/pkg/fanal/utils/utils.go b/pkg/fanal/utils/utils.go index 58b44510db89..463c8dd1f255 100644 --- a/pkg/fanal/utils/utils.go +++ b/pkg/fanal/utils/utils.go @@ -9,10 +9,14 @@ import ( "os" "os/exec" "path/filepath" + "strings" "unicode" + "github.com/bmatcuk/doublestar/v4" + "github.com/samber/lo" "golang.org/x/xerrors" + "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -98,6 +102,29 @@ func IsBinary(content xio.ReadSeekerAt, fileSize int64) (bool, error) { return false, nil } +func CleanSkipPaths(skipPaths []string) []string { + return lo.Map(skipPaths, func(skipPath string, index int) string { + skipPath = filepath.ToSlash(filepath.Clean(skipPath)) + return strings.TrimLeft(skipPath, "/") + }) +} + +func SkipPath(path string, skipPaths []string) bool { + path = strings.TrimLeft(path, "/") + + // skip files + for _, pattern := range skipPaths { + match, err := doublestar.Match(pattern, path) + if err != nil { + return false // return early if bad pattern + } else if match { + log.Debug("Skipping path", log.String("path", path)) + return true + } + } + return false +} + func ExtractPrintableBytes(content xio.ReadSeekerAt) ([]byte, error) { const minLength = 4 // Minimum length of strings to extract var result []byte diff --git a/pkg/fanal/walker/fs.go b/pkg/fanal/walker/fs.go index f6bec84d1fc2..3ebfb7258459 100644 --- a/pkg/fanal/walker/fs.go +++ b/pkg/fanal/walker/fs.go @@ -9,6 +9,7 @@ import ( "golang.org/x/xerrors" + "github.com/aquasecurity/trivy/pkg/fanal/utils" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" ) @@ -53,13 +54,13 @@ func (w *FS) WalkDirFunc(root string, fn WalkFunc, opt Option) fs.WalkDirFunc { // Skip unnecessary files switch { case d.IsDir(): - if SkipPath(relPath, opt.SkipDirs) { + if utils.SkipPath(relPath, opt.SkipDirs) { return filepath.SkipDir } return nil case !d.Type().IsRegular(): return nil - case SkipPath(relPath, opt.SkipFiles): + case utils.SkipPath(relPath, opt.SkipFiles): return nil } @@ -148,7 +149,7 @@ func (w *FS) BuildSkipPaths(base string, paths []string) []string { relativePaths = append(relativePaths, relPath) } - relativePaths = CleanSkipPaths(relativePaths) + relativePaths = utils.CleanSkipPaths(relativePaths) return relativePaths } diff --git a/pkg/fanal/walker/tar.go b/pkg/fanal/walker/tar.go index 51f185d89c50..0c7d0bee9d5d 100644 --- a/pkg/fanal/walker/tar.go +++ b/pkg/fanal/walker/tar.go @@ -27,8 +27,8 @@ type LayerTar struct { func NewLayerTar(opt Option) LayerTar { return LayerTar{ - skipFiles: CleanSkipPaths(opt.SkipFiles), - skipDirs: CleanSkipPaths(opt.SkipDirs), + skipFiles: utils.CleanSkipPaths(opt.SkipFiles), + skipDirs: utils.CleanSkipPaths(opt.SkipDirs), } } @@ -63,12 +63,12 @@ func (w LayerTar) Walk(layer io.Reader, analyzeFn WalkFunc) ([]string, []string, switch hdr.Typeflag { case tar.TypeDir: - if SkipPath(filePath, w.skipDirs) { + if utils.SkipPath(filePath, w.skipDirs) { skippedDirs = append(skippedDirs, filePath) continue } case tar.TypeReg: - if SkipPath(filePath, w.skipFiles) { + if utils.SkipPath(filePath, w.skipFiles) { continue } // symlinks and hardlinks have no content in reader, skip them diff --git a/pkg/fanal/walker/vm.go b/pkg/fanal/walker/vm.go index 0bc3e87ac86d..f8ef63ce0252 100644 --- a/pkg/fanal/walker/vm.go +++ b/pkg/fanal/walker/vm.go @@ -17,6 +17,7 @@ import ( "github.com/masahiro331/go-xfs-filesystem/xfs" "golang.org/x/xerrors" + "github.com/aquasecurity/trivy/pkg/fanal/utils" "github.com/aquasecurity/trivy/pkg/fanal/vm/filesystem" "github.com/aquasecurity/trivy/pkg/log" xio "github.com/aquasecurity/trivy/pkg/x/io" @@ -131,13 +132,13 @@ func (w *VM) fsWalk(fsys fs.FS, path string, d fs.DirEntry, err error) error { pathName := strings.TrimPrefix(filepath.Clean(path), "/") switch { case fi.IsDir(): - if SkipPath(pathName, w.skipDirs) { + if utils.SkipPath(pathName, w.skipDirs) { return filepath.SkipDir } return nil case !fi.Mode().IsRegular(): return nil - case SkipPath(pathName, w.skipFiles): + case utils.SkipPath(pathName, w.skipFiles): return nil case fi.Mode()&0x1000 == 0x1000 || fi.Mode()&0x2000 == 0x2000 || diff --git a/pkg/fanal/walker/walk.go b/pkg/fanal/walker/walk.go index 52c13808d86b..0785cef41606 100644 --- a/pkg/fanal/walker/walk.go +++ b/pkg/fanal/walker/walk.go @@ -2,14 +2,8 @@ package walker import ( "os" - "path/filepath" - "strings" - - "github.com/bmatcuk/doublestar/v4" - "github.com/samber/lo" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" - "github.com/aquasecurity/trivy/pkg/log" ) const defaultSizeThreshold = int64(100) << 20 // 200MB @@ -27,26 +21,3 @@ type Option struct { } type WalkFunc func(filePath string, info os.FileInfo, opener analyzer.Opener) error - -func CleanSkipPaths(skipPaths []string) []string { - return lo.Map(skipPaths, func(skipPath string, index int) string { - skipPath = filepath.ToSlash(filepath.Clean(skipPath)) - return strings.TrimLeft(skipPath, "/") - }) -} - -func SkipPath(path string, skipPaths []string) bool { - path = strings.TrimLeft(path, "/") - - // skip files - for _, pattern := range skipPaths { - match, err := doublestar.Match(pattern, path) - if err != nil { - return false // return early if bad pattern - } else if match { - log.Debug("Skipping path", log.String("path", path)) - return true - } - } - return false -} diff --git a/pkg/fanal/walker/walk_test.go b/pkg/fanal/walker/walk_test.go index 0bac6009d04f..09d55527c0fe 100644 --- a/pkg/fanal/walker/walk_test.go +++ b/pkg/fanal/walker/walk_test.go @@ -7,7 +7,7 @@ import ( "github.com/stretchr/testify/assert" - "github.com/aquasecurity/trivy/pkg/fanal/walker" + "github.com/aquasecurity/trivy/pkg/fanal/utils" ) func TestSkipFile(t *testing.T) { @@ -64,7 +64,7 @@ func TestSkipFile(t *testing.T) { t.Run(tt.name, func(t *testing.T) { for file, want := range tt.wants { file = filepath.ToSlash(filepath.Clean(file)) - got := walker.SkipPath(file, walker.CleanSkipPaths(tt.skipFiles)) + got := utils.SkipPath(file, utils.CleanSkipPaths(tt.skipFiles)) assert.Equal(t, want, got, fmt.Sprintf("skipFiles: %s, file: %s", tt.skipFiles, file)) } }) @@ -138,7 +138,7 @@ func TestSkipDir(t *testing.T) { t.Run(tt.name, func(t *testing.T) { for dir, want := range tt.wants { dir = filepath.ToSlash(filepath.Clean(dir)) - got := walker.SkipPath(dir, walker.CleanSkipPaths(tt.skipDirs)) + got := utils.SkipPath(dir, utils.CleanSkipPaths(tt.skipDirs)) assert.Equal(t, want, got, fmt.Sprintf("defaultSkipDirs: %s, dir: %s", tt.skipDirs, dir)) } }) diff --git a/pkg/iac/scanners/terraform/options.go b/pkg/iac/scanners/terraform/options.go index d256f0a34daa..5a665a05638f 100644 --- a/pkg/iac/scanners/terraform/options.go +++ b/pkg/iac/scanners/terraform/options.go @@ -84,3 +84,19 @@ func ScannerWithConfigsFileSystem(fsys fs.FS) options.ScannerOption { } } } + +func ScannerWithSkipFiles(files []string) options.ScannerOption { + return func(s options.ConfigurableScanner) { + if tf, ok := s.(ConfigurableTerraformScanner); ok { + tf.AddParserOptions(parser.OptionWithSkipFiles(files)) + } + } +} + +func ScannerWithSkipDirs(dirs []string) options.ScannerOption { + return func(s options.ConfigurableScanner) { + if tf, ok := s.(ConfigurableTerraformScanner); ok { + tf.AddParserOptions(parser.OptionWithSkipDirs(dirs)) + } + } +} diff --git a/pkg/iac/scanners/terraform/parser/option.go b/pkg/iac/scanners/terraform/parser/option.go index 277cf2a58c61..f9ada6545225 100644 --- a/pkg/iac/scanners/terraform/parser/option.go +++ b/pkg/iac/scanners/terraform/parser/option.go @@ -49,3 +49,15 @@ func OptionWithConfigsFS(fsys fs.FS) Option { p.configsFS = fsys } } + +func OptionWithSkipFiles(files []string) Option { + return func(p *Parser) { + p.skipPaths = files + } +} + +func OptionWithSkipDirs(dirs []string) Option { + return func(p *Parser) { + p.skipPaths = dirs + } +} diff --git a/pkg/iac/scanners/terraform/parser/parser.go b/pkg/iac/scanners/terraform/parser/parser.go index 60940d6c6241..695cbee4fb25 100644 --- a/pkg/iac/scanners/terraform/parser/parser.go +++ b/pkg/iac/scanners/terraform/parser/parser.go @@ -15,6 +15,7 @@ import ( "github.com/hashicorp/hcl/v2/hclparse" "github.com/zclconf/go-cty/cty" + "github.com/aquasecurity/trivy/pkg/fanal/utils" "github.com/aquasecurity/trivy/pkg/iac/ignore" "github.com/aquasecurity/trivy/pkg/iac/terraform" tfcontext "github.com/aquasecurity/trivy/pkg/iac/terraform/context" @@ -47,6 +48,7 @@ type Parser struct { skipCachedModules bool fsMap map[string]fs.FS configsFS fs.FS + skipPaths []string } // New creates a new Parser @@ -78,6 +80,7 @@ func (p *Parser) newModuleParser(moduleFS fs.FS, moduleSource, modulePath, modul mp.moduleName = moduleName mp.logger = log.WithPrefix("terraform parser").With("module", moduleName) mp.projectRoot = p.projectRoot + mp.skipPaths = p.skipPaths p.children = append(p.children, mp) for _, option := range p.options { option(mp) @@ -155,6 +158,10 @@ func (p *Parser) ParseFS(ctx context.Context, dir string) error { if info.IsDir() { continue } + if utils.SkipPath(realPath, utils.CleanSkipPaths(p.skipPaths)) { + p.logger.Debug("Skipping path based on input glob", log.FilePath(realPath), log.Any("glob", p.skipPaths)) + continue + } paths = append(paths, realPath) } sort.Strings(paths) diff --git a/pkg/iac/scanners/terraform/scanner_test.go b/pkg/iac/scanners/terraform/scanner_test.go index 39ee35e81321..a7020b4ddd06 100644 --- a/pkg/iac/scanners/terraform/scanner_test.go +++ b/pkg/iac/scanners/terraform/scanner_test.go @@ -1118,3 +1118,102 @@ func TestSkipDeprecatedGoChecks(t *testing.T) { require.Len(t, results, 1) }) } + +func TestSkipDir(t *testing.T) { + fs := testutil.CreateFS(t, map[string]string{ + "deployments/main.tf": ` +module "use_bad_configuration" { + source = "../modules" +} + +module "use_bad_configuration_2" { + source = "../modules/modules2" +} +`, + "modules/misconfig.tf": `data "aws_iam_policy_document" "bad" { + statement { + actions = [ + "apigateway:*", + ] + + resources = [ + "*", + ] + } +} + +resource "aws_iam_policy" "bad_configuration" { + name_prefix = local.setup_role_name + policy = data.aws_iam_policy_document.bad.json +} +`, + "modules/modules2/misconfig.tf": `data "aws_iam_policy_document" "bad" { + statement { + actions = [ + "apigateway:*", + ] + + resources = [ + "*", + ] + } +} + +resource "aws_iam_policy" "bad_configuration" { + name_prefix = local.setup_role_name + policy = data.aws_iam_policy_document.bad.json +} +`, + }) + + t.Run("use skip-dir option", func(t *testing.T) { + scanner := New( + options.ScannerWithIncludeDeprecatedChecks(true), + ScannerWithSkipDirs([]string{"**/modules/**"}), + ScannerWithAllDirectories(true), + ) + + results, err := scanner.ScanFS(context.TODO(), fs, "deployments") + require.NoError(t, err) + + assert.Empty(t, results) + }) + + t.Run("use skip-files option", func(t *testing.T) { + scanner := New( + options.ScannerWithIncludeDeprecatedChecks(true), + ScannerWithSkipFiles([]string{"**/modules/**/*.tf"}), + ScannerWithAllDirectories(true), + ) + + results, err := scanner.ScanFS(context.TODO(), fs, "deployments") + require.NoError(t, err) + + assert.Empty(t, results) + }) + + t.Run("non existing value for skip-files option", func(t *testing.T) { + scanner := New( + options.ScannerWithIncludeDeprecatedChecks(true), + ScannerWithSkipFiles([]string{"foo/bar*.tf"}), + ScannerWithAllDirectories(true), + ) + + results, err := scanner.ScanFS(context.TODO(), fs, "deployments") + require.NoError(t, err) + + assert.Len(t, results, 4) + }) + + t.Run("empty skip-files option", func(t *testing.T) { + scanner := New( + options.ScannerWithIncludeDeprecatedChecks(true), + ScannerWithAllDirectories(true), + ) + + results, err := scanner.ScanFS(context.TODO(), fs, "deployments") + require.NoError(t, err) + + assert.Len(t, results, 4) + }) +} diff --git a/pkg/misconf/scanner.go b/pkg/misconf/scanner.go index 78f4f4bdb158..7bec3ed6fe14 100644 --- a/pkg/misconf/scanner.go +++ b/pkg/misconf/scanner.go @@ -76,6 +76,8 @@ type ScannerOption struct { ConfigFileSchemas []*ConfigFileSchema DisabledCheckIDs []string + SkipFiles []string + SkipDirs []string } func (o *ScannerOption) Sort() { @@ -297,6 +299,8 @@ func addTFOpts(opts []options.ScannerOption, scannerOption ScannerOption) ([]opt opts = append(opts, terraform.ScannerWithAllDirectories(true), terraform.ScannerWithSkipDownloaded(scannerOption.TfExcludeDownloaded), + terraform.ScannerWithSkipFiles(scannerOption.SkipFiles), + terraform.ScannerWithSkipDirs(scannerOption.SkipDirs), ) return opts, nil From 1faf5297e72f9d4c6047451c79868daa9db5c6e7 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Wed, 2 Oct 2024 11:04:11 +0400 Subject: [PATCH 115/183] chore: add prefixes to log messages (#7625) Signed-off-by: knqyf263 Co-authored-by: simar7 <1254783+simar7@users.noreply.github.com> --- pkg/commands/artifact/run.go | 18 ++++++++-------- pkg/commands/operation/operation.go | 14 ++++++------- pkg/db/db.go | 19 +++++++++-------- pkg/javadb/client.go | 26 +++++++++++++---------- pkg/k8s/commands/cluster.go | 17 +++++++-------- pkg/log/logger.go | 2 ++ pkg/oci/artifact.go | 8 ++++---- pkg/policy/policy.go | 32 +++++++++++++++-------------- pkg/policy/policy_test.go | 4 ++-- pkg/version/version.go | 4 +++- 10 files changed, 77 insertions(+), 67 deletions(-) diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index 6f926519b91a..0c9560014a0a 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -470,7 +470,7 @@ func filterMisconfigAnalyzers(included, all []analyzer.Type) ([]analyzer.Type, e return lo.Without(all, included...), nil } -func (r *runner) initScannerConfig(opts flag.Options) (ScannerConfig, types.ScanOptions, error) { +func (r *runner) initScannerConfig(ctx context.Context, opts flag.Options) (ScannerConfig, types.ScanOptions, error) { target := opts.Target if opts.Input != "" { target = opts.Input @@ -505,7 +505,7 @@ func (r *runner) initScannerConfig(opts flag.Options) (ScannerConfig, types.Scan var configScannerOptions misconf.ScannerOption if opts.Scanners.Enabled(types.MisconfigScanner) || opts.ImageConfigScanners.Enabled(types.MisconfigScanner) { var err error - configScannerOptions, err = initMisconfScannerOption(opts) + configScannerOptions, err = initMisconfScannerOption(ctx, opts) if err != nil { return ScannerConfig{}, types.ScanOptions{}, err } @@ -600,7 +600,7 @@ func (r *runner) initScannerConfig(opts flag.Options) (ScannerConfig, types.Scan } func (r *runner) scan(ctx context.Context, opts flag.Options, initializeScanner InitializeScanner) (types.Report, error) { - scannerConfig, scanOptions, err := r.initScannerConfig(opts) + scannerConfig, scanOptions, err := r.initScannerConfig(ctx, opts) if err != nil { return types.Report{}, err } @@ -617,20 +617,20 @@ func (r *runner) scan(ctx context.Context, opts flag.Options, initializeScanner return report, nil } -func initMisconfScannerOption(opts flag.Options) (misconf.ScannerOption, error) { - logger := log.WithPrefix(log.PrefixMisconfiguration) - logger.Info("Misconfiguration scanning is enabled") +func initMisconfScannerOption(ctx context.Context, opts flag.Options) (misconf.ScannerOption, error) { + ctx = log.WithContextPrefix(ctx, log.PrefixMisconfiguration) + log.InfoContext(ctx, "Misconfiguration scanning is enabled") var downloadedPolicyPaths []string var disableEmbedded bool - downloadedPolicyPaths, err := operation.InitBuiltinPolicies(context.Background(), opts.CacheDir, opts.Quiet, opts.SkipCheckUpdate, opts.MisconfOptions.ChecksBundleRepository, opts.RegistryOpts()) + downloadedPolicyPaths, err := operation.InitBuiltinChecks(ctx, opts.CacheDir, opts.Quiet, opts.SkipCheckUpdate, opts.MisconfOptions.ChecksBundleRepository, opts.RegistryOpts()) if err != nil { if !opts.SkipCheckUpdate { - logger.Error("Falling back to embedded checks", log.Err(err)) + log.ErrorContext(ctx, "Falling back to embedded checks", log.Err(err)) } } else { - logger.Debug("Checks successfully loaded from disk") + log.DebugContext(ctx, "Checks successfully loaded from disk") disableEmbedded = true } diff --git a/pkg/commands/operation/operation.go b/pkg/commands/operation/operation.go index 7570c4393b69..ac52eee7fb1e 100644 --- a/pkg/commands/operation/operation.go +++ b/pkg/commands/operation/operation.go @@ -26,7 +26,7 @@ func DownloadDB(ctx context.Context, appVersion, cacheDir string, dbRepositories mu.Lock() defer mu.Unlock() - ctx = log.WithContextPrefix(ctx, "db") + ctx = log.WithContextPrefix(ctx, log.PrefixVulnerabilityDB) dbDir := db.Dir(cacheDir) client := db.NewClient(dbDir, quiet, db.WithDBRepository(dbRepositories)) needsUpdate, err := client.NeedsUpdate(ctx, appVersion, skipUpdate) @@ -77,8 +77,8 @@ func DownloadVEXRepositories(ctx context.Context, opts flag.Options) error { } -// InitBuiltinPolicies downloads the built-in policies and loads them -func InitBuiltinPolicies(ctx context.Context, cacheDir string, quiet, skipUpdate bool, checkBundleRepository string, registryOpts ftypes.RegistryOptions) ([]string, error) { +// InitBuiltinChecks downloads the built-in policies and loads them +func InitBuiltinChecks(ctx context.Context, cacheDir string, quiet, skipUpdate bool, checkBundleRepository string, registryOpts ftypes.RegistryOptions) ([]string, error) { mu.Lock() defer mu.Unlock() @@ -96,14 +96,14 @@ func InitBuiltinPolicies(ctx context.Context, cacheDir string, quiet, skipUpdate } if needsUpdate { - log.Info("Need to update the built-in policies") - log.Info("Downloading the built-in policies...") - if err = client.DownloadBuiltinPolicies(ctx, registryOpts); err != nil { + log.InfoContext(ctx, "Need to update the built-in checks") + log.InfoContext(ctx, "Downloading the built-in checks...") + if err = client.DownloadBuiltinChecks(ctx, registryOpts); err != nil { return nil, xerrors.Errorf("failed to download built-in policies: %w", err) } } - policyPaths, err := client.LoadBuiltinPolicies() + policyPaths, err := client.LoadBuiltinChecks() if err != nil { if skipUpdate { msg := "No downloadable policies were loaded as --skip-check-update is enabled" diff --git a/pkg/db/db.go b/pkg/db/db.go index f7ceb09af4c9..70fbb93a5a91 100644 --- a/pkg/db/db.go +++ b/pkg/db/db.go @@ -93,22 +93,22 @@ func NewClient(dbDir string, quiet bool, opts ...Option) *Client { func (c *Client) NeedsUpdate(ctx context.Context, cliVersion string, skip bool) (bool, error) { meta, err := c.metadata.Get() if err != nil { - log.Debug("There is no valid metadata file", log.Err(err)) + log.DebugContext(ctx, "There is no valid metadata file", log.Err(err)) if skip { - log.Error("The first run cannot skip downloading DB") + log.ErrorContext(ctx, "The first run cannot skip downloading DB") return false, xerrors.New("--skip-update cannot be specified on the first run") } meta = metadata.Metadata{Version: db.SchemaVersion} } if db.SchemaVersion < meta.Version { - log.Error("The Trivy version is old. Update to the latest version.", log.String("version", cliVersion)) + log.ErrorContext(ctx, "Trivy version is old. Update to the latest version.", log.String("version", cliVersion)) return false, xerrors.Errorf("the version of DB schema doesn't match. Local DB: %d, Expected: %d", meta.Version, db.SchemaVersion) } if skip { - log.Debug("Skipping DB update...") + log.DebugContext(ctx, "Skipping DB update...") if err = c.validate(meta); err != nil { return false, xerrors.Errorf("validate error: %w", err) } @@ -116,7 +116,7 @@ func (c *Client) NeedsUpdate(ctx context.Context, cliVersion string, skip bool) } if db.SchemaVersion != meta.Version { - log.Debug("The local DB schema version does not match with supported version schema.", + log.DebugContext(ctx, "The local DB schema version does not match with supported version schema.", log.Int("local_version", meta.Version), log.Int("supported_version", db.SchemaVersion)) return true, nil } @@ -151,7 +151,7 @@ func (c *Client) isNewDB(ctx context.Context, meta metadata.Metadata) bool { func (c *Client) Download(ctx context.Context, dst string, opt types.RegistryOptions) error { // Remove the metadata file under the cache directory before downloading DB if err := c.metadata.Delete(); err != nil { - log.Debug("No metadata file") + log.DebugContext(ctx, "No metadata file") } if err := c.downloadDB(ctx, opt, dst); err != nil { @@ -198,8 +198,11 @@ func (c *Client) initArtifacts(opt types.RegistryOptions) oci.Artifacts { } func (c *Client) downloadDB(ctx context.Context, opt types.RegistryOptions, dst string) error { - log.Info("Downloading vulnerability DB...") - downloadOpt := oci.DownloadOption{MediaType: dbMediaType, Quiet: c.quiet} + log.InfoContext(ctx, "Downloading vulnerability DB...") + downloadOpt := oci.DownloadOption{ + MediaType: dbMediaType, + Quiet: c.quiet, + } if err := c.initArtifacts(opt).Download(ctx, dst, downloadOpt); err != nil { return xerrors.Errorf("failed to download vulnerability DB: %w", err) } diff --git a/pkg/javadb/client.go b/pkg/javadb/client.go index 8c7aa81df9a3..6d5b589bb5d1 100644 --- a/pkg/javadb/client.go +++ b/pkg/javadb/client.go @@ -43,6 +43,7 @@ type Updater struct { } func (u *Updater) Update() error { + ctx := log.WithContextPrefix(context.Background(), log.PrefixJavaDB) metac := db.NewMetadata(u.dbDir) meta, err := metac.Get() @@ -50,15 +51,15 @@ func (u *Updater) Update() error { if !errors.Is(err, os.ErrNotExist) { return xerrors.Errorf("Java DB metadata error: %w", err) } else if u.skip { - log.Error("The first run cannot skip downloading Java DB") + log.ErrorContext(ctx, "The first run cannot skip downloading Java DB") return xerrors.New("'--skip-java-db-update' cannot be specified on the first run") } } - if (meta.Version != SchemaVersion || !u.isNewDB(meta)) && !u.skip { + if (meta.Version != SchemaVersion || !u.isNewDB(ctx, meta)) && !u.skip { // Download DB // TODO: support remote options - if err := u.downloadDB(); err != nil { + if err := u.downloadDB(ctx); err != nil { return xerrors.Errorf("OCI artifact error: %w", err) } @@ -73,33 +74,36 @@ func (u *Updater) Update() error { if err = metac.Update(meta); err != nil { return xerrors.Errorf("Java DB metadata update error: %w", err) } - log.Info("The Java DB is cached for 3 days. If you want to update the database more frequently, " + + log.InfoContext(ctx, "Java DB is cached for 3 days. If you want to update the database more frequently, "+ `"trivy clean --java-db" command clears the DB cache.`) } return nil } -func (u *Updater) isNewDB(meta db.Metadata) bool { +func (u *Updater) isNewDB(ctx context.Context, meta db.Metadata) bool { now := time.Now().UTC() if now.Before(meta.NextUpdate) { - log.Debug("Java DB update was skipped because the local Java DB is the latest") + log.DebugContext(ctx, "Java DB update was skipped because the local Java DB is the latest") return true } if now.Before(meta.DownloadedAt.Add(time.Hour * 24)) { // 1 day - log.Debug("Java DB update was skipped because the local Java DB was downloaded during the last day") + log.DebugContext(ctx, "Java DB update was skipped because the local Java DB was downloaded during the last day") return true } return false } -func (u *Updater) downloadDB() error { - log.Info("Downloading Java DB...") +func (u *Updater) downloadDB(ctx context.Context) error { + log.InfoContext(ctx, "Downloading Java DB...") artifacts := oci.NewArtifacts(u.repos, u.registryOption) - downloadOpt := oci.DownloadOption{MediaType: mediaType, Quiet: u.quiet} - if err := artifacts.Download(context.Background(), u.dbDir, downloadOpt); err != nil { + downloadOpt := oci.DownloadOption{ + MediaType: mediaType, + Quiet: u.quiet, + } + if err := artifacts.Download(ctx, u.dbDir, downloadOpt); err != nil { return xerrors.Errorf("failed to download vulnerability DB: %w", err) } diff --git a/pkg/k8s/commands/cluster.go b/pkg/k8s/commands/cluster.go index 179a089523df..11dd5e0d3a00 100644 --- a/pkg/k8s/commands/cluster.go +++ b/pkg/k8s/commands/cluster.go @@ -37,7 +37,7 @@ func clusterRun(ctx context.Context, opts flag.Options, cluster k8s.Cluster) err trivyk8s.WithExcludeOwned(opts.ExcludeOwned), } if opts.Scanners.AnyEnabled(types.MisconfigScanner) && !opts.DisableNodeCollector { - artifacts, err = trivyk8s.New(cluster, k8sOpts...).ListArtifactAndNodeInfo(ctx, nodeCollectorOptions(opts)...) + artifacts, err = trivyk8s.New(cluster, k8sOpts...).ListArtifactAndNodeInfo(ctx, nodeCollectorOptions(ctx, opts)...) if err != nil { return xerrors.Errorf("get k8s artifacts with node info error: %w", err) } @@ -59,20 +59,17 @@ func clusterRun(ctx context.Context, opts flag.Options, cluster k8s.Cluster) err return runner.run(ctx, artifacts) } -func nodeCollectorOptions(opts flag.Options) []trivyk8s.NodeCollectorOption { +func nodeCollectorOptions(ctx context.Context, opts flag.Options) []trivyk8s.NodeCollectorOption { nodeCollectorOptions := []trivyk8s.NodeCollectorOption{ trivyk8s.WithScanJobNamespace(opts.NodeCollectorNamespace), trivyk8s.WithIgnoreLabels(opts.ExcludeNodes), trivyk8s.WithScanJobImageRef(opts.NodeCollectorImageRef), - trivyk8s.WithTolerations(opts.Tolerations)} - - contentPath, err := operation.InitBuiltinPolicies(context.Background(), - opts.CacheDir, - opts.Quiet, - opts.SkipCheckUpdate, - opts.MisconfOptions.ChecksBundleRepository, - opts.RegistryOpts()) + trivyk8s.WithTolerations(opts.Tolerations), + } + ctx = log.WithContextPrefix(ctx, log.PrefixMisconfiguration) + contentPath, err := operation.InitBuiltinChecks(ctx, opts.CacheDir, opts.Quiet, opts.SkipCheckUpdate, + opts.MisconfOptions.ChecksBundleRepository, opts.RegistryOpts()) if err != nil { log.Error("Falling back to embedded checks", log.Err(err)) nodeCollectorOptions = append(nodeCollectorOptions, diff --git a/pkg/log/logger.go b/pkg/log/logger.go index ac629d211157..2948886b9559 100644 --- a/pkg/log/logger.go +++ b/pkg/log/logger.go @@ -23,6 +23,8 @@ const ( PrefixMisconfiguration = "misconfig" PrefixSecret = "secret" PrefixLicense = "license" + PrefixVulnerabilityDB = "vulndb" + PrefixJavaDB = "javadb" ) // Logger is an alias of slog.Logger diff --git a/pkg/oci/artifact.go b/pkg/oci/artifact.go index 345149892a4e..416952578918 100644 --- a/pkg/oci/artifact.go +++ b/pkg/oci/artifact.go @@ -225,19 +225,19 @@ func NewArtifacts(repos []name.Reference, opt types.RegistryOptions, opts ...Opt // Attempts to download next artifact if the first one fails due to a temporary error. func (a Artifacts) Download(ctx context.Context, dst string, opt DownloadOption) error { for i, art := range a { - log.Info("Downloading artifact...", log.String("repo", art.repository)) + log.InfoContext(ctx, "Downloading artifact...", log.String("repo", art.repository)) err := art.Download(ctx, dst, opt) if err == nil { - log.Info("Artifact successfully downloaded", log.String("repo", art.repository)) + log.InfoContext(ctx, "Artifact successfully downloaded", log.String("repo", art.repository)) return nil } if !shouldTryOtherRepo(err) { return xerrors.Errorf("failed to download artifact from %s: %w", art.repository, err) } - log.Error("Failed to download artifact", log.String("repo", art.repository), log.Err(err)) + log.ErrorContext(ctx, "Failed to download artifact", log.String("repo", art.repository), log.Err(err)) if i < len(a)-1 { - log.Info("Trying to download artifact from other repository...") + log.InfoContext(ctx, "Trying to download artifact from other repository...") } } diff --git a/pkg/policy/policy.go b/pkg/policy/policy.go index 2dbe2fc1b89a..e277936829c5 100644 --- a/pkg/policy/policy.go +++ b/pkg/policy/policy.go @@ -89,20 +89,22 @@ func NewClient(cacheDir string, quiet bool, checkBundleRepo string, opts ...Opti }, nil } -func (c *Client) populateOCIArtifact(registryOpts types.RegistryOptions) { +func (c *Client) populateOCIArtifact(ctx context.Context, registryOpts types.RegistryOptions) { if c.artifact == nil { - log.Debug("Loading check bundle", log.String("repository", c.checkBundleRepo)) + log.DebugContext(ctx, "Loading check bundle", log.String("repository", c.checkBundleRepo)) c.artifact = oci.NewArtifact(c.checkBundleRepo, registryOpts) } } -// DownloadBuiltinPolicies download default policies from GitHub Pages -func (c *Client) DownloadBuiltinPolicies(ctx context.Context, registryOpts types.RegistryOptions) error { - c.populateOCIArtifact(registryOpts) +// DownloadBuiltinChecks download default policies from GitHub Pages +func (c *Client) DownloadBuiltinChecks(ctx context.Context, registryOpts types.RegistryOptions) error { + c.populateOCIArtifact(ctx, registryOpts) dst := c.contentDir() - if err := c.artifact.Download(ctx, dst, - oci.DownloadOption{MediaType: policyMediaType, Quiet: c.quiet}, + if err := c.artifact.Download(ctx, dst, oci.DownloadOption{ + MediaType: policyMediaType, + Quiet: c.quiet, + }, ); err != nil { return xerrors.Errorf("download error: %w", err) } @@ -111,7 +113,7 @@ func (c *Client) DownloadBuiltinPolicies(ctx context.Context, registryOpts types if err != nil { return xerrors.Errorf("digest error: %w", err) } - log.Debug("Digest of the built-in policies", log.String("digest", digest)) + log.DebugContext(ctx, "Digest of the built-in checks", log.String("digest", digest)) // Update metadata.json with the new digest and the current date if err = c.updateMetadata(digest, c.clock.Now()); err != nil { @@ -121,8 +123,8 @@ func (c *Client) DownloadBuiltinPolicies(ctx context.Context, registryOpts types return nil } -// LoadBuiltinPolicies loads default policies -func (c *Client) LoadBuiltinPolicies() ([]string, error) { +// LoadBuiltinChecks loads default policies +func (c *Client) LoadBuiltinChecks() ([]string, error) { f, err := os.Open(c.manifestPath()) if err != nil { return nil, xerrors.Errorf("manifest file open error (%s): %w", c.manifestPath(), err) @@ -150,7 +152,7 @@ func (c *Client) LoadBuiltinPolicies() ([]string, error) { // NeedsUpdate returns if the default check should be updated func (c *Client) NeedsUpdate(ctx context.Context, registryOpts types.RegistryOptions) (bool, error) { - meta, err := c.GetMetadata() + meta, err := c.GetMetadata(ctx) if err != nil { return true, nil } @@ -160,7 +162,7 @@ func (c *Client) NeedsUpdate(ctx context.Context, registryOpts types.RegistryOpt return false, nil } - c.populateOCIArtifact(registryOpts) + c.populateOCIArtifact(ctx, registryOpts) digest, err := c.artifact.Digest(ctx) if err != nil { return false, xerrors.Errorf("digest error: %w", err) @@ -211,17 +213,17 @@ func (c *Client) updateMetadata(digest string, now time.Time) error { return nil } -func (c *Client) GetMetadata() (*Metadata, error) { +func (c *Client) GetMetadata(ctx context.Context) (*Metadata, error) { f, err := os.Open(c.metadataPath()) if err != nil { - log.Debug("Failed to open the check metadata", log.Err(err)) + log.DebugContext(ctx, "Failed to open the check metadata", log.Err(err)) return nil, err } defer f.Close() var meta Metadata if err = json.NewDecoder(f).Decode(&meta); err != nil { - log.Warn("Check metadata decode error", log.Err(err)) + log.WarnContext(ctx, "Check metadata decode error", log.Err(err)) return nil, err } diff --git a/pkg/policy/policy_test.go b/pkg/policy/policy_test.go index f6875eb1c9cb..4752fa4ce7fc 100644 --- a/pkg/policy/policy_test.go +++ b/pkg/policy/policy_test.go @@ -120,7 +120,7 @@ func TestClient_LoadBuiltinPolicies(t *testing.T) { c, err := policy.NewClient(tt.cacheDir, true, "", policy.WithOCIArtifact(art)) require.NoError(t, err) - got, err := c.LoadBuiltinPolicies() + got, err := c.LoadBuiltinChecks() if tt.wantErr != "" { require.Error(t, err) assert.Contains(t, err.Error(), tt.wantErr) @@ -361,7 +361,7 @@ func TestClient_DownloadBuiltinPolicies(t *testing.T) { c, err := policy.NewClient(tempDir, true, "", policy.WithClock(tt.clock), policy.WithOCIArtifact(art)) require.NoError(t, err) - err = c.DownloadBuiltinPolicies(context.Background(), ftypes.RegistryOptions{}) + err = c.DownloadBuiltinChecks(context.Background(), ftypes.RegistryOptions{}) if tt.wantErr != "" { require.Error(t, err) assert.Contains(t, err.Error(), tt.wantErr) diff --git a/pkg/version/version.go b/pkg/version/version.go index 60ee62bd52f1..17da77a2a1bd 100644 --- a/pkg/version/version.go +++ b/pkg/version/version.go @@ -1,6 +1,7 @@ package version import ( + "context" "fmt" "path/filepath" @@ -80,7 +81,8 @@ func NewVersionInfo(cacheDir string) VersionInfo { log.Debug("Failed to instantiate policy client", log.Err(err)) } if pc != nil && err == nil { - pbMetaRaw, err := pc.GetMetadata() + ctx := log.WithContextPrefix(context.TODO(), log.PrefixMisconfiguration) + pbMetaRaw, err := pc.GetMetadata(ctx) if err != nil { log.Debug("Failed to get policy metadata", log.Err(err)) From 82e2adc6f8e68d0cc0021031170c2adb60d213ba Mon Sep 17 00:00:00 2001 From: simar7 <1254783+simar7@users.noreply.github.com> Date: Wed, 2 Oct 2024 01:49:08 -0600 Subject: [PATCH 116/183] fix(misconf): Disable deprecated checks by default (#7632) --- docs/docs/references/configuration/cli/trivy_config.md | 2 +- docs/docs/references/configuration/cli/trivy_filesystem.md | 2 +- docs/docs/references/configuration/cli/trivy_image.md | 2 +- docs/docs/references/configuration/cli/trivy_kubernetes.md | 2 +- docs/docs/references/configuration/cli/trivy_repository.md | 2 +- docs/docs/references/configuration/cli/trivy_rootfs.md | 2 +- docs/docs/references/configuration/config-file.md | 2 +- pkg/flag/rego_flags.go | 1 - 8 files changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/docs/references/configuration/cli/trivy_config.md b/docs/docs/references/configuration/cli/trivy_config.md index 91cd64292ea8..b32e74c1c752 100644 --- a/docs/docs/references/configuration/cli/trivy_config.md +++ b/docs/docs/references/configuration/cli/trivy_config.md @@ -31,7 +31,7 @@ trivy config [flags] DIR -h, --help help for config --ignore-policy string specify the Rego file path to evaluate each vulnerability --ignorefile string specify .trivyignore file (default ".trivyignore") - --include-deprecated-checks include deprecated checks (default true) + --include-deprecated-checks include deprecated checks --include-non-failures include successes and exceptions, available with '--scanners misconfig' --k8s-version string specify k8s version to validate outdated api by it (example: 1.21.0) --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index 9944a2d618ff..620c43808e91 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -53,7 +53,7 @@ trivy filesystem [flags] PATH --ignore-unfixed display only fixed vulnerabilities --ignored-licenses strings specify a list of license to ignore --ignorefile string specify .trivyignore file (default ".trivyignore") - --include-deprecated-checks include deprecated checks (default true) + --include-deprecated-checks include deprecated checks --include-dev-deps include development dependencies in the report (supported: npm, yarn) --include-non-failures include successes and exceptions, available with '--scanners misconfig' --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [ghcr.io/aquasecurity/trivy-java-db:1]) diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index b63daffbf4ad..cd00214793e6 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -71,7 +71,7 @@ trivy image [flags] IMAGE_NAME --ignorefile string specify .trivyignore file (default ".trivyignore") --image-config-scanners strings comma-separated list of what security issues to detect on container image configurations (misconfig,secret) --image-src strings image source(s) to use, in priority order (docker,containerd,podman,remote) (default [docker,containerd,podman,remote]) - --include-deprecated-checks include deprecated checks (default true) + --include-deprecated-checks include deprecated checks --include-non-failures include successes and exceptions, available with '--scanners misconfig' --input string input file path instead of image name --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [ghcr.io/aquasecurity/trivy-java-db:1]) diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 35190b1b82b5..8cec25ec3cba 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -66,7 +66,7 @@ trivy kubernetes [flags] [CONTEXT] --ignore-unfixed display only fixed vulnerabilities --ignorefile string specify .trivyignore file (default ".trivyignore") --image-src strings image source(s) to use, in priority order (docker,containerd,podman,remote) (default [docker,containerd,podman,remote]) - --include-deprecated-checks include deprecated checks (default true) + --include-deprecated-checks include deprecated checks --include-kinds strings indicate the kinds included in scanning (example: node) --include-namespaces strings indicate the namespaces included in scanning (example: kube-system) --include-non-failures include successes and exceptions, available with '--scanners misconfig' diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index 59e4f2c08cb0..959bf9a8086f 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -53,7 +53,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --ignore-unfixed display only fixed vulnerabilities --ignored-licenses strings specify a list of license to ignore --ignorefile string specify .trivyignore file (default ".trivyignore") - --include-deprecated-checks include deprecated checks (default true) + --include-deprecated-checks include deprecated checks --include-dev-deps include development dependencies in the report (supported: npm, yarn) --include-non-failures include successes and exceptions, available with '--scanners misconfig' --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [ghcr.io/aquasecurity/trivy-java-db:1]) diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index 6022f4589446..277634ed62a9 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -56,7 +56,7 @@ trivy rootfs [flags] ROOTDIR --ignore-unfixed display only fixed vulnerabilities --ignored-licenses strings specify a list of license to ignore --ignorefile string specify .trivyignore file (default ".trivyignore") - --include-deprecated-checks include deprecated checks (default true) + --include-deprecated-checks include deprecated checks --include-non-failures include successes and exceptions, available with '--scanners misconfig' --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [ghcr.io/aquasecurity/trivy-java-db:1]) --license-confidence-level float specify license classifier's confidence level (default 0.9) diff --git a/docs/docs/references/configuration/config-file.md b/docs/docs/references/configuration/config-file.md index ae3a017fda05..21d327c301b7 100644 --- a/docs/docs/references/configuration/config-file.md +++ b/docs/docs/references/configuration/config-file.md @@ -479,7 +479,7 @@ rego: data: [] # Same as '--include-deprecated-checks' - include-deprecated-checks: true + include-deprecated-checks: false # Same as '--check-namespaces' namespaces: [] diff --git a/pkg/flag/rego_flags.go b/pkg/flag/rego_flags.go index 5e856f30062e..4b291f0a5eb3 100644 --- a/pkg/flag/rego_flags.go +++ b/pkg/flag/rego_flags.go @@ -11,7 +11,6 @@ var ( Name: "include-deprecated-checks", ConfigName: "rego.include-deprecated-checks", Usage: "include deprecated checks", - Default: true, } SkipCheckUpdateFlag = Flag[bool]{ Name: "skip-check-update", From 8735242b8fb7c45039c74cf9d9d6111814515740 Mon Sep 17 00:00:00 2001 From: simar7 <1254783+simar7@users.noreply.github.com> Date: Wed, 2 Oct 2024 01:51:30 -0600 Subject: [PATCH 117/183] chore(deps): Bump trivy-checks to v1.1.0 (#7631) --- docs/docs/references/configuration/cli/trivy_config.md | 2 +- docs/docs/references/configuration/cli/trivy_filesystem.md | 2 +- docs/docs/references/configuration/cli/trivy_image.md | 2 +- docs/docs/references/configuration/cli/trivy_kubernetes.md | 2 +- docs/docs/references/configuration/cli/trivy_repository.md | 2 +- docs/docs/references/configuration/cli/trivy_rootfs.md | 2 +- docs/docs/references/configuration/cli/trivy_vm.md | 2 +- docs/docs/references/configuration/config-file.md | 2 +- go.mod | 2 +- go.sum | 4 ++-- pkg/iac/scanners/terraformplan/tfjson/test/scanner_test.go | 2 +- pkg/policy/policy.go | 2 +- 12 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/docs/references/configuration/cli/trivy_config.md b/docs/docs/references/configuration/cli/trivy_config.md index b32e74c1c752..be7854548496 100644 --- a/docs/docs/references/configuration/cli/trivy_config.md +++ b/docs/docs/references/configuration/cli/trivy_config.md @@ -13,7 +13,7 @@ trivy config [flags] DIR --cache-ttl duration cache TTL when using redis as cache backend --cf-params strings specify paths to override the CloudFormation parameters files --check-namespaces strings Rego namespaces - --checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:0") + --checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:1") --compliance string compliance report to generate --config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files --config-data strings specify paths from which data for the Rego checks will be recursively loaded diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index 620c43808e91..0abec4990173 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -23,7 +23,7 @@ trivy filesystem [flags] PATH --cache-ttl duration cache TTL when using redis as cache backend --cf-params strings specify paths to override the CloudFormation parameters files --check-namespaces strings Rego namespaces - --checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:0") + --checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:1") --compliance string compliance report to generate --config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files --config-data strings specify paths from which data for the Rego checks will be recursively loaded diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index cd00214793e6..f9095f041572 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -37,7 +37,7 @@ trivy image [flags] IMAGE_NAME --cache-backend string [EXPERIMENTAL] cache backend (e.g. redis://localhost:6379) (default "fs") --cache-ttl duration cache TTL when using redis as cache backend --check-namespaces strings Rego namespaces - --checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:0") + --checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:1") --compliance string compliance report to generate (docker-cis-1.6.0) --config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files --config-data strings specify paths from which data for the Rego checks will be recursively loaded diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 8cec25ec3cba..99fbc1badaa2 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -33,7 +33,7 @@ trivy kubernetes [flags] [CONTEXT] --cache-backend string [EXPERIMENTAL] cache backend (e.g. redis://localhost:6379) (default "fs") --cache-ttl duration cache TTL when using redis as cache backend --check-namespaces strings Rego namespaces - --checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:0") + --checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:1") --compliance string compliance report to generate (k8s-nsa-1.0,k8s-cis-1.23,eks-cis-1.4,rke2-cis-1.24,k8s-pss-baseline-0.1,k8s-pss-restricted-0.1) --config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files --config-data strings specify paths from which data for the Rego checks will be recursively loaded diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index 959bf9a8086f..821923262dee 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -23,7 +23,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --cache-ttl duration cache TTL when using redis as cache backend --cf-params strings specify paths to override the CloudFormation parameters files --check-namespaces strings Rego namespaces - --checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:0") + --checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:1") --commit string pass the commit hash to be scanned --config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files --config-data strings specify paths from which data for the Rego checks will be recursively loaded diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index 277634ed62a9..bf2575af23b9 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -26,7 +26,7 @@ trivy rootfs [flags] ROOTDIR --cache-ttl duration cache TTL when using redis as cache backend --cf-params strings specify paths to override the CloudFormation parameters files --check-namespaces strings Rego namespaces - --checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:0") + --checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:1") --config-check strings specify the paths to the Rego check files or to the directories containing them, applying config files --config-data strings specify paths from which data for the Rego checks will be recursively loaded --config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking diff --git a/docs/docs/references/configuration/cli/trivy_vm.md b/docs/docs/references/configuration/cli/trivy_vm.md index 9b7f6a6fef43..14ce8b78c21a 100644 --- a/docs/docs/references/configuration/cli/trivy_vm.md +++ b/docs/docs/references/configuration/cli/trivy_vm.md @@ -23,7 +23,7 @@ trivy vm [flags] VM_IMAGE --aws-region string AWS region to scan --cache-backend string [EXPERIMENTAL] cache backend (e.g. redis://localhost:6379) (default "fs") --cache-ttl duration cache TTL when using redis as cache backend - --checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:0") + --checks-bundle-repository string OCI registry URL to retrieve checks bundle from (default "ghcr.io/aquasecurity/trivy-checks:1") --compliance string compliance report to generate --config-file-schemas strings specify paths to JSON configuration file schemas to determine that a file matches some configuration and pass the schema to Rego checks for type checking --custom-headers strings custom headers in client mode diff --git a/docs/docs/references/configuration/config-file.md b/docs/docs/references/configuration/config-file.md index 21d327c301b7..9bc9d4351360 100644 --- a/docs/docs/references/configuration/config-file.md +++ b/docs/docs/references/configuration/config-file.md @@ -373,7 +373,7 @@ license: ```yaml misconfiguration: # Same as '--checks-bundle-repository' - checks-bundle-repository: "ghcr.io/aquasecurity/trivy-checks:0" + checks-bundle-repository: "ghcr.io/aquasecurity/trivy-checks:1" cloudformation: # Same as '--cf-params' diff --git a/go.mod b/go.mod index 8f5e151e6ef4..d0d10457d81c 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/aquasecurity/table v1.8.0 github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8 github.com/aquasecurity/tml v0.6.1 - github.com/aquasecurity/trivy-checks v0.13.1-0.20240830230553-53ddbbade784 + github.com/aquasecurity/trivy-checks v1.1.0 github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1 github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20240707095038-0300bc49b68b diff --git a/go.sum b/go.sum index b284e23f5722..eafeea1e389b 100644 --- a/go.sum +++ b/go.sum @@ -347,8 +347,8 @@ github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8 h1:b43UVqY github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8/go.mod h1:wXA9k3uuaxY3yu7gxrxZDPo/04FEMJtwyecdAlYrEIo= github.com/aquasecurity/tml v0.6.1 h1:y2ZlGSfrhnn7t4ZJ/0rotuH+v5Jgv6BDDO5jB6A9gwo= github.com/aquasecurity/tml v0.6.1/go.mod h1:OnYMWY5lvI9ejU7yH9LCberWaaTBW7hBFsITiIMY2yY= -github.com/aquasecurity/trivy-checks v0.13.1-0.20240830230553-53ddbbade784 h1:1rvPiCK8uQd3sarOuZ60nwksHpxsNdrvptz4eDW/V14= -github.com/aquasecurity/trivy-checks v0.13.1-0.20240830230553-53ddbbade784/go.mod h1:Ralz7PWmR3LirHlXxVtUXc+7CFmWE82jbLk7+TPvV/0= +github.com/aquasecurity/trivy-checks v1.1.0 h1:I0tVOK8dG/KHrWsqfGNYp2uD/i0f+yS7Je31F+LIUqQ= +github.com/aquasecurity/trivy-checks v1.1.0/go.mod h1:tVzhU0gajD3GmxKPLn/BHR8ZeUquc5ajQTmAsi0kCCU= github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1 h1:G0gnacAORRUqz2Tm5MqivSpldY2GZ74ijhJcMsae+sA= github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1/go.mod h1:PYkSRx4dlgFATEt+okGwibvbxVEtqsOdH+vX/saACYE= github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 h1:JVgBIuIYbwG+ekC5lUHUpGJboPYiCcxiz06RCtz8neI= diff --git a/pkg/iac/scanners/terraformplan/tfjson/test/scanner_test.go b/pkg/iac/scanners/terraformplan/tfjson/test/scanner_test.go index 1c0ac8234862..d70280da437f 100644 --- a/pkg/iac/scanners/terraformplan/tfjson/test/scanner_test.go +++ b/pkg/iac/scanners/terraformplan/tfjson/test/scanner_test.go @@ -34,6 +34,6 @@ func Test_Scanning_Plan(t *testing.T) { } } - assert.Len(t, failedResults, 9) + assert.Len(t, failedResults, 8) } diff --git a/pkg/policy/policy.go b/pkg/policy/policy.go index e277936829c5..670588868dcb 100644 --- a/pkg/policy/policy.go +++ b/pkg/policy/policy.go @@ -18,7 +18,7 @@ import ( ) const ( - BundleVersion = 0 // Latest released MAJOR version for trivy-checks + BundleVersion = 1 // Latest released MAJOR version for trivy-checks BundleRepository = "ghcr.io/aquasecurity/trivy-checks" policyMediaType = "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip" updateInterval = 24 * time.Hour From 3e1fa2100074e840bacdd65947425b08750b7d9a Mon Sep 17 00:00:00 2001 From: Samuel Gaist Date: Wed, 2 Oct 2024 12:06:14 +0200 Subject: [PATCH 118/183] fix(secret): change grafana token regex to find them without unquoted (#7627) --- pkg/fanal/secret/builtin-rules.go | 2 +- pkg/fanal/secret/scanner_test.go | 74 +++++++++++++++++++++++ pkg/fanal/secret/testdata/grafana-env.txt | 2 + 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 pkg/fanal/secret/testdata/grafana-env.txt diff --git a/pkg/fanal/secret/builtin-rules.go b/pkg/fanal/secret/builtin-rules.go index a83d8eba35ba..09bf98fd3da8 100644 --- a/pkg/fanal/secret/builtin-rules.go +++ b/pkg/fanal/secret/builtin-rules.go @@ -553,7 +553,7 @@ var builtinRules = []Rule{ Category: CategoryGrafana, Title: "Grafana API token", Severity: "MEDIUM", - Regex: MustCompile(`['\"]eyJrIjoi(?i)[a-z0-9\-_=]{72,92}['\"]`), + Regex: MustCompile(`['\"]?eyJrIjoi(?i)[a-z0-9\-_=]{72,92}['\"]?`), Keywords: []string{"eyJrIjoi"}, }, { diff --git a/pkg/fanal/secret/scanner_test.go b/pkg/fanal/secret/scanner_test.go index 44b5a2458e79..f17b1150dd4a 100644 --- a/pkg/fanal/secret/scanner_test.go +++ b/pkg/fanal/secret/scanner_test.go @@ -690,6 +690,71 @@ func TestSecretScanner(t *testing.T) { }, } + wantFindingGrafanaQuoted := types.SecretFinding{ + RuleID: "grafana-api-token", + Category: secret.CategoryGrafana, + Title: "Grafana API token", + Severity: "MEDIUM", + StartLine: 1, + EndLine: 1, + Match: "GRAFANA_TOKEN=**********************************************************************************************", + Code: types.Code{ + Lines: []types.Line{ + { + Number: 1, + Content: "GRAFANA_TOKEN=**********************************************************************************************", + Highlighted: "GRAFANA_TOKEN=**********************************************************************************************", + IsCause: true, + FirstCause: true, + LastCause: true, + }, + { + Number: 2, + Content: "GRAFANA_TOKEN=**************************************************************************************", + Highlighted: "GRAFANA_TOKEN=**************************************************************************************", + IsCause: false, + FirstCause: false, + LastCause: false, + }, + }, + }, + } + + wantFindingGrafanaUnquoted := types.SecretFinding{ + RuleID: "grafana-api-token", + Category: secret.CategoryGrafana, + Title: "Grafana API token", + Severity: "MEDIUM", + StartLine: 2, + EndLine: 2, + Match: "GRAFANA_TOKEN=********************************************************************************************", + Code: types.Code{ + Lines: []types.Line{ + { + Number: 1, + Content: "GRAFANA_TOKEN=**************************************************************************************", + Highlighted: "GRAFANA_TOKEN=**************************************************************************************", + IsCause: false, + FirstCause: false, + LastCause: false, + }, + { + Number: 2, + Content: "GRAFANA_TOKEN=********************************************************************************************", + Highlighted: "GRAFANA_TOKEN=********************************************************************************************", + IsCause: true, + FirstCause: true, + LastCause: true, + }, + { + Number: 3, + Content: "", + Highlighted: "", + }, + }, + }, + } + wantMultiLine := types.SecretFinding{ RuleID: "multi-line-secret", Category: "general", @@ -858,6 +923,15 @@ func TestSecretScanner(t *testing.T) { Findings: []types.SecretFinding{wantFindingHuggingFace}, }, }, + { + name: "find grafana secret", + configPath: filepath.Join("testdata", "config.yaml"), + inputFilePath: filepath.Join("testdata", "grafana-env.txt"), + want: types.Secret{ + FilePath: filepath.Join("testdata", "grafana-env.txt"), + Findings: []types.SecretFinding{wantFindingGrafanaUnquoted, wantFindingGrafanaQuoted}, + }, + }, { name: "find JWT token", configPath: filepath.Join("testdata", "config.yaml"), diff --git a/pkg/fanal/secret/testdata/grafana-env.txt b/pkg/fanal/secret/testdata/grafana-env.txt new file mode 100644 index 000000000000..ede29f880a6b --- /dev/null +++ b/pkg/fanal/secret/testdata/grafana-env.txt @@ -0,0 +1,2 @@ +GRAFANA_TOKEN="eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbkT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk" +GRAFANA_TOKEN=eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbkT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk From 69bf7e00ea5ab483692db830fdded26a31f03183 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Wed, 2 Oct 2024 15:44:17 +0400 Subject: [PATCH 119/183] feat: support RPM archives (#7628) Signed-off-by: knqyf263 --- .gitignore | 3 + docs/docs/coverage/os/index.md | 4 +- docs/docs/coverage/{os => others}/bitnami.md | 4 +- docs/docs/coverage/{os => others}/conda.md | 0 docs/docs/coverage/others/rpm.md | 42 +++++ docs/docs/supply-chain/sbom.md | 2 +- go.mod | 7 +- go.sum | 14 +- magefiles/magefile.go | 4 +- mkdocs.yml | 6 +- pkg/commands/artifact/run.go | 7 + pkg/fanal/analyzer/const.go | 1 + pkg/fanal/analyzer/pkg/rpm/archive.go | 161 ++++++++++++++++++ pkg/fanal/analyzer/pkg/rpm/archive_test.go | 81 +++++++++ .../analyzer/pkg/rpm/testdata/fixture.go | 63 +++++++ pkg/fanal/applier/docker.go | 2 +- 16 files changed, 386 insertions(+), 15 deletions(-) rename docs/docs/coverage/{os => others}/bitnami.md (95%) rename docs/docs/coverage/{os => others}/conda.md (100%) create mode 100644 docs/docs/coverage/others/rpm.md create mode 100644 pkg/fanal/analyzer/pkg/rpm/archive.go create mode 100644 pkg/fanal/analyzer/pkg/rpm/archive_test.go create mode 100644 pkg/fanal/analyzer/pkg/rpm/testdata/fixture.go diff --git a/.gitignore b/.gitignore index 94254d6b0319..88070261a647 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,6 @@ dist # Signing gpg.key cmd/trivy/trivy + +# RPM +*.rpm diff --git a/docs/docs/coverage/os/index.md b/docs/docs/coverage/os/index.md index a49793db8124..8756ddc8aa95 100644 --- a/docs/docs/coverage/os/index.md +++ b/docs/docs/coverage/os/index.md @@ -28,14 +28,14 @@ Trivy supports operating systems for | [Photon OS](photon.md) | 1.0, 2.0, 3.0, 4.0 | tndf/yum/rpm | | [Debian GNU/Linux](debian.md) | 7, 8, 9, 10, 11, 12 | apt/dpkg | | [Ubuntu](ubuntu.md) | All versions supported by Canonical | apt/dpkg | -| [OSs with installed Conda](conda.md) | - | conda | +| [OSs with installed Conda](../others/conda.md) | - | conda | ## Supported container images | Container image | Supported Versions | Package Managers | |-----------------------------------------------|-------------------------------------|------------------| | [Google Distroless](google-distroless.md)[^2] | Any | apt/dpkg | -| [Bitnami](bitnami.md) | Any | - | +| [Bitnami](../others/bitnami.md) | Any | - | Each page gives more details. diff --git a/docs/docs/coverage/os/bitnami.md b/docs/docs/coverage/others/bitnami.md similarity index 95% rename from docs/docs/coverage/os/bitnami.md rename to docs/docs/coverage/others/bitnami.md index 56cfb97a4601..4773fd9ab20c 100644 --- a/docs/docs/coverage/os/bitnami.md +++ b/docs/docs/coverage/others/bitnami.md @@ -4,8 +4,8 @@ Scanning results may be inaccurate. While it is not an OS, this page describes the details of the [container images provided by Bitnami](https://github.com/bitnami/containers). -Bitnami images are based on [Debian](debian.md). -Please see [the Debian page](debian.md) for OS packages. +Bitnami images are based on [Debian](../os/debian.md). +Please see [the Debian page](../os/debian.md) for OS packages. Trivy supports the following scanners for Bitnami packages. diff --git a/docs/docs/coverage/os/conda.md b/docs/docs/coverage/others/conda.md similarity index 100% rename from docs/docs/coverage/os/conda.md rename to docs/docs/coverage/others/conda.md diff --git a/docs/docs/coverage/others/rpm.md b/docs/docs/coverage/others/rpm.md new file mode 100644 index 000000000000..092cd4396b07 --- /dev/null +++ b/docs/docs/coverage/others/rpm.md @@ -0,0 +1,42 @@ +# RPM Archives + +!!! warning "EXPERIMENTAL" + This feature might change without preserving backwards compatibility. + +Trivy supports the following scanners for RPM archives. + +| Scanner | Supported | +|:-------------:|:---------:| +| SBOM | ✓ | +| Vulnerability | ✓[^1] | +| License | ✓ | + +The table below outlines the features offered by Trivy. + +## SBOM +Trivy analyzes RPM archives matching `*.rpm`. +This feature is currently disabled by default but can be enabled with an environment variable, `TRIVY_EXPERIMENTAL_RPM_ARCHIVE`. + +```shell +TRIVY_EXPERIMENTAL_RPM_ARCHIVE=true trivy fs ./rpms --format cyclonedx --output rpms.cdx.json +``` + +!!! note + Currently, it works with `--format cyclonedx`, `--format spdx` or `--format spdx-json`. + + +## Vulnerability +Since RPM files don't have OS information, you need to generate SBOM, fill in the OS information manually and then scan the SBOM for vulnerabilities. + +For example: + +```shell +$ TRIVY_EXPERIMENTAL_RPM_ARCHIVE=true trivy fs ./rpms -f cyclonedx -o rpms.cdx.json +$ jq '(.components[] | select(.type == "operating-system")) |= (.name = "redhat" | .version = "7.9")' rpms.cdx.json > rpms-res.cdx.json +$ trivy sbom ./rpms-res.cdx.json +``` + +## License +If licenses are included in the RPM archive, Trivy extracts it. + +[^1]: Need to generate SBOM first and add OS information to that SBOM diff --git a/docs/docs/supply-chain/sbom.md b/docs/docs/supply-chain/sbom.md index ed57195b3550..f2f2d55c79a5 100644 --- a/docs/docs/supply-chain/sbom.md +++ b/docs/docs/supply-chain/sbom.md @@ -743,7 +743,7 @@ Trivy searches for SBOM files in container images with the following extensions: - `.cdx` - `.cdx.json` -In addition, Trivy automatically detects SBOM files in [Bitnami images](https://github.com/bitnami/containers), [see here](../coverage/os/bitnami.md) for more details. +In addition, Trivy automatically detects SBOM files in [Bitnami images](https://github.com/bitnami/containers), [see here](../coverage/others/bitnami.md) for more details. It is enabled in the following targets. diff --git a/go.mod b/go.mod index d0d10457d81c..d01ce2a7d4c7 100644 --- a/go.mod +++ b/go.mod @@ -98,6 +98,7 @@ require ( github.com/package-url/packageurl-go v0.1.3 github.com/quasilyte/go-ruleguard/dsl v0.3.22 github.com/samber/lo v1.47.0 + github.com/sassoftware/go-rpmutils v0.4.0 github.com/secure-systems-lab/go-securesystemslib v0.8.0 github.com/sigstore/rekor v1.3.6 github.com/sirupsen/logrus v1.9.3 @@ -152,6 +153,7 @@ require ( github.com/Azure/go-autorest/logger v0.2.1 // indirect github.com/Azure/go-autorest/tracing v0.6.0 // indirect github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 // indirect + github.com/DataDog/zstd v1.5.5 // indirect github.com/Intevation/gval v1.3.0 // indirect github.com/Intevation/jsonpath v0.2.1 // indirect github.com/MakeNowJust/heredoc v1.0.0 // indirect @@ -187,7 +189,7 @@ require ( github.com/briandowns/spinner v1.23.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect - github.com/cloudflare/circl v1.3.7 // indirect + github.com/cloudflare/circl v1.3.8 // indirect github.com/containerd/cgroups/v3 v3.0.2 // indirect github.com/containerd/containerd/api v1.7.19 // indirect github.com/containerd/continuity v0.4.3 // indirect @@ -359,7 +361,7 @@ require ( github.com/tklauser/numcpus v0.7.0 // indirect github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 // indirect github.com/transparency-dev/merkle v0.0.2 // indirect - github.com/ulikunitz/xz v0.5.11 // indirect + github.com/ulikunitz/xz v0.5.12 // indirect github.com/vbatts/tar-split v0.11.5 // indirect github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect @@ -367,6 +369,7 @@ require ( github.com/xanzy/ssh-agent v0.3.3 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect github.com/yashtewari/glob-intersection v0.2.0 // indirect github.com/yuin/gopher-lua v1.1.1 // indirect github.com/yusufpapurcu/wmi v1.2.4 // indirect diff --git a/go.sum b/go.sum index eafeea1e389b..51d43bf95aa1 100644 --- a/go.sum +++ b/go.sum @@ -245,6 +245,8 @@ github.com/CycloneDX/cyclonedx-go v0.9.1 h1:yffaWOZsv77oTJa/SdVZYdgAgFioCeycBUKk github.com/CycloneDX/cyclonedx-go v0.9.1/go.mod h1:NE/EWvzELOFlG6+ljX/QeMlVt9VKcTwu8u0ccsACEsw= github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU= github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU= +github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ= +github.com/DataDog/zstd v1.5.5/go.mod h1:g4AWEaM3yOg3HYfnJ3YIawPnVdXJh9QME85blwSAmyw= github.com/GoogleCloudPlatform/docker-credential-gcr v2.0.5+incompatible h1:juIaKLLVhqzP55d8x4cSVgwyQv76Z55/fRv/UBr2KkQ= github.com/GoogleCloudPlatform/docker-credential-gcr v2.0.5+incompatible/go.mod h1:BB1eHdMLYEFuFdBlRMb0N7YGVdM5s6Pt0njxgvfbGGs= github.com/Intevation/gval v1.3.0 h1:+Ze5sft5MmGbZrHj06NVUbcxCb67l9RaPTLMNr37mjw= @@ -461,8 +463,8 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= -github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cloudflare/circl v1.3.8 h1:j+V8jJt09PoeMFIu2uh5JUyEaIHTXVOHslFoLNAKqwI= +github.com/cloudflare/circl v1.3.8/go.mod h1:PDRU+oXvdD7KCtgKxW95M5Z8BpSCJXQORiZFnBQS5QU= github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= @@ -1219,6 +1221,8 @@ github.com/samber/lo v1.47.0 h1:z7RynLwP5nbyRscyvcD043DWYoOcYRv3mV8lBeqOCLc= github.com/samber/lo v1.47.0/go.mod h1:RmDH9Ct32Qy3gduHQuKJ3gW1fMHAnE/fAzQuf6He5cU= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 h1:lZUw3E0/J3roVtGQ+SCrUrg3ON6NgVqpn3+iol9aGu4= github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= +github.com/sassoftware/go-rpmutils v0.4.0 h1:ojND82NYBxgwrV+mX1CWsd5QJvvEZTKddtCdFLPWhpg= +github.com/sassoftware/go-rpmutils v0.4.0/go.mod h1:3goNWi7PGAT3/dlql2lv3+MSN5jNYPjT5mVcQcIsYzI= github.com/sassoftware/relic v7.2.1+incompatible h1:Pwyh1F3I0r4clFJXkSI8bOyJINGqpgjJU3DYAZeI05A= github.com/sassoftware/relic v7.2.1+incompatible/go.mod h1:CWfAxv73/iLZ17rbyhIEq3K9hs5w6FpNMdUT//qR+zk= github.com/sassoftware/relic/v7 v7.6.2 h1:rS44Lbv9G9eXsukknS4mSjIAuuX+lMq/FnStgmZlUv4= @@ -1344,8 +1348,8 @@ github.com/twitchtv/twirp v8.1.3+incompatible h1:+F4TdErPgSUbMZMwp13Q/KgDVuI7HJX github.com/twitchtv/twirp v8.1.3+incompatible/go.mod h1:RRJoFSAmTEh2weEqWtpPE3vFK5YBhA6bqp2l1kfCC5A= github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8= github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= -github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8= -github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= +github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts= github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk= @@ -1368,6 +1372,8 @@ github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHo github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yashtewari/glob-intersection v0.2.0 h1:8iuHdN88yYuCzCdjt0gDe+6bAhUwBeEWqThExu54RFg= diff --git a/magefiles/magefile.go b/magefiles/magefile.go index b1dbcd3439ad..06ebd7e665e1 100644 --- a/magefiles/magefile.go +++ b/magefiles/magefile.go @@ -16,6 +16,8 @@ import ( "github.com/magefile/mage/sh" "github.com/magefile/mage/target" + //mage:import rpm + rpm "github.com/aquasecurity/trivy/pkg/fanal/analyzer/pkg/rpm/testdata" // Trivy packages should not be imported in Mage (see https://github.com/aquasecurity/trivy/pull/4242), // but this package doesn't have so many dependencies, and Mage is still fast. "github.com/aquasecurity/trivy/pkg/log" @@ -268,7 +270,7 @@ func compileWasmModules(pattern string) error { // Unit runs unit tests func (t Test) Unit() error { - mg.Deps(t.GenerateModules) + mg.Deps(t.GenerateModules, rpm.Fixtures) return sh.RunWithV(ENV, "go", "test", "-v", "-short", "-coverprofile=coverage.txt", "-covermode=atomic", "./...") } diff --git a/mkdocs.yml b/mkdocs.yml index 60ed74306674..abe494df9dd9 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -78,7 +78,6 @@ nav: - Azure Linux (CBL-Mariner): docs/coverage/os/azure.md - CentOS: docs/coverage/os/centos.md - Chainguard: docs/coverage/os/chainguard.md - - Conda: docs/coverage/os/conda.md - Debian: docs/coverage/os/debian.md - Oracle Linux: docs/coverage/os/oracle.md - Photon OS: docs/coverage/os/photon.md @@ -88,7 +87,6 @@ nav: - Ubuntu: docs/coverage/os/ubuntu.md - Wolfi: docs/coverage/os/wolfi.md - Google Distroless (Images): docs/coverage/os/google-distroless.md - - Bitnami (Images): docs/coverage/os/bitnami.md - Language: - Overview: docs/coverage/language/index.md - C/C++: docs/coverage/language/c.md @@ -112,6 +110,10 @@ nav: - Helm: docs/coverage/iac/helm.md - Kubernetes: docs/coverage/iac/kubernetes.md - Terraform: docs/coverage/iac/terraform.md + - Others: + - Bitnami Images: docs/coverage/others/bitnami.md + - Conda: docs/coverage/others/conda.md + - RPM Archives: docs/coverage/others/rpm.md - Kubernetes: docs/coverage/kubernetes.md - Configuration: - Overview: docs/configuration/index.md diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index 0c9560014a0a..49c7d3b34296 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "os" "slices" "github.com/hashicorp/go-multierror" @@ -457,6 +458,12 @@ func disabledAnalyzers(opts flag.Options) []analyzer.Type { analyzers = append(analyzers, analyzer.TypeExecutable) } + // Disable RPM archive analyzer unless the environment variable is set + // TODO: add '--enable-analyzers' and delete this environment variable + if os.Getenv("TRIVY_EXPERIMENTAL_RPM_ARCHIVE") == "" { + analyzers = append(analyzers, analyzer.TypeRpmArchive) + } + return analyzers } diff --git a/pkg/fanal/analyzer/const.go b/pkg/fanal/analyzer/const.go index 197c0033296e..a9733d4b6076 100644 --- a/pkg/fanal/analyzer/const.go +++ b/pkg/fanal/analyzer/const.go @@ -32,6 +32,7 @@ const ( TypeDpkg Type = "dpkg" TypeDpkgLicense Type = "dpkg-license" // For analyzing licenses TypeRpm Type = "rpm" + TypeRpmArchive Type = "rpm-archive" TypeRpmqa Type = "rpmqa" // OS Package Repository diff --git a/pkg/fanal/analyzer/pkg/rpm/archive.go b/pkg/fanal/analyzer/pkg/rpm/archive.go new file mode 100644 index 000000000000..e9db78c6c648 --- /dev/null +++ b/pkg/fanal/analyzer/pkg/rpm/archive.go @@ -0,0 +1,161 @@ +package rpm + +import ( + "context" + "errors" + "os" + "path/filepath" + "strconv" + "strings" + + "github.com/package-url/packageurl-go" + "github.com/sassoftware/go-rpmutils" + "golang.org/x/xerrors" + + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" + "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/log" + "github.com/aquasecurity/trivy/pkg/scanner/utils" +) + +const archiveVersion = 1 + +func init() { + analyzer.RegisterAnalyzer(newRPMArchiveAnalyzer()) +} + +type rpmArchiveAnalyzer struct { + logger *log.Logger +} + +func newRPMArchiveAnalyzer() *rpmArchiveAnalyzer { + return &rpmArchiveAnalyzer{ + logger: log.WithPrefix("rpm-archive"), + } +} + +func (a *rpmArchiveAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) { + rpm, err := rpmutils.ReadRpm(input.Content) + if err != nil { + return nil, xerrors.Errorf("failed to read rpm (%s): %w", input.FilePath, err) + } + pkg, err := a.parseHeader(rpm.Header) + if err != nil { + return nil, xerrors.Errorf("failed to parse rpm header: %w", err) + } + pkg.FilePath = input.FilePath + pkg.Identifier.PURL = a.generatePURL(&pkg) + + return &analyzer.AnalysisResult{ + PackageInfos: []types.PackageInfo{ + { + FilePath: input.FilePath, + Packages: types.Packages{pkg}, + }, + }, + }, nil +} + +func (a *rpmArchiveAnalyzer) parseHeader(h *rpmutils.RpmHeader) (types.Package, error) { + if h == nil { + return types.Package{}, errors.New("rpm header is nil") + } + // Getting metadata + nevra, err := h.GetNEVRA() + if a.unexpectedError(err) != nil { + return types.Package{}, xerrors.Errorf("failed to get NEVRA: %w", err) + } + epoch, err := strconv.Atoi(nevra.Epoch) + if a.unexpectedError(err) != nil { + return types.Package{}, xerrors.Errorf("failed to convert epoch to int (%s): %w", nevra.Name, err) + } + licenses, err := h.GetStrings(rpmutils.LICENSE) + if a.unexpectedError(err) != nil { + return types.Package{}, xerrors.Errorf("failed to get licenses: %w", err) + } + srcName, srcVer, srcRel, err := a.parseSourceRPM(h) + if err != nil { + return types.Package{}, xerrors.Errorf("failed to parse source rpm: %w", err) + } + vendor, err := h.GetString(rpmutils.VENDOR) + if a.unexpectedError(err) != nil { + return types.Package{}, xerrors.Errorf("failed to get vendor: %w", err) + } + + // TODO: add the const to go-rpmutils + // cf. https://github.com/rpm-software-management/rpm/blob/rpm-4.16.0-release/lib/rpmtag.h#L375 + const modularityLabelTag = 5096 + modularityLabel, err := h.GetString(modularityLabelTag) + if a.unexpectedError(err) != nil { + return types.Package{}, xerrors.Errorf("failed to get modularitylabel: %w", err) + } + + return types.Package{ + Name: nevra.Name, + Version: nevra.Version, + Release: nevra.Release, + Epoch: epoch, + Arch: nevra.Arch, + SrcName: srcName, + SrcVersion: srcVer, + SrcRelease: srcRel, + SrcEpoch: epoch, + Licenses: licenses, + Maintainer: vendor, + Modularitylabel: modularityLabel, + }, nil +} + +func (a *rpmArchiveAnalyzer) parseSourceRPM(h *rpmutils.RpmHeader) (string, string, string, error) { + sourceRpm, err := h.GetString(rpmutils.SOURCERPM) + if a.unexpectedError(err) != nil { + return "", "", "", xerrors.Errorf("failed to get source rpm: %w", err) + } else if sourceRpm == "(none)" || sourceRpm == "" { + return "", "", "", nil + } + + srcName, srcVer, srcRel, err := splitFileName(sourceRpm) + if err != nil { + a.logger.Debug("Invalid Source RPM Found", log.String("sourcerpm", sourceRpm)) + } + return srcName, srcVer, srcRel, nil +} + +func (a *rpmArchiveAnalyzer) generatePURL(pkg *types.Package) *packageurl.PackageURL { + vendor := strings.ToLower(pkg.Maintainer) + + // TODO: Handle more vendors + var ns string + switch { + case strings.Contains(vendor, "red hat"): + ns = "redhat" + case strings.Contains(vendor, "fedora"): + ns = "fedora" + case strings.Contains(vendor, "opensuse"): + ns = "opensuse" + case strings.Contains(vendor, "suse"): + ns = "suse" + } + return packageurl.NewPackageURL(packageurl.TypeRPM, ns, pkg.Name, utils.FormatVersion(*pkg), nil, "") +} + +func (a *rpmArchiveAnalyzer) unexpectedError(err error) error { + var rerr rpmutils.NoSuchTagError + if errors.As(err, &rerr) { + a.logger.Debug("RPM tag not found", log.Err(rerr)) + return nil + } + return err +} + +func (a *rpmArchiveAnalyzer) Required(filePath string, _ os.FileInfo) bool { + return filepath.Ext(filePath) == ".rpm" +} + +func (a *rpmArchiveAnalyzer) Type() analyzer.Type { + return analyzer.TypeRpmArchive +} + +func (a *rpmArchiveAnalyzer) Version() int { + return archiveVersion +} diff --git a/pkg/fanal/analyzer/pkg/rpm/archive_test.go b/pkg/fanal/analyzer/pkg/rpm/archive_test.go new file mode 100644 index 000000000000..b9ac0a44ee53 --- /dev/null +++ b/pkg/fanal/analyzer/pkg/rpm/archive_test.go @@ -0,0 +1,81 @@ +package rpm + +import ( + "context" + "os" + "strings" + "testing" + + "github.com/package-url/packageurl-go" + "github.com/samber/lo" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" + "github.com/aquasecurity/trivy/pkg/fanal/types" +) + +func Test_rpmArchiveAnalyzer_Analyze(t *testing.T) { + tests := []struct { + name string + input analyzer.AnalysisInput + want *analyzer.AnalysisResult + wantErr require.ErrorAssertionFunc + }{ + { + name: "valid", + input: analyzer.AnalysisInput{ + FilePath: "testdata/valid.rpm", + Content: lo.Must(os.Open("testdata/socat-1.7.3.2-2.el7.x86_64.rpm")), // Must run 'mage rpm:fixtures' before this test + }, + want: &analyzer.AnalysisResult{ + PackageInfos: []types.PackageInfo{ + { + FilePath: "testdata/valid.rpm", + Packages: types.Packages{ + { + Name: "socat", + Version: "1.7.3.2", + Release: "2.el7", + Arch: "x86_64", + SrcName: "socat", + SrcVersion: "1.7.3.2", + SrcRelease: "2.el7", + FilePath: "testdata/valid.rpm", + Licenses: []string{ + "GPLv2", + }, + Maintainer: "Red Hat, Inc.", + Identifier: types.PkgIdentifier{ + PURL: &packageurl.PackageURL{ + Type: packageurl.TypeRPM, + Namespace: "redhat", + Name: "socat", + Version: "1.7.3.2-2.el7", + }, + }, + }, + }, + }, + }, + }, + wantErr: require.NoError, + }, + { + name: "broken", + input: analyzer.AnalysisInput{ + FilePath: "testdata/broken.rpm", + Content: strings.NewReader(`broken`), + }, + wantErr: require.Error, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := newRPMArchiveAnalyzer() + got, err := a.Analyze(context.Background(), tt.input) + tt.wantErr(t, err) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/pkg/fanal/analyzer/pkg/rpm/testdata/fixture.go b/pkg/fanal/analyzer/pkg/rpm/testdata/fixture.go new file mode 100644 index 000000000000..c9b1c0779f61 --- /dev/null +++ b/pkg/fanal/analyzer/pkg/rpm/testdata/fixture.go @@ -0,0 +1,63 @@ +package rpm + +import ( + "io" + "log/slog" + "net/http" + "os" + "path" + "path/filepath" + "runtime" + + "github.com/magefile/mage/target" + "golang.org/x/xerrors" +) + +const url = "https://mirror.openshift.com/pub/openshift-v4/amd64/dependencies/rpms/4.10-beta/socat-1.7.3.2-2.el7.x86_64.rpm" + +// Fixtures downloads RPM files for unit tests +func Fixtures() error { + _, filePath, _, _ := runtime.Caller(0) + dir := filepath.Dir(filePath) + dst := filepath.Join(dir, path.Base(url)) + + // Download the file only when it is needed + if updated, err := target.Path(dst, filePath); err != nil { + return err + } else if !updated { + return nil + } + return downloadFile(url, dst) +} + +// downloadFile downloads a file from the given URL and saves it with the original filename +// TODO: move this function to a common package for Mage +func downloadFile(url, dst string) error { + slog.Info("Downloading...", slog.String("url", url)) + + // Send a GET request to the URL + resp, err := http.Get(url) + if err != nil { + return xerrors.Errorf("error sending GET request: %v", err) + } + defer resp.Body.Close() + + // Check if the response status code is OK (200) + if resp.StatusCode != http.StatusOK { + return xerrors.Errorf("unexpected status code: %d", resp.StatusCode) + } + + // Create a new file with the extracted filename + out, err := os.Create(dst) + if err != nil { + return xerrors.Errorf("error creating file: %v", err) + } + defer out.Close() + + // Copy the response body to the file + if _, err = io.Copy(out, resp.Body); err != nil { + return xerrors.Errorf("error writing to file: %v", err) + } + + return nil +} diff --git a/pkg/fanal/applier/docker.go b/pkg/fanal/applier/docker.go index c1c21f236b22..6d1967497ab9 100644 --- a/pkg/fanal/applier/docker.go +++ b/pkg/fanal/applier/docker.go @@ -220,7 +220,7 @@ func ApplyLayers(layers []ftypes.BlobInfo) ftypes.ArtifactDetail { mergedLayer.Packages[i].InstalledFiles = installedFiles } - if mergedLayer.OS.Family != "" { + if mergedLayer.OS.Family != "" && pkg.Identifier.PURL == nil { mergedLayer.Packages[i].Identifier.PURL = newPURL(mergedLayer.OS.Family, types.Metadata{OS: &mergedLayer.OS}, pkg) } mergedLayer.Packages[i].Identifier.UID = dependency.UID("", pkg) From fcaea740808d5784c120e5c5d65f5f94e1d931d4 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Thu, 3 Oct 2024 10:27:25 +0600 Subject: [PATCH 120/183] fix(misconf): not to warn about missing selectors of libraries (#7638) Signed-off-by: nikpivkin --- pkg/iac/rego/load.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/pkg/iac/rego/load.go b/pkg/iac/rego/load.go index 8f1033ecfa2d..7356384a3327 100644 --- a/pkg/iac/rego/load.go +++ b/pkg/iac/rego/load.go @@ -302,14 +302,17 @@ func (s *Scanner) filterModules(retriever *MetadataRetriever) error { } if len(meta.InputOptions.Selectors) == 0 { - s.logger.Warn( - "Module has no input selectors - it will be loaded for all inputs!", - log.FilePath(module.Package.Location.File), - log.String("module", name), - ) + if !meta.Library { + s.logger.Warn( + "Module has no input selectors - it will be loaded for all inputs!", + log.FilePath(module.Package.Location.File), + log.String("module", name), + ) + } filtered[name] = module continue } + for _, selector := range meta.InputOptions.Selectors { if selector.Type == string(s.sourceType) { filtered[name] = module From d24640158fb215cc48bcc2e9fcd2676c61d0c480 Mon Sep 17 00:00:00 2001 From: Aqua Security automated builds <54269356+aqua-bot@users.noreply.github.com> Date: Thu, 3 Oct 2024 07:55:35 +0300 Subject: [PATCH 121/183] release: v0.56.0 [main] (#7447) --- .release-please-manifest.json | 2 +- CHANGELOG.md | 45 +++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index aeec62f4b8cc..208746a81be3 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1 +1 @@ -{".":"0.55.0"} +{".":"0.56.0"} diff --git a/CHANGELOG.md b/CHANGELOG.md index 19df5eb64851..afc44ba7a956 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,50 @@ # Changelog +## [0.56.0](https://github.com/aquasecurity/trivy/compare/v0.55.0...v0.56.0) (2024-10-03) + + +### Features + +* **java:** add empty versions if `pom.xml` dependency versions can't be detected ([#7520](https://github.com/aquasecurity/trivy/issues/7520)) ([b836232](https://github.com/aquasecurity/trivy/commit/b8362321adb2af220830c5de31c29978423d47da)) +* **license:** improve license normalization ([#7131](https://github.com/aquasecurity/trivy/issues/7131)) ([6472e3c](https://github.com/aquasecurity/trivy/commit/6472e3c9da2a8e7ba41598a45c80df8f18e57d4c)) +* **misconf:** add ability to disable checks by ID ([#7536](https://github.com/aquasecurity/trivy/issues/7536)) ([ef0a27d](https://github.com/aquasecurity/trivy/commit/ef0a27d515ff80762bf1959d44a8bde017ae06ec)) +* **misconf:** Register checks only when needed ([#7435](https://github.com/aquasecurity/trivy/issues/7435)) ([f768d3a](https://github.com/aquasecurity/trivy/commit/f768d3a767a99a86b0372f19d9f49a2de35dbe59)) +* **misconf:** Support `--skip-*` for all included modules ([#7579](https://github.com/aquasecurity/trivy/issues/7579)) ([c0e8da3](https://github.com/aquasecurity/trivy/commit/c0e8da3828e9d3a0b30d1f6568037db8dc827765)) +* **secret:** enhance secret scanning for python binary files ([#7223](https://github.com/aquasecurity/trivy/issues/7223)) ([60725f8](https://github.com/aquasecurity/trivy/commit/60725f879ba014c5c57583db6afc290b78facae8)) +* support multiple DB repositories for vulnerability and Java DB ([#7605](https://github.com/aquasecurity/trivy/issues/7605)) ([3562529](https://github.com/aquasecurity/trivy/commit/3562529ddfb26d301311ed450c192e17011353df)) +* support RPM archives ([#7628](https://github.com/aquasecurity/trivy/issues/7628)) ([69bf7e0](https://github.com/aquasecurity/trivy/commit/69bf7e00ea5ab483692db830fdded26a31f03183)) +* **suse:** added SUSE Linux Enterprise Micro support ([#7294](https://github.com/aquasecurity/trivy/issues/7294)) ([efdb68d](https://github.com/aquasecurity/trivy/commit/efdb68d3b9ddf9dfaf45ea5855b31c43a4366bab)) + + +### Bug Fixes + +* allow access to '..' in mapfs ([#7575](https://github.com/aquasecurity/trivy/issues/7575)) ([a8fbe46](https://github.com/aquasecurity/trivy/commit/a8fbe46119adbd89f827a75c75b9e97d392f1842)) +* **db:** check `DownloadedAt` for `trivy-java-db` ([#7592](https://github.com/aquasecurity/trivy/issues/7592)) ([13ef3e7](https://github.com/aquasecurity/trivy/commit/13ef3e7d62ba2bcb3a04d7b44f79b1299674b480)) +* **java:** use `dependencyManagement` from root/child pom's for dependencies from parents ([#7497](https://github.com/aquasecurity/trivy/issues/7497)) ([5442949](https://github.com/aquasecurity/trivy/commit/54429497e7d6a87eac236771d4efb8a5a7faaac5)) +* **license:** stop spliting a long license text ([#7336](https://github.com/aquasecurity/trivy/issues/7336)) ([4926da7](https://github.com/aquasecurity/trivy/commit/4926da79de901fba73819d71845ec0355b68ae0f)) +* **misconf:** Disable deprecated checks by default ([#7632](https://github.com/aquasecurity/trivy/issues/7632)) ([82e2adc](https://github.com/aquasecurity/trivy/commit/82e2adc6f8e68d0cc0021031170c2adb60d213ba)) +* **misconf:** disable DS016 check for image history analyzer ([#7540](https://github.com/aquasecurity/trivy/issues/7540)) ([de40df9](https://github.com/aquasecurity/trivy/commit/de40df9408d6d856a3ad384ec9f086edce3aa382)) +* **misconf:** escape all special sequences ([#7558](https://github.com/aquasecurity/trivy/issues/7558)) ([ea0cf03](https://github.com/aquasecurity/trivy/commit/ea0cf0379aff0348fde87356dab37947800fc1b6)) +* **misconf:** Fix logging typo ([#7473](https://github.com/aquasecurity/trivy/issues/7473)) ([56db43c](https://github.com/aquasecurity/trivy/commit/56db43c24f4f6be92891be85faaf9492cad516ac)) +* **misconf:** Fixed scope for China Cloud ([#7560](https://github.com/aquasecurity/trivy/issues/7560)) ([37d549e](https://github.com/aquasecurity/trivy/commit/37d549e5b86a1c5dce6710fbfd2310aec9abe949)) +* **misconf:** not to warn about missing selectors of libraries ([#7638](https://github.com/aquasecurity/trivy/issues/7638)) ([fcaea74](https://github.com/aquasecurity/trivy/commit/fcaea740808d5784c120e5c5d65f5f94e1d931d4)) +* **oracle:** Update EOL date for Oracle 7 ([#7480](https://github.com/aquasecurity/trivy/issues/7480)) ([dd0a64a](https://github.com/aquasecurity/trivy/commit/dd0a64a1cf0cd76e6f81e3ff55fa6ccb95ce3c3d)) +* **report:** change a receiver of MarshalJSON ([#7483](https://github.com/aquasecurity/trivy/issues/7483)) ([927c6e0](https://github.com/aquasecurity/trivy/commit/927c6e0c9d4d4a3f1be00f0f661c1d18325d9440)) +* **report:** fix error with unmarshal of `ExperimentalModifiedFindings` ([#7463](https://github.com/aquasecurity/trivy/issues/7463)) ([7ff9aff](https://github.com/aquasecurity/trivy/commit/7ff9aff2739b2eee4a98175b98914795e4077060)) +* **sbom:** export bom-ref when converting a package to a component ([#7340](https://github.com/aquasecurity/trivy/issues/7340)) ([5dd94eb](https://github.com/aquasecurity/trivy/commit/5dd94ebc1ffe3f1df511dee6381f92a5daefadf2)) +* **sbom:** parse type `framework` as `library` when unmarshalling `CycloneDX` files ([#7527](https://github.com/aquasecurity/trivy/issues/7527)) ([aeb7039](https://github.com/aquasecurity/trivy/commit/aeb7039d7ce090e243d29f0bf16c9e4e24252a01)) +* **secret:** change grafana token regex to find them without unquoted ([#7627](https://github.com/aquasecurity/trivy/issues/7627)) ([3e1fa21](https://github.com/aquasecurity/trivy/commit/3e1fa2100074e840bacdd65947425b08750b7d9a)) + + +### Performance Improvements + +* **misconf:** use port ranges instead of enumeration ([#7549](https://github.com/aquasecurity/trivy/issues/7549)) ([1f9fc13](https://github.com/aquasecurity/trivy/commit/1f9fc13da4a1e7c76c978e4f8e119bfd61a0480e)) + + +### Reverts + +* **java:** stop supporting of `test` scope for `pom.xml` files ([#7488](https://github.com/aquasecurity/trivy/issues/7488)) ([b0222fe](https://github.com/aquasecurity/trivy/commit/b0222feeb586ec59904bb321fda8f3f22496d07b)) + ## [0.55.0](https://github.com/aquasecurity/trivy/compare/v0.54.0...v0.55.0) (2024-09-03) From cb0b3a9279b31810ecd686a385e5140e567ce86f Mon Sep 17 00:00:00 2001 From: Samuel Gaist Date: Thu, 3 Oct 2024 06:56:59 +0200 Subject: [PATCH 122/183] feat(cli): error out when ignore file cannot be found (#7624) --- pkg/flag/report_flags.go | 6 ++++++ pkg/flag/report_flags_test.go | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/pkg/flag/report_flags.go b/pkg/flag/report_flags.go index 67d553b65553..d69443e89547 100644 --- a/pkg/flag/report_flags.go +++ b/pkg/flag/report_flags.go @@ -6,6 +6,7 @@ import ( "github.com/mattn/go-shellwords" "github.com/samber/lo" + "github.com/spf13/viper" "golang.org/x/xerrors" dbTypes "github.com/aquasecurity/trivy-db/pkg/types" @@ -14,6 +15,7 @@ import ( "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/result" "github.com/aquasecurity/trivy/pkg/types" + "github.com/aquasecurity/trivy/pkg/utils/fsutils" xstrings "github.com/aquasecurity/trivy/pkg/x/strings" ) @@ -238,6 +240,10 @@ func (f *ReportFlagGroup) ToOptions() (ReportOptions, error) { } } + if viper.IsSet(f.IgnoreFile.ConfigName) && !fsutils.FileExists(f.IgnoreFile.Value()) { + return ReportOptions{}, xerrors.Errorf("ignore file not found: %s", f.IgnoreFile.Value()) + } + return ReportOptions{ Format: format, ReportFormat: f.ReportFormat.Value(), diff --git a/pkg/flag/report_flags_test.go b/pkg/flag/report_flags_test.go index 9440bf373905..b113d7c62f97 100644 --- a/pkg/flag/report_flags_test.go +++ b/pkg/flag/report_flags_test.go @@ -209,4 +209,16 @@ func TestReportFlagGroup_ToOptions(t *testing.T) { assert.Equal(t, tt.wantLogs, out.Messages(), tt.name) }) } + + t.Run("Error on non existing ignore file", func(t *testing.T) { + t.Cleanup(viper.Reset) + + setValue(flag.IgnoreFileFlag.ConfigName, string("doesntexist")) + f := &flag.ReportFlagGroup{ + IgnoreFile: flag.IgnoreFileFlag.Clone(), + } + + _, err := f.ToOptions() + assert.ErrorContains(t, err, "ignore file not found: doesntexist") + }) } From 2c87f0cb794acd77446a273582ba1a45b9f18980 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Thu, 3 Oct 2024 18:11:58 +0600 Subject: [PATCH 123/183] fix(db): fix javadb downloading error handling (#7642) Signed-off-by: nikpivkin --- pkg/javadb/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/javadb/client.go b/pkg/javadb/client.go index 6d5b589bb5d1..835730109b02 100644 --- a/pkg/javadb/client.go +++ b/pkg/javadb/client.go @@ -104,10 +104,10 @@ func (u *Updater) downloadDB(ctx context.Context) error { Quiet: u.quiet, } if err := artifacts.Download(ctx, u.dbDir, downloadOpt); err != nil { - return xerrors.Errorf("failed to download vulnerability DB: %w", err) + return xerrors.Errorf("failed to download Java DB: %w", err) } - return xerrors.New("failed to download Java DB from any source") + return nil } func Init(cacheDir string, javaDBRepositories []name.Reference, skip, quiet bool, registryOption ftypes.RegistryOptions) { From ab3a3b2e6ed15db90967084fac825ddb2f50e70d Mon Sep 17 00:00:00 2001 From: Pierre Baumard Date: Mon, 7 Oct 2024 09:41:01 +0200 Subject: [PATCH 124/183] docs(report): Improve SARIF reporting doc (#7655) --- docs/docs/configuration/reporting.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/docs/configuration/reporting.md b/docs/docs/configuration/reporting.md index 17bf0b864283..fcbde0b106ff 100644 --- a/docs/docs/configuration/reporting.md +++ b/docs/docs/configuration/reporting.md @@ -5,7 +5,7 @@ Trivy supports the following formats: - Table - JSON -- [SARIF](https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/sarif-support-for-code-scanning) +- [SARIF][sarif-home] - Template - SBOM - GitHub dependency snapshot @@ -252,13 +252,15 @@ $ trivy image -f json -o results.json golang:1.12-alpine | Secret | ✓ | | License | ✓ | -[SARIF][sarif] can be generated with the `--format sarif` flag. +[SARIF][sarif-home] (Static Analysis Results Interchange Format) complying with [SARIF 2.1.0 OASIS standard][sarif-spec] can be generated with the `--format sarif` flag. ``` $ trivy image --format sarif -o report.sarif golang:1.12-alpine ``` -This SARIF file can be uploaded to GitHub code scanning results, and there is a [Trivy GitHub Action][action] for automating this process. +This SARIF file can be uploaded to several platforms, including: +- [GitHub code scanning results][sarif-github], and there is a [Trivy GitHub Action][action] for automating this process; +- [SonarQube][sarif-sonar]. ### GitHub dependency snapshot Trivy supports the following packages. @@ -430,7 +432,10 @@ $ trivy convert --format table --severity CRITICAL result.json [cargo-auditable]: https://github.com/rust-secure-code/cargo-auditable/ [action]: https://github.com/aquasecurity/trivy-action [asff]: ../../tutorials/integrations/aws-security-hub.md -[sarif]: https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/managing-results-from-code-scanning +[sarif-home]: https://sarifweb.azurewebsites.net +[sarif-spec]: https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html +[sarif-github]: https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning +[sarif-sonar]: https://docs.sonarsource.com/sonarqube/latest/analyzing-source-code/importing-external-issues/importing-issues-from-sarif-reports/ [sprig]: http://masterminds.github.io/sprig/ [github-sbom]: https://docs.github.com/en/rest/dependency-graph/dependency-submission?apiVersion=2022-11-28#about-dependency-submissions [github-sbom-submit]: https://docs.github.com/en/rest/dependency-graph/dependency-submission?apiVersion=2022-11-28#create-a-snapshot-of-dependencies-for-a-repository @@ -450,4 +455,4 @@ $ trivy convert --format table --severity CRITICAL result.json [gradle-lockfile]: ../coverage/language/java.md#gradlelock [sbt-lockfile]: ../coverage/language/java.md#sbt [pubspec-lock]: ../coverage/language/dart.md#dart -[cargo-binaries]: ../coverage/language/rust.md#binaries \ No newline at end of file +[cargo-binaries]: ../coverage/language/rust.md#binaries From 015bb885ac414b91201fa9791eead395d878149c Mon Sep 17 00:00:00 2001 From: Pierre Baumard Date: Mon, 7 Oct 2024 13:31:59 +0200 Subject: [PATCH 125/183] fix(report): Fix invalid URI in SARIF report (#7645) Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> --- pkg/report/sarif.go | 37 ++++++++++++++++++++++++------------- pkg/report/sarif_test.go | 34 +++++++++++++++++----------------- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/pkg/report/sarif.go b/pkg/report/sarif.go index a94dcccb2c9b..3bc3344611e2 100644 --- a/pkg/report/sarif.go +++ b/pkg/report/sarif.go @@ -5,6 +5,7 @@ import ( "fmt" "html" "io" + "net/url" "path/filepath" "regexp" "strings" @@ -15,6 +16,7 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/artifact" ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/types" ) @@ -61,9 +63,9 @@ type sarifData struct { helpMarkdown string resourceClass types.ResultClass severity string - url string + url *url.URL resultIndex int - artifactLocation string + artifactLocation *url.URL locationMessage string message string cvssScore string @@ -97,8 +99,8 @@ func (sw *SarifWriter) addSarifRule(data *sarifData) { "precision": "very-high", "security-severity": data.cvssScore, }) - if data.url != "" { - r.WithHelpURI(data.url) + if data.url != nil && data.url.String() != "" { + r.WithHelpURI(data.url.String()) } } @@ -109,7 +111,7 @@ func (sw *SarifWriter) addSarifResult(data *sarifData) { WithRuleIndex(data.resultIndex). WithMessage(sarif.NewTextMessage(data.message)). WithLevel(toSarifErrorLevel(data.severity)). - WithLocations(toSarifLocations(data.locations, data.artifactLocation, data.locationMessage)) + WithLocations(toSarifLocations(data.locations, data.artifactLocation.String(), data.locationMessage)) sw.run.AddResult(result) } @@ -163,9 +165,9 @@ func (sw *SarifWriter) Write(ctx context.Context, report types.Report) error { vulnerabilityId: vuln.VulnerabilityID, severity: vuln.Severity, cvssScore: getCVSSScore(vuln), - url: vuln.PrimaryURL, + url: toUri(vuln.PrimaryURL), resourceClass: res.Class, - artifactLocation: path, + artifactLocation: toUri(path), locationMessage: fmt.Sprintf("%v: %v@%v", path, vuln.PkgName, vuln.InstalledVersion), locations: sw.getLocations(vuln.PkgName, vuln.InstalledVersion, path, res.Packages), resultIndex: getRuleIndex(vuln.VulnerabilityID, ruleIndexes), @@ -186,9 +188,9 @@ func (sw *SarifWriter) Write(ctx context.Context, report types.Report) error { vulnerabilityId: misconf.ID, severity: misconf.Severity, cvssScore: severityToScore(misconf.Severity), - url: misconf.PrimaryURL, + url: toUri(misconf.PrimaryURL), resourceClass: res.Class, - artifactLocation: locationURI, + artifactLocation: toUri(locationURI), locationMessage: locationURI, locations: []location{ { @@ -213,9 +215,9 @@ func (sw *SarifWriter) Write(ctx context.Context, report types.Report) error { vulnerabilityId: secret.RuleID, severity: secret.Severity, cvssScore: severityToScore(secret.Severity), - url: builtinRulesUrl, + url: toUri(builtinRulesUrl), resourceClass: res.Class, - artifactLocation: target, + artifactLocation: toUri(target), locationMessage: target, locations: []location{ { @@ -242,9 +244,9 @@ func (sw *SarifWriter) Write(ctx context.Context, report types.Report) error { vulnerabilityId: id, severity: license.Severity, cvssScore: severityToScore(license.Severity), - url: license.Link, + url: toUri(license.Link), resourceClass: res.Class, - artifactLocation: target, + artifactLocation: toUri(target), resultIndex: getRuleIndex(id, ruleIndexes), shortDescription: desc, fullDescription: desc, @@ -348,6 +350,15 @@ func clearURI(s string) string { return strings.ReplaceAll(strings.ReplaceAll(s, "\\", "/"), "git::https:/", "") } +func toUri(str string) *url.URL { + uri, err := url.Parse(str) + if err != nil { + logger := log.WithPrefix("sarif") + logger.Error("Unable to parse URI", log.String("URI", str), log.Err(err)) + } + return uri +} + func (sw *SarifWriter) getLocations(name, version, path string, pkgs []ftypes.Package) []location { id := fmt.Sprintf("%s@%s@%s", path, name, version) locs, ok := sw.locationCache[id] diff --git a/pkg/report/sarif_test.go b/pkg/report/sarif_test.go index cf4bfea8eb0b..ce68fab06a8a 100644 --- a/pkg/report/sarif_test.go +++ b/pkg/report/sarif_test.go @@ -41,7 +41,7 @@ func TestReportWriter_Sarif(t *testing.T) { }, Results: types.Results{ { - Target: "library/test", + Target: "library/test 1", Class: types.ClassOSPkg, Packages: []ftypes.Package{ { @@ -137,10 +137,10 @@ func TestReportWriter_Sarif(t *testing.T) { Message: sarif.Message{Text: lo.ToPtr("Package: foo\nInstalled Version: 1.2.3\nVulnerability CVE-2020-0001\nSeverity: HIGH\nFixed Version: 3.4.5\nLink: [CVE-2020-0001](https://avd.aquasec.com/nvd/cve-2020-0001)")}, Locations: []*sarif.Location{ { - Message: &sarif.Message{Text: lo.ToPtr("library/test: foo@1.2.3")}, + Message: &sarif.Message{Text: lo.ToPtr("library/test 1: foo@1.2.3")}, PhysicalLocation: &sarif.PhysicalLocation{ ArtifactLocation: &sarif.ArtifactLocation{ - URI: lo.ToPtr("library/test"), + URI: lo.ToPtr("library/test%201"), URIBaseId: lo.ToPtr("ROOTPATH"), }, Region: &sarif.Region{ @@ -152,10 +152,10 @@ func TestReportWriter_Sarif(t *testing.T) { }, }, { - Message: &sarif.Message{Text: lo.ToPtr("library/test: foo@1.2.3")}, + Message: &sarif.Message{Text: lo.ToPtr("library/test 1: foo@1.2.3")}, PhysicalLocation: &sarif.PhysicalLocation{ ArtifactLocation: &sarif.ArtifactLocation{ - URI: lo.ToPtr("library/test"), + URI: lo.ToPtr("library/test%201"), URIBaseId: lo.ToPtr("ROOTPATH"), }, Region: &sarif.Region{ @@ -192,7 +192,7 @@ func TestReportWriter_Sarif(t *testing.T) { input: types.Report{ Results: types.Results{ { - Target: "library/test", + Target: "library/test 1", Class: types.ClassConfig, Misconfigurations: []types.DetectedMisconfiguration{ { @@ -283,13 +283,13 @@ func TestReportWriter_Sarif(t *testing.T) { RuleID: lo.ToPtr("KSV001"), RuleIndex: lo.ToPtr[uint](0), Level: lo.ToPtr("error"), - Message: sarif.Message{Text: lo.ToPtr("Artifact: library/test\nType: \nVulnerability KSV001\nSeverity: HIGH\nMessage: Message\nLink: [KSV001](https://avd.aquasec.com/appshield/ksv001)")}, + Message: sarif.Message{Text: lo.ToPtr("Artifact: library/test 1\nType: \nVulnerability KSV001\nSeverity: HIGH\nMessage: Message\nLink: [KSV001](https://avd.aquasec.com/appshield/ksv001)")}, Locations: []*sarif.Location{ { - Message: &sarif.Message{Text: lo.ToPtr("library/test")}, + Message: &sarif.Message{Text: lo.ToPtr("library/test 1")}, PhysicalLocation: &sarif.PhysicalLocation{ ArtifactLocation: &sarif.ArtifactLocation{ - URI: lo.ToPtr("library/test"), + URI: lo.ToPtr("library/test%201"), URIBaseId: lo.ToPtr("ROOTPATH"), }, Region: &sarif.Region{ @@ -306,13 +306,13 @@ func TestReportWriter_Sarif(t *testing.T) { RuleID: lo.ToPtr("KSV002"), RuleIndex: lo.ToPtr[uint](1), Level: lo.ToPtr("error"), - Message: sarif.Message{Text: lo.ToPtr("Artifact: library/test\nType: \nVulnerability KSV002\nSeverity: CRITICAL\nMessage: Message\nLink: [KSV002](https://avd.aquasec.com/appshield/ksv002)")}, + Message: sarif.Message{Text: lo.ToPtr("Artifact: library/test 1\nType: \nVulnerability KSV002\nSeverity: CRITICAL\nMessage: Message\nLink: [KSV002](https://avd.aquasec.com/appshield/ksv002)")}, Locations: []*sarif.Location{ { - Message: &sarif.Message{Text: lo.ToPtr("library/test")}, + Message: &sarif.Message{Text: lo.ToPtr("library/test 1")}, PhysicalLocation: &sarif.PhysicalLocation{ ArtifactLocation: &sarif.ArtifactLocation{ - URI: lo.ToPtr("library/test"), + URI: lo.ToPtr("library/test%201"), URIBaseId: lo.ToPtr("ROOTPATH"), }, Region: &sarif.Region{ @@ -341,7 +341,7 @@ func TestReportWriter_Sarif(t *testing.T) { input: types.Report{ Results: types.Results{ { - Target: "library/test", + Target: "library/test 1", Class: types.ClassSecret, Secrets: []types.DetectedSecret{ { @@ -400,13 +400,13 @@ func TestReportWriter_Sarif(t *testing.T) { RuleID: lo.ToPtr("aws-secret-access-key"), RuleIndex: lo.ToPtr[uint](0), Level: lo.ToPtr("error"), - Message: sarif.Message{Text: lo.ToPtr("Artifact: library/test\nType: \nSecret AWS Secret Access Key\nSeverity: CRITICAL\nMatch: 'AWS_secret_KEY'=\"****************************************\"")}, + Message: sarif.Message{Text: lo.ToPtr("Artifact: library/test 1\nType: \nSecret AWS Secret Access Key\nSeverity: CRITICAL\nMatch: 'AWS_secret_KEY'=\"****************************************\"")}, Locations: []*sarif.Location{ { - Message: &sarif.Message{Text: lo.ToPtr("library/test")}, + Message: &sarif.Message{Text: lo.ToPtr("library/test 1")}, PhysicalLocation: &sarif.PhysicalLocation{ ArtifactLocation: &sarif.ArtifactLocation{ - URI: lo.ToPtr("library/test"), + URI: lo.ToPtr("library/test%201"), URIBaseId: lo.ToPtr("ROOTPATH"), }, Region: &sarif.Region{ @@ -495,7 +495,7 @@ func TestReportWriter_Sarif(t *testing.T) { Message: sarif.NewTextMessage(""), PhysicalLocation: &sarif.PhysicalLocation{ ArtifactLocation: &sarif.ArtifactLocation{ - URI: lo.ToPtr("OS Packages"), + URI: lo.ToPtr("OS%20Packages"), URIBaseId: lo.ToPtr("ROOTPATH"), }, Region: &sarif.Region{ From a585e95f3398631d9ad10505c5ff642fde21aef7 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Mon, 7 Oct 2024 16:03:40 +0400 Subject: [PATCH 126/183] fix(redhat): include arch in PURL qualifiers (#7654) Signed-off-by: knqyf263 --- pkg/fanal/analyzer/pkg/rpm/archive.go | 9 ++++++++- pkg/fanal/analyzer/pkg/rpm/archive_test.go | 6 ++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/pkg/fanal/analyzer/pkg/rpm/archive.go b/pkg/fanal/analyzer/pkg/rpm/archive.go index e9db78c6c648..2eda91e4a563 100644 --- a/pkg/fanal/analyzer/pkg/rpm/archive.go +++ b/pkg/fanal/analyzer/pkg/rpm/archive.go @@ -136,7 +136,14 @@ func (a *rpmArchiveAnalyzer) generatePURL(pkg *types.Package) *packageurl.Packag case strings.Contains(vendor, "suse"): ns = "suse" } - return packageurl.NewPackageURL(packageurl.TypeRPM, ns, pkg.Name, utils.FormatVersion(*pkg), nil, "") + var qualifiers packageurl.Qualifiers + if pkg.Arch != "" { + qualifiers = append(qualifiers, packageurl.Qualifier{ + Key: "arch", + Value: pkg.Arch, + }) + } + return packageurl.NewPackageURL(packageurl.TypeRPM, ns, pkg.Name, utils.FormatVersion(*pkg), qualifiers, "") } func (a *rpmArchiveAnalyzer) unexpectedError(err error) error { diff --git a/pkg/fanal/analyzer/pkg/rpm/archive_test.go b/pkg/fanal/analyzer/pkg/rpm/archive_test.go index b9ac0a44ee53..5e8475e171f6 100644 --- a/pkg/fanal/analyzer/pkg/rpm/archive_test.go +++ b/pkg/fanal/analyzer/pkg/rpm/archive_test.go @@ -52,6 +52,12 @@ func Test_rpmArchiveAnalyzer_Analyze(t *testing.T) { Namespace: "redhat", Name: "socat", Version: "1.7.3.2-2.el7", + Qualifiers: packageurl.Qualifiers{ + { + Key: "arch", + Value: "x86_64", + }, + }, }, }, }, From fdf203cd209aeb40f454bd12d121a54d6ed7a542 Mon Sep 17 00:00:00 2001 From: Dan Kirkwood Date: Mon, 7 Oct 2024 22:04:06 -0700 Subject: [PATCH 127/183] fix(repo): `git clone` output to Stderr (#7561) --- pkg/fanal/artifact/repo/git.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/fanal/artifact/repo/git.go b/pkg/fanal/artifact/repo/git.go index 8eb3d9af7f9d..4532b631c6b7 100644 --- a/pkg/fanal/artifact/repo/git.go +++ b/pkg/fanal/artifact/repo/git.go @@ -128,7 +128,7 @@ func cloneRepo(u *url.URL, artifactOpt artifact.Option) (string, error) { cloneOptions := git.CloneOptions{ URL: u.String(), Auth: gitAuth(), - Progress: os.Stdout, + Progress: os.Stderr, InsecureSkipTLS: artifactOpt.Insecure, } From 55b5a7e01b679f58b54b1e84a96da21d940eaf22 Mon Sep 17 00:00:00 2001 From: Pierre Baumard Date: Tue, 8 Oct 2024 19:01:49 +0200 Subject: [PATCH 128/183] docs(report): fix reporting doc format (#7671) --- docs/docs/configuration/reporting.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/docs/configuration/reporting.md b/docs/docs/configuration/reporting.md index fcbde0b106ff..39ecb6e5333c 100644 --- a/docs/docs/configuration/reporting.md +++ b/docs/docs/configuration/reporting.md @@ -259,11 +259,12 @@ $ trivy image --format sarif -o report.sarif golang:1.12-alpine ``` This SARIF file can be uploaded to several platforms, including: -- [GitHub code scanning results][sarif-github], and there is a [Trivy GitHub Action][action] for automating this process; -- [SonarQube][sarif-sonar]. + +- [GitHub code scanning results][sarif-github], and there is a [Trivy GitHub Action][action] for automating this process +- [SonarQube][sarif-sonar] ### GitHub dependency snapshot -Trivy supports the following packages. +Trivy supports the following packages: - [OS packages][os_packages] - [Language-specific packages][language_packages] From 1f2e91b02b3606dd11963002a8cfac7962f3478f Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Wed, 9 Oct 2024 09:53:27 +0400 Subject: [PATCH 129/183] fix(sbom): add options for DBs in private registries (#7660) Signed-off-by: knqyf263 --- docs/docs/references/configuration/cli/trivy_sbom.md | 3 +++ pkg/commands/app.go | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/docs/references/configuration/cli/trivy_sbom.md b/docs/docs/references/configuration/cli/trivy_sbom.md index f09453845518..4eaedcf17aa5 100644 --- a/docs/docs/references/configuration/cli/trivy_sbom.md +++ b/docs/docs/references/configuration/cli/trivy_sbom.md @@ -47,12 +47,14 @@ trivy sbom [flags] SBOM_PATH --offline-scan do not issue API requests to identify dependencies -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments + --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend --redis-key string redis key file location, if using redis as cache backend --redis-tls enable redis TLS with public certificates, if using redis as cache backend + --registry-token string registry token --rekor-url string [EXPERIMENTAL] address of rekor STL server (default "https://rekor.sigstore.dev") --sbom-sources strings [EXPERIMENTAL] try to retrieve SBOM from the specified sources (oci,rekor) --scanners strings comma-separated list of what security issues to detect (vuln,license) (default [vuln]) @@ -67,6 +69,7 @@ trivy sbom [flags] SBOM_PATH -t, --template string output template --token string for authentication in client/server mode --token-header string specify a header name for token in client/server mode (default "Trivy-Token") + --username strings username. Comma-separated usernames allowed. --vex strings [EXPERIMENTAL] VEX sources ("repo", "oci" or file path) ``` diff --git a/pkg/commands/app.go b/pkg/commands/app.go index 23b44fdec553..bdba2fa12ac7 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -1143,7 +1143,8 @@ func NewSBOMCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { CacheFlagGroup: flag.NewCacheFlagGroup(), DBFlagGroup: flag.NewDBFlagGroup(), PackageFlagGroup: flag.NewPackageFlagGroup(), - RemoteFlagGroup: flag.NewClientFlags(), // for client/server mode + RemoteFlagGroup: flag.NewClientFlags(), // for client/server mode + RegistryFlagGroup: flag.NewRegistryFlagGroup(), // for DBs in private registries ReportFlagGroup: reportFlagGroup, ScanFlagGroup: scanFlagGroup, VulnerabilityFlagGroup: flag.NewVulnerabilityFlagGroup(), From 27117f81d52483c3ceec56fe56ac298e242fbc9a Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Wed, 9 Oct 2024 14:31:15 +0400 Subject: [PATCH 130/183] feat(cli): add `trivy auth` (#7664) Signed-off-by: knqyf263 Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> --- contrib/Trivy.gitlab-ci.yml | 2 +- .../docs/advanced/private-registries/index.md | 34 +++-- .../references/configuration/cli/trivy.md | 1 + .../configuration/cli/trivy_auth.md | 29 ++++ .../configuration/cli/trivy_auth_login.md | 41 +++++ .../configuration/cli/trivy_auth_logout.md | 38 +++++ .../configuration/cli/trivy_config.md | 1 + .../configuration/cli/trivy_filesystem.md | 1 + .../configuration/cli/trivy_image.md | 1 + .../configuration/cli/trivy_kubernetes.md | 1 + .../configuration/cli/trivy_repository.md | 1 + .../configuration/cli/trivy_rootfs.md | 1 + .../configuration/cli/trivy_sbom.md | 1 + .../configuration/cli/trivy_server.md | 1 + .../references/configuration/config-file.md | 3 + docs/docs/target/container_image.md | 2 +- go.mod | 2 +- integration/registry_test.go | 39 ++++- mkdocs.yml | 4 + pkg/commands/app.go | 58 +++++++ pkg/commands/auth/run.go | 109 ++++++++++++++ pkg/commands/auth/run_test.go | 142 ++++++++++++++++++ pkg/flag/registry_flags.go | 23 ++- 23 files changed, 512 insertions(+), 23 deletions(-) create mode 100644 docs/docs/references/configuration/cli/trivy_auth.md create mode 100644 docs/docs/references/configuration/cli/trivy_auth_login.md create mode 100644 docs/docs/references/configuration/cli/trivy_auth_logout.md create mode 100644 pkg/commands/auth/run.go create mode 100644 pkg/commands/auth/run_test.go diff --git a/contrib/Trivy.gitlab-ci.yml b/contrib/Trivy.gitlab-ci.yml index 66225b0dac06..a62e26301a20 100644 --- a/contrib/Trivy.gitlab-ci.yml +++ b/contrib/Trivy.gitlab-ci.yml @@ -12,9 +12,9 @@ Trivy_container_scanning: before_script: - export TRIVY_VERSION=${TRIVY_VERSION:-v0.19.2} - apk add --no-cache curl docker-cli - - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY - curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin ${TRIVY_VERSION} - curl -sSL -o /tmp/trivy-gitlab.tpl https://github.com/aquasecurity/trivy/raw/${TRIVY_VERSION}/contrib/gitlab.tpl + - trivy auth login --username "$CI_REGISTRY_USER" --password "$CI_REGISTRY_PASSWORD" $CI_REGISTRY script: - trivy --exit-code 0 --cache-dir .trivycache/ --no-progress --format template --template "@/tmp/trivy-gitlab.tpl" -o gl-container-scanning-report.json $IMAGE cache: diff --git a/docs/docs/advanced/private-registries/index.md b/docs/docs/advanced/private-registries/index.md index 7d5a594cf5b6..7bac7a2742d5 100644 --- a/docs/docs/advanced/private-registries/index.md +++ b/docs/docs/advanced/private-registries/index.md @@ -1,13 +1,30 @@ Trivy can download images from a private registry without the need for installing Docker or any other 3rd party tools. This makes it easy to run within a CI process. -## Credential -To use Trivy with private images, simply install it and provide your credentials: +## Login +You can log in to a private registry using the `trivy auth login` command. +It uses the Docker configuration file (`~/.docker/config.json`) to store the credentials under the hood, and the configuration file path can be configured by `DOCKER_CONFIG` environment variable. + +```shell +$ cat ~/my_password.txt | trivy auth login --username foo --password-stdin ghcr.io +$ trivy image ghcr.io/your/private_image +``` + +## Passing Credentials +You can also provide your credentials when scanning. ```shell $ TRIVY_USERNAME=YOUR_USERNAME TRIVY_PASSWORD=YOUR_PASSWORD trivy image YOUR_PRIVATE_IMAGE ``` +!!! warning + When passing credentials via environment variables or CLI flags, Trivy will attempt to use these credentials for all registries encountered during scanning, regardless of the target registry. + This can potentially lead to unintended credential exposure. + To mitigate this risk: + + 1. Set credentials cautiously and only when necessary. + 2. Prefer using `trivy auth config` to pre-configure credentials with specific registries, which ensures credentials are only sent to appropriate registries. + Trivy also supports providing credentials through CLI flags: ```shell @@ -17,6 +34,7 @@ $ TRIVY_PASSWORD=YOUR_PASSWORD trivy image --username YOUR_USERNAME YOUR_PRIVATE !!! warning The CLI flag `--password` is available, but its use is not recommended for security reasons. + You can also store your credentials in `trivy.yaml`. For more information, please refer to [the documentation](../../references/configuration/config-file.md). @@ -35,15 +53,5 @@ In the example above, Trivy attempts to use two pairs of credentials: Please note that the number of usernames and passwords must be the same. -## docker login -If you have Docker configured locally and have set up the credentials, Trivy can access them. - -```shell -$ docker login ghcr.io -Username: -Password: -$ trivy image ghcr.io/your/private_image -``` - !!! note - `docker login` can be used with any container runtime, such as Podman. + `--password-stdin` doesn't support comma-separated passwords. \ No newline at end of file diff --git a/docs/docs/references/configuration/cli/trivy.md b/docs/docs/references/configuration/cli/trivy.md index 3d8ece9cd0e8..2919e43cbe27 100644 --- a/docs/docs/references/configuration/cli/trivy.md +++ b/docs/docs/references/configuration/cli/trivy.md @@ -43,6 +43,7 @@ trivy [global flags] command [flags] target ### SEE ALSO +* [trivy auth](trivy_auth.md) - Authentication * [trivy clean](trivy_clean.md) - Remove cached files * [trivy config](trivy_config.md) - Scan config files for misconfigurations * [trivy convert](trivy_convert.md) - Convert Trivy JSON report into a different format diff --git a/docs/docs/references/configuration/cli/trivy_auth.md b/docs/docs/references/configuration/cli/trivy_auth.md new file mode 100644 index 000000000000..ba2eaa6a6715 --- /dev/null +++ b/docs/docs/references/configuration/cli/trivy_auth.md @@ -0,0 +1,29 @@ +## trivy auth + +Authentication + +### Options + +``` + -h, --help help for auth +``` + +### Options inherited from parent commands + +``` + --cache-dir string cache directory (default "/path/to/cache") + -c, --config string config path (default "trivy.yaml") + -d, --debug debug mode + --generate-default-config write the default config to trivy-default.yaml + --insecure allow insecure server connections + -q, --quiet suppress progress bar and log output + --timeout duration timeout (default 5m0s) + -v, --version show version +``` + +### SEE ALSO + +* [trivy](trivy.md) - Unified security scanner +* [trivy auth login](trivy_auth_login.md) - Log in to a registry +* [trivy auth logout](trivy_auth_logout.md) - Log out of a registry + diff --git a/docs/docs/references/configuration/cli/trivy_auth_login.md b/docs/docs/references/configuration/cli/trivy_auth_login.md new file mode 100644 index 000000000000..8f2cfdb18abc --- /dev/null +++ b/docs/docs/references/configuration/cli/trivy_auth_login.md @@ -0,0 +1,41 @@ +## trivy auth login + +Log in to a registry + +``` +trivy auth login SERVER [flags] +``` + +### Examples + +``` + # Log in to reg.example.com + cat ~/my_password.txt | trivy auth login --username foo --password-stdin reg.example.com +``` + +### Options + +``` + -h, --help help for login + --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin. Comma-separated passwords are not supported. + --username strings username. Comma-separated usernames allowed. +``` + +### Options inherited from parent commands + +``` + --cache-dir string cache directory (default "/path/to/cache") + -c, --config string config path (default "trivy.yaml") + -d, --debug debug mode + --generate-default-config write the default config to trivy-default.yaml + --insecure allow insecure server connections + -q, --quiet suppress progress bar and log output + --timeout duration timeout (default 5m0s) + -v, --version show version +``` + +### SEE ALSO + +* [trivy auth](trivy_auth.md) - Authentication + diff --git a/docs/docs/references/configuration/cli/trivy_auth_logout.md b/docs/docs/references/configuration/cli/trivy_auth_logout.md new file mode 100644 index 000000000000..3a25958001cd --- /dev/null +++ b/docs/docs/references/configuration/cli/trivy_auth_logout.md @@ -0,0 +1,38 @@ +## trivy auth logout + +Log out of a registry + +``` +trivy auth logout SERVER [flags] +``` + +### Examples + +``` + # Log out of reg.example.com + trivy auth logout reg.example.com +``` + +### Options + +``` + -h, --help help for logout +``` + +### Options inherited from parent commands + +``` + --cache-dir string cache directory (default "/path/to/cache") + -c, --config string config path (default "trivy.yaml") + -d, --debug debug mode + --generate-default-config write the default config to trivy-default.yaml + --insecure allow insecure server connections + -q, --quiet suppress progress bar and log output + --timeout duration timeout (default 5m0s) + -v, --version show version +``` + +### SEE ALSO + +* [trivy auth](trivy_auth.md) - Authentication + diff --git a/docs/docs/references/configuration/cli/trivy_config.md b/docs/docs/references/configuration/cli/trivy_config.md index be7854548496..0c279f1e7bf3 100644 --- a/docs/docs/references/configuration/cli/trivy_config.md +++ b/docs/docs/references/configuration/cli/trivy_config.md @@ -39,6 +39,7 @@ trivy config [flags] DIR -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin. Comma-separated passwords are not supported. --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend --redis-key string redis key file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index 0abec4990173..bbd5257d5f5d 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -68,6 +68,7 @@ trivy filesystem [flags] PATH --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin. Comma-separated passwords are not supported. --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index f9095f041572..779b54f4d5b9 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -86,6 +86,7 @@ trivy image [flags] IMAGE_NAME --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin. Comma-separated passwords are not supported. --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --platform string set platform in the form os/arch if image is multi-platform capable diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 99fbc1badaa2..6b8058cc00f0 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -83,6 +83,7 @@ trivy kubernetes [flags] [CONTEXT] --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin. Comma-separated passwords are not supported. --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --qps float specify the maximum QPS to the master from this client (default 5) diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index 821923262dee..190640f5cb2a 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -68,6 +68,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin. Comma-separated passwords are not supported. --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index bf2575af23b9..2f37484d0328 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -70,6 +70,7 @@ trivy rootfs [flags] ROOTDIR --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --parallel int number of goroutines enabled for parallel scanning, set 0 to auto-detect parallelism (default 5) --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin. Comma-separated passwords are not supported. --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_sbom.md b/docs/docs/references/configuration/cli/trivy_sbom.md index 4eaedcf17aa5..55df0959deb6 100644 --- a/docs/docs/references/configuration/cli/trivy_sbom.md +++ b/docs/docs/references/configuration/cli/trivy_sbom.md @@ -48,6 +48,7 @@ trivy sbom [flags] SBOM_PATH -o, --output string output file name --output-plugin-arg string [EXPERIMENTAL] output plugin arguments --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin. Comma-separated passwords are not supported. --pkg-relationships strings list of package relationships (unknown,root,direct,indirect) (default [unknown,root,direct,indirect]) --pkg-types strings list of package types (os,library) (default [os,library]) --redis-ca string redis ca file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/cli/trivy_server.md b/docs/docs/references/configuration/cli/trivy_server.md index b7ada8f2c19b..80eacd43ee4f 100644 --- a/docs/docs/references/configuration/cli/trivy_server.md +++ b/docs/docs/references/configuration/cli/trivy_server.md @@ -30,6 +30,7 @@ trivy server [flags] --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") --no-progress suppress progress bar --password strings password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons. + --password-stdin password from stdin. Comma-separated passwords are not supported. --redis-ca string redis ca file location, if using redis as cache backend --redis-cert string redis certificate file location, if using redis as cache backend --redis-key string redis key file location, if using redis as cache backend diff --git a/docs/docs/references/configuration/config-file.md b/docs/docs/references/configuration/config-file.md index 9bc9d4351360..ae04978801b3 100644 --- a/docs/docs/references/configuration/config-file.md +++ b/docs/docs/references/configuration/config-file.md @@ -461,6 +461,9 @@ registry: # Same as '--password' password: [] + # Same as '--password-stdin' + password-stdin: false + # Same as '--registry-token' token: "" diff --git a/docs/docs/target/container_image.md b/docs/docs/target/container_image.md index 94acc954a743..6f514db29fb5 100644 --- a/docs/docs/target/container_image.md +++ b/docs/docs/target/container_image.md @@ -297,7 +297,7 @@ Trivy supports registries that comply with the following specifications. - [Docker Registry HTTP API V2](https://docs.docker.com/registry/spec/api/) - [OCI Distribution Specification](https://github.com/opencontainers/distribution-spec) -You can configure credentials with `docker login`. +You can configure credentials with `trivy auth login`. See [here](../advanced/private-registries/index.md) for the detail. ### Tar Files diff --git a/go.mod b/go.mod index d01ce2a7d4c7..1611c8c7080a 100644 --- a/go.mod +++ b/go.mod @@ -43,6 +43,7 @@ require ( github.com/cheggaaa/pb/v3 v3.1.5 github.com/containerd/containerd v1.7.22 github.com/csaf-poc/csaf_distribution/v3 v3.0.0 + github.com/docker/cli v27.2.1+incompatible github.com/docker/docker v27.3.1+incompatible github.com/docker/go-connections v0.5.0 github.com/fatih/color v1.17.0 @@ -210,7 +211,6 @@ require ( github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect github.com/distribution/reference v0.6.0 // indirect github.com/dlclark/regexp2 v1.4.0 // indirect - github.com/docker/cli v27.2.1+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.2 // indirect github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect diff --git a/integration/registry_test.go b/integration/registry_test.go index 3831ea9a280e..ce77db5ad74a 100644 --- a/integration/registry_test.go +++ b/integration/registry_test.go @@ -117,6 +117,7 @@ type registryOption struct { Username string Password string RegistryToken bool + AuthLogin bool } func TestRegistry(t *testing.T) { @@ -164,7 +165,6 @@ func TestRegistry(t *testing.T) { imageFile: "testdata/fixtures/images/alpine-310.tar.gz", os: "alpine 3.10.2", option: registryOption{ - AuthURL: authURL, Username: authUsername, Password: authPassword, }, @@ -183,13 +183,24 @@ func TestRegistry(t *testing.T) { }, golden: "testdata/alpine-310.json.golden", }, + { + name: "authenticate with 'trivy auth login'", + imageName: "alpine:3.10", + imageFile: "testdata/fixtures/images/alpine-310.tar.gz", + os: "alpine 3.10.2", + option: registryOption{ + Username: authUsername, + Password: authPassword, + AuthLogin: true, + }, + golden: "testdata/alpine-310.json.golden", + }, { name: "amazonlinux 2", imageName: "amazonlinux:2", imageFile: "testdata/fixtures/images/amazon-2.tar.gz", os: "amazon 2 (Karoo)", option: registryOption{ - AuthURL: authURL, Username: authUsername, Password: authPassword, }, @@ -201,7 +212,6 @@ func TestRegistry(t *testing.T) { imageFile: "testdata/fixtures/images/debian-buster.tar.gz", os: "debian 10.1", option: registryOption{ - AuthURL: authURL, Username: authUsername, Password: authPassword, }, @@ -226,6 +236,7 @@ func TestRegistry(t *testing.T) { require.NoError(t, err) osArgs, err := scan(t, imageRef, baseDir, tt.option) + require.NoError(t, err) // Run Trivy runTest(t, osArgs, tt.golden, "", types.FormatJSON, runOptions{ @@ -262,7 +273,7 @@ func scan(t *testing.T, imageRef name.Reference, baseDir string, opt registryOpt "json", "--image-src", "remote", - "--skip-update", + "--skip-db-update", imageRef.Name(), } @@ -273,14 +284,30 @@ func setupEnv(t *testing.T, imageRef name.Reference, baseDir string, opt registr t.Setenv("TRIVY_INSECURE", "true") if opt.Username != "" && opt.Password != "" { - if opt.RegistryToken { + switch { + case opt.RegistryToken: // Get a registry token in advance token, err := requestRegistryToken(imageRef, baseDir, opt) if err != nil { return err } t.Setenv("TRIVY_REGISTRY_TOKEN", token) - } else { + case opt.AuthLogin: + t.Setenv("DOCKER_CONFIG", t.TempDir()) + err := execute([]string{ + "auth", + "login", + "--username", + opt.Username, + "--password", + opt.Password, + "--insecure", + imageRef.Context().RegistryStr(), + }) + if err != nil { + return err + } + default: t.Setenv("TRIVY_USERNAME", opt.Username) t.Setenv("TRIVY_PASSWORD", opt.Password) } diff --git a/mkdocs.yml b/mkdocs.yml index abe494df9dd9..1d3d6276e2c3 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -158,6 +158,10 @@ nav: - Configuration: - CLI: - Overview: docs/references/configuration/cli/trivy.md + - Auth: + - Auth: docs/references/configuration/cli/trivy_auth.md + - Auth Login: docs/references/configuration/cli/trivy_auth_login.md + - Auth Logout: docs/references/configuration/cli/trivy_auth_logout.md - Clean: docs/references/configuration/cli/trivy_clean.md - Config: docs/references/configuration/cli/trivy_config.md - Convert: docs/references/configuration/cli/trivy_convert.md diff --git a/pkg/commands/app.go b/pkg/commands/app.go index bdba2fa12ac7..eec063a3eba3 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -15,6 +15,7 @@ import ( "github.com/aquasecurity/trivy/pkg/cache" "github.com/aquasecurity/trivy/pkg/commands/artifact" + "github.com/aquasecurity/trivy/pkg/commands/auth" "github.com/aquasecurity/trivy/pkg/commands/clean" "github.com/aquasecurity/trivy/pkg/commands/convert" "github.com/aquasecurity/trivy/pkg/commands/server" @@ -99,6 +100,7 @@ func NewApp() *cobra.Command { NewVersionCommand(globalFlags), NewVMCommand(globalFlags), NewCleanCommand(globalFlags), + NewAuthCommand(globalFlags), NewVEXCommand(globalFlags), ) @@ -1233,6 +1235,62 @@ func NewCleanCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { return cmd } +func NewAuthCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { + cmd := &cobra.Command{ + Use: "auth [flags]", + GroupID: groupUtility, + Short: "Authentication", + SilenceErrors: true, + SilenceUsage: true, + } + + loginFlags := &flag.Flags{ + GlobalFlagGroup: globalFlags, + RegistryFlagGroup: flag.NewRegistryFlagGroup(), + } + loginFlags.RegistryFlagGroup.RegistryToken = nil // disable '--registry-token' + loginCmd := &cobra.Command{ + Use: "login SERVER", + Short: "Log in to a registry", + SilenceErrors: true, + SilenceUsage: true, + Example: ` # Log in to reg.example.com + cat ~/my_password.txt | trivy auth login --username foo --password-stdin reg.example.com`, + Args: cobra.ExactArgs(1), + PreRunE: func(cmd *cobra.Command, args []string) error { + if err := loginFlags.Bind(cmd); err != nil { + return xerrors.Errorf("flag bind error: %w", err) + } + return nil + }, + RunE: func(cmd *cobra.Command, args []string) error { + loginOpts, err := loginFlags.ToOptions(args) + if err != nil { + return xerrors.Errorf("flag error: %w", err) + } + return auth.Login(cmd.Context(), args[0], loginOpts) + }, + } + logoutCmd := &cobra.Command{ + Use: "logout SERVER", + Short: "Log out of a registry", + SilenceErrors: true, + SilenceUsage: true, + Example: ` # Log out of reg.example.com + trivy auth logout reg.example.com`, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + return auth.Logout(cmd.Context(), args[0]) + }, + } + loginFlags.AddFlags(loginCmd) + cmd.AddCommand(loginCmd, logoutCmd) + + cmd.SetFlagErrorFunc(flagErrorFunc) + + return cmd +} + func NewVEXCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { vexFlags := &flag.Flags{ GlobalFlagGroup: globalFlags, diff --git a/pkg/commands/auth/run.go b/pkg/commands/auth/run.go new file mode 100644 index 000000000000..7659702f2b7e --- /dev/null +++ b/pkg/commands/auth/run.go @@ -0,0 +1,109 @@ +package auth + +import ( + "context" + "net/http" + "os" + + "github.com/docker/cli/cli/config" + "github.com/docker/cli/cli/config/types" + "github.com/google/go-containerregistry/pkg/authn" + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" + "github.com/google/go-containerregistry/pkg/v1/remote/transport" + "golang.org/x/xerrors" + + "github.com/aquasecurity/trivy/pkg/flag" + "github.com/aquasecurity/trivy/pkg/log" +) + +func Login(ctx context.Context, registry string, opts flag.Options) error { + if len(opts.Credentials) == 0 { + return xerrors.New("username and password required") + } else if len(opts.Credentials) > 1 { + return xerrors.New("multiple credentials are not allowed") + } + + reg, err := parseRegistry(registry, opts) + if err != nil { + return xerrors.Errorf("failed to parse registry: %w", err) + } + serverAddress := reg.Name() + + // Validate the credential + _, err = transport.NewWithContext(ctx, reg, &authn.Basic{ + Username: opts.Credentials[0].Username, + Password: opts.Credentials[0].Password, + }, httpTransport(opts), []string{reg.Scope(transport.PullScope)}) + if err != nil { + return xerrors.Errorf("failed to authenticate: %w", err) + } + + cf, err := config.Load(os.Getenv("DOCKER_CONFIG")) + if err != nil { + return xerrors.Errorf("failed to load docker config: %w", err) + } + creds := cf.GetCredentialsStore(serverAddress) + if serverAddress == name.DefaultRegistry { + serverAddress = authn.DefaultAuthKey + } + if err := creds.Store(types.AuthConfig{ + ServerAddress: serverAddress, + Username: opts.Credentials[0].Username, + Password: opts.Credentials[0].Password, + }); err != nil { + return xerrors.Errorf("failed to store credentials: %w", err) + } + + if err := cf.Save(); err != nil { + return xerrors.Errorf("failed to save docker config: %w", err) + } + log.Info("Login succeeded", log.FilePath(cf.Filename), log.String("username", opts.Credentials[0].Username)) + return nil +} + +func Logout(_ context.Context, registry string) error { + reg, err := parseRegistry(registry, flag.Options{}) + if err != nil { + return xerrors.Errorf("failed to parse registry: %w", err) + } + serverAddress := reg.Name() + + cf, err := config.Load(os.Getenv("DOCKER_CONFIG")) + if err != nil { + return xerrors.Errorf("failed to load docker config: %w", err) + } + creds := cf.GetCredentialsStore(serverAddress) + if serverAddress == name.DefaultRegistry { + serverAddress = authn.DefaultAuthKey + } + if err := creds.Erase(serverAddress); err != nil { + return xerrors.Errorf("failed to delete credentials: %w", err) + } + + if err := cf.Save(); err != nil { + return xerrors.Errorf("failed to save docker config: %w", err) + } + log.Info("Logged out", log.FilePath(cf.Filename)) + return nil +} + +func parseRegistry(registry string, opts flag.Options) (name.Registry, error) { + var nameOpts []name.Option + if opts.Insecure { + nameOpts = append(nameOpts, name.Insecure) + } + reg, err := name.NewRegistry(registry, nameOpts...) + if err != nil { + return name.Registry{}, xerrors.Errorf("failed to parse registry: %w", err) + } + return reg, nil +} + +func httpTransport(opts flag.Options) *http.Transport { + tr := remote.DefaultTransport.(*http.Transport).Clone() + if opts.Insecure { + tr.TLSClientConfig.InsecureSkipVerify = true + } + return tr +} diff --git a/pkg/commands/auth/run_test.go b/pkg/commands/auth/run_test.go new file mode 100644 index 000000000000..2b2df244031f --- /dev/null +++ b/pkg/commands/auth/run_test.go @@ -0,0 +1,142 @@ +package auth_test + +import ( + "context" + "os" + "path/filepath" + "strings" + "testing" + + "github.com/samber/lo" + "github.com/stretchr/testify/require" + + testauth "github.com/aquasecurity/testdocker/auth" + "github.com/aquasecurity/testdocker/registry" + "github.com/aquasecurity/trivy/pkg/commands/auth" + "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/flag" +) + +func TestLogin(t *testing.T) { + type args struct { + registry string + opts flag.Options + } + tests := []struct { + name string + args args + wantErr string + }{ + { + name: "single credential", + args: args{ + opts: flag.Options{ + RegistryOptions: flag.RegistryOptions{ + Credentials: []types.Credential{ + { + Username: "user", + Password: "pass", + }, + }, + }, + }, + }, + }, + { + name: "multiple credentials", + args: args{ + opts: flag.Options{ + RegistryOptions: flag.RegistryOptions{ + Credentials: []types.Credential{ + { + Username: "user1", + Password: "pass1", + }, + { + Username: "user2", + Password: "pass2", + }, + }, + }, + }, + }, + wantErr: "multiple credentials are not allowed", + }, + { + name: "no credentials", + args: args{ + registry: "auth.test", + opts: flag.Options{}, + }, + wantErr: "username and password required", + }, + { + name: "invalid registry", + args: args{ + registry: "aaa://invalid.test", + opts: flag.Options{ + RegistryOptions: flag.RegistryOptions{ + Credentials: []types.Credential{ + { + Username: "user", + Password: "pass", + }, + }, + }, + }, + }, + wantErr: "registries must be valid RFC 3986 URI authorities", + }, + } + + tr := registry.NewDockerRegistry(registry.Option{ + Auth: testauth.Auth{ + User: "user", + Password: "pass", + }, + }) + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // Set the DOCKER_CONFIG environment variable to a temporary directory + // so that the test does not interfere with the user's configuration. + t.Setenv("DOCKER_CONFIG", filepath.Join(t.TempDir(), "config.json")) + + reg := lo.Ternary(tt.args.registry == "", strings.TrimPrefix(tr.URL, "http://"), tt.args.registry) + err := auth.Login(context.Background(), reg, tt.args.opts) + if tt.wantErr != "" { + require.ErrorContains(t, err, tt.wantErr) + return + } + require.NoError(t, err) + }) + } +} + +func TestLogout(t *testing.T) { + // Set the DOCKER_CONFIG environment variable to a temporary directory + // so that the test does not interfere with the user's configuration. + tmpDir := t.TempDir() + t.Setenv("DOCKER_CONFIG", tmpDir) + + t.Run("success", func(t *testing.T) { + configFile := filepath.Join(tmpDir, "config.json") + err := os.WriteFile(configFile, []byte(`{"auths": {"auth.test": {"auth": "dXNlcjpwYXNz"}}}`), 0600) + require.NoError(t, err) + + err = auth.Logout(context.Background(), "auth.test") + require.NoError(t, err) + b, err := os.ReadFile(configFile) + require.NoError(t, err) + require.JSONEq(t, `{"auths": {}}`, string(b)) + }) + t.Run("not found", func(t *testing.T) { + err := auth.Logout(context.Background(), "notfound.test") + require.NoError(t, err) // Return an error if "credsStore" is "osxkeychain". + }) + + t.Run("invalid registry", func(t *testing.T) { + err := auth.Logout(context.Background(), "aaa://invalid.test") + require.ErrorContains(t, err, "registries must be valid RFC 3986 URI authorities") + }) +} diff --git a/pkg/flag/registry_flags.go b/pkg/flag/registry_flags.go index 552eaf4276d6..9c03a07b8872 100644 --- a/pkg/flag/registry_flags.go +++ b/pkg/flag/registry_flags.go @@ -1,6 +1,8 @@ package flag import ( + "io" + "os" "strings" "golang.org/x/xerrors" @@ -19,6 +21,11 @@ var ( ConfigName: "registry.password", Usage: "password. Comma-separated passwords allowed. TRIVY_PASSWORD should be used for security reasons.", } + PasswordStdinFlag = Flag[bool]{ + Name: "password-stdin", + ConfigName: "registry.password-stdin", + Usage: "password from stdin. Comma-separated passwords are not supported.", + } RegistryTokenFlag = Flag[string]{ Name: "registry-token", ConfigName: "registry.token", @@ -29,6 +36,7 @@ var ( type RegistryFlagGroup struct { Username *Flag[[]string] Password *Flag[[]string] + PasswordStdin *Flag[bool] RegistryToken *Flag[string] } @@ -41,6 +49,7 @@ func NewRegistryFlagGroup() *RegistryFlagGroup { return &RegistryFlagGroup{ Username: UsernameFlag.Clone(), Password: PasswordFlag.Clone(), + PasswordStdin: PasswordStdinFlag.Clone(), RegistryToken: RegistryTokenFlag.Clone(), } } @@ -53,6 +62,7 @@ func (f *RegistryFlagGroup) Flags() []Flagger { return []Flagger{ f.Username, f.Password, + f.PasswordStdin, f.RegistryToken, } } @@ -65,8 +75,19 @@ func (f *RegistryFlagGroup) ToOptions() (RegistryOptions, error) { var credentials []types.Credential users := f.Username.Value() passwords := f.Password.Value() + if f.PasswordStdin.Value() { + if len(passwords) != 0 { + return RegistryOptions{}, xerrors.New("'--password' and '--password-stdin' can't be used at the same time") + } + contents, err := io.ReadAll(os.Stdin) + if err != nil { + return RegistryOptions{}, xerrors.Errorf("failed to read from stdin: %w", err) + } + // "--password-stdin" doesn't support comma-separated passwords + passwords = []string{strings.TrimRight(string(contents), "\r\n")} + } if len(users) != len(passwords) { - return RegistryOptions{}, xerrors.New("the length of usernames and passwords must match") + return RegistryOptions{}, xerrors.New("the number of usernames and passwords must match") } for i, user := range users { credentials = append(credentials, types.Credential{ From 672e886aed152ae0f09a16941706746f3053ca94 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Thu, 10 Oct 2024 15:02:06 +0400 Subject: [PATCH 131/183] fix(cli): `clean --all` deletes only relevant dirs (#7704) Signed-off-by: knqyf263 --- pkg/commands/clean/run.go | 15 +++++---------- pkg/commands/clean/run_test.go | 26 +++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/pkg/commands/clean/run.go b/pkg/commands/clean/run.go index c60227360d19..8dd83519422f 100644 --- a/pkg/commands/clean/run.go +++ b/pkg/commands/clean/run.go @@ -2,7 +2,6 @@ package clean import ( "context" - "os" "golang.org/x/xerrors" @@ -25,7 +24,11 @@ func Run(ctx context.Context, opts flag.Options) error { } if opts.CleanAll { - return cleanAll(ctx, opts) + opts.CleanScanCache = true + opts.CleanVulnerabilityDB = true + opts.CleanJavaDB = true + opts.CleanChecksBundle = true + opts.CleanVEXRepositories = true } if opts.CleanScanCache { @@ -60,14 +63,6 @@ func Run(ctx context.Context, opts flag.Options) error { return nil } -func cleanAll(ctx context.Context, opts flag.Options) error { - log.InfoContext(ctx, "Removing all caches...") - if err := os.RemoveAll(opts.CacheDir); err != nil { - return xerrors.Errorf("failed to remove the directory (%s) : %w", opts.CacheDir, err) - } - return nil -} - func cleanScanCache(ctx context.Context, opts flag.Options) error { log.InfoContext(ctx, "Removing scan cache...") c, cleanup, err := cache.New(opts.CacheOpts()) diff --git a/pkg/commands/clean/run_test.go b/pkg/commands/clean/run_test.go index 9b301d238219..32e4110aba97 100644 --- a/pkg/commands/clean/run_test.go +++ b/pkg/commands/clean/run_test.go @@ -28,7 +28,12 @@ func TestRun(t *testing.T) { }, wantErr: false, checkFunc: func(t *testing.T, dir string) { - assert.NoDirExists(t, dir) + assert.NoDirExists(t, filepath.Join(dir, "fanal")) + assert.NoDirExists(t, filepath.Join(dir, "db")) + assert.NoDirExists(t, filepath.Join(dir, "java-db")) + assert.NoDirExists(t, filepath.Join(dir, "policy")) + assert.NoDirExists(t, filepath.Join(dir, "vex")) + assert.DirExists(t, dir) }, }, { @@ -42,6 +47,7 @@ func TestRun(t *testing.T) { assert.DirExists(t, filepath.Join(dir, "db")) assert.DirExists(t, filepath.Join(dir, "java-db")) assert.DirExists(t, filepath.Join(dir, "policy")) + assert.DirExists(t, filepath.Join(dir, "vex")) }, }, { @@ -55,6 +61,7 @@ func TestRun(t *testing.T) { assert.DirExists(t, filepath.Join(dir, "fanal")) assert.DirExists(t, filepath.Join(dir, "java-db")) assert.DirExists(t, filepath.Join(dir, "policy")) + assert.DirExists(t, filepath.Join(dir, "vex")) }, }, { @@ -68,6 +75,7 @@ func TestRun(t *testing.T) { assert.DirExists(t, filepath.Join(dir, "fanal")) assert.DirExists(t, filepath.Join(dir, "db")) assert.DirExists(t, filepath.Join(dir, "policy")) + assert.DirExists(t, filepath.Join(dir, "vex")) }, }, { @@ -81,6 +89,21 @@ func TestRun(t *testing.T) { assert.DirExists(t, filepath.Join(dir, "fanal")) assert.DirExists(t, filepath.Join(dir, "db")) assert.DirExists(t, filepath.Join(dir, "java-db")) + assert.DirExists(t, filepath.Join(dir, "vex")) + }, + }, + { + name: "clean vex repositories", + cleanOpts: flag.CleanOptions{ + CleanVEXRepositories: true, + }, + wantErr: false, + checkFunc: func(t *testing.T, dir string) { + assert.DirExists(t, filepath.Join(dir, "policy")) + assert.DirExists(t, filepath.Join(dir, "fanal")) + assert.DirExists(t, filepath.Join(dir, "db")) + assert.DirExists(t, filepath.Join(dir, "java-db")) + assert.NoDirExists(t, filepath.Join(dir, "vex")) }, }, { @@ -127,6 +150,7 @@ func createTestFiles(t *testing.T, dir string) { "db", "java-db", "policy", + "vex", } for _, subdir := range subdirs { err := os.MkdirAll(filepath.Join(dir, subdir), 0755) From c78f45b4a71a0fb92232aad7594351466125bee2 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 11 Oct 2024 10:40:13 +0600 Subject: [PATCH 132/183] refactor(misconf): introduce generic scanner (#7515) Signed-off-by: nikpivkin --- pkg/iac/scanners/dockerfile/parser/parser.go | 64 +---- .../scanners/dockerfile/parser/parser_test.go | 13 +- pkg/iac/scanners/dockerfile/scanner.go | 108 +-------- pkg/iac/scanners/dockerfile/scanner_test.go | 7 +- pkg/iac/scanners/generic/scanner.go | 220 +++++++++++++++++ pkg/iac/scanners/generic/scanner_test.go | 223 ++++++++++++++++++ pkg/iac/scanners/json/parser/parser.go | 65 ----- pkg/iac/scanners/json/parser/parser_test.go | 51 ---- pkg/iac/scanners/json/scanner.go | 113 --------- pkg/iac/scanners/json/scanner_test.go | 80 ------- pkg/iac/scanners/toml/parser/parser.go | 65 ----- pkg/iac/scanners/toml/parser/parser_test.go | 55 ----- pkg/iac/scanners/toml/scanner.go | 111 --------- pkg/iac/scanners/toml/scanner_test.go | 85 ------- pkg/iac/scanners/yaml/parser/parser.go | 86 ------- pkg/iac/scanners/yaml/parser/parser_test.go | 150 ------------ pkg/iac/scanners/yaml/scanner.go | 113 --------- pkg/iac/scanners/yaml/scanner_test.go | 88 ------- pkg/misconf/scanner.go | 7 +- 19 files changed, 469 insertions(+), 1235 deletions(-) create mode 100644 pkg/iac/scanners/generic/scanner.go create mode 100644 pkg/iac/scanners/generic/scanner_test.go delete mode 100644 pkg/iac/scanners/json/parser/parser.go delete mode 100644 pkg/iac/scanners/json/parser/parser_test.go delete mode 100644 pkg/iac/scanners/json/scanner.go delete mode 100644 pkg/iac/scanners/json/scanner_test.go delete mode 100644 pkg/iac/scanners/toml/parser/parser.go delete mode 100644 pkg/iac/scanners/toml/parser/parser_test.go delete mode 100644 pkg/iac/scanners/toml/scanner.go delete mode 100644 pkg/iac/scanners/toml/scanner_test.go delete mode 100644 pkg/iac/scanners/yaml/parser/parser.go delete mode 100644 pkg/iac/scanners/yaml/parser/parser_test.go delete mode 100644 pkg/iac/scanners/yaml/scanner.go delete mode 100644 pkg/iac/scanners/yaml/scanner_test.go diff --git a/pkg/iac/scanners/dockerfile/parser/parser.go b/pkg/iac/scanners/dockerfile/parser/parser.go index e92116ae3079..128d9515e8b1 100644 --- a/pkg/iac/scanners/dockerfile/parser/parser.go +++ b/pkg/iac/scanners/dockerfile/parser/parser.go @@ -4,76 +4,26 @@ import ( "context" "fmt" "io" - "io/fs" - "path/filepath" "strings" "github.com/moby/buildkit/frontend/dockerfile/instructions" "github.com/moby/buildkit/frontend/dockerfile/parser" "github.com/aquasecurity/trivy/pkg/iac/providers/dockerfile" - "github.com/aquasecurity/trivy/pkg/log" ) -type Parser struct { - logger *log.Logger -} - -// New creates a new Dockerfile parser -func New() *Parser { - return &Parser{ - logger: log.WithPrefix("dockerfile parser"), - } -} - -func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[string]*dockerfile.Dockerfile, error) { - - files := make(map[string]*dockerfile.Dockerfile) - if err := fs.WalkDir(target, filepath.ToSlash(path), func(path string, entry fs.DirEntry, err error) error { - select { - case <-ctx.Done(): - return ctx.Err() - default: - } - if err != nil { - return err - } - if entry.IsDir() { - return nil - } - - df, err := p.ParseFile(ctx, target, path) - if err != nil { - p.logger.Error("Failed to parse Dockerfile", log.FilePath(path), log.Err(err)) - return nil - } - files[path] = df - return nil - }); err != nil { - return nil, err - } - return files, nil -} - -// ParseFile parses Dockerfile content from the provided filesystem path. -func (p *Parser) ParseFile(_ context.Context, fsys fs.FS, path string) (*dockerfile.Dockerfile, error) { - f, err := fsys.Open(filepath.ToSlash(path)) - if err != nil { - return nil, err - } - defer func() { _ = f.Close() }() - return p.parse(path, f) -} - -func (p *Parser) parse(path string, r io.Reader) (*dockerfile.Dockerfile, error) { +func Parse(_ context.Context, r io.Reader, path string) (any, error) { parsed, err := parser.Parse(r) if err != nil { return nil, fmt.Errorf("dockerfile parse error: %w", err) } - var parsedFile dockerfile.Dockerfile - var stage dockerfile.Stage - var stageIndex int + var ( + parsedFile dockerfile.Dockerfile + stage dockerfile.Stage + stageIndex int + ) + fromValue := "args" for _, child := range parsed.AST.Children { child.Value = strings.ToLower(child.Value) diff --git a/pkg/iac/scanners/dockerfile/parser/parser_test.go b/pkg/iac/scanners/dockerfile/parser/parser_test.go index 764cb3a0e091..ad1acf193bf3 100644 --- a/pkg/iac/scanners/dockerfile/parser/parser_test.go +++ b/pkg/iac/scanners/dockerfile/parser/parser_test.go @@ -1,11 +1,15 @@ -package parser +package parser_test import ( + "context" "strings" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + + "github.com/aquasecurity/trivy/pkg/iac/providers/dockerfile" + "github.com/aquasecurity/trivy/pkg/iac/scanners/dockerfile/parser" ) func Test_Parser(t *testing.T) { @@ -15,12 +19,13 @@ RUN make /app CMD python /app/app.py ` - df, err := New().parse("Dockerfile", strings.NewReader(input)) + res, err := parser.Parse(context.TODO(), strings.NewReader(input), "Dockerfile") require.NoError(t, err) - assert.Len(t, df.Stages, 1) + df, ok := res.(*dockerfile.Dockerfile) + require.True(t, ok) - require.Len(t, df.Stages, 1) + assert.Len(t, df.Stages, 1) assert.Equal(t, "ubuntu:18.04", df.Stages[0].Name) commands := df.Stages[0].Commands diff --git a/pkg/iac/scanners/dockerfile/scanner.go b/pkg/iac/scanners/dockerfile/scanner.go index 1694f28d814a..5637410945eb 100644 --- a/pkg/iac/scanners/dockerfile/scanner.go +++ b/pkg/iac/scanners/dockerfile/scanner.go @@ -1,114 +1,12 @@ package dockerfile import ( - "context" - "io/fs" - "sync" - - "github.com/aquasecurity/trivy/pkg/iac/framework" - "github.com/aquasecurity/trivy/pkg/iac/rego" - "github.com/aquasecurity/trivy/pkg/iac/scan" - "github.com/aquasecurity/trivy/pkg/iac/scanners" "github.com/aquasecurity/trivy/pkg/iac/scanners/dockerfile/parser" + "github.com/aquasecurity/trivy/pkg/iac/scanners/generic" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/types" - "github.com/aquasecurity/trivy/pkg/log" ) -var _ scanners.FSScanner = (*Scanner)(nil) -var _ options.ConfigurableScanner = (*Scanner)(nil) - -type Scanner struct { - mu sync.Mutex - logger *log.Logger - parser *parser.Parser - regoScanner *rego.Scanner - options []options.ScannerOption -} - -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} -func (s *Scanner) SetRegoOnly(bool) {} -func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {} - -func (s *Scanner) Name() string { - return "Dockerfile" -} - -func NewScanner(opts ...options.ScannerOption) *Scanner { - s := &Scanner{ - options: opts, - logger: log.WithPrefix("dockerfile scanner"), - } - for _, opt := range opts { - opt(s) - } - s.parser = parser.New() - return s -} - -func (s *Scanner) ScanFS(ctx context.Context, fsys fs.FS, path string) (scan.Results, error) { - - files, err := s.parser.ParseFS(ctx, fsys, path) - if err != nil { - return nil, err - } - - if len(files) == 0 { - return nil, nil - } - - var inputs []rego.Input - for path, dfile := range files { - inputs = append(inputs, rego.Input{ - Path: path, - FS: fsys, - Contents: dfile.ToRego(), - }) - } - - results, err := s.scanRego(ctx, fsys, inputs...) - if err != nil { - return nil, err - } - return results, nil -} - -func (s *Scanner) ScanFile(ctx context.Context, fsys fs.FS, path string) (scan.Results, error) { - dockerfile, err := s.parser.ParseFile(ctx, fsys, path) - if err != nil { - return nil, err - } - s.logger.Debug("Scanning", log.FilePath(path)) - return s.scanRego(ctx, fsys, rego.Input{ - Path: path, - Contents: dockerfile.ToRego(), - }) -} - -func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { - s.mu.Lock() - defer s.mu.Unlock() - if s.regoScanner != nil { - return s.regoScanner, nil - } - - regoScanner := rego.NewScanner(types.SourceDockerfile, s.options...) - if err := regoScanner.LoadPolicies(srcFS); err != nil { - return nil, err - } - s.regoScanner = regoScanner - return regoScanner, nil -} - -func (s *Scanner) scanRego(ctx context.Context, srcFS fs.FS, inputs ...rego.Input) (scan.Results, error) { - regoScanner, err := s.initRegoScanner(srcFS) - if err != nil { - return nil, err - } - results, err := regoScanner.ScanInput(ctx, inputs...) - if err != nil { - return nil, err - } - results.SetSourceAndFilesystem("", srcFS, false) - return results, nil +func NewScanner(opts ...options.ScannerOption) *generic.GenericScanner { + return generic.NewScanner("Dockerfile", types.SourceDockerfile, generic.ParseFunc(parser.Parse), opts...) } diff --git a/pkg/iac/scanners/dockerfile/scanner_test.go b/pkg/iac/scanners/dockerfile/scanner_test.go index 2872df1e4ef6..e8c66b27db08 100644 --- a/pkg/iac/scanners/dockerfile/scanner_test.go +++ b/pkg/iac/scanners/dockerfile/scanner_test.go @@ -1,4 +1,4 @@ -package dockerfile +package dockerfile_test import ( "bytes" @@ -13,6 +13,7 @@ import ( "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/rego/schemas" "github.com/aquasecurity/trivy/pkg/iac/scan" + "github.com/aquasecurity/trivy/pkg/iac/scanners/dockerfile" ) const DS006PolicyWithDockerfileSchema = `# METADATA @@ -219,7 +220,7 @@ USER root "/rules/rule.rego": DS006LegacyWithOldStyleMetadata, }) - scanner := NewScanner(rego.WithPolicyDirs("rules")) + scanner := dockerfile.NewScanner(rego.WithPolicyDirs("rules")) results, err := scanner.ScanFS(context.TODO(), fs, "code") require.NoError(t, err) @@ -563,7 +564,7 @@ COPY --from=dep /binary /` var traceBuf bytes.Buffer - scanner := NewScanner( + scanner := dockerfile.NewScanner( rego.WithPolicyDirs("rules"), rego.WithEmbeddedLibraries(true), rego.WithTrace(&traceBuf), diff --git a/pkg/iac/scanners/generic/scanner.go b/pkg/iac/scanners/generic/scanner.go new file mode 100644 index 000000000000..5a36709d9a04 --- /dev/null +++ b/pkg/iac/scanners/generic/scanner.go @@ -0,0 +1,220 @@ +package generic + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "io/fs" + "path/filepath" + "strings" + "sync" + + "github.com/BurntSushi/toml" + "gopkg.in/yaml.v3" + + "github.com/aquasecurity/trivy/pkg/iac/framework" + "github.com/aquasecurity/trivy/pkg/iac/rego" + "github.com/aquasecurity/trivy/pkg/iac/scan" + "github.com/aquasecurity/trivy/pkg/iac/scanners/options" + "github.com/aquasecurity/trivy/pkg/iac/types" + "github.com/aquasecurity/trivy/pkg/log" +) + +func NewJsonScanner(opts ...options.ScannerOption) *GenericScanner { + return NewScanner("JSON", types.SourceJSON, ParseFunc(parseJson), opts...) +} + +func NewYamlScanner(opts ...options.ScannerOption) *GenericScanner { + return NewScanner("YAML", types.SourceYAML, ParseFunc(parseYaml), opts...) +} + +func NewTomlScanner(opts ...options.ScannerOption) *GenericScanner { + return NewScanner("TOML", types.SourceTOML, ParseFunc(parseTOML), opts...) +} + +type configParser interface { + Parse(ctx context.Context, r io.Reader, path string) (any, error) +} + +// GenericScanner is a scanner that scans a file as is without processing it +type GenericScanner struct { + mu sync.Mutex + name string + source types.Source + logger *log.Logger + options []options.ScannerOption + regoScanner *rego.Scanner + + parser configParser +} + +type ParseFunc func(ctx context.Context, r io.Reader, path string) (any, error) + +func (f ParseFunc) Parse(ctx context.Context, r io.Reader, path string) (any, error) { + return f(ctx, r, path) +} + +func NewScanner(name string, source types.Source, parser configParser, opts ...options.ScannerOption) *GenericScanner { + s := &GenericScanner{ + name: name, + options: opts, + source: source, + logger: log.WithPrefix(fmt.Sprintf("%s scanner", source)), + parser: parser, + } + + for _, opt := range opts { + opt(s) + } + + return s +} + +func (s *GenericScanner) Name() string { + return s.name +} + +func (s *GenericScanner) ScanFS(ctx context.Context, fsys fs.FS, dir string) (scan.Results, error) { + fileset, err := s.parseFS(ctx, fsys, dir) + if err != nil { + return nil, err + } + + if len(fileset) == 0 { + return nil, nil + } + + var inputs []rego.Input + for path, val := range fileset { + switch v := val.(type) { + case interface{ ToRego() any }: + inputs = append(inputs, rego.Input{ + Path: path, + Contents: v.ToRego(), + FS: fsys, + }) + case []any: + for _, file := range v { + inputs = append(inputs, rego.Input{ + Path: path, + Contents: file, + FS: fsys, + }) + } + default: + inputs = append(inputs, rego.Input{ + Path: path, + Contents: v, + FS: fsys, + }) + } + } + + regoScanner, err := s.initRegoScanner(fsys) + if err != nil { + return nil, err + } + + s.logger.Debug("Scanning files...", log.Int("count", len(inputs))) + results, err := regoScanner.ScanInput(ctx, inputs...) + if err != nil { + return nil, err + } + results.SetSourceAndFilesystem("", fsys, false) + return results, nil +} + +func (s *GenericScanner) parseFS(ctx context.Context, fsys fs.FS, path string) (map[string]any, error) { + files := make(map[string]any) + if err := fs.WalkDir(fsys, filepath.ToSlash(path), func(path string, entry fs.DirEntry, err error) error { + select { + case <-ctx.Done(): + return ctx.Err() + default: + } + if err != nil { + return err + } + if entry.IsDir() { + return nil + } + + f, err := fsys.Open(filepath.ToSlash(path)) + if err != nil { + return err + } + defer f.Close() + + df, err := s.parser.Parse(ctx, f, path) + if err != nil { + s.logger.Error("Failed to parse file", log.FilePath(path), log.Err(err)) + return nil + } + files[path] = df + return nil + }); err != nil { + return nil, err + } + return files, nil +} + +func (s *GenericScanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { + s.mu.Lock() + defer s.mu.Unlock() + if s.regoScanner != nil { + return s.regoScanner, nil + } + regoScanner := rego.NewScanner(s.source, s.options...) + if err := regoScanner.LoadPolicies(srcFS); err != nil { + return nil, err + } + s.regoScanner = regoScanner + return regoScanner, nil +} + +func (*GenericScanner) SetRegoOnly(bool) {} +func (*GenericScanner) SetIncludeDeprecatedChecks(bool) {} +func (*GenericScanner) SetFrameworks([]framework.Framework) {} + +func parseJson(ctx context.Context, r io.Reader, _ string) (any, error) { + var target any + if err := json.NewDecoder(r).Decode(&target); err != nil { + return nil, err + } + return target, nil +} + +func parseYaml(ctx context.Context, r io.Reader, _ string) (any, error) { + contents, err := io.ReadAll(r) + if err != nil { + return nil, err + } + + var results []any + + marker := "\n---\n" + altMarker := "\r\n---\r\n" + if bytes.Contains(contents, []byte(altMarker)) { + marker = altMarker + } + + for _, partial := range strings.Split(string(contents), marker) { + var target any + if err := yaml.Unmarshal([]byte(partial), &target); err != nil { + return nil, err + } + results = append(results, target) + } + + return results, nil +} + +func parseTOML(ctx context.Context, r io.Reader, _ string) (any, error) { + var target any + if _, err := toml.NewDecoder(r).Decode(&target); err != nil { + return nil, err + } + return target, nil +} diff --git a/pkg/iac/scanners/generic/scanner_test.go b/pkg/iac/scanners/generic/scanner_test.go new file mode 100644 index 000000000000..46d0eef1653a --- /dev/null +++ b/pkg/iac/scanners/generic/scanner_test.go @@ -0,0 +1,223 @@ +package generic_test + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/aquasecurity/trivy/internal/testutil" + "github.com/aquasecurity/trivy/pkg/iac/framework" + "github.com/aquasecurity/trivy/pkg/iac/rego" + "github.com/aquasecurity/trivy/pkg/iac/scan" + "github.com/aquasecurity/trivy/pkg/iac/scanners/generic" +) + +func TestJsonScanner(t *testing.T) { + fsys := testutil.CreateFS(t, map[string]string{ + "/code/data.json": `{ "x": { "y": 123, "z": ["a", "b", "c"]}}`, + "/rules/rule.rego": `package builtin.json.lol + +__rego_metadata__ := { + "id": "ABC123", + "avd_id": "AVD-AB-0123", + "title": "title", + "short_code": "short", + "severity": "CRITICAL", + "type": "JSON Check", + "description": "description", + "recommended_actions": "actions", + "url": "https://example.com", +} + +__rego_input__ := { + "combine": false, + "selector": [{"type": "json"}], +} + +deny[res] { + input.x.y == 123 + res := { + "msg": "oh no", + "startline": 1, + "endline": 2, + } +} + +`, + }) + + scanner := generic.NewJsonScanner(rego.WithPolicyDirs("rules")) + + results, err := scanner.ScanFS(context.TODO(), fsys, "code") + require.NoError(t, err) + + require.Len(t, results.GetFailed(), 1) + + assert.Equal(t, scan.Rule{ + AVDID: "AVD-AB-0123", + Aliases: []string{"ABC123"}, + ShortCode: "short", + Summary: "title", + Explanation: "description", + Impact: "", + Resolution: "actions", + Provider: "json", + Service: "general", + Links: []string{"https://example.com"}, + Severity: "CRITICAL", + Terraform: &scan.EngineMetadata{}, + CloudFormation: &scan.EngineMetadata{}, + CustomChecks: scan.CustomChecks{ + Terraform: (*scan.TerraformCustomCheck)(nil), + }, + RegoPackage: "data.builtin.json.lol", + Frameworks: map[framework.Framework][]string{ + framework.Default: {}, + }, + }, results.GetFailed()[0].Rule()) +} + +func TestYamlScanner(t *testing.T) { + fsys := testutil.CreateFS(t, map[string]string{ + "/code/data.yaml": `--- +x: + y: 123 + z: + - a + - b + - c +`, + "/rules/rule.rego": `package builtin.yaml.lol + +__rego_metadata__ := { + "id": "ABC123", + "avd_id": "AVD-AB-0123", + "title": "title", + "short_code": "short", + "severity": "CRITICAL", + "type": "YAML Check", + "description": "description", + "recommended_actions": "actions", + "url": "https://example.com", +} + +__rego_input__ := { + "combine": false, + "selector": [{"type": "yaml"}], +} + +deny[res] { + input.x.y == 123 + res := { + "msg": "oh no", + "startline": 1, + "endline": 2, + } +} + +`, + }) + + scanner := generic.NewYamlScanner(rego.WithPolicyDirs("rules")) + + results, err := scanner.ScanFS(context.TODO(), fsys, "code") + require.NoError(t, err) + + require.Len(t, results.GetFailed(), 1) + + assert.Equal(t, scan.Rule{ + AVDID: "AVD-AB-0123", + Aliases: []string{"ABC123"}, + ShortCode: "short", + Summary: "title", + Explanation: "description", + Impact: "", + Resolution: "actions", + Provider: "yaml", + Service: "general", + Links: []string{"https://example.com"}, + Severity: "CRITICAL", + Terraform: &scan.EngineMetadata{}, + CloudFormation: &scan.EngineMetadata{}, + CustomChecks: scan.CustomChecks{ + Terraform: (*scan.TerraformCustomCheck)(nil)}, + RegoPackage: "data.builtin.yaml.lol", + Frameworks: map[framework.Framework][]string{ + framework.Default: {}, + }, + }, + results.GetFailed()[0].Rule(), + ) +} + +func TestTomlParser(t *testing.T) { + fsys := testutil.CreateFS(t, map[string]string{ + "/code/code.toml": ` +[x] +y = 123 +z = ["a", "b", "c"] +`, + "/rules/rule.rego": `package builtin.toml.lol + +__rego_metadata__ := { + "id": "ABC123", + "avd_id": "AVD-AB-0123", + "title": "title", + "short_code": "short", + "severity": "CRITICAL", + "type": "TOML Check", + "description": "description", + "recommended_actions": "actions", + "url": "https://example.com", +} + +__rego_input__ := { + "combine": false, + "selector": [{"type": "toml"}], +} + +deny[res] { + input.x.y == 123 + res := { + "msg": "oh no", + "startline": 1, + "endline": 2, + } +} + +`, + }) + + scanner := generic.NewTomlScanner(rego.WithPolicyDirs("rules")) + + results, err := scanner.ScanFS(context.TODO(), fsys, "code") + require.NoError(t, err) + + require.Len(t, results.GetFailed(), 1) + + assert.Equal(t, scan.Rule{ + AVDID: "AVD-AB-0123", + Aliases: []string{"ABC123"}, + ShortCode: "short", + Summary: "title", + Explanation: "description", + Impact: "", + Resolution: "actions", + Provider: "toml", + Service: "general", + Links: []string{"https://example.com"}, + Severity: "CRITICAL", + Terraform: &scan.EngineMetadata{}, + CloudFormation: &scan.EngineMetadata{}, + CustomChecks: scan.CustomChecks{ + Terraform: (*scan.TerraformCustomCheck)(nil)}, + RegoPackage: "data.builtin.toml.lol", + Frameworks: map[framework.Framework][]string{ + framework.Default: {}, + }, + }, + results.GetFailed()[0].Rule(), + ) +} diff --git a/pkg/iac/scanners/json/parser/parser.go b/pkg/iac/scanners/json/parser/parser.go deleted file mode 100644 index c97e54b40bd9..000000000000 --- a/pkg/iac/scanners/json/parser/parser.go +++ /dev/null @@ -1,65 +0,0 @@ -package parser - -import ( - "context" - "encoding/json" - "io/fs" - "path/filepath" - - "github.com/aquasecurity/trivy/pkg/log" -) - -type Parser struct { - logger *log.Logger -} - -// New creates a new parser -func New() *Parser { - return &Parser{ - logger: log.WithPrefix("json parser"), - } -} - -func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[string]any, error) { - - files := make(map[string]any) - if err := fs.WalkDir(target, filepath.ToSlash(path), func(path string, entry fs.DirEntry, err error) error { - select { - case <-ctx.Done(): - return ctx.Err() - default: - } - if err != nil { - return err - } - if entry.IsDir() { - return nil - } - - df, err := p.ParseFile(ctx, target, path) - if err != nil { - p.logger.Error("Parse error", log.FilePath(path), log.Err(err)) - return nil - } - - files[path] = df - return nil - }); err != nil { - return nil, err - } - return files, nil -} - -// ParseFile parses Dockerfile content from the provided filesystem path. -func (p *Parser) ParseFile(_ context.Context, fsys fs.FS, path string) (any, error) { - f, err := fsys.Open(filepath.ToSlash(path)) - if err != nil { - return nil, err - } - defer func() { _ = f.Close() }() - var target any - if err := json.NewDecoder(f).Decode(&target); err != nil { - return nil, err - } - return target, nil -} diff --git a/pkg/iac/scanners/json/parser/parser_test.go b/pkg/iac/scanners/json/parser/parser_test.go deleted file mode 100644 index a47868fad0ed..000000000000 --- a/pkg/iac/scanners/json/parser/parser_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package parser - -import ( - "context" - "testing" - - "github.com/liamg/memoryfs" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func Test_Parser(t *testing.T) { - input := `{ "x": { "y": 123, "z": ["a", "b", "c"]}}` - - memfs := memoryfs.New() - err := memfs.WriteFile("something.json", []byte(input), 0644) - require.NoError(t, err) - - data, err := New().ParseFile(context.TODO(), memfs, "something.json") - require.NoError(t, err) - - msi, ok := data.(map[string]any) - require.True(t, ok) - - xObj, ok := msi["x"] - require.True(t, ok) - - xMsi, ok := xObj.(map[string]any) - require.True(t, ok) - - yRaw, ok := xMsi["y"] - require.True(t, ok) - - y, ok := yRaw.(float64) - require.True(t, ok) - - assert.InEpsilon(t, 123.0, y, 0.0001) - - zRaw, ok := xMsi["z"] - require.True(t, ok) - - z, ok := zRaw.([]any) - require.True(t, ok) - - require.Len(t, z, 3) - - assert.Equal(t, "a", z[0]) - assert.Equal(t, "b", z[1]) - assert.Equal(t, "c", z[2]) - -} diff --git a/pkg/iac/scanners/json/scanner.go b/pkg/iac/scanners/json/scanner.go deleted file mode 100644 index f46f9cc56bc9..000000000000 --- a/pkg/iac/scanners/json/scanner.go +++ /dev/null @@ -1,113 +0,0 @@ -package json - -import ( - "context" - "io/fs" - "sync" - - "github.com/aquasecurity/trivy/pkg/iac/framework" - "github.com/aquasecurity/trivy/pkg/iac/rego" - "github.com/aquasecurity/trivy/pkg/iac/scan" - "github.com/aquasecurity/trivy/pkg/iac/scanners" - "github.com/aquasecurity/trivy/pkg/iac/scanners/json/parser" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" - "github.com/aquasecurity/trivy/pkg/iac/types" - "github.com/aquasecurity/trivy/pkg/log" -) - -var _ scanners.FSScanner = (*Scanner)(nil) -var _ options.ConfigurableScanner = (*Scanner)(nil) - -type Scanner struct { - mu sync.Mutex - logger *log.Logger - parser *parser.Parser - regoScanner *rego.Scanner - options []options.ScannerOption -} - -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} -func (s *Scanner) SetRegoOnly(bool) {} -func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {} - -func NewScanner(opts ...options.ScannerOption) *Scanner { - s := &Scanner{ - options: opts, - logger: log.WithPrefix("json scanner"), - parser: parser.New(), - } - for _, opt := range opts { - opt(s) - } - return s -} - -func (s *Scanner) Name() string { - return "JSON" -} - -func (s *Scanner) ScanFS(ctx context.Context, fsys fs.FS, path string) (scan.Results, error) { - - files, err := s.parser.ParseFS(ctx, fsys, path) - if err != nil { - return nil, err - } - - if len(files) == 0 { - return nil, nil - } - - var inputs []rego.Input - for path, file := range files { - inputs = append(inputs, rego.Input{ - Path: path, - FS: fsys, - Contents: file, - }) - } - - results, err := s.scanRego(ctx, fsys, inputs...) - if err != nil { - return nil, err - } - return results, nil -} - -func (s *Scanner) ScanFile(ctx context.Context, fsys fs.FS, path string) (scan.Results, error) { - parsed, err := s.parser.ParseFile(ctx, fsys, path) - if err != nil { - return nil, err - } - s.logger.Debug("Scanning", log.FilePath(path)) - return s.scanRego(ctx, fsys, rego.Input{ - Path: path, - Contents: parsed, - }) -} - -func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { - s.mu.Lock() - defer s.mu.Unlock() - if s.regoScanner != nil { - return s.regoScanner, nil - } - regoScanner := rego.NewScanner(types.SourceJSON, s.options...) - if err := regoScanner.LoadPolicies(srcFS); err != nil { - return nil, err - } - s.regoScanner = regoScanner - return regoScanner, nil -} - -func (s *Scanner) scanRego(ctx context.Context, srcFS fs.FS, inputs ...rego.Input) (scan.Results, error) { - regoScanner, err := s.initRegoScanner(srcFS) - if err != nil { - return nil, err - } - results, err := regoScanner.ScanInput(ctx, inputs...) - if err != nil { - return nil, err - } - results.SetSourceAndFilesystem("", srcFS, false) - return results, nil -} diff --git a/pkg/iac/scanners/json/scanner_test.go b/pkg/iac/scanners/json/scanner_test.go deleted file mode 100644 index 6656f70b2e25..000000000000 --- a/pkg/iac/scanners/json/scanner_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package json - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/aquasecurity/trivy/internal/testutil" - "github.com/aquasecurity/trivy/pkg/iac/framework" - "github.com/aquasecurity/trivy/pkg/iac/rego" - "github.com/aquasecurity/trivy/pkg/iac/scan" -) - -func Test_BasicScan(t *testing.T) { - - fs := testutil.CreateFS(t, map[string]string{ - "/code/data.json": `{ "x": { "y": 123, "z": ["a", "b", "c"]}}`, - "/rules/rule.rego": `package builtin.json.lol - -__rego_metadata__ := { - "id": "ABC123", - "avd_id": "AVD-AB-0123", - "title": "title", - "short_code": "short", - "severity": "CRITICAL", - "type": "JSON Check", - "description": "description", - "recommended_actions": "actions", - "url": "https://example.com", -} - -__rego_input__ := { - "combine": false, - "selector": [{"type": "json"}], -} - -deny[res] { - input.x.y == 123 - res := { - "msg": "oh no", - "startline": 1, - "endline": 2, - } -} - -`, - }) - - scanner := NewScanner(rego.WithPolicyDirs("rules")) - - results, err := scanner.ScanFS(context.TODO(), fs, "code") - require.NoError(t, err) - - require.Len(t, results.GetFailed(), 1) - - assert.Equal(t, scan.Rule{ - AVDID: "AVD-AB-0123", - Aliases: []string{"ABC123"}, - ShortCode: "short", - Summary: "title", - Explanation: "description", - Impact: "", - Resolution: "actions", - Provider: "json", - Service: "general", - Links: []string{"https://example.com"}, - Severity: "CRITICAL", - Terraform: &scan.EngineMetadata{}, - CloudFormation: &scan.EngineMetadata{}, - CustomChecks: scan.CustomChecks{ - Terraform: (*scan.TerraformCustomCheck)(nil), - }, - RegoPackage: "data.builtin.json.lol", - Frameworks: map[framework.Framework][]string{ - framework.Default: {}, - }, - }, results.GetFailed()[0].Rule()) -} diff --git a/pkg/iac/scanners/toml/parser/parser.go b/pkg/iac/scanners/toml/parser/parser.go deleted file mode 100644 index 95444389d74d..000000000000 --- a/pkg/iac/scanners/toml/parser/parser.go +++ /dev/null @@ -1,65 +0,0 @@ -package parser - -import ( - "context" - "io/fs" - "path/filepath" - - "github.com/BurntSushi/toml" - - "github.com/aquasecurity/trivy/pkg/log" -) - -type Parser struct { - logger *log.Logger -} - -// New creates a new parser -func New() *Parser { - return &Parser{ - logger: log.WithPrefix("toml parser"), - } -} - -func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[string]any, error) { - - files := make(map[string]any) - if err := fs.WalkDir(target, filepath.ToSlash(path), func(path string, entry fs.DirEntry, err error) error { - select { - case <-ctx.Done(): - return ctx.Err() - default: - } - if err != nil { - return err - } - if entry.IsDir() { - return nil - } - - df, err := p.ParseFile(ctx, target, path) - if err != nil { - p.logger.Error("Parse error", log.FilePath(path), log.Err(err)) - return nil - } - files[path] = df - return nil - }); err != nil { - return nil, err - } - return files, nil -} - -// ParseFile parses toml content from the provided filesystem path. -func (p *Parser) ParseFile(_ context.Context, fsys fs.FS, path string) (any, error) { - f, err := fsys.Open(filepath.ToSlash(path)) - if err != nil { - return nil, err - } - defer func() { _ = f.Close() }() - var target any - if _, err := toml.NewDecoder(f).Decode(&target); err != nil { - return nil, err - } - return target, nil -} diff --git a/pkg/iac/scanners/toml/parser/parser_test.go b/pkg/iac/scanners/toml/parser/parser_test.go deleted file mode 100644 index 1c9e9bdc341e..000000000000 --- a/pkg/iac/scanners/toml/parser/parser_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package parser - -import ( - "context" - "testing" - - "github.com/liamg/memoryfs" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func Test_Parser(t *testing.T) { - input := ` -[x] -y = 123 -z = ["a", "b", "c"] -` - - memfs := memoryfs.New() - err := memfs.WriteFile("something.yaml", []byte(input), 0644) - require.NoError(t, err) - - data, err := New().ParseFile(context.TODO(), memfs, "something.yaml") - require.NoError(t, err) - - msi, ok := data.(map[string]any) - require.True(t, ok) - - xObj, ok := msi["x"] - require.True(t, ok) - - xMsi, ok := xObj.(map[string]any) - require.True(t, ok) - - yRaw, ok := xMsi["y"] - require.True(t, ok) - - y, ok := yRaw.(int64) - require.True(t, ok) - - assert.Equal(t, int64(123), y) - - zRaw, ok := xMsi["z"] - require.True(t, ok) - - z, ok := zRaw.([]any) - require.True(t, ok) - - require.Len(t, z, 3) - - assert.Equal(t, "a", z[0]) - assert.Equal(t, "b", z[1]) - assert.Equal(t, "c", z[2]) - -} diff --git a/pkg/iac/scanners/toml/scanner.go b/pkg/iac/scanners/toml/scanner.go deleted file mode 100644 index 216d0b1f9697..000000000000 --- a/pkg/iac/scanners/toml/scanner.go +++ /dev/null @@ -1,111 +0,0 @@ -package toml - -import ( - "context" - "io/fs" - "sync" - - "github.com/aquasecurity/trivy/pkg/iac/framework" - "github.com/aquasecurity/trivy/pkg/iac/rego" - "github.com/aquasecurity/trivy/pkg/iac/scan" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" - "github.com/aquasecurity/trivy/pkg/iac/scanners/toml/parser" - "github.com/aquasecurity/trivy/pkg/iac/types" - "github.com/aquasecurity/trivy/pkg/log" -) - -var _ options.ConfigurableScanner = (*Scanner)(nil) - -type Scanner struct { - mu sync.Mutex - logger *log.Logger - options []options.ScannerOption - parser *parser.Parser - regoScanner *rego.Scanner -} - -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} -func (s *Scanner) SetRegoOnly(bool) {} -func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {} - -func (s *Scanner) Name() string { - return "TOML" -} - -func NewScanner(opts ...options.ScannerOption) *Scanner { - s := &Scanner{ - options: opts, - logger: log.WithPrefix("toml scanner"), - } - for _, opt := range opts { - opt(s) - } - s.parser = parser.New() - return s -} - -func (s *Scanner) ScanFS(ctx context.Context, fsys fs.FS, path string) (scan.Results, error) { - - files, err := s.parser.ParseFS(ctx, fsys, path) - if err != nil { - return nil, err - } - - if len(files) == 0 { - return nil, nil - } - - var inputs []rego.Input - for path, file := range files { - inputs = append(inputs, rego.Input{ - Path: path, - Contents: file, - FS: fsys, - }) - } - - results, err := s.scanRego(ctx, fsys, inputs...) - if err != nil { - return nil, err - } - return results, nil -} - -func (s *Scanner) ScanFile(ctx context.Context, fsys fs.FS, path string) (scan.Results, error) { - parsed, err := s.parser.ParseFile(ctx, fsys, path) - if err != nil { - return nil, err - } - s.logger.Debug("Scanning", log.FilePath(path)) - return s.scanRego(ctx, fsys, rego.Input{ - Path: path, - Contents: parsed, - }) -} - -func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { - s.mu.Lock() - defer s.mu.Unlock() - if s.regoScanner != nil { - return s.regoScanner, nil - } - regoScanner := rego.NewScanner(types.SourceTOML, s.options...) - if err := regoScanner.LoadPolicies(srcFS); err != nil { - return nil, err - } - s.regoScanner = regoScanner - return regoScanner, nil -} - -func (s *Scanner) scanRego(ctx context.Context, srcFS fs.FS, inputs ...rego.Input) (scan.Results, error) { - regoScanner, err := s.initRegoScanner(srcFS) - if err != nil { - return nil, err - } - results, err := regoScanner.ScanInput(ctx, inputs...) - if err != nil { - return nil, err - } - results.SetSourceAndFilesystem("", srcFS, false) - return results, nil -} diff --git a/pkg/iac/scanners/toml/scanner_test.go b/pkg/iac/scanners/toml/scanner_test.go deleted file mode 100644 index ea5819448288..000000000000 --- a/pkg/iac/scanners/toml/scanner_test.go +++ /dev/null @@ -1,85 +0,0 @@ -package toml - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/aquasecurity/trivy/internal/testutil" - "github.com/aquasecurity/trivy/pkg/iac/framework" - "github.com/aquasecurity/trivy/pkg/iac/rego" - "github.com/aquasecurity/trivy/pkg/iac/scan" -) - -func Test_BasicScan(t *testing.T) { - - fs := testutil.CreateFS(t, map[string]string{ - "/code/code.toml": ` -[x] -y = 123 -z = ["a", "b", "c"] -`, - "/rules/rule.rego": `package builtin.toml.lol - -__rego_metadata__ := { - "id": "ABC123", - "avd_id": "AVD-AB-0123", - "title": "title", - "short_code": "short", - "severity": "CRITICAL", - "type": "TOML Check", - "description": "description", - "recommended_actions": "actions", - "url": "https://example.com", -} - -__rego_input__ := { - "combine": false, - "selector": [{"type": "toml"}], -} - -deny[res] { - input.x.y == 123 - res := { - "msg": "oh no", - "startline": 1, - "endline": 2, - } -} - -`, - }) - - scanner := NewScanner(rego.WithPolicyDirs("rules")) - - results, err := scanner.ScanFS(context.TODO(), fs, "code") - require.NoError(t, err) - - require.Len(t, results.GetFailed(), 1) - - assert.Equal(t, scan.Rule{ - AVDID: "AVD-AB-0123", - Aliases: []string{"ABC123"}, - ShortCode: "short", - Summary: "title", - Explanation: "description", - Impact: "", - Resolution: "actions", - Provider: "toml", - Service: "general", - Links: []string{"https://example.com"}, - Severity: "CRITICAL", - Terraform: &scan.EngineMetadata{}, - CloudFormation: &scan.EngineMetadata{}, - CustomChecks: scan.CustomChecks{ - Terraform: (*scan.TerraformCustomCheck)(nil)}, - RegoPackage: "data.builtin.toml.lol", - Frameworks: map[framework.Framework][]string{ - framework.Default: {}, - }, - }, - results.GetFailed()[0].Rule(), - ) -} diff --git a/pkg/iac/scanners/yaml/parser/parser.go b/pkg/iac/scanners/yaml/parser/parser.go deleted file mode 100644 index 9b1f026ae248..000000000000 --- a/pkg/iac/scanners/yaml/parser/parser.go +++ /dev/null @@ -1,86 +0,0 @@ -package parser - -import ( - "bytes" - "context" - "io" - "io/fs" - "path/filepath" - - "gopkg.in/yaml.v3" - - "github.com/aquasecurity/trivy/pkg/log" -) - -type Parser struct { - logger *log.Logger -} - -// New creates a new YAML parser -func New() *Parser { - return &Parser{ - logger: log.WithPrefix("yaml parser"), - } -} - -func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[string][]any, error) { - - files := make(map[string][]any) - if err := fs.WalkDir(target, filepath.ToSlash(path), func(path string, entry fs.DirEntry, err error) error { - - select { - case <-ctx.Done(): - return ctx.Err() - default: - } - if err != nil { - return err - } - if entry.IsDir() { - return nil - } - - df, err := p.ParseFile(ctx, target, path) - if err != nil { - p.logger.Error("Parse error", log.FilePath(path), log.Err(err)) - return nil - } - files[path] = df - return nil - }); err != nil { - return nil, err - } - return files, nil -} - -// ParseFile parses yaml content from the provided filesystem path. -func (p *Parser) ParseFile(_ context.Context, fsys fs.FS, path string) ([]any, error) { - f, err := fsys.Open(filepath.ToSlash(path)) - if err != nil { - return nil, err - } - defer func() { _ = f.Close() }() - - contents, err := io.ReadAll(f) - if err != nil { - return nil, err - } - - var results []any - - marker := []byte("\n---\n") - altMarker := []byte("\r\n---\r\n") - if bytes.Contains(contents, altMarker) { - marker = altMarker - } - - for _, partial := range bytes.Split(contents, marker) { - var target any - if err := yaml.Unmarshal(partial, &target); err != nil { - return nil, err - } - results = append(results, target) - } - - return results, nil -} diff --git a/pkg/iac/scanners/yaml/parser/parser_test.go b/pkg/iac/scanners/yaml/parser/parser_test.go deleted file mode 100644 index f7817d5990fa..000000000000 --- a/pkg/iac/scanners/yaml/parser/parser_test.go +++ /dev/null @@ -1,150 +0,0 @@ -package parser - -import ( - "context" - "testing" - - "github.com/liamg/memoryfs" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func Test_Parser(t *testing.T) { - input := `--- -x: - y: 123 - z: - - a - - b - - c -` - - memfs := memoryfs.New() - err := memfs.WriteFile("something.yaml", []byte(input), 0644) - require.NoError(t, err) - - data, err := New().ParseFile(context.TODO(), memfs, "something.yaml") - require.NoError(t, err) - - assert.Len(t, data, 1) - - msi, ok := data[0].(map[string]any) - require.True(t, ok) - - xObj, ok := msi["x"] - require.True(t, ok) - - xMsi, ok := xObj.(map[string]any) - require.True(t, ok) - - yRaw, ok := xMsi["y"] - require.True(t, ok) - - y, ok := yRaw.(int) - require.True(t, ok) - - assert.Equal(t, 123, y) - - zRaw, ok := xMsi["z"] - require.True(t, ok) - - z, ok := zRaw.([]any) - require.True(t, ok) - - require.Len(t, z, 3) - - assert.Equal(t, "a", z[0]) - assert.Equal(t, "b", z[1]) - assert.Equal(t, "c", z[2]) - -} - -func Test_Parser_WithSeparatedContent(t *testing.T) { - input := `--- -x: - y: 123 - z: - - a - - b - - c ---- -x: - y: 456 - z: - - x - - y - - z -` - - memfs := memoryfs.New() - err := memfs.WriteFile("something.yaml", []byte(input), 0644) - require.NoError(t, err) - - data, err := New().ParseFile(context.TODO(), memfs, "something.yaml") - require.NoError(t, err) - - assert.Len(t, data, 2) - - { - msi, ok := data[0].(map[string]any) - require.True(t, ok) - - xObj, ok := msi["x"] - require.True(t, ok) - - xMsi, ok := xObj.(map[string]any) - require.True(t, ok) - - yRaw, ok := xMsi["y"] - require.True(t, ok) - - y, ok := yRaw.(int) - require.True(t, ok) - - assert.Equal(t, 123, y) - - zRaw, ok := xMsi["z"] - require.True(t, ok) - - z, ok := zRaw.([]any) - require.True(t, ok) - - require.Len(t, z, 3) - - assert.Equal(t, "a", z[0]) - assert.Equal(t, "b", z[1]) - assert.Equal(t, "c", z[2]) - } - - { - msi, ok := data[1].(map[string]any) - require.True(t, ok) - - xObj, ok := msi["x"] - require.True(t, ok) - - xMsi, ok := xObj.(map[string]any) - require.True(t, ok) - - yRaw, ok := xMsi["y"] - require.True(t, ok) - - y, ok := yRaw.(int) - require.True(t, ok) - - assert.Equal(t, 456, y) - - zRaw, ok := xMsi["z"] - require.True(t, ok) - - z, ok := zRaw.([]any) - require.True(t, ok) - - require.Len(t, z, 3) - - assert.Equal(t, "x", z[0]) - assert.Equal(t, "y", z[1]) - assert.Equal(t, "z", z[2]) - } - -} diff --git a/pkg/iac/scanners/yaml/scanner.go b/pkg/iac/scanners/yaml/scanner.go deleted file mode 100644 index 565d10df1f83..000000000000 --- a/pkg/iac/scanners/yaml/scanner.go +++ /dev/null @@ -1,113 +0,0 @@ -package yaml - -import ( - "context" - "io/fs" - "sync" - - "github.com/aquasecurity/trivy/pkg/iac/framework" - "github.com/aquasecurity/trivy/pkg/iac/rego" - "github.com/aquasecurity/trivy/pkg/iac/scan" - "github.com/aquasecurity/trivy/pkg/iac/scanners/options" - "github.com/aquasecurity/trivy/pkg/iac/scanners/yaml/parser" - "github.com/aquasecurity/trivy/pkg/iac/types" - "github.com/aquasecurity/trivy/pkg/log" -) - -var _ options.ConfigurableScanner = (*Scanner)(nil) - -type Scanner struct { - mu sync.Mutex - options []options.ScannerOption - logger *log.Logger - parser *parser.Parser - regoScanner *rego.Scanner -} - -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} -func (s *Scanner) SetRegoOnly(bool) {} -func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {} - -func (s *Scanner) Name() string { - return "YAML" -} - -func NewScanner(opts ...options.ScannerOption) *Scanner { - s := &Scanner{ - options: opts, - logger: log.WithPrefix("yaml scanner"), - parser: parser.New(), - } - for _, opt := range opts { - opt(s) - } - return s -} - -func (s *Scanner) ScanFS(ctx context.Context, fsys fs.FS, path string) (scan.Results, error) { - - fileset, err := s.parser.ParseFS(ctx, fsys, path) - if err != nil { - return nil, err - } - - if len(fileset) == 0 { - return nil, nil - } - - var inputs []rego.Input - for path, files := range fileset { - for _, file := range files { - inputs = append(inputs, rego.Input{ - Path: path, - Contents: file, - FS: fsys, - }) - } - } - - results, err := s.scanRego(ctx, fsys, inputs...) - if err != nil { - return nil, err - } - return results, nil -} - -func (s *Scanner) ScanFile(ctx context.Context, fsys fs.FS, path string) (scan.Results, error) { - parsed, err := s.parser.ParseFile(ctx, fsys, path) - if err != nil { - return nil, err - } - s.logger.Debug("Scanning", log.String("path", path)) - return s.scanRego(ctx, fsys, rego.Input{ - Path: path, - Contents: parsed, - }) -} - -func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { - s.mu.Lock() - defer s.mu.Unlock() - if s.regoScanner != nil { - return s.regoScanner, nil - } - regoScanner := rego.NewScanner(types.SourceYAML, s.options...) - if err := regoScanner.LoadPolicies(srcFS); err != nil { - return nil, err - } - s.regoScanner = regoScanner - return regoScanner, nil -} - -func (s *Scanner) scanRego(ctx context.Context, srcFS fs.FS, inputs ...rego.Input) (scan.Results, error) { - regoScanner, err := s.initRegoScanner(srcFS) - if err != nil { - return nil, err - } - results, err := regoScanner.ScanInput(ctx, inputs...) - if err != nil { - return nil, err - } - results.SetSourceAndFilesystem("", srcFS, false) - return results, nil -} diff --git a/pkg/iac/scanners/yaml/scanner_test.go b/pkg/iac/scanners/yaml/scanner_test.go deleted file mode 100644 index b7c4ec623887..000000000000 --- a/pkg/iac/scanners/yaml/scanner_test.go +++ /dev/null @@ -1,88 +0,0 @@ -package yaml - -import ( - "context" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/aquasecurity/trivy/internal/testutil" - "github.com/aquasecurity/trivy/pkg/iac/framework" - "github.com/aquasecurity/trivy/pkg/iac/rego" - "github.com/aquasecurity/trivy/pkg/iac/scan" -) - -func Test_BasicScan(t *testing.T) { - - fs := testutil.CreateFS(t, map[string]string{ - "/code/data.yaml": `--- -x: - y: 123 - z: - - a - - b - - c -`, - "/rules/rule.rego": `package builtin.yaml.lol - -__rego_metadata__ := { - "id": "ABC123", - "avd_id": "AVD-AB-0123", - "title": "title", - "short_code": "short", - "severity": "CRITICAL", - "type": "YAML Check", - "description": "description", - "recommended_actions": "actions", - "url": "https://example.com", -} - -__rego_input__ := { - "combine": false, - "selector": [{"type": "yaml"}], -} - -deny[res] { - input.x.y == 123 - res := { - "msg": "oh no", - "startline": 1, - "endline": 2, - } -} - -`, - }) - - scanner := NewScanner(rego.WithPolicyDirs("rules")) - - results, err := scanner.ScanFS(context.TODO(), fs, "code") - require.NoError(t, err) - - require.Len(t, results.GetFailed(), 1) - - assert.Equal(t, scan.Rule{ - AVDID: "AVD-AB-0123", - Aliases: []string{"ABC123"}, - ShortCode: "short", - Summary: "title", - Explanation: "description", - Impact: "", - Resolution: "actions", - Provider: "yaml", - Service: "general", - Links: []string{"https://example.com"}, - Severity: "CRITICAL", - Terraform: &scan.EngineMetadata{}, - CloudFormation: &scan.EngineMetadata{}, - CustomChecks: scan.CustomChecks{ - Terraform: (*scan.TerraformCustomCheck)(nil)}, - RegoPackage: "data.builtin.yaml.lol", - Frameworks: map[framework.Framework][]string{ - framework.Default: {}, - }, - }, - results.GetFailed()[0].Rule(), - ) -} diff --git a/pkg/misconf/scanner.go b/pkg/misconf/scanner.go index 7bec3ed6fe14..04fc28bc5296 100644 --- a/pkg/misconf/scanner.go +++ b/pkg/misconf/scanner.go @@ -24,14 +24,13 @@ import ( cfscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation" cfparser "github.com/aquasecurity/trivy/pkg/iac/scanners/cloudformation/parser" dfscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/dockerfile" + "github.com/aquasecurity/trivy/pkg/iac/scanners/generic" "github.com/aquasecurity/trivy/pkg/iac/scanners/helm" - jsonscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/json" k8sscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/kubernetes" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/scanners/terraform" tfprawscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/terraformplan/snapshot" tfpjsonscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/terraformplan/tfjson" - yamlscanner "github.com/aquasecurity/trivy/pkg/iac/scanners/yaml" "github.com/aquasecurity/trivy/pkg/log" "github.com/aquasecurity/trivy/pkg/mapfs" @@ -118,9 +117,9 @@ func NewScanner(t detection.FileType, opt ScannerOption) (*Scanner, error) { case detection.FileTypeTerraformPlanSnapshot: scanner = tfprawscanner.New(opts...) case detection.FileTypeYAML: - scanner = yamlscanner.NewScanner(opts...) + scanner = generic.NewYamlScanner(opts...) case detection.FileTypeJSON: - scanner = jsonscanner.NewScanner(opts...) + scanner = generic.NewJsonScanner(opts...) default: return nil, xerrors.Errorf("unknown file type: %s", t) } From 31aa20ab90d52dd6cbc364fe0ff257b59cf02187 Mon Sep 17 00:00:00 2001 From: Simon Deziel Date: Mon, 14 Oct 2024 00:45:56 -0400 Subject: [PATCH 133/183] docs: apt-transport-https is a transitional package (#7678) Signed-off-by: Simon Deziel --- docs/getting-started/installation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index 61f6e42871bb..fd8b19366e86 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -34,7 +34,7 @@ In this section you will find an aggregation of the different ways to install Tr Add repository setting to `/etc/apt/sources.list.d`. ``` bash - sudo apt-get install wget apt-transport-https gnupg + sudo apt-get install wget gnupg wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | gpg --dearmor | sudo tee /usr/share/keyrings/trivy.gpg > /dev/null echo "deb [signed-by=/usr/share/keyrings/trivy.gpg] https://aquasecurity.github.io/trivy-repo/deb generic main" | sudo tee -a /etc/apt/sources.list.d/trivy.list sudo apt-get update From 633a7abeea4287899392a24f2705f96dfeb7e312 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Tue, 15 Oct 2024 15:24:10 +0400 Subject: [PATCH 134/183] feat(cli): rename `trivy auth` to `trivy registry` (#7727) Signed-off-by: knqyf263 --- contrib/Trivy.gitlab-ci.yml | 2 +- docs/docs/advanced/private-registries/index.md | 6 +++--- docs/docs/references/configuration/cli/trivy.md | 2 +- .../cli/{trivy_auth.md => trivy_registry.md} | 10 +++++----- .../{trivy_auth_login.md => trivy_registry_login.md} | 8 ++++---- ...trivy_auth_logout.md => trivy_registry_logout.md} | 8 ++++---- docs/docs/target/container_image.md | 2 +- integration/registry_test.go | 4 ++-- mkdocs.yml | 8 ++++---- pkg/commands/app.go | 12 ++++++------ 10 files changed, 31 insertions(+), 31 deletions(-) rename docs/docs/references/configuration/cli/{trivy_auth.md => trivy_registry.md} (73%) rename docs/docs/references/configuration/cli/{trivy_auth_login.md => trivy_registry_login.md} (81%) rename docs/docs/references/configuration/cli/{trivy_auth_logout.md => trivy_registry_logout.md} (80%) diff --git a/contrib/Trivy.gitlab-ci.yml b/contrib/Trivy.gitlab-ci.yml index a62e26301a20..f91588240346 100644 --- a/contrib/Trivy.gitlab-ci.yml +++ b/contrib/Trivy.gitlab-ci.yml @@ -14,7 +14,7 @@ Trivy_container_scanning: - apk add --no-cache curl docker-cli - curl -sfL https://raw.githubusercontent.com/aquasecurity/trivy/main/contrib/install.sh | sh -s -- -b /usr/local/bin ${TRIVY_VERSION} - curl -sSL -o /tmp/trivy-gitlab.tpl https://github.com/aquasecurity/trivy/raw/${TRIVY_VERSION}/contrib/gitlab.tpl - - trivy auth login --username "$CI_REGISTRY_USER" --password "$CI_REGISTRY_PASSWORD" $CI_REGISTRY + - trivy registry login --username "$CI_REGISTRY_USER" --password "$CI_REGISTRY_PASSWORD" $CI_REGISTRY script: - trivy --exit-code 0 --cache-dir .trivycache/ --no-progress --format template --template "@/tmp/trivy-gitlab.tpl" -o gl-container-scanning-report.json $IMAGE cache: diff --git a/docs/docs/advanced/private-registries/index.md b/docs/docs/advanced/private-registries/index.md index 7bac7a2742d5..e40f2f8f7230 100644 --- a/docs/docs/advanced/private-registries/index.md +++ b/docs/docs/advanced/private-registries/index.md @@ -2,11 +2,11 @@ Trivy can download images from a private registry without the need for installin This makes it easy to run within a CI process. ## Login -You can log in to a private registry using the `trivy auth login` command. +You can log in to a private registry using the `trivy registry login` command. It uses the Docker configuration file (`~/.docker/config.json`) to store the credentials under the hood, and the configuration file path can be configured by `DOCKER_CONFIG` environment variable. ```shell -$ cat ~/my_password.txt | trivy auth login --username foo --password-stdin ghcr.io +$ cat ~/my_password.txt | trivy registry login --username foo --password-stdin ghcr.io $ trivy image ghcr.io/your/private_image ``` @@ -23,7 +23,7 @@ $ TRIVY_USERNAME=YOUR_USERNAME TRIVY_PASSWORD=YOUR_PASSWORD trivy image YOUR_PRI To mitigate this risk: 1. Set credentials cautiously and only when necessary. - 2. Prefer using `trivy auth config` to pre-configure credentials with specific registries, which ensures credentials are only sent to appropriate registries. + 2. Prefer using `trivy registry login` to pre-configure credentials with specific registries, which ensures credentials are only sent to appropriate registries. Trivy also supports providing credentials through CLI flags: diff --git a/docs/docs/references/configuration/cli/trivy.md b/docs/docs/references/configuration/cli/trivy.md index 2919e43cbe27..0f4faaecde0c 100644 --- a/docs/docs/references/configuration/cli/trivy.md +++ b/docs/docs/references/configuration/cli/trivy.md @@ -43,7 +43,6 @@ trivy [global flags] command [flags] target ### SEE ALSO -* [trivy auth](trivy_auth.md) - Authentication * [trivy clean](trivy_clean.md) - Remove cached files * [trivy config](trivy_config.md) - Scan config files for misconfigurations * [trivy convert](trivy_convert.md) - Convert Trivy JSON report into a different format @@ -52,6 +51,7 @@ trivy [global flags] command [flags] target * [trivy kubernetes](trivy_kubernetes.md) - [EXPERIMENTAL] Scan kubernetes cluster * [trivy module](trivy_module.md) - Manage modules * [trivy plugin](trivy_plugin.md) - Manage plugins +* [trivy registry](trivy_registry.md) - Manage registry authentication * [trivy repository](trivy_repository.md) - Scan a repository * [trivy rootfs](trivy_rootfs.md) - Scan rootfs * [trivy sbom](trivy_sbom.md) - Scan SBOM for vulnerabilities and licenses diff --git a/docs/docs/references/configuration/cli/trivy_auth.md b/docs/docs/references/configuration/cli/trivy_registry.md similarity index 73% rename from docs/docs/references/configuration/cli/trivy_auth.md rename to docs/docs/references/configuration/cli/trivy_registry.md index ba2eaa6a6715..4a42cea3f4df 100644 --- a/docs/docs/references/configuration/cli/trivy_auth.md +++ b/docs/docs/references/configuration/cli/trivy_registry.md @@ -1,11 +1,11 @@ -## trivy auth +## trivy registry -Authentication +Manage registry authentication ### Options ``` - -h, --help help for auth + -h, --help help for registry ``` ### Options inherited from parent commands @@ -24,6 +24,6 @@ Authentication ### SEE ALSO * [trivy](trivy.md) - Unified security scanner -* [trivy auth login](trivy_auth_login.md) - Log in to a registry -* [trivy auth logout](trivy_auth_logout.md) - Log out of a registry +* [trivy registry login](trivy_registry_login.md) - Log in to a registry +* [trivy registry logout](trivy_registry_logout.md) - Log out of a registry diff --git a/docs/docs/references/configuration/cli/trivy_auth_login.md b/docs/docs/references/configuration/cli/trivy_registry_login.md similarity index 81% rename from docs/docs/references/configuration/cli/trivy_auth_login.md rename to docs/docs/references/configuration/cli/trivy_registry_login.md index 8f2cfdb18abc..6e963b3ca9f4 100644 --- a/docs/docs/references/configuration/cli/trivy_auth_login.md +++ b/docs/docs/references/configuration/cli/trivy_registry_login.md @@ -1,16 +1,16 @@ -## trivy auth login +## trivy registry login Log in to a registry ``` -trivy auth login SERVER [flags] +trivy registry login SERVER [flags] ``` ### Examples ``` # Log in to reg.example.com - cat ~/my_password.txt | trivy auth login --username foo --password-stdin reg.example.com + cat ~/my_password.txt | trivy registry login --username foo --password-stdin reg.example.com ``` ### Options @@ -37,5 +37,5 @@ trivy auth login SERVER [flags] ### SEE ALSO -* [trivy auth](trivy_auth.md) - Authentication +* [trivy registry](trivy_registry.md) - Manage registry authentication diff --git a/docs/docs/references/configuration/cli/trivy_auth_logout.md b/docs/docs/references/configuration/cli/trivy_registry_logout.md similarity index 80% rename from docs/docs/references/configuration/cli/trivy_auth_logout.md rename to docs/docs/references/configuration/cli/trivy_registry_logout.md index 3a25958001cd..b3da44c5fe92 100644 --- a/docs/docs/references/configuration/cli/trivy_auth_logout.md +++ b/docs/docs/references/configuration/cli/trivy_registry_logout.md @@ -1,16 +1,16 @@ -## trivy auth logout +## trivy registry logout Log out of a registry ``` -trivy auth logout SERVER [flags] +trivy registry logout SERVER [flags] ``` ### Examples ``` # Log out of reg.example.com - trivy auth logout reg.example.com + trivy registry logout reg.example.com ``` ### Options @@ -34,5 +34,5 @@ trivy auth logout SERVER [flags] ### SEE ALSO -* [trivy auth](trivy_auth.md) - Authentication +* [trivy registry](trivy_registry.md) - Manage registry authentication diff --git a/docs/docs/target/container_image.md b/docs/docs/target/container_image.md index 6f514db29fb5..7c703980de15 100644 --- a/docs/docs/target/container_image.md +++ b/docs/docs/target/container_image.md @@ -297,7 +297,7 @@ Trivy supports registries that comply with the following specifications. - [Docker Registry HTTP API V2](https://docs.docker.com/registry/spec/api/) - [OCI Distribution Specification](https://github.com/opencontainers/distribution-spec) -You can configure credentials with `trivy auth login`. +You can configure credentials with `trivy registry login`. See [here](../advanced/private-registries/index.md) for the detail. ### Tar Files diff --git a/integration/registry_test.go b/integration/registry_test.go index ce77db5ad74a..aded09adce35 100644 --- a/integration/registry_test.go +++ b/integration/registry_test.go @@ -184,7 +184,7 @@ func TestRegistry(t *testing.T) { golden: "testdata/alpine-310.json.golden", }, { - name: "authenticate with 'trivy auth login'", + name: "authenticate with 'trivy registry login'", imageName: "alpine:3.10", imageFile: "testdata/fixtures/images/alpine-310.tar.gz", os: "alpine 3.10.2", @@ -295,7 +295,7 @@ func setupEnv(t *testing.T, imageRef name.Reference, baseDir string, opt registr case opt.AuthLogin: t.Setenv("DOCKER_CONFIG", t.TempDir()) err := execute([]string{ - "auth", + "registry", "login", "--username", opt.Username, diff --git a/mkdocs.yml b/mkdocs.yml index 1d3d6276e2c3..00e458e15a91 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -158,10 +158,6 @@ nav: - Configuration: - CLI: - Overview: docs/references/configuration/cli/trivy.md - - Auth: - - Auth: docs/references/configuration/cli/trivy_auth.md - - Auth Login: docs/references/configuration/cli/trivy_auth_login.md - - Auth Logout: docs/references/configuration/cli/trivy_auth_logout.md - Clean: docs/references/configuration/cli/trivy_clean.md - Config: docs/references/configuration/cli/trivy_config.md - Convert: docs/references/configuration/cli/trivy_convert.md @@ -182,6 +178,10 @@ nav: - Plugin Update: docs/references/configuration/cli/trivy_plugin_update.md - Plugin Upgrade: docs/references/configuration/cli/trivy_plugin_upgrade.md - Plugin Search: docs/references/configuration/cli/trivy_plugin_search.md + - Registry: + - Registry: docs/references/configuration/cli/trivy_registry.md + - Registry Login: docs/references/configuration/cli/trivy_registry_login.md + - Registry Logout: docs/references/configuration/cli/trivy_registry_logout.md - Repository: docs/references/configuration/cli/trivy_repository.md - Rootfs: docs/references/configuration/cli/trivy_rootfs.md - SBOM: docs/references/configuration/cli/trivy_sbom.md diff --git a/pkg/commands/app.go b/pkg/commands/app.go index eec063a3eba3..dbe3d54ba373 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -100,7 +100,7 @@ func NewApp() *cobra.Command { NewVersionCommand(globalFlags), NewVMCommand(globalFlags), NewCleanCommand(globalFlags), - NewAuthCommand(globalFlags), + NewRegistryCommand(globalFlags), NewVEXCommand(globalFlags), ) @@ -1235,11 +1235,11 @@ func NewCleanCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { return cmd } -func NewAuthCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { +func NewRegistryCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { cmd := &cobra.Command{ - Use: "auth [flags]", + Use: "registry [flags]", GroupID: groupUtility, - Short: "Authentication", + Short: "Manage registry authentication", SilenceErrors: true, SilenceUsage: true, } @@ -1255,7 +1255,7 @@ func NewAuthCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { SilenceErrors: true, SilenceUsage: true, Example: ` # Log in to reg.example.com - cat ~/my_password.txt | trivy auth login --username foo --password-stdin reg.example.com`, + cat ~/my_password.txt | trivy registry login --username foo --password-stdin reg.example.com`, Args: cobra.ExactArgs(1), PreRunE: func(cmd *cobra.Command, args []string) error { if err := loginFlags.Bind(cmd); err != nil { @@ -1277,7 +1277,7 @@ func NewAuthCommand(globalFlags *flag.GlobalFlagGroup) *cobra.Command { SilenceErrors: true, SilenceUsage: true, Example: ` # Log out of reg.example.com - trivy auth logout reg.example.com`, + trivy registry logout reg.example.com`, Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { return auth.Logout(cmd.Context(), args[0]) From ad914123c4d203af1e1da6b7e2d3e49d9d3831d8 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Wed, 16 Oct 2024 10:15:17 +0600 Subject: [PATCH 135/183] feat(misconf): public network support for Azure Storage Account (#7601) Signed-off-by: nikpivkin --- pkg/iac/adapters/arm/storage/adapt.go | 6 +++++ pkg/iac/adapters/arm/storage/adapt_test.go | 27 ++++++++++--------- .../adapters/terraform/azure/storage/adapt.go | 3 ++- .../terraform/azure/storage/adapt_test.go | 22 ++++++++++++--- pkg/iac/providers/azure/storage/storage.go | 15 ++++++----- pkg/iac/rego/schemas/cloud.json | 4 +++ 6 files changed, 54 insertions(+), 23 deletions(-) diff --git a/pkg/iac/adapters/arm/storage/adapt.go b/pkg/iac/adapters/arm/storage/adapt.go index 018949e24e10..186ab5beda9d 100644 --- a/pkg/iac/adapters/arm/storage/adapt.go +++ b/pkg/iac/adapters/arm/storage/adapt.go @@ -62,6 +62,12 @@ func adaptAccounts(deployment azure.Deployment) []storage.Account { MinimumTLSVersion: resource.Properties.GetMapValue("minimumTlsVersion").AsStringValue("", resource.Properties.GetMetadata()), Queues: queues, } + + publicNetworkAccess := resource.Properties.GetMapValue("publicNetworkAccess") + account.PublicNetworkAccess = types.Bool( + publicNetworkAccess.AsStringValue("Enabled", publicNetworkAccess.Metadata).EqualTo("Enabled"), + publicNetworkAccess.Metadata, + ) accounts = append(accounts, account) } return accounts diff --git a/pkg/iac/adapters/arm/storage/adapt_test.go b/pkg/iac/adapters/arm/storage/adapt_test.go index f4fd81f47ad2..a6965ca1560c 100644 --- a/pkg/iac/adapters/arm/storage/adapt_test.go +++ b/pkg/iac/adapters/arm/storage/adapt_test.go @@ -6,17 +6,17 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - azure2 "github.com/aquasecurity/trivy/pkg/iac/scanners/azure" + "github.com/aquasecurity/trivy/pkg/iac/scanners/azure" "github.com/aquasecurity/trivy/pkg/iac/types" ) func Test_AdaptStorageDefaults(t *testing.T) { - input := azure2.Deployment{ - Resources: []azure2.Resource{ + input := azure.Deployment{ + Resources: []azure.Resource{ { - Type: azure2.NewValue("Microsoft.Storage/storageAccounts", types.NewTestMetadata()), - Properties: azure2.NewValue(make(map[string]azure2.Value), types.NewTestMetadata()), + Type: azure.NewValue("Microsoft.Storage/storageAccounts", types.NewTestMetadata()), + Properties: azure.NewValue(make(map[string]azure.Value), types.NewTestMetadata()), }, }, } @@ -28,19 +28,21 @@ func Test_AdaptStorageDefaults(t *testing.T) { account := output.Accounts[0] assert.Equal(t, "", account.MinimumTLSVersion.Value()) assert.False(t, account.EnforceHTTPS.Value()) + assert.True(t, account.PublicNetworkAccess.Value()) } func Test_AdaptStorage(t *testing.T) { - input := azure2.Deployment{ - Resources: []azure2.Resource{ + input := azure.Deployment{ + Resources: []azure.Resource{ { - Type: azure2.NewValue("Microsoft.Storage/storageAccounts", types.NewTestMetadata()), - Name: azure2.Value{}, - Properties: azure2.NewValue(map[string]azure2.Value{ - "minimumTlsVersion": azure2.NewValue("TLS1_2", types.NewTestMetadata()), - "supportsHttpsTrafficOnly": azure2.NewValue(true, types.NewTestMetadata()), + Type: azure.NewValue("Microsoft.Storage/storageAccounts", types.NewTestMetadata()), + Name: azure.Value{}, + Properties: azure.NewValue(map[string]azure.Value{ + "minimumTlsVersion": azure.NewValue("TLS1_2", types.NewTestMetadata()), + "supportsHttpsTrafficOnly": azure.NewValue(true, types.NewTestMetadata()), + "publicNetworkAccess": azure.NewValue("Disabled", types.NewTestMetadata()), }, types.NewTestMetadata()), }, }, @@ -53,5 +55,6 @@ func Test_AdaptStorage(t *testing.T) { account := output.Accounts[0] assert.Equal(t, "TLS1_2", account.MinimumTLSVersion.Value()) assert.True(t, account.EnforceHTTPS.Value()) + assert.False(t, account.PublicNetworkAccess.Value()) } diff --git a/pkg/iac/adapters/terraform/azure/storage/adapt.go b/pkg/iac/adapters/terraform/azure/storage/adapt.go index 6a51cf1fca2b..3f125c3c828f 100644 --- a/pkg/iac/adapters/terraform/azure/storage/adapt.go +++ b/pkg/iac/adapters/terraform/azure/storage/adapt.go @@ -108,7 +108,8 @@ func adaptAccount(resource *terraform.Block) storage.Account { Metadata: resource.GetMetadata(), EnableLogging: iacTypes.BoolDefault(false, resource.GetMetadata()), }, - MinimumTLSVersion: iacTypes.StringDefault(minimumTlsVersionOneTwo, resource.GetMetadata()), + MinimumTLSVersion: iacTypes.StringDefault(minimumTlsVersionOneTwo, resource.GetMetadata()), + PublicNetworkAccess: resource.GetAttribute("public_network_access_enabled").AsBoolValueOrDefault(true, resource), } networkRulesBlocks := resource.GetBlocks("network_rules") diff --git a/pkg/iac/adapters/terraform/azure/storage/adapt_test.go b/pkg/iac/adapters/terraform/azure/storage/adapt_test.go index 87ffb1a919f4..5f576731d432 100644 --- a/pkg/iac/adapters/terraform/azure/storage/adapt_test.go +++ b/pkg/iac/adapters/terraform/azure/storage/adapt_test.go @@ -18,6 +18,20 @@ func Test_Adapt(t *testing.T) { terraform string expected storage.Storage }{ + { + name: "default", + terraform: `resource "azurerm_storage_account" "example" {}`, + expected: storage.Storage{ + Accounts: []storage.Account{ + { + PublicNetworkAccess: iacTypes.BoolTest(true), + MinimumTLSVersion: iacTypes.StringTest(minimumTlsVersionOneTwo), + EnforceHTTPS: iacTypes.BoolTest(true), + }, + {}, + }, + }, + }, { name: "defined", terraform: ` @@ -45,6 +59,7 @@ func Test_Adapt(t *testing.T) { } } min_tls_version = "TLS1_2" + public_network_access_enabled = false } resource "azurerm_storage_account_network_rules" "test" { @@ -65,9 +80,10 @@ func Test_Adapt(t *testing.T) { Accounts: []storage.Account{ { - Metadata: iacTypes.NewTestMetadata(), - EnforceHTTPS: iacTypes.Bool(true, iacTypes.NewTestMetadata()), - MinimumTLSVersion: iacTypes.String("TLS1_2", iacTypes.NewTestMetadata()), + Metadata: iacTypes.NewTestMetadata(), + EnforceHTTPS: iacTypes.Bool(true, iacTypes.NewTestMetadata()), + MinimumTLSVersion: iacTypes.String("TLS1_2", iacTypes.NewTestMetadata()), + PublicNetworkAccess: iacTypes.BoolTest(false), NetworkRules: []storage.NetworkRule{ { Metadata: iacTypes.NewTestMetadata(), diff --git a/pkg/iac/providers/azure/storage/storage.go b/pkg/iac/providers/azure/storage/storage.go index cccc5d55eda1..ce86ec8698cc 100755 --- a/pkg/iac/providers/azure/storage/storage.go +++ b/pkg/iac/providers/azure/storage/storage.go @@ -9,13 +9,14 @@ type Storage struct { } type Account struct { - Metadata iacTypes.Metadata - NetworkRules []NetworkRule - EnforceHTTPS iacTypes.BoolValue - Containers []Container - QueueProperties QueueProperties - MinimumTLSVersion iacTypes.StringValue - Queues []Queue + Metadata iacTypes.Metadata + NetworkRules []NetworkRule + EnforceHTTPS iacTypes.BoolValue + Containers []Container + QueueProperties QueueProperties + MinimumTLSVersion iacTypes.StringValue + Queues []Queue + PublicNetworkAccess iacTypes.BoolValue } type Queue struct { diff --git a/pkg/iac/rego/schemas/cloud.json b/pkg/iac/rego/schemas/cloud.json index b034f24fa104..d0ce7ffe515a 100644 --- a/pkg/iac/rego/schemas/cloud.json +++ b/pkg/iac/rego/schemas/cloud.json @@ -5396,6 +5396,10 @@ "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.azure.storage.NetworkRule" } }, + "publicnetworkaccess": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.BoolValue" + }, "queueproperties": { "type": "object", "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.providers.azure.storage.QueueProperties" From 83e5b83acc20861b28f72a0796fc46a7325898f6 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Wed, 16 Oct 2024 10:31:20 +0600 Subject: [PATCH 136/183] docs: add note about disabled DS016 check (#7724) Signed-off-by: nikpivkin --- docs/docs/target/container_image.md | 2 ++ .../analyzer/imgconf/dockerfile/dockerfile.go | 9 ++++--- pkg/misconf/scanner.go | 25 ++++++++++++++----- 3 files changed, 27 insertions(+), 9 deletions(-) diff --git a/docs/docs/target/container_image.md b/docs/docs/target/container_image.md index 7c703980de15..f1c491071a3f 100644 --- a/docs/docs/target/container_image.md +++ b/docs/docs/target/container_image.md @@ -154,6 +154,8 @@ See https://avd.aquasec.com/misconfig/ds026 !!! tip You can see how each layer is created with `docker history`. +The [AVD-DS-0016](https://avd.aquasec.com/misconfig/dockerfile/general/avd-ds-0016/) check is disabled for this scan type, see [issue](https://github.com/aquasecurity/trivy/issues/7368) for details. + ### Secrets Trivy detects secrets on the configuration of container images. The image config is converted into JSON and Trivy scans the file for secrets. diff --git a/pkg/fanal/analyzer/imgconf/dockerfile/dockerfile.go b/pkg/fanal/analyzer/imgconf/dockerfile/dockerfile.go index c79a81f54c61..35a4fc12fea1 100644 --- a/pkg/fanal/analyzer/imgconf/dockerfile/dockerfile.go +++ b/pkg/fanal/analyzer/imgconf/dockerfile/dockerfile.go @@ -16,8 +16,11 @@ import ( "github.com/aquasecurity/trivy/pkg/misconf" ) -var disabledChecks = []string{ - "DS016", // See https://github.com/aquasecurity/trivy/issues/7368 +var disabledChecks = []misconf.DisabledCheck{ + { + ID: "DS016", Scanner: string(analyzer.TypeHistoryDockerfile), + Reason: "See https://github.com/aquasecurity/trivy/issues/7368", + }, } const analyzerVersion = 1 @@ -31,7 +34,7 @@ type historyAnalyzer struct { } func newHistoryAnalyzer(opts analyzer.ConfigAnalyzerOptions) (analyzer.ConfigAnalyzer, error) { - opts.MisconfScannerOption.DisabledCheckIDs = append(opts.MisconfScannerOption.DisabledCheckIDs, disabledChecks...) + opts.MisconfScannerOption.DisabledChecks = append(opts.MisconfScannerOption.DisabledChecks, disabledChecks...) s, err := misconf.NewScanner(detection.FileTypeDockerfile, opts.MisconfScannerOption) if err != nil { return nil, xerrors.Errorf("misconfiguration scanner error: %w", err) diff --git a/pkg/misconf/scanner.go b/pkg/misconf/scanner.go index 04fc28bc5296..7a3642dfe895 100644 --- a/pkg/misconf/scanner.go +++ b/pkg/misconf/scanner.go @@ -50,6 +50,12 @@ var enablediacTypes = map[detection.FileType]types.ConfigType{ detection.FileTypeYAML: types.YAML, } +type DisabledCheck struct { + ID string + Scanner string // For logging + Reason string // For logging +} + type ScannerOption struct { Trace bool RegoOnly bool @@ -74,9 +80,9 @@ type ScannerOption struct { FilePatterns []string ConfigFileSchemas []*ConfigFileSchema - DisabledCheckIDs []string - SkipFiles []string - SkipDirs []string + DisabledChecks []DisabledCheck + SkipFiles []string + SkipDirs []string } func (o *ScannerOption) Sort() { @@ -133,6 +139,7 @@ func NewScanner(t detection.FileType, opt ScannerOption) (*Scanner, error) { } func (s *Scanner) Scan(ctx context.Context, fsys fs.FS) ([]types.Misconfiguration, error) { + ctx = log.WithContextPrefix(ctx, log.PrefixMisconfiguration) newfs, err := s.filterFS(fsys) if err != nil { return nil, xerrors.Errorf("fs filter error: %w", err) @@ -141,12 +148,12 @@ func (s *Scanner) Scan(ctx context.Context, fsys fs.FS) ([]types.Misconfiguratio return nil, nil } - log.Debug("Scanning files for misconfigurations...", log.String("scanner", s.scanner.Name())) + log.DebugContext(ctx, "Scanning files for misconfigurations...", log.String("scanner", s.scanner.Name())) results, err := s.scanner.ScanFS(ctx, newfs, ".") if err != nil { var invalidContentError *cfparser.InvalidContentError if errors.As(err, &invalidContentError) { - log.Error("scan was broken with InvalidContentError", s.scanner.Name(), log.Err(err)) + log.ErrorContext(ctx, "scan was broken with InvalidContentError", s.scanner.Name(), log.Err(err)) return nil, nil } return nil, xerrors.Errorf("scan config error: %w", err) @@ -211,11 +218,17 @@ func (s *Scanner) filterFS(fsys fs.FS) (fs.FS, error) { } func scannerOptions(t detection.FileType, opt ScannerOption) ([]options.ScannerOption, error) { + disabledCheckIDs := lo.Map(opt.DisabledChecks, func(check DisabledCheck, _ int) string { + log.Info("Check disabled", log.Prefix(log.PrefixMisconfiguration), log.String("ID", check.ID), + log.String("scanner", check.Scanner), log.String("reason", check.Reason)) + return check.ID + }) + opts := []options.ScannerOption{ rego.WithEmbeddedPolicies(!opt.DisableEmbeddedPolicies), rego.WithEmbeddedLibraries(!opt.DisableEmbeddedLibraries), options.ScannerWithIncludeDeprecatedChecks(opt.IncludeDeprecatedChecks), - rego.WithDisabledCheckIDs(opt.DisabledCheckIDs...), + rego.WithDisabledCheckIDs(disabledCheckIDs...), } policyFS, policyPaths, err := CreatePolicyFS(opt.PolicyPaths) From bcfc37bb16c6ddb3faa439cac0cec036475f4d30 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Thu, 17 Oct 2024 03:41:59 +0400 Subject: [PATCH 137/183] test: define constants for test images (#7739) Signed-off-by: knqyf263 Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> --- .github/workflows/cache-test-images.yaml | 6 +- .github/workflows/test.yaml | 9 ++- integration/testimages.ini | 3 + internal/testutil/image.go | 67 +++++++++++++++++++ magefiles/fixture.go | 10 +-- pkg/attestation/attestation_test.go | 3 +- .../analyzer/language/java/jar/jar_test.go | 4 -- pkg/fanal/test/integration/containerd_test.go | 23 ++++--- pkg/fanal/test/integration/registry_test.go | 9 +-- 9 files changed, 104 insertions(+), 30 deletions(-) create mode 100644 integration/testimages.ini create mode 100644 internal/testutil/image.go diff --git a/.github/workflows/cache-test-images.yaml b/.github/workflows/cache-test-images.yaml index a03dc683e3ae..4b73cc2fb5bc 100644 --- a/.github/workflows/cache-test-images.yaml +++ b/.github/workflows/cache-test-images.yaml @@ -27,7 +27,8 @@ jobs: if: github.ref_name == 'main' id: image-digest run: | - IMAGE_LIST=$(skopeo list-tags docker://ghcr.io/aquasecurity/trivy-test-images) + source integration/testimages.ini + IMAGE_LIST=$(skopeo list-tags docker://$TEST_IMAGES) DIGEST=$(echo "$IMAGE_LIST" | sha256sum | cut -d' ' -f1) echo "digest=$DIGEST" >> $GITHUB_OUTPUT @@ -67,7 +68,8 @@ jobs: if: github.ref_name == 'main' id: image-digest run: | - IMAGE_LIST=$(skopeo list-tags docker://ghcr.io/aquasecurity/trivy-test-vm-images) + source integration/testimages.ini + IMAGE_LIST=$(skopeo list-tags docker://$TEST_VM_IMAGES) DIGEST=$(echo "$IMAGE_LIST" | sha256sum | cut -d' ' -f1) echo "digest=$DIGEST" >> $GITHUB_OUTPUT diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 74b0933c6ef6..8932a683c5bc 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -90,7 +90,8 @@ jobs: - name: Generate image list digest id: image-digest run: | - IMAGE_LIST=$(skopeo list-tags docker://ghcr.io/aquasecurity/trivy-test-images) + source integration/testimages.ini + IMAGE_LIST=$(skopeo list-tags docker://$TEST_IMAGES) DIGEST=$(echo "$IMAGE_LIST" | sha256sum | cut -d' ' -f1) echo "digest=$DIGEST" >> $GITHUB_OUTPUT @@ -147,7 +148,8 @@ jobs: - name: Generate image list digest id: image-digest run: | - IMAGE_LIST=$(skopeo list-tags docker://ghcr.io/aquasecurity/trivy-test-images) + source integration/testimages.ini + IMAGE_LIST=$(skopeo list-tags docker://$TEST_IMAGES) DIGEST=$(echo "$IMAGE_LIST" | sha256sum | cut -d' ' -f1) echo "digest=$DIGEST" >> $GITHUB_OUTPUT @@ -185,7 +187,8 @@ jobs: - name: Generate image list digest id: image-digest run: | - IMAGE_LIST=$(skopeo list-tags docker://ghcr.io/aquasecurity/trivy-test-vm-images) + source integration/testimages.ini + IMAGE_LIST=$(skopeo list-tags docker://$TEST_VM_IMAGES) DIGEST=$(echo "$IMAGE_LIST" | sha256sum | cut -d' ' -f1) echo "digest=$DIGEST" >> $GITHUB_OUTPUT diff --git a/integration/testimages.ini b/integration/testimages.ini new file mode 100644 index 000000000000..1a7b8ef1a0c0 --- /dev/null +++ b/integration/testimages.ini @@ -0,0 +1,3 @@ +# Configuration file for both shell scripts and Go programs +TEST_IMAGES=ghcr.io/aquasecurity/trivy-test-images +TEST_VM_IMAGES=ghcr.io/aquasecurity/trivy-test-vm-images diff --git a/internal/testutil/image.go b/internal/testutil/image.go new file mode 100644 index 000000000000..dba54bc23dff --- /dev/null +++ b/internal/testutil/image.go @@ -0,0 +1,67 @@ +package testutil + +import ( + "bufio" + "fmt" + "os" + "path/filepath" + "runtime" + "strings" +) + +var ( + testImages string + testVMImages string +) + +func init() { + _, b, _, _ := runtime.Caller(0) + currentDir := filepath.Dir(b) + f, err := os.Open(filepath.Join(currentDir, "..", "..", "integration", "testimages.ini")) + if err != nil { + panic(err) + } + defer f.Close() + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + if strings.HasPrefix(scanner.Text(), "#") { + continue + } + parts := strings.SplitN(scanner.Text(), "=", 2) + if len(parts) == 2 { + key := strings.TrimSpace(parts[0]) + value := strings.TrimSpace(parts[1]) + switch key { + case "TEST_IMAGES": + testImages = value + case "TEST_VM_IMAGES": + testVMImages = value + } + } + } + if err = scanner.Err(); err != nil { + panic(err) + } +} + +func ImageName(subpath, tag, digest string) string { + return imageName(testImages, subpath, tag, digest) +} + +func VMImageName(subpath, tag, digest string) string { + return imageName(testVMImages, subpath, tag, digest) +} + +func imageName(img, subpath, tag, digest string) string { + if subpath != "" { + img = fmt.Sprintf("%s/%s", img, subpath) + } + if tag != "" { + img = fmt.Sprintf("%s:%s", img, tag) + } + if digest != "" { + img = fmt.Sprintf("%s@%s", img, digest) + } + return img +} diff --git a/magefiles/fixture.go b/magefiles/fixture.go index 0ed9ae8d4217..0112a8421133 100644 --- a/magefiles/fixture.go +++ b/magefiles/fixture.go @@ -10,13 +10,13 @@ import ( "github.com/google/go-containerregistry/pkg/crane" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/magefile/mage/sh" + + "github.com/aquasecurity/trivy/internal/testutil" ) func fixtureContainerImages() error { - const ( - testImages = "ghcr.io/aquasecurity/trivy-test-images" - dir = "integration/testdata/fixtures/images/" - ) + var testImages = testutil.ImageName("", "", "") + const dir = "integration/testdata/fixtures/images/" if err := os.MkdirAll(dir, 0750); err != nil { return err } @@ -48,8 +48,8 @@ func fixtureContainerImages() error { } func fixtureVMImages() error { + var testVMImages = testutil.VMImageName("", "", "") const ( - testVMImages = "ghcr.io/aquasecurity/trivy-test-vm-images" titleAnnotation = "org.opencontainers.image.title" dir = "integration/testdata/fixtures/vm-images/" ) diff --git a/pkg/attestation/attestation_test.go b/pkg/attestation/attestation_test.go index 763878f4ae41..de75b5676692 100644 --- a/pkg/attestation/attestation_test.go +++ b/pkg/attestation/attestation_test.go @@ -9,6 +9,7 @@ import ( slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" "github.com/stretchr/testify/require" + "github.com/aquasecurity/trivy/internal/testutil" "github.com/aquasecurity/trivy/pkg/attestation" ) @@ -27,7 +28,7 @@ func TestStatement_UnmarshalJSON(t *testing.T) { PredicateType: "cosign.sigstore.dev/attestation/v1", Subject: []in_toto.Subject{ { - Name: "ghcr.io/aquasecurity/trivy-test-images", + Name: testutil.ImageName("", "", ""), Digest: slsa.DigestSet{ "sha256": "72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb", }, diff --git a/pkg/fanal/analyzer/language/java/jar/jar_test.go b/pkg/fanal/analyzer/language/java/jar/jar_test.go index 146b60c1bbd6..58e7221066ac 100644 --- a/pkg/fanal/analyzer/language/java/jar/jar_test.go +++ b/pkg/fanal/analyzer/language/java/jar/jar_test.go @@ -18,10 +18,6 @@ import ( _ "modernc.org/sqlite" ) -const ( - defaultJavaDBRepository = "ghcr.io/aquasecurity/trivy-java-db" -) - func Test_javaLibraryAnalyzer_Analyze(t *testing.T) { tests := []struct { name string diff --git a/pkg/fanal/test/integration/containerd_test.go b/pkg/fanal/test/integration/containerd_test.go index d16ad3dac059..568af60528ea 100644 --- a/pkg/fanal/test/integration/containerd_test.go +++ b/pkg/fanal/test/integration/containerd_test.go @@ -27,6 +27,7 @@ import ( "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/wait" + "github.com/aquasecurity/trivy/internal/testutil" "github.com/aquasecurity/trivy/pkg/cache" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" "github.com/aquasecurity/trivy/pkg/fanal/applier" @@ -77,7 +78,7 @@ func startContainerd(t *testing.T, ctx context.Context, hostPath string) { t.Setenv("TESTCONTAINERS_RYUK_DISABLED", "true") req := testcontainers.ContainerRequest{ Name: "containerd", - Image: "ghcr.io/aquasecurity/trivy-test-images/containerd:latest", + Image: testutil.ImageName("containerd", "latest", ""), Entrypoint: []string{ "/bin/sh", "-c", @@ -122,7 +123,7 @@ func TestContainerd_SearchLocalStoreByNameOrDigest(t *testing.T) { digest := "sha256:f12582b2f2190f350e3904462c1c23aaf366b4f76705e97b199f9bbded1d816a" basename := "hello" tag := "world" - importedImageOriginalName := "ghcr.io/aquasecurity/trivy-test-images:alpine-310" + importedImageOriginalName := testutil.ImageName("", "alpine-310", "") tests := []struct { name string @@ -299,15 +300,15 @@ func localImageTestWithNamespace(t *testing.T, namespace string) { }{ { name: "alpine 3.10", - imageName: "ghcr.io/aquasecurity/trivy-test-images:alpine-310", + imageName: testutil.ImageName("", "alpine-310", ""), tarArchive: "../../../../integration/testdata/fixtures/images/alpine-310.tar.gz", wantMetadata: artifact.ImageMetadata{ ID: "sha256:961769676411f082461f9ef46626dd7a2d1e2b2a38e6a44364bcbecf51e66dd4", DiffIDs: []string{ "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0", }, - RepoTags: []string{"ghcr.io/aquasecurity/trivy-test-images:alpine-310"}, - RepoDigests: []string{"ghcr.io/aquasecurity/trivy-test-images@sha256:f12582b2f2190f350e3904462c1c23aaf366b4f76705e97b199f9bbded1d816a"}, + RepoTags: []string{testutil.ImageName("", "alpine-310", "")}, + RepoDigests: []string{testutil.ImageName("", "", "sha256:f12582b2f2190f350e3904462c1c23aaf366b4f76705e97b199f9bbded1d816a")}, ConfigFile: v1.ConfigFile{ Architecture: "amd64", Created: v1.Time{ @@ -347,7 +348,7 @@ func localImageTestWithNamespace(t *testing.T, namespace string) { }, { name: "vulnimage", - imageName: "ghcr.io/aquasecurity/trivy-test-images:vulnimage", + imageName: testutil.ImageName("", "vulnimage", ""), tarArchive: "../../../../integration/testdata/fixtures/images/vulnimage.tar.gz", wantMetadata: artifact.ImageMetadata{ ID: "sha256:c17083664da903e13e9092fa3a3a1aeee2431aa2728298e3dbcec72f26369c41", @@ -373,8 +374,8 @@ func localImageTestWithNamespace(t *testing.T, namespace string) { "sha256:ba17950e91742d6ac7055ea3a053fe764486658ca1ce8188f1e427b1fe2bc4da", "sha256:6ef42db7800507577383edf1937cb203b9b85f619feed6046594208748ceb52c", }, - RepoTags: []string{"ghcr.io/aquasecurity/trivy-test-images:vulnimage"}, - RepoDigests: []string{"ghcr.io/aquasecurity/trivy-test-images@sha256:e74abbfd81e00baaf464cf9e09f8b24926e5255171e3150a60aa341ce064688f"}, + RepoTags: []string{testutil.ImageName("", "vulnimage", "")}, + RepoDigests: []string{testutil.ImageName("", "", "sha256:e74abbfd81e00baaf464cf9e09f8b24926e5255171e3150a60aa341ce064688f")}, ConfigFile: v1.ConfigFile{ Architecture: "amd64", Created: v1.Time{ @@ -750,14 +751,14 @@ func TestContainerd_PullImage(t *testing.T) { }{ { name: "remote alpine 3.10", - imageName: "ghcr.io/aquasecurity/trivy-test-images:alpine-310", + imageName: testutil.ImageName("", "alpine-310", ""), wantMetadata: artifact.ImageMetadata{ ID: "sha256:961769676411f082461f9ef46626dd7a2d1e2b2a38e6a44364bcbecf51e66dd4", DiffIDs: []string{ "sha256:03901b4a2ea88eeaad62dbe59b072b28b6efa00491962b8741081c5df50c65e0", }, - RepoTags: []string{"ghcr.io/aquasecurity/trivy-test-images:alpine-310"}, - RepoDigests: []string{"ghcr.io/aquasecurity/trivy-test-images@sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb"}, + RepoTags: []string{testutil.ImageName("", "alpine-310", "")}, + RepoDigests: []string{testutil.ImageName("", "", "sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb")}, ConfigFile: v1.ConfigFile{ Architecture: "amd64", Created: v1.Time{ diff --git a/pkg/fanal/test/integration/registry_test.go b/pkg/fanal/test/integration/registry_test.go index 5b062e425729..4bca93f0ccba 100644 --- a/pkg/fanal/test/integration/registry_test.go +++ b/pkg/fanal/test/integration/registry_test.go @@ -20,6 +20,7 @@ import ( testcontainers "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/wait" + "github.com/aquasecurity/trivy/internal/testutil" "github.com/aquasecurity/trivy/pkg/cache" "github.com/aquasecurity/trivy/pkg/fanal/analyzer" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/all" @@ -95,7 +96,7 @@ func TestTLSRegistry(t *testing.T) { }{ { name: "happy path", - imageName: "ghcr.io/aquasecurity/trivy-test-images:alpine-310", + imageName: testutil.ImageName("", "alpine-310", ""), imageFile: "../../../../integration/testdata/fixtures/images/alpine-310.tar.gz", option: types.ImageOptions{ RegistryOptions: types.RegistryOptions{ @@ -120,7 +121,7 @@ func TestTLSRegistry(t *testing.T) { }, { name: "happy path with docker login", - imageName: "ghcr.io/aquasecurity/trivy-test-images:alpine-310", + imageName: testutil.ImageName("", "alpine-310", ""), imageFile: "../../../../integration/testdata/fixtures/images/alpine-310.tar.gz", option: types.ImageOptions{ RegistryOptions: types.RegistryOptions{ @@ -140,7 +141,7 @@ func TestTLSRegistry(t *testing.T) { }, { name: "sad path: tls verify", - imageName: "ghcr.io/aquasecurity/trivy-test-images:alpine-310", + imageName: testutil.ImageName("", "alpine-310", ""), imageFile: "../../../../integration/testdata/fixtures/images/alpine-310.tar.gz", option: types.ImageOptions{ RegistryOptions: types.RegistryOptions{ @@ -156,7 +157,7 @@ func TestTLSRegistry(t *testing.T) { }, { name: "sad path: no credential", - imageName: "ghcr.io/aquasecurity/trivy-test-images:alpine-310", + imageName: testutil.ImageName("", "alpine-310", ""), imageFile: "../../../../integration/testdata/fixtures/images/alpine-310.tar.gz", option: types.ImageOptions{ RegistryOptions: types.RegistryOptions{ From 2eaa17e0717940b27a79050e2efd9213b71178c9 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Thu, 17 Oct 2024 08:29:39 +0600 Subject: [PATCH 138/183] feat(misconf): ssl_mode support for GCP SQL DB instance (#7564) Signed-off-by: nikpivkin --- pkg/iac/adapters/terraform/google/sql/adapt.go | 12 ++++-------- pkg/iac/adapters/terraform/google/sql/adapt_test.go | 2 ++ pkg/iac/providers/google/sql/sql.go | 1 + pkg/iac/rego/schemas/cloud.json | 4 ++++ 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/pkg/iac/adapters/terraform/google/sql/adapt.go b/pkg/iac/adapters/terraform/google/sql/adapt.go index 6418942384d4..6d68795bcfac 100644 --- a/pkg/iac/adapters/terraform/google/sql/adapt.go +++ b/pkg/iac/adapters/terraform/google/sql/adapt.go @@ -52,6 +52,7 @@ func adaptInstance(resource *terraform.Block) sql.DatabaseInstance { IPConfiguration: sql.IPConfiguration{ Metadata: resource.GetMetadata(), RequireTLS: iacTypes.BoolDefault(false, resource.GetMetadata()), + SSLMode: iacTypes.String("", resource.GetMetadata()), EnableIPv4: iacTypes.BoolDefault(true, resource.GetMetadata()), AuthorizedNetworks: nil, }, @@ -125,12 +126,6 @@ func adaptIPConfig(resource *terraform.Block) sql.IPConfiguration { CIDR iacTypes.StringValue } - tlsRequiredAttr := resource.GetAttribute("require_ssl") - tlsRequiredVal := tlsRequiredAttr.AsBoolValueOrDefault(false, resource) - - ipv4enabledAttr := resource.GetAttribute("ipv4_enabled") - ipv4enabledVal := ipv4enabledAttr.AsBoolValueOrDefault(true, resource) - authNetworksBlocks := resource.GetBlocks("authorized_networks") for _, authBlock := range authNetworksBlocks { nameVal := authBlock.GetAttribute("name").AsStringValueOrDefault("", authBlock) @@ -147,8 +142,9 @@ func adaptIPConfig(resource *terraform.Block) sql.IPConfiguration { return sql.IPConfiguration{ Metadata: resource.GetMetadata(), - RequireTLS: tlsRequiredVal, - EnableIPv4: ipv4enabledVal, + RequireTLS: resource.GetAttribute("require_ssl").AsBoolValueOrDefault(false, resource), + SSLMode: resource.GetAttribute("ssl_mode").AsStringValueOrDefault("", resource), + EnableIPv4: resource.GetAttribute("ipv4_enabled").AsBoolValueOrDefault(true, resource), AuthorizedNetworks: authorizedNetworks, } } diff --git a/pkg/iac/adapters/terraform/google/sql/adapt_test.go b/pkg/iac/adapters/terraform/google/sql/adapt_test.go index 29e89d6282b7..fd3207ed3547 100644 --- a/pkg/iac/adapters/terraform/google/sql/adapt_test.go +++ b/pkg/iac/adapters/terraform/google/sql/adapt_test.go @@ -34,6 +34,7 @@ func Test_Adapt(t *testing.T) { name = "internal" } require_ssl = true + ssl_mode = "TRUSTED_CLIENT_CERTIFICATE_REQUIRED" } } } @@ -67,6 +68,7 @@ func Test_Adapt(t *testing.T) { Metadata: iacTypes.NewTestMetadata(), RequireTLS: iacTypes.Bool(true, iacTypes.NewTestMetadata()), EnableIPv4: iacTypes.Bool(false, iacTypes.NewTestMetadata()), + SSLMode: iacTypes.StringTest("TRUSTED_CLIENT_CERTIFICATE_REQUIRED"), AuthorizedNetworks: []struct { Name iacTypes.StringValue CIDR iacTypes.StringValue diff --git a/pkg/iac/providers/google/sql/sql.go b/pkg/iac/providers/google/sql/sql.go index 18778dd1daef..672e78a42fbd 100755 --- a/pkg/iac/providers/google/sql/sql.go +++ b/pkg/iac/providers/google/sql/sql.go @@ -66,6 +66,7 @@ type Backups struct { type IPConfiguration struct { Metadata iacTypes.Metadata RequireTLS iacTypes.BoolValue + SSLMode iacTypes.StringValue EnableIPv4 iacTypes.BoolValue AuthorizedNetworks []struct { Name iacTypes.StringValue diff --git a/pkg/iac/rego/schemas/cloud.json b/pkg/iac/rego/schemas/cloud.json index d0ce7ffe515a..3cc6301429be 100644 --- a/pkg/iac/rego/schemas/cloud.json +++ b/pkg/iac/rego/schemas/cloud.json @@ -6991,6 +6991,10 @@ "requiretls": { "type": "object", "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.BoolValue" + }, + "sslmode": { + "type": "object", + "$ref": "#/definitions/github.com.aquasecurity.trivy.pkg.iac.types.StringValue" } } }, From 9da84f54fadbe6ad0d73983952e945ed63b666f3 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Thu, 17 Oct 2024 09:39:58 +0600 Subject: [PATCH 139/183] fix(misconf): change default ACL of digitalocean_spaces_bucket to private (#7577) Signed-off-by: nikpivkin --- pkg/iac/adapters/terraform/digitalocean/spaces/adapt.go | 2 +- pkg/iac/adapters/terraform/digitalocean/spaces/adapt_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/iac/adapters/terraform/digitalocean/spaces/adapt.go b/pkg/iac/adapters/terraform/digitalocean/spaces/adapt.go index 46d1f25fa386..a1a1c792d647 100644 --- a/pkg/iac/adapters/terraform/digitalocean/spaces/adapt.go +++ b/pkg/iac/adapters/terraform/digitalocean/spaces/adapt.go @@ -24,7 +24,7 @@ func adaptBuckets(modules terraform.Modules) []spaces.Bucket { Metadata: block.GetMetadata(), Name: block.GetAttribute("name").AsStringValueOrDefault("", block), Objects: nil, - ACL: block.GetAttribute("acl").AsStringValueOrDefault("public-read", block), + ACL: block.GetAttribute("acl").AsStringValueOrDefault("private", block), ForceDestroy: block.GetAttribute("force_destroy").AsBoolValueOrDefault(false, block), Versioning: spaces.Versioning{ Metadata: block.GetMetadata(), diff --git a/pkg/iac/adapters/terraform/digitalocean/spaces/adapt_test.go b/pkg/iac/adapters/terraform/digitalocean/spaces/adapt_test.go index cf3fc84e4ff7..e87987a3f473 100644 --- a/pkg/iac/adapters/terraform/digitalocean/spaces/adapt_test.go +++ b/pkg/iac/adapters/terraform/digitalocean/spaces/adapt_test.go @@ -69,7 +69,7 @@ func Test_adaptBuckets(t *testing.T) { Metadata: iacTypes.NewTestMetadata(), Name: iacTypes.String("", iacTypes.NewTestMetadata()), Objects: nil, - ACL: iacTypes.String("public-read", iacTypes.NewTestMetadata()), + ACL: iacTypes.String("private", iacTypes.NewTestMetadata()), ForceDestroy: iacTypes.Bool(false, iacTypes.NewTestMetadata()), Versioning: spaces.Versioning{ Metadata: iacTypes.NewTestMetadata(), From c8c14d36245623019f29d258f813d2325f7490f7 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Thu, 17 Oct 2024 09:40:14 +0600 Subject: [PATCH 140/183] fix(misconf): check if property is not nil before conversion (#7578) Signed-off-by: nikpivkin --- .../cloudformation/aws/ec2/adapt_test.go | 28 +++++++++++++++++++ .../parser/property_conversion.go | 7 +++++ 2 files changed, 35 insertions(+) diff --git a/pkg/iac/adapters/cloudformation/aws/ec2/adapt_test.go b/pkg/iac/adapters/cloudformation/aws/ec2/adapt_test.go index b218b95a4e99..c56471aa2bad 100644 --- a/pkg/iac/adapters/cloudformation/aws/ec2/adapt_test.go +++ b/pkg/iac/adapters/cloudformation/aws/ec2/adapt_test.go @@ -338,6 +338,34 @@ Resources: }, }, }, + { + name: "empty", + source: `--- +AWSTemplateFormatVersion: 2010-09-09 +Description: Godd example of excessive ports +Resources: + NetworkACL: + Type: AWS::EC2::NetworkAcl + Rule: + Type: AWS::EC2::NetworkAclEntry + Properties: + NetworkAclId: + Ref: NetworkACL`, + expected: ec2.EC2{ + NetworkACLs: []ec2.NetworkACL{ + { + Rules: []ec2.NetworkACLRule{ + { + Action: types.StringTest("allow"), + Type: types.StringTest("ingress"), + FromPort: types.IntTest(-1), + ToPort: types.IntTest(-1), + }, + }, + }, + }, + }, + }, } for _, tt := range tests { diff --git a/pkg/iac/scanners/cloudformation/parser/property_conversion.go b/pkg/iac/scanners/cloudformation/parser/property_conversion.go index 35847bb35c5b..d1ef23d396f2 100644 --- a/pkg/iac/scanners/cloudformation/parser/property_conversion.go +++ b/pkg/iac/scanners/cloudformation/parser/property_conversion.go @@ -10,6 +10,10 @@ import ( ) func (p *Property) IsConvertableTo(conversionType cftypes.CfType) bool { + if p.IsNil() { + return false + } + switch conversionType { case cftypes.Int: return p.isConvertableToInt() @@ -62,6 +66,9 @@ func (p *Property) isConvertableToInt() bool { } func (p *Property) ConvertTo(conversionType cftypes.CfType) *Property { + if p.IsNil() { + return nil + } if p.Type() == conversionType { return p From 778df828eaad9827cb833c6285058a33aa2b83ca Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Thu, 17 Oct 2024 12:54:12 +0600 Subject: [PATCH 141/183] fix(java): correctly inherit `version` and `scope` from upper/root `depManagement` and `dependencies` into parents (#7541) Signed-off-by: knqyf263 Co-authored-by: knqyf263 --- pkg/dependency/parser/java/pom/parse.go | 147 ++++---- pkg/dependency/parser/java/pom/parse_test.go | 344 ++++++++++++++++++ pkg/dependency/parser/java/pom/pom.go | 29 +- .../pom.xml | 29 ++ .../pom.xml | 64 ++++ .../parent/pom.xml | 77 ++++ .../pom.xml | 39 ++ .../example-nested-scope-compile-1.0.0.pom | 41 +++ .../1.0.0/parent/pom.xml | 21 ++ .../example-nested-scope-empty-1.0.0.pom | 40 ++ .../1.0.0/parent/pom.xml | 21 ++ .../example-nested-scope-runtime-1.0.0.pom | 41 +++ .../1.0.0/parent/pom.xml | 21 ++ .../2.0.0/example-scope-compile-2.0.0.pom | 23 ++ .../2.0.0/example-scope-empty-2.0.0.pom | 22 ++ .../2.0.0/example-scope-runtime-2.0.0.pom | 23 ++ .../testdata/transitive-parents/base/pom.xml | 2 +- .../parent/pom.xml | 34 ++ .../pom.xml | 45 +++ .../top-parent/pom.xml | 34 ++ 20 files changed, 1013 insertions(+), 84 deletions(-) create mode 100644 pkg/dependency/parser/java/pom/testdata/inherit-scopes-from-child-deps-and-their-parents/pom.xml create mode 100644 pkg/dependency/parser/java/pom/testdata/inherit-scopes-in-children-from-root/pom.xml create mode 100644 pkg/dependency/parser/java/pom/testdata/inherit-scopes-in-parents-from-root/parent/pom.xml create mode 100644 pkg/dependency/parser/java/pom/testdata/inherit-scopes-in-parents-from-root/pom.xml create mode 100644 pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-compile/1.0.0/example-nested-scope-compile-1.0.0.pom create mode 100644 pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-compile/1.0.0/parent/pom.xml create mode 100644 pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-empty/1.0.0/example-nested-scope-empty-1.0.0.pom create mode 100644 pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-empty/1.0.0/parent/pom.xml create mode 100644 pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-runtime/1.0.0/example-nested-scope-runtime-1.0.0.pom create mode 100644 pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-runtime/1.0.0/parent/pom.xml create mode 100644 pkg/dependency/parser/java/pom/testdata/repository/org/example/example-scope-compile/2.0.0/example-scope-compile-2.0.0.pom create mode 100644 pkg/dependency/parser/java/pom/testdata/repository/org/example/example-scope-empty/2.0.0/example-scope-empty-2.0.0.pom create mode 100644 pkg/dependency/parser/java/pom/testdata/repository/org/example/example-scope-runtime/2.0.0/example-scope-runtime-2.0.0.pom create mode 100644 pkg/dependency/parser/java/pom/testdata/use-child-dep-management-in-parent/parent/pom.xml create mode 100644 pkg/dependency/parser/java/pom/testdata/use-child-dep-management-in-parent/pom.xml create mode 100644 pkg/dependency/parser/java/pom/testdata/use-child-dep-management-in-parent/top-parent/pom.xml diff --git a/pkg/dependency/parser/java/pom/parse.go b/pkg/dependency/parser/java/pom/parse.go index 542abcac3c8a..2c8a194ea50b 100644 --- a/pkg/dependency/parser/java/pom/parse.go +++ b/pkg/dependency/parser/java/pom/parse.go @@ -96,7 +96,7 @@ func NewParser(filePath string, opts ...option) *Parser { } func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependency, error) { - content, err := parsePom(r) + content, err := parsePom(r, true) if err != nil { return nil, nil, xerrors.Errorf("failed to parse POM: %w", err) } @@ -107,7 +107,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc } // Analyze root POM - result, err := p.analyze(root, analysisOptions{lineNumber: true}) + result, err := p.analyze(root, analysisOptions{}) if err != nil { return nil, nil, xerrors.Errorf("analyze error (%s): %w", p.rootPath, err) } @@ -330,53 +330,27 @@ type analysisResult struct { type analysisOptions struct { exclusions map[string]struct{} depManagement []pomDependency // from the root POM - lineNumber bool // Save line numbers } func (p *Parser) analyze(pom *pom, opts analysisOptions) (analysisResult, error) { - if pom == nil || pom.content == nil { + if pom.nil() { return analysisResult{}, nil } - // Update remoteRepositories pomReleaseRemoteRepos, pomSnapshotRemoteRepos := pom.repositories(p.servers) p.releaseRemoteRepos = lo.Uniq(append(pomReleaseRemoteRepos, p.releaseRemoteRepos...)) p.snapshotRemoteRepos = lo.Uniq(append(pomSnapshotRemoteRepos, p.snapshotRemoteRepos...)) - // We need to forward dependencyManagements from current and root pom to Parent, - // to use them for dependencies in parent. - // For better understanding see the following tests: - // - `dependency from parent uses version from child pom depManagement` - // - `dependency from parent uses version from root pom depManagement` - // - // depManagements from root pom has higher priority than depManagements from current pom. - depManagementForParent := lo.UniqBy(append(opts.depManagement, pom.content.DependencyManagement.Dependencies.Dependency...), - func(dep pomDependency) string { - return dep.Name() - }) - - // Parent - parent, err := p.parseParent(pom.filePath, pom.content.Parent, depManagementForParent) - if err != nil { - return analysisResult{}, xerrors.Errorf("parent error: %w", err) + // Resolve parent POM + if err := p.resolveParent(pom); err != nil { + return analysisResult{}, xerrors.Errorf("pom resolve error: %w", err) } - // Inherit values/properties from parent - pom.inherit(parent) - - // Generate properties + // Resolve dependencies props := pom.properties() - - // dependencyManagements have the next priority: - // 1. Managed dependencies from this POM - // 2. Managed dependencies from parent of this POM - depManagement := p.mergeDependencyManagements(pom.content.DependencyManagement.Dependencies.Dependency, - parent.dependencyManagement) - - // Merge dependencies. Child dependencies must be preferred than parent dependencies. - // Parents don't have to resolve dependencies. + depManagement := pom.content.DependencyManagement.Dependencies.Dependency deps := p.parseDependencies(pom.content.Dependencies.Dependency, props, depManagement, opts) - deps = p.mergeDependencies(parent.dependencies, deps, opts.exclusions) + deps = p.filterDependencies(deps, opts.exclusions) return analysisResult{ filePath: pom.filePath, @@ -388,6 +362,39 @@ func (p *Parser) analyze(pom *pom, opts analysisOptions) (analysisResult, error) }, nil } +// resolveParent resolves its parent POMs and inherits properties, dependencies, and dependencyManagement. +func (p *Parser) resolveParent(pom *pom) error { + if pom.nil() { + return nil + } + + // Parse parent POM + parent, err := p.parseParent(pom.filePath, pom.content.Parent) + if err != nil { + return xerrors.Errorf("parent error: %w", err) + } + + // Inherit values/properties from parent + pom.inherit(parent) + + // Merge properties + pom.content.Properties = p.mergeProperties(pom.content.Properties, parent.content.Properties) + + // Merge dependencyManagement with the following priority: + // 1. Managed dependencies from this POM + // 2. Managed dependencies from parent of this POM + pom.content.DependencyManagement.Dependencies.Dependency = p.mergeDependencyManagements( + pom.content.DependencyManagement.Dependencies.Dependency, + parent.content.DependencyManagement.Dependencies.Dependency) + + // Merge dependencies + pom.content.Dependencies.Dependency = p.mergeDependencies( + pom.content.Dependencies.Dependency, + parent.content.Dependencies.Dependency) + + return nil +} + func (p *Parser) mergeDependencyManagements(depManagements ...[]pomDependency) []pomDependency { uniq := make(map[string]struct{}) var depManagement []pomDependency @@ -463,22 +470,20 @@ func (p *Parser) resolveDepManagement(props map[string]string, depManagement []p return newDepManagement } -func (p *Parser) mergeDependencies(parent, child []artifact, exclusions map[string]struct{}) []artifact { - var deps []artifact - unique := make(map[string]struct{}) +func (p *Parser) mergeProperties(child, parent properties) properties { + return lo.Assign(parent, child) +} - for _, d := range append(child, parent...) { - if excludeDep(exclusions, d) { - continue - } - if _, ok := unique[d.Name()]; ok { - continue - } - unique[d.Name()] = struct{}{} - deps = append(deps, d) - } +func (p *Parser) mergeDependencies(child, parent []pomDependency) []pomDependency { + return lo.UniqBy(append(child, parent...), func(d pomDependency) string { + return d.Name() + }) +} - return deps +func (p *Parser) filterDependencies(artifacts []artifact, exclusions map[string]struct{}) []artifact { + return lo.Filter(artifacts, func(art artifact, _ int) bool { + return !excludeDep(exclusions, art) + }) } func excludeDep(exclusions map[string]struct{}, art artifact) bool { @@ -497,38 +502,29 @@ func excludeDep(exclusions map[string]struct{}, art artifact) bool { return false } -func (p *Parser) parseParent(currentPath string, parent pomParent, rootDepManagement []pomDependency) (analysisResult, error) { +func (p *Parser) parseParent(currentPath string, parent pomParent) (*pom, error) { // Pass nil properties so that variables in are not evaluated. target := newArtifact(parent.GroupId, parent.ArtifactId, parent.Version, nil, nil) // if version is property (e.g. ${revision}) - we still need to parse this pom if target.IsEmpty() && !isProperty(parent.Version) { - return analysisResult{}, nil + return &pom{content: &pomXML{}}, nil } logger := p.logger.With("artifact", target.String()) logger.Debug("Start parent") defer logger.Debug("Exit parent") - // If the artifact is found in cache, it is returned. - if result := p.cache.get(target); result != nil { - return *result, nil - } - parentPOM, err := p.retrieveParent(currentPath, parent.RelativePath, target) if err != nil { logger.Debug("Parent POM not found", log.Err(err)) + return &pom{content: &pomXML{}}, nil } - result, err := p.analyze(parentPOM, analysisOptions{ - depManagement: rootDepManagement, - }) - if err != nil { - return analysisResult{}, xerrors.Errorf("analyze error: %w", err) + if err = p.resolveParent(parentPOM); err != nil { + return nil, xerrors.Errorf("parent pom resolve error: %w", err) } - p.cache.put(target, result) - - return result, nil + return parentPOM, nil } func (p *Parser) retrieveParent(currentPath, relativePath string, target artifact) (*pom, error) { @@ -565,7 +561,7 @@ func (p *Parser) retrieveParent(currentPath, relativePath string, target artifac } func (p *Parser) tryRelativePath(parentArtifact artifact, currentPath, relativePath string) (*pom, error) { - pom, err := p.openRelativePom(currentPath, relativePath) + parsedPOM, err := p.openRelativePom(currentPath, relativePath) if err != nil { return nil, err } @@ -576,19 +572,18 @@ func (p *Parser) tryRelativePath(parentArtifact artifact, currentPath, relativeP // But GroupID can be inherited from parent (`p.analyze` function is required to get the GroupID). // Version can contain a property (`p.analyze` function is required to get the GroupID). // So we can only match ArtifactID's. - if pom.artifact().ArtifactID != parentArtifact.ArtifactID { + if parsedPOM.artifact().ArtifactID != parentArtifact.ArtifactID { return nil, xerrors.New("'parent.relativePath' points at wrong local POM") } - result, err := p.analyze(pom, analysisOptions{}) - if err != nil { + if err := p.resolveParent(parsedPOM); err != nil { return nil, xerrors.Errorf("analyze error: %w", err) } - if !parentArtifact.Equal(result.artifact) { + if !parentArtifact.Equal(parsedPOM.artifact()) { return nil, xerrors.New("'parent.relativePath' points at wrong local POM") } - return pom, nil + return parsedPOM, nil } func (p *Parser) openRelativePom(currentPath, relativePath string) (*pom, error) { @@ -620,7 +615,7 @@ func (p *Parser) openPom(filePath string) (*pom, error) { } defer f.Close() - content, err := parsePom(f) + content, err := parsePom(f, false) if err != nil { return nil, xerrors.Errorf("failed to parse the local POM: %w", err) } @@ -777,7 +772,7 @@ func (p *Parser) fetchPOMFromRemoteRepository(repo string, paths []string) (*pom } defer resp.Body.Close() - content, err := parsePom(resp.Body) + content, err := parsePom(resp.Body, false) if err != nil { return nil, xerrors.Errorf("failed to parse the remote POM: %w", err) } @@ -788,13 +783,19 @@ func (p *Parser) fetchPOMFromRemoteRepository(repo string, paths []string) (*pom }, nil } -func parsePom(r io.Reader) (*pomXML, error) { +func parsePom(r io.Reader, lineNumber bool) (*pomXML, error) { parsed := &pomXML{} decoder := xml.NewDecoder(r) decoder.CharsetReader = charset.NewReaderLabel if err := decoder.Decode(parsed); err != nil { return nil, xerrors.Errorf("xml decode error: %w", err) } + if !lineNumber { + for i := range parsed.Dependencies.Dependency { + parsed.Dependencies.Dependency[i].StartLine = 0 + parsed.Dependencies.Dependency[i].EndLine = 0 + } + } return parsed, nil } diff --git a/pkg/dependency/parser/java/pom/parse_test.go b/pkg/dependency/parser/java/pom/parse_test.go index 82604846a4f3..7b77c0a7ef5e 100644 --- a/pkg/dependency/parser/java/pom/parse_test.go +++ b/pkg/dependency/parser/java/pom/parse_test.go @@ -14,6 +14,100 @@ import ( ftypes "github.com/aquasecurity/trivy/pkg/fanal/types" ) +var ( + exampleNestedScopeCompile = func(start, end int) ftypes.Package { + var location ftypes.Locations + if start != 0 && end != 0 { + location = append(location, ftypes.Location{ + StartLine: start, + EndLine: end, + }) + } + return ftypes.Package{ + ID: "org.example:example-nested-scope-compile:1.0.0", + Name: "org.example:example-nested-scope-compile", + Version: "1.0.0", + Relationship: ftypes.RelationshipDirect, + Locations: location, + } + } + + exampleNestedScopeEmpty = func(start, end int) ftypes.Package { + var location ftypes.Locations + if start != 0 && end != 0 { + location = append(location, ftypes.Location{ + StartLine: start, + EndLine: end, + }) + } + return ftypes.Package{ + ID: "org.example:example-nested-scope-empty:1.0.0", + Name: "org.example:example-nested-scope-empty", + Version: "1.0.0", + Relationship: ftypes.RelationshipDirect, + Locations: location, + } + } + + exampleNestedScopeRuntime = func(start, end int) ftypes.Package { + var location ftypes.Locations + if start != 0 && end != 0 { + location = append(location, ftypes.Location{ + StartLine: start, + EndLine: end, + }) + } + return ftypes.Package{ + ID: "org.example:example-nested-scope-runtime:1.0.0", + Name: "org.example:example-nested-scope-runtime", + Version: "1.0.0", + Relationship: ftypes.RelationshipDirect, + Locations: location, + } + } + + exampleScopeCompile = ftypes.Package{ + ID: "org.example:example-scope-compile:2.0.0", + Name: "org.example:example-scope-compile", + Version: "2.0.0", + Relationship: ftypes.RelationshipIndirect, + } + + exampleScopeEmpty = ftypes.Package{ + ID: "org.example:example-scope-empty:2.0.0", + Name: "org.example:example-scope-empty", + Version: "2.0.0", + Relationship: ftypes.RelationshipIndirect, + } + + exampleScopeRuntime = ftypes.Package{ + ID: "org.example:example-scope-runtime:2.0.0", + Name: "org.example:example-scope-runtime", + Version: "2.0.0", + Relationship: ftypes.RelationshipIndirect, + } + exampleApiCompile = ftypes.Package{ + ID: "org.example:example-api-compile:3.0.0", + Name: "org.example:example-api-compile", + Version: "3.0.0", + Relationship: ftypes.RelationshipIndirect, + } + + exampleApiEmpty = ftypes.Package{ + ID: "org.example:example-api-empty:3.0.0", + Name: "org.example:example-api-empty", + Version: "3.0.0", + Relationship: ftypes.RelationshipIndirect, + } + + exampleApiRuntime = ftypes.Package{ + ID: "org.example:example-api-runtime:3.0.0", + Name: "org.example:example-api-runtime", + Version: "3.0.0", + Relationship: ftypes.RelationshipIndirect, + } +) + func TestPom_Parse(t *testing.T) { tests := []struct { name string @@ -1630,6 +1724,256 @@ func TestPom_Parse(t *testing.T) { }, }, }, + // [INFO] com.example:child-depManagement-in-parent:jar:1.0.0 + // [INFO] +- org.example:example-api2:jar:1.0.2:runtime + // [INFO] +- org.example:example-api3:jar:4.0.3:compile + // [INFO] \- org.example:example-api:jar:1.0.1:compile + { + name: "dependency from parent uses version from child(scanned) pom depManagement", + inputFile: filepath.Join("testdata", "use-child-dep-management-in-parent", "pom.xml"), + local: true, + want: []ftypes.Package{ + { + ID: "com.example:child-depManagement-in-parent:1.0.0", + Name: "com.example:child-depManagement-in-parent", + Version: "1.0.0", + Relationship: ftypes.RelationshipRoot, + }, + { + ID: "org.example:example-api:1.0.1", + Name: "org.example:example-api", + Version: "1.0.1", + Relationship: ftypes.RelationshipDirect, + }, + { + ID: "org.example:example-api2:1.0.2", + Name: "org.example:example-api2", + Version: "1.0.2", + Relationship: ftypes.RelationshipDirect, + }, + { + ID: "org.example:example-api3:4.0.3", + Name: "org.example:example-api3", + Version: "4.0.3", + Relationship: ftypes.RelationshipDirect, + }, + }, + wantDeps: []ftypes.Dependency{ + { + ID: "com.example:child-depManagement-in-parent:1.0.0", + DependsOn: []string{ + "org.example:example-api2:1.0.2", + "org.example:example-api3:4.0.3", + "org.example:example-api:1.0.1", + }, + }, + }, + }, + // [INFO] com.example:inherit-scopes-from-child-deps-and-their-parents:jar:0.0.1 + // [INFO] +- org.example:example-nested-scope-runtime:jar:1.0.0:runtime + // [INFO] | \- org.example:example-scope-runtime:jar:2.0.0:runtime + // [INFO] | \- org.example:example-api-runtime:jar:3.0.0:runtime + // [INFO] +- org.example:example-nested-scope-compile:jar:1.0.0:compile + // [INFO] | \- org.example:example-scope-compile:jar:2.0.0:compile + // [INFO] | \- org.example:example-api-compile:jar:3.0.0:compile + // [INFO] \- org.example:example-nested-scope-empty:jar:1.0.0:compile + // [INFO] \- org.example:example-scope-empty:jar:2.0.0:compile + // [INFO] \- org.example:example-api-empty:jar:3.0.0:compile + // + // `example-nested-*" dependencies and their parents contain `dependencyManagement` with changed scopes + { + name: "inherit scopes from child dependencies and their parents", + inputFile: filepath.Join("testdata", "inherit-scopes-from-child-deps-and-their-parents", "pom.xml"), + local: true, + want: []ftypes.Package{ + { + ID: "com.example:inherit-scopes-from-child-deps-and-their-parents:0.0.1", + Name: "com.example:inherit-scopes-from-child-deps-and-their-parents", + Version: "0.0.1", + Relationship: ftypes.RelationshipRoot, + }, + exampleNestedScopeCompile(16, 21), + exampleNestedScopeEmpty(22, 26), + exampleNestedScopeRuntime(10, 15), + exampleApiCompile, + exampleApiEmpty, + exampleApiRuntime, + exampleScopeCompile, + exampleScopeEmpty, + exampleScopeRuntime, + }, + wantDeps: []ftypes.Dependency{ + { + ID: "com.example:inherit-scopes-from-child-deps-and-their-parents:0.0.1", + DependsOn: []string{ + "org.example:example-nested-scope-compile:1.0.0", + "org.example:example-nested-scope-empty:1.0.0", + "org.example:example-nested-scope-runtime:1.0.0", + }, + }, + { + ID: "org.example:example-nested-scope-compile:1.0.0", + DependsOn: []string{ + "org.example:example-scope-compile:2.0.0", + }, + }, + { + ID: "org.example:example-nested-scope-empty:1.0.0", + DependsOn: []string{ + "org.example:example-scope-empty:2.0.0", + }, + }, + { + ID: "org.example:example-nested-scope-runtime:1.0.0", + DependsOn: []string{ + "org.example:example-scope-runtime:2.0.0", + }, + }, + { + ID: "org.example:example-scope-compile:2.0.0", + DependsOn: []string{ + "org.example:example-api-compile:3.0.0", + }, + }, + { + ID: "org.example:example-scope-empty:2.0.0", + DependsOn: []string{ + "org.example:example-api-empty:3.0.0", + }, + }, + { + ID: "org.example:example-scope-runtime:2.0.0", + DependsOn: []string{ + "org.example:example-api-runtime:3.0.0", + }, + }, + }, + }, + // [INFO] com.example:inherit-scopes-in-parents-from-root:jar:0.1.0 + // [INFO] +- org.example:example-nested-scope-runtime:jar:1.0.0:runtime + // [INFO] | \- org.example:example-scope-runtime:jar:2.0.0:compile + // [INFO] | \- org.example:example-api-runtime:jar:3.0.0:runtime + // [INFO] +- org.example:example-nested-scope-compile:jar:1.0.0:compile + // [INFO] | \- org.example:example-scope-compile:jar:2.0.0:runtime + // [INFO] | \- org.example:example-api-compile:jar:3.0.0:test + // [INFO] \- org.example:example-nested-scope-empty:jar:1.0.0:compile + // [INFO] \- org.example:example-scope-empty:jar:2.0.0:runtime + // [INFO] \- org.example:example-api-empty:jar:3.0.0:test + // + // `example-nested-*" dependencies and their parents contain `dependencyManagement` with changed scopes + // scopes from `dependencyManagement` of root pom are used + { + name: "inherit scopes in children from root pom", + inputFile: filepath.Join("testdata", "inherit-scopes-in-children-from-root", "pom.xml"), + local: true, + want: []ftypes.Package{ + { + ID: "com.example:inherit-scopes-in-children-from-root:0.0.1", + Name: "com.example:inherit-scopes-in-children-from-root", + Version: "0.0.1", + Relationship: ftypes.RelationshipRoot, + }, + exampleNestedScopeCompile(51, 56), + exampleNestedScopeEmpty(57, 61), + exampleNestedScopeRuntime(45, 50), + exampleApiRuntime, + exampleScopeCompile, + exampleScopeEmpty, + exampleScopeRuntime, + }, + wantDeps: []ftypes.Dependency{ + { + ID: "com.example:inherit-scopes-in-children-from-root:0.0.1", + DependsOn: []string{ + "org.example:example-nested-scope-compile:1.0.0", + "org.example:example-nested-scope-empty:1.0.0", + "org.example:example-nested-scope-runtime:1.0.0", + }, + }, + { + ID: "org.example:example-nested-scope-compile:1.0.0", + DependsOn: []string{ + "org.example:example-scope-compile:2.0.0", + }, + }, + { + ID: "org.example:example-nested-scope-empty:1.0.0", + DependsOn: []string{ + "org.example:example-scope-empty:2.0.0", + }, + }, + { + ID: "org.example:example-nested-scope-runtime:1.0.0", + DependsOn: []string{ + "org.example:example-scope-runtime:2.0.0", + }, + }, + { + ID: "org.example:example-scope-runtime:2.0.0", + DependsOn: []string{ + "org.example:example-api-runtime:3.0.0", + }, + }, + }, + }, + // [INFO] com.example:inherit-scopes-in-parents-from-root:jar:0.1.0 + // [INFO] +- org.example:example-nested-scope-runtime:jar:1.0.0:runtime + // [INFO] | \- org.example:example-scope-runtime:jar:2.0.0:compile + // [INFO] | \- org.example:example-api-runtime:jar:3.0.0:runtime + // [INFO] +- org.example:example-nested-scope-compile:jar:1.0.0:compile + // [INFO] | \- org.example:example-scope-compile:jar:2.0.0:runtime + // [INFO] | \- org.example:example-api-compile:jar:3.0.0:test + // [INFO] \- org.example:example-nested-scope-empty:jar:1.0.0:test + // [INFO] \- org.example:example-scope-empty:jar:2.0.0:test + // [INFO] \- org.example:example-api-empty:jar:3.0.0:test + // + // `example-nested-*" dependencies and their parents contain `dependencyManagement` with changed scopes + // scopes from `dependencyManagement` of root pom are used in parent dependencies + { + name: "inherit scopes in parent from root pom", + inputFile: filepath.Join("testdata", "inherit-scopes-in-parents-from-root", "pom.xml"), + local: true, + want: []ftypes.Package{ + { + ID: "com.example:inherit-scopes-in-parents-from-root:0.1.0", + Name: "com.example:inherit-scopes-in-parents-from-root", + Version: "0.1.0", + Relationship: ftypes.RelationshipRoot, + }, + exampleNestedScopeCompile(0, 0), + exampleNestedScopeRuntime(0, 0), + exampleApiRuntime, + exampleScopeCompile, + exampleScopeRuntime, + }, + wantDeps: []ftypes.Dependency{ + { + ID: "com.example:inherit-scopes-in-parents-from-root:0.1.0", + DependsOn: []string{ + "org.example:example-nested-scope-compile:1.0.0", + "org.example:example-nested-scope-runtime:1.0.0", + }, + }, + { + ID: "org.example:example-nested-scope-compile:1.0.0", + DependsOn: []string{ + "org.example:example-scope-compile:2.0.0", + }, + }, + { + ID: "org.example:example-nested-scope-runtime:1.0.0", + DependsOn: []string{ + "org.example:example-scope-runtime:2.0.0", + }, + }, + { + ID: "org.example:example-scope-runtime:2.0.0", + DependsOn: []string{ + "org.example:example-api-runtime:3.0.0", + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/dependency/parser/java/pom/pom.go b/pkg/dependency/parser/java/pom/pom.go index 889d107c3c6c..83c5d4fec609 100644 --- a/pkg/dependency/parser/java/pom/pom.go +++ b/pkg/dependency/parser/java/pom/pom.go @@ -23,11 +23,18 @@ type pom struct { content *pomXML } -func (p *pom) inherit(result analysisResult) { +func (p *pom) nil() bool { + return p == nil || p.content == nil +} + +func (p *pom) inherit(parent *pom) { + if parent == nil { + return + } // Merge properties - p.content.Properties = utils.MergeMaps(result.properties, p.content.Properties) + p.content.Properties = utils.MergeMaps(parent.properties(), p.content.Properties) - art := p.artifact().Inherit(result.artifact) + art := p.artifact().Inherit(parent.artifact()) p.content.GroupId = art.GroupID p.content.ArtifactId = art.ArtifactID @@ -40,12 +47,12 @@ func (p *pom) inherit(result analysisResult) { } } -func (p pom) properties() properties { +func (p *pom) properties() properties { props := p.content.Properties return utils.MergeMaps(props, p.projectProperties()) } -func (p pom) projectProperties() map[string]string { +func (p *pom) projectProperties() map[string]string { val := reflect.ValueOf(p.content).Elem() props := p.listProperties(val) @@ -73,7 +80,7 @@ func (p pom) projectProperties() map[string]string { return projectProperties } -func (p pom) listProperties(val reflect.Value) map[string]string { +func (p *pom) listProperties(val reflect.Value) map[string]string { props := make(map[string]string) for i := 0; i < val.NumField(); i++ { f := val.Type().Field(i) @@ -106,17 +113,17 @@ func (p pom) listProperties(val reflect.Value) map[string]string { return props } -func (p pom) artifact() artifact { +func (p *pom) artifact() artifact { return newArtifact(p.content.GroupId, p.content.ArtifactId, p.content.Version, p.licenses(), p.content.Properties) } -func (p pom) licenses() []string { +func (p *pom) licenses() []string { return slices.ZeroToNil(lo.FilterMap(p.content.Licenses.License, func(lic pomLicense, _ int) (string, bool) { return lic.Name, lic.Name != "" })) } -func (p pom) repositories(servers []Server) ([]string, []string) { +func (p *pom) repositories(servers []Server) ([]string, []string) { logger := log.WithPrefix("pom") var releaseRepos, snapshotRepos []string for _, rep := range p.content.Repositories.Repository { @@ -242,9 +249,11 @@ func (d pomDependency) Resolve(props map[string]string, depManagement, rootDepMa if managed.Version != "" { dep.Version = evaluateVariable(managed.Version, props, nil) } + if managed.Scope != "" { dep.Scope = evaluateVariable(managed.Scope, props, nil) } + if managed.Optional { dep.Optional = managed.Optional } @@ -287,7 +296,7 @@ func (d pomDependency) ToArtifact(opts analysisOptions) artifact { } var locations ftypes.Locations - if opts.lineNumber { + if d.StartLine != 0 && d.EndLine != 0 { locations = ftypes.Locations{ { StartLine: d.StartLine, diff --git a/pkg/dependency/parser/java/pom/testdata/inherit-scopes-from-child-deps-and-their-parents/pom.xml b/pkg/dependency/parser/java/pom/testdata/inherit-scopes-from-child-deps-and-their-parents/pom.xml new file mode 100644 index 000000000000..17e6c55de090 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/inherit-scopes-from-child-deps-and-their-parents/pom.xml @@ -0,0 +1,29 @@ + + 4.0.0 + + com.example + inherit-scopes-from-child-deps-and-their-parents + 0.0.1 + + + + org.example + example-nested-scope-runtime + 1.0.0 + runtime + + + org.example + example-nested-scope-compile + 1.0.0 + compile + + + org.example + example-nested-scope-empty + 1.0.0 + + + + diff --git a/pkg/dependency/parser/java/pom/testdata/inherit-scopes-in-children-from-root/pom.xml b/pkg/dependency/parser/java/pom/testdata/inherit-scopes-in-children-from-root/pom.xml new file mode 100644 index 000000000000..26bdb25621d7 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/inherit-scopes-in-children-from-root/pom.xml @@ -0,0 +1,64 @@ + + 4.0.0 + + com.example + inherit-scopes-in-children-from-root + 0.0.1 + + + + + org.example + example-scope-runtime + 2.0.0 + compile + + + org.example + example-scope-compile + 2.0.0 + runtime + + + org.example + example-api-compile + 3.0.0 + test + + + org.example + example-scope-empty + 2.0.0 + runtime + + + org.example + example-api-empty + 3.0.0 + test + + + + + + + org.example + example-nested-scope-runtime + 1.0.0 + runtime + + + org.example + example-nested-scope-compile + 1.0.0 + compile + + + org.example + example-nested-scope-empty + 1.0.0 + + + + diff --git a/pkg/dependency/parser/java/pom/testdata/inherit-scopes-in-parents-from-root/parent/pom.xml b/pkg/dependency/parser/java/pom/testdata/inherit-scopes-in-parents-from-root/parent/pom.xml new file mode 100644 index 000000000000..dad0101e3f25 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/inherit-scopes-in-parents-from-root/parent/pom.xml @@ -0,0 +1,77 @@ + + 4.0.0 + + com.example + inherit-scopes-in-parents-from-root-parent + 0.0.1 + pom + + + + + org.example + example-scope-runtime + 2.0.0 + compile + + + org.example + example-scope-compile + 2.0.0 + runtime + + + org.example + example-api-compile + 3.0.0 + test + + + org.example + example-scope-empty + 2.0.0 + test + + + org.example + example-api-empty + 3.0.0 + test + + + org.example + example-nested-scope-compile + 1.0.0 + runtime + + + org.example + example-nested-scope-empty + 1.0.0 + compile + + + + + + + org.example + example-nested-scope-runtime + 1.0.0 + runtime + + + org.example + example-nested-scope-compile + 1.0.0 + compile + + + org.example + example-nested-scope-empty + 1.0.0 + + + + diff --git a/pkg/dependency/parser/java/pom/testdata/inherit-scopes-in-parents-from-root/pom.xml b/pkg/dependency/parser/java/pom/testdata/inherit-scopes-in-parents-from-root/pom.xml new file mode 100644 index 000000000000..45ef37785e60 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/inherit-scopes-in-parents-from-root/pom.xml @@ -0,0 +1,39 @@ + + 4.0.0 + + com.example + inherit-scopes-in-parents-from-root + 0.1.0 + + + com.example + inherit-scopes-in-parents-from-root-parent + 0.0.1 + ./parent + + + + + + org.example + example-nested-scope-runtime + 1.0.0 + test + + + org.example + example-nested-scope-compile + 1.0.0 + test + + + org.example + example-nested-scope-empty + 1.0.0 + test + + + + + diff --git a/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-compile/1.0.0/example-nested-scope-compile-1.0.0.pom b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-compile/1.0.0/example-nested-scope-compile-1.0.0.pom new file mode 100644 index 000000000000..43ca478a88cd --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-compile/1.0.0/example-nested-scope-compile-1.0.0.pom @@ -0,0 +1,41 @@ + + + + 4.0.0 + + + com.example + example-nested-parent-scope-compile + 1.0.1 + ./parent + + + org.example + example-nested-scope-compile + 1.0.0 + + jar + Example pom with example-scope-compile 2.0.0 + + + + + org.example + example-api-compile + 3.0.0 + runtime + + + + + + + org.example + example-scope-compile + 2.0.0 + compile + + + \ No newline at end of file diff --git a/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-compile/1.0.0/parent/pom.xml b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-compile/1.0.0/parent/pom.xml new file mode 100644 index 000000000000..5fe41b350df1 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-compile/1.0.0/parent/pom.xml @@ -0,0 +1,21 @@ + + 4.0.0 + + com.example + example-nested-parent-scope-compile + 1.0.1 + pom + + + + + org.example + example-scope-compile + 2.0.0 + test + + + + + diff --git a/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-empty/1.0.0/example-nested-scope-empty-1.0.0.pom b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-empty/1.0.0/example-nested-scope-empty-1.0.0.pom new file mode 100644 index 000000000000..b1def2383f79 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-empty/1.0.0/example-nested-scope-empty-1.0.0.pom @@ -0,0 +1,40 @@ + + + + 4.0.0 + + + com.example + example-nested-parent-scope-empty + 1.0.1 + ./parent + + + org.example + example-nested-scope-empty + 1.0.0 + + jar + Example pom with example-scope-empty 2.0.0 + + + + + org.example + example-api-empty + 3.0.0 + test + + + + + + + org.example + example-scope-empty + 2.0.0 + + + \ No newline at end of file diff --git a/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-empty/1.0.0/parent/pom.xml b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-empty/1.0.0/parent/pom.xml new file mode 100644 index 000000000000..6ca0232f4fc3 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-empty/1.0.0/parent/pom.xml @@ -0,0 +1,21 @@ + + 4.0.0 + + com.example + example-nested-parent-scope-empty + 1.0.1 + pom + + + + + org.example + example-scope-empty + 2.0.0 + compile + + + + + diff --git a/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-runtime/1.0.0/example-nested-scope-runtime-1.0.0.pom b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-runtime/1.0.0/example-nested-scope-runtime-1.0.0.pom new file mode 100644 index 000000000000..8e48dcd812c3 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-runtime/1.0.0/example-nested-scope-runtime-1.0.0.pom @@ -0,0 +1,41 @@ + + + + 4.0.0 + + + com.example + example-nested-parent-scope-runtime + 1.0.1 + ./parent + + + org.example + example-nested-scope-runtime + 1.0.0 + + jar + Example pom with example-scope-runtime 2.0.0 + + + + + org.example + example-api-runtime + 3.0.0 + test + + + + + + + org.example + example-scope-runtime + 2.0.0 + runtime + + + \ No newline at end of file diff --git a/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-runtime/1.0.0/parent/pom.xml b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-runtime/1.0.0/parent/pom.xml new file mode 100644 index 000000000000..f59df7902390 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-nested-scope-runtime/1.0.0/parent/pom.xml @@ -0,0 +1,21 @@ + + 4.0.0 + + com.example + example-nested-parent-scope-runtime + 1.0.1 + pom + + + + + org.example + example-scope-runtime + 2.0.0 + test + + + + + diff --git a/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-scope-compile/2.0.0/example-scope-compile-2.0.0.pom b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-scope-compile/2.0.0/example-scope-compile-2.0.0.pom new file mode 100644 index 000000000000..1d5bc02ff3b9 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-scope-compile/2.0.0/example-scope-compile-2.0.0.pom @@ -0,0 +1,23 @@ + + + + 4.0.0 + + org.example + example-scope-compile + 2.0.0 + + jar + Example pom with example-api-compile 3.0.0 + + + + org.example + example-api-compile + 3.0.0 + compile + + + \ No newline at end of file diff --git a/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-scope-empty/2.0.0/example-scope-empty-2.0.0.pom b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-scope-empty/2.0.0/example-scope-empty-2.0.0.pom new file mode 100644 index 000000000000..82ce31008fc3 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-scope-empty/2.0.0/example-scope-empty-2.0.0.pom @@ -0,0 +1,22 @@ + + + + 4.0.0 + + org.example + example-scope-empty + 2.0.0 + + jar + Example pom with example-api-empty 3.0.0 + + + + org.example + example-api-empty + 3.0.0 + + + \ No newline at end of file diff --git a/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-scope-runtime/2.0.0/example-scope-runtime-2.0.0.pom b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-scope-runtime/2.0.0/example-scope-runtime-2.0.0.pom new file mode 100644 index 000000000000..90bf973def80 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/repository/org/example/example-scope-runtime/2.0.0/example-scope-runtime-2.0.0.pom @@ -0,0 +1,23 @@ + + + + 4.0.0 + + org.example + example-scope-runtime + 2.0.0 + + jar + Example pom with example-api-runtime 3.0.0 + + + + org.example + example-api-runtime + 3.0.0 + runtime + + + \ No newline at end of file diff --git a/pkg/dependency/parser/java/pom/testdata/transitive-parents/base/pom.xml b/pkg/dependency/parser/java/pom/testdata/transitive-parents/base/pom.xml index 5662c0c9e8de..ae1d6ced6e3f 100644 --- a/pkg/dependency/parser/java/pom/testdata/transitive-parents/base/pom.xml +++ b/pkg/dependency/parser/java/pom/testdata/transitive-parents/base/pom.xml @@ -13,7 +13,7 @@ com.example parent 3.0.0 - ../parent + ../ diff --git a/pkg/dependency/parser/java/pom/testdata/use-child-dep-management-in-parent/parent/pom.xml b/pkg/dependency/parser/java/pom/testdata/use-child-dep-management-in-parent/parent/pom.xml new file mode 100644 index 000000000000..dec887e6eecc --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/use-child-dep-management-in-parent/parent/pom.xml @@ -0,0 +1,34 @@ + + + + 4.0.0 + + + org.example + example-top-parent + 5.0.0 + ../top-parent/pom.xml + + + org.example + example-parent + 4.0.0 + pom + + + 4.0.1 + + + + org.example + example-api2 + + + org.example + example-api3 + 4.0.3 + compile + + + \ No newline at end of file diff --git a/pkg/dependency/parser/java/pom/testdata/use-child-dep-management-in-parent/pom.xml b/pkg/dependency/parser/java/pom/testdata/use-child-dep-management-in-parent/pom.xml new file mode 100644 index 000000000000..651fbba9f885 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/use-child-dep-management-in-parent/pom.xml @@ -0,0 +1,45 @@ + + 4.0.0 + + + org.example + example-parent + 4.0.0 + ./parent/pom.xml + + + com.example + child-depManagement-in-parent + 1.0.0 + + + + 1.0.1 + 1.0.2 + 1.0.3 + + + + + + org.example + example-api + ${api.version} + runtime + + + org.example + example-api2 + ${api2.version} + runtime + + + org.example + example-api3 + ${api3.version} + runtime + + + + diff --git a/pkg/dependency/parser/java/pom/testdata/use-child-dep-management-in-parent/top-parent/pom.xml b/pkg/dependency/parser/java/pom/testdata/use-child-dep-management-in-parent/top-parent/pom.xml new file mode 100644 index 000000000000..84d8954a4bf9 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/use-child-dep-management-in-parent/top-parent/pom.xml @@ -0,0 +1,34 @@ + + + + 4.0.0 + + org.example + example-top-parent + 5.0.0 + pom + + + 5.0.1 + + + + + org.example + example-api + ${api.version} + compile + + + org.example + example-api2 + + + org.example + example-api3 + 5.0.3 + compile + + + \ No newline at end of file From 922949a43ea21b10858962330ef8d8297ff40b0a Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Thu, 17 Oct 2024 12:12:44 +0400 Subject: [PATCH 142/183] test: use forked images (#7755) Signed-off-by: knqyf263 --- integration/testimages.ini | 4 ++-- pkg/attestation/attestation_test.go | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/integration/testimages.ini b/integration/testimages.ini index 1a7b8ef1a0c0..778fbc9b8e63 100644 --- a/integration/testimages.ini +++ b/integration/testimages.ini @@ -1,3 +1,3 @@ # Configuration file for both shell scripts and Go programs -TEST_IMAGES=ghcr.io/aquasecurity/trivy-test-images -TEST_VM_IMAGES=ghcr.io/aquasecurity/trivy-test-vm-images +TEST_IMAGES=ghcr.io/knqyf263/trivy-test-images +TEST_VM_IMAGES=ghcr.io/knqyf263/trivy-test-vm-images diff --git a/pkg/attestation/attestation_test.go b/pkg/attestation/attestation_test.go index de75b5676692..0233ba30cf78 100644 --- a/pkg/attestation/attestation_test.go +++ b/pkg/attestation/attestation_test.go @@ -9,7 +9,6 @@ import ( slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/internal/testutil" "github.com/aquasecurity/trivy/pkg/attestation" ) @@ -28,7 +27,7 @@ func TestStatement_UnmarshalJSON(t *testing.T) { PredicateType: "cosign.sigstore.dev/attestation/v1", Subject: []in_toto.Subject{ { - Name: testutil.ImageName("", "", ""), + Name: "ghcr.io/aquasecurity/trivy-test-images", // Defined in the attestations.json file Digest: slsa.DigestSet{ "sha256": "72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb", }, From a7baa93b00b8636aa097e64cdb8eed97dbd68511 Mon Sep 17 00:00:00 2001 From: Samuel Gaist Date: Thu, 17 Oct 2024 11:35:09 +0200 Subject: [PATCH 143/183] feat(parser): ignore white space in pom.xml files (#7747) Signed-off-by: Samuel Gaist --- pkg/dependency/parser/java/pom/artifact.go | 2 +- pkg/dependency/parser/java/pom/parse_test.go | 64 +++++++++++++++++++ .../java/pom/testdata/with-spaces/pom.xml | 31 +++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 pkg/dependency/parser/java/pom/testdata/with-spaces/pom.xml diff --git a/pkg/dependency/parser/java/pom/artifact.go b/pkg/dependency/parser/java/pom/artifact.go index 73ebe6b21407..8fc20b236b51 100644 --- a/pkg/dependency/parser/java/pom/artifact.go +++ b/pkg/dependency/parser/java/pom/artifact.go @@ -163,7 +163,7 @@ func evaluateVariable(s string, props map[string]string, seenProps []string) str } s = strings.ReplaceAll(s, m[0], newValue) } - return s + return strings.TrimSpace(s) } func printLoopedPropertiesStack(env string, usedProps []string) { diff --git a/pkg/dependency/parser/java/pom/parse_test.go b/pkg/dependency/parser/java/pom/parse_test.go index 7b77c0a7ef5e..8d0bf002d6dc 100644 --- a/pkg/dependency/parser/java/pom/parse_test.go +++ b/pkg/dependency/parser/java/pom/parse_test.go @@ -1974,6 +1974,70 @@ func TestPom_Parse(t *testing.T) { }, }, }, + //[INFO] com.example:root-pom-with-spaces:jar:1.0.0 + //[INFO] \- org.example:example-nested:jar:3.3.3:compile + //[INFO] \- org.example:example-dependency:jar:1.2.4:compile + //[INFO] \- org.example:example-api:jar:2.0.0:compile + { + name: "space at the start and/or end of the text nodes", + inputFile: filepath.Join("testdata", "with-spaces", "pom.xml"), + local: true, + want: []ftypes.Package{ + { + ID: "com.example:root-pom-with-spaces:1.0.0", + Name: "com.example:root-pom-with-spaces", + Version: "1.0.0", + Relationship: ftypes.RelationshipRoot, + }, + { + ID: "org.example:example-nested:3.3.3", + Name: "org.example:example-nested", + Version: "3.3.3", + Relationship: ftypes.RelationshipDirect, + Locations: ftypes.Locations{ + { + StartLine: 24, + EndLine: 28, + }, + }, + }, + { + ID: "org.example:example-api:2.0.0", + Name: "org.example:example-api", + Version: "2.0.0", + Licenses: []string{"The Apache Software License, Version 2.0"}, + Relationship: ftypes.RelationshipIndirect, + }, + // dependency version is taken from `com.example:root-pom-with-spaces` from dependencyManagement + // not from `com.example:example-nested` from `com.example:example-nested` + { + ID: "org.example:example-dependency:1.2.4", + Name: "org.example:example-dependency", + Version: "1.2.4", + Relationship: ftypes.RelationshipIndirect, + }, + }, + wantDeps: []ftypes.Dependency{ + { + ID: "com.example:root-pom-with-spaces:1.0.0", + DependsOn: []string{ + "org.example:example-nested:3.3.3", + }, + }, + { + ID: "org.example:example-dependency:1.2.4", + DependsOn: []string{ + "org.example:example-api:2.0.0", + }, + }, + { + ID: "org.example:example-nested:3.3.3", + DependsOn: []string{ + "org.example:example-dependency:1.2.4", + }, + }, + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { diff --git a/pkg/dependency/parser/java/pom/testdata/with-spaces/pom.xml b/pkg/dependency/parser/java/pom/testdata/with-spaces/pom.xml new file mode 100644 index 000000000000..7a0a1013aa31 --- /dev/null +++ b/pkg/dependency/parser/java/pom/testdata/with-spaces/pom.xml @@ -0,0 +1,31 @@ + + 4.0.0 + + com.example + root-pom-with-spaces + 1.0.0 + + + 1.2.4 + + + + + + org.example + example-dependency + ${dependency.version} + + + + + + + org.example + example-nested + 3.3.3 + + + + From cd44bb48f8ff3cca20bb9b4c6ab3dce1907fc528 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 18 Oct 2024 03:50:12 +0600 Subject: [PATCH 144/183] refactor(misconf): simplify k8s scanner (#7717) Signed-off-by: nikpivkin --- pkg/iac/scanners/helm/scanner.go | 2 +- pkg/iac/scanners/kubernetes/parser/parser.go | 57 +- pkg/iac/scanners/kubernetes/scanner.go | 112 +--- pkg/iac/scanners/kubernetes/scanner_test.go | 666 ++++--------------- 4 files changed, 132 insertions(+), 705 deletions(-) diff --git a/pkg/iac/scanners/helm/scanner.go b/pkg/iac/scanners/helm/scanner.go index bfa63a5d2c00..daf8f3108628 100644 --- a/pkg/iac/scanners/helm/scanner.go +++ b/pkg/iac/scanners/helm/scanner.go @@ -130,7 +130,7 @@ func (s *Scanner) getScanResults(path string, ctx context.Context, target fs.FS) file := file s.logger.Debug("Processing rendered chart file", log.FilePath(file.TemplateFilePath)) - manifests, err := kparser.New().Parse(strings.NewReader(file.ManifestContent), file.TemplateFilePath) + manifests, err := kparser.Parse(ctx, strings.NewReader(file.ManifestContent), file.TemplateFilePath) if err != nil { return nil, fmt.Errorf("unmarshal yaml: %w", err) } diff --git a/pkg/iac/scanners/kubernetes/parser/parser.go b/pkg/iac/scanners/kubernetes/parser/parser.go index f3ca7d613562..57d723801c98 100644 --- a/pkg/iac/scanners/kubernetes/parser/parser.go +++ b/pkg/iac/scanners/kubernetes/parser/parser.go @@ -5,69 +5,14 @@ import ( "encoding/json" "fmt" "io" - "io/fs" - "path/filepath" "regexp" "strings" "gopkg.in/yaml.v3" kyaml "sigs.k8s.io/yaml" - - "github.com/aquasecurity/trivy/pkg/log" ) -type Parser struct { - logger *log.Logger -} - -// New creates a new K8s parser -func New() *Parser { - return &Parser{ - logger: log.WithPrefix("k8s parser"), - } -} - -func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) (map[string][]any, error) { - files := make(map[string][]any) - if err := fs.WalkDir(target, filepath.ToSlash(path), func(path string, entry fs.DirEntry, err error) error { - select { - case <-ctx.Done(): - return ctx.Err() - default: - } - if err != nil { - return err - } - if entry.IsDir() { - return nil - } - - parsed, err := p.ParseFile(ctx, target, path) - if err != nil { - p.logger.Error("Parse error", log.FilePath(path), log.Err(err)) - return nil - } - - files[path] = parsed - return nil - }); err != nil { - return nil, err - } - return files, nil -} - -// ParseFile parses Kubernetes manifest from the provided filesystem path. -func (p *Parser) ParseFile(_ context.Context, fsys fs.FS, path string) ([]any, error) { - f, err := fsys.Open(filepath.ToSlash(path)) - if err != nil { - return nil, err - } - defer func() { _ = f.Close() }() - return p.Parse(f, path) -} - -func (p *Parser) Parse(r io.Reader, path string) ([]any, error) { - +func Parse(_ context.Context, r io.Reader, path string) ([]any, error) { contents, err := io.ReadAll(r) if err != nil { return nil, err diff --git a/pkg/iac/scanners/kubernetes/scanner.go b/pkg/iac/scanners/kubernetes/scanner.go index dfd248cc8b1d..f79d59aaaf12 100644 --- a/pkg/iac/scanners/kubernetes/scanner.go +++ b/pkg/iac/scanners/kubernetes/scanner.go @@ -3,119 +3,17 @@ package kubernetes import ( "context" "io" - "io/fs" - "path/filepath" - "sort" - "sync" - "github.com/liamg/memoryfs" - - "github.com/aquasecurity/trivy/pkg/iac/framework" - "github.com/aquasecurity/trivy/pkg/iac/rego" - "github.com/aquasecurity/trivy/pkg/iac/scan" - "github.com/aquasecurity/trivy/pkg/iac/scanners" + "github.com/aquasecurity/trivy/pkg/iac/scanners/generic" "github.com/aquasecurity/trivy/pkg/iac/scanners/kubernetes/parser" "github.com/aquasecurity/trivy/pkg/iac/scanners/options" "github.com/aquasecurity/trivy/pkg/iac/types" - "github.com/aquasecurity/trivy/pkg/log" ) -var _ scanners.FSScanner = (*Scanner)(nil) -var _ options.ConfigurableScanner = (*Scanner)(nil) - -type Scanner struct { - mu sync.Mutex - logger *log.Logger - options []options.ScannerOption - regoScanner *rego.Scanner - parser *parser.Parser -} - -func (s *Scanner) SetIncludeDeprecatedChecks(bool) {} -func (s *Scanner) SetRegoOnly(bool) {} -func (s *Scanner) SetFrameworks(frameworks []framework.Framework) {} - -func NewScanner(opts ...options.ScannerOption) *Scanner { - s := &Scanner{ - options: opts, - logger: log.WithPrefix("k8s scanner"), - parser: parser.New(), - } - for _, opt := range opts { - opt(s) - } - return s -} - -func (s *Scanner) Name() string { - return "Kubernetes" -} - -func (s *Scanner) initRegoScanner(srcFS fs.FS) (*rego.Scanner, error) { - s.mu.Lock() - defer s.mu.Unlock() - if s.regoScanner != nil { - return s.regoScanner, nil - } - regoScanner := rego.NewScanner(types.SourceKubernetes, s.options...) - if err := regoScanner.LoadPolicies(srcFS); err != nil { - return nil, err - } - s.regoScanner = regoScanner - return regoScanner, nil +func NewScanner(opts ...options.ScannerOption) *generic.GenericScanner { + return generic.NewScanner("Kubernetes", types.SourceKubernetes, generic.ParseFunc(parse), opts...) } -func (s *Scanner) ScanReader(ctx context.Context, filename string, reader io.Reader) (scan.Results, error) { - memfs := memoryfs.New() - if err := memfs.MkdirAll(filepath.Base(filename), 0o700); err != nil { - return nil, err - } - data, err := io.ReadAll(reader) - if err != nil { - return nil, err - } - if err := memfs.WriteFile(filename, data, 0o644); err != nil { - return nil, err - } - return s.ScanFS(ctx, memfs, ".") -} - -func (s *Scanner) ScanFS(ctx context.Context, target fs.FS, dir string) (scan.Results, error) { - - k8sFilesets, err := s.parser.ParseFS(ctx, target, dir) - if err != nil { - return nil, err - } - - if len(k8sFilesets) == 0 { - return nil, nil - } - - var inputs []rego.Input - for path, k8sFiles := range k8sFilesets { - for _, content := range k8sFiles { - inputs = append(inputs, rego.Input{ - Path: path, - FS: target, - Contents: content, - }) - } - } - - regoScanner, err := s.initRegoScanner(target) - if err != nil { - return nil, err - } - - s.logger.Debug("Scanning files", log.Int("count", len(inputs))) - results, err := regoScanner.ScanInput(ctx, inputs...) - if err != nil { - return nil, err - } - results.SetSourceAndFilesystem("", target, false) - - sort.Slice(results, func(i, j int) bool { - return results[i].Rule().AVDID < results[j].Rule().AVDID - }) - return results, nil +func parse(ctx context.Context, r io.Reader, path string) (any, error) { + return parser.Parse(ctx, r, path) } diff --git a/pkg/iac/scanners/kubernetes/scanner_test.go b/pkg/iac/scanners/kubernetes/scanner_test.go index ef1ac38560f4..c9186a7f9c40 100644 --- a/pkg/iac/scanners/kubernetes/scanner_test.go +++ b/pkg/iac/scanners/kubernetes/scanner_test.go @@ -1,24 +1,23 @@ -package kubernetes +package kubernetes_test import ( "context" - "os" + "io/fs" "strings" "testing" + "testing/fstest" + "github.com/samber/lo" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/aquasecurity/trivy/internal/testutil" - "github.com/aquasecurity/trivy/pkg/iac/framework" "github.com/aquasecurity/trivy/pkg/iac/rego" "github.com/aquasecurity/trivy/pkg/iac/scan" + "github.com/aquasecurity/trivy/pkg/iac/scanners/kubernetes" ) -func Test_BasicScan_YAML(t *testing.T) { - - fs := testutil.CreateFS(t, map[string]string{ - "/code/example.yaml": ` +func Test_ScanYAML(t *testing.T) { + file := ` apiVersion: v1 kind: Pod metadata: @@ -28,148 +27,48 @@ spec: - command: ["sh", "-c", "echo 'Hello' && sleep 1h"] image: busybox name: hello -`, - "/rules/rule.rego": ` +` + fsys := buildFS(map[string]string{ + "code/example.yaml": file, + "checks/rule.rego": `# METADATA +# title: test check +# custom: +# id: KSV011 +# avd_id: AVD-KSV-0011 +# severity: LOW +# input: +# selector: +# - type: kubernetes package builtin.kubernetes.KSV011 import data.lib.kubernetes -import data.lib.utils - -default failLimitsCPU = false - -__rego_metadata__ := { - "id": "KSV011", - "avd_id": "AVD-KSV-0011", - "title": "CPU not limited", - "short_code": "limit-cpu", - "version": "v1.0.0", - "severity": "LOW", - "type": "Kubernetes Security Check", - "description": "Enforcing CPU limits prevents DoS via resource exhaustion.", - "recommended_actions": "Set a limit value under 'containers[].resources.limits.cpu'.", - "url": "https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-resource-requests-and-limits", -} - -__rego_input__ := { - "combine": false, - "selector": [{"type": "kubernetes"}], -} - -# getLimitsCPUContainers returns all containers which have set resources.limits.cpu -getLimitsCPUContainers[container] { - allContainers := kubernetes.containers[_] - utils.has_key(allContainers.resources.limits, "cpu") - container := allContainers.name -} - -# getNoLimitsCPUContainers returns all containers which have not set -# resources.limits.cpu -getNoLimitsCPUContainers[container] { - container := kubernetes.containers[_].name - not getLimitsCPUContainers[container] -} - -# failLimitsCPU is true if containers[].resources.limits.cpu is not set -# for ANY container -failLimitsCPU { - count(getNoLimitsCPUContainers) > 0 -} deny[res] { - failLimitsCPU - - msg := kubernetes.format(sprintf("Container '%s' of %s '%s' should set 'resources.limits.cpu'", [getNoLimitsCPUContainers[_], kubernetes.kind, kubernetes.name])) - - res := { - "msg": msg, - "id": __rego_metadata__.id, - "title": __rego_metadata__.title, - "severity": __rego_metadata__.severity, - "type": __rego_metadata__.type, - "startline": 6, - "endline": 10, - } + container := kubernetes.containers[_] + res := result.new("fail", container) } `, }) - scanner := NewScanner( - rego.WithPolicyDirs("rules"), + scanner := kubernetes.NewScanner( + rego.WithPolicyFilesystem(fsys), + rego.WithPolicyDirs("checks"), rego.WithEmbeddedLibraries(true), ) - results, err := scanner.ScanFS(context.TODO(), fs, "code") + results, err := scanner.ScanFS(context.TODO(), fsys, "code") require.NoError(t, err) - require.Len(t, results.GetFailed(), 1) - - assert.Equal(t, scan.Rule{ - AVDID: "AVD-KSV-0011", - Aliases: []string{"KSV011"}, - ShortCode: "limit-cpu", - Summary: "CPU not limited", - Explanation: "Enforcing CPU limits prevents DoS via resource exhaustion.", - Impact: "", - Resolution: "Set a limit value under 'containers[].resources.limits.cpu'.", - Provider: "kubernetes", - Service: "general", - Links: []string{"https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-resource-requests-and-limits"}, - Severity: "LOW", - Terraform: &scan.EngineMetadata{}, - CloudFormation: &scan.EngineMetadata{}, - CustomChecks: scan.CustomChecks{Terraform: (*scan.TerraformCustomCheck)(nil)}, - RegoPackage: "data.builtin.kubernetes.KSV011", - Frameworks: map[framework.Framework][]string{ - framework.Default: {}, - }, - }, results.GetFailed()[0].Rule()) + failed := results.GetFailed() + require.Len(t, failed, 1) - failure := results.GetFailed()[0] - actualCode, err := failure.GetCode() - require.NoError(t, err) - for i := range actualCode.Lines { - actualCode.Lines[i].Highlighted = "" - } - assert.Equal(t, []scan.Line{ - { - Number: 6, - Content: "spec: ", - IsCause: true, - FirstCause: true, - Annotation: "", - }, - { - Number: 7, - Content: " containers: ", - IsCause: true, - Annotation: "", - }, - { - Number: 8, - Content: " - command: [\"sh\", \"-c\", \"echo 'Hello' && sleep 1h\"]", - IsCause: true, - Annotation: "", - }, - { - Number: 9, - Content: " image: busybox", - IsCause: true, - Annotation: "", - }, - { - Number: 10, - Content: " name: hello", - IsCause: true, - LastCause: true, - Annotation: "", - }, - }, actualCode.Lines) + assert.Equal(t, "AVD-KSV-0011", failed[0].Rule().AVDID) + assertLines(t, file, failed) } -func Test_BasicScan_JSON(t *testing.T) { +func Test_ScanJSON(t *testing.T) { - fs := testutil.CreateFS(t, map[string]string{ - "/code/example.json": ` + file := ` { "apiVersion": "v1", "kind": "Pod", @@ -190,165 +89,58 @@ func Test_BasicScan_JSON(t *testing.T) { ] } } -`, - "/rules/rule.rego": ` +` + + fsys := buildFS(map[string]string{ + "code/example.json": file, + "checks/rule.rego": `# METADATA +# title: test check +# custom: +# id: KSV011 +# avd_id: AVD-KSV-0011 +# severity: LOW +# input: +# selector: +# - type: kubernetes package builtin.kubernetes.KSV011 import data.lib.kubernetes -import data.lib.utils - -default failLimitsCPU = false - -__rego_metadata__ := { - "id": "KSV011", - "avd_id": "AVD-KSV-0011", - "title": "CPU not limited", - "short_code": "limit-cpu", - "version": "v1.0.0", - "severity": "LOW", - "type": "Kubernetes Security Check", - "description": "Enforcing CPU limits prevents DoS via resource exhaustion.", - "recommended_actions": "Set a limit value under 'containers[].resources.limits.cpu'.", - "url": "https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-resource-requests-and-limits", -} - -__rego_input__ := { - "combine": false, - "selector": [{"type": "kubernetes"}], -} - -# getLimitsCPUContainers returns all containers which have set resources.limits.cpu -getLimitsCPUContainers[container] { - allContainers := kubernetes.containers[_] - utils.has_key(allContainers.resources.limits, "cpu") - container := allContainers.name -} - -# getNoLimitsCPUContainers returns all containers which have not set -# resources.limits.cpu -getNoLimitsCPUContainers[container] { - container := kubernetes.containers[_].name - not getLimitsCPUContainers[container] -} - -# failLimitsCPU is true if containers[].resources.limits.cpu is not set -# for ANY container -failLimitsCPU { - count(getNoLimitsCPUContainers) > 0 -} deny[res] { - failLimitsCPU - - msg := kubernetes.format(sprintf("Container '%s' of %s '%s' should set 'resources.limits.cpu'", [getNoLimitsCPUContainers[_], kubernetes.kind, kubernetes.name])) - - res := { - "msg": msg, - "id": __rego_metadata__.id, - "title": __rego_metadata__.title, - "severity": __rego_metadata__.severity, - "type": __rego_metadata__.type, - "startline": 6, - "endline": 10, - } + container := kubernetes.containers[_] + res := result.new("fail", container) } `, }) - scanner := NewScanner( - rego.WithPolicyDirs("rules"), + scanner := kubernetes.NewScanner( + rego.WithPolicyFilesystem(fsys), + rego.WithPolicyDirs("checks"), rego.WithEmbeddedLibraries(true), ) - results, err := scanner.ScanFS(context.TODO(), fs, "code") + results, err := scanner.ScanFS(context.TODO(), fsys, "code") require.NoError(t, err) require.Len(t, results.GetFailed(), 1) - assert.Equal(t, scan.Rule{ - AVDID: "AVD-KSV-0011", - Aliases: []string{"KSV011"}, - ShortCode: "limit-cpu", - Summary: "CPU not limited", - Explanation: "Enforcing CPU limits prevents DoS via resource exhaustion.", - Impact: "", - Resolution: "Set a limit value under 'containers[].resources.limits.cpu'.", - Provider: "kubernetes", - Service: "general", - Links: []string{"https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-resource-requests-and-limits"}, - Severity: "LOW", - Terraform: &scan.EngineMetadata{}, - CloudFormation: &scan.EngineMetadata{}, - CustomChecks: scan.CustomChecks{Terraform: (*scan.TerraformCustomCheck)(nil)}, - RegoPackage: "data.builtin.kubernetes.KSV011", - Frameworks: map[framework.Framework][]string{ - framework.Default: {}, - }, - }, results.GetFailed()[0].Rule()) + failed := results.GetFailed() + require.Len(t, failed, 1) - failure := results.GetFailed()[0] - actualCode, err := failure.GetCode() - require.NoError(t, err) - for i := range actualCode.Lines { - actualCode.Lines[i].Highlighted = "" - } - assert.Equal(t, []scan.Line{ - { - Number: 6, - Content: ` "name": "hello-cpu-limit"`, - IsCause: true, - FirstCause: true, - Annotation: "", - }, - { - Number: 7, - Content: ` },`, - IsCause: true, - Annotation: "", - }, - { - Number: 8, - Content: ` "spec": {`, - IsCause: true, - Annotation: "", - }, - { - Number: 9, - Content: ` "containers": [`, - IsCause: true, - Annotation: "", - }, - { - Number: 10, - Content: ` {`, - IsCause: true, - LastCause: true, - Annotation: "", - }, - }, actualCode.Lines) + assert.Equal(t, "AVD-KSV-0011", failed[0].Rule().AVDID) + assertLines(t, file, failed) } -func Test_FileScan(t *testing.T) { +func Test_YamlWithSeparator(t *testing.T) { - results, err := NewScanner(rego.WithEmbeddedPolicies(true), rego.WithEmbeddedLibraries(true), rego.WithEmbeddedLibraries(true)).ScanReader(context.TODO(), "k8s.yaml", strings.NewReader(` -apiVersion: v1 -kind: Pod -metadata: - name: hello-cpu-limit -spec: - containers: - - command: ["sh", "-c", "echo 'Hello' && sleep 1h"] - image: busybox - name: hello -`)) - require.NoError(t, err) - - assert.NotEmpty(t, results.GetFailed()) -} - -func Test_FileScan_WithSeparator(t *testing.T) { + fsys := buildFS(map[string]string{ + "check.rego": `package defsec - results, err := NewScanner(rego.WithEmbeddedPolicies(true), rego.WithEmbeddedLibraries(true)).ScanReader(context.TODO(), "k8s.yaml", strings.NewReader(` +deny[res] { + input.kind == "Pod" + res := result.new("fail", input) +}`, + "k8s.yaml": ` --- --- apiVersion: v1 @@ -360,13 +152,21 @@ spec: - command: ["sh", "-c", "echo 'Hello' && sleep 1h"] image: busybox name: hello -`)) +`, + }) + + scanner := kubernetes.NewScanner( + rego.WithPolicyFilesystem(fsys), + rego.WithPolicyDirs("."), + rego.WithEmbeddedLibraries(true), + ) + results, err := scanner.ScanFS(context.TODO(), fsys, ".") require.NoError(t, err) assert.NotEmpty(t, results.GetFailed()) } -func Test_FileScan_MultiManifests(t *testing.T) { +func Test_YamlMultiDocument(t *testing.T) { file := ` --- apiVersion: v1 @@ -389,306 +189,71 @@ spec: image: busybox name: hello2 ` - - results, err := NewScanner( - rego.WithEmbeddedPolicies(true), - rego.WithEmbeddedLibraries(true), - rego.WithEmbeddedLibraries(true)).ScanReader(context.TODO(), "k8s.yaml", strings.NewReader(file)) - require.NoError(t, err) - - assert.Greater(t, len(results.GetFailed()), 1) - fileLines := strings.Split(file, "\n") - for _, failure := range results.GetFailed() { - actualCode, err := failure.GetCode() - require.NoError(t, err) - assert.NotEmpty(t, actualCode.Lines) - for _, line := range actualCode.Lines { - assert.Greater(t, len(fileLines), line.Number) - assert.Equal(t, line.Content, fileLines[line.Number-1]) - } - } -} - -func Test_FileScanWithPolicyReader(t *testing.T) { - - results, err := NewScanner(rego.WithPolicyReader(strings.NewReader(`package defsec - -deny[msg] { - msg = "fail" -} -`))).ScanReader(context.TODO(), "k8s.yaml", strings.NewReader(` -apiVersion: v1 -kind: Pod -metadata: - name: hello-cpu-limit -spec: - containers: - - command: ["sh", "-c", "echo 'Hello' && sleep 1h"] - image: busybox - name: hello -`)) - require.NoError(t, err) - - assert.Len(t, results.GetFailed(), 1) -} - -func Test_FileScanJSON(t *testing.T) { - - results, err := NewScanner(rego.WithPolicyReader(strings.NewReader(`package defsec - -deny[msg] { - input.kind == "Pod" - msg = "fail" -} -`))).ScanReader(context.TODO(), "k8s.json", strings.NewReader(` -{ - "kind": "Pod", - "apiVersion": "v1", - "metadata": { - "name": "mongo", - "labels": { - "name": "mongo", - "role": "mongo" - } - }, - "spec": { - "volumes": [ - { - "name": "mongo-disk", - "gcePersistentDisk": { - "pdName": "mongo-disk", - "fsType": "ext4" - } - } - ], - "containers": [ - { - "name": "mongo", - "image": "mongo:latest", - "ports": [ - { - "name": "mongo", - "containerPort": 27017 - } - ], - "volumeMounts": [ - { - "name": "mongo-disk", - "mountPath": "/data/db" - } - ] - } - ] - } -} -`)) - require.NoError(t, err) - - assert.Len(t, results.GetFailed(), 1) -} - -func Test_FileScanWithMetadata(t *testing.T) { - - results, err := NewScanner( - rego.WithTrace(os.Stdout), - rego.WithPolicyReader(strings.NewReader(`package defsec - -deny[msg] { - input.kind == "Pod" - msg := { - "msg": "fail", - "startline": 2, - "endline": 2, - "filepath": "chartname/template/serviceAccount.yaml" - } -} -`))).ScanReader( - context.TODO(), - "k8s.yaml", - strings.NewReader(` -apiVersion: v1 -kind: Pod -metadata: - name: hello-cpu-limit -spec: - containers: - - command: ["sh", "-c", "echo 'Hello' && sleep 1h"] - image: busybox - name: hello -`)) - require.NoError(t, err) - - assert.NotEmpty(t, results.GetFailed()) - - firstResult := results.GetFailed()[0] - assert.Equal(t, 2, firstResult.Metadata().Range().GetStartLine()) - assert.Equal(t, 2, firstResult.Metadata().Range().GetEndLine()) - assert.Equal(t, "chartname/template/serviceAccount.yaml", firstResult.Metadata().Range().GetFilename()) -} - -func Test_FileScanExampleWithResultFunction(t *testing.T) { - - results, err := NewScanner( - rego.WithEmbeddedPolicies(true), rego.WithEmbeddedLibraries(true), - rego.WithPolicyReader(strings.NewReader(`package defsec - -import data.lib.kubernetes - -default checkCapsDropAll = false - -__rego_metadata__ := { -"id": "KSV003", -"avd_id": "AVD-KSV-0003", -"title": "Default capabilities not dropped", -"short_code": "drop-default-capabilities", -"version": "v1.0.0", -"severity": "LOW", -"type": "Kubernetes Security Check", -"description": "The container should drop all default capabilities and add only those that are needed for its execution.", -"recommended_actions": "Add 'ALL' to containers[].securityContext.capabilities.drop.", -"url": "https://kubesec.io/basics/containers-securitycontext-capabilities-drop-index-all/", -} - -__rego_input__ := { -"combine": false, -"selector": [{"type": "kubernetes"}], -} - -# Get all containers which include 'ALL' in security.capabilities.drop -getCapsDropAllContainers[container] { -allContainers := kubernetes.containers[_] -lower(allContainers.securityContext.capabilities.drop[_]) == "all" -container := allContainers.name -} - -# Get all containers which don't include 'ALL' in security.capabilities.drop -getCapsNoDropAllContainers[container] { -container := kubernetes.containers[_] -not getCapsDropAllContainers[container.name] -} + fsys := buildFS(map[string]string{ + "check.rego": `package defsec deny[res] { -output := getCapsNoDropAllContainers[_] - -msg := kubernetes.format(sprintf("Container '%s' of %s '%s' should add 'ALL' to 'securityContext.capabilities.drop'", [output.name, kubernetes.kind, kubernetes.name])) + input.kind == "Pod" + res := result.new("fail", input) +}`, + "k8s.yaml": file, + }) -res := result.new(msg, output) -} + scanner := kubernetes.NewScanner( + rego.WithPolicyFilesystem(fsys), + rego.WithPolicyDirs("."), + rego.WithEmbeddedLibraries(true), + ) -`))).ScanReader( - context.TODO(), - "k8s.yaml", - strings.NewReader(` -apiVersion: v1 -kind: Pod -metadata: - name: hello-cpu-limit -spec: - containers: - - command: ["sh", "-c", "echo 'Hello' && sleep 1h"] - image: busybox - name: hello - securityContext: - capabilities: - drop: - - nothing -`)) + results, err := scanner.ScanFS(context.TODO(), fsys, ".") require.NoError(t, err) - require.NotEmpty(t, results.GetFailed()) - - firstResult := results.GetFailed()[0] - assert.Equal(t, 8, firstResult.Metadata().Range().GetStartLine()) - assert.Equal(t, 14, firstResult.Metadata().Range().GetEndLine()) - assert.Equal(t, "k8s.yaml", firstResult.Metadata().Range().GetFilename()) + assertLines(t, file, results) } -func Test_checkPolicyIsApplicable(t *testing.T) { - srcFS := testutil.CreateFS(t, map[string]string{ - "policies/pod_policy.rego": `# METADATA -# title: "Process can elevate its own privileges" -# description: "A program inside the container can elevate its own privileges and run as root, which might give the program control over the container and node." +func Test_CheckWithSubtype(t *testing.T) { + fsys := buildFS(map[string]string{ + "checks/pod_policy.rego": `# METADATA +# title: test check # scope: package # schemas: # - input: schema["kubernetes"] -# related_resources: -# - https://kubernetes.io/docs/concepts/security/pod-security-standards/#restricted # custom: # id: KSV001 -# avd_id: AVD-KSV-0999 +# avd_id: AVD-KSV-0001 # severity: MEDIUM -# short_code: no-self-privesc -# recommended_action: "Set 'set containers[].securityContext.allowPrivilegeEscalation' to 'false'." # input: # selector: # - type: kubernetes # subtypes: # - kind: Pod -package builtin.kubernetes.KSV999 +package builtin.kubernetes.KSV001 import data.lib.kubernetes -import data.lib.utils - -default checkAllowPrivilegeEscalation = false - -# getNoPrivilegeEscalationContainers returns the names of all containers which have -# securityContext.allowPrivilegeEscalation set to false. -getNoPrivilegeEscalationContainers[container] { - allContainers := kubernetes.containers[_] - allContainers.securityContext.allowPrivilegeEscalation == false - container := allContainers.name -} - -# getPrivilegeEscalationContainers returns the names of all containers which have -# securityContext.allowPrivilegeEscalation set to true or not set. -getPrivilegeEscalationContainers[container] { - containerName := kubernetes.containers[_].name - not getNoPrivilegeEscalationContainers[containerName] - container := kubernetes.containers[_] -} deny[res] { - output := getPrivilegeEscalationContainers[_] - msg := kubernetes.format(sprintf("Container '%s' of %s '%s' should set 'securityContext.allowPrivilegeEscalation' to false", [output.name, kubernetes.kind, kubernetes.name])) - res := result.new(msg, output) + res := result.new("fail", input) } - `, - "policies/namespace_policy.rego": `# METADATA -# title: "The default namespace should not be used" -# description: "ensure that default namespace should not be used" + "checks/namespace_policy.rego": `# METADATA +# title: test check 2 # scope: package # schemas: # - input: schema["kubernetes"] -# related_resources: -# - https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/ # custom: -# id: KSV110 -# avd_id: AVD-KSV-0888 +# id: KSV002 +# avd_id: AVD-KSV-0002 # severity: LOW -# short_code: default-namespace-should-not-be-used -# recommended_action: "Ensure that namespaces are created to allow for appropriate segregation of Kubernetes resources and that all new resources are created in a specific namespace." # input: # selector: # - type: kubernetes # subtypes: # - kind: Namespace -package builtin.kubernetes.KSV888 - -import data.lib.kubernetes - -default defaultNamespaceInUse = false - -defaultNamespaceInUse { - kubernetes.namespace == "default" -} +package builtin.kubernetes.KSV002 deny[res] { - defaultNamespaceInUse - msg := sprintf("%s '%s' should not be set with 'default' namespace", [kubernetes.kind, kubernetes.name]) - res := result.new(msg, input.metadata.namespace) + res := result.new("fail", input) } - `, "test/KSV001/pod.yaml": `apiVersion: v1 kind: Pod @@ -706,18 +271,37 @@ spec: `, }) - scanner := NewScanner( - // rego.WithEmbeddedPolicies(true), rego.WithEmbeddedLibraries(true), + scanner := kubernetes.NewScanner( rego.WithEmbeddedLibraries(true), - rego.WithPolicyDirs("policies/"), - rego.WithPolicyFilesystem(srcFS), + rego.WithPolicyDirs("checks"), + rego.WithPolicyFilesystem(fsys), ) - results, err := scanner.ScanFS(context.TODO(), srcFS, "test/KSV001") + results, err := scanner.ScanFS(context.TODO(), fsys, "test/KSV001") require.NoError(t, err) require.NoError(t, err) require.Len(t, results.GetFailed(), 1) - failure := results.GetFailed()[0].Rule() - assert.Equal(t, "Process can elevate its own privileges", failure.Summary) + failure := results.GetFailed()[0] + + assert.Equal(t, "AVD-KSV-0001", failure.Rule().AVDID) +} + +func assertLines(t *testing.T, content string, results scan.Results) { + lines := strings.Split(content, "\n") + for _, res := range results { + actualCode, err := res.GetCode() + require.NoError(t, err) + assert.NotEmpty(t, actualCode.Lines) + for _, line := range actualCode.Lines { + assert.Greater(t, len(lines), line.Number) + assert.Equal(t, line.Content, lines[line.Number-1]) + } + } +} + +func buildFS(files map[string]string) fs.FS { + return fstest.MapFS(lo.MapValues(files, func(val string, _ string) *fstest.MapFile { + return &fstest.MapFile{Data: []byte(val)} + })) } From 35fd018ae7ad86823f114f0ac2f1376726aee444 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 18 Oct 2024 10:45:24 +0600 Subject: [PATCH 145/183] fix(misconf): fix for Azure Storage Account network acls adaptation (#7602) Signed-off-by: nikpivkin --- pkg/iac/adapters/arm/storage/adapt.go | 24 ++++++++++----------- pkg/iac/adapters/arm/storage/adapt_test.go | 25 ++++++++++++++++++---- 2 files changed, 32 insertions(+), 17 deletions(-) diff --git a/pkg/iac/adapters/arm/storage/adapt.go b/pkg/iac/adapters/arm/storage/adapt.go index 186ab5beda9d..26a0d10c8616 100644 --- a/pkg/iac/adapters/arm/storage/adapt.go +++ b/pkg/iac/adapters/arm/storage/adapt.go @@ -18,20 +18,18 @@ func adaptAccounts(deployment azure.Deployment) []storage.Account { var accounts []storage.Account for _, resource := range deployment.GetResourcesByType("Microsoft.Storage/storageAccounts") { - var networkRules []storage.NetworkRule - for _, acl := range resource.Properties.GetMapValue("networkAcls").AsList() { + acl := resource.Properties.GetMapValue("networkAcls") - var bypasses []types.StringValue - bypassProp := acl.GetMapValue("bypass") - for _, bypass := range strings.Split(bypassProp.AsString(), ",") { - bypasses = append(bypasses, types.String(bypass, bypassProp.GetMetadata())) - } + var bypasses []types.StringValue + bypassProp := acl.GetMapValue("bypass") + for _, bypass := range strings.Split(bypassProp.AsString(), ",") { + bypasses = append(bypasses, types.String(strings.TrimSpace(bypass), bypassProp.GetMetadata())) + } - networkRules = append(networkRules, storage.NetworkRule{ - Metadata: acl.GetMetadata(), - Bypass: bypasses, - AllowByDefault: types.Bool(acl.GetMapValue("defaultAction").EqualTo("Allow"), acl.GetMetadata()), - }) + networkRule := storage.NetworkRule{ + Metadata: acl.GetMetadata(), + Bypass: bypasses, + AllowByDefault: types.Bool(acl.GetMapValue("defaultAction").EqualTo("Allow"), acl.GetMetadata()), } var queues []storage.Queue @@ -52,7 +50,7 @@ func adaptAccounts(deployment azure.Deployment) []storage.Account { account := storage.Account{ Metadata: resource.Metadata, - NetworkRules: networkRules, + NetworkRules: []storage.NetworkRule{networkRule}, EnforceHTTPS: resource.Properties.GetMapValue("supportsHttpsTrafficOnly").AsBoolValue(false, resource.Properties.GetMetadata()), Containers: containers, QueueProperties: storage.QueueProperties{ diff --git a/pkg/iac/adapters/arm/storage/adapt_test.go b/pkg/iac/adapters/arm/storage/adapt_test.go index a6965ca1560c..372986f23529 100644 --- a/pkg/iac/adapters/arm/storage/adapt_test.go +++ b/pkg/iac/adapters/arm/storage/adapt_test.go @@ -6,6 +6,8 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/aquasecurity/trivy/internal/testutil" + "github.com/aquasecurity/trivy/pkg/iac/providers/azure/storage" "github.com/aquasecurity/trivy/pkg/iac/scanners/azure" "github.com/aquasecurity/trivy/pkg/iac/types" ) @@ -43,6 +45,10 @@ func Test_AdaptStorage(t *testing.T) { "minimumTlsVersion": azure.NewValue("TLS1_2", types.NewTestMetadata()), "supportsHttpsTrafficOnly": azure.NewValue(true, types.NewTestMetadata()), "publicNetworkAccess": azure.NewValue("Disabled", types.NewTestMetadata()), + "networkAcls": azure.NewValue(map[string]azure.Value{ + "bypass": azure.NewValue("Logging, Metrics", types.NewTestMetadata()), + "defaultAction": azure.NewValue("Allow", types.NewTestMetadata()), + }, types.NewTestMetadata()), }, types.NewTestMetadata()), }, }, @@ -52,9 +58,20 @@ func Test_AdaptStorage(t *testing.T) { require.Len(t, output.Accounts, 1) - account := output.Accounts[0] - assert.Equal(t, "TLS1_2", account.MinimumTLSVersion.Value()) - assert.True(t, account.EnforceHTTPS.Value()) - assert.False(t, account.PublicNetworkAccess.Value()) + expected := storage.Storage{ + Accounts: []storage.Account{{ + MinimumTLSVersion: types.StringTest("TLS1_2"), + EnforceHTTPS: types.BoolTest(true), + PublicNetworkAccess: types.BoolTest(false), + NetworkRules: []storage.NetworkRule{{ + Bypass: []types.StringValue{ + types.StringTest("Logging"), + types.StringTest("Metrics"), + }, + AllowByDefault: types.BoolTest(true), + }}, + }}, + } + testutil.AssertDefsecEqual(t, expected, output) } From c225883649f58128a99fa2c1cef327d0e57940be Mon Sep 17 00:00:00 2001 From: Johannes Feichtner <343448+Churro@users.noreply.github.com> Date: Fri, 18 Oct 2024 09:10:46 +0200 Subject: [PATCH 146/183] feat(cyclonedx): add file checksums to `CycloneDX` reports (#7507) Co-authored-by: knqyf263 --- .../testdata/conda-cyclonedx.json.golden | 12 + ...fluentd-multiple-lockfiles.cdx.json.golden | 330 ++++++++++++++++++ pkg/commands/artifact/run.go | 4 +- 3 files changed, 344 insertions(+), 2 deletions(-) diff --git a/integration/testdata/conda-cyclonedx.json.golden b/integration/testdata/conda-cyclonedx.json.golden index 7f3a352fcce7..df8f575e9053 100644 --- a/integration/testdata/conda-cyclonedx.json.golden +++ b/integration/testdata/conda-cyclonedx.json.golden @@ -34,6 +34,12 @@ "type": "library", "name": "openssl", "version": "1.1.1q", + "hashes": [ + { + "alg": "SHA-1", + "content": "237db0da53131e4548cb1181337fa0f420299e1f" + } + ], "licenses": [ { "license": { @@ -58,6 +64,12 @@ "type": "library", "name": "pip", "version": "22.2.2", + "hashes": [ + { + "alg": "SHA-1", + "content": "a6a2db7668f1ad541d704369fc66c96a4415aa24" + } + ], "licenses": [ { "license": { diff --git a/integration/testdata/fluentd-multiple-lockfiles.cdx.json.golden b/integration/testdata/fluentd-multiple-lockfiles.cdx.json.golden index 65fc78e6c66f..9f23585a01da 100644 --- a/integration/testdata/fluentd-multiple-lockfiles.cdx.json.golden +++ b/integration/testdata/fluentd-multiple-lockfiles.cdx.json.golden @@ -6169,6 +6169,12 @@ "type": "library", "name": "activesupport", "version": "6.0.2.1", + "hashes": [ + { + "alg": "SHA-1", + "content": "a2cd09dcbaf8ca1951fb8e3f2ebdfe6728ab44f7" + } + ], "licenses": [ { "license": { @@ -6201,6 +6207,12 @@ "type": "library", "name": "addressable", "version": "2.7.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "b4596fdeffcb1c89b24623b6f775a6b054a8323f" + } + ], "licenses": [ { "license": { @@ -6233,6 +6245,12 @@ "type": "library", "name": "concurrent-ruby", "version": "1.1.6", + "hashes": [ + { + "alg": "SHA-1", + "content": "c96749b0390ad63300b13dca6fd83e5508facf18" + } + ], "licenses": [ { "license": { @@ -6265,6 +6283,12 @@ "type": "library", "name": "cool.io", "version": "1.6.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "706a2490b54301e8ae8f2ca8f9f56b279b96ac7b" + } + ], "purl": "pkg:gem/cool.io@1.6.0", "properties": [ { @@ -6290,6 +6314,12 @@ "type": "library", "name": "dig_rb", "version": "1.0.1", + "hashes": [ + { + "alg": "SHA-1", + "content": "04a4a555fe3a7e253098e870cf8a6c8746828829" + } + ], "licenses": [ { "license": { @@ -6322,6 +6352,12 @@ "type": "library", "name": "domain_name", "version": "0.5.20190701", + "hashes": [ + { + "alg": "SHA-1", + "content": "e45a352deedbf1d48c2563caa583d0864d6ac62b" + } + ], "licenses": [ { "license": { @@ -6364,6 +6400,12 @@ "type": "library", "name": "elasticsearch-api", "version": "7.5.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "aac794d1d845525dc57d73d8bd5bda4b7f593ea4" + } + ], "licenses": [ { "license": { @@ -6396,6 +6438,12 @@ "type": "library", "name": "elasticsearch-transport", "version": "7.5.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "29ab0a306cfc109b82ac19c37f288956a4d6d1d9" + } + ], "licenses": [ { "license": { @@ -6428,6 +6476,12 @@ "type": "library", "name": "elasticsearch", "version": "7.5.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "f3996e145e83f80d27ed48f8d2dca84f02c696c3" + } + ], "licenses": [ { "license": { @@ -6460,6 +6514,12 @@ "type": "library", "name": "excon", "version": "0.72.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "8b5c81a189d2748ae488dff8a7b4876493b86f76" + } + ], "licenses": [ { "license": { @@ -6492,6 +6552,12 @@ "type": "library", "name": "faraday", "version": "0.17.3", + "hashes": [ + { + "alg": "SHA-1", + "content": "b8c741fbdc2d729a59e2e855037421040673ca45" + } + ], "licenses": [ { "license": { @@ -6524,6 +6590,12 @@ "type": "library", "name": "ffi-compiler", "version": "1.0.1", + "hashes": [ + { + "alg": "SHA-1", + "content": "b9ffee214ef79e695c14c8703566f7c13be4c2ba" + } + ], "licenses": [ { "license": { @@ -6556,6 +6628,12 @@ "type": "library", "name": "ffi", "version": "1.12.2", + "hashes": [ + { + "alg": "SHA-1", + "content": "e6345da46b7a923b2248bc76d074362e7491376b" + } + ], "licenses": [ { "license": { @@ -6588,6 +6666,12 @@ "type": "library", "name": "fluent-plugin-concat", "version": "2.4.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "b6a0da88821e50d052cb244b57562f00abe79888" + } + ], "licenses": [ { "license": { @@ -6620,6 +6704,12 @@ "type": "library", "name": "fluent-plugin-detect-exceptions", "version": "0.0.13", + "hashes": [ + { + "alg": "SHA-1", + "content": "d1a7b50f7723ead908453f463e24424735be0a56" + } + ], "licenses": [ { "license": { @@ -6652,6 +6742,12 @@ "type": "library", "name": "fluent-plugin-elasticsearch", "version": "3.8.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "d60372f3af2757abd0a4ff68484e9328b2cbe386" + } + ], "licenses": [ { "license": { @@ -6684,6 +6780,12 @@ "type": "library", "name": "fluent-plugin-kubernetes_metadata_filter", "version": "2.4.1", + "hashes": [ + { + "alg": "SHA-1", + "content": "eeb3ce046c69c9c83ed1d4bc949058ef6a124f96" + } + ], "licenses": [ { "license": { @@ -6716,6 +6818,12 @@ "type": "library", "name": "fluent-plugin-multi-format-parser", "version": "1.0.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "9aa245fc07627474621e29f04507a377dfae09d3" + } + ], "licenses": [ { "license": { @@ -6748,6 +6856,12 @@ "type": "library", "name": "fluent-plugin-prometheus", "version": "1.7.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "597a311791f0d05968c558e8015c8bed864137e2" + } + ], "licenses": [ { "license": { @@ -6780,6 +6894,12 @@ "type": "library", "name": "fluent-plugin-systemd", "version": "1.0.2", + "hashes": [ + { + "alg": "SHA-1", + "content": "115901208913bc5031597a20fae33c50c6de6500" + } + ], "licenses": [ { "license": { @@ -6812,6 +6932,12 @@ "type": "library", "name": "fluentd", "version": "1.8.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "5f31ca316e345410e5a5b70b5fafed8a51fd5092" + } + ], "licenses": [ { "license": { @@ -6844,6 +6970,12 @@ "type": "library", "name": "http-accept", "version": "1.7.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "21dedf2ba79a24f86528c2dfc32d17dd9324d9fd" + } + ], "purl": "pkg:gem/http-accept@1.7.0", "properties": [ { @@ -6869,6 +7001,12 @@ "type": "library", "name": "http-cookie", "version": "1.0.3", + "hashes": [ + { + "alg": "SHA-1", + "content": "e6f5b8e237e694b3729797cca134525822769964" + } + ], "licenses": [ { "license": { @@ -6901,6 +7039,12 @@ "type": "library", "name": "http-form_data", "version": "2.2.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "53c844c1f954a9c43b78b8e57f18c0ec965beb1f" + } + ], "licenses": [ { "license": { @@ -6933,6 +7077,12 @@ "type": "library", "name": "http-parser", "version": "1.2.1", + "hashes": [ + { + "alg": "SHA-1", + "content": "7c6889d98755a1fe8859d850892412a0e001ba9a" + } + ], "licenses": [ { "license": { @@ -6965,6 +7115,12 @@ "type": "library", "name": "http", "version": "4.3.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "79032e0328aa1d3ee184a38c50cd93d5bce8998b" + } + ], "licenses": [ { "license": { @@ -6997,6 +7153,12 @@ "type": "library", "name": "http_parser.rb", "version": "0.6.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "0ed80e936eaf7151f540186333c3df436afd46c6" + } + ], "licenses": [ { "license": { @@ -7029,6 +7191,12 @@ "type": "library", "name": "i18n", "version": "1.8.2", + "hashes": [ + { + "alg": "SHA-1", + "content": "d13bccc2521cef33fc4303888b24f327a7369877" + } + ], "licenses": [ { "license": { @@ -7061,6 +7229,12 @@ "type": "library", "name": "kubeclient", "version": "4.6.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "31916cb42ac6b30c68a5422414946d0328be94d4" + } + ], "licenses": [ { "license": { @@ -7093,6 +7267,12 @@ "type": "library", "name": "lru_redux", "version": "1.1.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "c8c5874f406a8fefc655fee48b75dfa276a5b8fa" + } + ], "licenses": [ { "license": { @@ -7125,6 +7305,12 @@ "type": "library", "name": "mime-types-data", "version": "3.2019.1009", + "hashes": [ + { + "alg": "SHA-1", + "content": "8a80ce9bf4961df0184d25699612d29293a05aee" + } + ], "licenses": [ { "license": { @@ -7157,6 +7343,12 @@ "type": "library", "name": "mime-types", "version": "3.3.1", + "hashes": [ + { + "alg": "SHA-1", + "content": "b70aa1555acff548ee282c76ddd562e831483187" + } + ], "licenses": [ { "license": { @@ -7189,6 +7381,12 @@ "type": "library", "name": "minitest", "version": "5.14.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "8fcf25c201eacdf1a0e4db78efcb37ad590f33c0" + } + ], "licenses": [ { "license": { @@ -7221,6 +7419,12 @@ "type": "library", "name": "msgpack", "version": "1.3.3", + "hashes": [ + { + "alg": "SHA-1", + "content": "bda4ff6f3cd395534ba441ccacc4640f9dc43942" + } + ], "licenses": [ { "license": { @@ -7253,6 +7457,12 @@ "type": "library", "name": "multi_json", "version": "1.14.1", + "hashes": [ + { + "alg": "SHA-1", + "content": "fead333877a2db2e2aaca87d8cd1f270952cd42e" + } + ], "licenses": [ { "license": { @@ -7285,6 +7495,12 @@ "type": "library", "name": "multipart-post", "version": "2.1.1", + "hashes": [ + { + "alg": "SHA-1", + "content": "927edb51d5b23a49a417fe1503f196896c0e8034" + } + ], "licenses": [ { "license": { @@ -7317,6 +7533,12 @@ "type": "library", "name": "netrc", "version": "0.11.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "98d7bbb894429413feb5c0a3b766a7945f65e3ba" + } + ], "licenses": [ { "license": { @@ -7349,6 +7571,12 @@ "type": "library", "name": "oj", "version": "3.10.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "b348b933b9c2f6a6e952f6a15c7cbd9f1186815f" + } + ], "licenses": [ { "license": { @@ -7381,6 +7609,12 @@ "type": "library", "name": "prometheus-client", "version": "0.9.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "f829d25ee6b39cdda518f7b6f85be6563d7b5990" + } + ], "licenses": [ { "license": { @@ -7413,6 +7647,12 @@ "type": "library", "name": "public_suffix", "version": "4.0.3", + "hashes": [ + { + "alg": "SHA-1", + "content": "ac88907845a8bec2a0df25cf2e3ef61121e47252" + } + ], "licenses": [ { "license": { @@ -7445,6 +7685,12 @@ "type": "library", "name": "quantile", "version": "0.2.1", + "hashes": [ + { + "alg": "SHA-1", + "content": "07a0817cd9df688930b2d8481a647a7ec321b870" + } + ], "licenses": [ { "license": { @@ -7477,6 +7723,12 @@ "type": "library", "name": "rake", "version": "13.0.1", + "hashes": [ + { + "alg": "SHA-1", + "content": "d01a832a472daf914670adda88b44b419a4d2daf" + } + ], "licenses": [ { "license": { @@ -7509,6 +7761,12 @@ "type": "library", "name": "recursive-open-struct", "version": "1.1.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "5a4a02765d82d6786a832384b890f0a2497c2e14" + } + ], "licenses": [ { "license": { @@ -7541,6 +7799,12 @@ "type": "library", "name": "rest-client", "version": "2.1.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "a7e5943a216b16e0867693f20d5d1604cd015486" + } + ], "licenses": [ { "license": { @@ -7573,6 +7837,12 @@ "type": "library", "name": "serverengine", "version": "2.2.1", + "hashes": [ + { + "alg": "SHA-1", + "content": "16e5806b2d513f6b075355c602aed0f960584267" + } + ], "licenses": [ { "license": { @@ -7605,6 +7875,12 @@ "type": "library", "name": "sigdump", "version": "0.2.4", + "hashes": [ + { + "alg": "SHA-1", + "content": "1bae5c6042dc82a4bec6aacb42f75ba71f7cb634" + } + ], "licenses": [ { "license": { @@ -7637,6 +7913,12 @@ "type": "library", "name": "strptime", "version": "0.2.3", + "hashes": [ + { + "alg": "SHA-1", + "content": "17150d9e40754ea1a732796f224b9be78e77b86a" + } + ], "licenses": [ { "license": { @@ -7669,6 +7951,12 @@ "type": "library", "name": "systemd-journal", "version": "1.3.3", + "hashes": [ + { + "alg": "SHA-1", + "content": "4f310622fe58e95897147736c96d3d42174a3363" + } + ], "licenses": [ { "license": { @@ -7701,6 +7989,12 @@ "type": "library", "name": "thread_safe", "version": "0.3.6", + "hashes": [ + { + "alg": "SHA-1", + "content": "546993ac33864e279ae73e918d6da5d4ca083098" + } + ], "licenses": [ { "license": { @@ -7733,6 +8027,12 @@ "type": "library", "name": "tzinfo-data", "version": "1.2019.3", + "hashes": [ + { + "alg": "SHA-1", + "content": "26832d11382943b02433f3ad1df7653b4cfdf3a2" + } + ], "licenses": [ { "license": { @@ -7765,6 +8065,12 @@ "type": "library", "name": "tzinfo", "version": "1.2.6", + "hashes": [ + { + "alg": "SHA-1", + "content": "5b7db490d431d97366729086683e736d2b5fee99" + } + ], "licenses": [ { "license": { @@ -7797,6 +8103,12 @@ "type": "library", "name": "unf", "version": "0.1.4", + "hashes": [ + { + "alg": "SHA-1", + "content": "85ff87b60a6d16ffddf4db5f5f91c0ef76bacd3d" + } + ], "licenses": [ { "license": { @@ -7829,6 +8141,12 @@ "type": "library", "name": "unf_ext", "version": "0.0.7.6", + "hashes": [ + { + "alg": "SHA-1", + "content": "1b5141ee855f16e832534c2e73d81fec0601ebd3" + } + ], "licenses": [ { "license": { @@ -7861,6 +8179,12 @@ "type": "library", "name": "yajl-ruby", "version": "1.4.1", + "hashes": [ + { + "alg": "SHA-1", + "content": "670f3cd2fc601c9b7fde02b1d8c60e90491a7221" + } + ], "licenses": [ { "license": { @@ -7893,6 +8217,12 @@ "type": "library", "name": "zeitwerk", "version": "2.3.0", + "hashes": [ + { + "alg": "SHA-1", + "content": "803894c06d28932016866a26fc2b22c4db942094" + } + ], "licenses": [ { "license": { diff --git a/pkg/commands/artifact/run.go b/pkg/commands/artifact/run.go index 49c7d3b34296..5018434d10c2 100644 --- a/pkg/commands/artifact/run.go +++ b/pkg/commands/artifact/run.go @@ -538,9 +538,9 @@ func (r *runner) initScannerConfig(ctx context.Context, opts flag.Options) (Scan } } - // SPDX needs to calculate digests for package files + // SPDX and CycloneDX need to calculate digests for package files var fileChecksum bool - if opts.Format == types.FormatSPDXJSON || opts.Format == types.FormatSPDX { + if opts.Format == types.FormatSPDXJSON || opts.Format == types.FormatSPDX || opts.Format == types.FormatCycloneDX { fileChecksum = true } From 8d5dbc9fec3569b22ed81a03c40eaf732768718b Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Sat, 19 Oct 2024 06:58:51 +0600 Subject: [PATCH 147/183] fix(misconf): properly expand dynamic blocks (#7612) Signed-off-by: nikpivkin Co-authored-by: Simar --- pkg/iac/scanners/terraform/module_test.go | 2 +- .../scanners/terraform/parser/evaluator.go | 49 +-- .../scanners/terraform/parser/parser_test.go | 400 +++++++++++------- pkg/iac/terraform/attribute.go | 9 +- pkg/iac/terraform/block.go | 163 ++++++- 5 files changed, 409 insertions(+), 214 deletions(-) diff --git a/pkg/iac/scanners/terraform/module_test.go b/pkg/iac/scanners/terraform/module_test.go index d0d289a9d562..ec4291fd59e4 100644 --- a/pkg/iac/scanners/terraform/module_test.go +++ b/pkg/iac/scanners/terraform/module_test.go @@ -567,7 +567,7 @@ resource "something" "else" { for_each = toset(["true"]) content { - ok = each.value + ok = blah.value } } } diff --git a/pkg/iac/scanners/terraform/parser/evaluator.go b/pkg/iac/scanners/terraform/parser/evaluator.go index 809498f35c63..8e2e737b5d9b 100644 --- a/pkg/iac/scanners/terraform/parser/evaluator.go +++ b/pkg/iac/scanners/terraform/parser/evaluator.go @@ -260,36 +260,17 @@ func (e *evaluator) evaluateSteps() { } func (e *evaluator) expandBlocks(blocks terraform.Blocks) terraform.Blocks { - return e.expandDynamicBlocks(e.expandBlockForEaches(e.expandBlockCounts(blocks), false)...) + return e.expandDynamicBlocks(e.expandBlockForEaches(e.expandBlockCounts(blocks))...) } func (e *evaluator) expandDynamicBlocks(blocks ...*terraform.Block) terraform.Blocks { for _, b := range blocks { - e.expandDynamicBlock(b) - } - return blocks -} - -func (e *evaluator) expandDynamicBlock(b *terraform.Block) { - for _, sub := range b.AllBlocks() { - e.expandDynamicBlock(sub) - } - for _, sub := range b.AllBlocks().OfType("dynamic") { - if sub.IsExpanded() { - continue - } - blockName := sub.TypeLabel() - expanded := e.expandBlockForEaches(terraform.Blocks{sub}, true) - for _, ex := range expanded { - if content := ex.GetBlock("content"); content.IsNotNil() { - _ = e.expandDynamicBlocks(content) - b.InjectBlock(content, blockName) - } - } - if len(expanded) > 0 { - sub.MarkExpanded() + if err := b.ExpandBlock(); err != nil { + e.logger.Error(`Failed to expand dynamic block.`, + log.String("block", b.FullName()), log.Err(err)) } } + return blocks } func isBlockSupportsForEachMetaArgument(block *terraform.Block) bool { @@ -297,11 +278,10 @@ func isBlockSupportsForEachMetaArgument(block *terraform.Block) bool { "module", "resource", "data", - "dynamic", }, block.Type()) } -func (e *evaluator) expandBlockForEaches(blocks terraform.Blocks, isDynamic bool) terraform.Blocks { +func (e *evaluator) expandBlockForEaches(blocks terraform.Blocks) terraform.Blocks { var forEachFiltered terraform.Blocks @@ -348,7 +328,7 @@ func (e *evaluator) expandBlockForEaches(blocks terraform.Blocks, isDynamic bool // is the value of the collection. The exception is the use of for-each inside a dynamic block, // because in this case the collection element may not be a primitive value. if (forEachVal.Type().IsCollectionType() || forEachVal.Type().IsTupleType()) && - !forEachVal.Type().IsMapType() && !isDynamic { + !forEachVal.Type().IsMapType() { stringVal, err := convert.Convert(val, cty.String) if err != nil { e.logger.Error( @@ -374,22 +354,7 @@ func (e *evaluator) expandBlockForEaches(blocks terraform.Blocks, isDynamic bool ctx.Set(eachObj, "each") ctx.Set(eachObj, block.TypeLabel()) - - if isDynamic { - if iterAttr := block.GetAttribute("iterator"); iterAttr.IsNotNil() { - refs := iterAttr.AllReferences() - if len(refs) == 1 { - ctx.Set(idx, refs[0].TypeLabel(), "key") - ctx.Set(val, refs[0].TypeLabel(), "value") - } else { - e.logger.Debug("Ignoring iterator attribute in dynamic block, expected one reference", - log.Int("refs", len(refs))) - } - } - } - forEachFiltered = append(forEachFiltered, clone) - clones[idx.AsString()] = clone.Values() }) diff --git a/pkg/iac/scanners/terraform/parser/parser_test.go b/pkg/iac/scanners/terraform/parser/parser_test.go index e3bd817748f6..540338afb57f 100644 --- a/pkg/iac/scanners/terraform/parser/parser_test.go +++ b/pkg/iac/scanners/terraform/parser/parser_test.go @@ -1367,139 +1367,284 @@ func TestCountMetaArgumentInModule(t *testing.T) { } func TestDynamicBlocks(t *testing.T) { - t.Run("arg is list of int", func(t *testing.T) { - modules := parse(t, map[string]string{ - "main.tf": ` -resource "aws_security_group" "sg-webserver" { - vpc_id = "1111" - dynamic "ingress" { + tests := []struct { + name string + src string + expected []any + }{ + { + name: "for-each use tuple of int", + src: `resource "test_resource" "test" { + dynamic "foo" { for_each = [80, 443] content { - from_port = ingress.value - to_port = ingress.value - protocol = "tcp" - cidr_blocks = ["0.0.0.0/0"] + bar = foo.value } } -} -`, - }) - require.Len(t, modules, 1) - - secGroups := modules.GetResourcesByType("aws_security_group") - assert.Len(t, secGroups, 1) - ingressBlocks := secGroups[0].GetBlocks("ingress") - assert.Len(t, ingressBlocks, 2) - - var inboundPorts []int - for _, ingress := range ingressBlocks { - fromPort := ingress.GetAttribute("from_port").AsIntValueOrDefault(-1, ingress).Value() - inboundPorts = append(inboundPorts, fromPort) - } - - assert.True(t, compareSets([]int{80, 443}, inboundPorts)) - }) - - t.Run("empty for-each", func(t *testing.T) { - modules := parse(t, map[string]string{ - "main.tf": ` -resource "aws_lambda_function" "analyzer" { - dynamic "vpc_config" { +}`, + expected: []any{float64(80), float64(443)}, + }, + { + name: "for-each use list of int", + src: `resource "test_resource" "test" { + dynamic "foo" { + for_each = tolist([80, 443]) + content { + bar = foo.value + } + } +}`, + expected: []any{float64(80), float64(443)}, + }, + { + name: "for-each use set of int", + src: `resource "test_resource" "test" { + dynamic "foo" { + for_each = toset([80, 443]) + content { + bar = foo.value + } + } +}`, + expected: []any{float64(80), float64(443)}, + }, + { + name: "for-each use list of bool", + src: `resource "test_resource" "test" { + dynamic "foo" { + for_each = tolist([true]) + content { + bar = foo.value + } + } +}`, + expected: []any{true}, + }, + { + name: "empty for-each", + src: `resource "test_resource" "test" { + dynamic "foo" { for_each = [] content {} } +}`, + expected: []any{}, + }, + { + name: "for-each use tuple of objects", + src: `variable "test_var" { + type = list(object({ enabled = bool })) + default = [{ enabled = true }] } -`, - }) - require.Len(t, modules, 1) - functions := modules.GetResourcesByType("aws_lambda_function") - assert.Len(t, functions, 1) - vpcConfigs := functions[0].GetBlocks("vpc_config") - assert.Empty(t, vpcConfigs) - }) +resource "test_resource" "test" { + dynamic "foo" { + for_each = var.test_var - t.Run("arg is list of bool", func(t *testing.T) { - modules := parse(t, map[string]string{ - "main.tf": ` -resource "aws_lambda_function" "analyzer" { - dynamic "vpc_config" { - for_each = [true] - content {} + content { + bar = foo.value.enabled + } + } +}`, + expected: []any{true}, + }, + { + name: "attribute ref to object key", + src: `variable "some_var" { + type = map( + object({ + tag = string + }) + ) + default = { + ssh = { "tag" = "login" } + http = { "tag" = "proxy" } + https = { "tag" = "proxy" } } } -`, - }) - require.Len(t, modules, 1) - - functions := modules.GetResourcesByType("aws_lambda_function") - assert.Len(t, functions, 1) - vpcConfigs := functions[0].GetBlocks("vpc_config") - assert.Len(t, vpcConfigs, 1) - }) - t.Run("arg is list of objects", func(t *testing.T) { - modules := parse(t, map[string]string{ - "main.tf": `locals { - cluster_network_policy = [{ - enabled = true - }] +resource "test_resource" "test" { + dynamic "foo" { + for_each = { for name, values in var.some_var : name => values } + content { + bar = foo.key + } + } +}`, + expected: []any{"ssh", "http", "https"}, + }, + { + name: "attribute ref to object value", + src: `variable "some_var" { + type = map( + object({ + tag = string + }) + ) + default = { + ssh = { "tag" = "login" } + http = { "tag" = "proxy" } + https = { "tag" = "proxy" } + } } -resource "google_container_cluster" "primary" { - name = "test" +resource "test_resource" "test" { + dynamic "foo" { + for_each = { for name, values in var.some_var : name => values } + content { + bar = foo.value.tag + } + } +}`, + expected: []any{"login", "proxy", "proxy"}, + }, + { + name: "attribute ref to map key", + src: `variable "some_var" { + type = map + default = { + ssh = { "tag" = "login" } + http = { "tag" = "proxy" } + https = { "tag" = "proxy" } + } +} - dynamic "network_policy" { - for_each = local.cluster_network_policy +resource "test_resource" "test" { + dynamic "foo" { + for_each = var.some_var + content { + bar = foo.key + } + } +}`, + expected: []any{"ssh", "http", "https"}, + }, + { + name: "attribute ref to map value", + src: `variable "some_var" { + type = map + default = { + ssh = { "tag" = "login" } + http = { "tag" = "proxy" } + https = { "tag" = "proxy" } + } +} +resource "test_resource" "test" { + dynamic "foo" { + for_each = var.some_var content { - enabled = network_policy.value.enabled + bar = foo.value.tag } } }`, - }) - require.Len(t, modules, 1) + expected: []any{"login", "proxy", "proxy"}, + }, + { + name: "dynamic block with iterator", + src: `resource "test_resource" "test" { + dynamic "foo" { + for_each = ["foo", "bar"] + iterator = some_iterator + content { + bar = some_iterator.value + } + } +}`, + expected: []any{"foo", "bar"}, + }, + { + name: "iterator and parent block with same name", + src: `resource "test_resource" "test" { + dynamic "foo" { + for_each = ["foo", "bar"] + iterator = foo + content { + bar = foo.value + } + } +}`, + expected: []any{"foo", "bar"}, + }, + { + name: "for-each use null value", + src: `resource "test_resource" "test" { + dynamic "foo" { + for_each = null + content { + bar = foo.value + } + } +}`, + expected: []any{}, + }, + { + name: "no for-each attribute", + src: `resource "test_resource" "test" { + dynamic "foo" { + content { + bar = foo.value + } + } +}`, + expected: []any{}, + }, + } - clusters := modules.GetResourcesByType("google_container_cluster") - assert.Len(t, clusters, 1) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + modules := parse(t, map[string]string{ + "main.tf": tt.src, + }) + require.Len(t, modules, 1) - networkPolicies := clusters[0].GetBlocks("network_policy") - assert.Len(t, networkPolicies, 1) + resource := modules.GetResourcesByType("test_resource") + require.Len(t, resource, 1) + blocks := resource[0].GetBlocks("foo") - enabled := networkPolicies[0].GetAttribute("enabled") - assert.True(t, enabled.Value().True()) - }) + var vals []any + for _, attr := range blocks { + vals = append(vals, attr.GetAttribute("bar").GetRawValue()) + } - t.Run("nested dynamic", func(t *testing.T) { - modules := parse(t, map[string]string{ - "main.tf": ` -resource "test_block" "this" { - name = "name" - location = "loc" - dynamic "env" { - for_each = ["1", "2"] - content { - dynamic "value_source" { - for_each = [true, true] - content {} - } + assert.ElementsMatch(t, tt.expected, vals) + }) } +} + +func TestNestedDynamicBlock(t *testing.T) { + modules := parse(t, map[string]string{ + "main.tf": `resource "test_resource" "test" { + dynamic "foo" { + for_each = ["1", "1"] + content { + dynamic "bar" { + for_each = [true, true] + content { + baz = foo.value + qux = bar.value + } + } + } } }`, - }) - require.Len(t, modules, 1) + }) + require.Len(t, modules, 1) - testResources := modules.GetResourcesByType("test_block") - assert.Len(t, testResources, 1) - envs := testResources[0].GetBlocks("env") - assert.Len(t, envs, 2) + testResources := modules.GetResourcesByType("test_resource") + assert.Len(t, testResources, 1) + blocks := testResources[0].GetBlocks("foo") + assert.Len(t, blocks, 2) - var sources []*terraform.Block - for _, env := range envs { - sources = append(sources, env.GetBlocks("value_source")...) + var nested []*terraform.Block + for _, block := range blocks { + nested = append(nested, block.GetBlocks("bar")...) + for _, b := range nested { + assert.Equal(t, "1", b.GetAttribute("baz").GetRawValue()) + assert.Equal(t, true, b.GetAttribute("qux").GetRawValue()) } - assert.Len(t, sources, 4) - }) + } + assert.Len(t, nested, 4) } func parse(t *testing.T, files map[string]string) terraform.Modules { @@ -1513,21 +1658,6 @@ func parse(t *testing.T, files map[string]string) terraform.Modules { return modules } -func compareSets(a, b []int) bool { - m := make(map[int]bool) - for _, el := range a { - m[el] = true - } - - for _, el := range b { - if !m[el] { - return false - } - } - - return true -} - func TestModuleRefersToOutputOfAnotherModule(t *testing.T) { files := map[string]string{ "main.tf": ` @@ -1775,42 +1905,6 @@ variable "foo" {} assert.Equal(t, "bar", blocks[0].GetAttribute("foo").Value().AsString()) } -func TestDynamicWithIterator(t *testing.T) { - fsys := fstest.MapFS{ - "main.tf": &fstest.MapFile{ - Data: []byte(`resource "aws_s3_bucket" "this" { - dynamic versioning { - for_each = [true] - iterator = ver - - content { - enabled = ver.value - } - } -}`), - }, - } - - parser := New( - fsys, "", - OptionStopOnHCLError(true), - OptionWithDownloads(false), - ) - require.NoError(t, parser.ParseFS(context.TODO(), ".")) - - modules, _, err := parser.EvaluateAll(context.TODO()) - require.NoError(t, err) - - assert.Len(t, modules, 1) - - buckets := modules.GetResourcesByType("aws_s3_bucket") - assert.Len(t, buckets, 1) - - attr, _ := buckets[0].GetNestedAttribute("versioning.enabled") - - assert.True(t, attr.Value().True()) -} - func Test_AWSRegionNameDefined(t *testing.T) { fs := testutil.CreateFS(t, map[string]string{ diff --git a/pkg/iac/terraform/attribute.go b/pkg/iac/terraform/attribute.go index 39161a72a379..9c5536357283 100644 --- a/pkg/iac/terraform/attribute.go +++ b/pkg/iac/terraform/attribute.go @@ -729,15 +729,16 @@ func (a *Attribute) IsTrue() bool { if a == nil { return false } - switch a.Value().Type() { + val := a.Value() + switch val.Type() { case cty.Bool: - return a.Value().True() + return val.True() case cty.String: - val := a.Value().AsString() + val := val.AsString() val = strings.Trim(val, "\"") return strings.EqualFold(val, "true") case cty.Number: - val := a.Value().AsBigFloat() + val := val.AsBigFloat() f, _ := val.Float64() return f > 0 } diff --git a/pkg/iac/terraform/block.go b/pkg/iac/terraform/block.go index dbf7352959d0..dd6d8446c124 100644 --- a/pkg/iac/terraform/block.go +++ b/pkg/iac/terraform/block.go @@ -1,6 +1,7 @@ package terraform import ( + "errors" "fmt" "io/fs" "strconv" @@ -137,16 +138,15 @@ func (b *Block) GetRawValue() any { return nil } -func (b *Block) InjectBlock(block *Block, name string) { - block.hclBlock.Labels = []string{} - block.hclBlock.Type = name +func (b *Block) injectBlock(block *Block) { for attrName, attr := range block.Attributes() { - b.context.Root().SetByDot(attr.Value(), fmt.Sprintf("%s.%s.%s", b.reference.String(), name, attrName)) + path := fmt.Sprintf("%s.%s.%s", b.reference.String(), block.hclBlock.Type, attrName) + b.context.Root().SetByDot(attr.Value(), path) } b.childBlocks = append(b.childBlocks, block) } -func (b *Block) MarkExpanded() { +func (b *Block) markExpanded() { b.expanded = true } @@ -154,17 +154,26 @@ func (b *Block) IsExpanded() bool { return b.expanded } -func (b *Block) Clone(index cty.Value) *Block { - var childCtx *context.Context - if b.context != nil { - childCtx = b.context.NewChild() - } else { - childCtx = context.NewContext(&hcl.EvalContext{}, nil) +func (b *Block) inherit(ctx *context.Context, index ...cty.Value) *Block { + return NewBlock(b.copyBlock(), ctx, b.moduleBlock, b.parentBlock, b.moduleSource, b.moduleFS, index...) +} + +func (b *Block) copyBlock() *hcl.Block { + hclBlock := *b.hclBlock + return &hclBlock +} + +func (b *Block) childContext() *context.Context { + if b.context == nil { + return context.NewContext(&hcl.EvalContext{}, nil) } + return b.context.NewChild() +} - cloneHCL := *b.hclBlock +func (b *Block) Clone(index cty.Value) *Block { + childCtx := b.childContext() + clone := b.inherit(childCtx, index) - clone := NewBlock(&cloneHCL, childCtx, b.moduleBlock, b.parentBlock, b.moduleSource, b.moduleFS, index) if len(clone.hclBlock.Labels) > 0 { position := len(clone.hclBlock.Labels) - 1 labels := make([]string, len(clone.hclBlock.Labels)) @@ -188,7 +197,7 @@ func (b *Block) Clone(index cty.Value) *Block { } indexVal, _ := gocty.ToCtyValue(index, cty.Number) clone.context.SetByDot(indexVal, "count.index") - clone.MarkExpanded() + clone.markExpanded() b.cloneIndex++ return clone } @@ -446,6 +455,17 @@ func (b *Block) LocalName() string { return b.reference.String() } +func (b *Block) FullLocalName() string { + if b.parentBlock != nil { + return fmt.Sprintf( + "%s.%s", + b.parentBlock.FullLocalName(), + b.LocalName(), + ) + } + return b.LocalName() +} + func (b *Block) FullName() string { if b.moduleBlock != nil { @@ -576,3 +596,118 @@ func (b *Block) IsNil() bool { func (b *Block) IsNotNil() bool { return !b.IsNil() } + +func (b *Block) ExpandBlock() error { + var ( + expanded []*Block + errs []error + ) + + for _, child := range b.childBlocks { + if child.Type() == "dynamic" { + blocks, err := child.expandDynamic() + if err != nil { + errs = append(errs, err) + continue + } + expanded = append(expanded, blocks...) + } + } + + for _, block := range expanded { + b.injectBlock(block) + } + + return errors.Join(errs...) +} + +func (b *Block) expandDynamic() ([]*Block, error) { + if b.IsExpanded() || b.Type() != "dynamic" { + return nil, nil + } + + realBlockType := b.TypeLabel() + if realBlockType == "" { + return nil, errors.New("dynamic block must have 1 label") + } + + forEachVal, err := b.validateForEach() + if err != nil { + return nil, fmt.Errorf("invalid for-each in %s block: %w", b.FullLocalName(), err) + } + + var ( + expanded []*Block + errs []error + ) + + forEachVal.ForEachElement(func(key, val cty.Value) (stop bool) { + if val.IsNull() { + return + } + + iteratorName, err := b.iteratorName(realBlockType) + if err != nil { + errs = append(errs, err) + return + } + + forEachCtx := b.childContext() + obj := cty.ObjectVal(map[string]cty.Value{ + "key": key, + "value": val, + }) + forEachCtx.Set(obj, iteratorName) + + if content := b.GetBlock("content"); content != nil { + inherited := content.inherit(forEachCtx) + inherited.hclBlock.Labels = []string{} + inherited.hclBlock.Type = realBlockType + if err := inherited.ExpandBlock(); err != nil { + errs = append(errs, err) + return + } + expanded = append(expanded, inherited) + } + return + }) + + if len(expanded) > 0 { + b.markExpanded() + } + + return expanded, errors.Join(errs...) +} + +func (b *Block) validateForEach() (cty.Value, error) { + forEachAttr := b.GetAttribute("for_each") + if forEachAttr == nil { + return cty.NilVal, errors.New("for_each attribute required") + } + + forEachVal := forEachAttr.Value() + + if !forEachVal.CanIterateElements() { + return cty.NilVal, fmt.Errorf("cannot use a %s value in for_each. An iterable collection is required", forEachVal.GoString()) + } + + return forEachVal, nil +} + +func (b *Block) iteratorName(blockType string) (string, error) { + iteratorAttr := b.GetAttribute("iterator") + if iteratorAttr == nil { + return blockType, nil + } + + traversal, diags := hcl.AbsTraversalForExpr(iteratorAttr.hclAttribute.Expr) + if diags.HasErrors() { + return "", diags + } + + if len(traversal) != 1 { + return "", fmt.Errorf("dynamic iterator must be a single variable name") + } + + return traversal.RootName(), nil +} From 57e24aa85382f749df7f673e241caaf3fcbb45cb Mon Sep 17 00:00:00 2001 From: Matthieu MOREL Date: Mon, 21 Oct 2024 11:06:50 +0200 Subject: [PATCH 148/183] fix: enable usestdlibvars linter (#7770) Signed-off-by: Matthieu MOREL --- .golangci.yaml | 1 + integration/registry_test.go | 2 +- pkg/dependency/parser/java/pom/parse.go | 2 +- pkg/iac/adapters/terraform/aws/apigateway/adapt_test.go | 3 ++- pkg/iac/adapters/terraform/aws/apigateway/apiv1_test.go | 5 +++-- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.golangci.yaml b/.golangci.yaml index 95c66cc69f73..40bfa36e1a64 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -105,6 +105,7 @@ linters: - typecheck - unconvert - unused + - usestdlibvars run: go: '1.22' diff --git a/integration/registry_test.go b/integration/registry_test.go index aded09adce35..25ddaf5b2814 100644 --- a/integration/registry_test.go +++ b/integration/registry_test.go @@ -334,7 +334,7 @@ func requestRegistryToken(imageRef name.Reference, baseDir string, opt registryO } // Get a registry token - req, err := http.NewRequest("GET", fmt.Sprintf("%s/auth", opt.AuthURL), nil) + req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/auth", opt.AuthURL), nil) if err != nil { return "", err } diff --git a/pkg/dependency/parser/java/pom/parse.go b/pkg/dependency/parser/java/pom/parse.go index 2c8a194ea50b..60a83ba9d81b 100644 --- a/pkg/dependency/parser/java/pom/parse.go +++ b/pkg/dependency/parser/java/pom/parse.go @@ -703,7 +703,7 @@ func (p *Parser) remoteRepoRequest(repo string, paths []string) (*http.Request, paths = append([]string{repoURL.Path}, paths...) repoURL.Path = path.Join(paths...) - req, err := http.NewRequest("GET", repoURL.String(), http.NoBody) + req, err := http.NewRequest(http.MethodGet, repoURL.String(), http.NoBody) if err != nil { return nil, xerrors.Errorf("unable to create HTTP request: %w", err) } diff --git a/pkg/iac/adapters/terraform/aws/apigateway/adapt_test.go b/pkg/iac/adapters/terraform/aws/apigateway/adapt_test.go index 65393ae82f82..8d2b0155fee5 100644 --- a/pkg/iac/adapters/terraform/aws/apigateway/adapt_test.go +++ b/pkg/iac/adapters/terraform/aws/apigateway/adapt_test.go @@ -1,6 +1,7 @@ package apigateway import ( + "net/http" "testing" "github.com/stretchr/testify/assert" @@ -72,7 +73,7 @@ resource "aws_apigatewayv2_domain_name" "example" { { Methods: []v1.Method{ { - HTTPMethod: String("GET"), + HTTPMethod: String(http.MethodGet), AuthorizationType: String("NONE"), APIKeyRequired: Bool(false), }, diff --git a/pkg/iac/adapters/terraform/aws/apigateway/apiv1_test.go b/pkg/iac/adapters/terraform/aws/apigateway/apiv1_test.go index cf69e8d0ee23..9932ac864e7b 100644 --- a/pkg/iac/adapters/terraform/aws/apigateway/apiv1_test.go +++ b/pkg/iac/adapters/terraform/aws/apigateway/apiv1_test.go @@ -1,6 +1,7 @@ package apigateway import ( + "net/http" "testing" "github.com/aquasecurity/trivy/internal/testutil" @@ -35,7 +36,7 @@ resource "aws_api_gateway_method" "example" { `, expected: []v1.Method{ { - HTTPMethod: String("GET"), + HTTPMethod: String(http.MethodGet), AuthorizationType: String("NONE"), APIKeyRequired: Bool(false), }, @@ -63,7 +64,7 @@ resource "aws_api_gateway_method" "example" { `, expected: []v1.Method{ { - HTTPMethod: String("GET"), + HTTPMethod: String(http.MethodGet), AuthorizationType: String("NONE"), APIKeyRequired: Bool(true), }, From f6acdf713991f8ffdbe765178fcb8a9cde433cba Mon Sep 17 00:00:00 2001 From: Pierre Baumard Date: Mon, 21 Oct 2024 11:38:35 +0200 Subject: [PATCH 149/183] fix(license): fix license normalization for Universal Permissive License (#7766) --- pkg/licensing/normalize.go | 2 +- pkg/licensing/normalize_test.go | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pkg/licensing/normalize.go b/pkg/licensing/normalize.go index 4ce294275214..bce81e68903d 100644 --- a/pkg/licensing/normalize.go +++ b/pkg/licensing/normalize.go @@ -626,7 +626,7 @@ func TrimLicenseText(text string) string { } // version number match -var versionRegexpString = "([A-UW-Z)]{2,})( LICENSE)?\\s*[,(-]?\\s*(V|V\\.|VER|VER\\.|VERSION|VERSION-|-)?\\s*([1-9](\\.\\d)*)[)]?" +var versionRegexpString = "([A-UW-Z)])( LICENSE)?\\s*[,(-]?\\s*(V|V\\.|VER|VER\\.|VERSION|VERSION-|-)?\\s*([1-9](\\.\\d)*)[)]?" // case insensitive version match anywhere in string var versionRegexp = regexp.MustCompile("(?i)" + versionRegexpString) diff --git a/pkg/licensing/normalize_test.go b/pkg/licensing/normalize_test.go index 9b47fd923f29..7daf7b57d783 100644 --- a/pkg/licensing/normalize_test.go +++ b/pkg/licensing/normalize_test.go @@ -209,6 +209,13 @@ func TestNormalize(t *testing.T) { normalized: " The unmapped license ", normalizedKey: " The unmapped license ", }, + { + licenses: []string{ + "Universal Permissive License, Version 1.0", + }, + normalized: "UPL-1.0", + normalizedKey: "UPL-1.0", + }, } for _, tt := range tests { t.Run(tt.normalized, func(t *testing.T) { From 010b2138067184114a882d3b5d86e2f556f4355c Mon Sep 17 00:00:00 2001 From: afdesk Date: Tue, 22 Oct 2024 00:25:54 +0600 Subject: [PATCH 150/183] refactor(k8s): scan config files as a folder (#7690) --- pkg/k8s/scanner/io.go | 50 ++++++++++++++++++----- pkg/k8s/scanner/io_test.go | 5 +++ pkg/k8s/scanner/scanner.go | 82 ++++++++++++++++++++++---------------- 3 files changed, 92 insertions(+), 45 deletions(-) diff --git a/pkg/k8s/scanner/io.go b/pkg/k8s/scanner/io.go index 9c32699ddd63..65f102a4b08c 100644 --- a/pkg/k8s/scanner/io.go +++ b/pkg/k8s/scanner/io.go @@ -3,6 +3,7 @@ package scanner import ( "fmt" "os" + "path/filepath" "regexp" "runtime" @@ -13,36 +14,63 @@ import ( "github.com/aquasecurity/trivy/pkg/log" ) -var r = regexp.MustCompile("\\\\|/|:|\\*|\\?|<|>") +var r = regexp.MustCompile("[\\\\/:*?<>]") -func createTempFile(artifact *artifacts.Artifact) (string, error) { +func generateTempFileByArtifact(artifact *artifacts.Artifact, tempDir string) (string, error) { filename := fmt.Sprintf("%s-%s-%s-*.yaml", artifact.Namespace, artifact.Kind, artifact.Name) - if runtime.GOOS == "windows" { // removes characters not permitted in file/directory names on Windows filename = filenameWindowsFriendly(filename) } - file, err := os.CreateTemp("", filename) + file, err := os.CreateTemp(tempDir, filename) if err != nil { - return "", xerrors.Errorf("creating tmp file error: %w", err) + return "", xerrors.Errorf("failed to create temporary file: %w", err) } + shouldRemove := false defer func() { if err := file.Close(); err != nil { - log.Error("Failed to close temp file", log.String("path", file.Name()), log.Err(err)) + log.Error("Failed to close temp file", log.FilePath(file.Name()), log.Err(err)) + } + if shouldRemove { + removeFile(file.Name()) } }() - if err := yaml.NewEncoder(file).Encode(artifact.RawResource); err != nil { - removeFile(filename) - return "", xerrors.Errorf("marshaling resource error: %w", err) + shouldRemove = true + return "", xerrors.Errorf("failed to encode artifact: %w", err) + } + return filepath.Base(file.Name()), nil +} + +// generateTempDir creates a directory with yaml files generated from kubernetes artifacts +// returns a directory name, a map for mapping a temp target file to k8s artifact and error +func generateTempDir(arts []*artifacts.Artifact) (string, map[string]*artifacts.Artifact, error) { + tempDir, err := os.MkdirTemp("", "trivyk8s*") + if err != nil { + return "", nil, xerrors.Errorf("failed to create temp directory: %w", err) + } + + m := make(map[string]*artifacts.Artifact) + for _, artifact := range arts { + filename, err := generateTempFileByArtifact(artifact, tempDir) + if err != nil { + log.Error("Failed to create temp file", log.FilePath(filename), log.Err(err)) + continue + } + m[filename] = artifact } + return tempDir, m, nil +} - return file.Name(), nil +func removeDir(dirname string) { + if err := os.RemoveAll(dirname); err != nil { + log.Error("Failed to remove temp directory", log.FilePath(dirname), log.Err(err)) + } } func removeFile(filename string) { if err := os.Remove(filename); err != nil { - log.Error("Failed to remove temp file", log.String("path", filename), log.Err(err)) + log.Error("Failed to remove temp file", log.FilePath(filename), log.Err(err)) } } diff --git a/pkg/k8s/scanner/io_test.go b/pkg/k8s/scanner/io_test.go index 7587d1bb8282..9e256b39f2b3 100644 --- a/pkg/k8s/scanner/io_test.go +++ b/pkg/k8s/scanner/io_test.go @@ -23,6 +23,11 @@ func Test_FilenameWindowsFriendly(t *testing.T) { fileName: `kube-system-Role-system-controller-bootstrap-signer-2934213283.yaml`, want: `kube-system-Role-system-controller-bootstrap-signer-2934213283.yaml`, }, + { + name: "name with no invalid - slash", + fileName: "-ClusterRoleBinding-system\\basic-user-725844313.yaml", + want: `-ClusterRoleBinding-system_basic-user-725844313.yaml`, + }, } for _, test := range tests { diff --git a/pkg/k8s/scanner/scanner.go b/pkg/k8s/scanner/scanner.go index 67d06b4c54bd..70debfe6a85f 100644 --- a/pkg/k8s/scanner/scanner.go +++ b/pkg/k8s/scanner/scanner.go @@ -82,14 +82,18 @@ func (s *Scanner) Scan(ctx context.Context, artifactsData []*artifacts.Artifact) var resources []report.Resource - type scanResult struct { - vulns []report.Resource - misconfig report.Resource + // scans kubernetes artifacts as a scope of yaml files + if local.ShouldScanMisconfigOrRbac(s.opts.Scanners) { + misconfigs, err := s.scanMisconfigs(ctx, resourceArtifacts) + if err != nil { + return report.Report{}, xerrors.Errorf("scanning misconfigurations error: %w", err) + } + resources = append(resources, misconfigs...) } - onItem := func(ctx context.Context, artifact *artifacts.Artifact) (scanResult, error) { - scanResults := scanResult{} - if s.opts.Scanners.AnyEnabled(types.VulnerabilityScanner, types.SecretScanner) && !s.opts.SkipImages { + // scan images from kubernetes cluster in parallel + if s.opts.Scanners.AnyEnabled(types.VulnerabilityScanner, types.SecretScanner) && !s.opts.SkipImages { + onItem := func(ctx context.Context, artifact *artifacts.Artifact) ([]report.Resource, error) { opts := s.opts opts.Credentials = make([]ftypes.Credential, len(s.opts.Credentials)) copy(opts.Credentials, s.opts.Credentials) @@ -106,33 +110,22 @@ func (s *Scanner) Scan(ctx context.Context, artifactsData []*artifacts.Artifact) } vulns, err := s.scanVulns(ctx, artifact, opts) if err != nil { - return scanResult{}, xerrors.Errorf("scanning vulnerabilities error: %w", err) + return nil, xerrors.Errorf("scanning vulnerabilities error: %w", err) } - scanResults.vulns = vulns + return vulns, nil } - if local.ShouldScanMisconfigOrRbac(s.opts.Scanners) { - misconfig, err := s.scanMisconfigs(ctx, artifact) - if err != nil { - return scanResult{}, xerrors.Errorf("scanning misconfigurations error: %w", err) - } - scanResults.misconfig = misconfig + + onResult := func(result []report.Resource) error { + resources = append(resources, result...) + return nil } - return scanResults, nil - } - onResult := func(result scanResult) error { - resources = append(resources, result.vulns...) - // don't add empty misconfig results to resources slice to avoid an empty resource - if result.misconfig.Results != nil { - resources = append(resources, result.misconfig) + p := parallel.NewPipeline(s.opts.Parallel, !s.opts.Quiet, resourceArtifacts, onItem, onResult) + if err := p.Do(ctx); err != nil { + return report.Report{}, err } - return nil } - p := parallel.NewPipeline(s.opts.Parallel, !s.opts.Quiet, resourceArtifacts, onItem, onResult) - if err := p.Do(ctx); err != nil { - return report.Report{}, err - } if s.opts.Scanners.AnyEnabled(types.VulnerabilityScanner) { k8sResource, err := s.scanK8sVulns(ctx, k8sCoreArtifacts) if err != nil { @@ -173,22 +166,43 @@ func (s *Scanner) scanVulns(ctx context.Context, artifact *artifacts.Artifact, o return resources, nil } -func (s *Scanner) scanMisconfigs(ctx context.Context, artifact *artifacts.Artifact) (report.Resource, error) { - configFile, err := createTempFile(artifact) +func (s *Scanner) scanMisconfigs(ctx context.Context, k8sArtifacts []*artifacts.Artifact) ([]report.Resource, error) { + dir, artifactsByFilename, err := generateTempDir(k8sArtifacts) if err != nil { - return report.Resource{}, xerrors.Errorf("scan error: %w", err) + return nil, xerrors.Errorf("failed to generate temp dir: %w", err) } - s.opts.Target = configFile + s.opts.Target = dir configReport, err := s.runner.ScanFilesystem(ctx, s.opts) - // remove config file after scanning - removeFile(configFile) + // remove config files after scanning + removeDir(dir) + if err != nil { - return report.CreateResource(artifact, configReport, err), err + return nil, xerrors.Errorf("failed to scan filesystem: %w", err) + } + resources := make([]report.Resource, 0, len(k8sArtifacts)) + + for _, res := range configReport.Results { + artifact := artifactsByFilename[res.Target] + + singleReport := types.Report{ + SchemaVersion: configReport.SchemaVersion, + CreatedAt: configReport.CreatedAt, + ArtifactName: res.Target, + ArtifactType: configReport.ArtifactType, + Metadata: configReport.Metadata, + Results: types.Results{res}, + } + + resource, err := s.filter(ctx, singleReport, artifact) + if err != nil { + resource = report.CreateResource(artifact, singleReport, err) + } + resources = append(resources, resource) } - return s.filter(ctx, configReport, artifact) + return resources, nil } func (s *Scanner) filter(ctx context.Context, r types.Report, artifact *artifacts.Artifact) (report.Resource, error) { var err error From 9514148767865baddd73a49245385574927f7a74 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Tue, 22 Oct 2024 02:55:12 +0600 Subject: [PATCH 151/183] feat(misconf): export unresolvable field of IaC types to Rego (#7765) Signed-off-by: nikpivkin --- pkg/iac/rego/convert/slice_test.go | 2 ++ pkg/iac/rego/schemas/cloud.json | 21 +++++++++++++++++++++ pkg/iac/state/state_test.go | 2 ++ pkg/iac/types/metadata.go | 1 + pkg/iac/types/metadata_test.go | 3 +++ 5 files changed, 29 insertions(+) diff --git a/pkg/iac/rego/convert/slice_test.go b/pkg/iac/rego/convert/slice_test.go index e30c200142b2..ff318e2b1a03 100644 --- a/pkg/iac/rego/convert/slice_test.go +++ b/pkg/iac/rego/convert/slice_test.go @@ -38,6 +38,7 @@ func Test_SliceTypesConversion(t *testing.T) { "endline": 123, "sourceprefix": "", "managed": true, + "unresolvable": false, "explicit": false, "fskey": "", "resource": "", @@ -49,6 +50,7 @@ func Test_SliceTypesConversion(t *testing.T) { "endline": 123, "sourceprefix": "", "managed": true, + "unresolvable": false, "explicit": false, "fskey": "", "resource": "", diff --git a/pkg/iac/rego/schemas/cloud.json b/pkg/iac/rego/schemas/cloud.json index 3cc6301429be..bdaad1330898 100644 --- a/pkg/iac/rego/schemas/cloud.json +++ b/pkg/iac/rego/schemas/cloud.json @@ -7884,6 +7884,9 @@ "startline": { "type": "integer" }, + "unresolvable": { + "type": "boolean" + }, "value": { "type": "boolean" } @@ -7916,6 +7919,9 @@ "startline": { "type": "integer" }, + "unresolvable": { + "type": "boolean" + }, "value": { "type": "string" } @@ -7948,6 +7954,9 @@ "startline": { "type": "integer" }, + "unresolvable": { + "type": "boolean" + }, "value": { "type": "integer" } @@ -7980,6 +7989,9 @@ "startline": { "type": "integer" }, + "unresolvable": { + "type": "boolean" + }, "value": { "type": "object" } @@ -8011,6 +8023,9 @@ }, "startline": { "type": "integer" + }, + "unresolvable": { + "type": "boolean" } } }, @@ -8041,6 +8056,9 @@ "startline": { "type": "integer" }, + "unresolvable": { + "type": "boolean" + }, "value": { "type": "string" } @@ -8073,6 +8091,9 @@ "startline": { "type": "integer" }, + "unresolvable": { + "type": "boolean" + }, "value": { "type": "string" } diff --git a/pkg/iac/state/state_test.go b/pkg/iac/state/state_test.go index 60b4b061a2d3..46de9b506d4b 100644 --- a/pkg/iac/state/state_test.go +++ b/pkg/iac/state/state_test.go @@ -44,6 +44,7 @@ func Test_RegoConversion(t *testing.T) { "startline": 2, "endline": 4, "managed": true, + "unresolvable": false, "explicit": false, "fskey": "", }, @@ -55,6 +56,7 @@ func Test_RegoConversion(t *testing.T) { "endline": 3, "value": "my-bucket", "managed": true, + "unresolvable": false, "explicit": false, "fskey": "", }, diff --git a/pkg/iac/types/metadata.go b/pkg/iac/types/metadata.go index 359654bdc43b..c71460441622 100755 --- a/pkg/iac/types/metadata.go +++ b/pkg/iac/types/metadata.go @@ -84,6 +84,7 @@ func (m *Metadata) ToRego() any { "sourceprefix": m.Range().GetSourcePrefix(), "managed": m.isManaged, "explicit": m.isExplicit, + "unresolvable": m.isUnresolvable, "fskey": CreateFSKey(m.Range().GetFS()), "resource": m.Reference(), } diff --git a/pkg/iac/types/metadata_test.go b/pkg/iac/types/metadata_test.go index f447c6d85ca2..f7d46bbf9dbd 100644 --- a/pkg/iac/types/metadata_test.go +++ b/pkg/iac/types/metadata_test.go @@ -8,12 +8,14 @@ import ( func Test_MetadataToRego(t *testing.T) { m1 := NewTestMetadata() + m1.isUnresolvable = true expected := map[string]any{ "endline": 123, "explicit": false, "filepath": "test.test", "fskey": "", "managed": true, + "unresolvable": true, "resource": "", "sourceprefix": "", "startline": 123, @@ -27,6 +29,7 @@ func Test_MetadataToRego(t *testing.T) { "filepath": "test.test", "fskey": "", "managed": true, + "unresolvable": false, "resource": "", "sourceprefix": "", "startline": 123, From f75c0d1f0069d4856cb4826d6049f32c5b9409d9 Mon Sep 17 00:00:00 2001 From: simar7 <1254783+simar7@users.noreply.github.com> Date: Wed, 23 Oct 2024 12:54:29 -0600 Subject: [PATCH 152/183] feat(misconf): Show misconfig ID in output (#7762) --- pkg/report/table/misconfig.go | 12 ++++++------ pkg/report/table/misconfig_test.go | 21 +++++++++++---------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/pkg/report/table/misconfig.go b/pkg/report/table/misconfig.go index 112d783d0875..dfb724bdf458 100644 --- a/pkg/report/table/misconfig.go +++ b/pkg/report/table/misconfig.go @@ -124,18 +124,18 @@ func (r *misconfigRenderer) renderSummary(misconf types.DetectedMisconfiguration } } - // severity + // ID & severity switch misconf.Severity { case severityCritical: - r.printf("%s: ", misconf.Severity) + r.printf("%s (%s): ", misconf.AVDID, misconf.Severity) case severityHigh: - r.printf("%s: ", misconf.Severity) + r.printf("%s (%s): ", misconf.AVDID, misconf.Severity) case severityMedium: - r.printf("%s: ", misconf.Severity) + r.printf("%s (%s): ", misconf.AVDID, misconf.Severity) case severityLow: - r.printf("%s: ", misconf.Severity) + r.printf("%s (%s): ", misconf.AVDID, misconf.Severity) default: - r.printf("%s: ", misconf.Severity) + r.printf("%s (%s): ", misconf.AVDID, misconf.Severity) } // heading diff --git a/pkg/report/table/misconfig_test.go b/pkg/report/table/misconfig_test.go index a57399f0e253..785b2621b504 100644 --- a/pkg/report/table/misconfig_test.go +++ b/pkg/report/table/misconfig_test.go @@ -27,7 +27,8 @@ func TestMisconfigRenderer(t *testing.T) { MisconfSummary: &types.MisconfSummary{Successes: 0, Failures: 1, Exceptions: 0}, Misconfigurations: []types.DetectedMisconfiguration{ { - ID: "AVD-XYZ-0123", + ID: "some-alias-for-a-check", + AVDID: "AVD-XYZ-0123", Title: "Config file is bad", Description: "Your config file is not good.", Message: "Oh no, a bad config.", @@ -44,7 +45,7 @@ my-file () Tests: 1 (SUCCESSES: 0, FAILURES: 1, EXCEPTIONS: 0) Failures: 1 (LOW: 0, MEDIUM: 0, HIGH: 1, CRITICAL: 0) -HIGH: Oh no, a bad config. +AVD-XYZ-0123 (HIGH): Oh no, a bad config. ════════════════════════════════════════ Your config file is not good. @@ -61,7 +62,7 @@ See https://google.com/search?q=bad%20config MisconfSummary: &types.MisconfSummary{Successes: 0, Failures: 1, Exceptions: 0}, Misconfigurations: []types.DetectedMisconfiguration{ { - ID: "AVD-XYZ-0123", + AVDID: "AVD-XYZ-0123", Title: "Config file is bad", Description: "Your config file is not good.", Message: "Oh no, a bad config.", @@ -103,7 +104,7 @@ my-file () Tests: 1 (SUCCESSES: 0, FAILURES: 1, EXCEPTIONS: 0) Failures: 1 (LOW: 0, MEDIUM: 0, HIGH: 1, CRITICAL: 0) -HIGH: Oh no, a bad config. +AVD-XYZ-0123 (HIGH): Oh no, a bad config. ════════════════════════════════════════ Your config file is not good. @@ -126,7 +127,7 @@ See https://google.com/search?q=bad%20config MisconfSummary: &types.MisconfSummary{Successes: 1, Failures: 1, Exceptions: 0}, Misconfigurations: []types.DetectedMisconfiguration{ { - ID: "AVD-XYZ-0123", + AVDID: "AVD-XYZ-0123", Title: "Config file is bad", Description: "Your config file is not good.", Message: "Oh no, a bad config.", @@ -157,7 +158,7 @@ See https://google.com/search?q=bad%20config }, }, { - ID: "AVD-XYZ-0456", + AVDID: "AVD-XYZ-0456", Title: "Config file is bad again", Description: "Your config file is still not good.", Message: "Oh no, a bad config AGAIN.", @@ -174,7 +175,7 @@ my-file () Tests: 2 (SUCCESSES: 1, FAILURES: 1, EXCEPTIONS: 0) Failures: 1 (LOW: 0, MEDIUM: 0, HIGH: 1, CRITICAL: 0) -FAIL: HIGH: Oh no, a bad config. +FAIL: AVD-XYZ-0123 (HIGH): Oh no, a bad config. ════════════════════════════════════════ Your config file is not good. @@ -188,7 +189,7 @@ See https://google.com/search?q=bad%20config ──────────────────────────────────────── -PASS: MEDIUM: Oh no, a bad config AGAIN. +PASS: AVD-XYZ-0456 (MEDIUM): Oh no, a bad config AGAIN. ════════════════════════════════════════ Your config file is still not good. @@ -213,7 +214,7 @@ See https://google.com/search?q=bad%20config { Type: "Terraform Security Check", ID: "AVD-AWS-0107", - AVDID: "AVS-AWS-0107", + AVDID: "AVD-AWS-0107", Title: "An ingress security group rule allows traffic from /0", Description: "Opening up ports to the public internet is generally to be avoided. You should restrict access to IP addresses or ranges that explicitly require it where possible.", Message: "Security group rule allows ingress from public internet.", @@ -312,7 +313,7 @@ terraform-aws-modules/security-group/aws/main.tf (terraform) Tests: 6 (SUCCESSES: 5, FAILURES: 1, EXCEPTIONS: 0) Failures: 1 (LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 1) -CRITICAL: Security group rule allows ingress from public internet. +AVD-AWS-0107 (CRITICAL): Security group rule allows ingress from public internet. ════════════════════════════════════════ Opening up ports to the public internet is generally to be avoided. You should restrict access to IP addresses or ranges that explicitly require it where possible. From c0d79fa09e645f3a3dbff878e393b8631fb17b64 Mon Sep 17 00:00:00 2001 From: Aaron Goldenthal Date: Thu, 24 Oct 2024 02:24:02 -0500 Subject: [PATCH 153/183] feat(report): update gitlab template to populate operating_system value (#7735) --- contrib/gitlab.tpl | 13 +- integration/client_server_test.go | 11 + integration/testdata/alpine-310.gitlab.golden | 8 +- integration/testdata/npm.gitlab.golden | 214 ++++++++++++++++++ 4 files changed, 239 insertions(+), 7 deletions(-) create mode 100644 integration/testdata/npm.gitlab.golden diff --git a/contrib/gitlab.tpl b/contrib/gitlab.tpl index 744c0c9394cb..7ff8abd8bfec 100644 --- a/contrib/gitlab.tpl +++ b/contrib/gitlab.tpl @@ -24,11 +24,18 @@ "status": "success", "type": "container_scanning" }, + {{- $image := "Unknown" -}} + {{- $os := "Unknown" -}} + {{- range . }} + {{- if eq .Class "os-pkgs" -}} + {{- $target := .Target }} + {{- $image = $target | regexFind "[^\\s]+" }} + {{- $os = $target | splitList "(" | last | trimSuffix ")" }} + {{- end }} + {{- end }} "vulnerabilities": [ {{- $t_first := true }} {{- range . }} - {{- $target := .Target }} - {{- $image := $target | regexFind "[^\\s]+" }} {{- range .Vulnerabilities -}} {{- if $t_first -}} {{- $t_first = false -}} @@ -65,7 +72,7 @@ "version": "{{ .InstalledVersion }}" }, {{- /* TODO: No mapping available - https://github.com/aquasecurity/trivy/issues/332 */}} - "operating_system": "Unknown", + "operating_system": "{{ $os }}", "image": "{{ $image }}" }, "identifiers": [ diff --git a/integration/client_server_test.go b/integration/client_server_test.go index 07a4f086200c..4afed3fdc155 100644 --- a/integration/client_server_test.go +++ b/integration/client_server_test.go @@ -323,6 +323,17 @@ func TestClientServerWithFormat(t *testing.T) { }, golden: "testdata/alpine-310.gitlab.golden", }, + { + name: "scan package-lock.json with gitlab template (Unknown os and image)", + args: csArgs{ + Command: "fs", + Format: "template", + TemplatePath: "@../contrib/gitlab.tpl", + Target: "testdata/fixtures/repo/npm/", + ListAllPackages: true, + }, + golden: "testdata/npm.gitlab.golden", + }, { name: "alpine 3.10 with gitlab-codequality template", args: csArgs{ diff --git a/integration/testdata/alpine-310.gitlab.golden b/integration/testdata/alpine-310.gitlab.golden index ad769b31959e..a0339dcf6bfb 100644 --- a/integration/testdata/alpine-310.gitlab.golden +++ b/integration/testdata/alpine-310.gitlab.golden @@ -37,7 +37,7 @@ }, "version": "1.1.1c-r0" }, - "operating_system": "Unknown", + "operating_system": "alpine 3.10.2", "image": "testdata/fixtures/images/alpine-310.tar.gz" }, "identifiers": [ @@ -104,7 +104,7 @@ }, "version": "1.1.1c-r0" }, - "operating_system": "Unknown", + "operating_system": "alpine 3.10.2", "image": "testdata/fixtures/images/alpine-310.tar.gz" }, "identifiers": [ @@ -191,7 +191,7 @@ }, "version": "1.1.1c-r0" }, - "operating_system": "Unknown", + "operating_system": "alpine 3.10.2", "image": "testdata/fixtures/images/alpine-310.tar.gz" }, "identifiers": [ @@ -258,7 +258,7 @@ }, "version": "1.1.1c-r0" }, - "operating_system": "Unknown", + "operating_system": "alpine 3.10.2", "image": "testdata/fixtures/images/alpine-310.tar.gz" }, "identifiers": [ diff --git a/integration/testdata/npm.gitlab.golden b/integration/testdata/npm.gitlab.golden new file mode 100644 index 000000000000..6c8cc2ce97ba --- /dev/null +++ b/integration/testdata/npm.gitlab.golden @@ -0,0 +1,214 @@ +{ + "version": "15.0.7", + "scan": { + "analyzer": { + "id": "trivy", + "name": "Trivy", + "vendor": { + "name": "Aqua Security" + }, + "version": "dev" + }, + "end_time": "2021-08-25T12:20:30", + "scanner": { + "id": "trivy", + "name": "Trivy", + "url": "https://github.com/aquasecurity/trivy/", + "vendor": { + "name": "Aqua Security" + }, + "version": "dev" + }, + "start_time": "2021-08-25T12:20:30", + "status": "success", + "type": "container_scanning" + }, + "vulnerabilities": [ + { + "id": "CVE-2019-11358", + "name": "jquery: Prototype pollution in object's prototype leading to denial of service, remote code execution, or property injection", + "description": "jQuery before 3.4.0, as used in Drupal, Backdrop CMS, and other products, mishandles jQuery.extend(true, {}, ...) because of Object.prototype pollution. If an unsanitized source object contained an enumerable __proto__ property, it could extend the native Object.prototype.", + "severity": "Medium", + "solution": "Upgrade jquery to 3.4.0", + "location": { + "dependency": { + "package": { + "name": "jquery" + }, + "version": "3.3.9" + }, + "operating_system": "Unknown", + "image": "Unknown" + }, + "identifiers": [ + { + "type": "cve", + "name": "CVE-2019-11358", + "value": "CVE-2019-11358", + "url": "https://avd.aquasec.com/nvd/cve-2019-11358" + } + ], + "links": [{ + "url": "http://lists.opensuse.org/opensuse-security-announce/2019-08/msg00006.html" + },{ + "url": "http://lists.opensuse.org/opensuse-security-announce/2019-08/msg00025.html" + },{ + "url": "http://packetstormsecurity.com/files/152787/dotCMS-5.1.1-Vulnerable-Dependencies.html" + },{ + "url": "http://packetstormsecurity.com/files/153237/RetireJS-CORS-Issue-Script-Execution.html" + },{ + "url": "http://packetstormsecurity.com/files/156743/OctoberCMS-Insecure-Dependencies.html" + },{ + "url": "http://seclists.org/fulldisclosure/2019/May/10" + },{ + "url": "http://seclists.org/fulldisclosure/2019/May/11" + },{ + "url": "http://seclists.org/fulldisclosure/2019/May/13" + },{ + "url": "http://www.openwall.com/lists/oss-security/2019/06/03/2" + },{ + "url": "http://www.securityfocus.com/bid/108023" + },{ + "url": "https://access.redhat.com/errata/RHBA-2019:1570" + },{ + "url": "https://access.redhat.com/errata/RHSA-2019:1456" + },{ + "url": "https://access.redhat.com/errata/RHSA-2019:2587" + },{ + "url": "https://access.redhat.com/errata/RHSA-2019:3023" + },{ + "url": "https://access.redhat.com/errata/RHSA-2019:3024" + },{ + "url": "https://access.redhat.com/security/cve/CVE-2019-11358" + },{ + "url": "https://backdropcms.org/security/backdrop-sa-core-2019-009" + },{ + "url": "https://blog.jquery.com/2019/04/10/jquery-3-4-0-released/" + },{ + "url": "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11358" + },{ + "url": "https://github.com/DanielRuf/snyk-js-jquery-174006?files=1" + },{ + "url": "https://github.com/advisories/GHSA-6c3j-c64m-qhgq" + },{ + "url": "https://github.com/jquery/jquery/commit/753d591aea698e57d6db58c9f722cd0808619b1b" + },{ + "url": "https://github.com/jquery/jquery/pull/4333" + },{ + "url": "https://github.com/rails/jquery-rails/blob/master/CHANGELOG.md#434" + },{ + "url": "https://hackerone.com/reports/454365" + },{ + "url": "https://kb.pulsesecure.net/articles/Pulse_Security_Advisories/SA44601" + },{ + "url": "https://linux.oracle.com/cve/CVE-2019-11358.html" + },{ + "url": "https://linux.oracle.com/errata/ELSA-2020-4847.html" + },{ + "url": "https://lists.apache.org/thread.html/08720ef215ee7ab3386c05a1a90a7d1c852bf0706f176a7816bf65fc@%3Ccommits.airflow.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/519eb0fd45642dcecd9ff74cb3e71c20a4753f7d82e2f07864b5108f@%3Cdev.drill.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/5928aa293e39d248266472210c50f176cac1535220f2486e6a7fa844@%3Ccommits.airflow.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/6097cdbd6f0a337bedd9bb5cc441b2d525ff002a96531de367e4259f@%3Ccommits.airflow.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/88fb0362fd40e5b605ea8149f63241537b8b6fb5bfa315391fc5cbb7@%3Ccommits.airflow.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/b0656d359c7d40ec9f39c8cc61bca66802ef9a2a12ee199f5b0c1442@%3Cdev.drill.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/b736d0784cf02f5a30fbb4c5902762a15ad6d47e17e2c5a17b7d6205@%3Ccommits.airflow.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/ba79cf1658741e9f146e4c59b50aee56656ea95d841d358d006c18b6@%3Ccommits.roller.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/bcce5a9c532b386c68dab2f6b3ce8b0cc9b950ec551766e76391caa3@%3Ccommits.nifi.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/f9bc3e55f4e28d1dcd1a69aae6d53e609a758e34d2869b4d798e13cc@%3Cissues.drill.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/r2041a75d3fc09dec55adfd95d598b38d22715303f65c997c054844c9@%3Cissues.flink.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/r2baacab6e0acb5a2092eb46ae04fd6c3e8277b4fd79b1ffb7f3254fa@%3Cissues.flink.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/r38f0d1aa3c923c22977fe7376508f030f22e22c1379fbb155bf29766@%3Cdev.syncope.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/r41b5bfe009c845f67d4f68948cc9419ac2d62e287804aafd72892b08@%3Cissues.flink.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/r7aac081cbddb6baa24b75e74abf0929bf309b176755a53e3ed810355@%3Cdev.flink.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/r7d64895cc4dff84d0becfc572b20c0e4bf9bfa7b10c6f5f73e783734@%3Cdev.storm.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/r7e8ebccb7c022e41295f6fdb7b971209b83702339f872ddd8cf8bf73@%3Cissues.flink.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/rac25da84ecdcd36f6de5ad0d255f4e967209bbbebddb285e231da37d@%3Cissues.flink.apache.org%3E" + },{ + "url": "https://lists.apache.org/thread.html/rca37935d661f4689cb4119f1b3b224413b22be161b678e6e6ce0c69b@%3Ccommits.nifi.apache.org%3E" + },{ + "url": "https://lists.debian.org/debian-lts-announce/2019/05/msg00006.html" + },{ + "url": "https://lists.debian.org/debian-lts-announce/2019/05/msg00029.html" + },{ + "url": "https://lists.debian.org/debian-lts-announce/2020/02/msg00024.html" + },{ + "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/4UOAZIFCSZ3ENEFOR5IXX6NFAD3HV7FA/" + },{ + "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/5IABSKTYZ5JUGL735UKGXL5YPRYOPUYI/" + },{ + "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/KYH3OAGR2RTCHRA5NOKX2TES7SNQMWGO/" + },{ + "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/QV3PKZC3PQCO3273HAT76PAQZFBEO4KP/" + },{ + "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/RLXRX23725JL366CNZGJZ7AQQB7LHQ6F/" + },{ + "url": "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/WZW27UCJ5CYFL4KFFFMYMIBNMIU2ALG5/" + },{ + "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-11358" + },{ + "url": "https://seclists.org/bugtraq/2019/Apr/32" + },{ + "url": "https://seclists.org/bugtraq/2019/Jun/12" + },{ + "url": "https://seclists.org/bugtraq/2019/May/18" + },{ + "url": "https://security.netapp.com/advisory/ntap-20190919-0001/" + },{ + "url": "https://snyk.io/vuln/SNYK-JS-JQUERY-174006" + },{ + "url": "https://www.debian.org/security/2019/dsa-4434" + },{ + "url": "https://www.debian.org/security/2019/dsa-4460" + },{ + "url": "https://www.drupal.org/sa-core-2019-006" + },{ + "url": "https://www.oracle.com//security-alerts/cpujul2021.html" + },{ + "url": "https://www.oracle.com/security-alerts/cpuApr2021.html" + },{ + "url": "https://www.oracle.com/security-alerts/cpuapr2020.html" + },{ + "url": "https://www.oracle.com/security-alerts/cpujan2020.html" + },{ + "url": "https://www.oracle.com/security-alerts/cpujan2021.html" + },{ + "url": "https://www.oracle.com/security-alerts/cpujul2020.html" + },{ + "url": "https://www.oracle.com/security-alerts/cpuoct2020.html" + },{ + "url": "https://www.oracle.com/security-alerts/cpuoct2021.html" + },{ + "url": "https://www.oracle.com/technetwork/security-advisory/cpujul2019-5072835.html" + },{ + "url": "https://www.oracle.com/technetwork/security-advisory/cpuoct2019-5072832.html" + },{ + "url": "https://www.privacy-wise.com/mitigating-cve-2019-11358-in-old-versions-of-jquery/" + },{ + "url": "https://www.synology.com/security/advisory/Synology_SA_19_19" + },{ + "url": "https://www.tenable.com/security/tns-2019-08" + },{ + "url": "https://www.tenable.com/security/tns-2020-02" + } + ] + } + ], + "remediations": [] +} From ad3c09e006e134f3c5b879ffc34ce9895a8c860f Mon Sep 17 00:00:00 2001 From: dean Date: Fri, 25 Oct 2024 07:02:00 +0100 Subject: [PATCH 154/183] feat: add end of life date for Ubuntu 24.10 (#7787) --- pkg/detector/ospkg/ubuntu/ubuntu.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/detector/ospkg/ubuntu/ubuntu.go b/pkg/detector/ospkg/ubuntu/ubuntu.go index b396d530d84e..8b36a2b1f87e 100644 --- a/pkg/detector/ospkg/ubuntu/ubuntu.go +++ b/pkg/detector/ospkg/ubuntu/ubuntu.go @@ -62,6 +62,7 @@ var ( "23.04": time.Date(2024, 1, 20, 23, 59, 59, 0, time.UTC), "23.10": time.Date(2024, 6, 30, 23, 59, 59, 0, time.UTC), "24.04": time.Date(2034, 3, 31, 23, 59, 59, 0, time.UTC), + "24.10": time.Date(2025, 7, 9, 23, 59, 59, 0, time.UTC), } ) From a16b830e00bac47ca61bcb929e0b4b89884953e9 Mon Sep 17 00:00:00 2001 From: afdesk Date: Fri, 25 Oct 2024 12:07:30 +0600 Subject: [PATCH 155/183] ci(helm): auto public Helm chart after PR merged (#7526) --- .github/workflows/bypass-test.yaml | 2 + .github/workflows/publish-chart.yaml | 46 +++++++++-- .github/workflows/test.yaml | 1 + magefiles/helm.go | 117 +++++++++++++++++++++++++++ magefiles/helm_test.go | 92 +++++++++++++++++++++ magefiles/magefile.go | 7 ++ 6 files changed, 260 insertions(+), 5 deletions(-) create mode 100644 magefiles/helm.go create mode 100644 magefiles/helm_test.go diff --git a/.github/workflows/bypass-test.yaml b/.github/workflows/bypass-test.yaml index 3a3102e3e574..93c5ba2869d3 100644 --- a/.github/workflows/bypass-test.yaml +++ b/.github/workflows/bypass-test.yaml @@ -9,6 +9,7 @@ on: - 'mkdocs.yml' - 'LICENSE' - '.release-please-manifest.json' + - 'helm/trivy/Chart.yaml' pull_request: paths: - '**.md' @@ -16,6 +17,7 @@ on: - 'mkdocs.yml' - 'LICENSE' - '.release-please-manifest.json' + - 'helm/trivy/Chart.yaml' jobs: test: name: Test diff --git a/.github/workflows/publish-chart.yaml b/.github/workflows/publish-chart.yaml index 3a7db4970065..15c8d84da31d 100644 --- a/.github/workflows/publish-chart.yaml +++ b/.github/workflows/publish-chart.yaml @@ -4,6 +4,11 @@ name: Publish Helm chart on: workflow_dispatch: pull_request: + types: + - opened + - synchronize + - reopened + - closed branches: - main paths: @@ -18,8 +23,10 @@ env: KIND_VERSION: "v0.14.0" KIND_IMAGE: "kindest/node:v1.23.6@sha256:b1fa224cc6c7ff32455e0b1fd9cbfd3d3bc87ecaa8fcb06961ed1afb3db0f9ae" jobs: + # `test-chart` job starts if a PR with Helm Chart is created, merged etc. test-chart: - runs-on: ubuntu-20.04 + if: github.event_name != 'push' + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@v4.1.6 @@ -28,11 +35,12 @@ jobs: - name: Install Helm uses: azure/setup-helm@fe7b79cd5ee1e45176fcad797de68ecaf3ca4814 with: - version: v3.5.0 + version: v3.14.4 - name: Set up python uses: actions/setup-python@v5 with: - python-version: 3.7 + python-version: '3.x' + check-latest: true - name: Setup Chart Linting id: lint uses: helm/chart-testing-action@e6669bcd63d7cb57cb4380c33043eebe5d111992 @@ -48,11 +56,39 @@ jobs: sed -i -e '136s,false,'true',g' ./helm/trivy/values.yaml ct lint-and-install --validate-maintainers=false --charts helm/trivy + # `update-chart-version` job starts if a new tag is pushed + update-chart-version: + if: github.event_name == 'push' + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@v4.1.6 + with: + fetch-depth: 0 + - name: Set up Git user + run: | + git config --global user.email "actions@github.com" + git config --global user.name "GitHub Actions" + + - name: Install tools + uses: aquaproj/aqua-installer@v3.0.1 + with: + aqua_version: v1.25.0 + aqua_opts: "" + + - name: Create a PR with Trivy version + run: mage helm:updateVersion + env: + # Use ORG_REPO_TOKEN instead of GITHUB_TOKEN + # This allows the created PR to trigger tests and other workflows + GITHUB_TOKEN: ${{ secrets.ORG_REPO_TOKEN }} + + # `publish-chart` job starts if a PR with a new Helm Chart is merged or manually publish-chart: - if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' + if: github.event.pull_request.merged == true || github.event_name == 'workflow_dispatch' needs: - test-chart - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - name: Checkout uses: actions/checkout@v4.1.6 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 8932a683c5bc..05edadf93331 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -7,6 +7,7 @@ on: - 'mkdocs.yml' - 'LICENSE' - '.release-please-manifest.json' ## don't run tests for release-please PRs + - 'helm/trivy/Chart.yaml' merge_group: workflow_dispatch: diff --git a/magefiles/helm.go b/magefiles/helm.go new file mode 100644 index 000000000000..443c57eed029 --- /dev/null +++ b/magefiles/helm.go @@ -0,0 +1,117 @@ +//go:build mage_helm + +package main + +import ( + "fmt" + "log" + "os" + + "github.com/aquasecurity/go-version/pkg/semver" + + "github.com/magefile/mage/sh" + "golang.org/x/xerrors" + "gopkg.in/yaml.v3" +) + +const chartFile = "./helm/trivy/Chart.yaml" + +func main() { + trivyVersion, err := version() + if err != nil { + log.Fatalf("could not determine Trivy version: %v", err) + } + + newHelmVersion, err := bumpHelmChart(chartFile, trivyVersion) + if err != nil { + log.Fatalf("could not bump Trivy version to %q: %v", trivyVersion, err) + } + + log.Printf("Current helm version will bump up %q with Trivy %q", newHelmVersion, trivyVersion) + + newBranch := fmt.Sprintf("ci/helm-chart/bump-trivy-to-%s", trivyVersion) + title := fmt.Sprintf("ci(helm): bump Trivy version to %s for Trivy Helm Chart %s", trivyVersion, newHelmVersion) + description := fmt.Sprintf("This PR bumps Trivy up to the %s version for the Trivy Helm chart %s.", + trivyVersion, newHelmVersion) + + cmds := [][]string{ + []string{"git", "switch", "-c", newBranch}, + []string{"git", "add", chartFile}, + []string{"git", "commit", "-m", title}, + []string{"git", "push", "origin", newBranch}, + []string{"gh", "pr", "create", "--base", "main", "--head", newBranch, "--title", title, "--body", description, "--repo", "$GITHUB_REPOSITORY"}, + } + + if err := runShCommands(cmds); err != nil { + log.Fatal(err) + } + log.Print("Successfully created PR with a new helm version") +} + +type Chart struct { + Version string `yaml:"version"` + AppVersion string `yaml:"appVersion"` +} + +// bumpHelmChart bumps up helm and trivy versions inside a file (Chart.yaml) +// it returns a new helm version and error +func bumpHelmChart(filename, trivyVersion string) (string, error) { + input, err := os.ReadFile(filename) + if err != nil { + return "", xerrors.Errorf("could not read file %q: %w", filename, err) + } + currentHelmChart := &Chart{} + if err := yaml.Unmarshal(input, currentHelmChart); err != nil { + return "", xerrors.Errorf("could not unmarshal helm chart %q: %w", filename, err) + } + + newHelmVersion, err := buildNewHelmVersion(currentHelmChart.Version, currentHelmChart.AppVersion, trivyVersion) + if err != nil { + return "", xerrors.Errorf("could not build new helm version: %v", err) + } + cmds := [][]string{ + []string{"sed", "-i", "-e", fmt.Sprintf("s/appVersion: %s/appVersion: %s/g", currentHelmChart.AppVersion, trivyVersion), filename}, + []string{"sed", "-i", "-e", fmt.Sprintf("s/version: %s/version: %s/g", currentHelmChart.Version, newHelmVersion), filename}, + } + + if err := runShCommands(cmds); err != nil { + return "", xerrors.Errorf("could not update Helm Chart %q: %w", newHelmVersion, err) + } + return newHelmVersion, nil +} + +func runShCommands(cmds [][]string) error { + for _, cmd := range cmds { + if err := sh.Run(cmd[0], cmd[1:]...); err != nil { + return xerrors.Errorf("failed to run %v: %w", cmd, err) + } + } + return nil +} + +func buildNewHelmVersion(currentHelm, currentTrivy, newTrivy string) (string, error) { + currentHelmVersion, err := semver.Parse(currentHelm) + if err != nil { + return "", xerrors.Errorf("could not parse current helm version: %w", err) + } + + currentTrivyVersion, err := semver.Parse(currentTrivy) + if err != nil { + return "", xerrors.Errorf("could not parse current trivy version: %w", err) + } + + newTrivyVersion, err := semver.Parse(newTrivy) + if err != nil { + return "", xerrors.Errorf("could not parse new trivy version: %w", err) + } + + if newTrivyVersion.Major().Compare(currentTrivyVersion.Major()) > 0 { + return currentHelmVersion.IncMajor().String(), nil + } + + if newTrivyVersion.Minor().Compare(currentTrivyVersion.Minor()) > 0 { + return currentHelmVersion.IncMinor().String(), nil + } + + return currentHelmVersion.IncPatch().String(), nil +} diff --git a/magefiles/helm_test.go b/magefiles/helm_test.go new file mode 100644 index 000000000000..f2e3233d2879 --- /dev/null +++ b/magefiles/helm_test.go @@ -0,0 +1,92 @@ +//go:build mage_helm + +package main + +import ( + "os" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNewVersion(t *testing.T) { + tests := []struct { + name string + currentHelmVersion string + currentTrivyVersion string + newTrivyVersion string + newHelmVersion string + }{ + { + "created the first patch", + "0.1.0", + "0.55.0", + "0.55.1", + "0.1.1", + }, + { + "created the second patch", + "0.1.1", + "0.55.1", + "0.55.2", + "0.1.2", + }, + { + "created the second patch but helm chart was changed", + "0.1.2", + "0.55.1", + "0.55.2", + "0.1.3", + }, + { + "created a new minor version", + "0.1.1", + "0.55.1", + "0.56.0", + "0.2.0", + }, + { + "created a new major version", + "0.1.1", + "0.55.1", + "1.0.0", + "1.0.0", + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + newHelmVersion, err := buildNewHelmVersion(test.currentHelmVersion, test.currentTrivyVersion, test.newTrivyVersion) + assert.NoError(t, err) + assert.Equal(t, test.newHelmVersion, newHelmVersion) + }) + } +} + +func TestBumpHelmChart_Success(t *testing.T) { + tempFile, err := os.CreateTemp(t.TempDir(), "Chart-*.yaml") + assert.NoError(t, err) + + content := ` +apiVersion: v2 +name: trivy +version: 0.8.0 +appVersion: 0.55.0 +description: Trivy helm chart +keywords: + - scanner + - trivy + - vulnerability +` + err = os.WriteFile(tempFile.Name(), []byte(content), 0644) + assert.NoError(t, err) + + newVersion, err := bumpHelmChart(tempFile.Name(), "0.55.1") + assert.NoError(t, err) + assert.Equal(t, "0.8.1", newVersion) + + updatedContent, err := os.ReadFile(tempFile.Name()) + assert.NoError(t, err) + assert.Contains(t, string(updatedContent), "appVersion: 0.55.1") + assert.Contains(t, string(updatedContent), "version: 0.8.1") +} diff --git a/magefiles/magefile.go b/magefiles/magefile.go index 06ebd7e665e1..f70491bce2e8 100644 --- a/magefiles/magefile.go +++ b/magefiles/magefile.go @@ -489,3 +489,10 @@ func (CloudActions) Generate() error { func VEX(_ context.Context, dir string) error { return sh.RunWith(ENV, "go", "run", "-tags=mage_vex", "./magefiles/vex.go", "--dir", dir) } + +type Helm mg.Namespace + +// UpdateVersion updates a version for Trivy Helm Chart and creates a PR +func (Helm) UpdateVersion() error { + return sh.RunWith(ENV, "go", "run", "-tags=mage_helm", "./magefiles") +} From 63dd3d65a32296eee529c41c41f3221e2cd6d3fe Mon Sep 17 00:00:00 2001 From: okamototk Date: Mon, 28 Oct 2024 15:26:13 +0900 Subject: [PATCH 156/183] docs: add Windows install instructions (#7800) --- docs/getting-started/installation.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md index fd8b19366e86..6e3c8cd0cfd2 100644 --- a/docs/getting-started/installation.md +++ b/docs/getting-started/installation.md @@ -56,6 +56,13 @@ Homebrew for MacOS and Linux. brew install trivy ``` +### Windows (Official) + +1. Download trivy_x.xx.x_windows-64bit.zip file from [releases page](https://github.com/aquasecurity/trivy/releases/). +2. Unzip file and copy to any folder. +3. Ensure PATH environment variable is configured to folder trivy installed. + + ### Arch Linux (Community) Arch Linux Package Repository. From 7a4f4d8b12996687f3095a2042cdf2f5985332c9 Mon Sep 17 00:00:00 2001 From: afdesk Date: Tue, 29 Oct 2024 13:08:13 +0600 Subject: [PATCH 157/183] fix(k8s): support kubernetes v1.31 (#7810) --- go.mod | 16 ++++++++-------- go.sum | 32 ++++++++++++++++---------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index 1611c8c7080a..efc9daa926c9 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/aquasecurity/trivy-checks v1.1.0 github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1 github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 - github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20240707095038-0300bc49b68b + github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20241029051843-2606b7e0f0b4 github.com/aws/aws-sdk-go-v2 v1.31.0 github.com/aws/aws-sdk-go-v2/config v1.27.38 github.com/aws/aws-sdk-go-v2/credentials v1.17.36 @@ -131,7 +131,7 @@ require ( google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v3 v3.0.1 helm.sh/helm/v3 v3.16.1 - k8s.io/api v0.31.0 + k8s.io/api v0.31.2 k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 modernc.org/sqlite v1.33.1 sigs.k8s.io/yaml v1.4.0 @@ -173,7 +173,7 @@ require ( github.com/antchfx/xpath v1.3.1 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect - github.com/aws/aws-sdk-go v1.54.6 // indirect + github.com/aws/aws-sdk-go v1.55.5 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18 // indirect @@ -402,14 +402,14 @@ require ( gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/apiextensions-apiserver v0.31.0 // indirect - k8s.io/apimachinery v0.31.0 // indirect + k8s.io/apimachinery v0.31.2 // indirect k8s.io/apiserver v0.31.0 // indirect - k8s.io/cli-runtime v0.31.0 // indirect - k8s.io/client-go v0.31.0 // indirect - k8s.io/component-base v0.31.0 // indirect + k8s.io/cli-runtime v0.31.2 // indirect + k8s.io/client-go v0.31.2 // indirect + k8s.io/component-base v0.31.2 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect - k8s.io/kubectl v0.31.0 // indirect + k8s.io/kubectl v0.31.2 // indirect modernc.org/gc/v3 v3.0.0-20240107210532-573471604cb6 // indirect modernc.org/libc v1.55.3 // indirect modernc.org/mathutil v1.6.0 // indirect diff --git a/go.sum b/go.sum index 51d43bf95aa1..153c1ab02dea 100644 --- a/go.sum +++ b/go.sum @@ -355,8 +355,8 @@ github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1 h1:G0gnacAOR github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1/go.mod h1:PYkSRx4dlgFATEt+okGwibvbxVEtqsOdH+vX/saACYE= github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 h1:JVgBIuIYbwG+ekC5lUHUpGJboPYiCcxiz06RCtz8neI= github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48/go.mod h1:Ldya37FLi0e/5Cjq2T5Bty7cFkzUDwTcPeQua+2M8i8= -github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20240707095038-0300bc49b68b h1:h7gsIzHyrxpQnayOuQI0kX7+8rVcqhV6G5bM3KVFyJU= -github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20240707095038-0300bc49b68b/go.mod h1:HOhrqoyIeTxpwnKr1EyWtQ+rt2XahV8b0UDBrRpSfEQ= +github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20241029051843-2606b7e0f0b4 h1:i0Z0JS4xtMAcBVOpYSciS7slmIBi1SmjT6garbrJtcA= +github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20241029051843-2606b7e0f0b4/go.mod h1:ctlibFXOQyjWybeVVQI6NLG6GJoPWZJ4cIirQ/wPCQs= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= @@ -364,8 +364,8 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 h1:DklsrG3dyBCFEj5IhUbnKptjxatkF07cF2ak3yi77so= github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:WaHUgvxTVq04UNunO+XhnAqY/wQc+bxr74GqbsZ/Jqw= github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= -github.com/aws/aws-sdk-go v1.54.6 h1:HEYUib3yTt8E6vxjMWM3yAq5b+qjj/6aKA62mkgux9g= -github.com/aws/aws-sdk-go v1.54.6/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= +github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= +github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/aws/aws-sdk-go-v2 v1.31.0 h1:3V05LbxTSItI5kUqNwhJrrrY1BAXxXt0sN0l72QmG5U= github.com/aws/aws-sdk-go-v2 v1.31.0/go.mod h1:ztolYtaEUtdpf9Wftr31CJfLVjOnD/CVRkKOOYgF8hA= github.com/aws/aws-sdk-go-v2/config v1.27.38 h1:mMVyJJuSUdbD4zKXoxDgWrgM60QwlFEg+JhihCq6wCw= @@ -2076,26 +2076,26 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= -k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo= -k8s.io/api v0.31.0/go.mod h1:0YiFF+JfFxMM6+1hQei8FY8M7s1Mth+z/q7eF1aJkTE= +k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= +k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= -k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc= -k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= +k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= k8s.io/apiserver v0.31.0 h1:p+2dgJjy+bk+B1Csz+mc2wl5gHwvNkC9QJV+w55LVrY= k8s.io/apiserver v0.31.0/go.mod h1:KI9ox5Yu902iBnnyMmy7ajonhKnkeZYJhTZ/YI+WEMk= -k8s.io/cli-runtime v0.31.0 h1:V2Q1gj1u3/WfhD475HBQrIYsoryg/LrhhK4RwpN+DhA= -k8s.io/cli-runtime v0.31.0/go.mod h1:vg3H94wsubuvWfSmStDbekvbla5vFGC+zLWqcf+bGDw= -k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8= -k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU= -k8s.io/component-base v0.31.0 h1:/KIzGM5EvPNQcYgwq5NwoQBaOlVFrghoVGr8lG6vNRs= -k8s.io/component-base v0.31.0/go.mod h1:TYVuzI1QmN4L5ItVdMSXKvH7/DtvIuas5/mm8YT3rTo= +k8s.io/cli-runtime v0.31.2 h1:7FQt4C4Xnqx8V1GJqymInK0FFsoC+fAZtbLqgXYVOLQ= +k8s.io/cli-runtime v0.31.2/go.mod h1:XROyicf+G7rQ6FQJMbeDV9jqxzkWXTYD6Uxd15noe0Q= +k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= +k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs= +k8s.io/component-base v0.31.2 h1:Z1J1LIaC0AV+nzcPRFqfK09af6bZ4D1nAOpWsy9owlA= +k8s.io/component-base v0.31.2/go.mod h1:9PeyyFN/drHjtJZMCTkSpQJS3U9OXORnHQqMLDz0sUQ= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= -k8s.io/kubectl v0.31.0 h1:kANwAAPVY02r4U4jARP/C+Q1sssCcN/1p9Nk+7BQKVg= -k8s.io/kubectl v0.31.0/go.mod h1:pB47hhFypGsaHAPjlwrNbvhXgmuAr01ZBvAIIUaI8d4= +k8s.io/kubectl v0.31.2 h1:gTxbvRkMBwvTSAlobiTVqsH6S8Aa1aGyBcu5xYLsn8M= +k8s.io/kubectl v0.31.2/go.mod h1:EyASYVU6PY+032RrTh5ahtSOMgoDRIux9V1JLKtG5xM= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ= From c4347759234dcb5f372b07f92fb4230ef391d710 Mon Sep 17 00:00:00 2001 From: smtan-gl <139748976+smtan-gl@users.noreply.github.com> Date: Tue, 29 Oct 2024 15:26:28 +0800 Subject: [PATCH 158/183] fix(k8s)!: support k8s multi container (#7444) Co-authored-by: afdesk --- pkg/k8s/report/report.go | 16 +-- pkg/k8s/report/report_test.go | 185 ++++++++++++++++++++++++++++------ 2 files changed, 165 insertions(+), 36 deletions(-) diff --git a/pkg/k8s/report/report.go b/pkg/k8s/report/report.go index e71c218bf864..b52391ec8239 100644 --- a/pkg/k8s/report/report.go +++ b/pkg/k8s/report/report.go @@ -57,9 +57,9 @@ type Resource struct { Namespace string `json:",omitempty"` Kind string Name string - Metadata types.Metadata `json:",omitempty"` - Results types.Results `json:",omitempty"` - Error string `json:",omitempty"` + Metadata []types.Metadata `json:",omitempty"` + Results types.Results `json:",omitempty"` + Error string `json:",omitempty"` // original report Report types.Report `json:"-"` @@ -99,11 +99,15 @@ func (r Report) consolidate() ConsolidatedReport { key := v.fullname() if res, ok := index[key]; ok { + // Combine metadata + metadata := lo.UniqBy(append(res.Metadata, v.Metadata...), func(x types.Metadata) string { + return x.ImageID + }) index[key] = Resource{ Namespace: res.Namespace, Kind: res.Kind, Name: res.Name, - Metadata: res.Metadata, + Metadata: metadata, Results: append(res.Results, v.Results...), Error: res.Error, } @@ -214,7 +218,7 @@ func infraResource(misConfig Resource) bool { func CreateResource(artifact *artifacts.Artifact, report types.Report, err error) Resource { r := createK8sResource(artifact, report.Results) - r.Metadata = report.Metadata + r.Metadata = []types.Metadata{report.Metadata} r.Report = report // if there was any error during the scan if err != nil { @@ -244,7 +248,7 @@ func createK8sResource(artifact *artifacts.Artifact, scanResults types.Results) Namespace: artifact.Namespace, Kind: artifact.Kind, Name: artifact.Name, - Metadata: types.Metadata{}, + Metadata: []types.Metadata{}, Results: results, Report: types.Report{ Results: results, diff --git a/pkg/k8s/report/report_test.go b/pkg/k8s/report/report_test.go index e9e9ae5e3a91..1a984eb71b23 100644 --- a/pkg/k8s/report/report_test.go +++ b/pkg/k8s/report/report_test.go @@ -14,12 +14,15 @@ var ( Namespace: "default", Kind: "Deploy", Name: "orion", - Metadata: types.Metadata{ - RepoTags: []string{ - "alpine:3.14", - }, - RepoDigests: []string{ - "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + Metadata: []types.Metadata{ + { + ImageID: "123", + RepoTags: []string{ + "alpine:3.14", + }, + RepoDigests: []string{ + "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + }, }, }, Results: types.Results{ @@ -69,12 +72,15 @@ var ( Namespace: "default", Kind: "Deploy", Name: "orion", - Metadata: types.Metadata{ - RepoTags: []string{ - "alpine:3.14", - }, - RepoDigests: []string{ - "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + Metadata: []types.Metadata{ + { + ImageID: "123", + RepoTags: []string{ + "alpine:3.14", + }, + RepoDigests: []string{ + "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + }, }, }, Results: types.Results{ @@ -113,16 +119,117 @@ var ( }, } + image1WithVulns = Resource{ + Namespace: "default", + Kind: "Pod", + Name: "multi-image-pod", + Metadata: []types.Metadata{ + { + ImageID: "image1", + RepoTags: []string{ + "alpine:3.14", + }, + RepoDigests: []string{ + "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + }, + }, + }, + Results: types.Results{ + { + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2022-1111", + Vulnerability: dbTypes.Vulnerability{Severity: "LOW"}, + }, + }, + }, + }, + } + + image2WithVulns = Resource{ + Namespace: "default", + Kind: "Pod", + Name: "multi-image-pod", + Metadata: []types.Metadata{ + { + ImageID: "image2", + RepoTags: []string{ + "alpine:3.17.3", + }, + RepoDigests: []string{ + "alpine@sha256:124c7d2707904eea7431fffe91522a01e5a861a624ee31d03372cc1d138a3126", + }, + }, + }, + Results: types.Results{ + { + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2022-2222", + Vulnerability: dbTypes.Vulnerability{Severity: "MEDIUM"}, + }, + }, + }, + }, + } + + multiImagePodWithVulns = Resource{ + Namespace: "default", + Kind: "Pod", + Name: "multi-image-pod", + Metadata: []types.Metadata{ + { + ImageID: "image1", + RepoTags: []string{ + "alpine:3.14", + }, + RepoDigests: []string{ + "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + }, + }, + { + ImageID: "image2", + RepoTags: []string{ + "alpine:3.17.3", + }, + RepoDigests: []string{ + "alpine@sha256:124c7d2707904eea7431fffe91522a01e5a861a624ee31d03372cc1d138a3126", + }, + }, + }, + Results: types.Results{ + { + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2022-1111", + Vulnerability: dbTypes.Vulnerability{Severity: "LOW"}, + }, + }, + }, + { + Vulnerabilities: []types.DetectedVulnerability{ + { + VulnerabilityID: "CVE-2022-2222", + Vulnerability: dbTypes.Vulnerability{Severity: "MEDIUM"}, + }, + }, + }, + }, + } + deployOrionWithBothVulnsAndMisconfigs = Resource{ Namespace: "default", Kind: "Deploy", Name: "orion", - Metadata: types.Metadata{ - RepoTags: []string{ - "alpine:3.14", - }, - RepoDigests: []string{ - "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + Metadata: []types.Metadata{ + { + ImageID: "123", + RepoTags: []string{ + "alpine:3.14", + }, + RepoDigests: []string{ + "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + }, }, }, Results: types.Results{ @@ -204,12 +311,15 @@ var ( Namespace: "default", Kind: "Cronjob", Name: "hello", - Metadata: types.Metadata{ - RepoTags: []string{ - "alpine:3.14", - }, - RepoDigests: []string{ - "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + Metadata: []types.Metadata{ + { + ImageID: "123", + RepoTags: []string{ + "alpine:3.14", + }, + RepoDigests: []string{ + "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + }, }, }, Results: types.Results{ @@ -221,12 +331,15 @@ var ( Namespace: "default", Kind: "Pod", Name: "prometheus", - Metadata: types.Metadata{ - RepoTags: []string{ - "alpine:3.14", - }, - RepoDigests: []string{ - "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + Metadata: []types.Metadata{ + { + ImageID: "123", + RepoTags: []string{ + "alpine:3.14", + }, + RepoDigests: []string{ + "alpine:3.14@sha256:8fe1727132b2506c17ba0e1f6a6ed8a016bb1f5735e43b2738cd3fd1979b6260", + }, }, }, Results: types.Results{ @@ -358,6 +471,18 @@ func TestReport_consolidate(t *testing.T) { "default/cronjob/hello": cronjobHelloWithVulns, }, }, + { + name: "report with multi image pod containing vulnerabilities", + report: Report{ + Resources: []Resource{ + image1WithVulns, + image2WithVulns, + }, + }, + expectedFindings: map[string]Resource{ + "default/pod/multi-image-pod": multiImagePodWithVulns, + }, + }, } for _, tt := range tests { From c70b6fa16613fa5482fe4ece9859b2cf60752977 Mon Sep 17 00:00:00 2001 From: simar7 <1254783+simar7@users.noreply.github.com> Date: Tue, 29 Oct 2024 16:29:42 -0600 Subject: [PATCH 159/183] refactor(misconf): Deprecate `EXCEPTIONS` for misconfiguration scanning (#7776) Signed-off-by: Simar --- contrib/junit.tpl | 2 +- docs/docs/configuration/filtering.md | 6 +- .../configuration/cli/trivy_config.md | 2 +- .../configuration/cli/trivy_filesystem.md | 2 +- .../configuration/cli/trivy_image.md | 2 +- .../configuration/cli/trivy_kubernetes.md | 2 +- .../configuration/cli/trivy_repository.md | 2 +- .../configuration/cli/trivy_rootfs.md | 2 +- .../references/configuration/cli/trivy_vm.md | 2 +- .../misconfiguration/check/exceptions.md | 92 --- .../scanner/misconfiguration/custom/debug.md | 2 +- .../scanner/misconfiguration/custom/index.md | 2 +- docs/docs/scanner/misconfiguration/index.md | 22 +- docs/docs/target/container_image.md | 2 +- docs/docs/target/kubernetes.md | 3 +- integration/repo_test.go | 9 - .../dockerfile-custom-policies.json.golden | 3 +- ...dockerfile-namespace-exception.json.golden | 30 - .../dockerfile-rule-exception.json.golden | 3 +- integration/testdata/dockerfile.json.golden | 3 +- .../dockerfile_file_pattern.json.golden | 3 +- .../repo/namespace-exception/Dockerfile | 2 - .../namespace-exception/policy/exception.rego | 8 - integration/testdata/helm.json.golden | 3 +- .../testdata/helm_testchart.json.golden | 9 +- .../helm_testchart.overridden.json.golden | 9 +- mkdocs.yml | 1 - pkg/cache/mock_artifact_cache.go | 3 - pkg/compliance/report/report_test.go | 10 +- pkg/compliance/report/testdata/table_all.txt | 24 +- pkg/compliance/spec/mapper.go | 2 - pkg/compliance/spec/mapper_test.go | 10 +- pkg/fanal/types/misconf.go | 14 +- pkg/flag/misconf_flags.go | 2 +- pkg/iac/rego/exceptions.go | 35 - pkg/iac/rego/scanner.go | 25 +- pkg/iac/rego/scanner_test.go | 162 ----- pkg/iac/scanners/cloudformation/scanner.go | 1 + .../scanners/terraform/executor/executor.go | 1 + pkg/misconf/scanner.go | 2 - pkg/report/table/misconfig.go | 4 +- pkg/report/table/misconfig_test.go | 19 +- pkg/result/filter.go | 6 +- pkg/result/filter_test.go | 20 +- pkg/rpc/convert.go | 24 +- pkg/scanner/local/scan.go | 3 - pkg/scanner/local/scan_test.go | 23 - pkg/types/report.go | 7 +- rpc/cache/service.pb.go | 2 +- rpc/common/service.pb.go | 665 +++++++++--------- rpc/common/service.proto | 3 +- 51 files changed, 430 insertions(+), 865 deletions(-) delete mode 100644 docs/docs/scanner/misconfiguration/check/exceptions.md delete mode 100644 integration/testdata/dockerfile-namespace-exception.json.golden delete mode 100644 integration/testdata/fixtures/repo/namespace-exception/Dockerfile delete mode 100644 integration/testdata/fixtures/repo/namespace-exception/policy/exception.rego delete mode 100644 pkg/iac/rego/exceptions.go diff --git a/contrib/junit.tpl b/contrib/junit.tpl index b01bb9fd22dd..27b654b7b049 100644 --- a/contrib/junit.tpl +++ b/contrib/junit.tpl @@ -16,7 +16,7 @@ {{- if .MisconfSummary }} - + {{- else }} {{- end }} diff --git a/docs/docs/configuration/filtering.md b/docs/docs/configuration/filtering.md index befcc54180ac..22fbe2d7a24d 100644 --- a/docs/docs/configuration/filtering.md +++ b/docs/docs/configuration/filtering.md @@ -112,7 +112,7 @@ trivy config --severity HIGH,CRITICAL examples/misconf/mixed Dockerfile (dockerfile) ======================= -Tests: 17 (SUCCESSES: 16, FAILURES: 1, EXCEPTIONS: 0) +Tests: 17 (SUCCESSES: 16, FAILURES: 1) Failures: 1 (HIGH: 1, CRITICAL: 0) HIGH: Last USER command in Dockerfile should not be 'root' @@ -130,13 +130,13 @@ See https://avd.aquasec.com/misconfig/ds002 deployment.yaml (kubernetes) ============================ -Tests: 8 (SUCCESSES: 8, FAILURES: 0, EXCEPTIONS: 0) +Tests: 8 (SUCCESSES: 8, FAILURES: 0) Failures: 0 (HIGH: 0, CRITICAL: 0) main.tf (terraform) =================== -Tests: 1 (SUCCESSES: 0, FAILURES: 1, EXCEPTIONS: 0) +Tests: 1 (SUCCESSES: 0, FAILURES: 1) Failures: 1 (HIGH: 0, CRITICAL: 1) CRITICAL: Classic resources should not be used. diff --git a/docs/docs/references/configuration/cli/trivy_config.md b/docs/docs/references/configuration/cli/trivy_config.md index 0c279f1e7bf3..804b33725522 100644 --- a/docs/docs/references/configuration/cli/trivy_config.md +++ b/docs/docs/references/configuration/cli/trivy_config.md @@ -32,7 +32,7 @@ trivy config [flags] DIR --ignore-policy string specify the Rego file path to evaluate each vulnerability --ignorefile string specify .trivyignore file (default ".trivyignore") --include-deprecated-checks include deprecated checks - --include-non-failures include successes and exceptions, available with '--scanners misconfig' + --include-non-failures include successes, available with '--scanners misconfig' --k8s-version string specify k8s version to validate outdated api by it (example: 1.21.0) --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) --module-dir string specify directory to the wasm modules that will be loaded (default "$HOME/.trivy/modules") diff --git a/docs/docs/references/configuration/cli/trivy_filesystem.md b/docs/docs/references/configuration/cli/trivy_filesystem.md index bbd5257d5f5d..dd1b2cd7a2e4 100644 --- a/docs/docs/references/configuration/cli/trivy_filesystem.md +++ b/docs/docs/references/configuration/cli/trivy_filesystem.md @@ -55,7 +55,7 @@ trivy filesystem [flags] PATH --ignorefile string specify .trivyignore file (default ".trivyignore") --include-deprecated-checks include deprecated checks --include-dev-deps include development dependencies in the report (supported: npm, yarn) - --include-non-failures include successes and exceptions, available with '--scanners misconfig' + --include-non-failures include successes, available with '--scanners misconfig' --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [ghcr.io/aquasecurity/trivy-java-db:1]) --license-confidence-level float specify license classifier's confidence level (default 0.9) --license-full eagerly look for licenses in source code headers and license files diff --git a/docs/docs/references/configuration/cli/trivy_image.md b/docs/docs/references/configuration/cli/trivy_image.md index 779b54f4d5b9..4a76ca742cad 100644 --- a/docs/docs/references/configuration/cli/trivy_image.md +++ b/docs/docs/references/configuration/cli/trivy_image.md @@ -72,7 +72,7 @@ trivy image [flags] IMAGE_NAME --image-config-scanners strings comma-separated list of what security issues to detect on container image configurations (misconfig,secret) --image-src strings image source(s) to use, in priority order (docker,containerd,podman,remote) (default [docker,containerd,podman,remote]) --include-deprecated-checks include deprecated checks - --include-non-failures include successes and exceptions, available with '--scanners misconfig' + --include-non-failures include successes, available with '--scanners misconfig' --input string input file path instead of image name --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [ghcr.io/aquasecurity/trivy-java-db:1]) --license-confidence-level float specify license classifier's confidence level (default 0.9) diff --git a/docs/docs/references/configuration/cli/trivy_kubernetes.md b/docs/docs/references/configuration/cli/trivy_kubernetes.md index 6b8058cc00f0..1a25e859c3c8 100644 --- a/docs/docs/references/configuration/cli/trivy_kubernetes.md +++ b/docs/docs/references/configuration/cli/trivy_kubernetes.md @@ -69,7 +69,7 @@ trivy kubernetes [flags] [CONTEXT] --include-deprecated-checks include deprecated checks --include-kinds strings indicate the kinds included in scanning (example: node) --include-namespaces strings indicate the namespaces included in scanning (example: kube-system) - --include-non-failures include successes and exceptions, available with '--scanners misconfig' + --include-non-failures include successes, available with '--scanners misconfig' --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [ghcr.io/aquasecurity/trivy-java-db:1]) --k8s-version string specify k8s version to validate outdated api by it (example: 1.21.0) --kubeconfig string specify the kubeconfig file path to use diff --git a/docs/docs/references/configuration/cli/trivy_repository.md b/docs/docs/references/configuration/cli/trivy_repository.md index 190640f5cb2a..5936e0c34a61 100644 --- a/docs/docs/references/configuration/cli/trivy_repository.md +++ b/docs/docs/references/configuration/cli/trivy_repository.md @@ -55,7 +55,7 @@ trivy repository [flags] (REPO_PATH | REPO_URL) --ignorefile string specify .trivyignore file (default ".trivyignore") --include-deprecated-checks include deprecated checks --include-dev-deps include development dependencies in the report (supported: npm, yarn) - --include-non-failures include successes and exceptions, available with '--scanners misconfig' + --include-non-failures include successes, available with '--scanners misconfig' --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [ghcr.io/aquasecurity/trivy-java-db:1]) --license-confidence-level float specify license classifier's confidence level (default 0.9) --license-full eagerly look for licenses in source code headers and license files diff --git a/docs/docs/references/configuration/cli/trivy_rootfs.md b/docs/docs/references/configuration/cli/trivy_rootfs.md index 2f37484d0328..acd1d529a8ef 100644 --- a/docs/docs/references/configuration/cli/trivy_rootfs.md +++ b/docs/docs/references/configuration/cli/trivy_rootfs.md @@ -57,7 +57,7 @@ trivy rootfs [flags] ROOTDIR --ignored-licenses strings specify a list of license to ignore --ignorefile string specify .trivyignore file (default ".trivyignore") --include-deprecated-checks include deprecated checks - --include-non-failures include successes and exceptions, available with '--scanners misconfig' + --include-non-failures include successes, available with '--scanners misconfig' --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [ghcr.io/aquasecurity/trivy-java-db:1]) --license-confidence-level float specify license classifier's confidence level (default 0.9) --license-full eagerly look for licenses in source code headers and license files diff --git a/docs/docs/references/configuration/cli/trivy_vm.md b/docs/docs/references/configuration/cli/trivy_vm.md index 14ce8b78c21a..d4e3692f7e1c 100644 --- a/docs/docs/references/configuration/cli/trivy_vm.md +++ b/docs/docs/references/configuration/cli/trivy_vm.md @@ -51,7 +51,7 @@ trivy vm [flags] VM_IMAGE --ignore-status strings comma-separated list of vulnerability status to ignore (unknown,not_affected,affected,fixed,under_investigation,will_not_fix,fix_deferred,end_of_life) --ignore-unfixed display only fixed vulnerabilities --ignorefile string specify .trivyignore file (default ".trivyignore") - --include-non-failures include successes and exceptions, available with '--scanners misconfig' + --include-non-failures include successes, available with '--scanners misconfig' --java-db-repository strings OCI repository(ies) to retrieve trivy-java-db in order of priority (default [ghcr.io/aquasecurity/trivy-java-db:1]) --list-all-pkgs output all packages in the JSON report regardless of vulnerability --misconfig-scanners strings comma-separated list of misconfig scanners to use for misconfiguration scanning (default [azure-arm,cloudformation,dockerfile,helm,kubernetes,terraform,terraformplan-json,terraformplan-snapshot]) diff --git a/docs/docs/scanner/misconfiguration/check/exceptions.md b/docs/docs/scanner/misconfiguration/check/exceptions.md deleted file mode 100644 index 70ef974a4b74..000000000000 --- a/docs/docs/scanner/misconfiguration/check/exceptions.md +++ /dev/null @@ -1,92 +0,0 @@ -# Exceptions -Exceptions let you specify cases where you allow policy violations. -Trivy supports two types of exceptions. - -!!! info - Exceptions can be applied to built-in checks as well as custom checks. - -## Namespace-based exceptions -There are some cases where you need to disable built-in checks partially or fully. -Namespace-based exceptions lets you rough choose which individual packages to exempt. - -To use namespace-based exceptions, create a Rego rule with the name `exception` that returns the package names to exempt. -The `exception` rule must be defined under `namespace.exceptions`. -`data.namespaces` includes all package names. - - -!!! example - ``` rego - package namespace.exceptions - - import data.namespaces - - exception[ns] { - ns := data.namespaces[_] - startswith(ns, "builtin.kubernetes") - } - ``` - -This example exempts all built-in checks for Kubernetes. - -## Rule-based exceptions -There are some cases where you need more flexibility and granularity in defining which cases to exempt. -Rule-based exceptions lets you granularly choose which individual rules to exempt, while also declaring under which conditions to exempt them. - -To use rule-based exceptions, create a Rego rule with the name `exception` that returns the rule name suffixes to exempt, prefixed by `deny_` (for example, returning `foo` will exempt `deny_foo`). -The rule can make any other assertion, for example, on the input or data documents. -This is useful to specify the exemption for a specific case. - -Note that if you specify the empty string, the exception will match all rules named `deny`. - -``` -exception[rules] { - # Logic - - rules = ["foo","bar"] -} -``` - -The above would provide an exception from `deny_foo` and `deny_bar`. - - -!!! example - ``` - package user.kubernetes.ID100 - - __rego_metadata := { - "id": "ID100", - "title": "Deployment not allowed", - "severity": "HIGH", - "type": "Kubernetes Custom Check", - } - - deny_deployment[msg] { - input.kind == "Deployment" - msg = sprintf("Found deployment '%s' but deployments are not allowed", [name]) - } - - exception[rules] { - input.kind == "Deployment" - input.metadata.name == "allow-deployment" - - rules := ["deployment"] - } - ``` - -If you want to apply rule-based exceptions to built-in checks, you have to define the exception under the same package. - -!!! example - ``` rego - package builtin.kubernetes.KSV012 - - exception[rules] { - input.metadata.name == "can-run-as-root" - rules := [""] - } - ``` - -This exception is applied to [KSV012][ksv012] in trivy-checks. -You can get the package names in the [trivy-checks repository][trivy-checks] or the JSON output from Trivy. - -[ksv012]: https://github.com/aquasecurity/trivy-checks/blob/f36a5b732c4b1293a720c40baab0a7c106ea455e/checks/kubernetes/pss/restricted/3_runs_as_root.rego -[trivy-checks]: https://github.com/aquasecurity/trivy-checks/ \ No newline at end of file diff --git a/docs/docs/scanner/misconfiguration/custom/debug.md b/docs/docs/scanner/misconfiguration/custom/debug.md index 54ec9fd65273..bb7b506c7ece 100644 --- a/docs/docs/scanner/misconfiguration/custom/debug.md +++ b/docs/docs/scanner/misconfiguration/custom/debug.md @@ -12,7 +12,7 @@ $ trivy config --trace configs/ Dockerfile (dockerfile) ======================= -Tests: 23 (SUCCESSES: 21, FAILURES: 2, EXCEPTIONS: 0) +Tests: 23 (SUCCESSES: 21, FAILURES: 2) Failures: 2 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 1, CRITICAL: 0) MEDIUM: Specify a tag in the 'FROM' statement for image 'alpine' diff --git a/docs/docs/scanner/misconfiguration/custom/index.md b/docs/docs/scanner/misconfiguration/custom/index.md index 9598089b8562..d45638f1533d 100644 --- a/docs/docs/scanner/misconfiguration/custom/index.md +++ b/docs/docs/scanner/misconfiguration/custom/index.md @@ -163,7 +163,7 @@ Some fields are displayed in scan results. k.yaml (kubernetes) ─────────────────── -Tests: 32 (SUCCESSES: 31, FAILURES: 1, EXCEPTIONS: 0) +Tests: 32 (SUCCESSES: 31, FAILURES: 1) Failures: 1 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 0, CRITICAL: 0) LOW: Found deployment 'my-deployment' but deployments are not allowed diff --git a/docs/docs/scanner/misconfiguration/index.md b/docs/docs/scanner/misconfiguration/index.md index 368b4522b433..8a2f331b6ab0 100644 --- a/docs/docs/scanner/misconfiguration/index.md +++ b/docs/docs/scanner/misconfiguration/index.md @@ -20,7 +20,7 @@ $ trivy config [YOUR_IaC_DIRECTORY] Dockerfile (dockerfile) ======================= - Tests: 23 (SUCCESSES: 22, FAILURES: 1, EXCEPTIONS: 0) + Tests: 23 (SUCCESSES: 22, FAILURES: 1) Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0) MEDIUM: Specify a tag in the 'FROM' statement for image 'alpine' @@ -75,7 +75,7 @@ You can specify `--scanners vuln,misconfig,secret` to enable vulnerability and s Dockerfile (dockerfile) ======================= - Tests: 17 (SUCCESSES: 16, FAILURES: 1, EXCEPTIONS: 0) + Tests: 17 (SUCCESSES: 16, FAILURES: 1) Failures: 1 (HIGH: 1, CRITICAL: 0) HIGH: Last USER command in Dockerfile should not be 'root' @@ -112,7 +112,7 @@ $ trivy config --severity HIGH,CRITICAL ./iac Dockerfile (dockerfile) -Tests: 21 (SUCCESSES: 20, FAILURES: 1, EXCEPTIONS: 0) +Tests: 21 (SUCCESSES: 20, FAILURES: 1) Failures: 1 (MEDIUM: 0, HIGH: 1, CRITICAL: 0) HIGH: Specify at least 1 USER command in Dockerfile with non-root user as argument @@ -126,7 +126,7 @@ See https://avd.aquasec.com/misconfig/ds002 deployment.yaml (kubernetes) -Tests: 20 (SUCCESSES: 15, FAILURES: 5, EXCEPTIONS: 0) +Tests: 20 (SUCCESSES: 15, FAILURES: 5) Failures: 5 (MEDIUM: 4, HIGH: 1, CRITICAL: 0) MEDIUM: Container 'hello-kubernetes' of Deployment 'hello-kubernetes' should set 'securityContext.allowPrivilegeEscalation' to false @@ -225,7 +225,7 @@ See https://avd.aquasec.com/misconfig/ksv026 mysql-8.8.26.tar:templates/primary/statefulset.yaml (helm) -Tests: 20 (SUCCESSES: 18, FAILURES: 2, EXCEPTIONS: 0) +Tests: 20 (SUCCESSES: 18, FAILURES: 2) Failures: 2 (MEDIUM: 2, HIGH: 0, CRITICAL: 0) MEDIUM: Container 'mysql' of StatefulSet 'mysql' should set 'securityContext.allowPrivilegeEscalation' to false @@ -279,35 +279,35 @@ You can see the config type next to each file name. ``` bash Dockerfile (dockerfile) ======================= -Tests: 23 (SUCCESSES: 22, FAILURES: 1, EXCEPTIONS: 0) +Tests: 23 (SUCCESSES: 22, FAILURES: 1) Failures: 1 (HIGH: 1, CRITICAL: 0) ... deployment.yaml (kubernetes) ============================ -Tests: 28 (SUCCESSES: 15, FAILURES: 13, EXCEPTIONS: 0) +Tests: 28 (SUCCESSES: 15, FAILURES: 13) Failures: 13 (MEDIUM: 4, HIGH: 1, CRITICAL: 0) ... main.tf (terraform) =================== -Tests: 23 (SUCCESSES: 14, FAILURES: 9, EXCEPTIONS: 0) +Tests: 23 (SUCCESSES: 14, FAILURES: 9) Failures: 9 (HIGH: 6, CRITICAL: 1) ... bucket.yaml (cloudformation) ============================ -Tests: 9 (SUCCESSES: 3, FAILURES: 6, EXCEPTIONS: 0) +Tests: 9 (SUCCESSES: 3, FAILURES: 6) Failures: 6 (UNKNOWN: 0, LOW: 0, MEDIUM: 2, HIGH: 4, CRITICAL: 0) ... mysql-8.8.26.tar:templates/primary/statefulset.yaml (helm) ========================================================== -Tests: 20 (SUCCESSES: 18, FAILURES: 2, EXCEPTIONS: 0) +Tests: 20 (SUCCESSES: 18, FAILURES: 2) Failures: 2 (MEDIUM: 2, HIGH: 0, CRITICAL: 0) ``` @@ -381,7 +381,7 @@ deny[res] { $ trivy config --misconfig-scanners=json,yaml --config-check ./serverless.rego --check-namespaces user ./iac serverless.yaml (yaml) -Tests: 4 (SUCCESSES: 3, FAILURES: 1, EXCEPTIONS: 0) +Tests: 4 (SUCCESSES: 3, FAILURES: 1) Failures: 1 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 0, CRITICAL: 0) LOW: Service name "serverless-rest-api-with-pynamodb" is not allowed diff --git a/docs/docs/target/container_image.md b/docs/docs/target/container_image.md index f1c491071a3f..274b43862339 100644 --- a/docs/docs/target/container_image.md +++ b/docs/docs/target/container_image.md @@ -119,7 +119,7 @@ $ trivy image --image-config-scanners misconfig [YOUR_IMAGE_NAME] ``` alpine:3.17 (dockerfile) ======================== -Tests: 24 (SUCCESSES: 21, FAILURES: 3, EXCEPTIONS: 0) +Tests: 24 (SUCCESSES: 21, FAILURES: 3) Failures: 3 (UNKNOWN: 0, LOW: 2, MEDIUM: 0, HIGH: 1, CRITICAL: 0) HIGH: Specify at least 1 USER command in Dockerfile with non-root user as argument diff --git a/docs/docs/target/kubernetes.md b/docs/docs/target/kubernetes.md index 10253aff4c72..291c9fb7728e 100644 --- a/docs/docs/target/kubernetes.md +++ b/docs/docs/target/kubernetes.md @@ -280,8 +280,7 @@ trivy k8s --format json -o results.json cluster "Type": "kubernetes", "MisconfSummary": { "Successes": 20, - "Failures": 19, - "Exceptions": 0 + "Failures": 19 }, "Misconfigurations": [ { diff --git a/integration/repo_test.go b/integration/repo_test.go index 69833bcf2b77..6b4e3a338457 100644 --- a/integration/repo_test.go +++ b/integration/repo_test.go @@ -309,15 +309,6 @@ func TestRepository(t *testing.T) { }, golden: "testdata/dockerfile-rule-exception.json.golden", }, - { - name: "dockerfile with namespace exception", - args: args{ - scanner: types.MisconfigScanner, - policyPaths: []string{"testdata/fixtures/repo/namespace-exception/policy"}, - input: "testdata/fixtures/repo/namespace-exception", - }, - golden: "testdata/dockerfile-namespace-exception.json.golden", - }, { name: "dockerfile with custom policies", args: args{ diff --git a/integration/testdata/dockerfile-custom-policies.json.golden b/integration/testdata/dockerfile-custom-policies.json.golden index 438ecf5d7270..2cbda6f16703 100644 --- a/integration/testdata/dockerfile-custom-policies.json.golden +++ b/integration/testdata/dockerfile-custom-policies.json.golden @@ -22,8 +22,7 @@ "Type": "dockerfile", "MisconfSummary": { "Successes": 27, - "Failures": 2, - "Exceptions": 0 + "Failures": 2 }, "Misconfigurations": [ { diff --git a/integration/testdata/dockerfile-namespace-exception.json.golden b/integration/testdata/dockerfile-namespace-exception.json.golden deleted file mode 100644 index be3a6adfa8d6..000000000000 --- a/integration/testdata/dockerfile-namespace-exception.json.golden +++ /dev/null @@ -1,30 +0,0 @@ -{ - "SchemaVersion": 2, - "CreatedAt": "2021-08-25T12:20:30.000000005Z", - "ArtifactName": "testdata/fixtures/repo/namespace-exception", - "ArtifactType": "repository", - "Metadata": { - "ImageConfig": { - "architecture": "", - "created": "0001-01-01T00:00:00Z", - "os": "", - "rootfs": { - "type": "", - "diff_ids": null - }, - "config": {} - } - }, - "Results": [ - { - "Target": "Dockerfile", - "Class": "config", - "Type": "dockerfile", - "MisconfSummary": { - "Successes": 0, - "Failures": 0, - "Exceptions": 27 - } - } - ] -} diff --git a/integration/testdata/dockerfile-rule-exception.json.golden b/integration/testdata/dockerfile-rule-exception.json.golden index eae4e1e32fd6..eedcb902e145 100644 --- a/integration/testdata/dockerfile-rule-exception.json.golden +++ b/integration/testdata/dockerfile-rule-exception.json.golden @@ -22,8 +22,7 @@ "Type": "dockerfile", "MisconfSummary": { "Successes": 26, - "Failures": 1, - "Exceptions": 0 + "Failures": 1 }, "Misconfigurations": [ { diff --git a/integration/testdata/dockerfile.json.golden b/integration/testdata/dockerfile.json.golden index 3f6dd1b5b201..834b110404c1 100644 --- a/integration/testdata/dockerfile.json.golden +++ b/integration/testdata/dockerfile.json.golden @@ -22,8 +22,7 @@ "Type": "dockerfile", "MisconfSummary": { "Successes": 26, - "Failures": 1, - "Exceptions": 0 + "Failures": 1 }, "Misconfigurations": [ { diff --git a/integration/testdata/dockerfile_file_pattern.json.golden b/integration/testdata/dockerfile_file_pattern.json.golden index fe0372ddc79c..ed917023bc4b 100644 --- a/integration/testdata/dockerfile_file_pattern.json.golden +++ b/integration/testdata/dockerfile_file_pattern.json.golden @@ -22,8 +22,7 @@ "Type": "dockerfile", "MisconfSummary": { "Successes": 26, - "Failures": 1, - "Exceptions": 0 + "Failures": 1 }, "Misconfigurations": [ { diff --git a/integration/testdata/fixtures/repo/namespace-exception/Dockerfile b/integration/testdata/fixtures/repo/namespace-exception/Dockerfile deleted file mode 100644 index fa4b7580b688..000000000000 --- a/integration/testdata/fixtures/repo/namespace-exception/Dockerfile +++ /dev/null @@ -1,2 +0,0 @@ -FROM alpine:3.13 -LABEL user.root="allow" diff --git a/integration/testdata/fixtures/repo/namespace-exception/policy/exception.rego b/integration/testdata/fixtures/repo/namespace-exception/policy/exception.rego deleted file mode 100644 index 74abdccb1933..000000000000 --- a/integration/testdata/fixtures/repo/namespace-exception/policy/exception.rego +++ /dev/null @@ -1,8 +0,0 @@ -package namespace.exceptions - -import data.namespaces - -exception[ns] { - ns := data.namespaces[_] - startswith(ns, "builtin") -} \ No newline at end of file diff --git a/integration/testdata/helm.json.golden b/integration/testdata/helm.json.golden index 518458ac1088..8b9ccb11bc9c 100644 --- a/integration/testdata/helm.json.golden +++ b/integration/testdata/helm.json.golden @@ -22,8 +22,7 @@ "Type": "helm", "MisconfSummary": { "Successes": 80, - "Failures": 14, - "Exceptions": 0 + "Failures": 14 }, "Misconfigurations": [ { diff --git a/integration/testdata/helm_testchart.json.golden b/integration/testdata/helm_testchart.json.golden index 2e659b13e68a..886b0a702496 100644 --- a/integration/testdata/helm_testchart.json.golden +++ b/integration/testdata/helm_testchart.json.golden @@ -22,8 +22,7 @@ "Type": "helm", "MisconfSummary": { "Successes": 90, - "Failures": 4, - "Exceptions": 0 + "Failures": 4 }, "Misconfigurations": [ { @@ -342,8 +341,7 @@ "Type": "helm", "MisconfSummary": { "Successes": 61, - "Failures": 0, - "Exceptions": 0 + "Failures": 0 } }, { @@ -352,8 +350,7 @@ "Type": "helm", "MisconfSummary": { "Successes": 60, - "Failures": 0, - "Exceptions": 0 + "Failures": 0 } } ] diff --git a/integration/testdata/helm_testchart.overridden.json.golden b/integration/testdata/helm_testchart.overridden.json.golden index f4c984daa458..354cb3cbf786 100644 --- a/integration/testdata/helm_testchart.overridden.json.golden +++ b/integration/testdata/helm_testchart.overridden.json.golden @@ -22,8 +22,7 @@ "Type": "helm", "MisconfSummary": { "Successes": 88, - "Failures": 6, - "Exceptions": 0 + "Failures": 6 }, "Misconfigurations": [ { @@ -569,8 +568,7 @@ "Type": "helm", "MisconfSummary": { "Successes": 61, - "Failures": 0, - "Exceptions": 0 + "Failures": 0 } }, { @@ -579,8 +577,7 @@ "Type": "helm", "MisconfSummary": { "Successes": 60, - "Failures": 0, - "Exceptions": 0 + "Failures": 0 } } ] diff --git a/mkdocs.yml b/mkdocs.yml index 00e458e15a91..ab3d51b71275 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -56,7 +56,6 @@ nav: - Overview: docs/scanner/misconfiguration/index.md - Policy: - Built-in Checks: docs/scanner/misconfiguration/check/builtin.md - - Exceptions: docs/scanner/misconfiguration/check/exceptions.md - Custom Checks: - Overview: docs/scanner/misconfiguration/custom/index.md - Data: docs/scanner/misconfiguration/custom/data.md diff --git a/pkg/cache/mock_artifact_cache.go b/pkg/cache/mock_artifact_cache.go index e0b1430337e4..ef9503203a7f 100644 --- a/pkg/cache/mock_artifact_cache.go +++ b/pkg/cache/mock_artifact_cache.go @@ -229,9 +229,6 @@ func (_m *MockArtifactCache) PutBlob(blobID string, blobInfo types.BlobInfo) err for j := range blobInfo.Misconfigurations[i].Warnings { blobInfo.Misconfigurations[i].Warnings[j].Code = types.Code{} } - for j := range blobInfo.Misconfigurations[i].Exceptions { - blobInfo.Misconfigurations[i].Exceptions[j].Code = types.Code{} - } } ret := _m.Called(blobID, blobInfo) diff --git a/pkg/compliance/report/report_test.go b/pkg/compliance/report/report_test.go index e673bd50a24d..5481299b57ea 100644 --- a/pkg/compliance/report/report_test.go +++ b/pkg/compliance/report/report_test.go @@ -36,9 +36,8 @@ func TestBuildComplianceReport(t *testing.T) { Class: types.ClassConfig, Type: ftypes.Kubernetes, MisconfSummary: &types.MisconfSummary{ - Successes: 1, - Failures: 0, - Exceptions: 0, + Successes: 1, + Failures: 0, }, Misconfigurations: []types.DetectedMisconfiguration{ { @@ -158,9 +157,8 @@ func TestBuildComplianceReport(t *testing.T) { Class: types.ClassConfig, Type: ftypes.Kubernetes, MisconfSummary: &types.MisconfSummary{ - Successes: 1, - Failures: 0, - Exceptions: 0, + Successes: 1, + Failures: 0, }, Misconfigurations: []types.DetectedMisconfiguration{ { diff --git a/pkg/compliance/report/testdata/table_all.txt b/pkg/compliance/report/testdata/table_all.txt index 8a789b2ceaa5..159d5f8590ad 100644 --- a/pkg/compliance/report/testdata/table_all.txt +++ b/pkg/compliance/report/testdata/table_all.txt @@ -1,9 +1,9 @@ - -Deployment/metrics-server (kubernetes) -====================================== -Tests: 1 (SUCCESSES: 1, FAILURES: 0, EXCEPTIONS: 0) -Failures: 0 () - + +Deployment/metrics-server (kubernetes) +====================================== +Tests: 1 (SUCCESSES: 1, FAILURES: 0) +Failures: 0 () + MEDIUM: Container 'metrics-server' of Deployment 'metrics-server' should set 'securityContext.allowPrivilegeEscalation' to false ════════════════════════════════════════ A program inside the container can elevate its own privileges and run as root, which might give the program control over the container and node. @@ -24,12 +24,12 @@ See https://avd.aquasec.com/misconfig/ksv001 ──────────────────────────────────────── - -Deployment/metrics-server (kubernetes) -====================================== -Tests: 1 (SUCCESSES: 1, FAILURES: 0, EXCEPTIONS: 0) -Failures: 0 () - + +Deployment/metrics-server (kubernetes) +====================================== +Tests: 1 (SUCCESSES: 1, FAILURES: 0) +Failures: 0 () + LOW: Container 'metrics-server' of Deployment 'metrics-server' should add 'ALL' to 'securityContext.capabilities.drop' ════════════════════════════════════════ The container should drop all default capabilities and add only those that are needed for its execution. diff --git a/pkg/compliance/spec/mapper.go b/pkg/compliance/spec/mapper.go index 6fa5d2bbd45a..8c683753ad90 100644 --- a/pkg/compliance/spec/mapper.go +++ b/pkg/compliance/spec/mapper.go @@ -49,8 +49,6 @@ func misconfigSummary(misconfig types.DetectedMisconfiguration) *types.MisconfSu rms.Successes = 1 case types.MisconfStatusFailure: rms.Failures = 1 - case types.MisconfStatusException: - rms.Exceptions = 1 } return &rms } diff --git a/pkg/compliance/spec/mapper_test.go b/pkg/compliance/spec/mapper_test.go index 62050d27ec47..070c06a8ce96 100644 --- a/pkg/compliance/spec/mapper_test.go +++ b/pkg/compliance/spec/mapper_test.go @@ -61,9 +61,8 @@ func TestMapSpecCheckIDToFilteredResults(t *testing.T) { Class: types.ClassConfig, Type: ftypes.Kubernetes, MisconfSummary: &types.MisconfSummary{ - Successes: 0, - Failures: 1, - Exceptions: 0, + Successes: 0, + Failures: 1, }, Misconfigurations: []types.DetectedMisconfiguration{ { @@ -79,9 +78,8 @@ func TestMapSpecCheckIDToFilteredResults(t *testing.T) { Class: types.ClassConfig, Type: ftypes.Kubernetes, MisconfSummary: &types.MisconfSummary{ - Successes: 0, - Failures: 1, - Exceptions: 0, + Successes: 0, + Failures: 1, }, Misconfigurations: []types.DetectedMisconfiguration{ { diff --git a/pkg/fanal/types/misconf.go b/pkg/fanal/types/misconf.go index 3b4e9b447895..706220f0a1c7 100644 --- a/pkg/fanal/types/misconf.go +++ b/pkg/fanal/types/misconf.go @@ -8,13 +8,12 @@ import ( ) type Misconfiguration struct { - FileType ConfigType `json:",omitempty"` - FilePath string `json:",omitempty"` - Successes MisconfResults `json:",omitempty"` - Warnings MisconfResults `json:",omitempty"` - Failures MisconfResults `json:",omitempty"` - Exceptions MisconfResults `json:",omitempty"` - Layer Layer `json:",omitempty"` + FileType ConfigType `json:",omitempty"` + FilePath string `json:",omitempty"` + Successes MisconfResults `json:",omitempty"` + Warnings MisconfResults `json:",omitempty"` + Failures MisconfResults `json:",omitempty"` + Layer Layer `json:",omitempty"` } type MisconfResult struct { @@ -117,7 +116,6 @@ func ToMisconfigurations(misconfs map[string]Misconfiguration) []Misconfiguratio sort.Sort(misconf.Successes) sort.Sort(misconf.Warnings) sort.Sort(misconf.Failures) - sort.Sort(misconf.Exceptions) results = append(results, misconf) } diff --git a/pkg/flag/misconf_flags.go b/pkg/flag/misconf_flags.go index 128ecfcac42e..421e9c899285 100644 --- a/pkg/flag/misconf_flags.go +++ b/pkg/flag/misconf_flags.go @@ -34,7 +34,7 @@ var ( IncludeNonFailuresFlag = Flag[bool]{ Name: "include-non-failures", ConfigName: "misconfiguration.include-non-failures", - Usage: "include successes and exceptions, available with '--scanners misconfig'", + Usage: "include successes, available with '--scanners misconfig'", } HelmValuesFileFlag = Flag[[]string]{ Name: "helm-values", diff --git a/pkg/iac/rego/exceptions.go b/pkg/iac/rego/exceptions.go deleted file mode 100644 index 591c72abdbbb..000000000000 --- a/pkg/iac/rego/exceptions.go +++ /dev/null @@ -1,35 +0,0 @@ -package rego - -import ( - "context" - "fmt" - - "github.com/open-policy-agent/opa/ast" -) - -func (s *Scanner) isIgnored(ctx context.Context, namespace, ruleName string, input ast.Value) (bool, error) { - if ignored, err := s.isNamespaceIgnored(ctx, namespace, input); err != nil { - return false, err - } else if ignored { - return true, nil - } - return s.isRuleIgnored(ctx, namespace, ruleName, input) -} - -func (s *Scanner) isNamespaceIgnored(ctx context.Context, namespace string, input ast.Value) (bool, error) { - exceptionQuery := fmt.Sprintf("data.namespace.exceptions.exception[_] == %q", namespace) - result, _, err := s.runQuery(ctx, exceptionQuery, input, true) - if err != nil { - return false, fmt.Errorf("query namespace exceptions: %w", err) - } - return result.Allowed(), nil -} - -func (s *Scanner) isRuleIgnored(ctx context.Context, namespace, ruleName string, input ast.Value) (bool, error) { - exceptionQuery := fmt.Sprintf("endswith(%q, data.%s.exception[_][_])", ruleName, namespace) - result, _, err := s.runQuery(ctx, exceptionQuery, input, true) - if err != nil { - return false, err - } - return result.Allowed(), nil -} diff --git a/pkg/iac/rego/scanner.go b/pkg/iac/rego/scanner.go index 9cf80fc83da0..f791a45bf74d 100644 --- a/pkg/iac/rego/scanner.go +++ b/pkg/iac/rego/scanner.go @@ -345,16 +345,7 @@ func (s *Scanner) applyRule(ctx context.Context, namespace, rule string, inputs s.logger.Error("Error occurred while parsing input", log.Err(err)) continue } - if ignored, err := s.isIgnored(ctx, namespace, rule, parsedInput); err != nil { - return nil, err - } else if ignored { - var result regoResult - result.FS = input.FS - result.Filepath = input.Path - result.Managed = true - results.AddIgnored(result) - continue - } + set, traces, err := s.runQuery(ctx, qualified, parsedInput, false) if err != nil { return nil, err @@ -385,20 +376,6 @@ func (s *Scanner) applyRuleCombined(ctx context.Context, namespace, rule string, return nil, fmt.Errorf("failed to parse input: %w", err) } - var results scan.Results - - if ignored, err := s.isIgnored(ctx, namespace, rule, parsed); err != nil { - return nil, err - } else if ignored { - for _, input := range inputs { - var result regoResult - result.FS = input.FS - result.Filepath = input.Path - result.Managed = true - results.AddIgnored(result) - } - return results, nil - } qualified := fmt.Sprintf("data.%s.%s", namespace, rule) set, traces, err := s.runQuery(ctx, qualified, parsed, false) if err != nil { diff --git a/pkg/iac/rego/scanner_test.go b/pkg/iac/rego/scanner_test.go index 1310e56d2ec4..880bc9c1f9f9 100644 --- a/pkg/iac/rego/scanner_test.go +++ b/pkg/iac/rego/scanner_test.go @@ -166,168 +166,6 @@ deny { assert.Equal(t, "/evil.lol", results.GetPassed()[0].Metadata().Range().GetFilename()) } -func Test_RegoScanning_Namespace_Exception(t *testing.T) { - - srcFS := CreateFS(t, map[string]string{ - "policies/test.rego": ` -package defsec.test - -deny { - input.evil -} -`, - "policies/exceptions.rego": ` -package namespace.exceptions - -import data.namespaces - -exception[ns] { - ns := data.namespaces[_] - startswith(ns, "defsec") -} -`, - }) - - scanner := rego.NewScanner( - types.SourceJSON, - rego.WithPolicyDirs("policies"), - ) - require.NoError(t, scanner.LoadPolicies(srcFS)) - - results, err := scanner.ScanInput(context.TODO(), rego.Input{ - Path: "/evil.lol", - Contents: map[string]any{ - "evil": true, - }, - }) - require.NoError(t, err) - - assert.Empty(t, results.GetFailed()) - assert.Empty(t, results.GetPassed()) - assert.Len(t, results.GetIgnored(), 1) - -} - -func Test_RegoScanning_Namespace_Exception_WithoutMatch(t *testing.T) { - - srcFS := CreateFS(t, map[string]string{ - "policies/test.rego": ` -package defsec.test - -deny { - input.evil -} -`, "policies/something.rego": ` -package builtin.test - -deny_something { - input.something -} -`, - "policies/exceptions.rego": ` -package namespace.exceptions - -import data.namespaces - -exception[ns] { - ns := data.namespaces[_] - startswith(ns, "builtin") -} -`, - }) - - scanner := rego.NewScanner( - types.SourceJSON, - rego.WithPolicyDirs("policies"), - ) - require.NoError(t, scanner.LoadPolicies(srcFS)) - - results, err := scanner.ScanInput(context.TODO(), rego.Input{ - Path: "/evil.lol", - Contents: map[string]any{ - "evil": true, - }, - }) - require.NoError(t, err) - - assert.Len(t, results.GetFailed(), 1) - assert.Empty(t, results.GetPassed()) - assert.Len(t, results.GetIgnored(), 1) - -} - -func Test_RegoScanning_Rule_Exception(t *testing.T) { - srcFS := CreateFS(t, map[string]string{ - "policies/test.rego": ` -package defsec.test -deny_evil { - input.evil -} -`, - "policies/exceptions.rego": ` -package defsec.test - -exception[rules] { - rules := ["evil"] -} -`, - }) - - scanner := rego.NewScanner( - types.SourceJSON, - rego.WithPolicyDirs("policies"), - ) - require.NoError(t, scanner.LoadPolicies(srcFS)) - - results, err := scanner.ScanInput(context.TODO(), rego.Input{ - Path: "/evil.lol", - Contents: map[string]any{ - "evil": true, - }, - }) - require.NoError(t, err) - - assert.Empty(t, results.GetFailed()) - assert.Empty(t, results.GetPassed()) - assert.Len(t, results.GetIgnored(), 1) -} - -func Test_RegoScanning_Rule_Exception_WithoutMatch(t *testing.T) { - srcFS := CreateFS(t, map[string]string{ - "policies/test.rego": ` -package defsec.test -deny_evil { - input.evil -} -`, - "policies/exceptions.rego": ` -package defsec.test - -exception[rules] { - rules := ["good"] -} -`, - }) - - scanner := rego.NewScanner( - types.SourceJSON, - rego.WithPolicyDirs("policies"), - ) - require.NoError(t, scanner.LoadPolicies(srcFS)) - - results, err := scanner.ScanInput(context.TODO(), rego.Input{ - Path: "/evil.lol", - Contents: map[string]any{ - "evil": true, - }, - }) - require.NoError(t, err) - - assert.Len(t, results.GetFailed(), 1) - assert.Empty(t, results.GetPassed()) - assert.Empty(t, results.GetIgnored()) -} - func Test_RegoScanning_WithRuntimeValues(t *testing.T) { t.Setenv("DEFSEC_RUNTIME_VAL", "AOK") diff --git a/pkg/iac/scanners/cloudformation/scanner.go b/pkg/iac/scanners/cloudformation/scanner.go index 4497a807506c..0e3fec472b96 100644 --- a/pkg/iac/scanners/cloudformation/scanner.go +++ b/pkg/iac/scanners/cloudformation/scanner.go @@ -205,6 +205,7 @@ func (s *Scanner) scanFileContext(ctx context.Context, regoScanner *rego.Scanner } results = append(results, regoResults...) + // ignore a result based on user input results.Ignore(cfCtx.Ignores, nil) for _, ignored := range results.GetIgnored() { diff --git a/pkg/iac/scanners/terraform/executor/executor.go b/pkg/iac/scanners/terraform/executor/executor.go index 452e47dcc8de..8e14f778e5b4 100644 --- a/pkg/iac/scanners/terraform/executor/executor.go +++ b/pkg/iac/scanners/terraform/executor/executor.go @@ -85,6 +85,7 @@ func (e *Executor) Execute(modules terraform.Modules) (scan.Results, error) { "ignore": attributeIgnorer(modules), } + // ignore a result based on user input results.Ignore(ignores, ignorers) for _, ignored := range results.GetIgnored() { diff --git a/pkg/misconf/scanner.go b/pkg/misconf/scanner.go index 7a3642dfe895..1aa2a5cd5c16 100644 --- a/pkg/misconf/scanner.go +++ b/pkg/misconf/scanner.go @@ -488,8 +488,6 @@ func ResultsToMisconf(configType types.ConfigType, scannerName string, results s switch flattened.Status { case scan.StatusPassed: misconf.Successes = append(misconf.Successes, misconfResult) - case scan.StatusIgnored: - misconf.Exceptions = append(misconf.Exceptions, misconfResult) case scan.StatusFailed: misconf.Failures = append(misconf.Failures, misconfResult) } diff --git a/pkg/report/table/misconfig.go b/pkg/report/table/misconfig.go index dfb724bdf458..41f111d883c9 100644 --- a/pkg/report/table/misconfig.go +++ b/pkg/report/table/misconfig.go @@ -61,8 +61,8 @@ func (r *misconfigRenderer) Render() string { total, summaries := summarize(r.severities, r.countSeverities()) summary := r.result.MisconfSummary - r.printf("Tests: %d (SUCCESSES: %d, FAILURES: %d, EXCEPTIONS: %d)\n", - summary.Successes+summary.Failures+summary.Exceptions, summary.Successes, summary.Failures, summary.Exceptions) + r.printf("Tests: %d (SUCCESSES: %d, FAILURES: %d)\n", + summary.Successes+summary.Failures, summary.Successes, summary.Failures) r.printf("Failures: %d (%s)\n\n", total, strings.Join(summaries, ", ")) for _, m := range r.result.Misconfigurations { diff --git a/pkg/report/table/misconfig_test.go b/pkg/report/table/misconfig_test.go index 785b2621b504..8d17798f673d 100644 --- a/pkg/report/table/misconfig_test.go +++ b/pkg/report/table/misconfig_test.go @@ -24,7 +24,7 @@ func TestMisconfigRenderer(t *testing.T) { name: "single result", input: types.Result{ Target: "my-file", - MisconfSummary: &types.MisconfSummary{Successes: 0, Failures: 1, Exceptions: 0}, + MisconfSummary: &types.MisconfSummary{Successes: 0, Failures: 1}, Misconfigurations: []types.DetectedMisconfiguration{ { ID: "some-alias-for-a-check", @@ -42,7 +42,7 @@ func TestMisconfigRenderer(t *testing.T) { want: ` my-file () ========== -Tests: 1 (SUCCESSES: 0, FAILURES: 1, EXCEPTIONS: 0) +Tests: 1 (SUCCESSES: 0, FAILURES: 1) Failures: 1 (LOW: 0, MEDIUM: 0, HIGH: 1, CRITICAL: 0) AVD-XYZ-0123 (HIGH): Oh no, a bad config. @@ -59,7 +59,7 @@ See https://google.com/search?q=bad%20config name: "single result with code", input: types.Result{ Target: "my-file", - MisconfSummary: &types.MisconfSummary{Successes: 0, Failures: 1, Exceptions: 0}, + MisconfSummary: &types.MisconfSummary{Successes: 0, Failures: 1}, Misconfigurations: []types.DetectedMisconfiguration{ { AVDID: "AVD-XYZ-0123", @@ -101,7 +101,7 @@ See https://google.com/search?q=bad%20config want: ` my-file () ========== -Tests: 1 (SUCCESSES: 0, FAILURES: 1, EXCEPTIONS: 0) +Tests: 1 (SUCCESSES: 0, FAILURES: 1) Failures: 1 (LOW: 0, MEDIUM: 0, HIGH: 1, CRITICAL: 0) AVD-XYZ-0123 (HIGH): Oh no, a bad config. @@ -124,7 +124,7 @@ See https://google.com/search?q=bad%20config name: "multiple results", input: types.Result{ Target: "my-file", - MisconfSummary: &types.MisconfSummary{Successes: 1, Failures: 1, Exceptions: 0}, + MisconfSummary: &types.MisconfSummary{Successes: 1, Failures: 1}, Misconfigurations: []types.DetectedMisconfiguration{ { AVDID: "AVD-XYZ-0123", @@ -172,7 +172,7 @@ See https://google.com/search?q=bad%20config want: ` my-file () ========== -Tests: 2 (SUCCESSES: 1, FAILURES: 1, EXCEPTIONS: 0) +Tests: 2 (SUCCESSES: 1, FAILURES: 1) Failures: 1 (LOW: 0, MEDIUM: 0, HIGH: 1, CRITICAL: 0) FAIL: AVD-XYZ-0123 (HIGH): Oh no, a bad config. @@ -206,9 +206,8 @@ See https://google.com/search?q=bad%20config Class: types.ClassConfig, Type: "terraform", MisconfSummary: &types.MisconfSummary{ - Successes: 5, - Failures: 1, - Exceptions: 0, + Successes: 5, + Failures: 1, }, Misconfigurations: []types.DetectedMisconfiguration{ { @@ -310,7 +309,7 @@ See https://google.com/search?q=bad%20config want: ` terraform-aws-modules/security-group/aws/main.tf (terraform) ============================================================ -Tests: 6 (SUCCESSES: 5, FAILURES: 1, EXCEPTIONS: 0) +Tests: 6 (SUCCESSES: 5, FAILURES: 1) Failures: 1 (LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 1) AVD-AWS-0107 (CRITICAL): Security group rule allows ingress from public internet. diff --git a/pkg/result/filter.go b/pkg/result/filter.go index e1f0e632197e..83e0c0a7170e 100644 --- a/pkg/result/filter.go +++ b/pkg/result/filter.go @@ -130,13 +130,12 @@ func filterMisconfigurations(result *types.Result, severities []string, includeN // Filter by ignore file if f := ignoreConfig.MatchMisconfiguration(misconf.ID, misconf.AVDID, result.Target); f != nil { - result.MisconfSummary.Exceptions++ result.ModifiedFindings = append(result.ModifiedFindings, types.NewModifiedFinding(misconf, types.FindingStatusIgnored, f.Statement, ignoreConfig.FilePath)) continue } - // Count successes, failures, and exceptions + // Count successes and failures summarize(misconf.Status, result.MisconfSummary) if misconf.Status != types.MisconfStatusFailure && !includeNonFailures { @@ -210,8 +209,6 @@ func summarize(status types.MisconfStatus, summary *types.MisconfSummary) { summary.Failures++ case types.MisconfStatusPassed: summary.Successes++ - case types.MisconfStatusException: - summary.Exceptions++ } } @@ -256,7 +253,6 @@ func applyPolicy(ctx context.Context, result *types.Result, policyFile string) e return err } if ignored { - result.MisconfSummary.Exceptions++ switch misconf.Status { case types.MisconfStatusFailure: result.MisconfSummary.Failures-- diff --git a/pkg/result/filter_test.go b/pkg/result/filter_test.go index 0298cd0d9582..289ec2ee0c63 100644 --- a/pkg/result/filter_test.go +++ b/pkg/result/filter_test.go @@ -233,9 +233,8 @@ func TestFilter(t *testing.T) { vuln2, }, MisconfSummary: &types.MisconfSummary{ - Successes: 0, - Failures: 1, - Exceptions: 0, + Successes: 0, + Failures: 1, }, Misconfigurations: []types.DetectedMisconfiguration{ misconf1, @@ -403,9 +402,8 @@ func TestFilter(t *testing.T) { Target: "deployment.yaml", Class: types.ClassConfig, MisconfSummary: &types.MisconfSummary{ - Successes: 1, - Failures: 1, - Exceptions: 1, + Successes: 1, + Failures: 1, }, Misconfigurations: []types.DetectedMisconfiguration{ misconf1, @@ -522,9 +520,8 @@ func TestFilter(t *testing.T) { { Target: "app/Dockerfile", MisconfSummary: &types.MisconfSummary{ - Successes: 0, - Failures: 1, - Exceptions: 2, + Successes: 0, + Failures: 1, }, Misconfigurations: []types.DetectedMisconfiguration{ misconf3, @@ -641,9 +638,8 @@ func TestFilter(t *testing.T) { Results: types.Results{ { MisconfSummary: &types.MisconfSummary{ - Successes: 1, - Failures: 1, - Exceptions: 1, + Successes: 1, + Failures: 1, }, Misconfigurations: []types.DetectedMisconfiguration{ misconf1, diff --git a/pkg/rpc/convert.go b/pkg/rpc/convert.go index 1662877bd597..89097730111b 100644 --- a/pkg/rpc/convert.go +++ b/pkg/rpc/convert.go @@ -754,13 +754,12 @@ func ConvertFromRPCMisconfigurations(rpcMisconfs []*common.Misconfiguration) []f var misconfs []ftypes.Misconfiguration for _, rpcMisconf := range rpcMisconfs { misconfs = append(misconfs, ftypes.Misconfiguration{ - FileType: ftypes.ConfigType(rpcMisconf.FileType), - FilePath: rpcMisconf.FilePath, - Successes: ConvertFromRPCMisconfResults(rpcMisconf.Successes), - Warnings: ConvertFromRPCMisconfResults(rpcMisconf.Warnings), - Failures: ConvertFromRPCMisconfResults(rpcMisconf.Failures), - Exceptions: ConvertFromRPCMisconfResults(rpcMisconf.Exceptions), - Layer: ftypes.Layer{}, + FileType: ftypes.ConfigType(rpcMisconf.FileType), + FilePath: rpcMisconf.FilePath, + Successes: ConvertFromRPCMisconfResults(rpcMisconf.Successes), + Warnings: ConvertFromRPCMisconfResults(rpcMisconf.Warnings), + Failures: ConvertFromRPCMisconfResults(rpcMisconf.Failures), + Layer: ftypes.Layer{}, }) } return misconfs @@ -875,12 +874,11 @@ func ConvertToRPCPutBlobRequest(diffID string, blobInfo ftypes.BlobInfo) *cache. var misconfigurations []*common.Misconfiguration for _, m := range blobInfo.Misconfigurations { misconfigurations = append(misconfigurations, &common.Misconfiguration{ - FileType: string(m.FileType), - FilePath: m.FilePath, - Successes: ConvertToMisconfResults(m.Successes), - Warnings: ConvertToMisconfResults(m.Warnings), - Failures: ConvertToMisconfResults(m.Failures), - Exceptions: ConvertToMisconfResults(m.Exceptions), + FileType: string(m.FileType), + FilePath: m.FilePath, + Successes: ConvertToMisconfResults(m.Successes), + Warnings: ConvertToMisconfResults(m.Warnings), + Failures: ConvertToMisconfResults(m.Failures), }) } diff --git a/pkg/scanner/local/scan.go b/pkg/scanner/local/scan.go index f34723058e06..58cd4cc00167 100644 --- a/pkg/scanner/local/scan.go +++ b/pkg/scanner/local/scan.go @@ -210,9 +210,6 @@ func (s Scanner) MisconfsToResults(misconfs []ftypes.Misconfiguration) types.Res for _, w := range misconf.Successes { detected = append(detected, toDetectedMisconfiguration(w, dbTypes.SeverityUnknown, types.MisconfStatusPassed, misconf.Layer)) } - for _, w := range misconf.Exceptions { - detected = append(detected, toDetectedMisconfiguration(w, dbTypes.SeverityUnknown, types.MisconfStatusException, misconf.Layer)) - } results = append(results, types.Result{ Target: misconf.FilePath, diff --git a/pkg/scanner/local/scan_test.go b/pkg/scanner/local/scan_test.go index f3e6cac5d3fa..bdeb5166a2fa 100644 --- a/pkg/scanner/local/scan_test.go +++ b/pkg/scanner/local/scan_test.go @@ -820,17 +820,6 @@ func TestScanner_Scan(t *testing.T) { }, }, }, - Exceptions: ftypes.MisconfResults{ - { - Namespace: "main.kubernetes.id100", - PolicyMetadata: ftypes.PolicyMetadata{ - ID: "ID100", - Type: "Kubernetes Security Check", - Title: "Bad Deployment", - Severity: "HIGH", - }, - }, - }, Layer: ftypes.Layer{ DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", }, @@ -922,18 +911,6 @@ func TestScanner_Scan(t *testing.T) { DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", }, }, - { - Type: "Kubernetes Security Check", - ID: "ID100", - Title: "Bad Deployment", - Message: "No issues found", - Namespace: "main.kubernetes.id100", - Severity: "HIGH", - Status: types.MisconfStatusException, - Layer: ftypes.Layer{ - DiffID: "sha256:9922bc15eeefe1637b803ef2106f178152ce19a391f24aec838cbe2e48e73303", - }, - }, }, }, }, diff --git a/pkg/types/report.go b/pkg/types/report.go index af364c95a11d..3ada68a942d8 100644 --- a/pkg/types/report.go +++ b/pkg/types/report.go @@ -130,13 +130,12 @@ func (r *Result) IsEmpty() bool { } type MisconfSummary struct { - Successes int - Failures int - Exceptions int + Successes int + Failures int } func (s MisconfSummary) Empty() bool { - return s.Successes == 0 && s.Failures == 0 && s.Exceptions == 0 + return s.Successes == 0 && s.Failures == 0 } // Failed returns whether the result includes any vulnerabilities, misconfigurations or secrets diff --git a/rpc/cache/service.pb.go b/rpc/cache/service.pb.go index d3a1fa1a63b9..acca9623e93a 100644 --- a/rpc/cache/service.pb.go +++ b/rpc/cache/service.pb.go @@ -1,6 +1,6 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.27.1 +// protoc-gen-go v1.34.0 // protoc v3.19.4 // source: rpc/cache/service.proto diff --git a/rpc/common/service.pb.go b/rpc/common/service.pb.go index 4c7f0af79464..c8290cc52818 100644 --- a/rpc/common/service.pb.go +++ b/rpc/common/service.pb.go @@ -755,12 +755,11 @@ type Misconfiguration struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - FileType string `protobuf:"bytes,1,opt,name=file_type,json=fileType,proto3" json:"file_type,omitempty"` - FilePath string `protobuf:"bytes,2,opt,name=file_path,json=filePath,proto3" json:"file_path,omitempty"` - Successes []*MisconfResult `protobuf:"bytes,3,rep,name=successes,proto3" json:"successes,omitempty"` - Warnings []*MisconfResult `protobuf:"bytes,4,rep,name=warnings,proto3" json:"warnings,omitempty"` - Failures []*MisconfResult `protobuf:"bytes,5,rep,name=failures,proto3" json:"failures,omitempty"` - Exceptions []*MisconfResult `protobuf:"bytes,6,rep,name=exceptions,proto3" json:"exceptions,omitempty"` + FileType string `protobuf:"bytes,1,opt,name=file_type,json=fileType,proto3" json:"file_type,omitempty"` + FilePath string `protobuf:"bytes,2,opt,name=file_path,json=filePath,proto3" json:"file_path,omitempty"` + Successes []*MisconfResult `protobuf:"bytes,3,rep,name=successes,proto3" json:"successes,omitempty"` + Warnings []*MisconfResult `protobuf:"bytes,4,rep,name=warnings,proto3" json:"warnings,omitempty"` + Failures []*MisconfResult `protobuf:"bytes,5,rep,name=failures,proto3" json:"failures,omitempty"` } func (x *Misconfiguration) Reset() { @@ -830,13 +829,6 @@ func (x *Misconfiguration) GetFailures() []*MisconfResult { return nil } -func (x *Misconfiguration) GetExceptions() []*MisconfResult { - if x != nil { - return x.Exceptions - } - return nil -} - type MisconfResult struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2482,7 +2474,7 @@ var file_rpc_common_service_proto_rawDesc = []byte{ 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x65, 0x6e, - 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x22, 0xb6, 0x02, 0x0a, 0x10, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, + 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x22, 0xff, 0x01, 0x0a, 0x10, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, @@ -2498,300 +2490,296 @@ var file_rpc_common_service_proto_rawDesc = []byte{ 0x75, 0x72, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x08, 0x66, 0x61, 0x69, 0x6c, 0x75, 0x72, 0x65, - 0x73, 0x12, 0x3b, 0x0a, 0x0a, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x52, 0x0a, 0x65, 0x78, 0x63, 0x65, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xf3, - 0x01, 0x0a, 0x0d, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, - 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x18, - 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x45, 0x0a, 0x0f, 0x70, 0x6f, 0x6c, 0x69, - 0x63, 0x79, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, - 0x0e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, - 0x42, 0x0a, 0x0e, 0x63, 0x61, 0x75, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, - 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x63, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x07, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x52, - 0x02, 0x69, 0x64, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, - 0x72, 0x69, 0x74, 0x79, 0x22, 0xf0, 0x01, 0x0a, 0x0e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x64, 0x76, 0x5f, 0x69, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x64, 0x76, 0x49, 0x64, 0x12, 0x12, - 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, - 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, - 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, - 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x2f, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, - 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x65, 0x64, - 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, - 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x66, - 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x22, 0xf7, 0x03, 0x0a, 0x18, 0x44, 0x65, 0x74, 0x65, - 0x63, 0x74, 0x65, 0x64, 0x4d, 0x69, 0x73, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, - 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, - 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, - 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x73, 0x6f, - 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, - 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, - 0x72, 0x69, 0x74, 0x79, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, - 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, - 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x1f, 0x0a, 0x0b, - 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x55, 0x72, 0x6c, 0x12, 0x1e, 0x0a, - 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x16, 0x0a, - 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0c, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, - 0x12, 0x42, 0x0a, 0x0e, 0x63, 0x61, 0x75, 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x63, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x12, 0x15, 0x0a, 0x06, 0x61, 0x76, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x0e, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x76, 0x64, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x71, - 0x75, 0x65, 0x72, 0x79, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, - 0x79, 0x22, 0xff, 0x09, 0x0a, 0x0d, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, - 0x69, 0x74, 0x79, 0x12, 0x29, 0x0a, 0x10, 0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, - 0x6c, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x76, - 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x64, 0x12, 0x19, - 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x56, - 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, - 0x69, 0x78, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, - 0x69, 0x74, 0x6c, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, + 0x73, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x07, 0x22, 0xf3, 0x01, 0x0a, 0x0d, 0x4d, 0x69, 0x73, 0x63, + 0x6f, 0x6e, 0x66, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, + 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, + 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, + 0x65, 0x12, 0x45, 0x0a, 0x0f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x5f, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x72, 0x69, + 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0e, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x42, 0x0a, 0x0e, 0x63, 0x61, 0x75, 0x73, + 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x43, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, 0x63, + 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4a, 0x04, 0x08, 0x03, + 0x10, 0x07, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x52, 0x02, 0x69, 0x64, 0x52, 0x05, 0x74, 0x69, + 0x74, 0x6c, 0x65, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x22, 0xf0, 0x01, + 0x0a, 0x0e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, + 0x12, 0x15, 0x0a, 0x06, 0x61, 0x64, 0x76, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x61, 0x64, 0x76, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x74, + 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, - 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, - 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, - 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x66, - 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x42, 0x0a, 0x0e, 0x70, 0x6b, 0x67, 0x5f, 0x69, - 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, - 0x6b, 0x67, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0d, 0x70, 0x6b, - 0x67, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x65, 0x72, 0x12, 0x29, 0x0a, 0x05, 0x6c, - 0x61, 0x79, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, - 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, - 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, - 0x74, 0x79, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x0e, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, - 0x39, 0x0a, 0x04, 0x63, 0x76, 0x73, 0x73, 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, - 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x56, 0x75, 0x6c, - 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x43, 0x76, 0x73, 0x73, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x63, 0x76, 0x73, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x63, 0x77, - 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0d, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x63, 0x77, 0x65, - 0x49, 0x64, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x75, - 0x72, 0x6c, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, - 0x79, 0x55, 0x72, 0x6c, 0x12, 0x41, 0x0a, 0x0e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, - 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, + 0x2f, 0x0a, 0x13, 0x72, 0x65, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x5f, 0x61, + 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x72, 0x65, + 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x64, 0x65, 0x64, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x08, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, + 0x22, 0xf7, 0x03, 0x0a, 0x18, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4d, 0x69, 0x73, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, + 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x08, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, 0x76, + 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, + 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6d, + 0x61, 0x72, 0x79, 0x55, 0x72, 0x6c, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, + 0x6e, 0x63, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x66, 0x65, + 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x29, + 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, + 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, + 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x42, 0x0a, 0x0e, 0x63, 0x61, 0x75, + 0x73, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x0d, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x43, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x0d, + 0x63, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x15, 0x0a, + 0x06, 0x61, 0x76, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, + 0x76, 0x64, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x0f, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x22, 0xff, 0x09, 0x0a, 0x0d, 0x56, + 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x29, 0x0a, 0x10, + 0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x76, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, + 0x69, 0x6c, 0x69, 0x74, 0x79, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x2b, 0x0a, 0x11, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x5f, + 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x65, 0x64, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x23, 0x0a, 0x0d, 0x66, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x66, 0x69, 0x78, 0x65, 0x64, 0x56, 0x65, 0x72, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x32, 0x0a, 0x08, + 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, + 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, + 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, + 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x08, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, + 0x12, 0x42, 0x0a, 0x0e, 0x70, 0x6b, 0x67, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, + 0x65, 0x72, 0x18, 0x19, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x50, 0x6b, 0x67, 0x49, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x66, 0x69, 0x65, 0x72, 0x52, 0x0d, 0x70, 0x6b, 0x67, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, + 0x66, 0x69, 0x65, 0x72, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, + 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, + 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, + 0x74, 0x79, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x39, 0x0a, 0x04, 0x63, 0x76, 0x73, 0x73, + 0x18, 0x0c, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, + 0x69, 0x74, 0x79, 0x2e, 0x43, 0x76, 0x73, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x63, + 0x76, 0x73, 0x73, 0x12, 0x17, 0x0a, 0x07, 0x63, 0x77, 0x65, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x0d, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x63, 0x77, 0x65, 0x49, 0x64, 0x73, 0x12, 0x1f, 0x0a, 0x0b, + 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x0e, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0a, 0x70, 0x72, 0x69, 0x6d, 0x61, 0x72, 0x79, 0x55, 0x72, 0x6c, 0x12, 0x41, 0x0a, + 0x0e, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, + 0x0f, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x0d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, + 0x12, 0x48, 0x0a, 0x12, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, + 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x10, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, - 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, - 0x68, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x12, 0x48, 0x0a, 0x12, 0x6c, 0x61, 0x73, 0x74, 0x5f, - 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x10, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, - 0x10, 0x6c, 0x61, 0x73, 0x74, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, 0x61, 0x74, - 0x65, 0x12, 0x48, 0x0a, 0x14, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x61, 0x64, 0x76, 0x69, - 0x73, 0x6f, 0x72, 0x79, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x41, - 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x79, 0x44, 0x61, 0x74, 0x61, 0x12, 0x40, 0x0a, 0x10, 0x63, - 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x76, 0x75, 0x6c, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, - 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x63, - 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x56, 0x75, 0x6c, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1d, 0x0a, - 0x0a, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, - 0x09, 0x52, 0x09, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x0b, - 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0a, 0x64, 0x61, 0x74, - 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x58, 0x0a, 0x0f, 0x76, 0x65, 0x6e, 0x64, 0x6f, - 0x72, 0x5f, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x15, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x2f, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x56, 0x65, - 0x6e, 0x64, 0x6f, 0x72, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x52, 0x0e, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, - 0x79, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x16, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, 0x67, 0x50, 0x61, 0x74, 0x68, 0x12, 0x15, 0x0a, 0x06, - 0x70, 0x6b, 0x67, 0x5f, 0x69, 0x64, 0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x6b, - 0x67, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x18, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x1a, 0x4b, 0x0a, 0x09, 0x43, - 0x76, 0x73, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x28, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x72, 0x69, 0x76, - 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x56, 0x53, 0x53, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x59, 0x0a, 0x13, 0x56, 0x65, 0x6e, 0x64, - 0x6f, 0x72, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, - 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, - 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, - 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, - 0x02, 0x38, 0x01, 0x22, 0x42, 0x0a, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x22, 0x57, 0x0a, 0x05, 0x4c, 0x61, 0x79, 0x65, 0x72, - 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x69, 0x66, 0x66, - 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x66, 0x66, 0x49, - 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, - 0x22, 0xc3, 0x01, 0x0a, 0x0d, 0x43, 0x61, 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1a, - 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x69, - 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, - 0x69, 0x6e, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x26, - 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, - 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x64, 0x65, - 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x76, 0x0a, 0x04, 0x43, 0x56, 0x53, 0x53, 0x12, 0x1b, - 0x0a, 0x09, 0x76, 0x32, 0x5f, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x76, 0x32, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x76, - 0x33, 0x5f, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x76, 0x33, 0x56, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x32, 0x5f, 0x73, - 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x76, 0x32, 0x53, 0x63, - 0x6f, 0x72, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x33, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x76, 0x33, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x98, - 0x01, 0x0a, 0x0e, 0x43, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, - 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, - 0x74, 0x68, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x2a, 0x0a, - 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, - 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0xf3, 0x01, 0x0a, 0x04, 0x4c, 0x69, - 0x6e, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x05, 0x52, 0x06, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, - 0x74, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x63, 0x61, 0x75, 0x73, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x43, 0x61, 0x75, 0x73, 0x65, 0x12, - 0x1e, 0x0a, 0x0a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, - 0x1c, 0x0a, 0x09, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x09, 0x74, 0x72, 0x75, 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x20, 0x0a, - 0x0b, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x12, - 0x1f, 0x0a, 0x0b, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x75, 0x73, 0x65, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, 0x43, 0x61, 0x75, 0x73, 0x65, - 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x63, 0x61, 0x75, 0x73, 0x65, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x43, 0x61, 0x75, 0x73, 0x65, 0x22, - 0x30, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x28, 0x0a, 0x05, 0x6c, 0x69, 0x6e, 0x65, 0x73, - 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x6e, 0x65, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x65, - 0x73, 0x22, 0x9f, 0x02, 0x0a, 0x0d, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x46, 0x69, 0x6e, 0x64, - 0x69, 0x6e, 0x67, 0x12, 0x17, 0x0a, 0x07, 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x75, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, - 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, - 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, - 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, - 0x72, 0x69, 0x74, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, - 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, - 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x65, 0x6e, 0x64, - 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x07, 0x20, 0x01, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x10, 0x6c, 0x61, 0x73, 0x74, 0x4d, 0x6f, + 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x44, 0x61, 0x74, 0x65, 0x12, 0x48, 0x0a, 0x14, 0x63, 0x75, + 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x61, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x79, 0x5f, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x11, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x52, 0x12, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x41, 0x64, 0x76, 0x69, 0x73, 0x6f, 0x72, 0x79, + 0x44, 0x61, 0x74, 0x61, 0x12, 0x40, 0x0a, 0x10, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x5f, 0x76, + 0x75, 0x6c, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x18, 0x12, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x56, 0x75, + 0x6c, 0x6e, 0x44, 0x61, 0x74, 0x61, 0x12, 0x1d, 0x0a, 0x0a, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, + 0x5f, 0x69, 0x64, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x76, 0x65, 0x6e, 0x64, + 0x6f, 0x72, 0x49, 0x64, 0x73, 0x12, 0x39, 0x0a, 0x0b, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x18, 0x14, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x74, 0x72, 0x69, + 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x52, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x12, 0x58, 0x0a, 0x0f, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x73, 0x65, 0x76, 0x65, 0x72, + 0x69, 0x74, 0x79, 0x18, 0x15, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x74, 0x72, 0x69, 0x76, + 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x56, 0x75, 0x6c, 0x6e, 0x65, 0x72, 0x61, + 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x2e, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x53, 0x65, 0x76, + 0x65, 0x72, 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0e, 0x76, 0x65, 0x6e, 0x64, + 0x6f, 0x72, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6b, + 0x67, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, + 0x67, 0x50, 0x61, 0x74, 0x68, 0x12, 0x15, 0x0a, 0x06, 0x70, 0x6b, 0x67, 0x5f, 0x69, 0x64, 0x18, + 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x6b, 0x67, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, + 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x18, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x1a, 0x4b, 0x0a, 0x09, 0x43, 0x76, 0x73, 0x73, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, + 0x6b, 0x65, 0x79, 0x12, 0x28, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x61, 0x74, - 0x63, 0x68, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, - 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x4a, 0x04, 0x08, - 0x09, 0x10, 0x0a, 0x22, 0x5d, 0x0a, 0x06, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1a, 0x0a, - 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, 0x74, 0x68, 0x12, 0x37, 0x0a, 0x08, 0x66, 0x69, 0x6e, - 0x64, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, - 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, - 0x74, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x08, 0x66, 0x69, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x73, 0x22, 0x99, 0x02, 0x0a, 0x0f, 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4c, - 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, - 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, - 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, - 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x3e, 0x0a, 0x08, 0x63, 0x61, - 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x74, + 0x6e, 0x2e, 0x43, 0x56, 0x53, 0x53, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, + 0x01, 0x1a, 0x59, 0x0a, 0x13, 0x56, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x53, 0x65, 0x76, 0x65, 0x72, + 0x69, 0x74, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x2c, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, + 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, + 0x79, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x42, 0x0a, 0x0a, + 0x44, 0x61, 0x74, 0x61, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x10, + 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, + 0x22, 0x57, 0x0a, 0x05, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x06, 0x64, 0x69, 0x67, + 0x65, 0x73, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x67, 0x65, 0x73, + 0x74, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x69, 0x66, 0x66, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x06, 0x64, 0x69, 0x66, 0x66, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x22, 0xc3, 0x01, 0x0a, 0x0d, 0x43, 0x61, + 0x75, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x1d, 0x0a, + 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x19, 0x0a, 0x08, + 0x65, 0x6e, 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, + 0x65, 0x6e, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x26, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, + 0x76, 0x0a, 0x04, 0x43, 0x56, 0x53, 0x53, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x32, 0x5f, 0x76, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x32, 0x56, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x33, 0x5f, 0x76, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x33, 0x56, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x12, 0x19, 0x0a, 0x08, 0x76, 0x32, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x01, 0x52, 0x07, 0x76, 0x32, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x19, 0x0a, 0x08, + 0x76, 0x33, 0x5f, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, + 0x76, 0x33, 0x53, 0x63, 0x6f, 0x72, 0x65, 0x22, 0x98, 0x01, 0x0a, 0x0e, 0x43, 0x75, 0x73, 0x74, + 0x6f, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1b, + 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x29, 0x0a, 0x05, 0x6c, + 0x61, 0x79, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, + 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, + 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x2a, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x04, 0x64, 0x61, + 0x74, 0x61, 0x22, 0xf3, 0x01, 0x0a, 0x04, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6e, + 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x6e, 0x75, 0x6d, + 0x62, 0x65, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x0a, + 0x08, 0x69, 0x73, 0x5f, 0x63, 0x61, 0x75, 0x73, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x07, 0x69, 0x73, 0x43, 0x61, 0x75, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x61, 0x6e, 0x6e, 0x6f, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x61, 0x6e, + 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x72, 0x75, 0x6e, + 0x63, 0x61, 0x74, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x74, 0x72, 0x75, + 0x6e, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x68, 0x69, 0x67, 0x68, 0x6c, 0x69, + 0x67, 0x68, 0x74, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x68, 0x69, 0x67, + 0x68, 0x6c, 0x69, 0x67, 0x68, 0x74, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x66, 0x69, 0x72, 0x73, + 0x74, 0x5f, 0x63, 0x61, 0x75, 0x73, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x66, + 0x69, 0x72, 0x73, 0x74, 0x43, 0x61, 0x75, 0x73, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x6c, 0x61, 0x73, + 0x74, 0x5f, 0x63, 0x61, 0x75, 0x73, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6c, + 0x61, 0x73, 0x74, 0x43, 0x61, 0x75, 0x73, 0x65, 0x22, 0x30, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, + 0x12, 0x28, 0x0a, 0x05, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x12, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, + 0x69, 0x6e, 0x65, 0x52, 0x05, 0x6c, 0x69, 0x6e, 0x65, 0x73, 0x22, 0x9f, 0x02, 0x0a, 0x0d, 0x53, + 0x65, 0x63, 0x72, 0x65, 0x74, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x17, 0x0a, 0x07, + 0x72, 0x75, 0x6c, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, + 0x75, 0x6c, 0x65, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, + 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, + 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x14, 0x0a, + 0x05, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x74, 0x69, + 0x74, 0x6c, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x6c, 0x69, 0x6e, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x4c, 0x69, + 0x6e, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x6c, 0x69, 0x6e, 0x65, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x26, 0x0a, + 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x74, 0x72, + 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, + 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x18, 0x08, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x12, 0x29, 0x0a, 0x05, 0x6c, + 0x61, 0x79, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, + 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, + 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x4a, 0x04, 0x08, 0x09, 0x10, 0x0a, 0x22, 0x5d, 0x0a, 0x06, + 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, + 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x70, 0x61, + 0x74, 0x68, 0x12, 0x37, 0x0a, 0x08, 0x66, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, + 0x67, 0x52, 0x08, 0x66, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x99, 0x02, 0x0a, 0x0f, + 0x44, 0x65, 0x74, 0x65, 0x63, 0x74, 0x65, 0x64, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x12, + 0x32, 0x0a, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, + 0x2e, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x52, 0x08, 0x73, 0x65, 0x76, 0x65, 0x72, + 0x69, 0x74, 0x79, 0x12, 0x3e, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, + 0x67, 0x6f, 0x72, 0x79, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, + 0x6f, 0x72, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, + 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x02, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, + 0x69, 0x6e, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x22, 0xed, 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x63, 0x65, + 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x41, 0x0a, 0x0c, 0x6c, 0x69, 0x63, 0x65, 0x6e, + 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, + 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, + 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x0b, 0x6c, + 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, + 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, + 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x69, 0x6e, 0x67, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6e, 0x64, 0x69, + 0x6e, 0x67, 0x52, 0x08, 0x66, 0x69, 0x6e, 0x67, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x29, 0x0a, 0x05, + 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, + 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, + 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x22, 0x98, 0x01, 0x0a, 0x0e, 0x4c, 0x69, 0x63, 0x65, + 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x12, 0x3e, 0x0a, 0x08, 0x63, 0x61, + 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x2e, 0x45, 0x6e, 0x75, 0x6d, - 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x70, 0x6b, - 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x6b, - 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, - 0x74, 0x68, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, - 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, - 0x65, 0x6e, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, - 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x65, - 0x78, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, 0x22, 0xed, - 0x01, 0x0a, 0x0b, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x41, - 0x0a, 0x0c, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x2e, - 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x0b, 0x6c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x19, - 0x0a, 0x08, 0x70, 0x6b, 0x67, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x70, 0x6b, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x38, 0x0a, 0x08, 0x66, 0x69, 0x6e, - 0x67, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x74, 0x72, - 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, - 0x73, 0x65, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x52, 0x08, 0x66, 0x69, 0x6e, 0x67, 0x69, - 0x6e, 0x67, 0x73, 0x12, 0x29, 0x0a, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, - 0x6e, 0x2e, 0x4c, 0x61, 0x79, 0x65, 0x72, 0x52, 0x05, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x22, 0x98, - 0x01, 0x0a, 0x0e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x46, 0x69, 0x6e, 0x64, 0x69, 0x6e, - 0x67, 0x12, 0x3e, 0x0a, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, - 0x72, 0x79, 0x2e, 0x45, 0x6e, 0x75, 0x6d, 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, - 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, - 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x02, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x22, 0x95, 0x01, 0x0a, 0x0f, 0x4c, 0x69, - 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, 0x81, 0x01, - 0x0a, 0x04, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, - 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x42, 0x49, - 0x44, 0x44, 0x45, 0x4e, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x53, 0x54, 0x52, 0x49, - 0x43, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x43, 0x49, 0x50, 0x52, - 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x54, 0x49, 0x43, 0x45, - 0x10, 0x04, 0x12, 0x0e, 0x0a, 0x0a, 0x50, 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x56, 0x45, - 0x10, 0x05, 0x12, 0x10, 0x0a, 0x0c, 0x55, 0x4e, 0x45, 0x4e, 0x43, 0x55, 0x4d, 0x42, 0x45, 0x52, - 0x45, 0x44, 0x10, 0x06, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, - 0x07, 0x22, 0x4e, 0x0a, 0x0b, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, - 0x22, 0x3f, 0x0a, 0x04, 0x45, 0x6e, 0x75, 0x6d, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, - 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x50, 0x4b, - 0x47, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x10, 0x02, 0x12, - 0x10, 0x0a, 0x0c, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, - 0x03, 0x2a, 0x44, 0x0a, 0x08, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x0b, 0x0a, - 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4c, 0x4f, - 0x57, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x45, 0x44, 0x49, 0x55, 0x4d, 0x10, 0x02, 0x12, - 0x08, 0x0a, 0x04, 0x48, 0x49, 0x47, 0x48, 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x52, 0x49, - 0x54, 0x49, 0x43, 0x41, 0x4c, 0x10, 0x04, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, - 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x71, 0x75, 0x61, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, - 0x74, 0x79, 0x2f, 0x74, 0x72, 0x69, 0x76, 0x79, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6d, - 0x6d, 0x6f, 0x6e, 0x3b, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x52, 0x08, 0x63, 0x61, 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1e, + 0x0a, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x02, 0x52, 0x0a, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x64, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6c, 0x69, + 0x6e, 0x6b, 0x22, 0x95, 0x01, 0x0a, 0x0f, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x43, 0x61, + 0x74, 0x65, 0x67, 0x6f, 0x72, 0x79, 0x22, 0x81, 0x01, 0x0a, 0x04, 0x45, 0x6e, 0x75, 0x6d, 0x12, + 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, + 0x12, 0x0d, 0x0a, 0x09, 0x46, 0x4f, 0x52, 0x42, 0x49, 0x44, 0x44, 0x45, 0x4e, 0x10, 0x01, 0x12, + 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x53, 0x54, 0x52, 0x49, 0x43, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, + 0x0e, 0x0a, 0x0a, 0x52, 0x45, 0x43, 0x49, 0x50, 0x52, 0x4f, 0x43, 0x41, 0x4c, 0x10, 0x03, 0x12, + 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x54, 0x49, 0x43, 0x45, 0x10, 0x04, 0x12, 0x0e, 0x0a, 0x0a, 0x50, + 0x45, 0x52, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x56, 0x45, 0x10, 0x05, 0x12, 0x10, 0x0a, 0x0c, 0x55, + 0x4e, 0x45, 0x4e, 0x43, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x45, 0x44, 0x10, 0x06, 0x12, 0x0b, 0x0a, + 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x07, 0x22, 0x4e, 0x0a, 0x0b, 0x4c, 0x69, + 0x63, 0x65, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3f, 0x0a, 0x04, 0x45, 0x6e, 0x75, + 0x6d, 0x12, 0x0f, 0x0a, 0x0b, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x50, 0x4b, 0x47, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, + 0x48, 0x45, 0x41, 0x44, 0x45, 0x52, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x4c, 0x49, 0x43, 0x45, + 0x4e, 0x53, 0x45, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x03, 0x2a, 0x44, 0x0a, 0x08, 0x53, 0x65, + 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, + 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4c, 0x4f, 0x57, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, + 0x4d, 0x45, 0x44, 0x49, 0x55, 0x4d, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x48, 0x49, 0x47, 0x48, + 0x10, 0x03, 0x12, 0x0c, 0x0a, 0x08, 0x43, 0x52, 0x49, 0x54, 0x49, 0x43, 0x41, 0x4c, 0x10, 0x04, + 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, + 0x71, 0x75, 0x61, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x2f, 0x74, 0x72, 0x69, 0x76, + 0x79, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x3b, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -2852,42 +2840,41 @@ var file_rpc_common_service_proto_depIdxs = []int32{ 11, // 5: trivy.common.Misconfiguration.successes:type_name -> trivy.common.MisconfResult 11, // 6: trivy.common.Misconfiguration.warnings:type_name -> trivy.common.MisconfResult 11, // 7: trivy.common.Misconfiguration.failures:type_name -> trivy.common.MisconfResult - 11, // 8: trivy.common.Misconfiguration.exceptions:type_name -> trivy.common.MisconfResult - 12, // 9: trivy.common.MisconfResult.policy_metadata:type_name -> trivy.common.PolicyMetadata - 17, // 10: trivy.common.MisconfResult.cause_metadata:type_name -> trivy.common.CauseMetadata - 0, // 11: trivy.common.DetectedMisconfiguration.severity:type_name -> trivy.common.Severity - 16, // 12: trivy.common.DetectedMisconfiguration.layer:type_name -> trivy.common.Layer - 17, // 13: trivy.common.DetectedMisconfiguration.cause_metadata:type_name -> trivy.common.CauseMetadata - 0, // 14: trivy.common.Vulnerability.severity:type_name -> trivy.common.Severity - 8, // 15: trivy.common.Vulnerability.pkg_identifier:type_name -> trivy.common.PkgIdentifier - 16, // 16: trivy.common.Vulnerability.layer:type_name -> trivy.common.Layer - 29, // 17: trivy.common.Vulnerability.cvss:type_name -> trivy.common.Vulnerability.CvssEntry - 31, // 18: trivy.common.Vulnerability.published_date:type_name -> google.protobuf.Timestamp - 31, // 19: trivy.common.Vulnerability.last_modified_date:type_name -> google.protobuf.Timestamp - 32, // 20: trivy.common.Vulnerability.custom_advisory_data:type_name -> google.protobuf.Value - 32, // 21: trivy.common.Vulnerability.custom_vuln_data:type_name -> google.protobuf.Value - 15, // 22: trivy.common.Vulnerability.data_source:type_name -> trivy.common.DataSource - 30, // 23: trivy.common.Vulnerability.vendor_severity:type_name -> trivy.common.Vulnerability.VendorSeverityEntry - 21, // 24: trivy.common.CauseMetadata.code:type_name -> trivy.common.Code - 16, // 25: trivy.common.CustomResource.layer:type_name -> trivy.common.Layer - 32, // 26: trivy.common.CustomResource.data:type_name -> google.protobuf.Value - 20, // 27: trivy.common.Code.lines:type_name -> trivy.common.Line - 21, // 28: trivy.common.SecretFinding.code:type_name -> trivy.common.Code - 16, // 29: trivy.common.SecretFinding.layer:type_name -> trivy.common.Layer - 22, // 30: trivy.common.Secret.findings:type_name -> trivy.common.SecretFinding - 0, // 31: trivy.common.DetectedLicense.severity:type_name -> trivy.common.Severity - 1, // 32: trivy.common.DetectedLicense.category:type_name -> trivy.common.LicenseCategory.Enum - 2, // 33: trivy.common.LicenseFile.license_type:type_name -> trivy.common.LicenseType.Enum - 26, // 34: trivy.common.LicenseFile.fingings:type_name -> trivy.common.LicenseFinding - 16, // 35: trivy.common.LicenseFile.layer:type_name -> trivy.common.Layer - 1, // 36: trivy.common.LicenseFinding.category:type_name -> trivy.common.LicenseCategory.Enum - 18, // 37: trivy.common.Vulnerability.CvssEntry.value:type_name -> trivy.common.CVSS - 0, // 38: trivy.common.Vulnerability.VendorSeverityEntry.value:type_name -> trivy.common.Severity - 39, // [39:39] is the sub-list for method output_type - 39, // [39:39] is the sub-list for method input_type - 39, // [39:39] is the sub-list for extension type_name - 39, // [39:39] is the sub-list for extension extendee - 0, // [0:39] is the sub-list for field type_name + 12, // 8: trivy.common.MisconfResult.policy_metadata:type_name -> trivy.common.PolicyMetadata + 17, // 9: trivy.common.MisconfResult.cause_metadata:type_name -> trivy.common.CauseMetadata + 0, // 10: trivy.common.DetectedMisconfiguration.severity:type_name -> trivy.common.Severity + 16, // 11: trivy.common.DetectedMisconfiguration.layer:type_name -> trivy.common.Layer + 17, // 12: trivy.common.DetectedMisconfiguration.cause_metadata:type_name -> trivy.common.CauseMetadata + 0, // 13: trivy.common.Vulnerability.severity:type_name -> trivy.common.Severity + 8, // 14: trivy.common.Vulnerability.pkg_identifier:type_name -> trivy.common.PkgIdentifier + 16, // 15: trivy.common.Vulnerability.layer:type_name -> trivy.common.Layer + 29, // 16: trivy.common.Vulnerability.cvss:type_name -> trivy.common.Vulnerability.CvssEntry + 31, // 17: trivy.common.Vulnerability.published_date:type_name -> google.protobuf.Timestamp + 31, // 18: trivy.common.Vulnerability.last_modified_date:type_name -> google.protobuf.Timestamp + 32, // 19: trivy.common.Vulnerability.custom_advisory_data:type_name -> google.protobuf.Value + 32, // 20: trivy.common.Vulnerability.custom_vuln_data:type_name -> google.protobuf.Value + 15, // 21: trivy.common.Vulnerability.data_source:type_name -> trivy.common.DataSource + 30, // 22: trivy.common.Vulnerability.vendor_severity:type_name -> trivy.common.Vulnerability.VendorSeverityEntry + 21, // 23: trivy.common.CauseMetadata.code:type_name -> trivy.common.Code + 16, // 24: trivy.common.CustomResource.layer:type_name -> trivy.common.Layer + 32, // 25: trivy.common.CustomResource.data:type_name -> google.protobuf.Value + 20, // 26: trivy.common.Code.lines:type_name -> trivy.common.Line + 21, // 27: trivy.common.SecretFinding.code:type_name -> trivy.common.Code + 16, // 28: trivy.common.SecretFinding.layer:type_name -> trivy.common.Layer + 22, // 29: trivy.common.Secret.findings:type_name -> trivy.common.SecretFinding + 0, // 30: trivy.common.DetectedLicense.severity:type_name -> trivy.common.Severity + 1, // 31: trivy.common.DetectedLicense.category:type_name -> trivy.common.LicenseCategory.Enum + 2, // 32: trivy.common.LicenseFile.license_type:type_name -> trivy.common.LicenseType.Enum + 26, // 33: trivy.common.LicenseFile.fingings:type_name -> trivy.common.LicenseFinding + 16, // 34: trivy.common.LicenseFile.layer:type_name -> trivy.common.Layer + 1, // 35: trivy.common.LicenseFinding.category:type_name -> trivy.common.LicenseCategory.Enum + 18, // 36: trivy.common.Vulnerability.CvssEntry.value:type_name -> trivy.common.CVSS + 0, // 37: trivy.common.Vulnerability.VendorSeverityEntry.value:type_name -> trivy.common.Severity + 38, // [38:38] is the sub-list for method output_type + 38, // [38:38] is the sub-list for method input_type + 38, // [38:38] is the sub-list for extension type_name + 38, // [38:38] is the sub-list for extension extendee + 0, // [0:38] is the sub-list for field type_name } func init() { file_rpc_common_service_proto_init() } diff --git a/rpc/common/service.proto b/rpc/common/service.proto index d80bf57e3b86..e989738c285b 100644 --- a/rpc/common/service.proto +++ b/rpc/common/service.proto @@ -73,7 +73,8 @@ message Misconfiguration { repeated MisconfResult successes = 3; repeated MisconfResult warnings = 4; repeated MisconfResult failures = 5; - repeated MisconfResult exceptions = 6; + + reserved 6; // deprecated 'exceptions' } message MisconfResult { From 6fab88dd56c257ef2cc63b617c2a5decb1c4cf98 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Wed, 30 Oct 2024 04:47:26 +0600 Subject: [PATCH 160/183] fix(helm): properly handle multiple archived dependencies (#7782) Signed-off-by: nikpivkin --- pkg/iac/scanners/helm/parser/parser.go | 47 ++++++++++++------ pkg/iac/scanners/helm/parser/parser_test.go | 30 +++++++++++ .../multiple-archived-deps/Chart.yaml | 14 ++++++ .../charts/common-2.26.0.tgz | Bin 0 -> 15573 bytes .../opentelemetry-collector-0.108.0.tgz | Bin 0 -> 34993 bytes .../testdata/non-deps-archives/Chart.yaml | 14 ++++++ .../backup_charts/mysql-operator-2.2.2.tgz | Bin 0 -> 11892 bytes .../wordpress-operator-0.12.4.tgz | Bin 0 -> 38731 bytes 8 files changed, 89 insertions(+), 16 deletions(-) create mode 100644 pkg/iac/scanners/helm/parser/testdata/multiple-archived-deps/Chart.yaml create mode 100644 pkg/iac/scanners/helm/parser/testdata/multiple-archived-deps/charts/common-2.26.0.tgz create mode 100644 pkg/iac/scanners/helm/parser/testdata/multiple-archived-deps/charts/opentelemetry-collector-0.108.0.tgz create mode 100644 pkg/iac/scanners/helm/parser/testdata/non-deps-archives/Chart.yaml create mode 100644 pkg/iac/scanners/helm/parser/testdata/non-deps-archives/backup_charts/mysql-operator-2.2.2.tgz create mode 100644 pkg/iac/scanners/helm/parser/testdata/non-deps-archives/backup_charts/wordpress-operator-0.12.4.tgz diff --git a/pkg/iac/scanners/helm/parser/parser.go b/pkg/iac/scanners/helm/parser/parser.go index e38f032b6221..1a132fdc2f76 100644 --- a/pkg/iac/scanners/helm/parser/parser.go +++ b/pkg/iac/scanners/helm/parser/parser.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "io/fs" + "path" "path/filepath" "regexp" "sort" @@ -46,7 +47,7 @@ type ChartFile struct { ManifestContent string } -func New(path string, opts ...Option) (*Parser, error) { +func New(src string, opts ...Option) (*Parser, error) { client := action.NewInstall(&action.Configuration{}) client.DryRun = true // don't do anything @@ -55,7 +56,7 @@ func New(path string, opts ...Option) (*Parser, error) { p := &Parser{ helmClient: client, - ChartSource: path, + ChartSource: src, logger: log.WithPrefix("helm parser"), } @@ -79,10 +80,10 @@ func New(path string, opts ...Option) (*Parser, error) { return p, nil } -func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) error { - p.workingFS = target +func (p *Parser) ParseFS(ctx context.Context, fsys fs.FS, target string) error { + p.workingFS = fsys - if err := fs.WalkDir(p.workingFS, filepath.ToSlash(path), func(path string, entry fs.DirEntry, err error) error { + if err := fs.WalkDir(p.workingFS, filepath.ToSlash(target), func(filePath string, entry fs.DirEntry, err error) error { select { case <-ctx.Done(): return ctx.Err() @@ -95,16 +96,20 @@ func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) error { return nil } - if detection.IsArchive(path) { - tarFS, err := p.addTarToFS(path) + if _, err := fs.Stat(p.workingFS, filePath); err != nil { + return nil + } + + if detection.IsArchive(filePath) && !isDependencyChartArchive(p.workingFS, filePath) { + tarFS, err := p.addTarToFS(filePath) if errors.Is(err, errSkipFS) { // an unpacked Chart already exists return nil } else if err != nil { - return fmt.Errorf("failed to add tar %q to FS: %w", path, err) + return fmt.Errorf("failed to add tar %q to FS: %w", filePath, err) } - targetPath := filepath.Dir(path) + targetPath := filepath.Dir(filePath) if targetPath == "" { targetPath = "." } @@ -114,7 +119,7 @@ func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) error { } return nil } else { - return p.addPaths(path) + return p.addPaths(filePath) } }); err != nil { return fmt.Errorf("walk dir error: %w", err) @@ -123,19 +128,29 @@ func (p *Parser) ParseFS(ctx context.Context, target fs.FS, path string) error { return nil } +func isDependencyChartArchive(fsys fs.FS, archivePath string) bool { + parent := path.Dir(archivePath) + if path.Base(parent) != "charts" { + return false + } + + _, err := fs.Stat(fsys, path.Join(parent, "..", "Chart.yaml")) + return err == nil +} + func (p *Parser) addPaths(paths ...string) error { - for _, path := range paths { - if _, err := fs.Stat(p.workingFS, path); err != nil { + for _, filePath := range paths { + if _, err := fs.Stat(p.workingFS, filePath); err != nil { return err } - if strings.HasSuffix(path, "Chart.yaml") && p.rootPath == "" { - if err := p.extractChartName(path); err != nil { + if strings.HasSuffix(filePath, "Chart.yaml") && p.rootPath == "" { + if err := p.extractChartName(filePath); err != nil { return err } - p.rootPath = filepath.Dir(path) + p.rootPath = filepath.Dir(filePath) } - p.filepaths = append(p.filepaths, path) + p.filepaths = append(p.filepaths, filePath) } return nil } diff --git a/pkg/iac/scanners/helm/parser/parser_test.go b/pkg/iac/scanners/helm/parser/parser_test.go index 9c8b05ce7696..01aa697d559c 100644 --- a/pkg/iac/scanners/helm/parser/parser_test.go +++ b/pkg/iac/scanners/helm/parser/parser_test.go @@ -48,4 +48,34 @@ func TestParseFS(t *testing.T) { } assert.Equal(t, expectedFiles, p.filepaths) }) + + t.Run("chart with multiple archived deps", func(t *testing.T) { + p, err := New(".") + require.NoError(t, err) + + fsys := os.DirFS(filepath.Join("testdata", "multiple-archived-deps")) + require.NoError(t, p.ParseFS(context.TODO(), fsys, ".")) + + expectedFiles := []string{ + "Chart.yaml", + "charts/common-2.26.0.tgz", + "charts/opentelemetry-collector-0.108.0.tgz", + } + assert.Equal(t, expectedFiles, p.filepaths) + }) + + t.Run("archives are not dependencies", func(t *testing.T) { + p, err := New(".") + require.NoError(t, err) + + fsys := os.DirFS(filepath.Join("testdata", "non-deps-archives")) + require.NoError(t, p.ParseFS(context.TODO(), fsys, ".")) + + expectedFiles := []string{ + "Chart.yaml", + "backup_charts/wordpress-operator/Chart.yaml", + "backup_charts/mysql-operator/Chart.yaml", + } + assert.Subset(t, p.filepaths, expectedFiles) + }) } diff --git a/pkg/iac/scanners/helm/parser/testdata/multiple-archived-deps/Chart.yaml b/pkg/iac/scanners/helm/parser/testdata/multiple-archived-deps/Chart.yaml new file mode 100644 index 000000000000..82d6c918088f --- /dev/null +++ b/pkg/iac/scanners/helm/parser/testdata/multiple-archived-deps/Chart.yaml @@ -0,0 +1,14 @@ +apiVersion: v2 +appVersion: "1.1" +description: Test Chart +name: y-chart +version: 1.0.0 +kubeVersion: ">=1.21" + +dependencies: + - name: common + repository: https://charts.bitnami.com/bitnami + version: 2.26.0 + - name: opentelemetry-collector + version: 0.108.0 + repository: https://open-telemetry.github.io/opentelemetry-helm-charts \ No newline at end of file diff --git a/pkg/iac/scanners/helm/parser/testdata/multiple-archived-deps/charts/common-2.26.0.tgz b/pkg/iac/scanners/helm/parser/testdata/multiple-archived-deps/charts/common-2.26.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..43f85ba36a9160d8ee712e11c22de7732a8f53db GIT binary patch literal 15573 zcmV;`JSxKDc zVQyr3R8em|NM&qo0PMZ%dK)*gD4O4ViaIT4S#;D*Qr9faXx36>PofiFv?M1!v*K9^ z*bS11nvD*Cro`Aj53+ylXWLJ*Kis;}H~Yy`u?Y zBABCT{MGG0{eHi{yS=Uc+wb?Q{~ZkaTVD;f_xiho-OZh?!B_pk=JxL3E9l<=F107) z0h)IYOj`=3QJP)dHrj1!vd!)&vI(lr0M8Eozb{Z52=$Ve*GyF++Mh77Se{D9*rD6WGMWiVzm zOGz>Y&5sb%F$rOa#RbL*42ek4lt3uU^PmIpc0#!R34}vJ1w=TF=^PDX48u7P!Erna zIukm@`!EqA<@>#!ffIyu+99DtsNqX5q8CX_QN(*O9aC<<`BTKsgESd;&hh+$vWV|@ ze1mVthY5~T%sM^@JWXRHaL0#HmV~n79p84LGesm3h$NV)>Istgea9$@LOR`m<0K5= zFplArj3&z-6{JB~9@wvfc^Xqv|OXUU+sZj#Nw7yrboIx~ zf4gY$-mhphA_)-$^FXAxA`KSL|H1ZPt2+O8cDA=4=l^{?A3pS+b*?4?RuKTtdY?XZ zIuba{$aEh#7BC_)mYT%DRMI@0;C(2HbxyI!SON$*9SKNigby_%&LP5@BWcq4@Bv5? z##w~H)2tgf{3>hlKmzb!JtCn1?;OuP@c#bhjR&4yxWr+mG~f<^54sXgLM(sF zXNp8Pd2yLC%(+#?_2a`ip6|nl4-lN=Iehw*e*vH=W=K#bm38N}?&iMp20-?Tp=699 z(4WhYWIM76_y~VwRN(4YSsf>leSLu?Pwc~>V?X%yahxC)-Dn&ofV&+>-GZ!Q7p2vQ zQ9?MwF%AV~Z!w!1g8N_6SS}d78w^}NW^%H7;OW_NCnKl_Pxpz80RI7jY}B@Cdak~% zCN%;FAdWdML)H9p6{xyK396y@0@@3j(wL6tKjJHp-l?umUUAJ`jkeN&3f|hM3AeqT}q>h*bnJ6r3p?%&T?VK z1)aV`LmYDtf}iz484+*w_2$BrHQbn{z=gtB@`+^s-I1**Jz4)ib7{f zB=*(7bAD`kUD>xp;7j4bla)u)A&?!ECpn2=|DYI44}#)DQPv@zTU=4Q3qk37UaLm8 zhMKi9<=QoZxgaE^EQngcGMs|Ktq`0d*I(JoSXj9o%dXkQq7dfOqTBmQHmp~9Tvg=3 z)aA-`Ff3kT=<*O1JQA3{pxcFykdQ>`YcS}SR|O+K6DnXGPg5~>*rQu53MnIr7=ee< zG$_ygywW~=t&qxDsn(pMPE?n*C+B#+0Z-H-A&0BZNL7rU==D^st)^b%>Q`&nbiBqS zd4YWDmDX`73=Ls}QygQ&agf(`o0RY`h?p#BL3N-y@FIaAQ+N@AcG z*>9_@*ScGJ;Rv$*COodPz_=y4bycx6!p(D5)p>}s=*hprG^)$mTboAr#zu1D>AxKX zWNHUd5B9joabSKo>H&64r+X&1FMXeF6=bBWj>53i|ItSk#3 z6^hb}J6;D?RUkgwd}z@VzK992P(8Trgt!NWSYgG#wZ;B^Ok298Td-_7+y2`#Y&mQC zGP~C2KHPYGmOl0KzYwKpNa9;O0bFwax4YNxSI+--`#X>4fA{h{wDUhP!5|PDV*x+r z3mzDkqgLTr;#s*+8ZWeB+fnHM=8xdWt@C41CouobcTf(zF08NH*W;KDQQR$mUbqm+ zzM(W_G-U({`L}hRQ$BDhjUvKXrhMgwSv1BXSgpq?jY&8U3V6Rj!PPrh5 zK}O0sW8GC*++KHKo#W{Yvm-i95yRm9br5V0{JvK%mjhI44R{*u-fS?$0u7w=0=Yi5 zm8~BuT$kPn78jJA8{(}-X;bIq0TO&~DZTNfz==AOT#e?Yvm_Y@=ie%=^ESyJGMfBO zhbt1^mVQtqUxCMmQlDOp+_vcLkvKwlN)x`a94X2_C^8SWZ=JPKn)2HvwQ@h6;$&r7 z7Zo0feMMq(fdn39@#>uI*7(xMZOHdI2u+eP!0qT3!4dv0*E{m54P$dC~P zlKPu9dYj&pWZau=sv=7Us8*qEXqHyKy&?S>GeN@Z4(RN0K<|4%IS7_1Rp^99XE@9l z5p!)<0m6Z2X-b*E(TWx@o(6f9TbGfPH4a(hi0w3wm_8&?UA{Vn4x=ei&g4fl8If_O zCF3>7gc<>T4$7%%uoA;xn|@0drh>{O#p=zchYHY21dxR{V|0#ZLgB;kM(KvASTAW#h6hfkk8fIRR+&@rJFBwB>KZ6gi{7#`zGA(LdRrkU*bIo8o3Y*~`PU$=rSV3=pIkQe|0k0b)K z5el)Q$cSc1u)v|f5lG$~Q8txR z^i7HrJ|QE~`H7=3-q-W3x<;0mnDD%kT_jtlczZ>6<5iMuhbPBI0Px@k#KFtg5Nc~z z7mk$`*(AaY5LmQg47^Yz)CM!cDNZ6OH>j3!mRJFNH_!bZh>E?CN1svBTfGb5H~}gq znB^5Y#N-?ogoX<%OLK4;$E>G<_LwWGASOsaM3p$cpzIuICgf5eF&ffKy(-Bc40FMV z99DlefU~2c)yGl0uAY?%ko)9u9Okd=5rA3cYL!;^W?u<|Ty;YcN(GK=EBgl!6lmFj z)h8M2>$%5o#iOLuWVc`%Y zH0|cwKH1&gGdR`!M-pcytiXgMaoD)Rk!r-P!((;i4uDRHsJ-?^{CnA;2Oi6kL;e%T z%>HdY_^unJ_VaakAmI2VNwUi~%FBnBJ9#`Z^AshZ6=XX69fxAWnSn&Wh|#H?N?9y) z*es2o)vAa9^#_-fA(6Ega7mz$RW z5w2DiLA5~5=dj&stUkw@8!(27_VIJ4;GF)*)Qw=+k4xO@xSinc>wyqLgDR%(QG`?TX-$nvUJRlQfxCW z|J4geia1x%7fWlt1gVzVp;=&pj;mHaDOSN3vVnfT$*@)w;wG|6ARCTxpg@+dOzA6_ zDH4-F(7|D+~u$z;KXbSVP5#2|Y+S z2hZ!6xZTPx#x#sbodlIjr;?>kZS*+XAf$*P9eu}#YHQ$wv8niAYX*)Rg{7y-tF4ESi;BFhFVpOkRyM1`ff6{oARJ|t(M?=&71MuD_Cx>Te@7|m~KZ6&i zr*BU8;U6^9^D$*~Mj{MznlT77rl?TN-^wJ{3axJ3Yj5BOD)ZfA`#?> z1-1yRujdvH{ndQvy5LgEiJ%3*5+M7rsKBvQu>@sm!QXc8dAz9w~Q`aho|X1%ktTD60)EGDGPmiq;Juxvdr5Jpk`NE9+eal^UQ5Dh-X7hqJyc zdSCP2*IfS3tCX#doP%izui6QBy#)>a>JV4)qA=6QSaYxAsQ09wD$L!J#OstHF{mOi!ZX17oxA^8RGypXCc+m->;CW zgv&?B67q))h@x{ssHm`u#^v^=HlCq4L+WV4m}%r*$|{))=5KA%-})@BSQM7b+y;D> z&tLO3bWQ>7-}Tx3q~(O-&L?~ASZ-;IAT?JU0ydr1T~}mW9h(&}Sv283x8%7C^50B; z-S!atYfC|`_gmkwb&`xJ!`!@Pct+&=UdpgBohXYA{M+Jf$s*NeW}VEgwlTT-24q(A zNL3%+qVaMqUv2r6>szYNsTI0|GB$aJ^$Sq^dIy8 z-OKX;?0a}U)A%;6X!J2ftepf25N%@bfkQ|E(uqABvaD%-K{O# z$!qtH6A^%VrIf*S${@+6L(IC?v&~cs;8?%~iDMXI5DX<;PVY$S91$6*^fLnHXc{~I zqxo?sGUuT{nM9K$0*`U+sPnlboO{ms*7zXF&(@pY3YL6FxaiJIZEy;|%HlfC{y~F7 z;j%Ckxm%%YiZc$BF7T$<4c&UF_CO1|0cYg3!s)U?@m&sN>AM=)>Jo0gsiZS)00B}7 z%iSKzsU~+QdMLeG8vqUP+>alei#w8379dGP8CtjaHi{_{yW7?8wmHSB^#(sm7HiPS z7uy_9^raoaO%2)Hu(TZ%Hl}4E9>biGkwj-NG`Ktygmxt?3f|w|?JS z!pP;jUESKnrxA)dUVNiT6X$x@l}y);V#K+UHaDW@aRu5H=~}Pu(Dzozd*{^6i5p@j z{3%M%Sa~EEhZZLjuacf`U!DOc;{-1ny<|UU?qIaW)FmCnEDIOJ>V%^rH zq>5fz+};wQ}0&_~Py9f>y1Uk``4H z#DBzdD1r8>gb3qI?nAXJ1e0QZrD{uxm%}uRnENQ4Vz29pw>!Vpwfa-n|4kI^`}6Ugygk3)Kd_Rr7TsO1aJA)2X~b_-UP?ffKPhH($`YW+5wAt z^>&qWToO9qOW6pTs%Xg=`NMfbB@@3W@4LR5Y)c)r8Ka*3s_kT=AXY=mv--97LY5XA zkGe5?ikb57aBSJdu~I3rziqzTkn^HjQ`DQsu`%v_X(T0}(ikqNVn-1g+q2`RRqWEx zHI^?1uUx~9TWQ#8!_^2f&kkSBLAl5&qpU6&;;RerGyyW5WA}0XJNU(0%=lC{IE!%IO%(;(xmeaL!`WfFHoYcCdHJdKxdeN24=*X zIf5~+uTyo2N$uYao}45h1|puS@Yi#7Co{GN5xci%7@a$@NBM@`|MLyNA`Ch|&o?|yd+8&j3_TzTot-b%mUWYCAB{-p2{(qVu2zgkRhEJnf9H16NPU>oPwIm zu%43e{2J$1OVZkO;iEdl_y?NCjq*}Y;6;M8Yn!~OkiWXH?iLrRZc|cSRqA|x9ry8R zf9m?b9`IXK|Cj3jdt24~58FGNkMSSw<#_=5ze3@~Whxf|x#T3qK(4N|DxITsS#gDv zUlcJ39#mZ=hU~g6OTL+5#z=&vbYxi)!tR#(lT6RD(TH4v=eMOUK4MsEl={$Kp($~; zN4v$$x?W9}b-*ZfCF_#%)AYaQUb!Rs@51wy;WS1e2JagWykEWRcM9c%8)b1k zhd(kD%W;jQo?_gv-(d}1l^3!Ni8;@2opU+HPmLSm`sT|gb)+LVcn4G`Rg-T zR-J^TIP5BiZ|gRpfaKAN9NLrOfJ4z;#Uql)8*CTTTo$Yu5-p$Dk2$Z{GOYzxqPuHC ze3De%xtH;)gJ(_-4W+#1=D3#LUKznE7nY#ucCW&0i&g%mOsG$(a1zeHNM39=rD|?0 zy5}&a-Gazw%u!@f&fLo~8mRj5v)Rd7?x_}D+4pe)PVQuJ8eK4B7M8k&X_J$u+|;U5 zr%`n-kZ<~WlKT#g43`v*E3wY0#CiU`6`WC7cv#^&fGY4uY*421&LN&KAQSj8Sa)HUNNVF zh7dV5A_mrH@|&FJn(9`c;M~yUlFfs0qX8m!R=JQ{rhGsxXtekH2IG=B_UfC>CH+j zn>)KVL3(R%rvz^6+wB#R=2H~MD!4p^kpA|~*gDuLF-U)JRkpso0oDtfS%t65;C2VwtMc{c z=R|wA3~sQw`R!_~U2F-=@j@;fbyDPf&yYm;vih+eqO3{ZHvv&jR8+frqIy3i#mPMX zbCH901(XjjN-uhO>?s`$5yjd^T4H05dmR^Wd&gb9H|LhhLt87l#y+JEWI?6YchuKB z^12S2toPY8!A8btk3wQ~UaGx=ZEURd-!m@E;d4&>uF;>v^9#hH!U10gP<*0641md|A;};kvXeK)` zlVZP0Q7(7>Zko=!_GT}0Xw87N+$>P?SjzTh`eGqf zH#cj3=iQ3?PvTnGEY3|nJdLKm)}k(=1qE#Pn@vSksdJ9!D+!%*Jin35QT64&%B=e+ zSnflxNcF2R9N=r`yipdi@>og&T63pu!>lRAh_26@a*f*c|H^mS z;wzMzXwSTKTTSaO!~2Z|X+(Huf$ z%8gc{C6GPYc7@#RMBGQch#SLGFSiDHqIz3gm{#AS;&% z1-^=>`Bx3>Z)Ipzp=6`{*{~oDLTLkVFy5Cc82=;ADeMLCj>Iu2Kd%vCTVb>FL<;W&{i+5uN6Q(_r*)f)C$O8e^1{LA{$`6|qrJ zKv4vIJ{{7S+b%BwU7TJus5zDK(1&(Humh1XG7yVu`E6*__Y9~ zvWnbczDZu=i?(h*H;aJ@z8=8w$OdCqY`+2goTNHRDz`^23BCZen-#RSLK#}0lk~gY zZJdNFG^`qOTb7t?KtkO`M;*+X*uX=?@$NR@BxLhc*y$kK{4eFFdXpxVrz_9Tfl;JF zh%%ZPzZN@(UM~)hL!lrIZW8$`xmE4Kvjwq^-%k=nAO;01H z>J&A@XJjf*aj1_~O&6Z(4^K;iStC?5Ec;fVw^X;Puj#qg@g&D={{TD>@@R!d@Ks(H za@O%3@I2RjAU`89fXx!&lppjVFx@W>R5TA*&iYa7e^n(V6C~!r7>ghA{O^oT<&v2z zD3Z542rBEUqaD<)9Mqasbrv?PO30>vboMSv2WsrY!q)ZhJVyeljciQmd6t4Vle&@J z2CZfir3f>0sC#S_`LVN=I=d-DAu|Aj8M$=EB*a_;#neC+?GT?t_0L9y6e)Z zg-u$>)Kc0B@KYvKWjj&{V`j2>KzS>Y&&~sPN;Ygcsws394u=75uhO14lA#(8znR(X z7Qv2z4TZ19!m~(w4*m`Eqq^;?qN4&^Un{DAy=RrC(qhDFVc~VS{bpp!U~VnMe>*;n zVx_v}tPFo()bAQ6oe7qAa6P6Mn8CVSy$<7af?&|?>YuN(DP|;uK^NAuG_9BVXhP@z z>OnJE;Xtj5hdd;twm!61!DD=Rs{L~h+aOUkt;FD}Lig7Kp!{Yu*3cb#zZ8&{si|twcJ5PgE==RmcR>_|N^x$xJ_jO9&JwNtS*5~k zS68rb=ymq0b`8_c&*sXL5zo`PmhNAu4Z`hI3zW}od${7Bd#NsLM?W_;&aBSoIWO;4 zHLG0Nb6Z<)QOZgg(lpAg8d+(+I%gebnCo!L1xganNRSqBWFR!kgz~55F;gy#{RctH z@Ql!m*LPaT-LmslCc7@VY_fm0*?UFqUdG(Ew-r9VT^_FQEbcMU@&kPu{6Dm}%>Bjx z8*FaX;{Wv@|iXGljVMIMyjpMD<^M zC8p9;A*b|vg`$#HdHn9umygBe2dDA2G6fLx=B&A#SGtc=#-((?D0k1E@0E*G12x-4 z&@H1Q*uD4Odv4tGh6vy7mG$nV8MS3MSw8pd_}72x^1le0aBufNw)blHKXxADzuwF9 z0OY@u={`U7&}T~d2~zHNm0~tQDc9RB9?~?AR%m{3eFY>Di|$-D#07zJV33AIqqbiL zqfp)zcu#f7gC{6W7YD|xH(1{!*4#^GcF%-ag4o=?ST8e^bCDJxYonkc4QCsI`o0C$GnT-P!7#JzT zA&!)aqQW01Hsz!u+(d|Uzt@`F9N68mnL6_p>?Tf-PnGmoEABYN8qu4fHImyrKJP@985&8nS>rEc4>soBqy8hSoKYe0+ zkMVzY`t|(pJG+nfKknsuDEglc=1meVn7)OpT*Ss$6kbrqw%#ssH0PRQf-x3m&Mmf} z+N9^^t*YbOmn+80Xld9{!kG2?Z^l`*_m;j$W$+KhK6Z z6tN3kfyRnLbPvLh?6De^IybsFyAIK6q2KXnbr+u{EbiT^S zSY6Y;%SapnPG&GeOgnvPe{-b6uq++O3Q_bZ+L4*g{rr4p`Os8AIVTC~i@Fn$#zYB! zF8@#|;yvH99d>G{Bjh8*@!xAz)jH-^Q;b#HaF4rNp%odr+Dfd0KFkiF+h9>qKZ|qi zRwym5+M?KrspCzv0_zc6I&ur$jdJg4{p(6otOmHS!^z$l=PPFf1Fw9t)O={BRzC4& z_`Ce@q~gg^Q3Q&XYA*Z^9KXR)DAiF|7@iTV1G7lc$;>Gw9qG%V`XmHM0#-eGve+Z2 zawN8H57!E0${gZ+I9PPpm7j^tp8ADkqlOt6l&x-B)g-`8S4Vm~s50e7S!B z=BFuD<}$Zvb&#*;=GUxxmbdK=J5+9u1k1fVn(l!#amdjGhvz(-0&=!AW_Uci-BIB> z;F54M8>aBx?%6dj3`stgGmA@E#*zm*=7E|K4e?12m+WfK1ALU^I@E=tkp3LON$yQ~oU)FGz@b zN~u^RlN+JAH#t?T^1>2sFP?f36xsBv9iPv;&_$?aMc^%%@M?4KO-pqGPq|Nb$;ZhtXsl z&w*jtO`MopK4?ZsRHwF5Kamp>OK#%`qlvyaude6jwnTx$Nkl^)3=Qw7i@F)_;iNa4 zULb~jfs#M79!k@gglc8>LnKg4$36AMZ~9{6*!Khq{fLILI`>5;C?hE5zPh`lg4X*6 zb6;Zan~}kc`$`d3mdwRQ`!esDh`JG&%+PB8Bh;NOGA0R%SK`GfjnwU!W1F=6N;%9W zldi6jwlG9itKrS-gm<~cQ33Nz|A;yVzF()DuI=Thn z@B@yg<^t)3%BP|8jcuradGfz1ytVe5)lv6UjLEs9_kul75$EJiU)E(IdGsFlQ#+V14&RIb(D+{a~-gmcZ6%H}U#%-GM z7Rj?r3Q11pSO~jy$u~eI4x$v$aqPxuU2Tc9K?q&5sL9dh?2_&FSniAMRzl057nf+7 z#(3X^#=3qpAtxvLDh{(Z-${cUbDNKDuZg&!c!v#C8o zQ+Fn59Mg;3``g?d)t<6VxDV?y)THcc zC9rzk%NVf?3A}Sj3Mj;OCQ>sd$1g=P( zC+Eg=q>PZ-yje!&9R_vJNa=r!W@CM6x5)V$9%xfBzsKGnaryQs&k$_a2w2>0Sy@FM^gKXyg-HsgY3(X^w4zWL>XNEtz%Y22L=J06~cKbt*ws_zoM`UndcUzLYd_ zY=n*xqrzS!y5v0fkS)>6I>U||`NqLZCnWAdzfP9kvl5TM-=P1+3`&jGHmpU6INngf zOLQbBCBzJth1jam@(wz=LKmB)K|N5>%9?bpJik@)TO|;7@XLGeN@c5^1@M#7Ad3no zCbYBRO?SIJqRiP*2k`gO?@}Ooo^Rw;jFBeo1%)AHk(nNInlZSb>^!C@QqzYwYN+{O zwCkwly?r^)m&zO*(j>&G;Kt~kF@>?oBQW|Ggut%3`+BR^x-ndewqJI) z&QWw$#cD{70%kP)iDOocN$B2zZ`|tCL9Ps_Jx$Hk2Hr#!DY|mCvA245^PsOj7-fBZ z;V8I%6zwBoJGOxKC5H?ZPoX*FN|QU#P3dm0;_LCg63x%?+^|Vu49Wwlcv88mADBP5 z+2?j*$(UDXS<`TqzkE*3Xz}_#MU0?mc*CRMCF}p*-flJj|K8U2qyO){JP&34H<5xc zypk;U{5!A#i}DBrIzNJxdn)|ULc!k`{0Q@jc(6O$8$N91w^ICAlj6)G@nP_k1>g&VTWHIz7? zyi%(TaO9Gbl+RKnjLf`VTE7K{bk+7xaelnl)}4BZI@C_tuu7R$cAiwjVXxyqYE0&- zo9bQr(XfkFGAaiL)qrTc>cCwoR~@BVV7bQOY>h1E86NTF5Ie5yOK>aBHxtIwQzhNS|S)Kb}UIB&zTDi zX9UGqHczT{?rSK&0uvUs?tn~9I4!2w3d^}UU#r9-v`sd|OyrGh>PVbh+oP^-oLFTA zyfyp8Eh+=6;C&4Pg$3IH?>feb6~WxHX~K5m3gdoFvqT$|8yY1n*avQsaK-6W=2%Io zyF-J-9Zt7W7j81o+!g666RV}(EgPHU{Jp}+7HakvIjRNvOGea{l1(G#zF%ruT4Mj9 z$(Y`?{by@ut9Jggwf7kR=U$$NV*j~270a;j{is;7vFF2Ekq#^1eI3znz<${(mg&S5 z#{Ie~RtuDys#pf>16Q$DUWm(7x}SwuO||d-jp6ZM?qI&Hz8X6d>Kd!@ooc=n5pr*u z@7)f~&DCE!WOuLre(vRc>9a)tQ-RQLdJ%M){wk)c???Na zpZ(X%TM>9malVe!Q$W9Ly-#&v<V4?$y4B8X$YipSA%hZb4IB zxkq;*J&K|~8endfVyRQ=eCw!U*t7CPo$mkd@BqjNZ_S{KWU4N4GbO$m z#tm0E4fH{(?y0_wqvF!r1x@#UWlAf}R)M+GwMw;l8_QG`d7fk6KFqp~J7$YXuLGaw z)+`-xOX9B}KIN98I=Q@xZHgHA6PW-yGaaiN{&oO^?e5AWk;B1JFtg#lZ@~YJ@SIJ< z6Q{soCMM-OU|;iw+|BL854zx0?fKOPOia9MUS_Id+j5u5iILyjygOr8i0t{f<-UCu zumA4Fo9k-G>TeQ$k{QI%J-?}#R& zeqW_uu3n7GvwWDGOf9#)?S(kIN$~r9b1SctGoi`m?wUIVWU8qM> ztqcRC&Wdb%*?jQvc4G3_nDB8HYa6l5#!oXnn4@W2y60Y8Gj6$2U#$JDH|m?)Ga^U(e(^)LDZg#j^18(HTU9@lG%%qNo1V=y!tQpRA|;wJ#>)p8UuDt^DGe4wDau$@2tVkh!L7`IDY7B-*G590f{i` z>2i$z-U((rq!E^|$#e`O8b_FQ$aJh)n@F`SrsK}h4~MV6fAR9o_rWy!+=c)%|4&~W zK7aKhm_~Qe#^U)u*d5gFe{A-*9`AqL%d?i}X)&|mB^ffQSg6E4oz5ZrqO!!4UjK95 z28fo+M!+XJG_;^833)HpMSoSR74NOdGCE7+n9(eiB1Ll@#B@wT7-DgOagrmV>jj<8 z+8Vrl`IqOXoz8E+{U(*)PJ~mOL^ufvHVU>}{`L(#wGu%B?i17a2!*3M_C+s8i|*bo||~!8OJ~~ z22Nfr6~Md*H~t^+md)XppI==dhTGHg6a#IDqjG!UL|~RO!f|&a*H|zM35o$nL;*0m zcs`~Yo*vZWMC6EcI%-MLnvKc5!U0(h$rFT5aGYYs;bKC<34|z-I+Zf|D>u;@j%f-B zzA)TlvJxrYt#NDDE@_~nmb0MKDKlTG0kuB;@?$o{C{1|*?cBTxB0TG926wV}s0>32 zy!uH;I@{8bhEEa*#rdc3^mz1|3YA145l=Nf+EJ1h2qDJMyaPZ4)@Fvq znA%-(JU1!2By}|q$(1?!rX5%>{FV{VCm`f{+o+X$BWG zizAi3OMc-P1HKdt0ZCM*E-f+CdcfU5(nofZw+~H%ge1fU*bwh`)^fIVIc}{a@XP$N zCh6ZY`fK0}Ke!{&Sp(g5gOQTAa$cQCY0m{tLR`!&a~!*rPWB8_mzT<}g%!9&kaX;H zxS$M;@llL8U&fo?Pbk+Gl>$KlKdWR_aHau)g0un0Bg=c9?`?qF%xkqod7hEE5#cH` z8bouoOloN@7dw)SOBj2;*Xf`z#GJpP5nhJwp(+Ve8WrwSt$3FjI>jh@$B4jh)Bteu z=hDW`$e;KMEqwbu>2%~qW*OWQW5yd60~wVd*%fplJ6qP#gT7W84o%lJa0pu=z#1qD zD5Tfa_RDED=h+t}2ke4vl}56pm#&%3I&vEeUa7Owxq*I;=dVyIb-w*7Eb~5B|1`{0 zC!IORb0zuJLLk2+PRsIRp6;!NgvMW|$y-Qlt%BvKu7Qi}8bEF=l!dI9+K+gilXA^w z$C8L;Qc}H>8|MoX$QL+HI8j?+H5b(l%SxgzWDwr~PNx_InPM&hT%bfv%CW4iH9Dr< z0#eF38IqWYxo*~E2qcVGsUcMhJGyIyB<~qosrSC`H><6ND%aOp0b(@7v00%|nyy|| z58;~>{gL5Z_bo=_!v`mGsUim}{A z*S63m&y`9s3)8td)KQl3%0L}>-bRI%2cD-m{%NJ?il+8z15fNk|5bvhnBUuv5IXs+ z!Y>(u8CFfEU;{0Y*!3*G1_?^>4qIckZ2&BXd94`FiN%4j_ z-rWX2>UNq)Ft`>81}+H(w?l%#9gtv9C4mtd@KZWwD3Y3r5+QFX41#{p?{t27lfY{_ z!zx$cU~2<5`kQ6ZahWuVw3d|f+8w8aH zF{CV|CcUSd*3+gomSc_8;i~THme!yY6gdx#%ByS|c~hnbKm^C}NN%c-$t`C~%r@c0 zo0ox+%I_vfs__&4N)SQDgu@8)!ppsB+rt(4qm_MlkuSA!%vb5S`9Mh)Zc12&9;IPS|jvF zZ_SkU6>`2|^Cj5G2H%#sN#emF)!SdIY(LY<-sN)tOdXe~9I7g}IAsx*42|M+f`(X- zP|YZ%;ZEq3j&XwJ$X}qj)`R5=;MfNp+nC|8Bgw20X2yD{j-)a>+x0{tIVVZ(IyR;T zqdDucxLQ)D^GC94nipw;?V4n5eP-rtD0qA#w+zWs0V658P%;O?d4~DwO==z8%p=37 zJj4lNgxXAzW~7YK#jPDt%w_XdWZC(MlDQnn0*#^*UzMR=EqVb&6c zN0?bb^$Q)1h%!2=Vi659xwBDYws`W)Hh-OM{W>LMlRt7T|I^Pn_Cv%m@0w|1J|$y4 zc(xCM!feZM%TFASvKV5LoGa_;Uv1k0hZEUuFf^WxN|oQ{{FHLx7v0ocU_o|1G5H{4a8`+|GSL zwV#r}Yzm%z=V?Ar>|@_)mr;~NJ<8-#0z4aX5)s6R3esSjiy%uPF#@bvWX_1ohYXYl3}j^4a}e*E_M&FeFG^LIFW{SWx@`1SJ* zz(kuKFQtg*5Dc zVQyr3R8em|NM&qo0PMZ_a~n7EIJ!UcufUheeq{M04n*YsJaom*YEtEhGeD!!XmmFkjRwm|DoIQdBKfQrvN$H8 zWW0Yk#asq6oWy^-^Ru&5o|-v+xcwzjr*UTkj-{i(~F;6NX-AXb?3IKo%>22oY9{N7nG$#bhX{VS>}Fj1%tsL*y=|r9a?@tZ%CY=P%#Y}Gmie1j|fkRB%(8A2^pfPl$jXz`z3x0DC>7%Q5`b@!olrT=M?uIEK(6Pi_1l2lp>8i^spNFjk+X~p5zexhhFFbC z=gJ$ht(U=8XZi7OoBvlh&WX4m0Wg35?``kD*s0F{ox%Ro{C|vR4ZR{`oW~OB5r^5^ z!W2Pg4V_J?KvW=%{&Vo|ZEwtYf~6!88q=7l0AQ7Ue zWN5~6jwDI47)v684$Qm{SA=sKks<1KJL5c#YcD%%=w}?$$fBy6=|-3&EEPm{H&Hht zSvn4A)h#+1a7Kq6NH z6gX0S?5rVA>#v;4sAhU5VJZFfWQwFvxx|x^g$Hq za%#fFY=Srm3B4jvT)kICQARTo)099J)dy^=IV{i>i}OTHgETUKqlD$DG!6Yggw%t0 zP32Uv13}**H(hk0Q$pHRZ^S~;zjT_sUucJdfBS2uA3fI(B|#!0F^vUcshKwVn`%_` z&)5x0XLS%lh@?tXL_;*ju^{k@reT~%#90_`*+lr?*U)QKiKY`Il}x(kR1$&0DG4t# zM%C1!De7Ng-jC_1&m@UM7WdJV35g=g0q86+u--FCG@NjX(}@CP8(tTRiZDE!F}aBZ zgGr01geeCNtFKLvg=Cx@7C4oAa5g0Y`Vt6B_36+}&$FZe&gorX4h_FDl_(In-j@2Z0Ehr`$$GMmi(@ugvomd3k zvdJm^oea@nYkPNVYiX_riYRuXVU_#UC-bE?1MK^+XcDOI^bFoh&jeNJovza|4QgaA z>}qt(nIeLwxRUbTw}eO>VTmh5zkDgMR5oO;3S}h#ajd1Tp}Ckxbe z|6`K7D9|f9)GIo)fbd2216R9M5UrtqPf2RO7}aDOf_X$fNsfVnF&>dv+fX<~SO^wU ztgNGqMV6QfLZbAEwIxu|g}@UG0Bc=QR@VJwLeG0=J_590WkMQ;It+oBID z*jOC*(uV@zsvS8fP?<9w8l_IkBC@Hl)h3`?Ho?-+$(1o@2~2=%vKOs+`WqNXojigQ!$ zQ91uHhsDxi*J+l^fW%icWu2&Q*IZ0+9 z$0M}PNsMRfYLv>=K*Fm9osgKruvrY>gO{z_t@J@tImVJ+5tLy$1y;?4WQpG=<22Cj z2JMYt;F?6IZ$A9=_LW%)Y*RKu^&tAVefBo*@=q>vE z8I6>MPXxeeEC7%++Cvyag)Vqm71u{(luw4}<}-YfBo&~qJp*7$a4e_iK(wL=qC&0O zBdiumFx~9ZOS1}CEmTffF7;xe8A=1kjWLZ4E8$3)v3g|?(<^P&g4H`J8!0W&jXOpA zVMwIiBW9|mM9GPfad+4ylMhG}K?#NkR(?bD%?(MfhVTA!e*EFp`O)#`;b3R5v(rI^ zIc6v~!ZMs1swy0Z6@2%9J56EwJ zd#{6>sxYJZD<+eIxEW`Xg)A2K1ws>^g~hM=9J9Nnp8@ zL%Ae~{g*ofD9L1;-A}J}cLpz9$rXCDyED+8$v8`tR?S`eg~T!g7IK`CbNyQQ@O$W2 zHaefb^Mky{Kq|O;uqDa`luihnn$pcl%qK+FKIo6NKE8bUQupz9nqAU#390h!?m!KY zTGr5z=nAe=wtnKprk$l-*u5Q_&w54CoQ}rYa9@ zsj|2#eFBl`-c)9wEu=WMt^Z#NV){kF(B`#T7?Up+T`l5DuQa>DP6%ua=bV#N#xpd< zV6IXja)O>UY=%xrZ2rmeIPMR&U%vQuLtAsXP_|H-$8l+2!ix8bLR5=JYI8`PiMnW5~ArR||60S^P@3ox}o4O02qG6Yu z3T>wq!1juM2ge*x&8tL_d-ZycL0XVQkW8-$WebG*D*p%uRf0F`7l1$Dv(S^l{ zXv6!$xqs{y6KG-Icv%;A$|FB#yoD4j@t;w#_ITn9s4V{pLrjc4kD;6xw z+p7KfOs#xD4k%)i7zP7N+nP4Y1WpJV=PB%^;F!wUhQiP6#znft!(zA5ZE8hob!oP- zims=>l2E!mF%A71!`9~vwp*2%X(<+TDx?9MwL=qS3&E1e>N z_F!6Qls9!d#Rw=2_1Kuo&p4T29>r?u!p49Q)Z9=l>N3zMz&Xz2_>_cP*%#>JFG~Ej z#p{qyB+R8+?RE?))sUsd+8n&G2Yg~68GGU&3|XGacCUshhp;YK_iZ$JGCXIm-OMoV ziVC<6@_p21jigs`;8(VrTooiV?**18!7V|g_8zekncmWACHG7R3d63Yyk092}K$N=_ zEIHslQQHQ4<$=Ag4y3-r>j02pW8)FU0!1v$)jFC)Xi7LiMJ!z5qjY{vPR4|jG$ef- zD&ww)b2&}n-{1Rugv0(lA#R5jM-kP!MPm$dRs8{CLABLGIHNyumS-j&LfL=o>*i0l zlJ>r3EE4O*&y+>P{k|f6Zg=@pHs@PA$_b9KE__+%9W{GgfMdZCtLS5wDSxd-Zb zGp~t*7x1t_$7AI?GxJ0AtB`ydi%v@%!S>=I8+ixu5Vobmn%fYX>#V`P=`qtw6F>zk(vqkH1=M^hd_Hc! z!{~5SY_lp5L*$$~Mi*D!PMMIESJsI%L}!P`hGQ*CL$tGH%i%0Lc10&V3k_nu!gaI^ zb}t*Tds)ZsWg~Wa&D$$E&lWc8oM)wG-P@vB_o`_2r&nIH+I6>NtA*FE)NJv(Xt#LR z(%-_Zw@kCfSy^q?ye>6s-c_6R-Che@G_J2ogYIq7o_keouH+Xo@mY44)69&B3LQz| zZ7`!Z>>73i)N;kHR5ZF~(~V05lBS69NN=Lr_0XwC_Z>^sVg)@DrQd<+_Xc7d9ka+4 z%iQ0tNYECXj(v-j>PIDTk13dJ7{YM<_MdRsa^E5g9|wnsitx%@;8OUW_T|C+pUDbM)hzxBn?T8>NxaD>K+( zQ?|3#ta>e}1Y;|bxgbSn4L`!lzO>1L{s-3KL`cz&PvHQmZP65_lTw6hzA3e4cRkGC z2!&ZbMB95?iTSNj9iqL#_B#p+`k-QksCPD8Nc{vqLBdiS#8endIF6B8R~IXDk2L7D zA{ba8;90V2E9exaqu0zD2=Jh6+Gd!`9vcr)GV9?i1Gga)5~W05Gk&SY$54_)#dcxF zq5%D5=8&4)>%!J3!nuQv`tn}CcH8q1;Q($G6CEj;np&t&WY|{~gtmwj76&oKf+z(! z$1ayxT#CMFy|4G0>F=ZmuzF(}lirx|p0a%VfRTafSU0LT;9R{hP|^8%>T)^q!?;({3*6pPeWb z)<2>*un+YHyn=51X(z_Fr2TKtb^xLTiYn@yrYI@S-~s7Lg7oaFpc`JPT;B zRE;YtC`;c^AsL^&Ra0Sz23ws@)zl z@{L3fN)0a%E2@}|aDY~P`YNN{i?$OP3B@KN!6bk=8?tPsLow8jE>zq7X1v89gHD{U~m&yx}1YM2EHSsDq1$I?2I zour;(p~Ljls)mdiC&+-`EP4n=pN*-~t%5MqGE(Xos5L7xUy&HkPIa3~rK?YG*fnBf z37d!xAITJhj2TaCX!^+bZZpCuxRnfyt+_qY8o+^oXeEJIZX!n2PnOFHM(=0}XKzB5 z3Z;eU6@dsch@`dB)xcv$ohbW3SwE_r(pu2^6kjP(E%GoVB(k(Hpw6b8h$)LB+w3dr zeevm_V>4m(sFjKm`l-@#6OKbN&Xq>XGrfH|a(J5VnZlH%KdREl4YX5y_#-h+gG{fx zO#~W(DLX{{4lFZDqx>f`wfp$xbM>=gI5)mLz6RbDVliWzg5x|cGq+}V-K;57NCe*NyDD7aVMJd70ye! ziKtu`?jRUT^qaSdL(-6YS)==!dI6598<0h$nI|ZlI37p{78y-~}7~+8CJIe@K z_uE=8&c&L87}hi*`>@sW&qH?61LAA6K)ZC#R$r#+0P8 zr+s=onr)a94fFckY1o@@C3h=bA&|D-22fzViRo6P^yz|z>;UQmfUcE>h&Urh=aYn{ z6NsbjG@jFH3S}@gylu&JLeo!LGB6>%&2aT|SOk{^=4?k0nsY5y-+A6bh$c1Sqj;x_ zoxxl?=44Dil|TAhUu#Il9u5M+i!`Fe+ET{CK`0?@d;^Ur+mmKCzQ9m|2-MU5Kg%q1 zY`@u!4jZonAbt``41;30)?rs;2$E2IU?>h7-T=Ywc<4E2RD9G^6B${b!PHoJx{0!S(5#O#KRyki~^qA$v46d5-Hp|+>zRJ&4LhP|*r z*CdXErfF;{zcwNGX0xzoC}O_4<0sxhfjyyF-eWQEytu-)*xj=Mc;3#5ji-qT7GwyA zLwiM_xH2-sOJ^d~Xk|m<{!;WRZ=AN#YyruP2=VsepcT6*s1ZCVUYe5~_GD-chhm?o zXv*pB;#FV!BKxIvNafd>!Nr^=fsj^}R{OP9@7jI!R2j`NB5Ciq97=U`GqLjKxnLwq) zO&t$HqiRiPdZIUx%pwA^m$(_UfM9248U3RF0!>k0+ zv5X2mBVOF`0PhTyDSQIKgN=u#7YN4^mJO4=s({#>AXLevYzjvB4D;19)2uXIyGbV4Mise6AK;@ErL zFJub#TY-*<%F=?43P9w~t zawpKbsu);9R(BdAS*VM|OWdd&PesYJuOXxX(!GuJHBD}jgVtzuDs2~}hEc7}%{CsuY5J@lnH z3~>Ubvp_{Km(2;X6z$2MP5K6+qaKpXqtiUuGmp4c>TU&tt^W3|EmImzx#vj{k=;5-xquPgQxtzkMZ1e5bA!Thq*gMT?nG@_tk*+%-}OV>FYn&x|>iu zB4g1Vq8qRxyEK&__^DJzzk7*L7pJoiW&*Kbtf?!;n>Hb((O`dKcn&-%x#hK z@gxZNwr7XDHHt~t212U=ZGU_%9@Xs5%iyAS+J4J%4C#0f&N66o$tKm(yNOJutb;+) zJW)(LC$DtLHL;1h-Ct@%F6D$?rrAob-+P2FGE>h>MIDs8YmRcwVGP&wBK9}%YEuB- zmy`LHzO^^GbhGoCZkdJdQ-z}Sqqya4N#-bSDPMC5;r6-c1W~zow<&}1{bNeis`NU& z7mTafif@H2WNP%&Fc+ts0e-YpUgkUYq#=9pN}Z89GjoxHS#=8%F3-WNrkaqap2~lF z_;$TCz<-?yR7(B4>R>J;Sve)?Ux#X@Uk^*TYUbmwpM3S~*AVP1Sz~_UJBpTue9O1) zNn1j0(=XE$9KccwL+ug2*A95D+{fyL=M#QN2G==rzkcSnvY}>jKLGX0scru{w6i%3 z?pLmM{Qq0a+okng#`bPAtM$H7mHrE9uwqi-G8x)Q;B$zd#dm4^{QSh>!u-U|Sk3Vh zbp6!33y?agrWl6QrhZmomzB(>)^N##3)}7$&-mHb}`;gdz#zf9fws=LYI5H7;FoQ(n!k3ck|xi*T) zsqsd~EY-*4@I>ES9kIg~<2(pCb0`_g^VGE76 zws}8maZV;wNIq*5+w*2nkt*#rwI!b1rkYM)cAJ_-BDV##OViHzcKqCL-A&Xzh_CTX zsK4HmE5eOKr+r3NldUz0ddxYV6(dU}Nh;&j#CUaW0teFOImi|!cza;BOB*!7azfiA zm}{$CreF&d=Qg)kTbI+?J-EB9S+6gpcyX(t-oi-b>MM;>r&7Ob<78p>m`;?vo?iB< zCo0zJ!7lv$@p%=+1?Ie$QtZ)9`gVdZ=uv&$+Ccod1ArD=?kg~OJ;m9wyDs8()%-kZ z%hvHysXd%dviaGTN2(=-+ryz)OZGNr52jSHlB45ZF!aSw^OSrsHlLcOz;f!Z zWbAp&4j_MNHgigeBL2H+;W7h09MhJP4?b`+CjH=}w4zfvJm6$!e7T*@3`@0=K5j89 zg6Ch7!)qm%ZYjOnJZQ~ZRMl<3A}QRRVc8h=I|H(*Any#wMrW;TN>t!@c_{B>m6VvJ zB#tb1ELx7bNPvgm?uVRnk3LPpET2Q-k8ZJFaKJBfhmK@Zk`RvLp23CDc(4%%E^Nsd}?J($Ww`H0`3u%&?gcuu{Nu1nJnA*A_Nd>baXZ1QeP{( zBF$^&8iXdc(9h@EyXu?I^HrVBi|uzGlwf|}L$ zYVL$()@&P~h4w)kKnQtll2gl}IG=S|4FHysO4KZ>M8cxFouDT0T=_e{zGd8BT5=LxJ9R{>GYb@=B^nkN=7{Z-k? z_cAIzG59JVo&-8V{xcN2A6?$l79%zYXVOU6>ta6Zu8jXaC=s8qipW9iDx zK^qH#9AMAr!6k3=j@fd-Kc-M)#kuizRPFSG)IXfy<`m0s^C>#l^PB9XZz-xyT#1B0ZL& zir1souS@wz8(n1%_E}vc%!A(y$)DD*Kj9EGgHD>N{yIvs7?Q^ULz_b}Rrl9IWZRvE zXrXcHfH%BtY_RNYgF)Ez2)1ePsdr&D|8uPsQ3BblHe~I%<(E6PizK-BGr^k#+d>-5 zrNmN*tmGVS7U=c7$Y0GMwuBwuV)z!Q##=(2A7MR5Wwrr)a4vgvH8N*|3EhVpX>WR| zoj|mRaurB(=x0i5nACiQaK9PbLEf2Hird z(n|oow42~Iv@YMN@I>!b=l}215Cgj=O}3=-)mTP& zLZ#Ff(drvW+?7500v~-DOdMOHH6-n8cM2?Wde0sI+U*{9XMp-Om&MI2ILqQ$k^c^E zJi4cQP#$`?A8$zJ4@NB~mZ7z|38i$a-sW-_H7&a5CHAF7Rk00K> ze)sn1-O<_7L4A!Em@KaCE^#O+cF5uXOXu_b+Z?1n*+5fXj=+_|}do9$8e^#Ob@cwnAkpbqX(}YoLz7?HAWzar{natu#c70|sXjj=zqx+HRixg%9~&F3 zWs2)S+6(y$j*X3GBC3*KAK|>Nx_D|6?rf;xeb%wgrvJSP0o-@b7S1@kqLIBbr)Yo* z1Why}W?M8Dp9JMh*6!YLg9RO6arZhtR=jaN@G{Ta=t$-<9ps4xY+>(N(1jllE4i|@@=l!C~ zFuSH$psrt}>quY{5}Qq$pn%^z=gy`CwM+?f$C0r)gic4S48;;|t^t$4+H}CBO)kF2 zR7gvgo+5|Gul_74(n@R3nyT^f-v=k}kKX_Ii=RjYK`vw-+n!YN-X2xz?1q#($2mxdoQTSWZ{R5^CKBOMfJb zJDEyD_};sSLZ?tdFz0k~A9PK)5&nlP6*MAT{gV1RT3ySPRWvam)V!UsoENTwXJP|g zQ4DN&;c&S?V@l$vjSuFkz|vPc#TrBJow(_4lskV)BqV-st|b{-Hx<_rOVKMQLyee% z8+a0uMkMm+qpwn1htTy`p^r1U4-&?S97Y<9{?iG2N#psz4i>^wridZaM4|kV~4%U-k zd=iXLg7L2>7^~MQ-eV^;z$eMRs$^d*mfNOkuP!kgWh`{YCiJksGn$c@rmBDDjR{D1 zzc~pBy&_z6!SlJXv9YlPS*LY8t)lShW!D6@3+D=ZW!!&L@&7tJ1A|`)v1d5T6e$00jBXZS$UVoi&7B;;XGtu;#=V||PNA%sj2vJihdk1;M!b`&E zl`zVv5rY(GmG=pj;q+Y2GBQM*OvtCKfkI;eB`P#%eybY7xnyRD{nsO!juUyFP!ZO@ zW#ihr5CT`X>+gZ@8XAbmC~tm$mC44}GRYdsk8?pn8Q0!V^9hmhsG$ZG?A!hQt=jwK zx18jp_Bs^}FxVC0F`m`lD}HKx*#IMhYwK&Tc@~~4vC&Y&-uTq`DW+-usp-paITq8V z53{D8Nshy6+dkt7B`T!*Yyymiw^Js~YVV8GCt)M1Uz$p}d@0TirVpc1n#oYpDjpug z`Re0VeA8@of02B1*@)^F$2S^FA+dZQTcnu|b;j`!nZr5T#_+(ow1TO6=O%n7=2YVl zb-%eG>DBOGFHg_ke|Yu!{QbeZ*Pn-jt?j+7?(LYcdAWVhOc=AtT{$pr#PgmwPyt_& z{Ztj7_mssKvq_!pyk*yX#|bFX!zl?bwf$Efg4ac4$V!7zM0{9syFpzZK9M`?l~1fh)hKT;dRe6Ifb{`?;qi~K)x8hzjYhl8v?_5Z>1^qfZD zs~%O*tu%0Rv)GC0aOi@2;Cz`n<2;Tb1p!ofe*S!^mST2Ic!&i#hsdY`KyCC4FQ}i8 zi1{4Lp?axTstW8mOV3TF;bL)P+%fvr#}!ziL6GRCHT#yBxd}(p^K&St*U%1w(l^y* zbD{}8vW##nS+Rm%LmB3R6wCyy)Nxiis66-4b(}`t+a7=@J|_6ndCVr~g8oj1=;j7} zvw$3MS~z6Mh^FK%o1D_$$*uiH^Sq2p>dd8Vt+qCn(06paNYTMCmmPffrra}qnt_$H zyQgp*4;O)pmoEi&9qlesxkUpTmS0!X@;-*oGESD!^F^H+y1r^F&7`{b6)$7Y-uLKK z?f-`yAZwD}VT{~bV8vmoH~nxU1Bv^HnY7O6dknU?SH&2)s zXc}igf#|TH|C|6(OVu%roeKe>lqvnmS#nO&tMe<&hp4ok>(mr-hJ}z*&hp9BSGUTf z!a}f+>ce&&;}O%bjzgzrRa-+B1bOayQMkWAk6*qNLB^thX7>arr_p>!Axl%Oq>bID z_(R%K36VI$5*G$h57?zJ@!+p+^>eZB-u&G=ZO{V14q)@=khAnxHfsLZ`az9)^A|;` z)(<(28sBR>QqrQ@N}H{k(g$&TY%e{qyoL}Y-Vr|4C7u{t@0)K1o=^3X%+A4uKSa-h z=NsM^J-!)>Jmfrvz5}-2#SR5D?|A!z;a!a&K{|p&P6^0o#Kv$m8^TEJ0($9K5${sz zx;?2+d^ZG(1p139$Km+NHY<4ak*6Ko^1oi+yU*Cvad=?On>q&jn-ei7aoLKvAP1+1?{cax|IFpLGlZ<>zZ3I zK*plw2R~!c7c=msF}$C#1!F3p;$T8jX$snl&vilj%Y#%du;SRPyqGITTYP!W&uXB_ zm*@Vxd@1z#`3H2ow~bYG&&D94H9_eI?1Tc-6M#}U6<9=usC$iNI4$%o>;?}}R~HVH z?xn2wY&WZ~i;YE3mGn^e)$6yf&tAVOdFKD@koKo%g=dNLA5#)%gp1oB0GWUOWAI{c zuv(yi^>b##EpY2{9b2X9+=tk)yd6PP+<(xjAf0 zBAr}`3iNC=1I~W+{#2Ev=>&<4gd0KUXpA_~r`!REu?B@X6AtgFbm^;dq3{$41M&vj zr8%S6jcM4yvmf33s2q-}eP3q&n5{6dRiH0maxXbS3mhF)G?3s#lPo9>hW9EjS41x3 zG?io2{k!P>U34q3bfe3Qi#aPB%Y@$ODha4eEXq%V_Ct^WZT7H~*V_kX*nd){45M5^AgBw?xXb1aXsF0WCZk~j&(RA&)^Wy|8wE8Sre zv%I*xAZ8=iG#mH<1)3xWS!Sv7`Ev(nSx`>1Wd;oJt5^90{gyLX-3zNjNg$VE)Emt- zAj@^9#>uf{e`>d7wj9hkHT_d6(KrHb~aN&{V0Pkd#T{&-A7VRkb0k zp9qI8TSzWeP@?5vq4#YnXtNXsuD7qzmJh)ALTed$x&@@sC`3~JOARerD^`=@nyp%`GzreRKl&9tj zzOlzdT8dcrL;c*yEzt9YOdYerrQU>;`Fel&)J1F4LG((YM(k>ZmPNAvymLZi&UKa_ zoMoJ4oPuSVQLAx`XSA9!zrku~Dpdf|{VO>bp9P0F!y_6~Nr?y!j*m=P5xl`d0gP!l z>t7AJ8|axJ$ra&;EXkA^-2MJLGzhi_y)9*T_)wJXY`|FaW5YD98wab!2ks#T(r;ej z5s|oDqp~LG`4&r-OM>VbP-u$G`w)bl1%cKityd77k!bis8pjIDOsBu|7BzdLT74` zul<#3t$Ibc)Y-IYn&lF~(Q;*anCwWBp&w?--0dKA1SL{JB4LPyb<#Rh3k%5H#JJS! z!poP!f^k{8OrEXf_r(m3??`gS025zaB_vTYN;{{5GV!Na*d-w8>Y_dY;l+0-$>TA4 z=C2oR;XlwgW?1g;ZlD1fysQpJr3HG&Cbm8evi+_3jby8|ku`Q>Z$S$yb;Fge^kZ*9 zKjbQn$i{wbFKA(@MiXWR*rHP5tc;+p23G1u z($bCX1>Lw@rIE{~ZtN^*V5M$cwsd2#)vTwW>@Cdx2}?)$rqKIFPxp^RqBq9}=#r+9zRv&>!*bFfdeIE9 zMlZeX{SIfw=RQWIJfc(>8bq6j$tmI2)TG$8Hj~~1U>r?IN;u?5HGBN4Y~82|g&(12 z^t5C-ZL)mY)2Pld6~RyZchOzdYw^r9m*7m#)eY2YI8}W!1?3^pt;iEE>dbimo06t3 z9ul{iyy^(pD|QYILWQ$q>2U!Rby?f3zAjbrkv=nPpTIU5{D1|4%H4i7*>Dy92FMdJ z#oK%Pifrwc?Gl@Hs_3mTb)(;djlN)p6SXjDK(DL`7RreG!Rq$-)P&4Ek;xC0U5H%T zux`Kkx&vR9i2uk~bcf`hi}QcN-?jT6p5i|qO>reES2PwtfEpltWV1Yn{X_3e9DA8 zh$$BOl#KUth3*=K;7<27UX}yhX!>A|EPC)<1S=rn1;5_@pl8#W%#bAsP9wMV0g_n1 zD`F7)H#c)D+?2!RF`u{qM$;VQcS%ui@#yt*neRa6_c@923`f>fYQSaD?(1>UOQ_c7313Y=q+t4dH}LsF12) zAKbf1CT9zZDx!Go*l@qi|6Tj+@a#68C;w6qAJ#rgJn#uL$2YHJ^~-t;d4 z&fG_{V_(|ud1=o@BVXs{NdI4(XoqO z2B+>nIV)u^1OM#_8JDwf6}xgnbTue_f(plQeq0%nIp`ACN?njGNN)Mezwu(JT#^g! zFY*MHCPeiZ-pa)Adz_IF&X*{eyWkYm+-n$?yMY1Kd*j_^Q0mHZO3!yL)!MJzqu@mn z&FN^#L;!X1I=vF*GC^@jU|AvB3|5Vo$MVJSEpBDLppNO7gtIUvZy39D*t@sGb}dn< zxwz$+UXhdtam?9>44V(mmC6Kg7bA{eDLsBlLY79V9W6}%fbCmH$%djOv9=iS{Lya3 zF(aIUNjVR@QlU9`m4V$7BS{m&a=8Gda;Z5uRlwa6DU%K4Y|4q4vN&o(t6FXjVl|Mr zr5E7|O~KLhBgY{*US>q+R+>l6xsA2=U@B$yBawxC)`?77+cD*X%-oOUs@ZdC3#z%Z zY6x+HBf4nfmJ8kI%v}QV(gRsMQgLzxz z?nSsPf_ay@S%JOu0aiEe`qyX1zNbt%z;@pG7vgfvTmSn`mcYIj1HFj5+$83_Z$UjPo9`o4-z3Md6KQwkMnyFr~8GPWjDnPP^rjD>a*O%E0p+W4-x-Aa7OWWl5ygt27@3 z(}K>=bahwxb}xG_6%ppzbJ?|)Zo&^^@pdVwBuOcY&?T7-5p0ckzCNwrN*g9O4dLpm z$k7%V3Ykz;YaPGkswlmK6l<4Y^O~*+GM&uxl}(HLf$PATDq)ro>=)1)jS?v&)`&mI5wiW{sYxOhBPq6l^{?B92RCs|B* zaX!oYc{ivTi`is$nkkia$WkFWwpp87Kd#uK`EzmnhdK1dSxi6o=}W)%!*;8%wb7(FqYy$NhUjCr`%7iXjXrjjz0%!8U3cV3m{M1SkD$ba zNL4`R;@U*rm0cBE=tlk&#gSvV#NJ_KVV{!;0aR)y36xIJqw5R)v8%`ICWxet|we`O7=O{&=<-C zk24n8vWhEKoDqxUObRG_6FOv`M z`*5Z_uD3*FBvhCQFNg-A1j}&xwsaZZQk1GEZf^}*Tp~uz-ICD&CeI=)$*JU6lF4l7 zA8+tjma{l!xeSCUhq@;$j%hmi395J7W2a3;?iY7))c(s`#!^>)>IgFbG)EP4C}`Q; zj8f&6$i}Mxm!$Qgq)L9DUixwCOTn)uwQhk{y?*h|JhwWgEnIi2F3-itPCQf`VvqFL zH{E(yo;#}SD=aaTguB&rsjd&DTS@rUMO`gKyQph!r0aTlj#uee7d>+*{Ly?toWp-( zqge(_nUL>^yk`8e#Q5I(GGe9q8Kt5~IiSn9SHt|$3Hz_OZ1$E0;3E6)#dg*H8w~cJ;{P7yX|?|<`QPRkfUe|UasBp}vHfm}1osY& zBL1Zu;bDV!DhE&DHXjwX!oa*5j<`W`awzVc}TfNsr zTBhqR5xkSycOY9r(~~BX(B~AdjH!e_Ev{6QX*RaKvLiCZS5%(|M9BUsMxt^eq_JwF zaqrYiqJs__4x;$LBn;I%$P4$Aq&9>9G2tOeC7w7%(K8m-i3x@_65Yl|7g|t{jLtOY zUg~E2SkdN#wzxA+GU8bbwpMYs;*l#}DdQj- z4@m*HVjgr;ZQZJw>cX|V#!N8aOJ;%XNs(pRX}rqS%d6a}@y&)0@urjp_%<5#n+EB6 z2dm_pJ6a{*v^kPiS+q6)v4e3ZZ`q%-MQTwuoLR~{f>8CX)-KIuZ)$f&D7Z2q1}@ovG&zm1p(xih`(i0d8> z9qQ^=6Z%srvvS@o;hO^Z&H=vf$2~C(Qn;mKx#kk`(#v?PEgrtFP}Q z8p;pk3#+|FD9w`*;Rb0hTiBve>h*dpnIQgbP4x8q8P8(-&*))&sqd|>K)RbRb~_nG7M zE_~$bI1%q!&xDNdVNF{VhDAV|-Fx{huYWQM@BS^Xo8}GptT+Hs94^#UyW&@sISS{` z#NfH?`2s>O-yOJa_QRepte%-)9pkRWd;6A&r5-*&ctgW3(Ds{MBY3;TY(2~6X0D`C zmu!KSgW&tNqEJa&km$*V2|d1W^0jBNQhuGRh|qac2-s5jw@M}LEAw?;@W#f54)`dF z<{6+>YyyKU;npMH!W1oviBwl0Z^fvgfi69c` z+r;*kw)?_{X7Qx)C0AzY+V+pkX7_E*5RDy=KA99XggeQ#5f)-&VR?%`eVc5I7AyOr za3MgtuR0taVJe-QaSl0JPZm5f%SOh^K~{(C8QhG+y=>|y^IP~vv?Qh0JAbc5D0ATy zBP&Y`t4e;{6^#_8ZIi7|Fy` z-7k}dyQCL;{8OG#QM41~whM*Z_494VK)}&SM8o)P_K4^&!4y{P0e_Il0Xs>*oH}^Z z6=lnD4*UPI$wDRt$39JhKNnF>1zhEmwet96B*N>M6?DS$Y+)hdacK>l5EF`rRC$dr zwdwNnvcpA({i{Ct{UWXs<0QrD@;xt@yodCZBK1__h89tIk{#eYrdL84VVnPw+x}y@ zCqr`d_=TY^b%Iic(c8Kv^*y*Vt>;b?c;5F7FDk_b*5y6C4NIK7bwcLRzwsJC98KmV1bCx?}Bvi4S(9Etq6@cGr+td1Yqzgy5Y%wKY{-(!KAA6%+Ms^G*; zh4~vHer`ZX3AmOaZC-K8@OWgg8COD`jH4p2&F20c{c3N0Fa;vWj6)>HaP%#Y>shK2e&uhk%Kh+{r>BA1{oqU=?%oAUW^p&azn9RW}%L(mWew0G&(cWcO}+YGMjUQxc+L$iGIYiTt_-nCXcpVv83mnCF-?4 z>1>bOJJw2b5h5s1N8*Bwdhs!A(fR9i2OaB-FQPBhQV?SKSfi;F&O@qJyB?td3#oDD z3*DQevB@4Hs=w=>pR{9G>teG4W1C*U56ZdVGWIv>Xj~CiA&HBap0@U}U9z*toTHu0fa&*8W+jNjU<=m{7H^&2?@Lav7VT&=ox@Z4CtO?@MZo9q_qs}7mggnlIkf9XhXI?v?Poq?Oxj-=lP(c+g*ku;QK6?QIrUcUz!5UwwpH zVNtJB5GCA#w?c(iXL5X6m1`@N?ayUovqCy(yX_Oux424c`Eo1wplD+$(*l*@{ohN_PDkkk1ih3};h54qd%Zmd_5oOg7*!<#mLQ);I>?c7E{9um z2_^q0Db`|mLOV3}F>90^?=NUf*C7%4O<|LzYNQF4-a`6v(u76Qe1?4Ni05FvsOFY&`{gDT|}N7|s%Fm(!3id1{W zO<`!-iS;;dzMhffW8yUFN-Nn+&`;6LTQ{O)natJH#StRCD1SE6IEnI%Fr$nfy*zqNz;3fj2$vVtH}C#A;X7+AwL6~3_UU<9-x32_>tr+27F_;AZ1We;0a09t1qf|(JKqPxVb`WJQ z?Y^8zKz>we4L# zsDGjOAzK0XuyqO8w+DV2{{eM(w_uiNbIsXAPm@_p;=Zfer}36Pv$IH2a<0jB)6 z$D$ImY~vqtiM@)b`O;x>Cbhk8=G3GJM?U)5RrtbdH_sH%b^MhKDHHqSjNMn$yvah7 zUk{ri=Ef^bs^4(YJRmxbihFvW+#O#Z;rocbT=2Bn_3@qv2j;DIobspc zr}+cf84eEA)%vm`+fe$jkC_HQE>>+#9P+|H*jYXbIx@`9WfX<>pW&!c35t-@!mmuQ z^>LnUm@xK^f8SEm&7I~&Q&iJ08Hlm+h%a&Xh`Eeu3uY7|CK%O!O(2slwnK^g;9Afg zjpSHsNB&*vN3LgzKRc-+$Ee9}GHuB+0$Rl<>>|hblP_j31m2P0WO;6l$o4tq#fOpq z6{VHL>=@=g_sWH;VjX77aQLWxrzq*9lNB$UqyEgTEGniV>X0eHcod@*EpF9`PcE3lC0dfBi(AXW=EPBQ3rjT z55(>qi49iz`9*vAb6#bOyX-`4<}-K|Ru#FtBt&%nq#}i;v7*wV=8PQ0Le9-wzBfByddgAr93~v^AZoC+;3XvQwv7x6G$kwzsO(;;*tzkR(UZ{* zX18(t989BJs3n}pz@tj5+UIFsW?yt)t%U7kk2Cf_Y?#OF`m7_$*VZ{gDaX{}$PsQW z=~eqhwp-hEJhdKt0uL&$aQe+0n~>XTw55Ab8ifn|$7C`_nme_|B4$g~v}VY3~7*(cao77MLcZXAxp zr^*XbIC{3VClw;mVK`_GhW%}D4;9j;BkqwrP2ipPOYM$U6DlLKS*-wjU94H3=<7QX zrM+P4_DJ;Zz2=o=x!6IL=pfh1Lh5iA3FPh5xNNSn_@?o*U(PZS>aA7`OaXIloH0&-}a$2t7H zS~Pb1H?^!OG&_!D9@S1z8Q7Ml(Y2;AavD&&sWd5T8=thrsZ%nQaMbi%#2YkBU(R5$ zbQs|_&zXI!f8P+%Aa*ti&PB1u?IAalD@d`DuSaT=8S4aLsbG0sTh^?VCf2_O3{U8a2(ZgT8Nps0!SP- zI!lO*3{RBBe4#42M1Xp)+GyFB1zM!_`p{1t;R`N4xj3Gua((@y%5Aofa>u~9v2p7? z`v7j1Zwl`HoG8+gidxPVX%KNH-s+*NH_Av59ebUXScsr^oT*u?7VQV}dzNR+pDXvJ zg(t~_+APqR^2z5acZ}C<=Gjnmewno0WyXk9!-!~Q;$&>LT`xUR10p*8>~weffl^xv zIqgZe)A9Rh=yL@HLBeSxcV0zM!KoZMZs&~e_>(jZdi2_ zlyNhjBB#S;maC#HS9ZX&u`mxA&mixIP3Ql9ggUbqqk5Jqj;HBu`(=H8AhWhPvU`r@ z0+r8O0Z-n>*(l|!mgdzk#)f=(D=Ff3QxeRQr^YF%iUba=&exQZ61hNRwn{v4f9cZj zYY{S+9ZJo7{VIRlF*)sX4O0(F)zlxw+L^;*v;+xB7N7pys?COwE-x-UxU+;VCTOd# zwo_;1?%7&dsf44<^j?tAsOeP}#C{n+cUk{zAORcgpYBN)@z<_30TX zH0&y8;ab|VA!4$Rg2!%X$&pfD+SVJ~#^r(-y}Q5tmb3{Kc%8I~L>^?N(I$AU8U(#GzuZcf4K2vf`N{Kq;EUI0_A`3E% zuXMap68fPeu4xmd8kHfuC#+d`0Zp{bU<8z?EQak24nERq1#M|QbdXiIK3f0zFFSaI zpR92j@GaV;+#yWK358~_;;p_ibG1(;o!teP{VwDUYX$W97>4XVx!5hhhbdV zE^OG|Z7wofSg6q^j39$puYK!xLmtFOshgE1Hiqu#1xrM0dtuoKGMkb`5m9V8F-uhq z{JROcg^)!e!}#@kzr}vFp**Mi$oaH4aUbErYpMTs5eYT zrD@lAD$X~Zxk`TF9G{l)v0)81XFZ$0d}{`qV-3e%Q~iJ=^AHji4vs%_@ZYRU`HPl` z7milRx}j8E`M~TC>F)Tn;*RA(p+;mwGN!h9g=np?5BJb7RM11J^>Nm!^8DqqOfqNM zW}JPZsTf7Km2;N*`LZUY{VP36#DmujF$woC8ZW1?sIMB9P5a!+a|wDC8Fx&6EhH;y zIpYYZorJR5Vw|5s?=;*CRL|W!DqpvsMxUbkTO;Ho0=IX}h2@IlwIW}2f9QKF0ad96 z6V{}}-lcd9oD9ol z;&Gs_w|>-)EUJ>K9-VVcZ_BBG=`2<7NN!GIeXnvX^DDlL%TkZ?E|mn-eXDsP5uEW$ z>x35K;WTyc#~P!SIV$yWS4SpIzc2<7*J4p;bw2Kf;y7EN zJMWwEru@sd^=Sxw6CnmhSU)x@betCBy-L-l$jC1v{!C8#KA5w<#Z+XD&=~rrHClf! zi!Dd~q4XAh`@paM`P2Gq=_EjVXR{_B(C}yidUsuJS%?XkC8jCM65OSKtKq^NG&Aw8 z56Bs74P5clQe)dB7yAhyt9>{@yG~2mCFS z6k|=4$ZVUBf~PIyy)!zVVV`8ej=*YjAA*e^>3MYhwR)KnlhQ&Ab36~jYp@>#e%jeM z^KgvYB+B^^fXp4{ThMJpC(0sA6C!#ws+YeQy-gVt(OAu2C2MLIc6TstB#Ztoh^-Qh zoc2RM4HW)zsPg60JJ`_%u4|YdYjaaycmJ2;haQzMWFLOpa%NhtZmIEPeLM|{L90rK zB*n4xQr6r+h7eU(qq2ynA6?~g2!yUdMcO5q^O$1Im6_I(*+%)ff(0se4H-#anbY_T zC^9?Ra7oiCy<`qhp7mR)^Y8?vB1bi#GLVB9am5)7?Sh7IOlni#u2HUcJ!d7E{HyF< zY}hu*T$x1ALsMH&orU`8h_K0GzQfTppZCzD;Qk@6T|5gYL4ftrW10ErW>z@mTCs7Q zLcGYo&S-%WMx3qhKCr6eu_&IGb!#g-^?7KNJMym@w!5ls=K;@+oyycAoS2(j1|LiS zE_{uxY-i&FJtZnrb5mLR^18v7QaMEEPq2R*lC2ss>_Tzp&51i) z-z5k#-b)q&@#TAV>(9?37rka zZ@;25oeVbK6M46^ZC5K#V6EGc%eVRB!IBgquUIp=3C9zHrsr|xj0iu1+L8bm!rB5oQlF_A7@J{tC z9n7Zgm`}!Oq_JvK)|Cs~v8L`dEL4f?l7%?rWw;%DrIhXtsE+?mO;h1&$R#Mt5|6!V z2jDDo%UzjMNXf7ewQ9cINV@S;>q!O=ti;wmbbTE4HbiTe?!-g+TfCu3zSsPtCq8q> zO5bF!%~wKeq?Zb&tnm3bg4JqWNsH0D%>FM)bj-5QiVz%Cx z*m{NR{S9qfH?Z_6GC9O4V7fuj(*iL$(RN^YTc#_(-r@quFTBZvUa_Q2xchPfFXyM6 zUR$AKdi;Ay$5AQ{<-XV?!|vdMZiI`9d1kOM6OztnhF^d^voKHuEIX)5E@5)GR?2Ltj}dIJw=aHvvad=SD}bz1 zP6+A_6>tsf#LmF&;GR}7S}|5aC{Pw*ODpoz2C z_N|J+PURJWu-QwJ=+YnDy+~^-6l_f`{htXFQY>DXQ1-gn*GqYtTaKKKO%;-@T#RG! z>I{1Q{2pFXcBQ4tn8zc8gRBqxD^3%B1kvKcJ%8Ze)gHt&!=B$f{H8>NgqgXjejXub zjnC6sX`&`TZ!G7Oc?RnlLdBT*c>>J*rRhwG)K;DS%EvDbU3un@>bGkvohN#*C`BoU z(`Pl(B~BR>J*W@FFeY5u;PTw4cV*jo-HQEBWKyrD!LI)0_CR16DswO{XBk_xNh}&l)_P z6H>ZIMYu5kI)7Al*yZ}BsxOaZU4!q3z1M+fQbUhT#HWz_z{0-1*5v-U*;7#XcNdv` zQZ;@&lqI}KDh`LnXoPLRwHZ#HOwF-?X@h)a|IcaA4QS}%sRK@ zhcC2r7}yBKm~8t=<_UT55kV^~F@&FfM;3LhOMm$=zQKL_E{=d>|L~q}K;0UPStF$S zE>_z?Jve>+;n3D*^v|f%+itRbAW4N%uEX8q{ix( zHHyq*7D1u`s$nmn&C;GdG}y>{jOzopNwfdyP%S14)2Xs`OYcePuUbPDN$Zl-unnqG zn|*5#9yHg7nsC8tQo4*G5cZh1mtk9DbZ}+j4+KvA5$aQc(3WYoqi`&wZQD&1dY$e9})`s{tq#X}^7V@vQmH&?O=SBVbKi$|(zk;x#mmiTIyx!7dv)^iR zXoMz{NRIx*nZ9vb4r?2klM#qEqB%Ac|7rWl9kxI!Wy;l+Wg*8ht+cXL5dFR8VK~~* zlvv*?96knGfO-gzxo|#HQpv&f{?o3i05zAZpLOys^3FV(x|% z>dJxaM2oku0cvL}*SJ^Yny_{SO8C%!Fl{VveCcu$PwoGJ!my8apO#=%d3Ev6=vup) z3hgZ|7QB|%;dNO;yt5jm!xQ6o5lUwn+};wjQPbCk;|`zysvu_-+Dh26IQbrFQ$9=h zEb9^#qQ@cL+RC@=#HUY9t1zL=De*a{*Ekze%Z`!F%ks#B;csw$`iY=MhG2yhYMr+VD*s|zYAw1wkAOy79aA3mj5|+U-dk|bzcy5+O7>)kKM3`e4c=;&SSEe zV!Df+>)Ssj(`B2g8#ZpjIKmtY=f`n}>0xTdCol8dohJkpcBZH8$}tz)%^EPF9AtI2 zZY>HZkvj~{h7UQTTmEt+D4@RxJYXwReaC#n$h*la4bJ{3p&1TY8~VO5qI$;=TRo<9 z*DA3SyJoZg46M995c9;?Z-F=RKFZhb?~e)$Wc^zd(3G(wp;5`!YVoLzEws`TW*Oj| zs}Iced=Px?BvDouR{wx{7yK_ndmQAMDXFa1P`S9*x=7ymLh{#4r=-#%l;rpQMBbL) z%k}+Z7lyJgI|E+gUGqWf2&d~;_-HnCHT&tDvN`f;TP!1a)uO(msl3+DaFKIqNPph? z)z;JYAJ82QfUDEFtfeK#&9|#trsAS`x;%B%7JYS&KViCcP#iCbHKLH=0T>#Qn2;0$ zmw*&W4&M@gv2X6rjMMV1;2)6hlA!n7uP;gOp2LUF~mBpH0pdm zHgkeaDP+)jyNwmlgfpXgzVsaUa5Gky_0r-$^>oF=bbbHvuWueRs;A|; zrs$SmWJqKromJTmRU-Vf&4%=FFXah0)LS0E1_iRMHByq9wXZqGl{dtk3#Vb}NkHrU zxIgmgI5!pK40fi<`YEz^>uH;;aS^hbXlN=;UapfxDJqKnx*opp^EdR2>KoZ1s45>taQ=5J~Qg=48kM^nBj@?S5V z5P!ZV`a&Xm51Fbip=#Qbi*gd|1_>w*&ncq_@5SK1AFG#sE0s!oE0A*>DNh>?ak^Tu zazED>DGN$-gWqb!W{Ex=V|+xz?tA}&?wkNudK_Xa4EwchQpc3LaQ|) z%%0#lR3@SV^)Cvd@k}Icd;mkgI2v_Yi+q#Y6?5+LU{7XY!42Y3n3j8Yt|Asb$L8QsPCj{fP#)>L2w2wn;3D zejI3%myA9y^;#092ZF(=VIEEEi{^S9%`R$~71HNReRpfz(x_RDn1k+ zbmQf9uxRj|&)6vM+vK7Qsa|RYHM4hY2xU=!*8~vp8!*wkB~0*+Sc`14hK4bF)<#t4 zr9D5D9Q4Xlf{|0ARoo6#ls7Rmcp@{?G&Y#d6n=7mPUB+rrS6$3zO<}?hySv=z#Gio zjp7`t3C1A>HoiG>no{FuT&zNK4n~!uN4$y+#U=ZdN;E&rp)dFoOyY?9LVJr2Fe&>Q z#xMk%9j2=M`Gmgf|6=?Q3dr9C37YZr6iJ5K*P0jEu9QD*(t&WY#$_3aZe@F_K(kD3 zgjyyLN0Q0mp5C0Dm<;~djmfsu0$a3fX1m?|pQ0`A=mV6+<$}cam?~@KdfiTyxd~U@ zrLBbMrP)Q6wmSQ8Tfjo6)=o6@XH~Ue@?PR{ujrX=;zLwY{a0z%CbZt#+S=KPmq>## zNatUZOWBJbsFzM%bQ&HURYEOez8>=1jgPdIOxzzOZ|YbxschxVspHJJrgHvR5hrWw zN;EVti)VTKOeg==t0Y?r3O&DpDU%n~AK&b$hVC?P^OvQkfsJ2UOzTK_7=-BYK9l_c zOK;_>3IeJ$&db3ab|nU$>hQV~Jd0a9U;OU#I7TpULC2NGr}2O(k`3clC!EMsrMD@P zve&Y_`gLsvM(@bOhH5XQsf+X$Djfte9Yo$nq{|DGiDKSXj_$}} zrEU!(l?@0~Rv36tUou^{HpOSs8{#KFTzG^acl#NcJW2ZoM#~eFk^hWFUmM*G3{qg>$kz zgB^E()wrg-r>$|I!+89r*FF#|geX4(9JSnj@S7U|QdB(6-nLlWyZ}vxQGf?=!FVrp zzT@l8<#L&;pl!ot?gEnYFWLta?$Nr%&kwuj3jJrgnT5am`hQP_PXL?{n#B!~go?s; zcU^>+r>$T6Z-%W5$WI`o%=m6;UwP+LB(N(Pzp{vn8s3cO;KkB>LTJpl^ncUtSo;Z% zEw_Mu&>?)n2k&P?`(vO5?V(rNN(6FL$g<`>-s$uf=pD<3w9p}H*baRvr>y52^>2Wi zs+>mrkFt00t>z{0(8?eE8-&$*>XYs5nS)oCPd|T3o+(}T+M%jA@TWW+X!n*FX#z4b zSL*>D&MN>%>^U#XLJKPQll>0RNPU-G!Oh16B>=AD@fL+FsYAbao7dyMN3}bbuH+-| zRYd#Yo7e6OwI1Fnb6h-i46e+B`R66^Dh;Z(3VlUOnzIPv+WgysPxpnr>Mt#MCwvQ= z3cShpu&#LK1tU9tp@P$!`~9t==5RlE%g6Ok^XWqVXyb|| zvS)95Dw|HD1zxwGyu2Pq>sup2VrQa9++Z4?(B`)EC}yjsJ6{aUxB*9PKpQNAC0X!T zA4kyU__n0>1u#y>Uk1?>+&%z*m${yDeS>SVp#E$OX-ohzdwl*Il*(Kr&h5L{84cWc z)It&sBVHlh(~9l%%9>$o%K;zAyC0#@e08 zH4%8x+X*!oc2`bs5{-4Qt=3Oq%Os|x7t44yzZ`@N>fLnayb!>x=D^hfK5bC1ccAV- zV8IUc9F#QOJ`M;F^i_mk&dlLL%IFkja7?x5Ji>qE#{sAli3dV`fP$Fn3oxt}5C6E% zK0gHzhB!--<>vt$D-g>seL&K*+soF~?m^${oU#xA(l#r0nVvZZDrfqDvrM$7Jn3Wh z*Iqp+WQ{=887RnB8~5+m2&gykRy}ZvzYWk7B%K52Ngpw{@7SY(6P=jKU6(zLKm*8< zIk?w4vmQ_sq1gkqSCUtMq$%)+#O-EPE9AN+ziqL;ODVQN)CEabz~-M5V`FX{`vYK^ zsB@uJ1s$;Uh6W03IF|wHf|Dm9q|0l3%azyNCLPQtgYp3RVL#eM1_In zx>)U|uVuPF{-)DW{&=Du%5zZ7-WX0$oO_r#?}Fif;1nnJXX3QLMQ@w9-Dj{c7RTAC z*J4b)qY?MoFu^%!1?W@p_rt?4JX@~$v&~gT)(kD>G@}%GwkSskja?oC!=L8)ud=Pj zUqJE8agJfzLgy0TaEAae7oz+ZfQ$wXmh9i%yzaN7fh-b(ULRMlqf1D%;PVtS6=aE! z=*n&Z|{M_>8+T z1oFkuNxJ;!2+~**xo;M&quTc)mle)P%OAe0V+^tXj1T{z`?aP?3_T{)=*>ZG7g-!KEG4&5Y1(gLHD?pm%PA9q>?m7C{>gX3tZMkl=gJ$IPjtCdZUGF*MyD3>lhKmzFWo zc?Fc6(#iNS;toc(k5jh)ahBFr)JFbr8Clk zTOHEY*6-!~LE1zIj2Wt}P@AA5DV^9X5GZ~5WwJAqnn5GZ${HUuah*BuEI13jnpv_< zWo;K?C^ok-9o!IiCR7`lQ}d)A>u@dP!Exq%U4WM;r{l|clFIhG=2sN3Jjg>XsYN_? zF0yic&`Djp`ufMzW+(X4$}3eBCXRhP*r#c4ZsRoMZo7Ac(JL%%*!JeJc0kXP#mYxc zvi){LGRe2cj%ee?Pj+J5ZnGIeVgXp5#PAIU2)-#cnFD#yPg_5&;@m(t1y+8*~=5IkNkk2fvYP3k;Lag~wqt57-&qNsP;mLQqdJ8gcUL3XK0c(8xZU}M`BmL|Bu0pL>cw)}tUFxSjFNV8= zfD&#I^lt|sT7HSzl`~ThSJeY{soCWLZQP}!UV82>3!-U77yM*tE^U7(hs4u1z=WXU zTN*BiL%}uFPIt<6OiU8GgmKzGQ~LCRhEEYEQ};E4@}X1FPNesq`?|vLh|EJbsFA)` zes5yJKF2yaC-TiU*}MU-5PwySAQ>rXI+&77jB3hIlZ|@cI)BS%rGS}7qzJs`XulA( zWNTAykr|dq<$HRWU~&}f z_L?B-ED%Y|7r7=8y!J~xw7BV;_8HxQs6?6MTt0kU8_RC2P8Sz7(J2An*(@GRx+Uk9 zhu870tGqhj2&UwH81*@l^BD!L-}LH3ohJbFO@Tm@I_lNCN!EH+%yjz>B_^G?@YVl< z6_&*bkA+#bzO@n=yD9sf;Da8e0YYlxS0M36y!@SAaKlRWsw%r!rf&dxf}(AH^cqUB z#9bY~!8v$345Tur)V>uQRK}@wgrq)2M9?0z4jYJKDd@66d$%sXCfff?cW+cd(M9bF ztyn1ycjK#%KQNl&ke|A*FFPe>B^ppq3v8|T!($-ib7FV=LOQUR-PdwnY5pKdX+E`T zPdO5O5I?iuq2*7nm&ev`c6%n=Qsm*C#r~JXVCakxbl?VCYDY`uAiDf8o*n0Bnomop z5S{j=miyOd52O;V7;w02%a=ErjO%ZObTjwmJ(af%AzXA3A2(mf9KHp{wfk&27DkxU zs`#V%$J{>BO%c^r-ZRS)Q=e!f_Gl=$w(#&Wt(x=nhxUx8E_1fHecw(F*$5|sV$kch%i$vYK z@BWK^$8!mJeV3%x)q(t(IK-5=0jgqRdO8H>eYUDbxkURiuMh3d0{t$kBNhcRkaa=0 z9|v14lQqf6q8{fSJ8}Gu9OQ5|SknjV@y(W2C3#r|U&8X+N82FKTw8_WQOrx32;1su zXsKOi#w*sOB-3NeUXKwrw#@V9iXmTK3Is9XKJXivoba z!>m?t=sLy!6qE7X#N3Qz{hr`NWVJ?!R_R>0{^!oq-;gku?ij19Y%YtStl zZC47y%bVY_|L!Sgrk&sz%SX>elL;652lGwm+ci|R@*SP{cMR{6%{!#(p|bq9N01mQ zitb=Q?wetA3>;*QvmX#byl4Y%lX}!qXfZ`eQKOUKN;83LFzD)qq_SxInFMtJ<{5;Q z$qw+5K&tMkoM$rLdO3rl$4LeFC+7QnlRwcY`C>~;F!3&U$;AfXTN%NL4fa88`3@8r zZWaAnXZM8oJokQcOW>PnCBM7rWjF$Ps6_yoVWs21?hj}A0=ASb4ue-|LfkXaIM4ds zX0A;RyxO08@S0uSOcaw;X#++*gsWn?ME zAqrQOOB0JLaoZyYvFe4lZbUL?E;6?pR(Y>LkkF;aDx|WjOZ5v5$B%K+luVBrZl-P2 zeBl9%Ou54!#%u5e#A>@0_7k_08!5p-by;c0xb4M(cBQdDU)oC&^gowov0saE-M6%+ zk#f!-IZuGugR>HxgsW55_!Womid_mK45uKDbUV%x_p)vY>pNgvN6&4;5>>UN(-PYL zrMr+~ML@v4F5G0kGIjMM?lLUTm}uRFaxpi}_1|B@xcHZCTJ&Qc#gn<;vsJx(imyVb zRVQIv=p|i`XyFh8IQT<^_YHTFzYQ6=iG4zdBPQN+Vicf0P^+qIGq9q1yHxH9S7J{k z#^O);SD)Qf=_fMfmK|gTAH}-|b7Z08cB|U^8Ss@Z508&yn12|3Z3G))_ z?c;47A+)bTLARMpNGT_!+vA>CL$}nU`qs1_sDcS~;dg3}Q)*xn0=@bp1Htp*tl_Sa zHT^|s19MuX{iCV!Jmh(95kq6H3q%)$Bdl9X=Mvm$Z(fpQn%vo$Fk)z2W>eHy z?O0N_-e0dr!>56l8{zvCQ0dn_fC&4p*BaqQD5vuu{Bz#$Sw!H4(RefJ(vsbNyqsce z;78EOYERK~U{pg@QJ-#l>|sSMetBgH0UVm#IC^R($by%AAM{aNIS{NE5B$WSHOTiA zz#cl2uGF&>ho1(#Z-wuVK@87%b|drOfvg}>U{0IP4{0A11XdJ@iU$ynBi!2Fdil`R z48a~0KvDrd?>;C!og`s~tg&Xp0c%QtDOS+arK|o2oCw%2ILKHb zn6V~|HvtQXx^y70HWBjD-Dk@`9UYP<>Ns0^35A=0GPpB(m*6?|tk4g)igeK%n=!w% z^ecN$K6gLenCXlp)=Smu9iO67CZg3P-`zcLq+@N!H$SHS>WCwGMg0rm#{R0r;5)`Y`ngy+~ACc-tz%t(5?c6TEt zJK5$R@}dYQxkVka>Y}k)#!u5cpjXDWnWO?4dltEUBP- zOyWfUkv3*Gi}Hc3LK%|Lg(%-q{W)c8aVFTzBasBN!~fi`-@5z$PJq#^?wCO{=kb@| z>%LKosRZWzUjpOZ-AV1Hng?mZ_Y!4!#|&oS-JDFce1K#Ka0~!ISRVnvs}gvhi+^CD zE;Ka~;H-sV38aoX3J4;~YXYI)Hr0HE>W(j9Juq^uI_NS$_v+8thPzqOIfD1)0z~-z zKxq9iKPg3@kmxyJK>?)g3BRRDBU}j`ef>Zi0DK7nc2cQ`xs?Ag5qm=YD3SQ~uK3zFKe7ZyL^71W%jj)PwL z&7!&PM6`ae>YSs_QJIQz8nPx`VB>|3_J9IC3aN!{{lFOkgBJ|&1(xIOfW3m z)`=AiAZZ-X4bSxZc8wdt`Vo3@04S||ANZPE06_EKld53yp&-aMfzZbvh4G*|mdk?U z3lRD~3Fo*WJolnQ&*A~b?0Z6T(5HaBNC3cXc};RfA`cF4o&GrCuJ^-QE45QhcIk?! znv6}0QC`T2gODCKtm&?yj%-f9vg0UAN|JanmD43vef%7~4+I5)z9I<#J_Aa9pkMC0 zgx4f;E-CzHbddCspI{~MC!dMfU$qW*&2=u>2b$U;4g5PpE68Vma5%CFBY$)0pt#r; zt^af)I;_*-V)5$C_@?R5<{+oDWY+Q*qIaEm=y3ac!wlU4{6l>306b(T>)48FJ=Mvz z>V1>`#W!sqy>7sb%Hbv^Fd$i_=osS#L;`2U4jECBC%6&%Z*V+{_n^xEIXsvKct07c z5y$+k*X+}4ccrm&of2zt?{3hdXvYu zPAug*J)|dT0SK4*{JT#+^G*DtL=rX|m_u>qvRQ4hO&-JQY5Z)2+3#{6#@nPsKv_v_{7u)`T#+` zG7JD#%Yp-dk6=6{nhSaWT^c-4E(vKxk(>lfzrYQG6y8U~``>iEw|sB3-3tZ4{&(|t zNM2D;Z7zEVg3(tKof~?y*%s^p zaA=f|3+zfh?=Sgj{d!SN|5W+RG&HMv9&QPTMay`lj8oSzZNP~sL0V5_*WR-8k{Ls& zsSlTHn%`&G(Q;|!zio1UN_&M{TI5w(1y^Zv5*7$OcN1K4sL9YIq!5jH{8_#>3JM1* zKcMjwt&ZH4ouHqw^F_pK<+p5BdveB>=DkPYp zM@Kgqp+v(N8z{9l zGar!u&i4Ym5&`*l7ln6p&@h0?V%h0jl~vLKH`N*=joDfYZrv`4G%2i)w%L}+d+h*bL@X8id9iK49_zDA;^V^3=|bn=s8}j~3C+ES zE(S5Sw#I(e9@_ZC&(c6s7qQ+&nd&E796uRlj1Yqgu7=AeZO37n{O(8K15_W;6(|+; zx%b@)06Ass%nRVSLx2b>zzoT#xj znSW=9dQyy5jGWTV(n6R*bWg=dV4=_F0FJeUN6^TJxA)Btyv1|zg0v05?EsTlcpl7m zOI~})q-TFs3;%mPbA9gH7W=ux82j&NltIRX;E z_ne~;Arr76#N76K;)3g%3bb~720@{`{~k+nlCeOuJp4ZJ-#%(db@xrOAK?FbjBKP{ zS}a-vtQnCOU6V*$<5dHy7~4XVu3YIh5RU_Zg*n~;;$a3(v;Gdbw6+ofOH$=TIGK%& zdB&_Gyp}|kMlf%`hxcoHhClh@!k_F{Pim3zbZfa|ns@&!oF&sa>?}ubEFFgqdaT=- zPtx~(b7+|@(-4X;3C)K`;{Z&bKuJ415PS=-ww?^lOhJ(NYvuF^5Nj&?+FKd~SmN8< z0Pbq3rIj9knH2-IJ1Tp=dHr1R>%u7_)bw?)h7E07R=pF|VICsEOO#KCkml_Urxuhuu!B-!MuTH z<3j)*JA!VktCe? ziG9SFn9cKm#K|;QN-H(Ckr4zU9%~V%aN3tv2>kl}kvAKRS`sR>vO9ID5}C{psVq6t zIbYxJ_-v>AF?=5A$cGYmF=PY63v_Vj-+hlh0Hh(4_wiYX6bPRt-v^+0$%%{sN8#_o zdqQsV@UNHeYb@?I`9Igy08;n*ESg(Z(D^6y7}Q}?=KKrx!}$bq6SKAe?(uUeuHNTv6=F4LfDh=6`ct7>bWW zdHcTh#w!0mG-+!wT-z~HAzS-jWU}9o_R%3qsE~R54~NPbt#o4xO|n02wg-p2PBrn& ztQ!#)C>=gK(<>K>$l=XnpqZrBQKu!a=iaa>ChQIVv{zo#ry2l{8t~-UJ*|j(WvEBT-6NfTY?7e9ypi@QSh$6owfJ|KY_5Gx<5&<+p z0UW5`A$3i<$0Y9;rYIEkst-#qOZ+L7=3`F`Hmi&ebM!$A;=2Zk1j5;(HWC_-gR4UnJ$#j?tx7D56PB8#91h!UHy zXjsHZ0wOXH_E5J3Vlqic{%`)YozHXTeS7D<_vOC#?r*s_tLjBn)r?y~_J4i8Ta=pg z;m47?R{cv}q__C9pSH!eKEEB2W*JcQ+7d`{ILV^Ki1@tsVHy3^3GLL_bmHlICv2(- z$5LZ+5a^p0r!jM7f46Y@eQMqc`_Wm(GvV4y*&3YN}->zM6YT04zUNxuIO+C zBVR=khcPOhYV$x~=%Zzs?krgb7Y*Z-i5IxKMVhNr(aQ$4mD2fZYVF$zfvk%jMvT?z z`s1cn(hcOSR`rqBj`6y3Qi)JlVSWCSmr;F6YOZ}is)05tsNxW z;q3_sPQH{69&bXwO%H=O^ijC(V=np&EQAAK=04;k5iw(&)=9ZLU?8a-S2D-m+iQ_C zqi<&ovLK=l`Jq#KJThp{rtlOooj|$WKS?aFv+OU`JJU$TPlUCwddwe2nWA=>@G?Sp zIy@eO#gcN9KjkchH|M%@`uB&=V^d4^Me+tcq+fCxqMSsxpDvhl9L5c`io14OPx=02 za(&HFvyN?c^&_K>O(RS+{p{;!=h5-Nc{?`vs~bI`Uq=ArJe4w*tnz&vqvALOZt>@v zVA*hmfH>1gU|8?J>m`5NG$Cu!{+K^*2?3jziGty0E_*cGOh8l9R&fy~$sR_@Fc_$T z;bU4#6o1b=hND48$~a4@#v&?~O>SHijuF?ww9!N3-2t6;ZOY(>6=kER z!{3yBc51kgo{0Otr((s6XdLk}_Sd9MA-DT@BEuU5dq-ZhQXCn$~vFj zmvMdCAZd;))~a@yXK)S_>$nP+Qi=bp{d6)a)qVtt=sfL9AWdwyMT#F)A&rR)?0Qu>@$=z+zS808d$DFpcr6qNp zxEgI(eFJTFk*6Q8s}hnWm}O;9V*&yq!pV;FC|I%g9?)H&di`ANru^zXprSu9foTJj z*XF5$3C<#h6JiAO7q%EUZZJpW_!Qq9nb0r3Ujce)?kk=W0eeD9#noGV^*c>w zeV4~GC%&CVExXP}_b_%=|B6NPvJ`v=0}%nVuiV+cMhelBkvRUphp@m-2rmNafj-*P zfOw9zq+%AS$uW&^2Kws@4FZevtY;9us}%T7(jfNXlrz9Su3Z#daOGUw+kX6jt?rZy z)4A1vZjvns)R1F(eXOJcTRo$=`VQ6?5$QB!Fq5t1^YoTUC+X+$*-HBopt-@sLIy*i zBS_mEjMj>oDWfC}GjgU3Gxi{6vv?H&{XuP?+{`9}5Hm1(cM%MwiE1uuG2aw~ANelJ z2QOpdqAym^2Cs7|B|L$l!4 zNc-%h3wJ#v(Rl_!Gu*Q@cP-h`6i+hx?Iv>I` X(}Twu8&x6#fdIf*neT%*tcmy!-ZISW literal 0 HcmV?d00001 diff --git a/pkg/iac/scanners/helm/parser/testdata/non-deps-archives/Chart.yaml b/pkg/iac/scanners/helm/parser/testdata/non-deps-archives/Chart.yaml new file mode 100644 index 000000000000..65225b732935 --- /dev/null +++ b/pkg/iac/scanners/helm/parser/testdata/non-deps-archives/Chart.yaml @@ -0,0 +1,14 @@ +apiVersion: v2 +appVersion: "1.1" +description: Test Chart +name: y-chart +version: 1.0.0 +kubeVersion: ">=1.21" + +dependencies: + - name: mysql-operator + repository: https://mysql.github.io/mysql-operator/ + version: 2.2.2 + - name: wordpress-operator + version: 0.12.4 + repository: https://helm-charts.bitpoke.io \ No newline at end of file diff --git a/pkg/iac/scanners/helm/parser/testdata/non-deps-archives/backup_charts/mysql-operator-2.2.2.tgz b/pkg/iac/scanners/helm/parser/testdata/non-deps-archives/backup_charts/mysql-operator-2.2.2.tgz new file mode 100644 index 0000000000000000000000000000000000000000..b80fc3c0425e174020f5829338d436dceda8b322 GIT binary patch literal 11892 zcmV-)E{oA0iwG0|00000|0w_~VMtOiV@ORlOnEsqVl!4SWK%V1T2nbTPgYhoO;>Dc zVQyr3R8em|NM&qo0PMYKd)qj&C_JC_E9#Yd-XuL1y=9sBJUREeZD+=}9ou6$>F3;@ zK5mGFB(zC@4S;ggo}Ax)A8Zs!anoYE(_?-}WD+P;6$*typ-_mX;@7apV$6|beCu$G zxb&td3jegeXM1~l`}ND0`v2|i?c)F2d#_*pY3Jpe?Y)<;U%q+N{ky=Y=7R_dF91))S)QC`;Zsnj-1ALA5a{J z#77F{&cxAVsCjIr|Bjx*_@AIK!D7t{pke&)?Ci{q|CcYH#{YvnBtj#+-vQuwM1UPCNHKMM_kwNG(t>NoNBP z4FH89gcjT_2}6+MM8FV{u#<1hvG}ot`RQ5sDd>MEB4X?8{OY*x$ z57D$<AB>En|gZ**7W9@J|g|J-wc_aJ7NEo%*W75AodHZGGE0{v0b~ z!Wp^1hBJSQ*ZFqq%a_jGT@M00Bosq8VzH;nb)h%=q8&A!**{Q90K8Aem#9iQHxK*^ zBu}UhulMv%67`eekbH)2uL~9yrh)p|(U`gAN!r3N3BxJ;nxK#j2@aHw*EoBfAFzR~ z%S+XQ!e77u`zR3@1dDLS^=v2|5*!8s5XTUbh)5i0f6AB$cs`hFE*zcpRav$45Ha>& zc%73WaBOUT4a7RkgmqBqcSIVO$pAwl6rKW*M&4pu%2f3|&sZ`{`RG2TytG9szqjGF znnCREZ#3Tf@7j0f49AoM28efQ*kkHCJaaD>L@wrp${}?BEP8(y-2yDrXnWBr|CtlG zOi!wj;U;w?OmAAzFr`8?z+pv?>Jqc=ERvDsu=#CWoA58SybYDX-Tg}!y4T&shmPJp zG1!T6?94ZVo-&L)G2YS`@59|45bB3XkSD}5P36A{9AaNGermya8Og9@9i&cM^$o?b zcax4pkFc$DgXZq8q{_eG*Mv!2Aafo{geV%}pf{KrKu${fm`{jbtZ&%Vx5(Ersz_n4 zw0YwMFLK8WXs;Y&ZHZDJ=kd)Bn=l=(?%n2PW zwKLeX|G%?a*#FzzdHv>T|L;Mb?Ee36C`2@19^<2}$xi2n&|u$rg1=|+@B(WY=tNke z07FJPIQ}^c@%4bvfY8ykE4P>$XxjhZ-7c*EcK3E)Z9k3whj=#N zZ)Bn^2P}kH`(Q{1a#lO=0rEYR$T8#OHyu{v-Tc)UZv|a($wK^{k(fqZ(Npqe#j7Kd z!7tc1`}aLCF#EarU%R17;Ruv|(>_UKhz+&*{yep;PQ;1v{k?$a_}9F}W&GQz1@Z#E ze7U>R+uhK;uvrG50p8^p!u4)2t!eb_|07k>9CM`;YREx|2hgjl3L2{h?8)r$ZL0gWAsgO9@ zw-%K(7KJH+Vxr5}^m9jb)g>OP-kIy~s;QtIvcTbc5@6DU-qW$;k z_3J17{}9iHRyh$O6jV=ZO|zycpxI93NrBo2_ov!;HsQ3A?1*5OzJbXj23 zZlwvZ{1ha>KH@HpinCi=_bS6|3q!jf6%uMb9$-L&PzQ+V00Sc3ENwxyqtc>NL7`dR zug*)e$rquxxuF>^E1KL?Q?Z)V+BR1SR$S46@ zIbO@!%NSw}l$5j->$u5^;S~_U6CFD~NP{Qq!xc_iRD3Id`&Z)t)Fqc6NUL{UueXNjqr zuY?u$d3^muNEW#_+B>Qti#!#fj_%SZw;QuFq!$4cF-j!U-Zh_b%tTdJS#@K}FC{do ztho8Vo&9I0nkCN#G}wQ;FL(Ef_TS##Q~c+HJR5nl&qRZyro}xNe-88?!S-9;^7|Ss zw$&P1);hZnQ|#d^ur{_po!~7wspo>#s#>_sP0mZUq{|GDf0N8h(2P@s!FqqzOctGG z2livDVg7%!H+TNy&ED?Q{Qn@2j{MOF*wW)~1Pj=I2WqfFmkcSB zu{j9Wg)Rzj(NuJyOYsErZYI#<`Sa&?%l?I@;l1!?C;wg;C$}w1nS|$KB;a|-ZZU7D z`U0NMBlyBXG%&xxoGX-Fc+E$8L)k60=Lr=oFbh=pv+&@9b(u4&11SDH={6x>!k|p+ zdWS%xkPbj`j~#fA~xySrkvSuRk>9G9pHw3*{g zS<(6coANp<2Sdp?c4wHaxMu_Bwq{XAx^P++zI@r5jooSmH#-U44!SFC z;HTi>Imf>ygyR6Zrl<)a72w`04OMJhl~K*^*9vI~))I|U?U~_W_W1MN9TZWT>BAyo z&3fNGh>vDgn$Xr)uNSgWFT@iZzWd)NXYbF=%Xk{8AG)CHboC1& zJihK9d^*0qIOz9(IKMpVmqFE&Wah)XkYYMtOR5%~5<{vKlY&K+|2W6eihe%% zaPYU|>x+-4r`H$frzeM1-CU3HT<4WZYH5cS6F;<*&hP))zjkLxkIp|FoSd~myVzE< z9CC~TLa`7RoDJ}Pt`YosHjBH*XHkS`P<-73AIZ6QTQZ8big7*|1=Czf?Q}=s5f0I` zk9|f1YsAc+7<0mc^y6OUwFjrCxp&%d`Y15phuz!<6o%~ff|Cge@dzIa zABD)IYMP}!Nm=TO1!Z4VFP+nHs%*3OB*ZpkC~KudxblCUwC z|1SQBQqtT~)+Cd&v+K!42OwtLg{Z2Z`|$SVOEWXYoJr=ha38J?FXmR`Wz9Tx_cxCJ zYrCVeN(f+6{P&yPV*KCk?%vb+j|X|Q;cv5fUAtso`|ncovXE8GofWki6s~8(Qq?IN zbk09qs~1Y(<@ADft1hJ)z{^M2`G~3&)Bw9A5I6ur^+xS8+u}3GDV8cPZc$sh2=&H@ zcO9vo*PA8u=RE7BE*6{YPOUd|qC3r~bb*ygg{OPWY$sp4L%w;}R0fydG=qUHmj#bRH^+In{@MOwXGEI!H(u5ITYw`8Q~Uh1c1Dt1%HE zl33e7AjUWhVHC1~*=itkvwDE2zuQUAIx8ONOsum{^e9rht0Ty(q5X%THhlNo$i5i;z^f zB=LwN{f-7!3wWJQBW(lDlF?Wn!MX`3B=U0DHasEgJfi&3^9@k$J(G$fL>_(Npj@h-~h&$ zx~iE;tlsHpJY01U$si(9;s7QD!HCFlGSDDVC|C*?Nyx+b4-go`kB8@HSC=Q>eY`q3 z``b^?vwwL}@Iv!XPYK%49x@)8*ip@zQ{rPPaHn&~;wdMJtIz!xu)Dpxy{Z0vxoJ76 z=-y%+h%y$3LlP3TNcB1$3n2?y+4#!9PpvW4JwKkF93G$bkAHgZm}2PE4ACSN9M)Td zkPWsZPw35-t@}dH5ne}6g1Mxp5t^n+KO!VCCnyvU;0X>{?DEAB9zcw^Bv^Rxo~fzL zP_J_>%NaDvB=NCuLAfFWGfg(i@ep%&66j}(;LjF8#o7ywd)nd_M2+KbvqHS%?e6@g z^Q}pvI@#0Z>&4!#)(n5O%&NMbj(wj`%IeZzcYgl)XEE-4^PeW`p3c{bf}pS-N~P2Y zmhBe8iv5v?W1{v{3tA&ld+k8(?Aja#v%G&f1WNP$rC+m)$+=H+$zCl&Nwo(x=)-7s{!`{F+Ug>tNvj|Mu6(Cb)W?!IfE<_35Aic56VTnjv6oS0EmWpOGAbNqY!nNwaG=S46jX?D5-B~ z#{$TeY0wEuPfZE&cv!DdP8n_SI>>3gx~zC6-AYt}%}}nW*14 zcv_3@$7~woYK#Yrg&5INly$F`1u&G+bgVtgI(4HWP2h0YvljytGu3Yb$3fyNB9*zL z-OTC_Rc?R;4$>G8rJ_tNrKjfUbV0<6cZl_V?ZdPG{%7!)e|qkp=RNN)FaFoFMskf! zV*ALVF^?ZMw$v*4b^rT$dgIT(FqN3coCy5loB7siaXdDtzzmvVeg@z?Jnfe+UbV9j z6?uFzA$+%L0d4Q}(W~G%(Yr*-JpYf>O4gbC>n=(%reg)>nONIZF+a*6bf8aXY{DRs z+8H8Q?jj=~Zkg1}?dBSP@9f?-XU^6jpSx(O412^mnwESe5=W)gYNsIc)XgyFshTRY z4OH;8B#da$u2BlYi1bN~S|e2A5iSOmsV5?oL`k#{+vU@_`S^18?aQ~X-|W17Ri_zu zwztcmCN^=DGngsftJ3k?uBW3Q=jTAJJC?Nckj{iCg5s9vHhYHGg zQQ6s_d$Z#YJ$?L$PjD|W5ve_swYelJt&B*Ag(e5Vg;Iz@Vk$G3ZrV&ME>*LorIN@C z%p)Q)7V1L8HOaBS@{)|kQhXGIj!r0%hfdQ}33tdObBWjylIVzVh-W;4vIzlTDD>gZ!!e>GT&)hFStZV+e(tQOl18k^ zn=V)QThWeLW_tHc45tTu7O77{kU?lii`Ywt$QRHr~C6@q$}&jQyLu zYb4|S$$3f2`IYIy?tF=8>eJ!M(}`K-fjJhQaO<a0OXGPQHo44FI6R2jliR$8bo(PUr=anpwXU|H;9ss63pT-gg@9$-Z9y{=` z;$YQDC#?JFY2ZE$T>UtSSW9P?JM!G6Zet{87qz%{Q;WwDKvH_(nSFQd3O{>NKxNgL zPu8z?&JRzP&^3v``keF)p4#|V^T&HaN7|c4^&1l!GhImysixL0wI2oMK=c)PL!y2f zX;h0Sy@BnMV8>G}d(7YQJg=@-Gk#QE@1MHjKfN*!s(Dhbt(~re@=>T)of)rrLIZ4u zqZT@NWbw)c0#yJQ20sD zwCko;L#?NCqKYg>p{`m-TZHu8D0uyH`awh1V=kpGD535KFDa%sxK>0l4Pr*-&Q_OE zw#bZL>bc6`*<#*-naN+Ve>IO{BlG9cJWiWPc>y0UPaq^W817~g_ob)HG4Cc4-W|sy z!sr*f59Eg|33RHu+NMohYm+uuiJA{-6HV02kXeBuJ#ZTOa0O~UnH{frN=&;Mq3oXwwb+lozyQgVSMEITv~fYM}{6ASVApjrJ1hOwG83fokGf{0KeWJTCUN-~n;^)C-IEJ9Q!hy&f>!RV;qLh1cVF)M@bYvukmZH?1h50dg0otpJHdVQ$>x< zLt!uv692}=oo+(cIE`&WZ*9AxP}FMEMMzT5ti9&43+Y#=RR`yXC${N~H`5F%p*t6s zM6S-$skn3Rcu@5lwX>Ip7D5}8OLeIufq*bIRUYlppu z7JeP1@kfyR{@%a0*z1mbB#H0u6{CG$BUZw{I^L;?+6#jf46r`yD~$P> zCslV3_52}6+6b}KuJ3apntR0gH za{Q`PQYG47nN~7gQtXjswN&YnV~vBR&7Sqer^8H?v0fSl@C*qc;@K>?T6-iQWX9owF$VRgsaoQ{_^GOSs?+H?M_J_&E2xhbhITq; z#c|#oJN#gHRL2oN3voN=k<=FxefJ532aCxPBSQ2mrv^Hv7&H0))uF0C$8}> z*B_ID`lC|NM&=vbVXIQf6I$mzzkmAF975=5q0a1M>FT9aHpcvC@u`*1HrDP2P!yT8 zY9`5~FcZWHP-}#CR@N~lj#TqRm zd_JQT`z||+DxOa@wv1V*QC{BgaI8#INGtxGu>fB%u7fd884A8bp|a+9r6i`plFdXt z|Dd%@^`%F`GN4nHY5Sr|Wv)117q6XK4;=>T1Ce06O?CC!Z0{>Q%8LX%6X`8b&-eDW zU%$}F$vrq3+N@Rl79>Z*A@R*sv?Jz*NX$uu_*83deU*e(Df-V_PNdt9R6W0GR_7KX zOCgS!S&1lc?o?e0PJj-C*FdX4-S$Kr5)&L^=A>uB1kr00%vU|G-N^x??5Z6ZZrr&B z()*-(oMnF7hMNc83{YpTXoMvv{xV188WbLa3(g`e$2bu^A*UgBZMg*4r7A7!#4~x7 z6~+4Wekq|%D$u}K%i-g?qZS1@XQNT5gZxeNvy2?Zt>qYDFIX;@19Lsx+LyiVZpqBC zaW@_dXl()+y1ok1k4}hP((7dm_+|^c>_~Lhs?Vb9#0ijam;IQ<0OF&>TvU8dcKj_K z9M-xTSMW|4z#mX-6K$%-JmW~z9#P#pa!iC}HV`rEER<)2Ez#@EV0h-Zj{p<|RlS%x zVD5putjDyF%4So0RuuAw2b*fi=8sdUb0=nyge@5gWvjA+_ZX#VG>vd`7R@@UoY06- zl3sREMP`$h$Z12JTv3y$r??NM0X@=YYOy9=i38fGdMxUX>#1pV6u&U*JC+!{8aZ(H zWq$4gy`a0&c}5Y(X0A?GYc}npPGqXXhvS6DOjM}UjbKn6=C{#;i5uk}UL8iJb9hNw z)VV$jLu>L|T~^M9jpk`?18QTwHq3vGsMgTvF4Qm9}r^@o%}mx$>OW==XmpM1mxWPuy+btKrfvszEi_;GABd zO;~?e>QROx^`WV2+HGzTp1J@x+Q*hG8l<|=-hW-J-Xh_tiv`Op8mhN&kj6q`s#b?B z5E`>caLmfMy8xM$ab7S!b!|*vTa0R(DAn~zf4dm5uSoFM5vTenlE2Pq)kPx1?r8+9 z9<#bo)ap`HEE2hTkFl$ZMX#>hUrR)=wv1t2K`qV2vEGwrS~!Art;*@XqF5hIVXZNi z^>?7N)*I2fWK8RVgJ>ObtuYG#f5yJOGiB^7uf_n^H7z>U07g(0i!rOwple(oTiv@%+hhNqR$ zA8KW^LUluF-|Yvlx>ub7($-&$Ibi|uQ5a4whtrML``=>Tgs$7?uF#{a9;JHt-Ri71 zE$ro239I|QRy?l8I0fwR`GpNOK}@Mcp8*L#;B!U+e^!jGK9~pdTkH4CF=x8WR6;Av zR&+Y#vC3nT3+VtdEQvNC!kpf5DZHvx(;8G#JDZ|yd_!v%tqJ>9u?`Q9RJ*u`h45-` z`?ZdNSg3t?+*k-$-vr#!-M27z7PHP5cl|Al5UkM!2n!PkOE^bh8FLpJ<0iga)zbzG zE<4sl$J#uFu#C5GO+?&-*AQBI4q?qBrtLZ%zShCA9*-hC?r2%BcM%p`t*?og`|~uy zqTa?8C|b0uGgoVA2u%5nL$_okYJ&~}gnp@r@2}^0ZB|MX`er0!m9!hw81-Mpk zCH$Ur;JQ7Ru)OyYmKk`D?8St2E~M6S{w~B4n{zKmNTMd!OVbT=E$^4Byj{-VlXbdj zQ&mknNSOC}6>CrGn2uNSrW3N*Wa7WDfzlWTR?TU7eGqwV6xViG1;JV09uW>DU>s<5 zrhiEy{C{h1WLVD4NFw~3zSh8=aw_;dHvxY}Q5@oZcy+#hf=C$6i@Fem{)W)UKDUa57A_kSdurk)EU%w?rzPptSY> z>7Sp0x$YfUBIBgScQC-TouNypnZ)IK8JRhF=xQ%c#DP(UInt zn$()9F=vh22vS|zvRRVT`cipGq9aSDn$$s#ITm9UeidrHq>t`Vvs+jzX?I5PdF8D} zz1*7IBo5ky?l4R+m8)G}U7L{y+OO8?GxKZ$p?;VIimM!th>$kH700pCHH=R;%d+<< z<(_iaJKPRhDis>C|x{1l2El+H0LpBUYNP3^#W~Hp~9_h(}^0U0m^XAW{C^}ZRw#duX|e9zj?q*?zw6?bNj8Dn6swqX=l&kTdrwykG9=vZmZTwJDr_B(=|p2 zO!S~mUN+-M%cj!`k49k30)vI|F^rj7jHnNWEVIxto34=10P|U=xLw;BLz>BMk#>BZ z*x&Uim{IgJ6f#4hz?PQn=WG4D3<{x0_TQU1{Esmz^dFxTx1L6X9T6FpEJC5K@t`Dr zGB`UURST!3Rnw%C7D#l1X@;PAE_x#pLr{5b<+m^;lO3TH-GDW5RJGTV_GEx9vqt( z7qhZ;_~~%HeZBhiC=2u{u}z4uL~5<%DJ>#mD6yD7m`QVR=|9*C6TxhTZAg%?Wuv;%UqMS zl~EQwr!0E-bIb(p#VqI%YQk7l*^NZtUdl}ClIkI0j@OCaknvs_yatcm%*XPcgc9@I z%{T3wSFQM$=h`K@Ed=PYVbS0sr-c>OHM?1hr9OEfv_(2|?Tm zc8+cj+XmjRF@$$9Rabw^J^QRNnTYC88wIVe%Fq{NWaF0H6&bCfy;D9fLPysSvP}M* z(h=auD!EdCV-#H4i~kl+(y;El3Iimt2_QSE3PO2+rEwr~aPzne?VE8!XjleT|~MW3lE6kh;699`Npur<+K!kG&Z8{jUM7(-#dR zsCIzA|HsjpUXp~9%q_U~mY!z<#ux=579tg}^g>-k)k-TM6A~mSgbP-_>%KAD;=i-> zeDUtmb^jMnOnmPyU=bqpOBZ_Z0|p<_XHpBWKKp0yDMdB{_Ex)Em^+!OV={8?jMUkx zy)O2;w;XE5*HGkTO?NKbi6R-eg5fV`9(0QU2EW3FN_rc`{x`o=QJb~&ml9fEpyn+bk_OV>B-q~0il@= zYlRxqIGoJYaX8L@Ss2YK{4z1S6{yD8_vXoQsF{oLS3u0(tY3yus{dQ{w!+igpId|O z!Dzm#10-=d%+$B14;B(euSkT2L{Z!U5I$42&)o1={L{L?2>cD9!M?>ji+D(c{C@u1 zDG_F%3PMLoh`3@QWx>GD)Q!W0qp#P;&co~9#Bm1 zXNjr$OL#Yb)jpKTPRC$w43kSc@Ml559mkY?ORv3#&*qr3H}Nx${1AISi#ozi$0N>? z*cQ%yZ^_BbanAxDGha%$m_aVb!z|L39E=7xopjY>-#by7>^l9Z6ljoFnKqkH?wvoz zQRZMRi!nX8IQg{KFMO!f-c<`cQDX4aOaQr@14f2QclztrlbL!8Pvfn!&$WlJ#PQMx z$PBlV&DOM%Z)aV$FzHrJ$Jk_7-aiU$a=fkSSX|4DZcCjwc)%=fYglKu$lTVF3vIog zi{@!tzze*d+-!@uZx>53wQv~nJ>Ff{KAp-+Sg$GL+Jd>(*23tu=6{v8grFBsxDe@X0oMnk}WV)9yJfyTEZ7r0D^)b^{8Djn|(|# zaaehhlctkX^+~weBspu{!u(mRg+1|gDy|$DGz}Rc5tmizPHJoVEQ&+yoSX|+$03RZ z4wkBGQU)ztEy8llO1JatSyUOaR_}AtcG}{!`Q!>yMEx3huIv%3kQXO0Mm|26AQGZM zorA2ZI{9t!N)Z;KVqsoVZ|!?Z^LqnrHkGndxkP+~CHRe-3>n|&92#rb+RFI2=i4{? zMpau`dK|65f|#=)@v)8q#9M*W#I?Ave4}gMXt}pt3)_u1EFQ)fD;5dwHxwcoFpu$3 zx^H23CuRa>H!`wiOZF>l`R`dgyfEPPN4Nb@(z^aW+qjr7QN0!6LM+nB4Jx|Zm^Yq-y^Zx<>0RR8m-milINC5ycGHq@E literal 0 HcmV?d00001 diff --git a/pkg/iac/scanners/helm/parser/testdata/non-deps-archives/backup_charts/wordpress-operator-0.12.4.tgz b/pkg/iac/scanners/helm/parser/testdata/non-deps-archives/backup_charts/wordpress-operator-0.12.4.tgz new file mode 100644 index 0000000000000000000000000000000000000000..4086e9f1a6bab460c3517d28d39566d0226371d2 GIT binary patch literal 38731 zcmYg%Q;aCUvhCQmZQHhO+r}Q-wr$(CZF`Sx&%Axky*GKC^h%@BAD!+>s@5v}C{3Ze>_+3D@R zZ#rAviv#hBXjx(Tm1@?QYpRvif6e#Si|$YbfwGH-6o{G*Zf;bgd>2MO@ppaN)y2i- z>3U6ns83v6e8n#=u8->{?x?Ph^W&t-K28tc=NVsoY!Aoh``ItQ2)4)XI7KpK#1Dt} zLw9AOCmx!46jd#m*`qNC0WA{Fv3PVNU;LdgXCE9Hq%o5C3G{UxT zpb_2a3DTnKFx;I9z<1c}sC?%sQlyPR<$>NEUSOy};cVh|qn`Yfd zmm#@!8O6upgaV6olt8OF{|amfQp_Y4&mm*Y$ju+$MN-csLMn4Z^a$OSia=ml=Z_9& zt4JImcH%orD%d0l%*-X6Y*Cp1_TU!V^9go!feremlCYB?iA*3rz4`&jyW0DAJqa?u zmSF6kf#i2cN{WOfOStfpS;>HO{!E=?A`L$nkc{z28^!cUAXH0K&r!Wyf}A7Uiz6|X zAaceK3G5^)GB&;v+Spa&Yrwl?N`rdBI^taVv6xW}ojbP?2JM^I@dyJyuD=E_j+DS9F9#nuVY6u4|FWvL9?KE z2O3eO>__l@2e57X^GgxQO%vQy-Ga_7esvkXLu&@e0DnP=iUOLQq6$%<@v!>2E}Unv zbJxWaaQKcTX5{v}u@E|up=PXCbZfEnsf%L7#l^<{`7<7b^rjLGBibjlV<+SwBa%i! zqU48lD3X|iD_@A#4G&_)Y!BClsBMYIFq_fN_ z8mUqRh}q4+C4RcF!S`8vvK%eLGZV+0N0?FkH9f^l(VfQFtaK8AP#(!we#7DvRf=MX zeg7>lBUqo@(_M^+h!m{}ZdxZEGRy-R#gr(cAfVqrrGNpWB_IIJy$^>#ak+ z;$?HSMd0VL?D1fwYbz=%*Ha-$!+ zHqV#qYiD*u7z#*J)CxSHvhA^JNZ)tk{k*Ie?TCWd!Y#nF9Dhr6=SwX9)pInt`W@_| zhutisP$}4Vb&w)zzD<81&&4STHtY%T`j1-zu5?sV-&bQ3uzxP*F~BFg#k*hVPs)MF zC2xb;h5=Mh4*YO5>?`#*7%y%F7|CD;iNph>AioJP5r(2jW&}K?q)|jO60{O}gC~57 zg&zZOakl=>nO6%?A?Q%h?(8uF?xO zs)FtY`b*UE$;16+Y|AHm4p}cZU*%T{{--~dv=h_356mCxqo@`8Ccep#X6_<~HwJ%{ zkRt4=4UG}yay(Z+s#YM~(1na?a9G=!s|(xQ`3R00!n3C#-K)-eJq2jkEo~s?pou;qqgoI~Vy}+kJO-DS?-y*#RYQK%yE&Mrm?>pw+RM({5>7|$|!V!1~ z;~c@4$NlR1K0aPe-*2B6)c3r%CjI0cRbR3&_RH(1B7YR#AkD3&LBH8CB0b&w7-(MH zPh%V3KyolWJ5C@sG7v(HtM4M(##isE2E|tD#8Pc@{p~UPb?zMw;luL~i)hGX3hJI2 zh@_*%k;_n`YyJq_rApl~ySJ6S^O0E&nj5fh3x3$(zvaOgefdD%*M#`$^Dgg ztl|4TjeYLJV1hu0L5l>89n4jLi{IGKBT-_ILC^5mNe*_$;D;F&os0rqg#lE1@YtEe zo_mh%Bol_6?*7}%R*2K4*FfUT<9PftCt4sb3cPalTc_{$-AVO}@Avun=a+v(b$eWk zXg1{Cx$kXGG&PMf!p1^Dh?r&u%sIOXLBeGB+=lX`2ALMAo6=tqe!Tmc68ud25w1=B ziW|z^iQa!67~F)DXv8tv2`1)ylBecv?~a7B=NI1Ya8a<3uhC3wj2vK zWrzu#{5d^h#(7%{OJ}0^Io#P$;Bo$VN-Y9Q3#OIT1z9oOhJBAw6uQ>WjFd)tKS4Tx z(^nU7L(JqBjSb3sWoqbhp1v=8`n&oL;#;TXIZdXfYo+Z8dcn>4=(xbc^o{BeJeWYY z-twJnu(XBZUY>4j1V@n;cwZ&jFTHpqzz8?ndSP4=&Jdwz zwzBY@&cHHmfuzhPL>YT?7cP+pOwoh_r$;hIA~{cS0Bo#RWV0+7NTRVo3D{C~$7^;! zOFcXe!G^vm4~n@6j+Ax%?uYv{&z(ArV18E&23aB^AS7#F=H~l&FXkxtM~@J@>gDGO zY(!-|XE(f3_^l7nuZ;bzjU)KCi+;37_?!P#QEtPKZyrG0O%qBp+UeAd*CX%dtCqdr zjl1u%LbCI*>(~Ai)iVzCI71}u6y2#T4eCc8sUin229l5E74l~ez4`jP#o$+8KRdUt z=S=ocw#WGSho6rtck1{1X0S6t<-&Z@+|| z9spod3jlfsi9bzwpWb`0+kM6I1i0;i+I$v;^&O@_4|jvdY=J&n@|Ne*aLb)B-Y|7} zC;}8Gj|z!iHS(d4{65apT3Ty@dJo0FRPc23c(DGQ?gRG<WMNr1&$v#lnZN6ml?5QNTVumH==$uRw75GchMpmjW|)R!k2IcN5$% zcje|<@pj*u-6NFr!~>^!dCQpf%AT`Vyv7)~<2;F`EfC3R2kRlLPTW7eT_((<^9V23BuOPu9E+g3c)1HA6uzDUgD!}q+Z&=+~#8C5Z=#Y0(MzEbER1aVPdC7sn$ zV2FA%Eoci`Us+g)$7Q-;@h0# zm9qkKs;)v+*_RkCW(5!Ys_uFEG4Ncc88R5+P0vkw)O*Lv!K` z{Pe57^c@}9_r14T{d#>rU)F7X(91ie9QjdtCHF*4%l?38WTer*!)| z?>2q$T*pEL(U>^UU@Q$ZE9gGIDx9_`WhamCJ|q_vMmcCEJ{2;Rv1J>WJY^go36u0; z?&j|Y(a%K^?8;W+Pww?Oc1T(#LS|=AlL}5SqVJzR9VqC!RR1!008sJ3pkXpC=efU;qPr+C4sKj@A z!m{1jzE#}=Qp{iaF|EUZqGHL&RPq}kZmyT528=FYzqP!x39psxWe3oRBy7k@N8v0KLKUF|WASt;G2%v;_E4j|)m})^3!I30oaKV%^R3O0S^yUJ};*5YD7^KYwUvs089>H*& zGF_E#QT8ne4F4rLx3UR9qNV~Tn}Emf^#H&EP?@LCpgbvVFD#YV9t4&lq%wdPGny@3 zm_iyOg5f5`=^zkpxDO=zB-YfaVfdD-xcp_TQV5wwHI~H9_QZgIQ@|fBAf4p7B>$BE z8XP++^#|cP0gncCV4$8bQ^d5txs{osEf^Fv6#SI~btDLCQihG-kdwW4l(pw+XUP*!nCs z0+Nbw7M&U-fs#EG{_U73?Aq@$?B!T6cA6142A8gZA;fmlx;}dUSrj#+I{%eZh}RV2 z>1YrNeN_mN@t!&Gm?@(YOp8kr8B5W04I8(>N5i4=g#j%HVuNx zII}bIVrF3J%fql#mIFhO{%i4y)x~MRAcZ5Pf^MT@B(hbN_5Nc znGS~ovxxu3wTHM_saPhg7X)z223E#pEDi6ERf8k+;H5ta0KLp0#ykyNeiPVo6MPP! z7U@lOr?+{M>#5Uqh*Xn=*J9{jN3t;%&@Qs|pSOAGy<0~i<6kRffcr$(c~td}yeM$0 zXGQ1Pi0(ruzL)ve$?D%Mf7w@wVhoNou?b3H4G5kkWxB}=B%1<<<&VQQCFv=h_KKhv z6E5O(Lb42ygG|R&(Ar)Hm>@=8IYe{nP;I{DS1I^Mv-2Tio)F@+M#V$;HMmavC5x*l zxj?B@s6v}-NwB@>hr|npTtx_EoCJ&!hbQb~Flwek#7qQ6qS7;|Bvkw1;^`K&g!VB5 zx&V1jL2{h#+FfPXo7!fH%C1x^o+^BZ9A+HzJ;9Wv>pYXvOe?R%7V-^GXG{4;&g5ot zO|L}SUSC~u&7gr8y>$i1Z-eIR%GL8mO|RX=*9G7)crJ9Kr-dK-&JQUE=PGIdwuo#~;4Jx^M zIhXI}UUnXn$b6Zo_n_R6(V;Jz(I#y5Oo@6eRZxN2UYZmNHK_|$nEwm+RSQg7UjJ^c z3NjpACu$YYI>iju=?H63C@m;VUY%qQktmlFM*Bw%Hs zL$l2xU48aAIu=OHr8mLhsZpkm`K2Z{3VmB9iw~UEvgn7`Ns~e`v|Lw8*I3l)(wNKT zWUskk5Lu8b+~xZnuGf^Fb6WUCV`d_F#S zZl35ke=kAWQld5Nk={I3CM@qT;|#;AN>o&+(hJY+a4mtaDSImzt3Kv}BG8hC6p29< zY>s6LUsZ%y&~n$9$0+-uD$TAP@>tV4e@9;Nx1G(0lzYDUl*DJP2lN%BEETc>oXC`j z?9=S2;fTfykSew`ibOV|A~QG%w&C@B#<|V^Y*5o>*Cyz@j6r3 z!7lCtIjPAc^v^-t&J51CbtY;c{@wK~8}(Dh(bD?t4z`JJW8h=AL#1aN-#n1_t+boT zbZKkn%gP@HXRf)iKkJ}}FjPE}K4GM(gF_DXa~yAv#L? z;Ro*sAW56lD)qqM{y}7>TBTjdg<559msUmRhX}PQJwQ`RWgkI>XHI=mVf5wHy&;9W zU=a_=2s=q=9~-qc`tiv~qO0OZ?h>IVt5Gw0^J%UQrJ+4vW9faY^{8Yr?EN>PN`9rg zcy(N(g2MtQgK_gM4;XmuvdOu4sReuA&?iE_s)|$)h2~ce_p;abL&;KCW;haz%H|>s zLKXqj=u>$%r+U62aA|EUDHAaQ5Dx+B2?o_$Z9P*-w9PcD`D#~5-~9+8?e{=*xt|xj zF2DpTcq!6dP*U(-m{WvU^1|QYD>T8a;v>Hrk&MsL2qx6FwWygSO8KIfA2!VsQ1Yq% zxX?!%9&0ck4CHmdK!8dz%|eSza2LtP%3%sJVQg>3UF8p34lMNuq|qP%2FUJNFphna zh7EeTC`Lsbm!{cwXKk0Ms``G**XMxvv*U$opApH!Pl=6Z`~^zGcgIG0c)0B8#syak^fXr9kLVK}Pvc>YSKr(^Jy&_V<(uB*Ip&ELP0;&}_nZ|Mp*=C(rK7aBJ;nXvrw z60gkcsJ^lBH>*7D`&Ps?dD6wtSfzbq>EBp&M%Fjh?mX;;sbK7N2ORb}C;FjF-6?j$ z{&po>YMr+KKcrFZu+e5NbJeZ6>VZ2?h;>nAbF(<9wZ&eX?w7-r20QdwlskJG&(7v2 zJCvRoFAherw9>HS$aBUhW>RJqZ=HnA9fzgOuaiZ9lSa@FX=YLGnni}m_ROHzGmiur zS~_c`>e$LnO`h{QEAJK|ET1$tbJE(%NoOrRfMx+I{xj$5*^;^c@9TP4ky_ajQlM6C zQ*!-Z;J*l9Q||unVfvN8cr6)+wx#aJKlD_}-G6(3yw4A31}vOMx3cfq%)RedPNMzn zij1;UmD@L~Gt*31Y?`ccBMRzgDlMC={gb2R_BCzytl-FM}QpEsK(ZJzg%1Go0 zCd+gfQzgsq$6em-1?p;aSBVf6Pg3+6#T+xibry>I??74F6{{T=DNu6<3E75xE#;K> z_bbPEtHjmED{F^JHbyIba2 zbb$?F`mZLTSN4Ty@&Nbow-01M>&M6bHjZEC>$>mt<>$WQjoN|P zn3HC&P_!jCwXtp=_iiEAtW0s3x%3Jis!HZ%RHt&P_c#5a{X=qXc(?+)B6A`@9qxN78V!7YC4X9y}8-hc+`k*@L@5|{9lyEP6}slOXTa_7dWJU&y3|>)mRDzu3&}$7dn0;@ z=Gg9hRy-s+^KU}2F%uyWxo$;!Kk?#yT-MkZ`J=%(=%YM#2is&YUsqzr5dq2Wo8D7; zyVhg#vsE-_9q*362HUYD8=)3{GkFrF&`7D4K$12murXH&)3RpJ#+5FBW=7Q(!LsL1 zg=CHgi>+7%Y z@^_uz*Xhsi(|+6@?$`Ui`Rf5cJlxCc@6XWIt^FtZZ$3ExZ;oja_v88LcVAMJ9|)Y2 z!`W|<_xY8YSC?zl2tb^62R=-Ucr769u3&Ab>rMjJ^@45<(orcivHC2X6i}EV~IUw6UW;iI;W%=HP}F zaF?928rtkA5T+c}csw6V{+M#=B@zmcqOg_JM`>Vj@CctI4A6vz$DsDJErw+N`%9-L ziDk3brRfcAS9+d@G4F?qE~mioQHY4D&@5)$gqOlEHQrywKK3wNRTKF^gO9fqi$Uhn zZ9tvIMgO4~#}w>7E{H7hm=M4n=hm`)6t^OSaCnWeTN}B_ESvhtaCUQ$34F@w6%Y-J z#n)Uh_$F%MnmiFkRD?Rf23R(%qQ4g04Q_NrpITOH<0LYyIcf(P^B$O|r(r*1O>XLK z=<03wbM$p-@|S$qTJx*9SZ_D8=So@fngC7g*1lPif#sz%PwI3j%(z}e+DtkSuQ~DQ zX4F0zrZRs1{k57>G8i-%fY$_kS`gxHWJ*)WQTG_y+VCK&*PT+Q2!^I*XHHYEFU5Tu z(YhS)KAr*ha<^O9gc#?v>onMTfPe79Qt9*tppB^1?r#WcY0vv6u(=ATFF8ThUothG z0l#?HOyDMDqxC^{-w8#Q15`I^ zE@+3H`Q|0r1T&WH539Z9e+s?Oqre37lLv%H+4%@Aa?`7QT#g*{?gY|Je6blVyx`W` zG`Kr!v~M{(SQ_Xl<4!Ho7K&xM=~fryd5m8;a*BpWg3~35I*X!5XC&@4HwD+4eOIA? zijK3&MaK7(OCm&5s~3nXo1vy~ix!e0$OV%fkh|O}^1+20JOU?#4uxs!#YsZnFeEOW zP&Oty8cJ(=(SC~g2%1r)>xu| zbMp?1i~_QRqchFy?TP3xYSPBBZm{xzpQIZc`GLGn$N@7m%yM{l+p z`?2nISr6mS5qn=Uj$8CxZ&ILPvc`yuS&xwvJs&16oJPrt&20oG>SKp1ip3lyFQ6Hv zEG*SO?6;dPXD6{o>5FN{8H(jeVs1I{Fk7Xx(F=KO$z(HoPGoA|%^a8tsf`M-yPHdR zWM;ZspkN?>ztdc2!9|N*l3ugVxoL7sbYcdV&wvZ&@#33&?^`aXv$O5%5e6(fKYrp2 zESGOUfq|*c$=dexTP@#=rM2R(!L*BQZAD{WyO`*D41|5Ws@S8+KAx2Cw#AA>g8?;J zL`P4!$5V==KqD~02IhZM4-(S?8=>4!1PeW_zUBWxV~wJhm?Txzsa`gfdTf7*Yq#pB zTc7s5?Dj>ByA(!I8&s#CafPPWb5g!8jI))|R%p(F_ooJ>q>m2XQWFY6M=s^^EYm% z#NcdeT6Qn_X3Bi7<4_wz$*6ul@LU`Fc=*z4>%O(dh4sv(gTm|{!nP>OBg7`F6umj?^; z$Q_=bzh-_olgM{sYWOex~y-56);#ST^GJejGOS=Z)&!-N6TFJKln)3OcXp?u$pO zaudr?@m8w$jcX8cN!(Nm@&`(OU|}A4UHGv~jJ*$_q{m0j!(m~crEz_>`LR8^0F0_#0o^`l4BhIt{O)EOD4aeYx;Y%(@<9v2y`IIrip{m0*TDXnpm)WT z)5{n@domSJB9=ooE(`QogF{W-nDb8k+~n5e-kCet>xXVc6wyIBuxHrkKwk zKAvjUhmzUz2T=pHvL)LUb>)LuKMKzmhYB%Ip~OZ4X_nW5pa_-N=*qW1nA%KA1aC1| z4CS!FX#feH%WB!P*0EnH zY1KNb&S$;6L+2lNb5@PjoTx1?pu?WhZHuEGw*o6kC+5m0U7ze4a5HrTVh2_9m+@x4 zAU&UAz@wcVe6QgRMiR7wlxbzT@KtCiUCEh$>02{M#l*%}(-sNri@>$e2@Pz(o0a zNO3i{6P^1eEM$(U@fZhyd5MX2O<(Cp;dB_`ggo&)6DW@CH%Vd0Pcs1#-;xpG5XuV2 zre|TnuR}g#;(fgJhvj$+CoA}t5AIR;z9#OGmO!c?qnk&^>M#f$6=$li>!fIZS5og%{7Q= zq!DujYyyZTreQ_4UmU#zsc4d~2r@*EgdSDP`;&~*w|Xl+V*HEKvoe9;5eXT&elE`1 zRC!+Jxy!v$G@4`Ylk))yVRjZs2p!ANz6{Bh)5GD2WUxT{`_%(r#oS_e8h}nw?`GF| zMYc^^Aj;>1rCTumswVbtp0r6u==G-8WT3wE zB{uqY^?trSqO2K2ZGQiC%TIl1L14TD>E5v?b!Ne|RN6DpYx2*UzU~Co8R$Q#=wB`h z=^;kT%jKr1l9&Z<+J)JA<)gKKSd@}S!g=s}G+-LWelh3M2d3x_?lMH`42h zex0NU?{nt&b=lR1?x5v;=GWcP-Sc+;0jp7nY9@te5nUW8P_T^*A=q(}5m+gzgov}{ zWA$XBF8fb6CmVw_G!CpG51AVE&z*EdcMnp)`tik-@|(zi{iqc5FQr(mp>llanE>Bjma z135vsr?67%aH<-AbkVTVfu)hUC5N0>6E#Kb)HCF@n`dm+?W&2Fy9Ksw+ zw$jLFoKg*zRVk=iOJjfNOt zaqhqR(3LO%z0}*VVq!sKBEv+0lNM0$=)jbFbQt;d##9Ggm(1;>jYH?wD7r9posGL5 z(l(uhb0JqA7}8LpOWcdJ6!31Eq_8e+wiE0*!DjKy3<-Gm17neNcAmir?)*LL+m1)T zqu_fR7O+}kvQoU@LkdEu8F#a;)zlu}25J+wxv_d&wngr1 z7WO%MAuIP*QP^rzt2{5a-Ke=of762=>Qfm^)m;gVzH7P1oszumXtsT1L7Ogtb-Io; z+`@vV){ZfXQ(;7!^x-~ZyTHNVTguI^4-cEK*l+z~R34d!N=&5h}|5k-Ui zgUSwrdeLxwzghWJ2A1WYK0Uxv+GZ%&R#Wg6NZTRsJZ^65b&_UGk6;#v@9t~CER|f1 zBGxl8>>##lk)?e288fXwHae#H;-YEv5($1Jds(ju9#ic3(i)RY)jyyhMAp>vj<99b+Mw#}kTmiMm~aKX%~b3EOup3@}u zSDS8HY_=Dh^;PGc(p>A7r!N~=-aJQuk`A`T=_X6+xf%9{ZKfo<`N1Z{IJ?bW=dBs; zJT1db&#hUt0nZAk)lx0jUXE)jjxN&b_D?dZHt>x`Y?A>luhzPqSzYT0QnoSBQQIjY zCv5W@P$u(nlLl7w95TqlX$BOG{tO~eMkb=c(OljYg11PVj+A66<+z~6e=cgi4;#+r zIykvNGL<5ejLt~~tx}JOhBS`ik1w^ho+=eMn?TVWu7)Eq5;9tc7S+2BxE4St5#TIN zCgxbUVO7-FdMUTTqpqxQTp<~*Ec?n_^8_QNXTEnqm}F5<@dRPx3SOx!T#Ugg-fGVi z<`W&PUekVW3HG_x=1nJh{pIS7N@oad8{vkTrF&gRrRhH+8d;goBBm9j_SQcFl2%Q) zkjWe(GHWo)LPi|x8!{ttShbbq8iuTuqk&b=!g6!u0u2=F5oIN9|1Tp4xJF|(3a2>t>n%CzQ?%UOSao#Z20?+6yl)iZA}N_ z0wGsJ!!lHy)Xp~-mhlMSLo7;MxV2{Qa-9Lm49oPXI3ZhsFw#t+Dk%6=n5+p9r%yv0 z5bVaoU~OFy8f}3?sthOd4yTjT!!0XOvki$yDC2vwv}=*+9oYni&ucs_c6xlfiZ?tw zDrF08z-NA~_HKt=v}QI!KxjIdS}pxfU3j_z*kKQ&Vo;^Q2a^+E2?Q#5%IZ(DGX32= z&}>!f9~KFB7jnf>6j>OC>^(uRRFJbv#J{J%S05{v7YoM+RbS+9M#`!nMECoUJ? zH3?93;Im(fwp3VF%O|3#-)J`l|HypQNv2D3hrdMotd#bhJ7TsjM~j%b8RWXIHrxnO z6hXXZ#CTDN?;&{Ht==pu6SG^Wr?ka08VU;8&LJe_S*w!n21bGdTM}0^* z))V6^RW|jR15^6$b6nBGPcFFH0#k&Ae|kLYOKaV`R>=*c*3Db%0Z+~*rt9YYVYKOaf>R7$A0s=}72!Q}tJ>HzM2Yiot;RD3AaO7@nef*OQ+SpZw%8a$WeFnEYvGD&2eG<&DC?3ccUHy^ z`f|JcV9kF6)9n>0G;G^@6duEA-_UBOuT$72fSM2m$37O<1w3T73@=KzOJ+!j zp2No7U`dO5wVC@o8VE8BPE%qe%X%=e#!T7GeE|G{{{hm45;@KAT^%9UOfuMY!zC7U z5GpA|v#pWmjUfi>@F?v z8`(9%(=@WhiYG)bwz8v2k2{=p?cu%F_r#4#lMxvehmFy$Hk%4h4l~f0R3fGhs-QwH zE;UL5)|?@HM> z2KFV&vnPQTSxE`6bLPJbLq0*HkAZHUe-W_jFDqZf_G?S|CtngLb~LU@uuZH#Mco?2 zCdNOib`@eB3s9Tb;J?!vM2Gj4|4jEAt5|_H|Mga}{*tx2%&-=*ekLydAVh|JGV_2- z>vtBG#0Gda94t*|T>Mm{^J)K{Zg(X@{gIJW%^@AT8*L2dwPmKifr7_|lQX|gT?zvP zCMNgC+8ojE%i4jt0jTAYaoGZw^49Mj1*v%kC2fdD@GF!;TT_@zztv|&y4$3$yoFNZX-2SQOwRx0-3Xu7}nGo8lkqV%JnVwSeMc}mIz{Ob%mC=3M9|| zV;P4@k!fo19{oYI85wR4M4CzbTK9!_UqA$Nt$cFlrGRkb#JP@K^7H&QzVn3xqJz*| zvYm`)5LTrQauqW~LrD!RCP;C6c*LXojWPPXT+zaUz4(L^k7+^X%Sm=vV@06N3jJ$E z5@K%qZx&v zAu{Tad^O;L&>CtwsZqT%GWNYf^(KdbZAvub1N$A%^ zgoVR>OvIj)tHowmZM=WP*Tkcamj^(8B%MGkxs<4G-HA+E5+H-5F$fIvO-)IVTw~ru z4M*m2lllf^LKC(4(G8vb>|%%31u)=)-ne@DmZ1i4L4F0QWqTZ|}mMnGw>H0u*pa@L*JTvw)Iqi}=>pTrshB%9P` zkz{LGNCXfwX>{y8JK>s&;n9$JX}U+ahX<1+6{F(5u93`j2Jwx^o6jGZ{c4*-fIgcr zxY4VKN%tAUa4(2l?JGB@cA2~^Me$b zZ;M!}kB6?_AJsfrHL5!VcvVBW)K&rn^f1^_8s2-ZSgROp$%Lx?5V4MS%BY=C<_zj7-(BbN|+zQc*S^ zNZPt9{hy_+`(kC68WaDX4d=4G>nOQpDMaVX&X~`Z%{rM1ntWDF^CjkD!m)E$X{GU+ z@D8ntl6Q62go~)YY^X=EBEN`1-#4 zAhR+QOCv~j+Z=e;tvQkGa`ih+0&PgI4pdJowML1e7eq~=;+Tmb+QX4T#9J^Gt)OKA zB)U(ZN{S0b7dHV70JU=6+NW$(&sw&-$t8i8D^hv)W#++Pz@qF&piEoyImmFd}0DSoYC4OX)vn{XoI-;I0@Pv4anE;!NjOn!`sfzRP2H z>HX}VfpV5YVt<9iI08a!i6(OBFo#%$lY19P|6BkJ2gWd%S`;=Uc7~NKP_v|zX;`d` zUcwX5!E?ylpolO{jkN_ZMf;ij{VBqeEi?=i*R%Bpn_Tf-_B|^>_D2YcCa}T6qr0;7 z353um*|X!z{U_P)hT1@Qj^QEBJ_MAt_^x0$<)r3=>L!eZ zHy%)CW-c>4(Qc=4LKn`o6~9>YCl1J%RIS00Br?{D+)M7m8IuKekTb3ULJQbQ1~)8Hf~!3ULj zm;R)%x8*R|hbENTKp?RPs9P4UI=gY=XKSLF#L~MaiKiT9T!^7iSX zQq^#;EmPl3-0(h_E4yo9tVO-9zGKy%69P6%awH2lHCy=wyG(+H@h^qR)ODicb2{{e zmH!oFFQTjReETm__gs{)KY_{t~-T{nI!T&ugxROk+2Pkm|Vc8K^nzm4lh{U^X}2Vf}v^$keK0D ztIVKsLTQvd!&`fYn?Qj|Ld0mekfi-?AX>|@1hQ%%OV`u0+$J`w4nR|g7od~5gR+- z>$?U>^N&5YfV9hmQZMc*zy=Zk$`sJSFuElem4(KHPD;hd>9_0|H%M>~AX&Dk`k{!h zXjk^rF)l-kqmU&%e#cTu|BpPOerLcV_)S_Tc;?nva#tah7Xw~h`S{=j2u~~_3x)u> z%u?uaR|K@{-qaGZ(kE~`HUze)MPY{G$udZDn%tRwX^esLc=BaFN@v-Dm7GvnDQj3| zW@=^b>}dS}9!wAtFMhaQq)E@ow}C|ErZ z$7H1}l&9)=&^g|ER5ujo?P5s?uUtwJNz^;>1#}I_LU`2_f7aGV%vodq3P??{7c(jl z83 z0J}<<2`@>=EY)#w4-1`c`*iy%Q<`hZOvh8pF^lYJmHgcb05XaaJ0N%EU$xGtp#8-C zEJUbReW0B}oA=F%L!-j%)p-7R`=gOXE7d;%V2rSUZQx1k`$TQP#L?barCajIs-|9M zEX@HQgGn&oq^=_k;nf^VdHu5WIeQSyMNs z5I;4n)Syh&UXwYZQHgv)3$9JGmV+HZQHhO+nkA;Ywfdd;hy`~{?dpZ@kKB6Hri;TM|vJ4fMAs>ApI+?|cjPi5WG*ahAwi6Nv3TZrQk)S8^9*R`*dY)Dls$78 zH2z72Oh^ejRgjT}>R;+-1yK;xW1O!WQV=$z!OciQT9A2F!LzDD=G26ZNeB^YT95`# z_RUEM>;D#vFa0~hlfhE=-`d(sOKQT`i#92!|8;}P_KM*>^aa$iNJ38dz!|#-?hP(j5=C5zoZ35dX}lJ~+Bids@L&*-P`YiO6_P$85<~3m?-qT*)}dVpED>;=Ur0L>fhwryxQ}0+9g*O@5QxYlH*ofJvZlHfS_@Q=I^Y?Eshy z$#T2ZOFqh-qH0*UzHyEf^>+Ufve#pz%YB9CwWDYIt< zqmA}oU8G9;h-Wp8^R$V>eF`ZBNNDto@u6QCoAl~@?sJ2kYxpfcuBnPd*`j`?H&_QY za;w4}eWzXUK8!WRsP4*Fa8^KpNkkY5PQ?DqMMe&iZ6xoHrrqA8q&!?T-n%}aGLaD? z-QkwdB_3`*Vk=0M_x;nHpHCzh^VGv0jhgn}pga?yb)ka^+b_=QNh1Ku3XI-Zy&c%` zuvr6{;xNz;7i2!oUtFed@rb$HGz2gb&G00!DKWvrAKRlr(97H}_ih}LU>xloM|Q6g-A3p__KKmTed)x} z%&uy-g7LTU$!PO3ZRT;J$ZT`nF>{=XocJL;v)Xv3;ioUySX43ek%xEhrx*Mfh6_+z z_%Xdb^xUQ!fZwx|?tzISk;$S=^Wodhddx*akR<9PtzDnkqrkr;6JWT>FeW0)y?W_h zF5y;6ri$V3Ddp=SImu@^$n71A%reK5R{3m$g2mk^n)%T-otLz~WS_99g_IpJfj`zxkVZ6 z@EAX9Bj(c7tSFl&Xev5wSh+UkZO+wwxiL*odSxSh$LJ*@GA zs!S8s&>@gbGz_h(zPC@9DQ-kQqjw^Xt7&Zn+*J-f!GDZ<70r$%Y2Hk3yM3+JTUA&T zr>@ZwU&OQAGg~wCR3V7`9Yt=ToQdsHn4-+&o-9c?{cXpLY+#2rKIMr}Bb#{`l2>hp z{-PI;u=;J(km}3*`T53pWDN)KUGLH3DKJbW^DiqGC@VhuO>Vw-@5zhi`APYi`*CJ^ z;TG(m=_E~akUgymhQlP3(h0k;nnq6nD3y+9L6O;dWx~t9KfmuWw=A~7#%%77Uk%u> z;r8*Nq-xefN*SFxjds_Y%z2sM*jjwtQ;}hfY-;r^OOatHLCeXu_S1fZMm(el&Qi!U zNVSpM7!Y~!wEyHL0KcrDKu3W8w#ku5O{EM7-Xe zO$FNC+nv8jGp1rzF~Q3xNpx;6`$VMzetp>22nS#zd&{iOEgPD0eL3_NU{1BfP%EW# z@s)r7)sZjXTdu+Oy6s+}V|%zM2>F{VL#6e6*?y>ev2vt5iQ7~{yHD;k&)z1~T zfb!K7O{QF~TQkY&R-*w{2xPz?CWx(NcjyQWL_?PV9y&d5$ zI{-Eza)-7m20f-pxsv7<#f+}MaJ5#$nFydl`;?@XJ5+^2hz_?1#? zC`;7rbI<~=QMwsVXT4_zH))$%m$DZSmRtK-)m$IeGqR2)ShEG!9Tau(j$-55A5j{T zt}w^{-UEZgtbL&?IT%C?oC$Vnfr-0?_Mv@*Cy`-vbWAf#*y{qXh{D|b{IfQ_6rxl$ zEf9vyp6l+q6PVz#8w1&1wh!9yz*!e4Rl5yLjS!EFNchSSC}=dJr@!73LU7$?f{VC) zM}6kyjP4gTk;?|NFb#R~mc6CLQT%;aEM^We2lT!MSsADIW4)z^CP4{OuE+G8Z!&$$ zXAh=pp8yqK1|z80;Z8yl0&17CjENh5XXpAvp3OtvaULl+h0{oT@Q8Ork(unf)cx_@ z$7~p~KA~`6Bs5J3zosZ~U`FyzriEKUxwRsFR74@;^!9T#ie)zkQon}0{aincS`<^>C9JVoX70gAy;y(oUdc3Q#(OTY(IX>PC72J2WTZb{ z`;c2OrUj@tVl5K|*XL)4+fGm0tNZ#*Pa6++SC_Zj)7|C!{>T3L^Zn!0)X4YA@z%Jn zyX>bTy7fC=WT(-OxPt~R)s|+|XEQTEy=pm6Xs1$#MibPo{O$XEhotbjbu{!Ob^%j$ z(7f)|qpP4vHTvgX=KcL3(v79Byg_|Ck>W6kO4k>%YZFx~h zGarfI)C|>|N3D%6HPFk+O{ez5S4UCBBg#2-@%;aq?vTxP!I%a(B;#PwO#dVE)4%3e zRcmr_JPKt53!!&yz1>sEsQ^T8a<}Q*hEBnTGoWUix{bD8^G^k|AO!&j?&=I8_9i5A zp7VC9bkmvqb`I~rX*!9y?-)yz3Be-i7rER_%y}bbwzHn*8N!t{+)CJCogkXB6IgN( zM6>>30pZJ(4l9)?JDH04y*O9CiqT21v=}m!ZTyXdx;kCb9b#bdVOTsKuTWog!!HXQ z&GGkXBm*>zX!vXYaP20NJ`He9Cg*>&_KID-xPB~m!(UH~PCx@|)qUJ-rg%w1U`=~4 zwuwL3a+D;an>thDkd{y9F^j18)cr{6qzGv$I(9ubN7&oyz+G+pd=A|>XVR@NEDkQ? z_$Cp=^MW}aDYI_k|66N|#>G;%_{aaMxK+D_do`CIRVI#G!zU=OVLw*VdHx*vGqNPl zv^y(c#aQY6QYkt4Y!PM+0nKo{dGkobK^;BQVya)cY-YB`-o(udclxkj&B}H)8_;kp zVn9X*fqpvCU`bwcSpNK@vSeXRn>oskJC=zJu)S8AGQVw!y;h^yQkp#s4f7x9zLwqh zqP}Mbe!^zfBIhfO>`pPY!oDTu8PgB~604UyxW618QooI(NruoT`E86ZD3ITIWK7#$ z+^xJ;j7Tb-h7E(gTqZ_AOt4d$2An^Bo3(#o@-`N)%G_xhbqqU8k;0$m99Qo$SzcS} z%2mA^7eLaY0A-2}lU-rIgs<@6D^ZZ{Q+D+;#$I$Vwq0mojg7AmTlKV05L#`0+F!X_ zPW$uZ>=5;_n;pS*+Sofv5(zGnvC=ae_5t>g$D_ApS1}z2V*z{nZo`A-v>KZ*015UO zxb5IV&W3I+QQ6V!d2}#dd|54T2HI`w@BSqdUjK$@^K$r!DP&#@QU`3K~pihNP~pwXtK>rQ1;E^H&e!Y7vlu?64jxd!EFriC7b+kR4;`uh^6Ap zAo;T;h()mKD_dOjWKqwJE_f8s%a|BG4+ul-^Tmu%tI!wA z@k-}EMDfE0mL@s9U`zMt_dzf#n;gQB zA6v(v7WZDUv3qEz>#X+rkm$J^zK=v)yzeYq0-(lWtjSZh=%c7=6fZ@4mYcnqrDVS5 z9T!Ws+h)idXH=sLG}K$C_eAsQ>fi^kooK=T1-6i>??;%WdeexR)#l4JOeHT@dn99% zCp?b1&M!O9$S05j<6w{|z`8XP%`B}`G{>`)$CP@vm|dS1aIR0sAUp(z*(XDK@;@P}b4K#R{B#BF^kG&4F3C(33vP?G~g z^~iT>JIwLfd|s>{ooJn}8{486>U3yjw@Duik4lW^bn*Qh%k^C?YY%bYU0OhZ(;-Cs z31(VzvLJbgxsicyVMe!bhJD~UenDF*L}7;~hI1#GPN|fuSqfe!)^1Bl^I#u{i5Fju z-<%Ss!ImrC^mHD@Vh{ z%!LLaXkO+xV6OT;8|Jv^hHjUKr#fBovfHc0zmGee_Zonbzrbj=HV_f8D@Q&wi~yK% zyaJWGpnd0~Fd^>H{}@sk!)LW0ix2H+^I02U@CKr3d?n3M%7s(PhG7yds}6@bk!yo* z#kR3{Z>ybccM&&iO>a)Gbs2Yb>nM8Eygq>9KzH13TpPg+MN9n`bLN>(6d?YCITg*T zH$(%^j1#$h3iTS+ZE;21tJef@_%1#WvGEAzd>C_9v6xSlXj0Fiy&<|ZWGs|VjacSR z9IVGx7^)FW6cdJu=ka+giQ?IrkHnxqxB2%$psC~09DOUjnk)gsL@X1FK|Y&V{zEyd zD=75R*PFW9b|o9Ce3Fwe>Cv)gsCSN8qfW}9D>FyR)e+xRW>KiJYaFXjr_^jrPa~&c zy57p!7#|-mFZYj+58%=LE^;#>8!jR@V&Bwkq|7sr){BFiDf51sPT`6_S7NAP`n9r< zI=)T+cJ?k62j{bqHp)WUC<{GQ{0uno9@vAs{X2SE{?p;2R?*1|=JoHrxZFO+m4(#4 zDpA)mQ12}FvcJ;Pk`=r;X+j~MJz(r#{R@i|B|JV{Mep^R1UqLwgJyMhG8SFPKpT1u z7-wP|0+oNZToKL8Spt9_1(vT#jl4s_9Fe{}053=X?gi{d$tQ&-f{3wjS6;c8zmo1~ ze^<<@tg_meY_d6CXLGX2XltI*-Y~7UVO}Xx`)_YZ#lM3(F>%dl7n@6LPC8t3&1pZA zT>5x^YMuVy!v9S7OPbOK4XFMNeb;eoj`42k{$dQkmjdLH_s5E(*BU89$r3ZkXoqbs z%?|cA_C*C%`oTp05>VXx=X?C{p_Fc0~cllXFWk+A1GBO{)qdn~Y~Q{3ae{K=K*Z zO)!Y5A+&KZ`(XtOX@_9~dbqMUC>;FVY|>)y$)BAzJ>6bjfF~C}t&E9{Nc@@|{}5q= z(nnxCUucE4W80A)scCf(F8@Vw&P5Ct;{H=cN?L|e`*%O~&xMA_>`c1JK)ty^?!if=PYOXGJ(N} z=%f&mNy`V0xLj!&T-u#i@}25v@at{RxD}6?-Oo*0GTO|_mjq=$^zZ0)u(E|&fJ;3S zsLT;-iZ%sw3u-$jFk#Ou>-bYP?r*Ld+u0<&2?sRV$P$K0`XjSyj<~cO@PZ7oDcSIM z$P4hWNI2TDl>qV3MU5O|&5-sG4bFEFGgeo;>#ElJ^y4zl_Xtw&Cb_Fvw{0w(77%=< ze4>ZULwFR+-e|?r$}SAAe1a(%fmw&2jZWrp5yRzfAVaHiF-=vMLr%G$EC-E=K({3xR=h*RNi?c+0($n73{jU1H zzCUl?0=Xh{N6XMRK~0$lb2p0Ar>m}4j1i;4a5_fp`O3_x{3UG;GVj^6+@erO%7H{d z!Bs{(bHBN!F>p^aHA-B_GI2sXIZsk!8=X&sO*=Nv0$wW!wrd(u$1*K$l`!!FYIe^$ zthGSXT|(14&+@xQ14_>vNUz|ri_AoAJ)e50f>PR2*Z!y>Ma!a-6FWuIV_t|Fwq(KC zjg7Ky-aNKiS+|I`I&gWlzzS8>r%7`fGfd060{}BAl@KyO0;74o z$^~x;_kKj)x(MyK81JLtw=G9)6S7k1zx%%t4vWHgma(MAh(~vsie(lgCI3g{QKAgC zIIRB5@x;)r&!_Uz9HKCq+ufsV+JPVUwUmvED9x%lUTvkeUF)gPIUgzR*@pdzov&fW zt2mAt%!1fvXMvBPd1bJ0No3*T!O+@|!Nn7WiBp?a(4*5cRwyT2_^^8fVup+9v8m;~FYsuIW2+kOY|$jWud2P?I;QC^8&(~$6Kn`VNmzazbt1R{{c4q~ ztbslbQ7jx&x`XZK5mwkt#tu^D>UW)IJRxLa>_^@Rn?&u~??3TF{fF;Cv5pZumCV}f z{pdYJXSpA)Z%xdIR)8InM7E5buZr0X41u`4{U3i@HA_xyLFd26@)LO5AH-W)I23lu z(l)}pCa7jCB?7JkSJQfq9bb6a#mY{^B|<*ytV|d}Xx)mjOe+O^Xt4eNL4C{QHlX>B zi>fX6TRhM##@xTxq>KqPl|p~=V9e%=h_oEXoeBkmlcPyy7|3!Q%WNBAwsS3~b$56{ z`c63{CA7!oSTNmMY0frsU3R7%{{ek~m=*tcz8hv8otXTJGyj6{$W^qyS*of}$`ak( zJkU%vn=A9U+f%vxD9ZFzF02nYM?9q58u2*2?Bx@+8feb@u#hPJSHq_}WM8qG^4Jz* z(42OqZLS3&gQbV$$=a%d7o_vkqm>5>yp7)8U&@wrJ#2c;bUi=bt=$lFLjUW7^z6Q3 z?;bq4OpEE^3axUYMhttmEMoOY?Sbf4cB06xa8Sp$YKelV_ELvp)ByAr57cRa>M-Ew zF5(}LHsA_A#o^?G+4ZrmE!ag>**BrAc1_-c#rd(~^is2T>4!M2&?s zi>)kZiz1J`mN7{zT`Ai2OYXv@wXC9 zk>UY#G0VU5>*(F|h|3-!9{0g36wFv8&G~f!nDbxrrJO(Te>Pv03VqYVn5CY%?D`7} zrBi-d5xC_~>^RZ*Wm{?s-9YAvqiD;mSER1R@;O(>%>{bH>}vndhEoK|u0|1Qx2rFNf6 z>IjY4f@YH8Rmy{AmEcWdw1mdZuu7WkwOPw;s%-1t1Zy~6?+iy@baVxD%xS*6Y&OMT zk8lM9(zO*{w;^PnmHBX#8Pr-5XtqTAT9Sa8S^xM;A-Q)ZztNPwlU`vHu+iN6S+BL5 zPF;v->o5a~lP)OhfPPs|U&DHh6TwcD0>aR<#FkSu#pH-eR8tT|+JE|SeteLz(4*aX zmIsX!9T|VwjF`N}_OoUUQ4lrfXVRRw*6sJ4tLPCPx9p@%bF%6eZTkVOZIvA; zUmkWA@--H2Zhsr|dt1ucaxJ_nF1`fIQiB%Hzr;`mfmlj8Ud@^_v53T925C(& z2*#VbEEk!^oQWE)*yAechL5Kr(E00nA55pKBZQ7X;oBrC=?%A-mEavxYp*#>Zf)|z z{24h(LOLEK27y|!^_;OoocGmEZD!ut#hEY1e45)L7>P>)YPHd6$B>fihV<%!5*2&V zeQ>~7Hcw#TkapczE4>s#prBrzGsnp>i&RXv^4N3DZL|e^piqez6^{+A2#!n0PXzun zmf*xki+nW1snEXJ?pNr9FR_gGEJ#JpLcbMMI{CPGhCXWa#9|FRdszf6vJqTF;ayRTMOA|lH^^M8!vYnIsxvA= z#3iTl=z^q&bu7i_eQPg}YNnzp?L8Wtx{+*JGa({MIPx$p?=5elWjvNl;y)>!oy{~E zN7Lk*S9XER-MILs<}h&6U-t(dJq2Mw_iF5BEuT^=1se^%HtgZO9-+x~w0BD?j>o2! z-70@HeMnr%Ij*+j*T#VfaAvFZcEJcRddWF-?xP4eim_n@9IJXiMk9&i$-Jcuon}v_ z1`N&DC^l{j|0{=%YyR8%A49Z`llfl{q*DFwm?v9z#(#^Fb!^-dda^4DXa9vo|E>Hn zMitkZV;|lPM+!Ylm^p=MM5pU+_%AjM1{n$(JT`3e)n*dn$uqd=K$Y%u~Ux;rDOl+2yHI zL>QyN-vJwE_==DJ8|%sPI}{SnqX`g;LhY~O-@Ft#03jHrz*-CU*4mOMNG?7A%RZzx zM#IN<0GbA~lFwLnzm7L|&#&iuDr4bA_WLON2ym9Xr;`56lgd|$+fWX^C{X#S$;{9+ zyS@5R9T!oY75C>L9MtU%SjN5gK^H(eF35 zbl>uzFAXf4pDlYB$ia^Z?1Q^a(Z8%5)LZFu-vSQ6VcE`IhQ~1p-zd!cjpl`Y>;@>m zH6b*H0||Vfl~KlTt>%m(kT;gmh=!!*mWO=!27gzsRpxa{HLSL15?M0%eZxdR9*je& zzegi5(YXgl#i`hnC%;D9lMZh?7g`@4F6oEsd~D z9%-uum3I7fs4WBlq&bj-L3mdX20N`Wjf|$DGf>GBQIP09Xo5mP)q4R+{+`^YLv)rV zPd-c1pA#zy10j@{x_(#i6U2Rb2Sm1>SW*vRjc0uxZP}!-3}|-@QClW|napCyDKBKy z%i)wF($Z&0M{YE>sAVD6g4q&SQ^uUhE*boR!avj-!t{=c1525~GLkk(%B=Ki`~|T_ zVf+{%r0xPp14vVzV{cFEh040ODpL>WLcUYT_S^dK?RbY{gkf44f^bN>kdARGIav3V z$p!|q>?CilI!T&(7CW0DLx!6Pnc5%0S(aVqHm@&P`1XEFz^n` z{og8;oK-KHNi%JVnNI8c7JjQ3ExU+v1i0)V!cOYte7d(TL3423PN7Dl03mjjaAWQ= zP-z;&l73d&t@b%i4OVn#G8qnM7DG1avsyWa6@Vl(#nvF6s^E|b7~ox`BizIo*L_g! zf?M}(Y6D|JoDIZ5Lm+s^op+@rC!x8LR?|}`X`;!Hav*t& z^EuwW*SubCT5V|LKmI#oMcZ0tG5%hWns4Nnn?Zf{bA`;}e`RjY#dZ~?fw*i09&4n!S{$NOlsSW>)$d?P=iFKl^z1$6nDMaWxCTWWbX5Hh%I2 zsCd43TdUyRk)3fZyCHway6On>Gxd*Vqlr>p3)?;Ik3-^gG+y|WDwZ?YGGNJVU00jh zb`5jJ7hUGLR~Wx^;u_0JE@NL|084QjKf?#V0g?G(NY%zM|1uu^r#p$ml;+j6bGn+1cpOQad5j~H=n+(|F%f=Smw^8eE|ZLL%|^C8I+_G zke8O~VYaH1kfc}xrus)IfrpNuW1T6B9!yg4dM%TxhUE0qw|}s`fDi`(Ax<0uoCE|o zNiZ-{KOiJw=g-CG)5Cv98>|2A-dijDjr-q1mlZ(BKD`+grT;bCU_n_6$Cq;_u01v3 zLBESiP~^NYTTTP?1Y=##k@EF}&9A;{L4c9h{}B?~ukP3d8wi>*6jeFSpI~(8<))oP zy->t@;H3v$qnx=hEnmff&$YN-h{}0s_qHArHIUOG)k{Oez=C5``=a_|Gb(}}5D0v#BNkk9rvz?F8h(iP-z>rn=Ozv(N?@9y>y?#@! z(xDn^1X1t=1D?9)A#RIIOh-xcB-9-C*snyx;zC})BUZszW%W9!oDhsfs;AG^SdFqr z+8P0hun;boQXF&DB@9b3bcPqtsFci{8C8&!61Lp1`A{sd!XS1F^TQ#a2$$2B zfXR#l_^0VU?JI0Qdv?H!QMwG&u&bOe3LO|0S(PCp)$|MVdKO+mjfSOX!I z6DCnja{?ecaM8Rr@9BK)qgm*&smL9*J_F+=ht~ecaB?8@6|whbB1K#(P!_aE>=lx) z)F8gixyq$W@6JJ}uXY^I)gyT7ffCKn8EPv=NX~wlzmy9tGX# z=qjWYt@NO*C>E-b8?7LsgmzJl3d`%FL6ukxVt=`WPDGB1QJ+KD?`sJrz42cZR=c5E zMs9R{pIB|#3TAyikv{%f`j5b!h7k@sX`+ZV!nDMvopxWOTV%BhCWr=JTzms~_*)G{ zoB;&Yb(VU<9Nw>H+Yi{hn;yE=m!4c^3hreN_KDtbBvsV9Y?6gc+Dh8`!E8ETX@7N} zM~8I%#tHq2n&WFM&3{o`(Y7I4x4UAr_GV7hU<^HGWzQo0z#b4u-v9Q7NW+JoS7A2f zVDC~9IM=3>a({qW9)K!fE}NT2{nNa_-&@{AOOXSR2*I9P&r3eaD|mBY{BA=p%ZTq-Jr zFXz&`TJ^z3WFEubV5vtsQWNXN9l}v6mHbEss8qt*{5(NoHrkm6bO-AD(k6NPr-JxM zJA4`Js(6se6-KP91X_q%BXaXxS6AnA_Wf3zQh>*vlQ%RVz$FyBN={iATsK;`%bRQ8 zWsBuFk$*7bk!rzA^|Ykr{> zQt`?7=D`de%er3$D|y`>rGUvp{17CEXINo+VLN#S?qOfLja7{a>wG9BA#hpsnd6w< zTI>b`BjD*6Vm z>IC4FemSC2qD|Su$au+m2p?dD>DsQ>qiVhB~#$qmMeJ61CbEdM@W4S{!(M7YS(z>NbE~`*QwJxpvVT_0Nn2?0K?ve6A#T0 zG>M5iK91Z-ksp@Cti~>FJZCm{7pSx*&dG+Xfo?5O?QhEN=AY~P2R-$wHpSr}xd@BB z+X%X(c;DQ1Eq_ijqYCx#!!A2otJ!{91}vJBcs^Id{Nz{XYk!jJ_e2SoEEYA&koQNi z3;S;%8M@arpW;y$GKcJLH=o#u+@1Q6y=a&K!lkGbx<3Q?rR|MY-k2`{F<4@bcTTdA zsTb>7&xFh#h+-SO^!Goz&7mU2p_$|Wk^!gf#6tKBr`jnh8W*G-*U&4^QHZ1sC6z0j=Zfu1gIaR3+Wa4k~Rcrl~R^fPUH+hrSCtS~ji$f8;Q; zLQ8Ljb6L@vpIO^1@kV>C*Mw~jtw&No!N5tLbcJ-oK%Id&Fhzg3{ zOHFMUhl58j$Gec}iNLaz!*HKDJzUt)xs)=dZ)DH%7_mdgYeBHq)cW%KJBinRrhS?3 zNF!vPD3(7NMv_tmDv;5LWaC+(`dI$!W{$e5j?=&wNY>SV)}genW^!5VUY44W^m^~? z^hg+kG+Xvll+_+h^o4=E-NRoXfb-AP?%4Wp)dpKx#8#?_T{CLFM#x zVIeXaxdSu6&p0WrzlQ~)*!~H|2;95Sx2C}8GNL0`%gh0_v@X#?(s-Xyka8Mmiu1YL z#KF9~h5%u;FvlR#W8`tpvF?}xXbb(mS0wVSsy10W zCo=7QoNec1F%Lq zq8j5ohYr8QD{CmX8D;Ud3v9EAcDrzbt)ROwo$vTK*>0dWBDObV0{?35zChrh()1?C+!=S5B0#=p}k@e<+(bt3qxN=;ouoYEHq1uv`8)?r~_f zKyk)`TsUic!23K@~a zlbiV--xiLxCy%$pcuq}Bf%mQ}Qei(BOi>4G_=tMmSg(-{58$|%N*GvH!07xF45lE) zs~1-j0+^-2{BzQt-eQV&t8IAO1VFf4am{hp>My)dSJE-JKT@$L`N(OFj;zzqQGF)H z*E$@mxtLx?JMJQ!O!~gfL(DG`pntNh7QBU17UY(-p{kGAaO#hcN*P`bgM6?fA&l!O zF#35%Dd9#~d!$ayRC92*d|?fHP;d2iMY>;|9bCWm3|VIUm=j-wX~UWfg{#>gvPdrL zV>lW&^b4DXC90$q{#MRn!kEIGgvTktONiPKMaa_TEQ^R2q4X`Dm3ifDpp2k< zzUXbJJgM76hfXdzt2vW8%hPZQ#{o!v0(Ger+w3%dXELtK1m%1zu{ z_ZOXQ*V%pM$vPZIwu@m)iQX6ZyCHO~fv08rShLPTCwE6Z8iMu>zEVj$0d%*!*!q%{ zyX<~wng?ZEUf;uRgy^m?4DlMUyoVZKb~h>hMw)Cm-Lyr^x)!|q1;pD9eI^=OV)WC} zskG5hCq%Xr$o8DP1Tpp`y6-X--dVV6&-EIPZ^zK}t6624@RFj}ZDgnJ-w>Kos z*HO>ML=S?7AZAO{ObUK*$=6AR8u2~88UD7HGmb!iZ}JrI+=QjT*URhQSlD@?4{CED zUw4PfrHLKCr={@B4H9ZN!8N}0N@qk>Axj~`?#((Ak)OjW`o-km8>!&j1s4L%u=*I| z%wLg$5K8PCq;Vdj&Nlr~K9b`pRa>9^1>xStR89JZ)0>oJ_}deC`%>rSv?9)91-q8D znlUs1xW;{=klkq+5m?D?F(-nEk1HtEn4!i3FeAwEHw^x@?%wY2y9il~TwT8UyAc+5YzOU6_u^i=fox zrB+`p3Y12@u_=#}F-}^zOlW`dYyK?W{(1v}(i1|AT&2&~w|Iy@m^;OQ4{l^oZ|#`+ zoHD&3+0erAmX>bt9))JWmlQgeLcWx|Ds3T6buELdWi+#tRjax3?H7_Xm9`d#y@F`q z-;tVEd#s=~Xu)Ix{VS??zl2%$%mac`2O9I%3CX5=X3V{*RF>OmaRjS+=^{@ahayA# z+Q=Esc`cyN%O!nPO5mJttZ3!k^u|cSG)vLYJ1wB`VFWlP2qKURyHO_3!EKQQkZ7d| zGbMnWP1QnL=vHbNf9$zht@3%!Qa*_4`cV_+;rsRrSPtd zf;yzE^5>3}^9}=e8`YbVrJ|U{s3h;ae;hNT0cscgjuU->w}6OV0d86y)GWnkt`e!y zU;Yra$0&)2+%6UI7{Sv`I8-9v7r4sR;c)=E!ZLy_Ymjlz|5s^L^duB@u)-|!poLh4 zow8~*6BjU>3~JeGG~%NWOGrK&yC)?1Ipd4tX zu=-_JTG;kP*-;HnCcbSD2LzCn{Eo1f-JTxALm{pUVxzF;-42}Ez)rOv*ZT6H*j79a z{%qH%R36dX_y*M@wvMqI-HXHbLgpeu-m=REo%OfA+Sp$@k9)O4Kh{qmI7??tjyqw! zj;^(D)v?lN62pWlUsdUCluLBIhgsw6x%q6jGNw4lH;yWF7q0+SQ zCxh*@cfo#j)J zbH!jAb2VRl^kmp!>Y(i!5%aM0&a;~6jO=ClX8C%0OJz;PP0 z>Ory~LZ#PyT9~!0Qq$zWZH#ubs*inJhKT;u+z$OwJp{3fsjtUd1s8K-OIb49#b@Fd zvs)ua2q&$eF8D-`1V8@mtG$7&zbvb1lnt5@Rf2hV*&x+P z_Wg1=^ZoI%cZM%7_x0%bTI2V2lE@#si{Hchd2qI~h5zmC>FIc1a>M8C<>PXP?)(12 z|J&0y((m*0Q2uhC{&#d{_Sanw5_hZFoK@#0%T@CWw&UjRD97)!05&(Zyiu1*y|mKE ziMzV2-;mJ(CY-oO@2~xQ_~PRhZ1g6g6{5f%T||AfqxKuvj6m;M50*Qvx119myf=o| zZ-~9#Gzf7IH3rOhX;G#v6hmMTyDPLT@daokW%QpU#?vvt1oqb4OxL;mz3+4Kmq8_B zj&A^!4~WGn&ZGGIenvO2H#>%hvU|K+9CF}%3;o{#N|uYoHgb}L4ZRsyjIQctel(e| zTb0e2>`=V=Zj>nP6YgNUPPu%&mT#!tV5bH23O5a|CWHBA>F`_JFgy}0Q4zshMI#?f zu1@%;6$rvNEFdaDot8a@CLEkL=uu9!X3~GvZ;7@?;V#DEJJFU)x*Mt0?8Y_gEZvnK zIxk$ki@iO~t}}(Yvr72meerc(XZ^$d!)8?-QUP4L?R)-aDIcs?v?SLW9l2JAA0xuy zuw4jzwvq`y;Fo}LTRjKM&dFO$VEkAgFvH_YeTACo6pvw`1=NfQ?uME#no%=w)Txph zNZx3nUDR@_z&e})=E!4i71~9A89AL=U~69kkg=cGOXrJ-G)R9DIf@)g^D#sB;a{iww+QxqW2~!K4iTq#LaeiFj|q(@ZnG zkBS60Z3he4;?-)x+Cxi|r5fZRj5};#KgT3p)IJFw4s_n{Pm^I3>`~~O#gF0H=Y`cfW|4; z$3(!sK?9`Izi z?QX}4`_Zic$JERdwN@#Af6o2seYkIl7oz4G0a~1`r(cc6=&!zPwg8%12`5knSz7Kf z2~^>+vdJnnWIw!udeG$4tg$N^vvix9ZZ&$ z?Ccw5#pi{@Mr}vZZ0UFVeg`kzlRvr4*uw{E?X&x`Os-~vA9NewppI4hT%k_Gru|{F z8s8D)UdgyLN_FC3O&c> zkPKU_xiyKPX--9FwAk@=1~PffP-gP_iW8-_P75(-j-$17CCx+(l+Lsv~G_r~v(qRX|ssWPlY_yG&3(-{%(kxk)H$&5wjO&9>dOfU8= zY&>A6y_rxT4AtsnA@eF(eU}PMWrwuLe1E1FFz_!H2MhdxWrWi1GIE>yGmjZwc0At3 zqDLls9T^?%Rz4dDrU@9$VQNezI#&fk=OqyVmlPK=E!P=a&w!s^dzYcZO%$dG=RoX5oN13J&x3AmJ^-&pl+7CLl z+4-7iVx%=Gu?bjBg&rb8)&yMJEdw&jSREJ|*kvln!hz1RI0utU)Q@1p^Ri?rzAMp` z?8}oHA14)7ubkGVc%onD@r|=Br)>KK*lXAo127iK1Y(Dt`1D6R1N#@R40#V$(uIKJ8p-9v-5by+-d$&Mvn$v@|lis z6q6q-BB&o{lv*Awm%j2}#cEl$g<0E5Q`i5V{_GrKDt0W)~@Z~ z1WTfUQtcyBS1CVQ4cpdt1J^ZqGAz)4(dEm9il=w(i27)MPViRW>QYD80OZ?sCYOss zb$5ZR;ZC~+`?CMDO1~YPRyB9%*8eB$rrJJ){oxjO7jj+n!Nq_IEFR@{2yxdyxvo}Q zcE&vkURv`E)HYM_krf{@i{}*gLw>_RaAlebW>rO_zWAWY=`GGk0(w}NGc;BZt$Kkc zTOVetlP~UcNYv7=Sry%;TF!tu+RcXi>vQbys+P-g=2nYCKR?gI^NuG4R4Ci&qfWcD zz5Amtdk*{Bz>TcylTYG_)pkscuJ)Yq8AzvikBIV#40v_Iux#R(hlUkeCU^y~3m<@D z=peL+BHp`cShSfj^e-cK7ZS`tCGKLl5`(vQaX#1_ZFiLm9(CK=GaeC6qi)=4?Imcd zn1{dEhuaL+!`ULWS9w#>K6mOS0fXo$w}134-I(|?OY>YHxprgp_RlU~frk4FLk)+7 zII$u|XILxHM7HawD#MZ_^W1H-z9N(}{~Fx4ycl*Li;#DW~6 zToMzY(e$>^(P~6clA4sAHWmwpIU~*$|NewQD7t;D$4n9x={xt|8iz5>qY!NzEmm!h z8_uT~3h+tUe4#HU@ukT4{K2~BSqCv-e@Vx~MxV)R1>lM#5E;izH^5T;1rH`2p8+0w zTxg9vEk{s@p$W3vgc>f(y?1G2KFtO?%<%zw31K4GFw6zVA@-{QJ3F4U!j|9;OtIw7H;wZXIH(=bJmzxJ zPVZk6wOAYg->~{NmLk*I@oBg0Rw2+CjI=Z=wI%&VAEReT`1tCBY{Ji788@fNv@u}P z^<}jadkTZkCZ#NYAE5G}Scvvz!X-k#P(m*ce;D-ghWH<9%Ak0o7E@qm6 z3B}9s(qb}}mo(+239K5>zUyO&JKzuOGbCzQoq|KIk61v|_MjS(u8Ags7lR`!OPxRh z1JnddBscW9Wk+K&4#B_cky|SddoKUld3g}Pm;o#~0Sn$#oo_f*a%(MSQBAXP*57O+ z$yQ(&%OZ;`K0t0Dy?*dm*72dGd-3~Uat!f*z1AtG6{=J?(^nAnoN%@ep>Q%rXY=)> zi@m(??D*6s5A^FpMlI(@JM~5e4a<*#j_8X%pp(r{lWVgeR{PEeOs0KaJu(ilgr*4= zCNDDQzjo5Gpvo+lt6OV4kL1jv@F~^Ox4J05{q`d~re?=5zd$qiUB?mt_Xa&D1j9HbJvWJyAXp2;u(;h7@`0{41+;dc7KBFJ~naIp87$y92x1 z%lueuf#(9i6;PdvFS??Jgv=ob-C`i{DWPH;Ie0igwO<&Ud(hfl`vEB;EwWqL0U@pj zJhWd4lVK2$4U+giOk)Jl0~D2R`RXE%jt{?xqacldNm8?-mu)v`8dfA$mvL?2+4 zY(q9^ktkcO*G65{LTsAaM4nDHRh=u>wo9rjrV%j_YGAquc{2RQGJO#}Y1q9Rn@gQ$ z-k*tWpICdY*&VKpx=T4<|%;T+5j(omUE%?uMC=EkynID&Ze*exV?Ae=)HO8KE zu5MGa`oDd95x*F354&4?LyY%-e&b! zVe*=nugQf_b;TMNXCb$iQlUrt?!&4B1Q zh2A}67C1=E3zzhr&vGR%a(4GZ<@D76KI3u*bkrxR$kD5#5gGG2FKAUPA~dq*IYWV6 zgW!~Tc|=ZR1ubV(kb==W=3?p1;aQ+)cKVp-mOO}wtIRv{y5rAC>7%sE^M)pJVF=|2 zD?qoavBCa#Pdx6_JzxRHJrbqd$xIs`Z&`}CHaDc= z0K!8x)LyDI&+392`4sI$BXWLm_37g6+4aTwYvNksp|~|7*I^!X5EE#VP5rk9mV8ms zz>`4M9TntKaNXddVLVhJg^h4BZ(BRn4aaB=VH-0)$F0G6Ll`07l@0n?qS)&IdOB?T zYqa||P)A6uJ(!@&?p#r9ix@s|JUVuay;uT@^o@o|IScR}Ku*r7J`{@Sm<_?{BE9Y~}F`oG}s3w!i zpQrtMmqulpiQJ3QU{3aQ!_jEb8uvm=G4Qu-$gyZ7)b99S>nd>j-u71xnu#1s>UQCF z7w)Cd?e1C%a0qgyDKAtoJ6e{qkT>0m*RL4%Z!r0ANQY)V`;mXQfv?7M;J{V^{=<*Y z%awqU`pkydyI`|4Zq%Y&0d%0D4Yol5Zk#IdJmhrsBkcI|vsonCgm;)grVJg~4B;KG z+P~T7VoA0iO+NmNQs5^9DXuEZT;PM*i?-AaKzE5QYaBu}Unx!EE5l znpMk+-|>Ro04fj{H$epvhu8qnnQW?c1Nc`Ywa$&bu_M*EVc=ug%QDfk02Med>jI(uhdNE~4k5Mh$|3pa*4d z*={G==FEJn_D7RgZmA$8YB4XkxNXwIr_!vUMVk`0ZpT!N7VGKbF6+|^ZPXo2UDt~e zy|n(QS%+ju*p7~#(HIkzw>>EpSLvnvjxWb=$5F`}qbI?=$2798V=^$5{v@qzM$5BW z&(68Z~RaLuWf3F!2(_KKh@xD78|BjC0JW)`*EDq_xo$7PE9BBQO4tN}ovVB6e3 z^9LIiXLbNBzIh#C%`KsRHYGV7l4LLT2L5xGQ)>-6IFf&_X@N8Fu`laKJc}JV=GM*4 z?MJU;)(YSq?Gw79LYWDVHH>5HWH=@#IxCYZ_w^jsirusG``(AMZtlqg*!p2Fc2V}D zj$gs+1{~pWL{Ey%L{^gcMdx|*H9rWqm{RB@I8wD&JqoROz+4G0{#4MVps9hNSA&%$? zs;T0l;o07gG9Xd7dM-qvN4<#uylLYO4L8{MdpO7Y=vSM!eZ1X~b{PFA@XJ8d?)k^@ zf4)C^bMYQ#(gyB?r6zZXM@c^y>vwpp?mBTs0THebJ}WUrBV_c*I3LB7uS3{%o@#2ZyS`{po|2>vU#Jl5v3fXk;0j$W8?Im2kDoR!qwGW*^2`|?-a^@ zd2U4{7p|`CQj_&-{b;N$zdYaTK*&np%c@(-gmV15-&bbysY9-o>oxNeb3_?6#VY6gdbAMqkGqhIk)DF z+HXY_BA5uHbNP-TJHj;zVY%0S2gxT07Sy zwuki_usT>G99UN%&Q3^yG0lrO>wqwt&B!fV4Do1}6vF6XK<8!{2+tOK1u~W!G0=|I zxoVrW^kMi;9#U3(u&{3;P+J{%X;7NS{ynY*VLvjH~wiuDlFZu#nRih z-jkJu;Dgk`lLkI+sN!bJRoG|UEcuCug6b91wVfIW2Qc4e3aVN{_Ih>8a$n+oM6OIH zJ;n)Qgx+DSjyWk|wt)G_@o036G;l@kK;o|G2sYWOO;sucy)=RifVWCWAki~NrD+m2 zM|kZ9M%x*RcBz<@?Y`Ya-7q_Mgx;JdquZ_QbpX6DPmu&PRuU@MFN*bFPFGcjarrNe z+~moCnSrP0`RPdFq>~WPzIMgZ-|jAHUrQ&()2A|sgoUXyY9lQ@Vb^j5b?hvarG{N9 zS=8F+0IVQx(5M3s#cU||SU~E4$RqvfLiNJA>v(K;LA~vYd7D)Gzqxk6y6uW|+oclF zuQHqblp`w=0$2fk9|b6r4PR|^f|ElwGfwVxjIkD1C%D`AcB+hz~UTy zV{53@#*rVplCH1G7%B;%_7SKtrOaR3V%1GG)q$E?Mus;#xCAs$kVz5jh=1MO}{WULAD>wciV$e(Jin z=LB3uf{NJ+ASoAs6ee04qaibQIAf1E*xf+&jmY39X$KjoBToL)sV)Q0>JF;QL3K&J z)-eW0@$AHe>P!gR;&hrO5g~wYFk8`SGqQ^9Ge#vjb~=vTx3!)Qza~s%GRMU>?N>?z zn{Nc=urIzOd1&K-w!1CWjzr11Lf-Yjlp9v;^VZ}vPLj1expBZ?g-6)HuD~5R!JDJ3 ztOxdi(VWd?wHWw^%#YDq_K8#A<5^u9Ris!v0Y~>^O^5RjuT}_<$4dbvttn|R^(atk z;1v$29Cdb%^< zaxwkhZ^>P+jyiYY7g6{SuinZZ;^iiB-}BY5ize09NsW(qfOZ!QUAG@zF5JyF_PlIe zoj!oE0X^9_EG+S}Hf{9eHnb^G|KL8uv4xmEI1CRC!=&rrFg$48c>UtE?t{bd;4oZw z9UO+u)w{#cidv1g@HsjQZHa=jER(g+*YcJn`8tw>>ZO(+LBghW&W)tI(<+|Xmz_Xs zXtl^$?pt-ILz~fz$Qh|v#!GIitWvy>%j{95xmK*0S}a}>)*onORZB=$eg;`tQ>Nb* zV5rznjtAP_T!$@$)(aR)RQ3QqR&twG`A{c{eJObb+hWWzDYg|gTeBz^?N;3CSmPpA zf%c`#?r6btt{2|dW@~Uz+=qVYR5NvimSrVrHe)L2GfFQuWyA;QV$~TCVBj6YRf`3w zq;}rhH6OeV8iUu7HR@^sE?yZnfxY6>@DD{~kvjx}uU{I8F|+&5kQc}W*OC;5%Nvrj z{^j3&MP{fDeT|z z={OtA-AqAJXn+*felU##-59N-L*PGXDNg!!CYLN@Sa$2YDLNq}ww*Bf50QekF~!Qw zbPw>l3B%hi0afgVE8P*h9AAmIkS)A!)Z4nyyeyir`WGyn4^2)qu(43gGDIvHFwdR% zwwTZeqgokuQPPU~34eO1VD0u9UP#J1p(ZUZh^fL9aIW!YgY_X`uiY2^274 zLNNN)uCTJr8=BoRkz>^j7;3%{bZ+r;g2I@s_tn4}GBB^mV#eKSz#H> zP3KmjS*PN68FONQ`Ai?(z1xyByVT(ye93jcH-Qd%qcA|v(83(mg-=>*E#hR+SB-&G z_t8z0(|Aeq2zs!3|9;_;_9=P`}=M02Ugn?h!{eCdwg7*0hcSJJuS9~r zmSBj1`-XphdUI|F`Y4pRUND`#$XGdhVL$q;CSooH*RtwV5aWzwvM6l&r<{_vtep9V z9%pn<0f1Rb*#$5#I0WWRdj^7yQBArbbU*Y~c(#?m9%w=ysETq_J2{L#jDbO2lt4r_ zE~hBE<}4@jj#U-UnIfKUgnAq=9%rr&7^P2uQQA?72uO{2bD7l8e9px)A~uOAq(*kw z_=ICR`v~nSqXoPCK2dNV>y9)>TQ3^3u7SQ{D-reioM=bzQvjO%iM~#MGbio7(6q zR=+p^F0H+GVet)z4~!lz=&a%DZl!=Ed#4*wOehZCfxyveOAKL6DU2{fFT)F{2t7=wQv$6m^m$3 z@&V;|u=+U*NG&>oS6zzSbdaeiTEVu3Xk0!h(ii)`p7HGVDzMVZ%G?vdt%zB)f9r#w z*)CpnQ|qn+8a%dxG))kyl+1Wzde>Mz+Y#v;h;%<42R^$84{?j*D%GiwXK>-h*Gp${ z={v&VUPl19PL^uflwI(xT?{9wxawI;%i)1=EwI+3S)Z+Zvhf+uhc-V2W86#H-4f`& zN|$Xpv+$lZMZ_`6qEjGKYWBn-XX4kCGto6uqFVr9YVhB$ zB^RQ@flH4XOv`piiYx3jP%t$bzk3XRH^i=PMyakPL_(X471EmmSFSD=;vZ>g4*r9S z=p=Qcr6?}=ZJAmR%j)Lek6WgCfBRsee>TM|4yNU0)3SC8&9*+f zx-{x2DNv_Je=P*G8-7R1D2Y0ULAV zSZYzm5pl7eI8jF7htTV|fFcb_bM*3CiSBoS_|pAGtd$0jG@gPpGr6 zq2^~E@zYqEMsb=Jg}ldahrGnhxao^c)0r?b=SDfTcFM3j=+QG$Ijc~Rt*ok8l2k{sEefTS;E?M*sZIn0kvt(d2e&5xiCCH*ohk$U5WW)&4|iku>6cL#=pRRX@Q$2M0iA5%28)pUdfU z?doK$qjopXAFUo)Gl<HJm2ru@sQ4#c$+m*0s( zoJ+h_i=0)~0P8;kezrTx3nNU7$fb_*gkRj3t2Wh!m0CM=rKzr$=;P{fjNw_Uk6Vnk z38W_H&<+Rz{^@oPH&NqEikyQDZ0oGP^^dkIv-vMKC}d5$U{+r>X&X$&t7pM?z)yt# zikbU5!x)tb&2H<`cV#sZ*v_E}s`Pb5A+SY?Yo5$(-&3V+vhggK2%>#sEXM=~DVW^` zDDHr?zMg0~Yhg|`8*WUpJT^hhfmQ!+F)oeiC(L%8S`7CaQyx*^PdZT<8&zViRYG{$~-yU7q z&hwVZ#M(#gep~xHF8SJ@ajDk+Y{t?z^R1YXeCc-Ha4j`0h^XfiM9&aX3^l9fT!2_v z%3Kjms~cto@q0EQIV%gf0NL%@MhO}n(xwR@g+y)7Keu)e+Z-vI94Bk$XT@#gxDnu| zm1yI8^~8guHZun?+2KSQh2fK(U=T0K$lMyaNe>@|rEfnBH4p;Bj{|f*B|Ns94Yd8Q%1prfPL686d literal 0 HcmV?d00001 From b661d680ff0372c8e4beea0db13bf69d6a2203a8 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Wed, 30 Oct 2024 16:16:02 +0600 Subject: [PATCH 161/183] fix(cli): add config name to skip-policy-update alias (#7820) Signed-off-by: nikpivkin --- pkg/flag/rego_flags.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/flag/rego_flags.go b/pkg/flag/rego_flags.go index 4b291f0a5eb3..84e0aed910f4 100644 --- a/pkg/flag/rego_flags.go +++ b/pkg/flag/rego_flags.go @@ -19,6 +19,7 @@ var ( Aliases: []Alias{ { Name: "skip-policy-update", + ConfigName: "rego.skip-policy-update", Deprecated: true, }, }, From f2bb9c6227743dd61f44eb591d4b15192fe110c6 Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Wed, 30 Oct 2024 16:32:40 +0600 Subject: [PATCH 162/183] fix(sbom): use `Annotation` instead of `AttributionTexts` for `SPDX` formats (#7811) --- integration/testdata/conda-spdx.json.golden | 39 +++-- integration/testdata/julia-spdx.json.golden | 93 +++++++--- pkg/sbom/spdx/marshal.go | 42 +++-- pkg/sbom/spdx/marshal_test.go | 184 +++++++++++--------- pkg/sbom/spdx/testdata/happy/bom.json | 98 +++++++++-- pkg/sbom/spdx/unmarshal.go | 18 +- 6 files changed, 316 insertions(+), 158 deletions(-) diff --git a/integration/testdata/conda-spdx.json.golden b/integration/testdata/conda-spdx.json.golden index c14d1bf4e018..c11f52eeca1b 100644 --- a/integration/testdata/conda-spdx.json.golden +++ b/integration/testdata/conda-spdx.json.golden @@ -31,10 +31,15 @@ "referenceLocator": "pkg:conda/openssl@1.1.1q" } ], - "attributionTexts": [ - "PkgType: conda-pkg" - ], - "primaryPackagePurpose": "LIBRARY" + "primaryPackagePurpose": "LIBRARY", + "annotations": [ + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2021-08-25T12:20:30Z", + "annotationType": "OTHER", + "comment": "PkgType: conda-pkg" + } + ] }, { "name": "pip", @@ -55,20 +60,30 @@ "referenceLocator": "pkg:conda/pip@22.2.2" } ], - "attributionTexts": [ - "PkgType: conda-pkg" - ], - "primaryPackagePurpose": "LIBRARY" + "primaryPackagePurpose": "LIBRARY", + "annotations": [ + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2021-08-25T12:20:30Z", + "annotationType": "OTHER", + "comment": "PkgType: conda-pkg" + } + ] }, { "name": "testdata/fixtures/repo/conda", "SPDXID": "SPDXRef-Filesystem-2e2426fd0f2580ef", "downloadLocation": "NONE", "filesAnalyzed": false, - "attributionTexts": [ - "SchemaVersion: 2" - ], - "primaryPackagePurpose": "SOURCE" + "primaryPackagePurpose": "SOURCE", + "annotations": [ + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2021-08-25T12:20:30Z", + "annotationType": "OTHER", + "comment": "SchemaVersion: 2" + } + ] } ], "files": [ diff --git a/integration/testdata/julia-spdx.json.golden b/integration/testdata/julia-spdx.json.golden index 89a4edb3f287..a770765dd849 100644 --- a/integration/testdata/julia-spdx.json.golden +++ b/integration/testdata/julia-spdx.json.golden @@ -17,11 +17,21 @@ "SPDXID": "SPDXRef-Application-18fc3597717a3e56", "downloadLocation": "NONE", "filesAnalyzed": false, - "attributionTexts": [ - "Class: lang-pkgs", - "Type: julia" - ], - "primaryPackagePurpose": "APPLICATION" + "primaryPackagePurpose": "APPLICATION", + "annotations": [ + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2021-08-25T12:20:30Z", + "annotationType": "OTHER", + "comment": "Class: lang-pkgs" + }, + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2021-08-25T12:20:30Z", + "annotationType": "OTHER", + "comment": "Type: julia" + } + ] }, { "name": "A", @@ -40,11 +50,21 @@ "referenceLocator": "pkg:julia/A@1.9.0?uuid=ead4f63c-334e-11e9-00e6-e7f0a5f21b60" } ], - "attributionTexts": [ - "PkgID: ead4f63c-334e-11e9-00e6-e7f0a5f21b60", - "PkgType: julia" - ], - "primaryPackagePurpose": "LIBRARY" + "primaryPackagePurpose": "LIBRARY", + "annotations": [ + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2021-08-25T12:20:30Z", + "annotationType": "OTHER", + "comment": "PkgID: ead4f63c-334e-11e9-00e6-e7f0a5f21b60" + }, + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2021-08-25T12:20:30Z", + "annotationType": "OTHER", + "comment": "PkgType: julia" + } + ] }, { "name": "B", @@ -63,11 +83,21 @@ "referenceLocator": "pkg:julia/B@1.9.0?uuid=f41f7b98-334e-11e9-1257-49272045fb24" } ], - "attributionTexts": [ - "PkgID: f41f7b98-334e-11e9-1257-49272045fb24", - "PkgType: julia" - ], - "primaryPackagePurpose": "LIBRARY" + "primaryPackagePurpose": "LIBRARY", + "annotations": [ + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2021-08-25T12:20:30Z", + "annotationType": "OTHER", + "comment": "PkgID: f41f7b98-334e-11e9-1257-49272045fb24" + }, + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2021-08-25T12:20:30Z", + "annotationType": "OTHER", + "comment": "PkgType: julia" + } + ] }, { "name": "B", @@ -86,21 +116,36 @@ "referenceLocator": "pkg:julia/B@1.9.0?uuid=edca9bc6-334e-11e9-3554-9595dbb4349c" } ], - "attributionTexts": [ - "PkgID: edca9bc6-334e-11e9-3554-9595dbb4349c", - "PkgType: julia" - ], - "primaryPackagePurpose": "LIBRARY" + "primaryPackagePurpose": "LIBRARY", + "annotations": [ + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2021-08-25T12:20:30Z", + "annotationType": "OTHER", + "comment": "PkgID: edca9bc6-334e-11e9-3554-9595dbb4349c" + }, + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2021-08-25T12:20:30Z", + "annotationType": "OTHER", + "comment": "PkgType: julia" + } + ] }, { "name": "testdata/fixtures/repo/julia", "SPDXID": "SPDXRef-Filesystem-1be792dd0077c431", "downloadLocation": "NONE", "filesAnalyzed": false, - "attributionTexts": [ - "SchemaVersion: 2" - ], - "primaryPackagePurpose": "SOURCE" + "primaryPackagePurpose": "SOURCE", + "annotations": [ + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2021-08-25T12:20:30Z", + "annotationType": "OTHER", + "comment": "SchemaVersion: 2" + } + ] } ], "relationships": [ diff --git a/pkg/sbom/spdx/marshal.go b/pkg/sbom/spdx/marshal.go index 809ce95d7e4c..51f9144f682d 100644 --- a/pkg/sbom/spdx/marshal.go +++ b/pkg/sbom/spdx/marshal.go @@ -50,6 +50,8 @@ const ( PackageSupplierNoAssertion = "NOASSERTION" PackageSupplierOrganization = "Organization" + PackageAnnotatorToolField = "Tool" + RelationShipContains = common.TypeRelationshipContains RelationShipDescribe = common.TypeRelationshipDescribe RelationShipDependsOn = common.TypeRelationshipDependsOn @@ -122,6 +124,9 @@ func (m *Marshaler) Marshal(ctx context.Context, bom *core.BOM) (*spdx.Document, packages []*spdx.Package ) + // Lock time to use same time for all spdx fields + timeNow := clock.Now(ctx).UTC().Format(time.RFC3339) + root := bom.Root() pkgDownloadLocation := m.packageDownloadLocation(root) @@ -129,7 +134,7 @@ func (m *Marshaler) Marshal(ctx context.Context, bom *core.BOM) (*spdx.Document, packageIDs := make(map[uuid.UUID]spdx.ElementID) // Root package contains OS, OS packages, language-specific packages and so on. - rootPkg, err := m.rootSPDXPackage(root, pkgDownloadLocation) + rootPkg, err := m.rootSPDXPackage(root, timeNow, pkgDownloadLocation) if err != nil { return nil, xerrors.Errorf("failed to generate a root package: %w", err) } @@ -144,7 +149,7 @@ func (m *Marshaler) Marshal(ctx context.Context, bom *core.BOM) (*spdx.Document, if c.Root { continue } - spdxPackage, err := m.spdxPackage(c, pkgDownloadLocation) + spdxPackage, err := m.spdxPackage(c, timeNow, pkgDownloadLocation) if err != nil { return nil, xerrors.Errorf("spdx package error: %w", err) } @@ -216,7 +221,7 @@ func (m *Marshaler) Marshal(ctx context.Context, bom *core.BOM) (*spdx.Document, CreatorType: "Tool", }, }, - Created: clock.Now(ctx).UTC().Format(time.RFC3339), + Created: timeNow, }, Packages: packages, Relationships: relationShips, @@ -237,7 +242,7 @@ func (m *Marshaler) packageDownloadLocation(root *core.Component) string { return location } -func (m *Marshaler) rootSPDXPackage(root *core.Component, pkgDownloadLocation string) (*spdx.Package, error) { +func (m *Marshaler) rootSPDXPackage(root *core.Component, timeNow, pkgDownloadLocation string) (*spdx.Package, error) { var externalReferences []*spdx.PackageExternalReference // When the target is a container image, add PURL to the external references of the root package. if root.PkgIdentifier.PURL != nil { @@ -258,17 +263,25 @@ func (m *Marshaler) rootSPDXPackage(root *core.Component, pkgDownloadLocation st PackageName: root.Name, PackageSPDXIdentifier: elementID(camelCase(string(root.Type)), pkgID), PackageDownloadLocation: pkgDownloadLocation, - PackageAttributionTexts: m.spdxAttributionTexts(root), + Annotations: m.spdxAnnotations(root, timeNow), PackageExternalReferences: externalReferences, PrimaryPackagePurpose: pkgPurpose, }, nil } -func (m *Marshaler) appendAttributionText(attributionTexts []string, key, value string) []string { +func (m *Marshaler) appendAnnotation(annotations []spdx.Annotation, timeNow, key, value string) []spdx.Annotation { if value == "" { - return attributionTexts + return annotations } - return append(attributionTexts, fmt.Sprintf("%s: %s", key, value)) + return append(annotations, spdx.Annotation{ + AnnotationDate: timeNow, + AnnotationType: spdx.CategoryOther, + Annotator: spdx.Annotator{ + Annotator: fmt.Sprintf("%s-%s", CreatorTool, m.appVersion), + AnnotatorType: PackageAnnotatorToolField, + }, + AnnotationComment: fmt.Sprintf("%s: %s", key, value), + }) } func (m *Marshaler) purlExternalReference(packageURL string) *spdx.PackageExternalReference { @@ -287,7 +300,7 @@ func (m *Marshaler) advisoryExternalReference(primaryURL string) *spdx.PackageEx } } -func (m *Marshaler) spdxPackage(c *core.Component, pkgDownloadLocation string) (spdx.Package, error) { +func (m *Marshaler) spdxPackage(c *core.Component, timeNow, pkgDownloadLocation string) (spdx.Package, error) { pkgID, err := calcPkgID(m.hasher, c) if err != nil { return spdx.Package{}, xerrors.Errorf("failed to get os metadata package ID: %w", err) @@ -343,7 +356,7 @@ func (m *Marshaler) spdxPackage(c *core.Component, pkgDownloadLocation string) ( PrimaryPackagePurpose: purpose, PackageDownloadLocation: pkgDownloadLocation, PackageExternalReferences: pkgExtRefs, - PackageAttributionTexts: m.spdxAttributionTexts(c), + Annotations: m.spdxAnnotations(c, timeNow), PackageSourceInfo: sourceInfo, PackageSupplier: supplier, PackageChecksums: m.spdxChecksums(digests), @@ -365,16 +378,15 @@ func spdxPkgName(component *core.Component) string { } return component.Name } - -func (m *Marshaler) spdxAttributionTexts(c *core.Component) []string { - var texts []string +func (m *Marshaler) spdxAnnotations(c *core.Component, timeNow string) []spdx.Annotation { + var annotations []spdx.Annotation for _, p := range c.Properties { // Add properties that are not in other fields. if !slices.Contains(duplicateProperties, p.Name) { - texts = m.appendAttributionText(texts, p.Name, p.Value) + annotations = m.appendAnnotation(annotations, timeNow, p.Name, p.Value) } } - return texts + return annotations } func (m *Marshaler) spdxLicense(c *core.Component) string { diff --git a/pkg/sbom/spdx/marshal_test.go b/pkg/sbom/spdx/marshal_test.go index 74e9bee0a45d..4d9d33c013a7 100644 --- a/pkg/sbom/spdx/marshal_test.go +++ b/pkg/sbom/spdx/marshal_test.go @@ -25,6 +25,20 @@ import ( "github.com/aquasecurity/trivy/pkg/uuid" ) +func annotation(t *testing.T, comment string) spdx.Annotation { + t.Helper() + + return spdx.Annotation{ + AnnotationDate: "2021-08-25T12:20:30Z", + AnnotationType: spdx.CategoryOther, + Annotator: spdx.Annotator{ + Annotator: "trivy-0.56.2", + AnnotatorType: tspdx.PackageAnnotatorToolField, + }, + AnnotationComment: comment, + } +} + func TestMarshaler_Marshal(t *testing.T) { testCases := []struct { name string @@ -164,7 +178,7 @@ func TestMarshaler_Marshal(t *testing.T) { CreatorType: "Organization", }, { - Creator: "trivy-0.38.1", + Creator: "trivy-0.56.2", CreatorType: "Tool", }, }, @@ -176,9 +190,9 @@ func TestMarshaler_Marshal(t *testing.T) { PackageDownloadLocation: "NONE", PackageName: "app/Gemfile.lock", PrimaryPackagePurpose: tspdx.PackagePurposeApplication, - PackageAttributionTexts: []string{ - "Class: lang-pkgs", - "Type: bundler", + Annotations: []spdx.Annotation{ + annotation(t, "Class: lang-pkgs"), + annotation(t, "Type: bundler"), }, }, { @@ -186,9 +200,9 @@ func TestMarshaler_Marshal(t *testing.T) { PackageDownloadLocation: "NONE", PackageName: "app/subproject/Gemfile.lock", PrimaryPackagePurpose: tspdx.PackagePurposeApplication, - PackageAttributionTexts: []string{ - "Class: lang-pkgs", - "Type: bundler", + Annotations: []spdx.Annotation{ + annotation(t, "Class: lang-pkgs"), + annotation(t, "Type: bundler"), }, }, { @@ -202,14 +216,14 @@ func TestMarshaler_Marshal(t *testing.T) { Locator: "pkg:oci/rails@sha256%3Aa27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177?arch=arm64&repository_url=index.docker.io%2Flibrary%2Frails", }, }, - PackageAttributionTexts: []string{ - "DiffID: sha256:d871dadfb37b53ef1ca45be04fc527562b91989991a8f545345ae3be0b93f92a", - "ImageID: sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6", - "Labels:vendor: aquasecurity", - "RepoDigest: rails@sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177", - "RepoTag: rails:latest", - "SchemaVersion: 2", - "Size: 1024", + Annotations: []spdx.Annotation{ + annotation(t, "DiffID: sha256:d871dadfb37b53ef1ca45be04fc527562b91989991a8f545345ae3be0b93f92a"), + annotation(t, "ImageID: sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6"), + annotation(t, "Labels:vendor: aquasecurity"), + annotation(t, "RepoDigest: rails@sha256:a27fd8080b517143cbbbab9dfb7c8571c40d67d534bbdee55bd6c473f432b177"), + annotation(t, "RepoTag: rails:latest"), + annotation(t, "SchemaVersion: 2"), + annotation(t, "Size: 1024"), }, PrimaryPackagePurpose: tspdx.PackagePurposeContainer, }, @@ -220,8 +234,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageVersion: "7.0.1", PackageLicenseConcluded: "NOASSERTION", PackageLicenseDeclared: "NOASSERTION", - PackageAttributionTexts: []string{ - "PkgType: bundler", + Annotations: []spdx.Annotation{ + annotation(t, "PkgType: bundler"), }, PackageExternalReferences: []*spdx.PackageExternalReference{ { @@ -241,8 +255,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageVersion: "7.0.1", PackageLicenseConcluded: "NOASSERTION", PackageLicenseDeclared: "NOASSERTION", - PackageAttributionTexts: []string{ - "PkgType: bundler", + Annotations: []spdx.Annotation{ + annotation(t, "PkgType: bundler"), }, PackageExternalReferences: []*spdx.PackageExternalReference{ { @@ -262,8 +276,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageVersion: "7.0.1", PackageLicenseConcluded: "NOASSERTION", PackageLicenseDeclared: "NOASSERTION", - PackageAttributionTexts: []string{ - "PkgType: bundler", + Annotations: []spdx.Annotation{ + annotation(t, "PkgType: bundler"), }, PackageExternalReferences: []*spdx.PackageExternalReference{ { @@ -283,8 +297,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageVersion: "2.30-93.el8", PackageLicenseConcluded: "GPL-3.0-or-later", PackageLicenseDeclared: "GPL-3.0-or-later", - PackageAttributionTexts: []string{ - "PkgType: centos", + Annotations: []spdx.Annotation{ + annotation(t, "PkgType: centos"), }, PackageSupplier: &spdx.Supplier{ SupplierType: tspdx.PackageSupplierOrganization, @@ -312,9 +326,9 @@ func TestMarshaler_Marshal(t *testing.T) { PackageName: "centos", PackageVersion: "8.3.2011", PrimaryPackagePurpose: tspdx.PackagePurposeOS, - PackageAttributionTexts: []string{ - "Class: os-pkgs", - "Type: centos", + Annotations: []spdx.Annotation{ + annotation(t, "Class: os-pkgs"), + annotation(t, "Type: centos"), }, }, }, @@ -486,7 +500,7 @@ func TestMarshaler_Marshal(t *testing.T) { CreatorType: "Organization", }, { - Creator: "trivy-0.38.1", + Creator: "trivy-0.56.2", CreatorType: "Tool", }, }, @@ -497,11 +511,11 @@ func TestMarshaler_Marshal(t *testing.T) { PackageName: "centos:latest", PackageSPDXIdentifier: "ContainerImage-413bfede37ad01fc", PackageDownloadLocation: "NONE", - PackageAttributionTexts: []string{ - "ImageID: sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6", - "RepoTag: centos:latest", - "SchemaVersion: 2", - "Size: 1024", + Annotations: []spdx.Annotation{ + annotation(t, "ImageID: sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6"), + annotation(t, "RepoTag: centos:latest"), + annotation(t, "SchemaVersion: 2"), + annotation(t, "Size: 1024"), }, PrimaryPackagePurpose: tspdx.PackagePurposeContainer, }, @@ -512,8 +526,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageVersion: "1:2.2.53-1.el8", PackageLicenseConcluded: "GPL-2.0-or-later", PackageLicenseDeclared: "GPL-2.0-or-later", - PackageAttributionTexts: []string{ - "PkgType: centos", + Annotations: []spdx.Annotation{ + annotation(t, "PkgType: centos"), }, PackageExternalReferences: []*spdx.PackageExternalReference{ { @@ -546,9 +560,9 @@ func TestMarshaler_Marshal(t *testing.T) { Locator: "pkg:gem/actionpack@7.0.1", }, }, - PackageAttributionTexts: []string{ - "LayerDiffID: sha256:ccb64cf0b7ba2e50741d0b64cae324eb5de3b1e2f580bbf177e721b67df38488", - "PkgType: gemspec", + Annotations: []spdx.Annotation{ + annotation(t, "LayerDiffID: sha256:ccb64cf0b7ba2e50741d0b64cae324eb5de3b1e2f580bbf177e721b67df38488"), + annotation(t, "PkgType: gemspec"), }, PrimaryPackagePurpose: tspdx.PackagePurposeLibrary, PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion}, @@ -571,9 +585,9 @@ func TestMarshaler_Marshal(t *testing.T) { Locator: "pkg:gem/actionpack@7.0.1", }, }, - PackageAttributionTexts: []string{ - "LayerDiffID: sha256:ccb64cf0b7ba2e50741d0b64cae324eb5de3b1e2f580bbf177e721b67df38488", - "PkgType: gemspec", + Annotations: []spdx.Annotation{ + annotation(t, "LayerDiffID: sha256:ccb64cf0b7ba2e50741d0b64cae324eb5de3b1e2f580bbf177e721b67df38488"), + annotation(t, "PkgType: gemspec"), }, PrimaryPackagePurpose: tspdx.PackagePurposeLibrary, PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion}, @@ -588,9 +602,9 @@ func TestMarshaler_Marshal(t *testing.T) { PackageName: "centos", PackageVersion: "8.3.2011", PrimaryPackagePurpose: tspdx.PackagePurposeOS, - PackageAttributionTexts: []string{ - "Class: os-pkgs", - "Type: centos", + Annotations: []spdx.Annotation{ + annotation(t, "Class: os-pkgs"), + annotation(t, "Type: centos"), }, }, }, @@ -719,7 +733,7 @@ func TestMarshaler_Marshal(t *testing.T) { CreatorType: "Organization", }, { - Creator: "trivy-0.38.1", + Creator: "trivy-0.56.2", CreatorType: "Tool", }, }, @@ -731,9 +745,9 @@ func TestMarshaler_Marshal(t *testing.T) { PackageDownloadLocation: "NONE", PackageName: "Gemfile.lock", PrimaryPackagePurpose: tspdx.PackagePurposeApplication, - PackageAttributionTexts: []string{ - "Class: lang-pkgs", - "Type: bundler", + Annotations: []spdx.Annotation{ + annotation(t, "Class: lang-pkgs"), + annotation(t, "Type: bundler"), }, }, { @@ -741,9 +755,9 @@ func TestMarshaler_Marshal(t *testing.T) { PackageDownloadLocation: "NONE", PackageName: "pom.xml", PrimaryPackagePurpose: tspdx.PackagePurposeApplication, - PackageAttributionTexts: []string{ - "Class: lang-pkgs", - "Type: pom", + Annotations: []spdx.Annotation{ + annotation(t, "Class: lang-pkgs"), + annotation(t, "Type: pom"), }, }, { @@ -763,8 +777,8 @@ func TestMarshaler_Marshal(t *testing.T) { PrimaryPackagePurpose: tspdx.PackagePurposeLibrary, PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion}, PackageSourceInfo: "package found in: Gemfile.lock", - PackageAttributionTexts: []string{ - "PkgType: bundler", + Annotations: []spdx.Annotation{ + annotation(t, "PkgType: bundler"), }, }, { @@ -784,17 +798,17 @@ func TestMarshaler_Marshal(t *testing.T) { PrimaryPackagePurpose: tspdx.PackagePurposeLibrary, PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion}, PackageSourceInfo: "package found in: pom.xml", - PackageAttributionTexts: []string{ - "PkgID: com.example:example:1.0.0", - "PkgType: pom", + Annotations: []spdx.Annotation{ + annotation(t, "PkgID: com.example:example:1.0.0"), + annotation(t, "PkgType: pom"), }, }, { PackageSPDXIdentifier: spdx.ElementID("Filesystem-5af0f1f08c20909a"), PackageDownloadLocation: "NONE", PackageName: "masahiro331/CVE-2021-41098", - PackageAttributionTexts: []string{ - "SchemaVersion: 2", + Annotations: []spdx.Annotation{ + annotation(t, "SchemaVersion: 2"), }, PrimaryPackagePurpose: tspdx.PackagePurposeSource, }, @@ -878,7 +892,7 @@ func TestMarshaler_Marshal(t *testing.T) { CreatorType: "Organization", }, { - Creator: "trivy-0.38.1", + Creator: "trivy-0.56.2", CreatorType: "Tool", }, }, @@ -906,16 +920,16 @@ func TestMarshaler_Marshal(t *testing.T) { }, PrimaryPackagePurpose: tspdx.PackagePurposeLibrary, PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion}, - PackageAttributionTexts: []string{ - "PkgType: jar", + Annotations: []spdx.Annotation{ + annotation(t, "PkgType: jar"), }, }, { PackageSPDXIdentifier: spdx.ElementID("Filesystem-121e7e7a43f02ab"), PackageDownloadLocation: "NONE", PackageName: "log4j-core-2.17.0.jar", - PackageAttributionTexts: []string{ - "SchemaVersion: 2", + Annotations: []spdx.Annotation{ + annotation(t, "SchemaVersion: 2"), }, PrimaryPackagePurpose: tspdx.PackagePurposeSource, }, @@ -980,7 +994,7 @@ func TestMarshaler_Marshal(t *testing.T) { CreatorType: "Organization", }, { - Creator: "trivy-0.38.1", + Creator: "trivy-0.56.2", CreatorType: "Tool", }, }, @@ -1001,9 +1015,9 @@ func TestMarshaler_Marshal(t *testing.T) { Locator: "pkg:npm/ruby-typeprof@0.20.1", }, }, - PackageAttributionTexts: []string{ - "LayerDiffID: sha256:661c3fd3cc16b34c070f3620ca6b03b6adac150f9a7e5d0e3c707a159990f88e", - "PkgType: node-pkg", + Annotations: []spdx.Annotation{ + annotation(t, "LayerDiffID: sha256:661c3fd3cc16b34c070f3620ca6b03b6adac150f9a7e5d0e3c707a159990f88e"), + annotation(t, "PkgType: node-pkg"), }, PrimaryPackagePurpose: tspdx.PackagePurposeLibrary, PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion}, @@ -1016,8 +1030,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageSPDXIdentifier: "Repository-1a78857c1a6a759e", PackageName: "http://test-aggregate", PackageDownloadLocation: "git+http://test-aggregate", - PackageAttributionTexts: []string{ - "SchemaVersion: 2", + Annotations: []spdx.Annotation{ + annotation(t, "SchemaVersion: 2"), }, PrimaryPackagePurpose: tspdx.PackagePurposeSource, }, @@ -1075,7 +1089,7 @@ func TestMarshaler_Marshal(t *testing.T) { CreatorType: "Organization", }, { - Creator: "trivy-0.38.1", + Creator: "trivy-0.56.2", CreatorType: "Tool", }, }, @@ -1086,8 +1100,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageName: "empty/path", PackageSPDXIdentifier: "Filesystem-70f34983067dba86", PackageDownloadLocation: "NONE", - PackageAttributionTexts: []string{ - "SchemaVersion: 2", + Annotations: []spdx.Annotation{ + annotation(t, "SchemaVersion: 2"), }, PrimaryPackagePurpose: tspdx.PackagePurposeSource, }, @@ -1137,7 +1151,7 @@ func TestMarshaler_Marshal(t *testing.T) { CreatorType: "Organization", }, { - Creator: "trivy-0.38.1", + Creator: "trivy-0.56.2", CreatorType: "Tool", }, }, @@ -1148,8 +1162,8 @@ func TestMarshaler_Marshal(t *testing.T) { PackageName: "secret", PackageSPDXIdentifier: "Filesystem-5c08d34162a2c5d3", PackageDownloadLocation: "NONE", - PackageAttributionTexts: []string{ - "SchemaVersion: 2", + Annotations: []spdx.Annotation{ + annotation(t, "SchemaVersion: 2"), }, PrimaryPackagePurpose: tspdx.PackagePurposeSource, }, @@ -1209,7 +1223,7 @@ func TestMarshaler_Marshal(t *testing.T) { CreatorType: "Organization", }, { - Creator: "trivy-0.38.1", + Creator: "trivy-0.56.2", CreatorType: "Tool", }, }, @@ -1221,9 +1235,9 @@ func TestMarshaler_Marshal(t *testing.T) { PackageDownloadLocation: "NONE", PackageName: "/usr/local/bin/test", PrimaryPackagePurpose: tspdx.PackagePurposeApplication, - PackageAttributionTexts: []string{ - "Class: lang-pkgs", - "Type: gobinary", + Annotations: []spdx.Annotation{ + annotation(t, "Class: lang-pkgs"), + annotation(t, "Type: gobinary"), }, }, { @@ -1235,8 +1249,8 @@ func TestMarshaler_Marshal(t *testing.T) { PrimaryPackagePurpose: tspdx.PackagePurposeLibrary, PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion}, PackageSourceInfo: "package found in: /usr/local/bin/test", - PackageAttributionTexts: []string{ - "PkgType: gobinary", + Annotations: []spdx.Annotation{ + annotation(t, "PkgType: gobinary"), }, }, { @@ -1256,16 +1270,16 @@ func TestMarshaler_Marshal(t *testing.T) { PrimaryPackagePurpose: tspdx.PackagePurposeLibrary, PackageSupplier: &spdx.Supplier{Supplier: tspdx.PackageSupplierNoAssertion}, PackageSourceInfo: "package found in: /usr/local/bin/test", - PackageAttributionTexts: []string{ - "PkgType: gobinary", + Annotations: []spdx.Annotation{ + annotation(t, "PkgType: gobinary"), }, }, { PackageName: "go-artifact", PackageSPDXIdentifier: "Filesystem-e340f27468b382be", PackageDownloadLocation: "NONE", - PackageAttributionTexts: []string{ - "SchemaVersion: 2", + Annotations: []spdx.Annotation{ + annotation(t, "SchemaVersion: 2"), }, PrimaryPackagePurpose: tspdx.PackagePurposeSource, }, @@ -1326,7 +1340,7 @@ func TestMarshaler_Marshal(t *testing.T) { ctx := clock.With(context.Background(), time.Date(2021, 8, 25, 12, 20, 30, 5, time.UTC)) uuid.SetFakeUUID(t, "3ff14136-e09f-4df9-80ea-%012d") - marshaler := tspdx.NewMarshaler("0.38.1", tspdx.WithHasher(hasher)) + marshaler := tspdx.NewMarshaler("0.56.2", tspdx.WithHasher(hasher)) spdxDoc, err := marshaler.MarshalReport(ctx, tc.inputReport) require.NoError(t, err) diff --git a/pkg/sbom/spdx/testdata/happy/bom.json b/pkg/sbom/spdx/testdata/happy/bom.json index 823c0471351f..88af63b3b71a 100644 --- a/pkg/sbom/spdx/testdata/happy/bom.json +++ b/pkg/sbom/spdx/testdata/happy/bom.json @@ -37,13 +37,43 @@ }, { "SPDXID": "SPDXRef-ContainerImage-b5d81cde5f95c8fc", - "attributionTexts": [ - "SchemaVersion: 2", - "ImageID: sha256:49193a2310dbad4c02382da87ac624a80a92387a4f7536235f9ba590e5bcd7b5", - "DiffID: sha256:dd565ff850e7003356e2b252758f9bdc1ff2803f61e995e24c7844f6297f8fc3", - "DiffID: sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1", - "RepoTag: maven-test-project:latest", - "RepoTag: tmp-test:latest" + "annotations": [ + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2024-10-29T06:50:38Z", + "annotationType": "OTHER", + "comment": "SchemaVersion: 2" + }, + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2024-10-29T06:50:38Z", + "annotationType": "OTHER", + "comment": "ImageID: sha256:49193a2310dbad4c02382da87ac624a80a92387a4f7536235f9ba590e5bcd7b5" + }, + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2024-10-29T06:50:38Z", + "annotationType": "OTHER", + "comment": "DiffID: sha256:dd565ff850e7003356e2b252758f9bdc1ff2803f61e995e24c7844f6297f8fc3" + }, + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2024-10-29T06:50:38Z", + "annotationType": "OTHER", + "comment": "DiffID: sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1" + }, + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2024-10-29T06:50:38Z", + "annotationType": "OTHER", + "comment": "RepoTag: maven-test-project:latest" + }, + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2024-10-29T06:50:38Z", + "annotationType": "OTHER", + "comment": "RepoTag: tmp-test:latest" + } ], "filesAnalyzed": false, "name": "meven-test-project" @@ -56,8 +86,13 @@ }, { "SPDXID": "SPDXRef-Package-2906575950df652b", - "attributionTexts": [ - "LayerDiffID: sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1" + "annotations": [ + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2024-10-29T06:50:38Z", + "annotationType": "OTHER", + "comment": "LayerDiffID: sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1" + } ], "externalRefs": [ { @@ -74,8 +109,13 @@ }, { "SPDXID": "SPDXRef-Package-2a53baa495b9ddaf", - "attributionTexts": [ - "LayerDiffID: sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1" + "annotations": [ + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2024-10-29T06:50:38Z", + "annotationType": "OTHER", + "comment": "LayerDiffID: sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1" + } ], "externalRefs": [ { @@ -92,8 +132,13 @@ }, { "SPDXID": "SPDXRef-Package-5e2e255ac76747ef", - "attributionTexts": [ - "LayerDiffID: sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1" + "annotations": [ + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2024-10-29T06:50:38Z", + "annotationType": "OTHER", + "comment": "LayerDiffID: sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1" + } ], "externalRefs": [ { @@ -110,8 +155,13 @@ }, { "SPDXID": "SPDXRef-Package-5f1dbaff8de5eb06", - "attributionTexts": [ - "LayerDiffID: sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1" + "annotations": [ + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2024-10-29T06:50:38Z", + "annotationType": "OTHER", + "comment": "LayerDiffID: sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1" + } ], "externalRefs": [ { @@ -128,8 +178,13 @@ }, { "SPDXID": "SPDXRef-Package-84ebffe38343d949", - "attributionTexts": [ - "LayerDiffID: sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1" + "annotations": [ + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2024-10-29T06:50:38Z", + "annotationType": "OTHER", + "comment": "LayerDiffID: sha256:3c79e832b1b4891a1cb4a326ef8524e0bd14a2537150ac0e203a5677176c1ca1" + } ], "externalRefs": [ { @@ -146,8 +201,13 @@ }, { "SPDXID": "SPDXRef-Package-b7ebaf0233f1ef7b", - "attributionTexts": [ - "LayerDiffID: sha256:dd565ff850e7003356e2b252758f9bdc1ff2803f61e995e24c7844f6297f8fc3" + "annotations": [ + { + "annotator": "Tool: trivy-dev", + "annotationDate": "2024-10-29T06:50:38Z", + "annotationType": "OTHER", + "comment": "LayerDiffID: sha256:dd565ff850e7003356e2b252758f9bdc1ff2803f61e995e24c7844f6297f8fc3" + } ], "externalRefs": [ { diff --git a/pkg/sbom/spdx/unmarshal.go b/pkg/sbom/spdx/unmarshal.go index d2ba05b44999..c7ed6b0905dd 100644 --- a/pkg/sbom/spdx/unmarshal.go +++ b/pkg/sbom/spdx/unmarshal.go @@ -194,9 +194,21 @@ func (s *SPDX) parsePackage(spdxPkg spdx.Package) (*core.Component, error) { } } - // Attributions - for _, attr := range spdxPkg.PackageAttributionTexts { - k, v, ok := strings.Cut(attr, ": ") + // Trivy stores properties in Annotations + // But previous versions stored properties in AttributionTexts + // So we need to check both cases to maintain backward compatibility + var props []string + if len(spdxPkg.Annotations) > 0 { + for _, annotation := range spdxPkg.Annotations { + props = append(props, annotation.AnnotationComment) + } + } else if len(spdxPkg.PackageAttributionTexts) > 0 { + for _, attr := range spdxPkg.PackageAttributionTexts { + props = append(props, attr) + } + } + for _, prop := range props { + k, v, ok := strings.Cut(prop, ": ") if !ok { continue } From 78827768a612ab305bf9c55409ce76d6774302a5 Mon Sep 17 00:00:00 2001 From: afdesk Date: Thu, 31 Oct 2024 07:14:56 +0600 Subject: [PATCH 163/183] fix(k8s): skip resources without misconfigs (#7797) --- pkg/k8s/report/report.go | 11 ++++++++++- pkg/k8s/report/report_test.go | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/pkg/k8s/report/report.go b/pkg/k8s/report/report.go index b52391ec8239..947d39de14b8 100644 --- a/pkg/k8s/report/report.go +++ b/pkg/k8s/report/report.go @@ -90,8 +90,13 @@ func (r Report) consolidate() ConsolidatedReport { for _, m := range r.Resources { if vulnerabilitiesOrSecretResource(m) { vulnerabilities = append(vulnerabilities, m) - } else { + } + if misconfigsResource(m) { + res, ok := index[m.fullname()] index[m.fullname()] = m + if ok { + index[m.fullname()].Results[0].Misconfigurations = append(index[m.fullname()].Results[0].Misconfigurations, res.Results[0].Misconfigurations...) + } } } @@ -278,6 +283,10 @@ func vulnerabilitiesOrSecretResource(resource Resource) bool { return len(resource.Results) > 0 && (len(resource.Results[0].Vulnerabilities) > 0 || len(resource.Results[0].Secrets) > 0) } +func misconfigsResource(resource Resource) bool { + return len(resource.Results) > 0 && len(resource.Results[0].Misconfigurations) > 0 +} + func nodeKind(resource Resource) Resource { if nodeInfoResource(resource) { resource.Kind = "Node" diff --git a/pkg/k8s/report/report_test.go b/pkg/k8s/report/report_test.go index 1a984eb71b23..9ba663dc4783 100644 --- a/pkg/k8s/report/report_test.go +++ b/pkg/k8s/report/report_test.go @@ -119,6 +119,23 @@ var ( }, } + orionDeployWithAnotherMisconfig = Resource{ + Namespace: "default", + Kind: "Deploy", + Name: "orion", + Results: types.Results{ + { + Misconfigurations: []types.DetectedMisconfiguration{ + { + ID: "ID201", + Status: types.MisconfStatusFailure, + Severity: "HIGH", + }, + }, + }, + }, + } + image1WithVulns = Resource{ Namespace: "default", Kind: "Pod", @@ -424,6 +441,10 @@ var ( ) func TestReport_consolidate(t *testing.T) { + concatenatedResource := orionDeployWithAnotherMisconfig + concatenatedResource.Results[0].Misconfigurations = append(concatenatedResource.Results[0].Misconfigurations, + deployOrionWithMisconfigs.Results[0].Misconfigurations...) + tests := []struct { name string report Report @@ -471,6 +492,18 @@ func TestReport_consolidate(t *testing.T) { "default/cronjob/hello": cronjobHelloWithVulns, }, }, + { + name: "report with misconfigs in image and pod", + report: Report{ + Resources: []Resource{ + deployOrionWithMisconfigs, + orionDeployWithAnotherMisconfig, + }, + }, + expectedFindings: map[string]Resource{ + "default/deploy/orion": concatenatedResource, + }, + }, { name: "report with multi image pod containing vulnerabilities", report: Report{ From e872ec006c0745a5a142728af0096c6d6bb9ddf3 Mon Sep 17 00:00:00 2001 From: Rutam Prita Mishra Date: Thu, 31 Oct 2024 11:33:22 +0530 Subject: [PATCH 164/183] fix(go): Do not trim v prefix from versions in Go Mod Analyzer (#7733) Co-authored-by: DmitriyLewen --- docs/docs/supply-chain/vex/file.md | 8 +- .../testdata/fixtures/vex/file/openvex.json | 2 +- integration/testdata/gomod-skip.json.golden | 24 +- integration/testdata/gomod-vex.json.golden | 24 +- integration/testdata/gomod.json.golden | 30 +- pkg/dependency/id_test.go | 2 +- pkg/dependency/parser/golang/binary/parse.go | 3 + .../parser/golang/binary/parse_test.go | 10 +- pkg/dependency/parser/golang/mod/parse.go | 25 +- .../parser/golang/mod/parse_testcase.go | 48 +- pkg/dependency/parser/golang/sum/parse.go | 2 +- .../parser/golang/sum/parse_testcase.go | 704 +++++++++--------- .../language/golang/binary/binary_test.go | 2 +- pkg/fanal/analyzer/language/golang/mod/mod.go | 2 +- .../analyzer/language/golang/mod/mod_test.go | 12 +- pkg/purl/purl_test.go | 20 +- pkg/result/filter_test.go | 14 +- pkg/result/testdata/openvex.json | 2 +- pkg/sbom/io/encode_test.go | 32 +- pkg/vex/testdata/csaf-relationships.json | 4 +- pkg/vex/testdata/csaf.json | 2 +- pkg/vex/testdata/openvex-nested.json | 4 +- pkg/vex/vex_test.go | 40 +- 23 files changed, 510 insertions(+), 506 deletions(-) diff --git a/docs/docs/supply-chain/vex/file.md b/docs/docs/supply-chain/vex/file.md index 7c847ec49e14..242ec4c5a040 100644 --- a/docs/docs/supply-chain/vex/file.md +++ b/docs/docs/supply-chain/vex/file.md @@ -64,7 +64,7 @@ $ cat < trivy.vex.cdx }, "affects": [ { - "ref": "urn:cdx:3e671687-395b-41f5-a30f-a58921a69b79/1#pkg:golang/github.com/aws/aws-sdk-go@1.44.234" + "ref": "urn:cdx:3e671687-395b-41f5-a30f-a58921a69b79/1#pkg:golang/github.com/aws/aws-sdk-go@v1.44.234" } ] } @@ -115,7 +115,7 @@ Total: 1 (UNKNOWN: 0, LOW: 1, MEDIUM: 0, HIGH: 0, CRITICAL: 0) ┌───────────────────────────┬───────────────┬──────────┬───────────────────┬───────────────┬────────────────────────────────────────────────────────────┐ │ Library │ Vulnerability │ Severity │ Installed Version │ Fixed Version │ Title │ ├───────────────────────────┼───────────────┼──────────┼───────────────────┼───────────────┼────────────────────────────────────────────────────────────┤ -│ github.com/aws/aws-sdk-go │ CVE-2020-8912 │ LOW │ 1.44.234 │ │ aws-sdk-go: In-band key negotiation issue in AWS S3 Crypto │ +│ github.com/aws/aws-sdk-go │ CVE-2020-8912 │ LOW │ v1.44.234 │ │ aws-sdk-go: In-band key negotiation issue in AWS S3 Crypto │ │ │ │ │ │ │ SDK for golang... │ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-8912 │ └───────────────────────────┴───────────────┴──────────┴───────────────────┴───────────────┴────────────────────────────────────────────────────────────┘ @@ -497,9 +497,9 @@ Now, suppose a VEX statement is issued for `Module B` as follows: "vulnerability": {"name": "CVE-XXXX-YYYY"}, "products": [ { - "@id": "pkg:golang/module-b@1.0.0", + "@id": "pkg:golang/module-b@v1.0.0", "subcomponents": [ - { "@id": "pkg:golang/module-c@2.0.0" } + { "@id": "pkg:golang/module-c@v2.0.0" } ] } ], diff --git a/integration/testdata/fixtures/vex/file/openvex.json b/integration/testdata/fixtures/vex/file/openvex.json index 38773ba57694..9782e1716387 100644 --- a/integration/testdata/fixtures/vex/file/openvex.json +++ b/integration/testdata/fixtures/vex/file/openvex.json @@ -11,7 +11,7 @@ { "@id": "pkg:golang/github.com/testdata/testdata", "subcomponents": [ - { "@id": "pkg:golang/github.com/open-policy-agent/opa@0.35.0" } + { "@id": "pkg:golang/github.com/open-policy-agent/opa@v0.35.0" } ] } ], diff --git a/integration/testdata/gomod-skip.json.golden b/integration/testdata/gomod-skip.json.golden index 69ab998ec9dd..877fd627b89a 100644 --- a/integration/testdata/gomod-skip.json.golden +++ b/integration/testdata/gomod-skip.json.golden @@ -26,10 +26,10 @@ "PkgID": "github.com/docker/distribution@v2.7.1+incompatible", "PkgName": "github.com/docker/distribution", "PkgIdentifier": { - "PURL": "pkg:golang/github.com/docker/distribution@2.7.1%2Bincompatible", - "UID": "de19cd663ca047a8" + "PURL": "pkg:golang/github.com/docker/distribution@v2.7.1%2Bincompatible", + "UID": "9d949a7b01249e68" }, - "InstalledVersion": "2.7.1+incompatible", + "InstalledVersion": "v2.7.1+incompatible", "FixedVersion": "v2.8.0", "Status": "fixed", "Layer": {}, @@ -53,10 +53,10 @@ "PkgID": "github.com/open-policy-agent/opa@v0.35.0", "PkgName": "github.com/open-policy-agent/opa", "PkgIdentifier": { - "PURL": "pkg:golang/github.com/open-policy-agent/opa@0.35.0", - "UID": "6b685002e082ffc5" + "PURL": "pkg:golang/github.com/open-policy-agent/opa@v0.35.0", + "UID": "e89e2b0d8977e2a" }, - "InstalledVersion": "0.35.0", + "InstalledVersion": "v0.35.0", "FixedVersion": "0.37.0", "Status": "fixed", "Layer": {}, @@ -100,10 +100,10 @@ "PkgID": "golang.org/x/text@v0.3.6", "PkgName": "golang.org/x/text", "PkgIdentifier": { - "PURL": "pkg:golang/golang.org/x/text@0.3.6", - "UID": "825dc613c0f39d45" + "PURL": "pkg:golang/golang.org/x/text@v0.3.6", + "UID": "3050088ce9eb2ce4" }, - "InstalledVersion": "0.3.6", + "InstalledVersion": "v0.3.6", "FixedVersion": "0.3.7", "Status": "fixed", "Layer": {}, @@ -133,10 +133,10 @@ "PkgID": "github.com/docker/distribution@v2.7.1+incompatible", "PkgName": "github.com/docker/distribution", "PkgIdentifier": { - "PURL": "pkg:golang/github.com/docker/distribution@2.7.1%2Bincompatible", - "UID": "94376dc37054a7e8" + "PURL": "pkg:golang/github.com/docker/distribution@v2.7.1%2Bincompatible", + "UID": "2f7f0fa81860b8f1" }, - "InstalledVersion": "2.7.1+incompatible", + "InstalledVersion": "v2.7.1+incompatible", "FixedVersion": "v2.8.0", "Status": "fixed", "Layer": {}, diff --git a/integration/testdata/gomod-vex.json.golden b/integration/testdata/gomod-vex.json.golden index a2269bd1d0b7..34d96dc0ce95 100644 --- a/integration/testdata/gomod-vex.json.golden +++ b/integration/testdata/gomod-vex.json.golden @@ -26,10 +26,10 @@ "PkgID": "github.com/docker/distribution@v2.7.1+incompatible", "PkgName": "github.com/docker/distribution", "PkgIdentifier": { - "PURL": "pkg:golang/github.com/docker/distribution@2.7.1%2Bincompatible", - "UID": "de19cd663ca047a8" + "PURL": "pkg:golang/github.com/docker/distribution@v2.7.1%2Bincompatible", + "UID": "9d949a7b01249e68" }, - "InstalledVersion": "2.7.1+incompatible", + "InstalledVersion": "v2.7.1+incompatible", "FixedVersion": "v2.8.0", "Status": "fixed", "Layer": {}, @@ -53,10 +53,10 @@ "PkgID": "golang.org/x/text@v0.3.6", "PkgName": "golang.org/x/text", "PkgIdentifier": { - "PURL": "pkg:golang/golang.org/x/text@0.3.6", - "UID": "825dc613c0f39d45" + "PURL": "pkg:golang/golang.org/x/text@v0.3.6", + "UID": "3050088ce9eb2ce4" }, - "InstalledVersion": "0.3.6", + "InstalledVersion": "v0.3.6", "FixedVersion": "0.3.7", "Status": "fixed", "Layer": {}, @@ -86,10 +86,10 @@ "PkgID": "github.com/docker/distribution@v2.7.1+incompatible", "PkgName": "github.com/docker/distribution", "PkgIdentifier": { - "PURL": "pkg:golang/github.com/docker/distribution@2.7.1%2Bincompatible", - "UID": "94376dc37054a7e8" + "PURL": "pkg:golang/github.com/docker/distribution@v2.7.1%2Bincompatible", + "UID": "2f7f0fa81860b8f1" }, - "InstalledVersion": "2.7.1+incompatible", + "InstalledVersion": "v2.7.1+incompatible", "FixedVersion": "v2.8.0", "Status": "fixed", "Layer": {}, @@ -120,10 +120,10 @@ "PkgID": "github.com/docker/distribution@v2.7.1+incompatible", "PkgName": "github.com/docker/distribution", "PkgIdentifier": { - "PURL": "pkg:golang/github.com/docker/distribution@2.7.1%2Bincompatible", - "UID": "94306cdcf85fb50a" + "PURL": "pkg:golang/github.com/docker/distribution@v2.7.1%2Bincompatible", + "UID": "3ad40723ed2fce22" }, - "InstalledVersion": "2.7.1+incompatible", + "InstalledVersion": "v2.7.1+incompatible", "FixedVersion": "v2.8.0", "Status": "fixed", "Layer": {}, diff --git a/integration/testdata/gomod.json.golden b/integration/testdata/gomod.json.golden index 627088188285..551b787cadd6 100644 --- a/integration/testdata/gomod.json.golden +++ b/integration/testdata/gomod.json.golden @@ -26,10 +26,10 @@ "PkgID": "github.com/docker/distribution@v2.7.1+incompatible", "PkgName": "github.com/docker/distribution", "PkgIdentifier": { - "PURL": "pkg:golang/github.com/docker/distribution@2.7.1%2Bincompatible", - "UID": "de19cd663ca047a8" + "PURL": "pkg:golang/github.com/docker/distribution@v2.7.1%2Bincompatible", + "UID": "9d949a7b01249e68" }, - "InstalledVersion": "2.7.1+incompatible", + "InstalledVersion": "v2.7.1+incompatible", "FixedVersion": "v2.8.0", "Status": "fixed", "Layer": {}, @@ -53,10 +53,10 @@ "PkgID": "github.com/open-policy-agent/opa@v0.35.0", "PkgName": "github.com/open-policy-agent/opa", "PkgIdentifier": { - "PURL": "pkg:golang/github.com/open-policy-agent/opa@0.35.0", - "UID": "6b685002e082ffc5" + "PURL": "pkg:golang/github.com/open-policy-agent/opa@v0.35.0", + "UID": "e89e2b0d8977e2a" }, - "InstalledVersion": "0.35.0", + "InstalledVersion": "v0.35.0", "FixedVersion": "0.37.0", "Status": "fixed", "Layer": {}, @@ -100,10 +100,10 @@ "PkgID": "golang.org/x/text@v0.3.6", "PkgName": "golang.org/x/text", "PkgIdentifier": { - "PURL": "pkg:golang/golang.org/x/text@0.3.6", - "UID": "825dc613c0f39d45" + "PURL": "pkg:golang/golang.org/x/text@v0.3.6", + "UID": "3050088ce9eb2ce4" }, - "InstalledVersion": "0.3.6", + "InstalledVersion": "v0.3.6", "FixedVersion": "0.3.7", "Status": "fixed", "Layer": {}, @@ -133,10 +133,10 @@ "PkgID": "github.com/docker/distribution@v2.7.1+incompatible", "PkgName": "github.com/docker/distribution", "PkgIdentifier": { - "PURL": "pkg:golang/github.com/docker/distribution@2.7.1%2Bincompatible", - "UID": "94376dc37054a7e8" + "PURL": "pkg:golang/github.com/docker/distribution@v2.7.1%2Bincompatible", + "UID": "2f7f0fa81860b8f1" }, - "InstalledVersion": "2.7.1+incompatible", + "InstalledVersion": "v2.7.1+incompatible", "FixedVersion": "v2.8.0", "Status": "fixed", "Layer": {}, @@ -167,10 +167,10 @@ "PkgID": "github.com/docker/distribution@v2.7.1+incompatible", "PkgName": "github.com/docker/distribution", "PkgIdentifier": { - "PURL": "pkg:golang/github.com/docker/distribution@2.7.1%2Bincompatible", - "UID": "94306cdcf85fb50a" + "PURL": "pkg:golang/github.com/docker/distribution@v2.7.1%2Bincompatible", + "UID": "3ad40723ed2fce22" }, - "InstalledVersion": "2.7.1+incompatible", + "InstalledVersion": "v2.7.1+incompatible", "FixedVersion": "v2.8.0", "Status": "fixed", "Layer": {}, diff --git a/pkg/dependency/id_test.go b/pkg/dependency/id_test.go index 18359f771e7b..2b8c0e4a71b1 100644 --- a/pkg/dependency/id_test.go +++ b/pkg/dependency/id_test.go @@ -34,7 +34,7 @@ func TestID(t *testing.T) { args: args{ ltype: types.GoModule, name: "test", - version: "1.0.0", + version: "v1.0.0", }, want: "test@v1.0.0", }, diff --git a/pkg/dependency/parser/golang/binary/parse.go b/pkg/dependency/parser/golang/binary/parse.go index 6959e0ede5fa..2a7a2a128de7 100644 --- a/pkg/dependency/parser/golang/binary/parse.go +++ b/pkg/dependency/parser/golang/binary/parse.go @@ -3,6 +3,7 @@ package binary import ( "cmp" "debug/buildinfo" + "fmt" "runtime/debug" "slices" "sort" @@ -56,6 +57,8 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc // Ex: "go1.22.3 X:boringcrypto" stdlibVersion := strings.TrimPrefix(info.GoVersion, "go") stdlibVersion, _, _ = strings.Cut(stdlibVersion, " ") + // Add the `v` prefix to be consistent with module and dependency versions. + stdlibVersion = fmt.Sprintf("v%s", stdlibVersion) ldflags := p.ldFlags(info.Settings) pkgs := make(ftypes.Packages, 0, len(info.Deps)+2) diff --git a/pkg/dependency/parser/golang/binary/parse_test.go b/pkg/dependency/parser/golang/binary/parse_test.go index 2fbb6acff7b2..aade2a32cf24 100644 --- a/pkg/dependency/parser/golang/binary/parse_test.go +++ b/pkg/dependency/parser/golang/binary/parse_test.go @@ -20,7 +20,7 @@ func TestParse(t *testing.T) { }, { Name: "stdlib", - Version: "1.15.2", + Version: "v1.15.2", Relationship: ftypes.RelationshipDirect, }, { @@ -69,7 +69,7 @@ func TestParse(t *testing.T) { }, { Name: "stdlib", - Version: "1.16.4", + Version: "v1.16.4", Relationship: ftypes.RelationshipDirect, }, { @@ -93,7 +93,7 @@ func TestParse(t *testing.T) { }, { Name: "stdlib", - Version: "1.20.6", + Version: "v1.20.6", Relationship: ftypes.RelationshipDirect, }, }, @@ -109,7 +109,7 @@ func TestParse(t *testing.T) { }, { Name: "stdlib", - Version: "1.22.1", + Version: "v1.22.1", Relationship: ftypes.RelationshipDirect, }, }, @@ -120,7 +120,7 @@ func TestParse(t *testing.T) { want: []ftypes.Package{ { Name: "stdlib", - Version: "1.22.1", + Version: "v1.22.1", Relationship: ftypes.RelationshipDirect, }, }, diff --git a/pkg/dependency/parser/golang/mod/parse.go b/pkg/dependency/parser/golang/mod/parse.go index bbf42926a766..ddcd2ccc880e 100644 --- a/pkg/dependency/parser/golang/mod/parse.go +++ b/pkg/dependency/parser/golang/mod/parse.go @@ -1,6 +1,7 @@ package mod import ( + "fmt" "io" "regexp" "strconv" @@ -90,9 +91,11 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc if p.useMinVersion { if toolchainVer := toolchainVersion(modFileParsed.Toolchain, modFileParsed.Go); toolchainVer != "" { pkgs["stdlib"] = ftypes.Package{ - ID: packageID("stdlib", toolchainVer), - Name: "stdlib", - Version: toolchainVer, + ID: packageID("stdlib", toolchainVer), + Name: "stdlib", + // Our versioning library doesn't support canonical (goX.Y.Z) format, + // So we need to add `v` prefix for consistency (with module and dependency versions). + Version: fmt.Sprintf("v%s", toolchainVer), Relationship: ftypes.RelationshipDirect, // Considered a direct dependency as the main module depends on the standard packages. } } @@ -100,11 +103,10 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc // Main module if m := modFileParsed.Module; m != nil { - ver := strings.TrimPrefix(m.Mod.Version, "v") pkgs[m.Mod.Path] = ftypes.Package{ - ID: packageID(m.Mod.Path, ver), + ID: packageID(m.Mod.Path, m.Mod.Version), Name: m.Mod.Path, - Version: ver, + Version: m.Mod.Version, ExternalReferences: p.GetExternalRefs(m.Mod.Path), Relationship: ftypes.RelationshipRoot, } @@ -116,11 +118,10 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc if skipIndirect && require.Indirect { continue } - ver := strings.TrimPrefix(require.Mod.Version, "v") pkgs[require.Mod.Path] = ftypes.Package{ - ID: packageID(require.Mod.Path, ver), + ID: packageID(require.Mod.Path, require.Mod.Version), Name: require.Mod.Path, - Version: ver, + Version: require.Mod.Version, Relationship: lo.Ternary(require.Indirect, ftypes.RelationshipIndirect, ftypes.RelationshipDirect), ExternalReferences: p.GetExternalRefs(require.Mod.Path), } @@ -136,7 +137,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc } // If the replace directive has a version on the left side, make sure it matches the version that was imported. - if rep.Old.Version != "" && old.Version != rep.Old.Version[1:] { + if rep.Old.Version != "" && old.Version != rep.Old.Version { continue } @@ -153,9 +154,9 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc // Add replaced package to package register. pkgs[rep.New.Path] = ftypes.Package{ - ID: packageID(rep.New.Path, rep.New.Version[1:]), + ID: packageID(rep.New.Path, rep.New.Version), Name: rep.New.Path, - Version: rep.New.Version[1:], + Version: rep.New.Version, Relationship: old.Relationship, ExternalReferences: p.GetExternalRefs(rep.New.Path), } diff --git a/pkg/dependency/parser/golang/mod/parse_testcase.go b/pkg/dependency/parser/golang/mod/parse_testcase.go index 4671ef3e6854..b8ed49008926 100644 --- a/pkg/dependency/parser/golang/mod/parse_testcase.go +++ b/pkg/dependency/parser/golang/mod/parse_testcase.go @@ -23,13 +23,13 @@ var ( { ID: "stdlib@v1.22.5", Name: "stdlib", - Version: "1.22.5", + Version: "v1.22.5", Relationship: ftypes.RelationshipDirect, }, { ID: "github.com/aquasecurity/go-version@v0.0.0-20240603093900-cf8a8d29271d", Name: "github.com/aquasecurity/go-version", - Version: "0.0.0-20240603093900-cf8a8d29271d", + Version: "v0.0.0-20240603093900-cf8a8d29271d", Relationship: ftypes.RelationshipDirect, ExternalReferences: []ftypes.ExternalRef{ { @@ -41,7 +41,7 @@ var ( { ID: "github.com/davecgh/go-spew@v1.1.2-0.20180830191138-d8f796af33cc", Name: "github.com/davecgh/go-spew", - Version: "1.1.2-0.20180830191138-d8f796af33cc", + Version: "v1.1.2-0.20180830191138-d8f796af33cc", Relationship: ftypes.RelationshipIndirect, ExternalReferences: []ftypes.ExternalRef{ { @@ -53,7 +53,7 @@ var ( { ID: "github.com/pmezard/go-difflib@v1.0.1-0.20181226105442-5d4384ee4fb2", Name: "github.com/pmezard/go-difflib", - Version: "1.0.1-0.20181226105442-5d4384ee4fb2", + Version: "v1.0.1-0.20181226105442-5d4384ee4fb2", Relationship: ftypes.RelationshipIndirect, ExternalReferences: []ftypes.ExternalRef{ { @@ -65,7 +65,7 @@ var ( { ID: "github.com/stretchr/testify@v1.9.0", Name: "github.com/stretchr/testify", - Version: "1.9.0", + Version: "v1.9.0", Relationship: ftypes.RelationshipIndirect, ExternalReferences: []ftypes.ExternalRef{ { @@ -77,7 +77,7 @@ var ( { ID: "golang.org/x/xerrors@v0.0.0-20231012003039-104605ab7028", Name: "golang.org/x/xerrors", - Version: "0.0.0-20231012003039-104605ab7028", + Version: "v0.0.0-20231012003039-104605ab7028", Relationship: ftypes.RelationshipIndirect, }, } @@ -102,7 +102,7 @@ var ( { ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20220406074731-71021a481237", Name: "github.com/aquasecurity/go-dep-parser", - Version: "0.0.0-20220406074731-71021a481237", + Version: "v0.0.0-20220406074731-71021a481237", Relationship: ftypes.RelationshipDirect, ExternalReferences: []ftypes.ExternalRef{ { @@ -114,7 +114,7 @@ var ( { ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", Name: "golang.org/x/xerrors", - Version: "0.0.0-20200804184101-5ec99f83aff1", + Version: "v0.0.0-20200804184101-5ec99f83aff1", Relationship: ftypes.RelationshipIndirect, }, } @@ -135,7 +135,7 @@ var ( { ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20211110174639-8257534ffed3", Name: "github.com/aquasecurity/go-dep-parser", - Version: "0.0.0-20211110174639-8257534ffed3", + Version: "v0.0.0-20211110174639-8257534ffed3", Relationship: ftypes.RelationshipDirect, ExternalReferences: []ftypes.ExternalRef{ { @@ -147,7 +147,7 @@ var ( { ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", Name: "golang.org/x/xerrors", - Version: "0.0.0-20200804184101-5ec99f83aff1", + Version: "v0.0.0-20200804184101-5ec99f83aff1", Relationship: ftypes.RelationshipIndirect, }, } @@ -168,7 +168,7 @@ var ( { ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20220406074731-71021a481237", Name: "github.com/aquasecurity/go-dep-parser", - Version: "0.0.0-20220406074731-71021a481237", + Version: "v0.0.0-20220406074731-71021a481237", Relationship: ftypes.RelationshipDirect, ExternalReferences: []ftypes.ExternalRef{ { @@ -180,7 +180,7 @@ var ( { ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", Name: "golang.org/x/xerrors", - Version: "0.0.0-20200804184101-5ec99f83aff1", + Version: "v0.0.0-20200804184101-5ec99f83aff1", Relationship: ftypes.RelationshipIndirect, }, } @@ -201,7 +201,7 @@ var ( { ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20211224170007-df43bca6b6ff", Name: "github.com/aquasecurity/go-dep-parser", - Version: "0.0.0-20211224170007-df43bca6b6ff", + Version: "v0.0.0-20211224170007-df43bca6b6ff", Relationship: ftypes.RelationshipDirect, ExternalReferences: []ftypes.ExternalRef{ { @@ -213,13 +213,13 @@ var ( { ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", Name: "golang.org/x/xerrors", - Version: "0.0.0-20200804184101-5ec99f83aff1", + Version: "v0.0.0-20200804184101-5ec99f83aff1", Relationship: ftypes.RelationshipIndirect, }, { ID: "gopkg.in/yaml.v3@v3.0.0-20210107192922-496545a6307b", Name: "gopkg.in/yaml.v3", - Version: "3.0.0-20210107192922-496545a6307b", + Version: "v3.0.0-20210107192922-496545a6307b", Relationship: ftypes.RelationshipIndirect, ExternalReferences: []ftypes.ExternalRef{ { @@ -246,7 +246,7 @@ var ( { ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20211224170007-df43bca6b6ff", Name: "github.com/aquasecurity/go-dep-parser", - Version: "0.0.0-20211224170007-df43bca6b6ff", + Version: "v0.0.0-20211224170007-df43bca6b6ff", Relationship: ftypes.RelationshipDirect, ExternalReferences: []ftypes.ExternalRef{ { @@ -258,7 +258,7 @@ var ( { ID: "gopkg.in/yaml.v3@v3.0.0-20210107192922-496545a6307b", Name: "gopkg.in/yaml.v3", - Version: "3.0.0-20210107192922-496545a6307b", + Version: "v3.0.0-20210107192922-496545a6307b", Relationship: ftypes.RelationshipIndirect, ExternalReferences: []ftypes.ExternalRef{ { @@ -285,7 +285,7 @@ var ( { ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20211224170007-df43bca6b6ff", Name: "github.com/aquasecurity/go-dep-parser", - Version: "0.0.0-20211224170007-df43bca6b6ff", + Version: "v0.0.0-20211224170007-df43bca6b6ff", Relationship: ftypes.RelationshipDirect, ExternalReferences: []ftypes.ExternalRef{ { @@ -297,7 +297,7 @@ var ( { ID: "gopkg.in/yaml.v3@v3.0.0-20210107192922-496545a6307b", Name: "gopkg.in/yaml.v3", - Version: "3.0.0-20210107192922-496545a6307b", + Version: "v3.0.0-20210107192922-496545a6307b", Relationship: ftypes.RelationshipIndirect, ExternalReferences: []ftypes.ExternalRef{ { @@ -324,7 +324,7 @@ var ( { ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20211224170007-df43bca6b6ff", Name: "github.com/aquasecurity/go-dep-parser", - Version: "0.0.0-20211224170007-df43bca6b6ff", + Version: "v0.0.0-20211224170007-df43bca6b6ff", Relationship: ftypes.RelationshipDirect, ExternalReferences: []ftypes.ExternalRef{ { @@ -336,13 +336,13 @@ var ( { ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", Name: "golang.org/x/xerrors", - Version: "0.0.0-20200804184101-5ec99f83aff1", + Version: "v0.0.0-20200804184101-5ec99f83aff1", Relationship: ftypes.RelationshipIndirect, }, { ID: "gopkg.in/yaml.v3@v3.0.0-20210107192922-496545a6307b", Name: "gopkg.in/yaml.v3", - Version: "3.0.0-20210107192922-496545a6307b", + Version: "v3.0.0-20210107192922-496545a6307b", Relationship: ftypes.RelationshipIndirect, ExternalReferences: []ftypes.ExternalRef{ { @@ -369,7 +369,7 @@ var ( { ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20211224170007-df43bca6b6ff", Name: "github.com/aquasecurity/go-dep-parser", - Version: "0.0.0-20211224170007-df43bca6b6ff", + Version: "v0.0.0-20211224170007-df43bca6b6ff", Relationship: ftypes.RelationshipDirect, ExternalReferences: []ftypes.ExternalRef{ { @@ -396,7 +396,7 @@ var ( { ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20211224170007-df43bca6b6ff", Name: "github.com/aquasecurity/go-dep-parser", - Version: "0.0.0-20211224170007-df43bca6b6ff", + Version: "v0.0.0-20211224170007-df43bca6b6ff", Relationship: ftypes.RelationshipDirect, ExternalReferences: []ftypes.ExternalRef{ { diff --git a/pkg/dependency/parser/golang/sum/parse.go b/pkg/dependency/parser/golang/sum/parse.go index 4ec742b1bae2..8362a808c036 100644 --- a/pkg/dependency/parser/golang/sum/parse.go +++ b/pkg/dependency/parser/golang/sum/parse.go @@ -32,7 +32,7 @@ func (p *Parser) Parse(r xio.ReadSeekerAt) ([]ftypes.Package, []ftypes.Dependenc // go.sum records and sorts all non-major versions // with the latest version as last entry - uniquePkgs[s[0]] = strings.TrimSuffix(strings.TrimPrefix(s[1], "v"), "/go.mod") + uniquePkgs[s[0]] = strings.TrimSuffix(s[1], "/go.mod") } if err := scanner.Err(); err != nil { return nil, nil, xerrors.Errorf("scan error: %w", err) diff --git a/pkg/dependency/parser/golang/sum/parse_testcase.go b/pkg/dependency/parser/golang/sum/parse_testcase.go index fc607de86e2a..532a241b1ccc 100644 --- a/pkg/dependency/parser/golang/sum/parse_testcase.go +++ b/pkg/dependency/parser/golang/sum/parse_testcase.go @@ -11,13 +11,13 @@ var ( // go get golang.org/x/xerrors // go list -m all | awk 'NR>1 {sub(/^v/, "", $2); printf("{\""$1"\", \""$2"\", },\n")}' GoModNormal = []ftypes.Package{ - {Name: "golang.org/x/xerrors", Version: "0.0.0-20200804184101-5ec99f83aff1"}, + {Name: "golang.org/x/xerrors", Version: "v0.0.0-20200804184101-5ec99f83aff1"}, } // https://github.com/uudashr/gopkgs/blob/616744904701ef01d868da4b66aad0e6856c361d/v2/go.sum GoModEmptyLine = []ftypes.Package{ - {Name: "github.com/karrick/godirwalk", Version: "1.12.0"}, - {Name: "github.com/pkg/errors", Version: "0.8.1"}, + {Name: "github.com/karrick/godirwalk", Version: "v1.12.0"}, + {Name: "github.com/pkg/errors", Version: "v0.8.1"}, } // docker run --name gomod --rm -it golang:1.15 bash @@ -31,19 +31,19 @@ var ( // go get github.com/BurntSushi/toml // go list -m all | awk 'NR>1 {sub(/^v/, "", $2); printf("{\""$1"\", \""$2"\", },\n")}' GoModMany = []ftypes.Package{ - {Name: "github.com/BurntSushi/toml", Version: "0.3.1"}, - {Name: "github.com/cpuguy83/go-md2man/v2", Version: "2.0.0-20190314233015-f79a8a8ca69d"}, - {Name: "github.com/davecgh/go-spew", Version: "1.1.0"}, - {Name: "github.com/pmezard/go-difflib", Version: "1.0.0"}, - {Name: "github.com/russross/blackfriday/v2", Version: "2.0.1"}, - {Name: "github.com/shurcooL/sanitized_anchor_name", Version: "1.0.0"}, - {Name: "github.com/stretchr/objx", Version: "0.1.0"}, - {Name: "github.com/stretchr/testify", Version: "1.7.0"}, - {Name: "github.com/urfave/cli", Version: "1.22.5"}, - {Name: "golang.org/x/xerrors", Version: "0.0.0-20200804184101-5ec99f83aff1"}, - {Name: "gopkg.in/check.v1", Version: "0.0.0-20161208181325-20d25e280405"}, - {Name: "gopkg.in/yaml.v2", Version: "2.2.2"}, - {Name: "gopkg.in/yaml.v3", Version: "3.0.0-20200313102051-9f266ea9e77c"}, + {Name: "github.com/BurntSushi/toml", Version: "v0.3.1"}, + {Name: "github.com/cpuguy83/go-md2man/v2", Version: "v2.0.0-20190314233015-f79a8a8ca69d"}, + {Name: "github.com/davecgh/go-spew", Version: "v1.1.0"}, + {Name: "github.com/pmezard/go-difflib", Version: "v1.0.0"}, + {Name: "github.com/russross/blackfriday/v2", Version: "v2.0.1"}, + {Name: "github.com/shurcooL/sanitized_anchor_name", Version: "v1.0.0"}, + {Name: "github.com/stretchr/objx", Version: "v0.1.0"}, + {Name: "github.com/stretchr/testify", Version: "v1.7.0"}, + {Name: "github.com/urfave/cli", Version: "v1.22.5"}, + {Name: "golang.org/x/xerrors", Version: "v0.0.0-20200804184101-5ec99f83aff1"}, + {Name: "gopkg.in/check.v1", Version: "v0.0.0-20161208181325-20d25e280405"}, + {Name: "gopkg.in/yaml.v2", Version: "v2.2.2"}, + {Name: "gopkg.in/yaml.v3", Version: "v3.0.0-20200313102051-9f266ea9e77c"}, } // docker run --name gomod --rm -it golang:1.15 bash @@ -54,341 +54,341 @@ var ( // go get github.com/aquasecurity/trivy // go list -m all | awk 'NR>1 {sub(/^v/, "", $2); printf("{\""$1"\", \""$2"\", },\n")}' GoModTrivy = []ftypes.Package{ - {Name: "cloud.google.com/go", Version: "0.65.0"}, - {Name: "cloud.google.com/go/bigquery", Version: "1.8.0"}, - {Name: "cloud.google.com/go/datastore", Version: "1.1.0"}, - {Name: "cloud.google.com/go/pubsub", Version: "1.3.1"}, - {Name: "cloud.google.com/go/storage", Version: "1.10.0"}, - {Name: "dmitri.shuralyov.com/gpu/mtl", Version: "0.0.0-20190408044501-666a987793e9"}, - {Name: "github.com/Azure/azure-sdk-for-go", Version: "38.0.0+incompatible"}, - {Name: "github.com/Azure/go-ansiterm", Version: "0.0.0-20170929234023-d6e3b3328b78"}, - {Name: "github.com/Azure/go-autorest/autorest", Version: "0.9.3"}, - {Name: "github.com/Azure/go-autorest/autorest/adal", Version: "0.8.1"}, - {Name: "github.com/Azure/go-autorest/autorest/date", Version: "0.2.0"}, - {Name: "github.com/Azure/go-autorest/autorest/mocks", Version: "0.3.0"}, - {Name: "github.com/Azure/go-autorest/autorest/to", Version: "0.3.0"}, - {Name: "github.com/Azure/go-autorest/autorest/validation", Version: "0.1.0"}, - {Name: "github.com/Azure/go-autorest/logger", Version: "0.1.0"}, - {Name: "github.com/Azure/go-autorest/tracing", Version: "0.5.0"}, - {Name: "github.com/BurntSushi/toml", Version: "0.3.1"}, - {Name: "github.com/BurntSushi/xgb", Version: "0.0.0-20160522181843-27f122750802"}, - {Name: "github.com/GoogleCloudPlatform/docker-credential-gcr", Version: "1.5.0"}, - {Name: "github.com/GoogleCloudPlatform/k8s-cloud-provider", Version: "0.0.0-20190822182118-27a4ced34534"}, - {Name: "github.com/Microsoft/go-winio", Version: "0.4.15-0.20190919025122-fc70bd9a86b5"}, - {Name: "github.com/Microsoft/hcsshim", Version: "0.8.6"}, - {Name: "github.com/NYTimes/gziphandler", Version: "0.0.0-20170623195520-56545f4a5d46"}, - {Name: "github.com/OneOfOne/xxhash", Version: "1.2.7"}, - {Name: "github.com/PuerkitoBio/purell", Version: "1.1.1"}, - {Name: "github.com/PuerkitoBio/urlesc", Version: "0.0.0-20170810143723-de5bf2ad4578"}, - {Name: "github.com/VividCortex/ewma", Version: "1.1.1"}, - {Name: "github.com/alcortesm/tgz", Version: "0.0.0-20161220082320-9c5fe88206d7"}, - {Name: "github.com/alecthomas/template", Version: "0.0.0-20160405071501-a0175ee3bccc"}, - {Name: "github.com/alecthomas/units", Version: "0.0.0-20151022065526-2efee857e7cf"}, - {Name: "github.com/alicebob/gopher-json", Version: "0.0.0-20200520072559-a9ecdc9d1d3a"}, - {Name: "github.com/alicebob/miniredis/v2", Version: "2.14.1"}, - {Name: "github.com/anmitsu/go-shlex", Version: "0.0.0-20161002113705-648efa622239"}, - {Name: "github.com/aquasecurity/bolt-fixtures", Version: "0.0.0-20200903104109-d34e7f983986"}, - {Name: "github.com/aquasecurity/fanal", Version: "0.0.0-20210119051230-28c249da7cfd"}, - {Name: "github.com/aquasecurity/go-dep-parser", Version: "0.0.0-20201028043324-889d4a92b8e0"}, - {Name: "github.com/aquasecurity/go-gem-version", Version: "0.0.0-20201115065557-8eed6fe000ce"}, - {Name: "github.com/aquasecurity/go-npm-version", Version: "0.0.0-20201110091526-0b796d180798"}, - {Name: "github.com/aquasecurity/go-pep440-version", Version: "0.0.0-20210121094942-22b2f8951d46"}, - {Name: "github.com/aquasecurity/go-version", Version: "0.0.0-20210121072130-637058cfe492"}, - {Name: "github.com/aquasecurity/testdocker", Version: "0.0.0-20210106133225-0b17fe083674"}, - {Name: "github.com/aquasecurity/trivy", Version: "0.16.0"}, - {Name: "github.com/aquasecurity/trivy-db", Version: "0.0.0-20210105160501-c5bf4e153277"}, - {Name: "github.com/aquasecurity/vuln-list-update", Version: "0.0.0-20191016075347-3d158c2bf9a2"}, - {Name: "github.com/araddon/dateparse", Version: "0.0.0-20190426192744-0d74ffceef83"}, - {Name: "github.com/armon/consul-api", Version: "0.0.0-20180202201655-eb2c6b5be1b6"}, - {Name: "github.com/armon/go-socks5", Version: "0.0.0-20160902184237-e75332964ef5"}, - {Name: "github.com/aws/aws-sdk-go", Version: "1.27.1"}, - {Name: "github.com/beorn7/perks", Version: "1.0.0"}, - {Name: "github.com/bgentry/speakeasy", Version: "0.1.0"}, - {Name: "github.com/blang/semver", Version: "3.5.0+incompatible"}, - {Name: "github.com/briandowns/spinner", Version: "1.12.0"}, - {Name: "github.com/caarlos0/env/v6", Version: "6.0.0"}, - {Name: "github.com/cenkalti/backoff", Version: "2.2.1+incompatible"}, - {Name: "github.com/census-instrumentation/opencensus-proto", Version: "0.2.1"}, - {Name: "github.com/cespare/xxhash/v2", Version: "2.1.1"}, - {Name: "github.com/cheggaaa/pb/v3", Version: "3.0.3"}, - {Name: "github.com/chzyer/logex", Version: "1.1.10"}, - {Name: "github.com/chzyer/readline", Version: "0.0.0-20180603132655-2972be24d48e"}, - {Name: "github.com/chzyer/test", Version: "0.0.0-20180213035817-a1ea475d72b1"}, - {Name: "github.com/client9/misspell", Version: "0.3.4"}, - {Name: "github.com/cncf/udpa/go", Version: "0.0.0-20191209042840-269d4d468f6f"}, - {Name: "github.com/cockroachdb/datadriven", Version: "0.0.0-20190809214429-80d97fb3cbaa"}, - {Name: "github.com/containerd/containerd", Version: "1.3.3"}, - {Name: "github.com/containerd/continuity", Version: "0.0.0-20190426062206-aaeac12a7ffc"}, - {Name: "github.com/coreos/etcd", Version: "3.3.10+incompatible"}, - {Name: "github.com/coreos/go-etcd", Version: "2.0.0+incompatible"}, - {Name: "github.com/coreos/go-oidc", Version: "2.1.0+incompatible"}, - {Name: "github.com/coreos/go-semver", Version: "0.3.0"}, - {Name: "github.com/coreos/go-systemd", Version: "0.0.0-20190321100706-95778dfbb74e"}, - {Name: "github.com/coreos/pkg", Version: "0.0.0-20180108230652-97fdf19511ea"}, - {Name: "github.com/cpuguy83/go-md2man", Version: "1.0.10"}, - {Name: "github.com/cpuguy83/go-md2man/v2", Version: "2.0.0"}, - {Name: "github.com/creack/pty", Version: "1.1.9"}, - {Name: "github.com/davecgh/go-spew", Version: "1.1.1"}, - {Name: "github.com/deckarep/golang-set", Version: "1.7.1"}, - {Name: "github.com/dgrijalva/jwt-go", Version: "3.2.0+incompatible"}, - {Name: "github.com/dgryski/go-rendezvous", Version: "0.0.0-20200823014737-9f7001d12a5f"}, - {Name: "github.com/dnaeon/go-vcr", Version: "1.0.1"}, - {Name: "github.com/docker/cli", Version: "0.0.0-20191017083524-a8ff7f821017"}, - {Name: "github.com/docker/distribution", Version: "2.7.1+incompatible"}, - {Name: "github.com/docker/docker", Version: "1.4.2-0.20190924003213-a8608b5b67c7"}, - {Name: "github.com/docker/docker-credential-helpers", Version: "0.6.3"}, - {Name: "github.com/docker/go-connections", Version: "0.4.0"}, - {Name: "github.com/docker/go-units", Version: "0.4.0"}, - {Name: "github.com/docker/spdystream", Version: "0.0.0-20160310174837-449fdfce4d96"}, - {Name: "github.com/dustin/go-humanize", Version: "1.0.0"}, - {Name: "github.com/elazarl/goproxy", Version: "0.0.0-20200809112317-0581fc3aee2d"}, - {Name: "github.com/elazarl/goproxy/ext", Version: "0.0.0-20200809112317-0581fc3aee2d"}, - {Name: "github.com/emicklei/go-restful", Version: "2.9.5+incompatible"}, - {Name: "github.com/emirpasic/gods", Version: "1.12.0"}, - {Name: "github.com/envoyproxy/go-control-plane", Version: "0.9.4"}, - {Name: "github.com/envoyproxy/protoc-gen-validate", Version: "0.1.0"}, - {Name: "github.com/evanphx/json-patch", Version: "4.2.0+incompatible"}, - {Name: "github.com/fatih/color", Version: "1.10.0"}, - {Name: "github.com/flynn/go-shlex", Version: "0.0.0-20150515145356-3f9db97f8568"}, - {Name: "github.com/fsnotify/fsnotify", Version: "1.4.9"}, - {Name: "github.com/ghodss/yaml", Version: "1.0.0"}, - {Name: "github.com/gin-contrib/sse", Version: "0.1.0"}, - {Name: "github.com/gin-gonic/gin", Version: "1.5.0"}, - {Name: "github.com/gliderlabs/ssh", Version: "0.2.2"}, - {Name: "github.com/go-git/gcfg", Version: "1.5.0"}, - {Name: "github.com/go-git/go-billy/v5", Version: "5.0.0"}, - {Name: "github.com/go-git/go-git-fixtures/v4", Version: "4.0.1"}, - {Name: "github.com/go-git/go-git/v5", Version: "5.0.0"}, - {Name: "github.com/go-gl/glfw", Version: "0.0.0-20190409004039-e6da0acd62b1"}, - {Name: "github.com/go-gl/glfw/v3.3/glfw", Version: "0.0.0-20200222043503-6f7a984d4dc4"}, - {Name: "github.com/go-kit/kit", Version: "0.8.0"}, - {Name: "github.com/go-logfmt/logfmt", Version: "0.3.0"}, - {Name: "github.com/go-logr/logr", Version: "0.1.0"}, - {Name: "github.com/go-openapi/jsonpointer", Version: "0.19.3"}, - {Name: "github.com/go-openapi/jsonreference", Version: "0.19.3"}, - {Name: "github.com/go-openapi/spec", Version: "0.19.3"}, - {Name: "github.com/go-openapi/swag", Version: "0.19.5"}, - {Name: "github.com/go-playground/locales", Version: "0.13.0"}, - {Name: "github.com/go-playground/universal-translator", Version: "0.17.0"}, - {Name: "github.com/go-redis/redis", Version: "6.15.7+incompatible"}, - {Name: "github.com/go-redis/redis/v8", Version: "8.4.0"}, - {Name: "github.com/go-restruct/restruct", Version: "0.0.0-20191227155143-5734170a48a1"}, - {Name: "github.com/go-sql-driver/mysql", Version: "1.5.0"}, - {Name: "github.com/go-stack/stack", Version: "1.8.0"}, - {Name: "github.com/gobwas/glob", Version: "0.2.3"}, - {Name: "github.com/goccy/go-yaml", Version: "1.8.2"}, - {Name: "github.com/gogo/protobuf", Version: "1.3.1"}, - {Name: "github.com/golang/glog", Version: "0.0.0-20160126235308-23def4e6c14b"}, - {Name: "github.com/golang/groupcache", Version: "0.0.0-20200121045136-8c9f03a8e57e"}, - {Name: "github.com/golang/mock", Version: "1.4.4"}, - {Name: "github.com/golang/protobuf", Version: "1.4.2"}, - {Name: "github.com/google/btree", Version: "1.0.0"}, - {Name: "github.com/google/go-cmp", Version: "0.5.3"}, - {Name: "github.com/google/go-containerregistry", Version: "0.0.0-20200331213917-3d03ed9b1ca2"}, - {Name: "github.com/google/go-github/v28", Version: "28.1.1"}, - {Name: "github.com/google/go-querystring", Version: "1.0.0"}, - {Name: "github.com/google/gofuzz", Version: "1.0.0"}, - {Name: "github.com/google/martian", Version: "2.1.0+incompatible"}, - {Name: "github.com/google/martian/v3", Version: "3.0.0"}, - {Name: "github.com/google/pprof", Version: "0.0.0-20200708004538-1a94d8640e99"}, - {Name: "github.com/google/renameio", Version: "0.1.0"}, - {Name: "github.com/google/subcommands", Version: "1.0.1"}, - {Name: "github.com/google/uuid", Version: "1.1.1"}, - {Name: "github.com/google/wire", Version: "0.3.0"}, - {Name: "github.com/googleapis/gax-go/v2", Version: "2.0.5"}, - {Name: "github.com/googleapis/gnostic", Version: "0.2.2"}, - {Name: "github.com/gophercloud/gophercloud", Version: "0.1.0"}, - {Name: "github.com/gopherjs/gopherjs", Version: "0.0.0-20200217142428-fce0ec30dd00"}, - {Name: "github.com/gorilla/context", Version: "1.1.1"}, - {Name: "github.com/gorilla/mux", Version: "1.7.4"}, - {Name: "github.com/gorilla/websocket", Version: "1.4.0"}, - {Name: "github.com/gregjones/httpcache", Version: "0.0.0-20180305231024-9cad4c3443a7"}, - {Name: "github.com/grpc-ecosystem/go-grpc-middleware", Version: "1.0.1-0.20190118093823-f849b5445de4"}, - {Name: "github.com/grpc-ecosystem/go-grpc-prometheus", Version: "1.2.0"}, - {Name: "github.com/grpc-ecosystem/grpc-gateway", Version: "1.9.5"}, - {Name: "github.com/hashicorp/errwrap", Version: "1.0.0"}, - {Name: "github.com/hashicorp/go-multierror", Version: "1.1.0"}, - {Name: "github.com/hashicorp/go-version", Version: "1.2.1"}, - {Name: "github.com/hashicorp/golang-lru", Version: "0.5.3"}, - {Name: "github.com/hashicorp/hcl", Version: "1.0.0"}, - {Name: "github.com/hpcloud/tail", Version: "1.0.0"}, - {Name: "github.com/ianlancetaylor/demangle", Version: "0.0.0-20181102032728-5e5cf60278f6"}, - {Name: "github.com/imdario/mergo", Version: "0.3.5"}, - {Name: "github.com/inconshreveable/mousetrap", Version: "1.0.0"}, - {Name: "github.com/jbenet/go-context", Version: "0.0.0-20150711004518-d14ea06fba99"}, - {Name: "github.com/jessevdk/go-flags", Version: "1.4.0"}, - {Name: "github.com/jmespath/go-jmespath", Version: "0.0.0-20180206201540-c2b33e8439af"}, - {Name: "github.com/joefitzgerald/rainbow-reporter", Version: "0.1.0"}, - {Name: "github.com/jonboulle/clockwork", Version: "0.1.0"}, - {Name: "github.com/json-iterator/go", Version: "1.1.8"}, - {Name: "github.com/jstemmer/go-junit-report", Version: "0.9.1"}, - {Name: "github.com/jtolds/gls", Version: "4.20.0+incompatible"}, - {Name: "github.com/julienschmidt/httprouter", Version: "1.2.0"}, - {Name: "github.com/kevinburke/ssh_config", Version: "0.0.0-20190725054713-01f96b0aa0cd"}, - {Name: "github.com/kisielk/errcheck", Version: "1.2.0"}, - {Name: "github.com/kisielk/gotool", Version: "1.0.0"}, - {Name: "github.com/knqyf263/go-apk-version", Version: "0.0.0-20200609155635-041fdbb8563f"}, - {Name: "github.com/knqyf263/go-deb-version", Version: "0.0.0-20190517075300-09fca494f03d"}, - {Name: "github.com/knqyf263/go-rpm-version", Version: "0.0.0-20170716094938-74609b86c936"}, - {Name: "github.com/knqyf263/go-rpmdb", Version: "0.0.0-20201215100354-a9e3110d8ee1"}, - {Name: "github.com/knqyf263/nested", Version: "0.0.1"}, - {Name: "github.com/konsorten/go-windows-terminal-sequences", Version: "1.0.2"}, - {Name: "github.com/kr/logfmt", Version: "0.0.0-20140226030751-b84e30acd515"}, - {Name: "github.com/kr/pretty", Version: "0.1.0"}, - {Name: "github.com/kr/pty", Version: "1.1.5"}, - {Name: "github.com/kr/text", Version: "0.2.0"}, - {Name: "github.com/kylelemons/godebug", Version: "1.1.0"}, - {Name: "github.com/leodido/go-urn", Version: "1.2.0"}, - {Name: "github.com/magiconair/properties", Version: "1.8.0"}, - {Name: "github.com/mailru/easyjson", Version: "0.7.0"}, - {Name: "github.com/mattn/go-colorable", Version: "0.1.8"}, - {Name: "github.com/mattn/go-isatty", Version: "0.0.12"}, - {Name: "github.com/mattn/go-jsonpointer", Version: "0.0.0-20180225143300-37667080efed"}, - {Name: "github.com/mattn/go-runewidth", Version: "0.0.9"}, - {Name: "github.com/matttproud/golang_protobuf_extensions", Version: "1.0.1"}, - {Name: "github.com/maxbrunsfeld/counterfeiter/v6", Version: "6.2.2"}, - {Name: "github.com/mitchellh/go-homedir", Version: "1.1.0"}, - {Name: "github.com/mitchellh/mapstructure", Version: "1.1.2"}, - {Name: "github.com/modern-go/concurrent", Version: "0.0.0-20180306012644-bacd9c7ef1dd"}, - {Name: "github.com/modern-go/reflect2", Version: "1.0.1"}, - {Name: "github.com/morikuni/aec", Version: "1.0.0"}, - {Name: "github.com/munnerz/goautoneg", Version: "0.0.0-20191010083416-a7dc8b61c822"}, - {Name: "github.com/mwitkow/go-conntrack", Version: "0.0.0-20161129095857-cc309e4a2223"}, - {Name: "github.com/mxk/go-flowrate", Version: "0.0.0-20140419014527-cca7078d478f"}, - {Name: "github.com/niemeyer/pretty", Version: "0.0.0-20200227124842-a10e7caefd8e"}, - {Name: "github.com/nxadm/tail", Version: "1.4.4"}, - {Name: "github.com/olekukonko/tablewriter", Version: "0.0.2-0.20190607075207-195002e6e56a"}, - {Name: "github.com/onsi/ginkgo", Version: "1.14.2"}, - {Name: "github.com/onsi/gomega", Version: "1.10.3"}, - {Name: "github.com/open-policy-agent/opa", Version: "0.21.1"}, - {Name: "github.com/opencontainers/go-digest", Version: "1.0.0-rc1"}, - {Name: "github.com/opencontainers/image-spec", Version: "1.0.2-0.20190823105129-775207bd45b6"}, - {Name: "github.com/opencontainers/runc", Version: "0.1.1"}, - {Name: "github.com/parnurzeal/gorequest", Version: "0.2.16"}, - {Name: "github.com/pelletier/go-toml", Version: "1.2.0"}, - {Name: "github.com/peterbourgon/diskv", Version: "2.0.1+incompatible"}, - {Name: "github.com/peterh/liner", Version: "0.0.0-20170211195444-bf27d3ba8e1d"}, - {Name: "github.com/pkg/errors", Version: "0.9.1"}, - {Name: "github.com/pmezard/go-difflib", Version: "1.0.0"}, - {Name: "github.com/pquerna/cachecontrol", Version: "0.0.0-20171018203845-0dec1b30a021"}, - {Name: "github.com/prometheus/client_golang", Version: "1.0.0"}, - {Name: "github.com/prometheus/client_model", Version: "0.0.0-20190812154241-14fe0d1b01d4"}, - {Name: "github.com/prometheus/common", Version: "0.4.1"}, - {Name: "github.com/prometheus/procfs", Version: "0.0.2"}, - {Name: "github.com/rcrowley/go-metrics", Version: "0.0.0-20181016184325-3113b8401b8a"}, - {Name: "github.com/remyoudompheng/bigfft", Version: "0.0.0-20170806203942-52369c62f446"}, - {Name: "github.com/rogpeppe/fastuuid", Version: "0.0.0-20150106093220-6724a57986af"}, - {Name: "github.com/rogpeppe/go-charset", Version: "0.0.0-20180617210344-2471d30d28b4"}, - {Name: "github.com/rogpeppe/go-internal", Version: "1.3.0"}, - {Name: "github.com/rubiojr/go-vhd", Version: "0.0.0-20160810183302-0bfd3b39853c"}, - {Name: "github.com/russross/blackfriday", Version: "1.5.2"}, - {Name: "github.com/russross/blackfriday/v2", Version: "2.0.1"}, - {Name: "github.com/saracen/walker", Version: "0.0.0-20191201085201-324a081bae7e"}, - {Name: "github.com/satori/go.uuid", Version: "1.2.0"}, - {Name: "github.com/sclevine/spec", Version: "1.2.0"}, - {Name: "github.com/sergi/go-diff", Version: "1.1.0"}, - {Name: "github.com/shurcooL/sanitized_anchor_name", Version: "1.0.0"}, - {Name: "github.com/simplereach/timeutils", Version: "1.2.0"}, - {Name: "github.com/sirupsen/logrus", Version: "1.5.0"}, - {Name: "github.com/smartystreets/assertions", Version: "1.2.0"}, - {Name: "github.com/smartystreets/goconvey", Version: "1.6.4"}, - {Name: "github.com/soheilhy/cmux", Version: "0.1.4"}, - {Name: "github.com/sosedoff/gitkit", Version: "0.2.0"}, - {Name: "github.com/spf13/afero", Version: "1.2.2"}, - {Name: "github.com/spf13/cast", Version: "1.3.0"}, - {Name: "github.com/spf13/cobra", Version: "0.0.5"}, - {Name: "github.com/spf13/jwalterweatherman", Version: "1.0.0"}, - {Name: "github.com/spf13/pflag", Version: "1.0.5"}, - {Name: "github.com/spf13/viper", Version: "1.3.2"}, - {Name: "github.com/stretchr/objx", Version: "0.3.0"}, - {Name: "github.com/stretchr/testify", Version: "1.6.1"}, - {Name: "github.com/testcontainers/testcontainers-go", Version: "0.3.1"}, - {Name: "github.com/tmc/grpc-websocket-proxy", Version: "0.0.0-20170815181823-89b8d40f7ca8"}, - {Name: "github.com/twitchtv/twirp", Version: "5.10.1+incompatible"}, - {Name: "github.com/ugorji/go", Version: "1.1.7"}, - {Name: "github.com/ugorji/go/codec", Version: "1.1.7"}, - {Name: "github.com/urfave/cli", Version: "1.22.5"}, - {Name: "github.com/urfave/cli/v2", Version: "2.3.0"}, - {Name: "github.com/vdemeester/k8s-pkg-credentialprovider", Version: "1.17.4"}, - {Name: "github.com/vmware/govmomi", Version: "0.20.3"}, - {Name: "github.com/xanzy/ssh-agent", Version: "0.2.1"}, - {Name: "github.com/xiang90/probing", Version: "0.0.0-20190116061207-43a291ad63a2"}, - {Name: "github.com/xordataexchange/crypt", Version: "0.0.3-0.20170626215501-b2862e3d0a77"}, - {Name: "github.com/yashtewari/glob-intersection", Version: "0.0.0-20180916065949-5c77d914dd0b"}, - {Name: "github.com/yuin/goldmark", Version: "1.1.32"}, - {Name: "github.com/yuin/gopher-lua", Version: "0.0.0-20191220021717-ab39c6098bdb"}, - {Name: "go.etcd.io/bbolt", Version: "1.3.5"}, - {Name: "go.etcd.io/etcd", Version: "0.0.0-20191023171146-3cf2f69b5738"}, - {Name: "go.opencensus.io", Version: "0.22.4"}, - {Name: "go.opentelemetry.io/otel", Version: "0.14.0"}, - {Name: "go.uber.org/atomic", Version: "1.5.1"}, - {Name: "go.uber.org/multierr", Version: "1.4.0"}, - {Name: "go.uber.org/tools", Version: "0.0.0-20190618225709-2cfd321de3ee"}, - {Name: "go.uber.org/zap", Version: "1.13.0"}, - {Name: "golang.org/x/crypto", Version: "0.0.0-20201002170205-7f63de1d35b0"}, - {Name: "golang.org/x/exp", Version: "0.0.0-20200224162631-6cc2880d07d6"}, - {Name: "golang.org/x/image", Version: "0.0.0-20190802002840-cff245a6509b"}, - {Name: "golang.org/x/lint", Version: "0.0.0-20200302205851-738671d3881b"}, - {Name: "golang.org/x/mobile", Version: "0.0.0-20190719004257-d2bd2a29d028"}, - {Name: "golang.org/x/mod", Version: "0.3.0"}, - {Name: "golang.org/x/net", Version: "0.0.0-20201006153459-a7d1128ccaa0"}, - {Name: "golang.org/x/oauth2", Version: "0.0.0-20201208152858-08078c50e5b5"}, - {Name: "golang.org/x/sync", Version: "0.0.0-20200625203802-6e8e738ad208"}, - {Name: "golang.org/x/sys", Version: "0.0.0-20201006155630-ac719f4daadf"}, - {Name: "golang.org/x/text", Version: "0.3.3"}, - {Name: "golang.org/x/time", Version: "0.0.0-20191024005414-555d28b269f0"}, - {Name: "golang.org/x/tools", Version: "0.0.0-20200825202427-b303f430e36d"}, - {Name: "golang.org/x/xerrors", Version: "0.0.0-20200804184101-5ec99f83aff1"}, - {Name: "gonum.org/v1/gonum", Version: "0.0.0-20190331200053-3d26580ed485"}, - {Name: "gonum.org/v1/netlib", Version: "0.0.0-20190331212654-76723241ea4e"}, - {Name: "google.golang.org/api", Version: "0.30.0"}, - {Name: "google.golang.org/appengine", Version: "1.6.6"}, - {Name: "google.golang.org/genproto", Version: "0.0.0-20200825200019-8632dd797987"}, - {Name: "google.golang.org/grpc", Version: "1.31.0"}, - {Name: "google.golang.org/protobuf", Version: "1.25.0"}, - {Name: "gopkg.in/alecthomas/kingpin.v2", Version: "2.2.6"}, - {Name: "gopkg.in/check.v1", Version: "1.0.0-20200902074654-038fdea0a05b"}, - {Name: "gopkg.in/cheggaaa/pb.v1", Version: "1.0.28"}, - {Name: "gopkg.in/errgo.v2", Version: "2.1.0"}, - {Name: "gopkg.in/fsnotify.v1", Version: "1.4.7"}, - {Name: "gopkg.in/gcfg.v1", Version: "1.2.0"}, - {Name: "gopkg.in/go-playground/assert.v1", Version: "1.2.1"}, - {Name: "gopkg.in/go-playground/validator.v9", Version: "9.31.0"}, - {Name: "gopkg.in/inf.v0", Version: "0.9.1"}, - {Name: "gopkg.in/mgo.v2", Version: "2.0.0-20180705113604-9856a29383ce"}, - {Name: "gopkg.in/natefinch/lumberjack.v2", Version: "2.0.0"}, - {Name: "gopkg.in/resty.v1", Version: "1.12.0"}, - {Name: "gopkg.in/square/go-jose.v2", Version: "2.2.2"}, - {Name: "gopkg.in/tomb.v1", Version: "1.0.0-20141024135613-dd632973f1e7"}, - {Name: "gopkg.in/warnings.v0", Version: "0.1.2"}, - {Name: "gopkg.in/yaml.v2", Version: "2.4.0"}, - {Name: "gopkg.in/yaml.v3", Version: "3.0.0-20200615113413-eeeca48fe776"}, - {Name: "gotest.tools", Version: "2.2.0+incompatible"}, - {Name: "honnef.co/go/tools", Version: "0.0.1-2020.1.4"}, - {Name: "k8s.io/api", Version: "0.17.4"}, - {Name: "k8s.io/apimachinery", Version: "0.17.4"}, - {Name: "k8s.io/apiserver", Version: "0.17.4"}, - {Name: "k8s.io/client-go", Version: "0.17.4"}, - {Name: "k8s.io/cloud-provider", Version: "0.17.4"}, - {Name: "k8s.io/code-generator", Version: "0.17.2"}, - {Name: "k8s.io/component-base", Version: "0.17.4"}, - {Name: "k8s.io/csi-translation-lib", Version: "0.17.4"}, - {Name: "k8s.io/gengo", Version: "0.0.0-20190822140433-26a664648505"}, - {Name: "k8s.io/klog", Version: "1.0.0"}, - {Name: "k8s.io/klog/v2", Version: "2.0.0"}, - {Name: "k8s.io/kube-openapi", Version: "0.0.0-20191107075043-30be4d16710a"}, - {Name: "k8s.io/legacy-cloud-providers", Version: "0.17.4"}, - {Name: "k8s.io/utils", Version: "0.0.0-20201110183641-67b214c5f920"}, - {Name: "modernc.org/cc", Version: "1.0.0"}, - {Name: "modernc.org/golex", Version: "1.0.0"}, - {Name: "modernc.org/mathutil", Version: "1.0.0"}, - {Name: "modernc.org/strutil", Version: "1.0.0"}, - {Name: "modernc.org/xc", Version: "1.0.0"}, - {Name: "moul.io/http2curl", Version: "1.0.0"}, - {Name: "rsc.io/binaryregexp", Version: "0.2.0"}, - {Name: "rsc.io/quote/v3", Version: "3.1.0"}, - {Name: "rsc.io/sampler", Version: "1.3.0"}, - {Name: "sigs.k8s.io/structured-merge-diff", Version: "1.0.1-0.20191108220359-b1b620dd3f06"}, - {Name: "sigs.k8s.io/yaml", Version: "1.1.0"}, + {Name: "cloud.google.com/go", Version: "v0.65.0"}, + {Name: "cloud.google.com/go/bigquery", Version: "v1.8.0"}, + {Name: "cloud.google.com/go/datastore", Version: "v1.1.0"}, + {Name: "cloud.google.com/go/pubsub", Version: "v1.3.1"}, + {Name: "cloud.google.com/go/storage", Version: "v1.10.0"}, + {Name: "dmitri.shuralyov.com/gpu/mtl", Version: "v0.0.0-20190408044501-666a987793e9"}, + {Name: "github.com/Azure/azure-sdk-for-go", Version: "v38.0.0+incompatible"}, + {Name: "github.com/Azure/go-ansiterm", Version: "v0.0.0-20170929234023-d6e3b3328b78"}, + {Name: "github.com/Azure/go-autorest/autorest", Version: "v0.9.3"}, + {Name: "github.com/Azure/go-autorest/autorest/adal", Version: "v0.8.1"}, + {Name: "github.com/Azure/go-autorest/autorest/date", Version: "v0.2.0"}, + {Name: "github.com/Azure/go-autorest/autorest/mocks", Version: "v0.3.0"}, + {Name: "github.com/Azure/go-autorest/autorest/to", Version: "v0.3.0"}, + {Name: "github.com/Azure/go-autorest/autorest/validation", Version: "v0.1.0"}, + {Name: "github.com/Azure/go-autorest/logger", Version: "v0.1.0"}, + {Name: "github.com/Azure/go-autorest/tracing", Version: "v0.5.0"}, + {Name: "github.com/BurntSushi/toml", Version: "v0.3.1"}, + {Name: "github.com/BurntSushi/xgb", Version: "v0.0.0-20160522181843-27f122750802"}, + {Name: "github.com/GoogleCloudPlatform/docker-credential-gcr", Version: "v1.5.0"}, + {Name: "github.com/GoogleCloudPlatform/k8s-cloud-provider", Version: "v0.0.0-20190822182118-27a4ced34534"}, + {Name: "github.com/Microsoft/go-winio", Version: "v0.4.15-0.20190919025122-fc70bd9a86b5"}, + {Name: "github.com/Microsoft/hcsshim", Version: "v0.8.6"}, + {Name: "github.com/NYTimes/gziphandler", Version: "v0.0.0-20170623195520-56545f4a5d46"}, + {Name: "github.com/OneOfOne/xxhash", Version: "v1.2.7"}, + {Name: "github.com/PuerkitoBio/purell", Version: "v1.1.1"}, + {Name: "github.com/PuerkitoBio/urlesc", Version: "v0.0.0-20170810143723-de5bf2ad4578"}, + {Name: "github.com/VividCortex/ewma", Version: "v1.1.1"}, + {Name: "github.com/alcortesm/tgz", Version: "v0.0.0-20161220082320-9c5fe88206d7"}, + {Name: "github.com/alecthomas/template", Version: "v0.0.0-20160405071501-a0175ee3bccc"}, + {Name: "github.com/alecthomas/units", Version: "v0.0.0-20151022065526-2efee857e7cf"}, + {Name: "github.com/alicebob/gopher-json", Version: "v0.0.0-20200520072559-a9ecdc9d1d3a"}, + {Name: "github.com/alicebob/miniredis/v2", Version: "v2.14.1"}, + {Name: "github.com/anmitsu/go-shlex", Version: "v0.0.0-20161002113705-648efa622239"}, + {Name: "github.com/aquasecurity/bolt-fixtures", Version: "v0.0.0-20200903104109-d34e7f983986"}, + {Name: "github.com/aquasecurity/fanal", Version: "v0.0.0-20210119051230-28c249da7cfd"}, + {Name: "github.com/aquasecurity/go-dep-parser", Version: "v0.0.0-20201028043324-889d4a92b8e0"}, + {Name: "github.com/aquasecurity/go-gem-version", Version: "v0.0.0-20201115065557-8eed6fe000ce"}, + {Name: "github.com/aquasecurity/go-npm-version", Version: "v0.0.0-20201110091526-0b796d180798"}, + {Name: "github.com/aquasecurity/go-pep440-version", Version: "v0.0.0-20210121094942-22b2f8951d46"}, + {Name: "github.com/aquasecurity/go-version", Version: "v0.0.0-20210121072130-637058cfe492"}, + {Name: "github.com/aquasecurity/testdocker", Version: "v0.0.0-20210106133225-0b17fe083674"}, + {Name: "github.com/aquasecurity/trivy", Version: "v0.16.0"}, + {Name: "github.com/aquasecurity/trivy-db", Version: "v0.0.0-20210105160501-c5bf4e153277"}, + {Name: "github.com/aquasecurity/vuln-list-update", Version: "v0.0.0-20191016075347-3d158c2bf9a2"}, + {Name: "github.com/araddon/dateparse", Version: "v0.0.0-20190426192744-0d74ffceef83"}, + {Name: "github.com/armon/consul-api", Version: "v0.0.0-20180202201655-eb2c6b5be1b6"}, + {Name: "github.com/armon/go-socks5", Version: "v0.0.0-20160902184237-e75332964ef5"}, + {Name: "github.com/aws/aws-sdk-go", Version: "v1.27.1"}, + {Name: "github.com/beorn7/perks", Version: "v1.0.0"}, + {Name: "github.com/bgentry/speakeasy", Version: "v0.1.0"}, + {Name: "github.com/blang/semver", Version: "v3.5.0+incompatible"}, + {Name: "github.com/briandowns/spinner", Version: "v1.12.0"}, + {Name: "github.com/caarlos0/env/v6", Version: "v6.0.0"}, + {Name: "github.com/cenkalti/backoff", Version: "v2.2.1+incompatible"}, + {Name: "github.com/census-instrumentation/opencensus-proto", Version: "v0.2.1"}, + {Name: "github.com/cespare/xxhash/v2", Version: "v2.1.1"}, + {Name: "github.com/cheggaaa/pb/v3", Version: "v3.0.3"}, + {Name: "github.com/chzyer/logex", Version: "v1.1.10"}, + {Name: "github.com/chzyer/readline", Version: "v0.0.0-20180603132655-2972be24d48e"}, + {Name: "github.com/chzyer/test", Version: "v0.0.0-20180213035817-a1ea475d72b1"}, + {Name: "github.com/client9/misspell", Version: "v0.3.4"}, + {Name: "github.com/cncf/udpa/go", Version: "v0.0.0-20191209042840-269d4d468f6f"}, + {Name: "github.com/cockroachdb/datadriven", Version: "v0.0.0-20190809214429-80d97fb3cbaa"}, + {Name: "github.com/containerd/containerd", Version: "v1.3.3"}, + {Name: "github.com/containerd/continuity", Version: "v0.0.0-20190426062206-aaeac12a7ffc"}, + {Name: "github.com/coreos/etcd", Version: "v3.3.10+incompatible"}, + {Name: "github.com/coreos/go-etcd", Version: "v2.0.0+incompatible"}, + {Name: "github.com/coreos/go-oidc", Version: "v2.1.0+incompatible"}, + {Name: "github.com/coreos/go-semver", Version: "v0.3.0"}, + {Name: "github.com/coreos/go-systemd", Version: "v0.0.0-20190321100706-95778dfbb74e"}, + {Name: "github.com/coreos/pkg", Version: "v0.0.0-20180108230652-97fdf19511ea"}, + {Name: "github.com/cpuguy83/go-md2man", Version: "v1.0.10"}, + {Name: "github.com/cpuguy83/go-md2man/v2", Version: "v2.0.0"}, + {Name: "github.com/creack/pty", Version: "v1.1.9"}, + {Name: "github.com/davecgh/go-spew", Version: "v1.1.1"}, + {Name: "github.com/deckarep/golang-set", Version: "v1.7.1"}, + {Name: "github.com/dgrijalva/jwt-go", Version: "v3.2.0+incompatible"}, + {Name: "github.com/dgryski/go-rendezvous", Version: "v0.0.0-20200823014737-9f7001d12a5f"}, + {Name: "github.com/dnaeon/go-vcr", Version: "v1.0.1"}, + {Name: "github.com/docker/cli", Version: "v0.0.0-20191017083524-a8ff7f821017"}, + {Name: "github.com/docker/distribution", Version: "v2.7.1+incompatible"}, + {Name: "github.com/docker/docker", Version: "v1.4.2-0.20190924003213-a8608b5b67c7"}, + {Name: "github.com/docker/docker-credential-helpers", Version: "v0.6.3"}, + {Name: "github.com/docker/go-connections", Version: "v0.4.0"}, + {Name: "github.com/docker/go-units", Version: "v0.4.0"}, + {Name: "github.com/docker/spdystream", Version: "v0.0.0-20160310174837-449fdfce4d96"}, + {Name: "github.com/dustin/go-humanize", Version: "v1.0.0"}, + {Name: "github.com/elazarl/goproxy", Version: "v0.0.0-20200809112317-0581fc3aee2d"}, + {Name: "github.com/elazarl/goproxy/ext", Version: "v0.0.0-20200809112317-0581fc3aee2d"}, + {Name: "github.com/emicklei/go-restful", Version: "v2.9.5+incompatible"}, + {Name: "github.com/emirpasic/gods", Version: "v1.12.0"}, + {Name: "github.com/envoyproxy/go-control-plane", Version: "v0.9.4"}, + {Name: "github.com/envoyproxy/protoc-gen-validate", Version: "v0.1.0"}, + {Name: "github.com/evanphx/json-patch", Version: "v4.2.0+incompatible"}, + {Name: "github.com/fatih/color", Version: "v1.10.0"}, + {Name: "github.com/flynn/go-shlex", Version: "v0.0.0-20150515145356-3f9db97f8568"}, + {Name: "github.com/fsnotify/fsnotify", Version: "v1.4.9"}, + {Name: "github.com/ghodss/yaml", Version: "v1.0.0"}, + {Name: "github.com/gin-contrib/sse", Version: "v0.1.0"}, + {Name: "github.com/gin-gonic/gin", Version: "v1.5.0"}, + {Name: "github.com/gliderlabs/ssh", Version: "v0.2.2"}, + {Name: "github.com/go-git/gcfg", Version: "v1.5.0"}, + {Name: "github.com/go-git/go-billy/v5", Version: "v5.0.0"}, + {Name: "github.com/go-git/go-git-fixtures/v4", Version: "v4.0.1"}, + {Name: "github.com/go-git/go-git/v5", Version: "v5.0.0"}, + {Name: "github.com/go-gl/glfw", Version: "v0.0.0-20190409004039-e6da0acd62b1"}, + {Name: "github.com/go-gl/glfw/v3.3/glfw", Version: "v0.0.0-20200222043503-6f7a984d4dc4"}, + {Name: "github.com/go-kit/kit", Version: "v0.8.0"}, + {Name: "github.com/go-logfmt/logfmt", Version: "v0.3.0"}, + {Name: "github.com/go-logr/logr", Version: "v0.1.0"}, + {Name: "github.com/go-openapi/jsonpointer", Version: "v0.19.3"}, + {Name: "github.com/go-openapi/jsonreference", Version: "v0.19.3"}, + {Name: "github.com/go-openapi/spec", Version: "v0.19.3"}, + {Name: "github.com/go-openapi/swag", Version: "v0.19.5"}, + {Name: "github.com/go-playground/locales", Version: "v0.13.0"}, + {Name: "github.com/go-playground/universal-translator", Version: "v0.17.0"}, + {Name: "github.com/go-redis/redis", Version: "v6.15.7+incompatible"}, + {Name: "github.com/go-redis/redis/v8", Version: "v8.4.0"}, + {Name: "github.com/go-restruct/restruct", Version: "v0.0.0-20191227155143-5734170a48a1"}, + {Name: "github.com/go-sql-driver/mysql", Version: "v1.5.0"}, + {Name: "github.com/go-stack/stack", Version: "v1.8.0"}, + {Name: "github.com/gobwas/glob", Version: "v0.2.3"}, + {Name: "github.com/goccy/go-yaml", Version: "v1.8.2"}, + {Name: "github.com/gogo/protobuf", Version: "v1.3.1"}, + {Name: "github.com/golang/glog", Version: "v0.0.0-20160126235308-23def4e6c14b"}, + {Name: "github.com/golang/groupcache", Version: "v0.0.0-20200121045136-8c9f03a8e57e"}, + {Name: "github.com/golang/mock", Version: "v1.4.4"}, + {Name: "github.com/golang/protobuf", Version: "v1.4.2"}, + {Name: "github.com/google/btree", Version: "v1.0.0"}, + {Name: "github.com/google/go-cmp", Version: "v0.5.3"}, + {Name: "github.com/google/go-containerregistry", Version: "v0.0.0-20200331213917-3d03ed9b1ca2"}, + {Name: "github.com/google/go-github/v28", Version: "v28.1.1"}, + {Name: "github.com/google/go-querystring", Version: "v1.0.0"}, + {Name: "github.com/google/gofuzz", Version: "v1.0.0"}, + {Name: "github.com/google/martian", Version: "v2.1.0+incompatible"}, + {Name: "github.com/google/martian/v3", Version: "v3.0.0"}, + {Name: "github.com/google/pprof", Version: "v0.0.0-20200708004538-1a94d8640e99"}, + {Name: "github.com/google/renameio", Version: "v0.1.0"}, + {Name: "github.com/google/subcommands", Version: "v1.0.1"}, + {Name: "github.com/google/uuid", Version: "v1.1.1"}, + {Name: "github.com/google/wire", Version: "v0.3.0"}, + {Name: "github.com/googleapis/gax-go/v2", Version: "v2.0.5"}, + {Name: "github.com/googleapis/gnostic", Version: "v0.2.2"}, + {Name: "github.com/gophercloud/gophercloud", Version: "v0.1.0"}, + {Name: "github.com/gopherjs/gopherjs", Version: "v0.0.0-20200217142428-fce0ec30dd00"}, + {Name: "github.com/gorilla/context", Version: "v1.1.1"}, + {Name: "github.com/gorilla/mux", Version: "v1.7.4"}, + {Name: "github.com/gorilla/websocket", Version: "v1.4.0"}, + {Name: "github.com/gregjones/httpcache", Version: "v0.0.0-20180305231024-9cad4c3443a7"}, + {Name: "github.com/grpc-ecosystem/go-grpc-middleware", Version: "v1.0.1-0.20190118093823-f849b5445de4"}, + {Name: "github.com/grpc-ecosystem/go-grpc-prometheus", Version: "v1.2.0"}, + {Name: "github.com/grpc-ecosystem/grpc-gateway", Version: "v1.9.5"}, + {Name: "github.com/hashicorp/errwrap", Version: "v1.0.0"}, + {Name: "github.com/hashicorp/go-multierror", Version: "v1.1.0"}, + {Name: "github.com/hashicorp/go-version", Version: "v1.2.1"}, + {Name: "github.com/hashicorp/golang-lru", Version: "v0.5.3"}, + {Name: "github.com/hashicorp/hcl", Version: "v1.0.0"}, + {Name: "github.com/hpcloud/tail", Version: "v1.0.0"}, + {Name: "github.com/ianlancetaylor/demangle", Version: "v0.0.0-20181102032728-5e5cf60278f6"}, + {Name: "github.com/imdario/mergo", Version: "v0.3.5"}, + {Name: "github.com/inconshreveable/mousetrap", Version: "v1.0.0"}, + {Name: "github.com/jbenet/go-context", Version: "v0.0.0-20150711004518-d14ea06fba99"}, + {Name: "github.com/jessevdk/go-flags", Version: "v1.4.0"}, + {Name: "github.com/jmespath/go-jmespath", Version: "v0.0.0-20180206201540-c2b33e8439af"}, + {Name: "github.com/joefitzgerald/rainbow-reporter", Version: "v0.1.0"}, + {Name: "github.com/jonboulle/clockwork", Version: "v0.1.0"}, + {Name: "github.com/json-iterator/go", Version: "v1.1.8"}, + {Name: "github.com/jstemmer/go-junit-report", Version: "v0.9.1"}, + {Name: "github.com/jtolds/gls", Version: "v4.20.0+incompatible"}, + {Name: "github.com/julienschmidt/httprouter", Version: "v1.2.0"}, + {Name: "github.com/kevinburke/ssh_config", Version: "v0.0.0-20190725054713-01f96b0aa0cd"}, + {Name: "github.com/kisielk/errcheck", Version: "v1.2.0"}, + {Name: "github.com/kisielk/gotool", Version: "v1.0.0"}, + {Name: "github.com/knqyf263/go-apk-version", Version: "v0.0.0-20200609155635-041fdbb8563f"}, + {Name: "github.com/knqyf263/go-deb-version", Version: "v0.0.0-20190517075300-09fca494f03d"}, + {Name: "github.com/knqyf263/go-rpm-version", Version: "v0.0.0-20170716094938-74609b86c936"}, + {Name: "github.com/knqyf263/go-rpmdb", Version: "v0.0.0-20201215100354-a9e3110d8ee1"}, + {Name: "github.com/knqyf263/nested", Version: "v0.0.1"}, + {Name: "github.com/konsorten/go-windows-terminal-sequences", Version: "v1.0.2"}, + {Name: "github.com/kr/logfmt", Version: "v0.0.0-20140226030751-b84e30acd515"}, + {Name: "github.com/kr/pretty", Version: "v0.1.0"}, + {Name: "github.com/kr/pty", Version: "v1.1.5"}, + {Name: "github.com/kr/text", Version: "v0.2.0"}, + {Name: "github.com/kylelemons/godebug", Version: "v1.1.0"}, + {Name: "github.com/leodido/go-urn", Version: "v1.2.0"}, + {Name: "github.com/magiconair/properties", Version: "v1.8.0"}, + {Name: "github.com/mailru/easyjson", Version: "v0.7.0"}, + {Name: "github.com/mattn/go-colorable", Version: "v0.1.8"}, + {Name: "github.com/mattn/go-isatty", Version: "v0.0.12"}, + {Name: "github.com/mattn/go-jsonpointer", Version: "v0.0.0-20180225143300-37667080efed"}, + {Name: "github.com/mattn/go-runewidth", Version: "v0.0.9"}, + {Name: "github.com/matttproud/golang_protobuf_extensions", Version: "v1.0.1"}, + {Name: "github.com/maxbrunsfeld/counterfeiter/v6", Version: "v6.2.2"}, + {Name: "github.com/mitchellh/go-homedir", Version: "v1.1.0"}, + {Name: "github.com/mitchellh/mapstructure", Version: "v1.1.2"}, + {Name: "github.com/modern-go/concurrent", Version: "v0.0.0-20180306012644-bacd9c7ef1dd"}, + {Name: "github.com/modern-go/reflect2", Version: "v1.0.1"}, + {Name: "github.com/morikuni/aec", Version: "v1.0.0"}, + {Name: "github.com/munnerz/goautoneg", Version: "v0.0.0-20191010083416-a7dc8b61c822"}, + {Name: "github.com/mwitkow/go-conntrack", Version: "v0.0.0-20161129095857-cc309e4a2223"}, + {Name: "github.com/mxk/go-flowrate", Version: "v0.0.0-20140419014527-cca7078d478f"}, + {Name: "github.com/niemeyer/pretty", Version: "v0.0.0-20200227124842-a10e7caefd8e"}, + {Name: "github.com/nxadm/tail", Version: "v1.4.4"}, + {Name: "github.com/olekukonko/tablewriter", Version: "v0.0.2-0.20190607075207-195002e6e56a"}, + {Name: "github.com/onsi/ginkgo", Version: "v1.14.2"}, + {Name: "github.com/onsi/gomega", Version: "v1.10.3"}, + {Name: "github.com/open-policy-agent/opa", Version: "v0.21.1"}, + {Name: "github.com/opencontainers/go-digest", Version: "v1.0.0-rc1"}, + {Name: "github.com/opencontainers/image-spec", Version: "v1.0.2-0.20190823105129-775207bd45b6"}, + {Name: "github.com/opencontainers/runc", Version: "v0.1.1"}, + {Name: "github.com/parnurzeal/gorequest", Version: "v0.2.16"}, + {Name: "github.com/pelletier/go-toml", Version: "v1.2.0"}, + {Name: "github.com/peterbourgon/diskv", Version: "v2.0.1+incompatible"}, + {Name: "github.com/peterh/liner", Version: "v0.0.0-20170211195444-bf27d3ba8e1d"}, + {Name: "github.com/pkg/errors", Version: "v0.9.1"}, + {Name: "github.com/pmezard/go-difflib", Version: "v1.0.0"}, + {Name: "github.com/pquerna/cachecontrol", Version: "v0.0.0-20171018203845-0dec1b30a021"}, + {Name: "github.com/prometheus/client_golang", Version: "v1.0.0"}, + {Name: "github.com/prometheus/client_model", Version: "v0.0.0-20190812154241-14fe0d1b01d4"}, + {Name: "github.com/prometheus/common", Version: "v0.4.1"}, + {Name: "github.com/prometheus/procfs", Version: "v0.0.2"}, + {Name: "github.com/rcrowley/go-metrics", Version: "v0.0.0-20181016184325-3113b8401b8a"}, + {Name: "github.com/remyoudompheng/bigfft", Version: "v0.0.0-20170806203942-52369c62f446"}, + {Name: "github.com/rogpeppe/fastuuid", Version: "v0.0.0-20150106093220-6724a57986af"}, + {Name: "github.com/rogpeppe/go-charset", Version: "v0.0.0-20180617210344-2471d30d28b4"}, + {Name: "github.com/rogpeppe/go-internal", Version: "v1.3.0"}, + {Name: "github.com/rubiojr/go-vhd", Version: "v0.0.0-20160810183302-0bfd3b39853c"}, + {Name: "github.com/russross/blackfriday", Version: "v1.5.2"}, + {Name: "github.com/russross/blackfriday/v2", Version: "v2.0.1"}, + {Name: "github.com/saracen/walker", Version: "v0.0.0-20191201085201-324a081bae7e"}, + {Name: "github.com/satori/go.uuid", Version: "v1.2.0"}, + {Name: "github.com/sclevine/spec", Version: "v1.2.0"}, + {Name: "github.com/sergi/go-diff", Version: "v1.1.0"}, + {Name: "github.com/shurcooL/sanitized_anchor_name", Version: "v1.0.0"}, + {Name: "github.com/simplereach/timeutils", Version: "v1.2.0"}, + {Name: "github.com/sirupsen/logrus", Version: "v1.5.0"}, + {Name: "github.com/smartystreets/assertions", Version: "v1.2.0"}, + {Name: "github.com/smartystreets/goconvey", Version: "v1.6.4"}, + {Name: "github.com/soheilhy/cmux", Version: "v0.1.4"}, + {Name: "github.com/sosedoff/gitkit", Version: "v0.2.0"}, + {Name: "github.com/spf13/afero", Version: "v1.2.2"}, + {Name: "github.com/spf13/cast", Version: "v1.3.0"}, + {Name: "github.com/spf13/cobra", Version: "v0.0.5"}, + {Name: "github.com/spf13/jwalterweatherman", Version: "v1.0.0"}, + {Name: "github.com/spf13/pflag", Version: "v1.0.5"}, + {Name: "github.com/spf13/viper", Version: "v1.3.2"}, + {Name: "github.com/stretchr/objx", Version: "v0.3.0"}, + {Name: "github.com/stretchr/testify", Version: "v1.6.1"}, + {Name: "github.com/testcontainers/testcontainers-go", Version: "v0.3.1"}, + {Name: "github.com/tmc/grpc-websocket-proxy", Version: "v0.0.0-20170815181823-89b8d40f7ca8"}, + {Name: "github.com/twitchtv/twirp", Version: "v5.10.1+incompatible"}, + {Name: "github.com/ugorji/go", Version: "v1.1.7"}, + {Name: "github.com/ugorji/go/codec", Version: "v1.1.7"}, + {Name: "github.com/urfave/cli", Version: "v1.22.5"}, + {Name: "github.com/urfave/cli/v2", Version: "v2.3.0"}, + {Name: "github.com/vdemeester/k8s-pkg-credentialprovider", Version: "v1.17.4"}, + {Name: "github.com/vmware/govmomi", Version: "v0.20.3"}, + {Name: "github.com/xanzy/ssh-agent", Version: "v0.2.1"}, + {Name: "github.com/xiang90/probing", Version: "v0.0.0-20190116061207-43a291ad63a2"}, + {Name: "github.com/xordataexchange/crypt", Version: "v0.0.3-0.20170626215501-b2862e3d0a77"}, + {Name: "github.com/yashtewari/glob-intersection", Version: "v0.0.0-20180916065949-5c77d914dd0b"}, + {Name: "github.com/yuin/goldmark", Version: "v1.1.32"}, + {Name: "github.com/yuin/gopher-lua", Version: "v0.0.0-20191220021717-ab39c6098bdb"}, + {Name: "go.etcd.io/bbolt", Version: "v1.3.5"}, + {Name: "go.etcd.io/etcd", Version: "v0.0.0-20191023171146-3cf2f69b5738"}, + {Name: "go.opencensus.io", Version: "v0.22.4"}, + {Name: "go.opentelemetry.io/otel", Version: "v0.14.0"}, + {Name: "go.uber.org/atomic", Version: "v1.5.1"}, + {Name: "go.uber.org/multierr", Version: "v1.4.0"}, + {Name: "go.uber.org/tools", Version: "v0.0.0-20190618225709-2cfd321de3ee"}, + {Name: "go.uber.org/zap", Version: "v1.13.0"}, + {Name: "golang.org/x/crypto", Version: "v0.0.0-20201002170205-7f63de1d35b0"}, + {Name: "golang.org/x/exp", Version: "v0.0.0-20200224162631-6cc2880d07d6"}, + {Name: "golang.org/x/image", Version: "v0.0.0-20190802002840-cff245a6509b"}, + {Name: "golang.org/x/lint", Version: "v0.0.0-20200302205851-738671d3881b"}, + {Name: "golang.org/x/mobile", Version: "v0.0.0-20190719004257-d2bd2a29d028"}, + {Name: "golang.org/x/mod", Version: "v0.3.0"}, + {Name: "golang.org/x/net", Version: "v0.0.0-20201006153459-a7d1128ccaa0"}, + {Name: "golang.org/x/oauth2", Version: "v0.0.0-20201208152858-08078c50e5b5"}, + {Name: "golang.org/x/sync", Version: "v0.0.0-20200625203802-6e8e738ad208"}, + {Name: "golang.org/x/sys", Version: "v0.0.0-20201006155630-ac719f4daadf"}, + {Name: "golang.org/x/text", Version: "v0.3.3"}, + {Name: "golang.org/x/time", Version: "v0.0.0-20191024005414-555d28b269f0"}, + {Name: "golang.org/x/tools", Version: "v0.0.0-20200825202427-b303f430e36d"}, + {Name: "golang.org/x/xerrors", Version: "v0.0.0-20200804184101-5ec99f83aff1"}, + {Name: "gonum.org/v1/gonum", Version: "v0.0.0-20190331200053-3d26580ed485"}, + {Name: "gonum.org/v1/netlib", Version: "v0.0.0-20190331212654-76723241ea4e"}, + {Name: "google.golang.org/api", Version: "v0.30.0"}, + {Name: "google.golang.org/appengine", Version: "v1.6.6"}, + {Name: "google.golang.org/genproto", Version: "v0.0.0-20200825200019-8632dd797987"}, + {Name: "google.golang.org/grpc", Version: "v1.31.0"}, + {Name: "google.golang.org/protobuf", Version: "v1.25.0"}, + {Name: "gopkg.in/alecthomas/kingpin.v2", Version: "v2.2.6"}, + {Name: "gopkg.in/check.v1", Version: "v1.0.0-20200902074654-038fdea0a05b"}, + {Name: "gopkg.in/cheggaaa/pb.v1", Version: "v1.0.28"}, + {Name: "gopkg.in/errgo.v2", Version: "v2.1.0"}, + {Name: "gopkg.in/fsnotify.v1", Version: "v1.4.7"}, + {Name: "gopkg.in/gcfg.v1", Version: "v1.2.0"}, + {Name: "gopkg.in/go-playground/assert.v1", Version: "v1.2.1"}, + {Name: "gopkg.in/go-playground/validator.v9", Version: "v9.31.0"}, + {Name: "gopkg.in/inf.v0", Version: "v0.9.1"}, + {Name: "gopkg.in/mgo.v2", Version: "v2.0.0-20180705113604-9856a29383ce"}, + {Name: "gopkg.in/natefinch/lumberjack.v2", Version: "v2.0.0"}, + {Name: "gopkg.in/resty.v1", Version: "v1.12.0"}, + {Name: "gopkg.in/square/go-jose.v2", Version: "v2.2.2"}, + {Name: "gopkg.in/tomb.v1", Version: "v1.0.0-20141024135613-dd632973f1e7"}, + {Name: "gopkg.in/warnings.v0", Version: "v0.1.2"}, + {Name: "gopkg.in/yaml.v2", Version: "v2.4.0"}, + {Name: "gopkg.in/yaml.v3", Version: "v3.0.0-20200615113413-eeeca48fe776"}, + {Name: "gotest.tools", Version: "v2.2.0+incompatible"}, + {Name: "honnef.co/go/tools", Version: "v0.0.1-2020.1.4"}, + {Name: "k8s.io/api", Version: "v0.17.4"}, + {Name: "k8s.io/apimachinery", Version: "v0.17.4"}, + {Name: "k8s.io/apiserver", Version: "v0.17.4"}, + {Name: "k8s.io/client-go", Version: "v0.17.4"}, + {Name: "k8s.io/cloud-provider", Version: "v0.17.4"}, + {Name: "k8s.io/code-generator", Version: "v0.17.2"}, + {Name: "k8s.io/component-base", Version: "v0.17.4"}, + {Name: "k8s.io/csi-translation-lib", Version: "v0.17.4"}, + {Name: "k8s.io/gengo", Version: "v0.0.0-20190822140433-26a664648505"}, + {Name: "k8s.io/klog", Version: "v1.0.0"}, + {Name: "k8s.io/klog/v2", Version: "v2.0.0"}, + {Name: "k8s.io/kube-openapi", Version: "v0.0.0-20191107075043-30be4d16710a"}, + {Name: "k8s.io/legacy-cloud-providers", Version: "v0.17.4"}, + {Name: "k8s.io/utils", Version: "v0.0.0-20201110183641-67b214c5f920"}, + {Name: "modernc.org/cc", Version: "v1.0.0"}, + {Name: "modernc.org/golex", Version: "v1.0.0"}, + {Name: "modernc.org/mathutil", Version: "v1.0.0"}, + {Name: "modernc.org/strutil", Version: "v1.0.0"}, + {Name: "modernc.org/xc", Version: "v1.0.0"}, + {Name: "moul.io/http2curl", Version: "v1.0.0"}, + {Name: "rsc.io/binaryregexp", Version: "v0.2.0"}, + {Name: "rsc.io/quote/v3", Version: "v3.1.0"}, + {Name: "rsc.io/sampler", Version: "v1.3.0"}, + {Name: "sigs.k8s.io/structured-merge-diff", Version: "v1.0.1-0.20191108220359-b1b620dd3f06"}, + {Name: "sigs.k8s.io/yaml", Version: "v1.1.0"}, } ) diff --git a/pkg/fanal/analyzer/language/golang/binary/binary_test.go b/pkg/fanal/analyzer/language/golang/binary/binary_test.go index 70256113cfd3..041d43e1b45b 100644 --- a/pkg/fanal/analyzer/language/golang/binary/binary_test.go +++ b/pkg/fanal/analyzer/language/golang/binary/binary_test.go @@ -36,7 +36,7 @@ func Test_gobinaryLibraryAnalyzer_Analyze(t *testing.T) { }, { Name: "stdlib", - Version: "1.15.2", + Version: "v1.15.2", Relationship: types.RelationshipDirect, }, { diff --git a/pkg/fanal/analyzer/language/golang/mod/mod.go b/pkg/fanal/analyzer/language/golang/mod/mod.go index 398511fdc63c..52d7b32f3bee 100644 --- a/pkg/fanal/analyzer/language/golang/mod/mod.go +++ b/pkg/fanal/analyzer/language/golang/mod/mod.go @@ -148,7 +148,7 @@ func (a *gomodAnalyzer) fillAdditionalData(apps []types.Application) error { } // e.g. $GOPATH/pkg/mod/github.com/aquasecurity/go-dep-parser@v1.0.0 - modDir := filepath.Join(modPath, fmt.Sprintf("%s@v%s", normalizeModName(lib.Name), lib.Version)) + modDir := filepath.Join(modPath, fmt.Sprintf("%s@%s", normalizeModName(lib.Name), lib.Version)) // Collect licenses if licenseNames, err := findLicense(modDir, a.licenseClassifierConfidenceLevel); err != nil { diff --git a/pkg/fanal/analyzer/language/golang/mod/mod_test.go b/pkg/fanal/analyzer/language/golang/mod/mod_test.go index 5cf006430aca..3963bcebbad9 100644 --- a/pkg/fanal/analyzer/language/golang/mod/mod_test.go +++ b/pkg/fanal/analyzer/language/golang/mod/mod_test.go @@ -46,7 +46,7 @@ func Test_gomodAnalyzer_Analyze(t *testing.T) { { ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20220406074731-71021a481237", Name: "github.com/aquasecurity/go-dep-parser", - Version: "0.0.0-20220406074731-71021a481237", + Version: "v0.0.0-20220406074731-71021a481237", Relationship: types.RelationshipDirect, Licenses: []string{"MIT"}, ExternalReferences: []types.ExternalRef{ @@ -62,7 +62,7 @@ func Test_gomodAnalyzer_Analyze(t *testing.T) { { ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1", Name: "golang.org/x/xerrors", - Version: "0.0.0-20200804184101-5ec99f83aff1", + Version: "v0.0.0-20200804184101-5ec99f83aff1", Relationship: types.RelationshipIndirect, Indirect: true, }, @@ -96,7 +96,7 @@ func Test_gomodAnalyzer_Analyze(t *testing.T) { { ID: "github.com/sad/sad@v0.0.1", Name: "github.com/sad/sad", - Version: "0.0.1", + Version: "v0.0.1", Relationship: types.RelationshipDirect, ExternalReferences: []types.ExternalRef{ { @@ -136,7 +136,7 @@ func Test_gomodAnalyzer_Analyze(t *testing.T) { { ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20230219131432-590b1dfb6edd", Name: "github.com/aquasecurity/go-dep-parser", - Version: "0.0.0-20230219131432-590b1dfb6edd", + Version: "v0.0.0-20230219131432-590b1dfb6edd", Relationship: types.RelationshipDirect, DependsOn: []string{ "github.com/BurntSushi/toml@v0.3.1", @@ -151,7 +151,7 @@ func Test_gomodAnalyzer_Analyze(t *testing.T) { { ID: "github.com/BurntSushi/toml@v0.3.1", Name: "github.com/BurntSushi/toml", - Version: "0.3.1", + Version: "v0.3.1", Relationship: types.RelationshipIndirect, Indirect: true, Licenses: []string{ @@ -188,7 +188,7 @@ func Test_gomodAnalyzer_Analyze(t *testing.T) { { ID: "github.com/aquasecurity/go-dep-parser@v0.0.0-20230219131432-590b1dfb6edd", Name: "github.com/aquasecurity/go-dep-parser", - Version: "0.0.0-20230219131432-590b1dfb6edd", + Version: "v0.0.0-20230219131432-590b1dfb6edd", Relationship: types.RelationshipDirect, DependsOn: []string{}, ExternalReferences: []types.ExternalRef{ diff --git a/pkg/purl/purl_test.go b/pkg/purl/purl_test.go index 25e9e7829d7b..d5ba15300393 100644 --- a/pkg/purl/purl_test.go +++ b/pkg/purl/purl_test.go @@ -809,38 +809,38 @@ func TestPackageURL_Match(t *testing.T) { }{ { name: "same purl", - constraint: "pkg:golang/github.com/aquasecurity/trivy@0.49.0", - target: "pkg:golang/github.com/aquasecurity/trivy@0.49.0", + constraint: "pkg:golang/github.com/aquasecurity/trivy@v0.49.0", + target: "pkg:golang/github.com/aquasecurity/trivy@v0.49.0", want: true, }, { name: "different type", - constraint: "pkg:golang/github.com/aquasecurity/trivy@0.49.0", + constraint: "pkg:golang/github.com/aquasecurity/trivy@v0.49.0", target: "pkg:maven/github.com/aquasecurity/trivy@0.49.0", want: false, }, { name: "different namespace", - constraint: "pkg:golang/github.com/aquasecurity/trivy@0.49.0", - target: "pkg:golang/github.com/aquasecurity2/trivy@0.49.0", + constraint: "pkg:golang/github.com/aquasecurity/trivy@v0.49.0", + target: "pkg:golang/github.com/aquasecurity2/trivy@v.49.0", want: false, }, { name: "different name", - constraint: "pkg:golang/github.com/aquasecurity/trivy@0.49.0", - target: "pkg:golang/github.com/aquasecurity/tracee@0.49.0", + constraint: "pkg:golang/github.com/aquasecurity/trivy@v0.49.0", + target: "pkg:golang/github.com/aquasecurity/tracee@v0.49.0", want: false, }, { name: "different version", - constraint: "pkg:golang/github.com/aquasecurity/trivy@0.49.0", - target: "pkg:golang/github.com/aquasecurity/trivy@0.49.1", + constraint: "pkg:golang/github.com/aquasecurity/trivy@v0.49.0", + target: "pkg:golang/github.com/aquasecurity/trivy@v0.49.1", want: false, }, { name: "version wildcard", constraint: "pkg:golang/github.com/aquasecurity/trivy", - target: "pkg:golang/github.com/aquasecurity/trivy@0.50.0", + target: "pkg:golang/github.com/aquasecurity/trivy@v0.50.0", want: true, }, { diff --git a/pkg/result/filter_test.go b/pkg/result/filter_test.go index 289ec2ee0c63..08b523dd2dde 100644 --- a/pkg/result/filter_test.go +++ b/pkg/result/filter_test.go @@ -21,16 +21,16 @@ import ( func TestFilter(t *testing.T) { var ( pkg1 = ftypes.Package{ - ID: "foo@1.2.3", + ID: "foo@v1.2.3", Name: "foo", - Version: "1.2.3", + Version: "v1.2.3", Identifier: ftypes.PkgIdentifier{ UID: "01", PURL: &packageurl.PackageURL{ Type: packageurl.TypeGolang, Namespace: "github.com/aquasecurity", Name: "foo", - Version: "1.2.3", + Version: "v1.2.3", }, }, } @@ -90,14 +90,14 @@ func TestFilter(t *testing.T) { vuln6 = types.DetectedVulnerability{ VulnerabilityID: "CVE-2019-0006", PkgName: "foo", - InstalledVersion: "1.2.3", + InstalledVersion: "v1.2.3", FixedVersion: "1.2.4", PkgIdentifier: ftypes.PkgIdentifier{ PURL: &packageurl.PackageURL{ Type: packageurl.TypeGolang, Namespace: "github.com/aquasecurity", Name: "foo", - Version: "1.2.3", + Version: "v1.2.3", }, }, Vulnerability: dbTypes.Vulnerability{ @@ -107,14 +107,14 @@ func TestFilter(t *testing.T) { vuln7 = types.DetectedVulnerability{ VulnerabilityID: "CVE-2019-0007", PkgName: "bar", - InstalledVersion: "2.3.4", + InstalledVersion: "v2.3.4", FixedVersion: "2.3.5", PkgIdentifier: ftypes.PkgIdentifier{ PURL: &packageurl.PackageURL{ Type: packageurl.TypeGolang, Namespace: "github.com/aquasecurity", Name: "bar", - Version: "2.3.4", + Version: "v2.3.4", }, }, Vulnerability: dbTypes.Vulnerability{ diff --git a/pkg/result/testdata/openvex.json b/pkg/result/testdata/openvex.json index dcdd344700c7..385f22e47deb 100644 --- a/pkg/result/testdata/openvex.json +++ b/pkg/result/testdata/openvex.json @@ -8,7 +8,7 @@ { "vulnerability": {"name": "CVE-2019-0001"}, "products": [ - {"@id": "pkg:golang/github.com/aquasecurity/foo@1.2.3"} + {"@id": "pkg:golang/github.com/aquasecurity/foo@v1.2.3"} ], "status": "not_affected", "justification": "vulnerable_code_not_in_execute_path" diff --git a/pkg/sbom/io/encode_test.go b/pkg/sbom/io/encode_test.go index 52fbed415933..5a5b821590b8 100644 --- a/pkg/sbom/io/encode_test.go +++ b/pkg/sbom/io/encode_test.go @@ -461,7 +461,7 @@ func TestEncoder_Encode(t *testing.T) { Type: packageurl.TypeGolang, Namespace: "github.com/org", Name: "direct", - Version: "1.0.0", + Version: "v1.0.0", }, }, Relationship: ftypes.RelationshipDirect, @@ -472,28 +472,28 @@ func TestEncoder_Encode(t *testing.T) { { ID: "github.com/org/indirect@v2.0.0", Name: "github.com/org/indirect", - Version: "2.0.0", + Version: "v2.0.0", Identifier: ftypes.PkgIdentifier{ UID: "955AB4E7E24AC085", PURL: &packageurl.PackageURL{ Type: packageurl.TypeGolang, Namespace: "github.com/org", Name: "indirect", - Version: "2.0.0", + Version: "v2.0.0", }, }, Relationship: ftypes.RelationshipIndirect, }, { - ID: "stdlib@1.22.1", + ID: "stdlib@v1.22.1", Name: "stdlib", - Version: "1.22.1", + Version: "v1.22.1", Identifier: ftypes.PkgIdentifier{ UID: "49728B9674E318A6", PURL: &packageurl.PackageURL{ Type: packageurl.TypeGolang, Name: "stdlib", - Version: "1.22.1", + Version: "v1.22.1", }, }, Relationship: ftypes.RelationshipDirect, @@ -561,7 +561,7 @@ func TestEncoder_Encode(t *testing.T) { uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000004"): { Type: core.TypeLibrary, Name: "github.com/org/direct", - Version: "1.0.0", + Version: "v1.0.0", SrcFile: "test", Properties: []core.Property{ { @@ -579,15 +579,15 @@ func TestEncoder_Encode(t *testing.T) { Type: packageurl.TypeGolang, Namespace: "github.com/org", Name: "direct", - Version: "1.0.0", + Version: "v1.0.0", }, - BOMRef: "pkg:golang/github.com/org/direct@1.0.0", + BOMRef: "pkg:golang/github.com/org/direct@v1.0.0", }, }, uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000005"): { Type: core.TypeLibrary, Name: "github.com/org/indirect", - Version: "2.0.0", + Version: "v2.0.0", SrcFile: "test", Properties: []core.Property{ { @@ -605,20 +605,20 @@ func TestEncoder_Encode(t *testing.T) { Type: packageurl.TypeGolang, Namespace: "github.com/org", Name: "indirect", - Version: "2.0.0", + Version: "v2.0.0", }, - BOMRef: "pkg:golang/github.com/org/indirect@2.0.0", + BOMRef: "pkg:golang/github.com/org/indirect@v2.0.0", }, }, uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000006"): { Type: core.TypeLibrary, Name: "stdlib", - Version: "1.22.1", + Version: "v1.22.1", SrcFile: "test", Properties: []core.Property{ { Name: core.PropertyPkgID, - Value: "stdlib@1.22.1", + Value: "stdlib@v1.22.1", }, { Name: core.PropertyPkgType, @@ -630,9 +630,9 @@ func TestEncoder_Encode(t *testing.T) { PURL: &packageurl.PackageURL{ Type: packageurl.TypeGolang, Name: "stdlib", - Version: "1.22.1", + Version: "v1.22.1", }, - BOMRef: "pkg:golang/stdlib@1.22.1", + BOMRef: "pkg:golang/stdlib@v1.22.1", }, }, }, diff --git a/pkg/vex/testdata/csaf-relationships.json b/pkg/vex/testdata/csaf-relationships.json index 2e823d17a2c6..18c311228206 100644 --- a/pkg/vex/testdata/csaf-relationships.json +++ b/pkg/vex/testdata/csaf-relationships.json @@ -42,7 +42,7 @@ "name": "go-direct1 v2.0.0", "product_id": "go-direct1-v2.0.0", "product_identification_helper": { - "purl": "pkg:golang/github.com/aquasecurity/go-direct1@2.0.0" + "purl": "pkg:golang/github.com/aquasecurity/go-direct1@v2.0.0" } } } @@ -65,7 +65,7 @@ "name": "go-transitive v4.0.0", "product_id": "go-transitive-v4.0.0", "product_identification_helper": { - "purl": "pkg:golang/github.com/aquasecurity/go-transitive@4.0.0" + "purl": "pkg:golang/github.com/aquasecurity/go-transitive@v4.0.0" } } } diff --git a/pkg/vex/testdata/csaf.json b/pkg/vex/testdata/csaf.json index 70afefe70205..182856f96a51 100644 --- a/pkg/vex/testdata/csaf.json +++ b/pkg/vex/testdata/csaf.json @@ -50,7 +50,7 @@ "name": "go-transitive v4.0.0", "product_id": "go-transitive-v4.0.0", "product_identification_helper": { - "purl": "pkg:golang/github.com/aquasecurity/go-transitive@4.0.0" + "purl": "pkg:golang/github.com/aquasecurity/go-transitive@v4.0.0" } } } diff --git a/pkg/vex/testdata/openvex-nested.json b/pkg/vex/testdata/openvex-nested.json index da7dd68615a5..637603d9e48c 100644 --- a/pkg/vex/testdata/openvex-nested.json +++ b/pkg/vex/testdata/openvex-nested.json @@ -11,10 +11,10 @@ }, "products": [ { - "@id": "pkg:golang/github.com/aquasecurity/go-direct1@2.0.0", + "@id": "pkg:golang/github.com/aquasecurity/go-direct1@v2.0.0", "subcomponents": [ { - "@id": "pkg:golang/github.com/aquasecurity/go-transitive@4.0.0" + "@id": "pkg:golang/github.com/aquasecurity/go-transitive@v4.0.0" } ] } diff --git a/pkg/vex/vex_test.go b/pkg/vex/vex_test.go index 4a9686972a5e..bc7a5c069402 100644 --- a/pkg/vex/vex_test.go +++ b/pkg/vex/vex_test.go @@ -58,9 +58,9 @@ var ( }, } goModulePackage = ftypes.Package{ - ID: "github.com/aquasecurity/go-module@1.0.0", + ID: "github.com/aquasecurity/go-module@v1.0.0", Name: "github.com/aquasecurity/go-module", - Version: "1.0.0", + Version: "v1.0.0", Relationship: ftypes.RelationshipRoot, Identifier: ftypes.PkgIdentifier{ UID: "03", @@ -68,14 +68,14 @@ var ( Type: packageurl.TypeGolang, Namespace: "github.com/aquasecurity", Name: "go-module", - Version: "1.0.0", + Version: "v1.0.0", }, }, } goDirectPackage1 = ftypes.Package{ - ID: "github.com/aquasecurity/go-direct1@2.0.0", + ID: "github.com/aquasecurity/go-direct1@v2.0.0", Name: "github.com/aquasecurity/go-direct1", - Version: "2.0.0", + Version: "v2.0.0", Relationship: ftypes.RelationshipDirect, Identifier: ftypes.PkgIdentifier{ UID: "04", @@ -83,14 +83,14 @@ var ( Type: packageurl.TypeGolang, Namespace: "github.com/aquasecurity", Name: "go-direct1", - Version: "2.0.0", + Version: "v2.0.0", }, }, } goDirectPackage2 = ftypes.Package{ - ID: "github.com/aquasecurity/go-direct2@3.0.0", + ID: "github.com/aquasecurity/go-direct2@v3.0.0", Name: "github.com/aquasecurity/go-direct2", - Version: "3.0.0", + Version: "v3.0.0", Relationship: ftypes.RelationshipDirect, Identifier: ftypes.PkgIdentifier{ UID: "05", @@ -98,14 +98,14 @@ var ( Type: packageurl.TypeGolang, Namespace: "github.com/aquasecurity", Name: "go-direct2", - Version: "3.0.0", + Version: "v3.0.0", }, }, } goTransitivePackage = ftypes.Package{ - ID: "github.com/aquasecurity/go-transitive@4.0.0", + ID: "github.com/aquasecurity/go-transitive@v4.0.0", Name: "github.com/aquasecurity/go-transitive", - Version: "4.0.0", + Version: "v4.0.0", Relationship: ftypes.RelationshipIndirect, Identifier: ftypes.PkgIdentifier{ UID: "06", @@ -113,7 +113,7 @@ var ( Type: packageurl.TypeGolang, Namespace: "github.com/aquasecurity", Name: "go-transitive", - Version: "4.0.0", + Version: "v4.0.0", }, }, } @@ -646,9 +646,9 @@ func goSinglePathResult(result types.Result) types.Result { result.Type = ftypes.GoModule result.Class = types.ClassLangPkg - // - pkg:golang/github.com/aquasecurity/go-module@1.0.0 - // - pkg:golang/github.com/aquasecurity/go-direct1@2.0.0 - // - pkg:golang/github.com/aquasecurity/go-transitive@4.0.0 + // - pkg:golang/github.com/aquasecurity/go-module@v1.0.0 + // - pkg:golang/github.com/aquasecurity/go-direct1@v2.0.0 + // - pkg:golang/github.com/aquasecurity/go-transitive@v4.0.0 goModule := clonePackage(goModulePackage) goDirect1 := clonePackage(goDirectPackage1) goTransitive := clonePackage(goTransitivePackage) @@ -667,11 +667,11 @@ func goMultiPathResult(result types.Result) types.Result { result.Type = ftypes.GoModule result.Class = types.ClassLangPkg - // - pkg:golang/github.com/aquasecurity/go-module@2.0.0 - // - pkg:golang/github.com/aquasecurity/go-direct1@3.0.0 - // - pkg:golang/github.com/aquasecurity/go-transitive@5.0.0 - // - pkg:golang/github.com/aquasecurity/go-direct2@4.0.0 - // - pkg:golang/github.com/aquasecurity/go-transitive@5.0.0 + // - pkg:golang/github.com/aquasecurity/go-module@v2.0.0 + // - pkg:golang/github.com/aquasecurity/go-direct1@v3.0.0 + // - pkg:golang/github.com/aquasecurity/go-transitive@v5.0.0 + // - pkg:golang/github.com/aquasecurity/go-direct2@v4.0.0 + // - pkg:golang/github.com/aquasecurity/go-transitive@v5.0.0 goModule := clonePackage(goModulePackage) goDirect1 := clonePackage(goDirectPackage1) goDirect2 := clonePackage(goDirectPackage2) From 194d4abb03ba72a6f38287fa7c0e5bef6217c7bc Mon Sep 17 00:00:00 2001 From: simar7 <1254783+simar7@users.noreply.github.com> Date: Thu, 31 Oct 2024 00:37:21 -0600 Subject: [PATCH 165/183] chore(deps): Bump trivy-checks (#7819) --- go.mod | 8 +-- go.sum | 26 +++++---- integration/repo_test.go | 9 --- .../dockerfile-custom-policies.json.golden | 2 +- .../dockerfile-rule-exception.json.golden | 57 ------------------- integration/testdata/dockerfile.json.golden | 2 +- .../dockerfile_file_pattern.json.golden | 2 +- .../fixtures/repo/rule-exception/Dockerfile | 4 -- .../repo/rule-exception/policy/exception.rego | 15 ----- integration/testdata/helm.json.golden | 5 +- .../testdata/helm_testchart.json.golden | 9 +-- .../helm_testchart.overridden.json.golden | 9 +-- 12 files changed, 34 insertions(+), 114 deletions(-) delete mode 100644 integration/testdata/dockerfile-rule-exception.json.golden delete mode 100644 integration/testdata/fixtures/repo/rule-exception/Dockerfile delete mode 100644 integration/testdata/fixtures/repo/rule-exception/policy/exception.rego diff --git a/go.mod b/go.mod index efc9daa926c9..f4a034a8063a 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,7 @@ require ( github.com/aquasecurity/table v1.8.0 github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8 github.com/aquasecurity/tml v0.6.1 - github.com/aquasecurity/trivy-checks v1.1.0 + github.com/aquasecurity/trivy-checks v1.2.2 github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1 github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20241029051843-2606b7e0f0b4 @@ -124,7 +124,7 @@ require ( golang.org/x/mod v0.21.0 golang.org/x/net v0.29.0 golang.org/x/sync v0.8.0 - golang.org/x/term v0.24.0 + golang.org/x/term v0.25.0 golang.org/x/text v0.18.0 golang.org/x/vuln v1.1.3 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 @@ -385,7 +385,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect - golang.org/x/sys v0.25.0 // indirect + golang.org/x/sys v0.26.0 // indirect golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 // indirect golang.org/x/time v0.6.0 // indirect golang.org/x/tools v0.24.0 // indirect @@ -416,7 +416,7 @@ require ( modernc.org/memory v1.8.0 // indirect modernc.org/strutil v1.2.0 // indirect modernc.org/token v1.1.0 // indirect - mvdan.cc/sh/v3 v3.8.0 // indirect + mvdan.cc/sh/v3 v3.10.0 // indirect oras.land/oras-go v1.2.5 // indirect sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect sigs.k8s.io/kustomize/api v0.17.2 // indirect diff --git a/go.sum b/go.sum index 153c1ab02dea..5eadfbf83818 100644 --- a/go.sum +++ b/go.sum @@ -349,8 +349,8 @@ github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8 h1:b43UVqY github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8/go.mod h1:wXA9k3uuaxY3yu7gxrxZDPo/04FEMJtwyecdAlYrEIo= github.com/aquasecurity/tml v0.6.1 h1:y2ZlGSfrhnn7t4ZJ/0rotuH+v5Jgv6BDDO5jB6A9gwo= github.com/aquasecurity/tml v0.6.1/go.mod h1:OnYMWY5lvI9ejU7yH9LCberWaaTBW7hBFsITiIMY2yY= -github.com/aquasecurity/trivy-checks v1.1.0 h1:I0tVOK8dG/KHrWsqfGNYp2uD/i0f+yS7Je31F+LIUqQ= -github.com/aquasecurity/trivy-checks v1.1.0/go.mod h1:tVzhU0gajD3GmxKPLn/BHR8ZeUquc5ajQTmAsi0kCCU= +github.com/aquasecurity/trivy-checks v1.2.2 h1:EVHi0gthYzDLfqdAqBBwVGfg2l/gdZ622pIlC9rP+lU= +github.com/aquasecurity/trivy-checks v1.2.2/go.mod h1:TNV0QNVFyBIkt865eO2PtfpubmHt3Ve19Klny//SWIU= github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1 h1:G0gnacAORRUqz2Tm5MqivSpldY2GZ74ijhJcMsae+sA= github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1/go.mod h1:PYkSRx4dlgFATEt+okGwibvbxVEtqsOdH+vX/saACYE= github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 h1:JVgBIuIYbwG+ekC5lUHUpGJboPYiCcxiz06RCtz8neI= @@ -510,8 +510,8 @@ github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHf github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= -github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0= +github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/csaf-poc/csaf_distribution/v3 v3.0.0 h1:ob9+Fmpff0YWgTP3dYaw7G2hKQ9cegh9l3zksc+q3sM= github.com/csaf-poc/csaf_distribution/v3 v3.0.0/go.mod h1:uilCTiNKivq+6zrDvjtZaUeLk70oe21iwKivo6ILwlQ= github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 h1:2Dx4IHfC1yHWI12AxQDJM1QbRCDfk6M+blLzlZCXdrc= @@ -683,6 +683,8 @@ github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91 github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.18.0 h1:BvolUXjp4zuvkZ5YN5t7ebzbhlUtPsPm2S9NAZ5nl9U= github.com/go-playground/validator/v10 v10.18.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= +github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= @@ -1204,8 +1206,8 @@ github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII= +github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o= github.com/rubenv/sql-migrate v1.7.0 h1:HtQq1xyTN2ISmQDggnh0c9U3JlP8apWh8YO2jzlXpTI= github.com/rubenv/sql-migrate v1.7.0/go.mod h1:S4wtDEG1CKn+0ShpTtzWhFpHHI5PvCUtiGI+C+Z2THE= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -1703,8 +1705,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 h1:FemxDzfMUcK2f3YY4H+05K9CDzbSVr2+q/JKN45pey0= golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1715,8 +1717,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= -golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2124,8 +2126,8 @@ modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA= modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= -mvdan.cc/sh/v3 v3.8.0 h1:ZxuJipLZwr/HLbASonmXtcvvC9HXY9d2lXZHnKGjFc8= -mvdan.cc/sh/v3 v3.8.0/go.mod h1:w04623xkgBVo7/IUK89E0g8hBykgEpN0vgOj3RJr6MY= +mvdan.cc/sh/v3 v3.10.0 h1:v9z7N1DLZ7owyLM/SXZQkBSXcwr2IGMm2LY2pmhVXj4= +mvdan.cc/sh/v3 v3.10.0/go.mod h1:z/mSSVyLFGZzqb3ZIKojjyqIx/xbmz/UHdCSv9HmqXY= oras.land/oras-go v1.2.5 h1:XpYuAwAb0DfQsunIyMfeET92emK8km3W4yEzZvUbsTo= oras.land/oras-go v1.2.5/go.mod h1:PuAwRShRZCsZb7g8Ar3jKKQR/2A/qN+pkYxIOd/FAoo= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/integration/repo_test.go b/integration/repo_test.go index 6b4e3a338457..87c27684d3ab 100644 --- a/integration/repo_test.go +++ b/integration/repo_test.go @@ -300,15 +300,6 @@ func TestRepository(t *testing.T) { }, golden: "testdata/dockerfile_file_pattern.json.golden", }, - { - name: "dockerfile with rule exception", - args: args{ - scanner: types.MisconfigScanner, - policyPaths: []string{"testdata/fixtures/repo/rule-exception/policy"}, - input: "testdata/fixtures/repo/rule-exception", - }, - golden: "testdata/dockerfile-rule-exception.json.golden", - }, { name: "dockerfile with custom policies", args: args{ diff --git a/integration/testdata/dockerfile-custom-policies.json.golden b/integration/testdata/dockerfile-custom-policies.json.golden index 2cbda6f16703..64ce52ba64b3 100644 --- a/integration/testdata/dockerfile-custom-policies.json.golden +++ b/integration/testdata/dockerfile-custom-policies.json.golden @@ -21,7 +21,7 @@ "Class": "config", "Type": "dockerfile", "MisconfSummary": { - "Successes": 27, + "Successes": 28, "Failures": 2 }, "Misconfigurations": [ diff --git a/integration/testdata/dockerfile-rule-exception.json.golden b/integration/testdata/dockerfile-rule-exception.json.golden deleted file mode 100644 index eedcb902e145..000000000000 --- a/integration/testdata/dockerfile-rule-exception.json.golden +++ /dev/null @@ -1,57 +0,0 @@ -{ - "SchemaVersion": 2, - "CreatedAt": "2021-08-25T12:20:30.000000005Z", - "ArtifactName": "testdata/fixtures/repo/rule-exception", - "ArtifactType": "repository", - "Metadata": { - "ImageConfig": { - "architecture": "", - "created": "0001-01-01T00:00:00Z", - "os": "", - "rootfs": { - "type": "", - "diff_ids": null - }, - "config": {} - } - }, - "Results": [ - { - "Target": "Dockerfile", - "Class": "config", - "Type": "dockerfile", - "MisconfSummary": { - "Successes": 26, - "Failures": 1 - }, - "Misconfigurations": [ - { - "Type": "Dockerfile Security Check", - "ID": "DS002", - "AVDID": "AVD-DS-0002", - "Title": "Image user should not be 'root'", - "Description": "Running containers with 'root' user can lead to a container escape situation. It is a best practice to run containers as non-root users, which can be done by adding a 'USER' statement to the Dockerfile.", - "Message": "Specify at least 1 USER command in Dockerfile with non-root user as argument", - "Namespace": "builtin.dockerfile.DS002", - "Query": "data.builtin.dockerfile.DS002.deny", - "Resolution": "Add 'USER \u003cnon root user name\u003e' line to the Dockerfile", - "Severity": "HIGH", - "PrimaryURL": "https://avd.aquasec.com/misconfig/ds002", - "References": [ - "https://docs.docker.com/develop/develop-images/dockerfile_best-practices/", - "https://avd.aquasec.com/misconfig/ds002" - ], - "Status": "FAIL", - "Layer": {}, - "CauseMetadata": { - "Provider": "Dockerfile", - "Service": "general", - "Code": { - "Lines": null - } - } - } - ] - } - ] -} diff --git a/integration/testdata/dockerfile.json.golden b/integration/testdata/dockerfile.json.golden index 834b110404c1..fd1fcbfceec8 100644 --- a/integration/testdata/dockerfile.json.golden +++ b/integration/testdata/dockerfile.json.golden @@ -21,7 +21,7 @@ "Class": "config", "Type": "dockerfile", "MisconfSummary": { - "Successes": 26, + "Successes": 27, "Failures": 1 }, "Misconfigurations": [ diff --git a/integration/testdata/dockerfile_file_pattern.json.golden b/integration/testdata/dockerfile_file_pattern.json.golden index ed917023bc4b..adcd916456d5 100644 --- a/integration/testdata/dockerfile_file_pattern.json.golden +++ b/integration/testdata/dockerfile_file_pattern.json.golden @@ -21,7 +21,7 @@ "Class": "config", "Type": "dockerfile", "MisconfSummary": { - "Successes": 26, + "Successes": 27, "Failures": 1 }, "Misconfigurations": [ diff --git a/integration/testdata/fixtures/repo/rule-exception/Dockerfile b/integration/testdata/fixtures/repo/rule-exception/Dockerfile deleted file mode 100644 index 5bcf55456482..000000000000 --- a/integration/testdata/fixtures/repo/rule-exception/Dockerfile +++ /dev/null @@ -1,4 +0,0 @@ -FROM alpine:3.13 -LABEL user.root="allow" - -HEALTHCHECK NONE \ No newline at end of file diff --git a/integration/testdata/fixtures/repo/rule-exception/policy/exception.rego b/integration/testdata/fixtures/repo/rule-exception/policy/exception.rego deleted file mode 100644 index 224f626021e4..000000000000 --- a/integration/testdata/fixtures/repo/rule-exception/policy/exception.rego +++ /dev/null @@ -1,15 +0,0 @@ -package builtin.dockerfile.DS002 - -exception[rules] { - instruction := input.stages[_][_] - instruction.Cmd == "label" - - key := instruction.Value[i] - i % 2 == 0 - key == "user.root" - - value := instruction.Value[plus(i, 1)] - value == "\"allow\"" - - rules = [""] -} diff --git a/integration/testdata/helm.json.golden b/integration/testdata/helm.json.golden index 8b9ccb11bc9c..36ac8cf19935 100644 --- a/integration/testdata/helm.json.golden +++ b/integration/testdata/helm.json.golden @@ -21,7 +21,7 @@ "Class": "config", "Type": "helm", "MisconfSummary": { - "Successes": 80, + "Successes": 79, "Failures": 14 }, "Misconfigurations": [ @@ -889,10 +889,11 @@ "Namespace": "builtin.kubernetes.KSV117", "Query": "data.builtin.kubernetes.KSV117.deny", "Resolution": "Do not map the container ports to privileged host ports when starting a container.", - "Severity": "HIGH", + "Severity": "MEDIUM", "PrimaryURL": "https://avd.aquasec.com/misconfig/ksv117", "References": [ "https://kubernetes.io/docs/concepts/security/pod-security-standards/", + "https://www.stigviewer.com/stig/kubernetes/2022-12-02/finding/V-242414", "https://avd.aquasec.com/misconfig/ksv117" ], "Status": "FAIL", diff --git a/integration/testdata/helm_testchart.json.golden b/integration/testdata/helm_testchart.json.golden index 886b0a702496..478bcea3b672 100644 --- a/integration/testdata/helm_testchart.json.golden +++ b/integration/testdata/helm_testchart.json.golden @@ -21,7 +21,7 @@ "Class": "config", "Type": "helm", "MisconfSummary": { - "Successes": 90, + "Successes": 89, "Failures": 4 }, "Misconfigurations": [ @@ -317,10 +317,11 @@ "Namespace": "builtin.kubernetes.KSV117", "Query": "data.builtin.kubernetes.KSV117.deny", "Resolution": "Do not map the container ports to privileged host ports when starting a container.", - "Severity": "HIGH", + "Severity": "MEDIUM", "PrimaryURL": "https://avd.aquasec.com/misconfig/ksv117", "References": [ "https://kubernetes.io/docs/concepts/security/pod-security-standards/", + "https://www.stigviewer.com/stig/kubernetes/2022-12-02/finding/V-242414", "https://avd.aquasec.com/misconfig/ksv117" ], "Status": "FAIL", @@ -340,7 +341,7 @@ "Class": "config", "Type": "helm", "MisconfSummary": { - "Successes": 61, + "Successes": 60, "Failures": 0 } }, @@ -349,7 +350,7 @@ "Class": "config", "Type": "helm", "MisconfSummary": { - "Successes": 60, + "Successes": 59, "Failures": 0 } } diff --git a/integration/testdata/helm_testchart.overridden.json.golden b/integration/testdata/helm_testchart.overridden.json.golden index 354cb3cbf786..36710b35734e 100644 --- a/integration/testdata/helm_testchart.overridden.json.golden +++ b/integration/testdata/helm_testchart.overridden.json.golden @@ -21,7 +21,7 @@ "Class": "config", "Type": "helm", "MisconfSummary": { - "Successes": 88, + "Successes": 87, "Failures": 6 }, "Misconfigurations": [ @@ -544,10 +544,11 @@ "Namespace": "builtin.kubernetes.KSV117", "Query": "data.builtin.kubernetes.KSV117.deny", "Resolution": "Do not map the container ports to privileged host ports when starting a container.", - "Severity": "HIGH", + "Severity": "MEDIUM", "PrimaryURL": "https://avd.aquasec.com/misconfig/ksv117", "References": [ "https://kubernetes.io/docs/concepts/security/pod-security-standards/", + "https://www.stigviewer.com/stig/kubernetes/2022-12-02/finding/V-242414", "https://avd.aquasec.com/misconfig/ksv117" ], "Status": "FAIL", @@ -567,7 +568,7 @@ "Class": "config", "Type": "helm", "MisconfSummary": { - "Successes": 61, + "Successes": 60, "Failures": 0 } }, @@ -576,7 +577,7 @@ "Class": "config", "Type": "helm", "MisconfSummary": { - "Successes": 60, + "Successes": 59, "Failures": 0 } } From 7654b2e27e8af2d71586374d3a8c254d46f2416a Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Thu, 31 Oct 2024 15:04:52 +0600 Subject: [PATCH 166/183] docs: add example of creating whitelist of checks (#7821) Signed-off-by: nikpivkin --- docs/docs/configuration/filtering.md | 4 ++-- .../ignore-policies}/advanced.rego | 0 .../ignore-policies}/basic.rego | 0 examples/ignore-policies/whitelist.rego | 13 +++++++++++++ 4 files changed, 15 insertions(+), 2 deletions(-) rename {contrib/example_policy => examples/ignore-policies}/advanced.rego (100%) rename {contrib/example_policy => examples/ignore-policies}/basic.rego (100%) create mode 100644 examples/ignore-policies/whitelist.rego diff --git a/docs/docs/configuration/filtering.md b/docs/docs/configuration/filtering.md index 22fbe2d7a24d..095e5c3bb559 100644 --- a/docs/docs/configuration/filtering.md +++ b/docs/docs/configuration/filtering.md @@ -477,13 +477,13 @@ ignore { ``` ```bash -trivy image --ignore-policy contrib/example_policy/basic.rego centos:7 +trivy image --ignore-policy examples/ignore-policies/basic.rego centos:7 ``` For more advanced use cases, there is a built-in Rego library with helper functions that you can import into your policy using: `import data.lib.trivy`. More info about the helper functions are in the library [here](https://github.com/aquasecurity/trivy/tree/{{ git.tag }}/pkg/result/module.go). -You can find more example checks [here](https://github.com/aquasecurity/trivy/tree/{{ git.tag }}/pkg/result/module.go) +You can create a whitelist of checks using Rego, see the detailed [example](https://github.com/aquasecurity/trivy/tree/{{ git.tag }}/examples/ignore-policies/whitelist.rego). Additional examples are available [here](https://github.com/aquasecurity/trivy/tree/{{ git.tag }}/examples/ignore-policies). ### By Vulnerability Exploitability Exchange (VEX) | Scanner | Supported | diff --git a/contrib/example_policy/advanced.rego b/examples/ignore-policies/advanced.rego similarity index 100% rename from contrib/example_policy/advanced.rego rename to examples/ignore-policies/advanced.rego diff --git a/contrib/example_policy/basic.rego b/examples/ignore-policies/basic.rego similarity index 100% rename from contrib/example_policy/basic.rego rename to examples/ignore-policies/basic.rego diff --git a/examples/ignore-policies/whitelist.rego b/examples/ignore-policies/whitelist.rego new file mode 100644 index 000000000000..51a75c37c72f --- /dev/null +++ b/examples/ignore-policies/whitelist.rego @@ -0,0 +1,13 @@ +package trivy + +import rego.v1 + +allowed_checks := { + "AVD-AWS-0089" +} + +default ignore := false + +ignore if not is_check_allowed + +is_check_allowed if input.AVDID in allowed_checks \ No newline at end of file From dc44946881a9d1c1ef4e655114e9691e828b810d Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Thu, 31 Oct 2024 15:41:24 +0600 Subject: [PATCH 167/183] docs(java): add info about supported scopes (#7842) --- docs/docs/coverage/language/java.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/docs/coverage/language/java.md b/docs/docs/coverage/language/java.md index 0ee39bbd3155..30aca897670a 100644 --- a/docs/docs/coverage/language/java.md +++ b/docs/docs/coverage/language/java.md @@ -69,6 +69,9 @@ The vulnerability database will be downloaded anyway. !!! Warning Trivy may skip some dependencies (that were not found on your local machine) when the `--offline-scan` flag is passed. +### supported scopes +Trivy only scans `import`, `compile`, `runtime` and empty [maven scopes][maven-scopes]. Other scopes and `Optional` dependencies are not currently being analyzed. + ### empty dependency version There are cases when Trivy cannot determine the version of dependencies: @@ -128,6 +131,7 @@ Make sure that you have cache[^8] directory to find licenses from `*.pom` depend [maven-invoker-plugin]: https://maven.apache.org/plugins/maven-invoker-plugin/usage.html [maven-central]: https://repo.maven.apache.org/maven2/ [maven-pom-repos]: https://maven.apache.org/settings.html#repositories +[maven-scopes]: https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope [sbt-dependency-lock]: https://stringbean.github.io/sbt-dependency-lock [detection-priority]: ../../scanner/vulnerability.md#detection-priority [version-requirement]: https://maven.apache.org/pom.html#dependency-version-requirement-specification From 5e78b6c12fb5740c12dedeea3d335d48ec2f752b Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Thu, 31 Oct 2024 14:41:02 +0400 Subject: [PATCH 168/183] feat(db): append errors (#7843) Signed-off-by: knqyf263 --- pkg/oci/artifact.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pkg/oci/artifact.go b/pkg/oci/artifact.go index 416952578918..8ed7dcdad03d 100644 --- a/pkg/oci/artifact.go +++ b/pkg/oci/artifact.go @@ -12,6 +12,7 @@ import ( "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/remote/transport" + "github.com/hashicorp/go-multierror" "github.com/samber/lo" "golang.org/x/xerrors" @@ -224,6 +225,7 @@ func NewArtifacts(repos []name.Reference, opt types.RegistryOptions, opts ...Opt // Download downloads artifacts until one of them succeeds. // Attempts to download next artifact if the first one fails due to a temporary error. func (a Artifacts) Download(ctx context.Context, dst string, opt DownloadOption) error { + var errs error for i, art := range a { log.InfoContext(ctx, "Downloading artifact...", log.String("repo", art.repository)) err := art.Download(ctx, dst, opt) @@ -239,9 +241,10 @@ func (a Artifacts) Download(ctx context.Context, dst string, opt DownloadOption) if i < len(a)-1 { log.InfoContext(ctx, "Trying to download artifact from other repository...") } + errs = multierror.Append(errs, err) } - return xerrors.New("failed to download artifact from any source") + return xerrors.Errorf("failed to download artifact from any source: %w", errs) } func shouldTryOtherRepo(err error) bool { From 7632625be2c4aa6f18e286baa5466b3dd885dddc Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Thu, 31 Oct 2024 16:08:47 +0400 Subject: [PATCH 169/183] chore: lint `errors.Join` (#7845) Signed-off-by: knqyf263 --- misc/lint/rules.go | 10 ++++++++++ pkg/iac/scanners/cloudformation/parser/parser.go | 11 +++++------ pkg/iac/terraform/block.go | 15 ++++++++------- pkg/report/writer.go | 4 ++-- pkg/vex/repo/repo.go | 3 ++- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/misc/lint/rules.go b/misc/lint/rules.go index e477175a244f..4f1b098535ec 100644 --- a/misc/lint/rules.go +++ b/misc/lint/rules.go @@ -20,3 +20,13 @@ func initializeMaps(m dsl.Matcher) { Suggest(`make(map[$key]$value)`). Report(`replace '$$' with 'make(map[$key]$value)`) } + +// While errors.Join from standard library can combine multiple errors, +// we use hashicorp/go-multierror for more user-friendly error outputs. +func errorsJoin(m dsl.Matcher) { + m.Match(`errors.Join($x...)`). + Report("use github.com/hashicorp/go-multierror.Append instead of errors.Join.") + + m.Match(`errors.Join($*args)`). + Report("use github.com/hashicorp/go-multierror.Append instead of errors.Join.") +} diff --git a/pkg/iac/scanners/cloudformation/parser/parser.go b/pkg/iac/scanners/cloudformation/parser/parser.go index 40d0035f6cd2..696dfcf16349 100644 --- a/pkg/iac/scanners/cloudformation/parser/parser.go +++ b/pkg/iac/scanners/cloudformation/parser/parser.go @@ -3,13 +3,13 @@ package parser import ( "context" "encoding/json" - "errors" "fmt" "io" "io/fs" "path/filepath" "strings" + "github.com/hashicorp/go-multierror" "github.com/liamg/jfather" "gopkg.in/yaml.v3" @@ -171,18 +171,17 @@ func (p *Parser) parseParams() error { params := make(Parameters) - var errs []error - + var errs error for _, path := range p.parameterFiles { if parameters, err := p.parseParametersFile(path); err != nil { - errs = append(errs, err) + errs = multierror.Append(errs, err) } else { params.Merge(parameters) } } - if len(errs) != 0 { - return errors.Join(errs...) + if errs != nil { + return errs } params.Merge(p.parameters) diff --git a/pkg/iac/terraform/block.go b/pkg/iac/terraform/block.go index dd6d8446c124..348f938d4559 100644 --- a/pkg/iac/terraform/block.go +++ b/pkg/iac/terraform/block.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/google/uuid" + "github.com/hashicorp/go-multierror" "github.com/hashicorp/hcl/v2" "github.com/hashicorp/hcl/v2/hclsyntax" "github.com/zclconf/go-cty/cty" @@ -600,14 +601,14 @@ func (b *Block) IsNotNil() bool { func (b *Block) ExpandBlock() error { var ( expanded []*Block - errs []error + errs error ) for _, child := range b.childBlocks { if child.Type() == "dynamic" { blocks, err := child.expandDynamic() if err != nil { - errs = append(errs, err) + errs = multierror.Append(errs, err) continue } expanded = append(expanded, blocks...) @@ -618,7 +619,7 @@ func (b *Block) ExpandBlock() error { b.injectBlock(block) } - return errors.Join(errs...) + return errs } func (b *Block) expandDynamic() ([]*Block, error) { @@ -638,7 +639,7 @@ func (b *Block) expandDynamic() ([]*Block, error) { var ( expanded []*Block - errs []error + errs error ) forEachVal.ForEachElement(func(key, val cty.Value) (stop bool) { @@ -648,7 +649,7 @@ func (b *Block) expandDynamic() ([]*Block, error) { iteratorName, err := b.iteratorName(realBlockType) if err != nil { - errs = append(errs, err) + errs = multierror.Append(errs, err) return } @@ -664,7 +665,7 @@ func (b *Block) expandDynamic() ([]*Block, error) { inherited.hclBlock.Labels = []string{} inherited.hclBlock.Type = realBlockType if err := inherited.ExpandBlock(); err != nil { - errs = append(errs, err) + errs = multierror.Append(errs, err) return } expanded = append(expanded, inherited) @@ -676,7 +677,7 @@ func (b *Block) expandDynamic() ([]*Block, error) { b.markExpanded() } - return expanded, errors.Join(errs...) + return expanded, errs } func (b *Block) validateForEach() (cty.Value, error) { diff --git a/pkg/report/writer.go b/pkg/report/writer.go index a5b7ae231599..f25d579d66ef 100644 --- a/pkg/report/writer.go +++ b/pkg/report/writer.go @@ -2,10 +2,10 @@ package report import ( "context" - "errors" "io" "strings" + "github.com/hashicorp/go-multierror" "golang.org/x/xerrors" cr "github.com/aquasecurity/trivy/pkg/compliance/report" @@ -32,7 +32,7 @@ func Write(ctx context.Context, report types.Report, option flag.Options) (err e } defer func() { if cerr := cleanup(); cerr != nil { - err = errors.Join(err, cerr) + err = multierror.Append(err, cerr) } }() diff --git a/pkg/vex/repo/repo.go b/pkg/vex/repo/repo.go index 433b8224c20e..b9637c229ee9 100644 --- a/pkg/vex/repo/repo.go +++ b/pkg/vex/repo/repo.go @@ -11,6 +11,7 @@ import ( "time" "github.com/hashicorp/go-getter" + "github.com/hashicorp/go-multierror" "github.com/samber/lo" "golang.org/x/xerrors" @@ -256,7 +257,7 @@ func (r *Repository) download(ctx context.Context, ver Version, dst string, opts etag = etags[loc.URL] // Keep the old ETag // Update last updated time so that Trivy will not try to download the same URL soon case err != nil: - errs = errors.Join(errs, err) + errs = multierror.Append(errs, err) continue // Try the next location default: // Successfully downloaded From efec32669b79aba5ae61771e2d655e45e313ac2f Mon Sep 17 00:00:00 2001 From: Aqua Security automated builds <54269356+aqua-bot@users.noreply.github.com> Date: Fri, 1 Nov 2024 06:01:54 +0200 Subject: [PATCH 170/183] release: v0.57.0 [main] (#7710) --- .release-please-manifest.json | 2 +- CHANGELOG.md | 46 +++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 208746a81be3..0fd1f968a6d2 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1 +1 @@ -{".":"0.56.0"} +{".":"0.57.0"} diff --git a/CHANGELOG.md b/CHANGELOG.md index afc44ba7a956..f4bad92b11d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,51 @@ # Changelog +## [0.57.0](https://github.com/aquasecurity/trivy/compare/v0.56.0...v0.57.0) (2024-10-31) + + +### ⚠ BREAKING CHANGES + +* **k8s:** support k8s multi container ([#7444](https://github.com/aquasecurity/trivy/issues/7444)) + +### Features + +* add end of life date for Ubuntu 24.10 ([#7787](https://github.com/aquasecurity/trivy/issues/7787)) ([ad3c09e](https://github.com/aquasecurity/trivy/commit/ad3c09e006e134f3c5b879ffc34ce9895a8c860f)) +* **cli:** add `trivy auth` ([#7664](https://github.com/aquasecurity/trivy/issues/7664)) ([27117f8](https://github.com/aquasecurity/trivy/commit/27117f81d52483c3ceec56fe56ac298e242fbc9a)) +* **cli:** error out when ignore file cannot be found ([#7624](https://github.com/aquasecurity/trivy/issues/7624)) ([cb0b3a9](https://github.com/aquasecurity/trivy/commit/cb0b3a9279b31810ecd686a385e5140e567ce86f)) +* **cli:** rename `trivy auth` to `trivy registry` ([#7727](https://github.com/aquasecurity/trivy/issues/7727)) ([633a7ab](https://github.com/aquasecurity/trivy/commit/633a7abeea4287899392a24f2705f96dfeb7e312)) +* **cyclonedx:** add file checksums to `CycloneDX` reports ([#7507](https://github.com/aquasecurity/trivy/issues/7507)) ([c225883](https://github.com/aquasecurity/trivy/commit/c225883649f58128a99fa2c1cef327d0e57940be)) +* **db:** append errors ([#7843](https://github.com/aquasecurity/trivy/issues/7843)) ([5e78b6c](https://github.com/aquasecurity/trivy/commit/5e78b6c12fb5740c12dedeea3d335d48ec2f752b)) +* **misconf:** export unresolvable field of IaC types to Rego ([#7765](https://github.com/aquasecurity/trivy/issues/7765)) ([9514148](https://github.com/aquasecurity/trivy/commit/9514148767865baddd73a49245385574927f7a74)) +* **misconf:** public network support for Azure Storage Account ([#7601](https://github.com/aquasecurity/trivy/issues/7601)) ([ad91412](https://github.com/aquasecurity/trivy/commit/ad914123c4d203af1e1da6b7e2d3e49d9d3831d8)) +* **misconf:** Show misconfig ID in output ([#7762](https://github.com/aquasecurity/trivy/issues/7762)) ([f75c0d1](https://github.com/aquasecurity/trivy/commit/f75c0d1f0069d4856cb4826d6049f32c5b9409d9)) +* **misconf:** ssl_mode support for GCP SQL DB instance ([#7564](https://github.com/aquasecurity/trivy/issues/7564)) ([2eaa17e](https://github.com/aquasecurity/trivy/commit/2eaa17e0717940b27a79050e2efd9213b71178c9)) +* **parser:** ignore white space in pom.xml files ([#7747](https://github.com/aquasecurity/trivy/issues/7747)) ([a7baa93](https://github.com/aquasecurity/trivy/commit/a7baa93b00b8636aa097e64cdb8eed97dbd68511)) +* **report:** update gitlab template to populate operating_system value ([#7735](https://github.com/aquasecurity/trivy/issues/7735)) ([c0d79fa](https://github.com/aquasecurity/trivy/commit/c0d79fa09e645f3a3dbff878e393b8631fb17b64)) + + +### Bug Fixes + +* **cli:** `clean --all` deletes only relevant dirs ([#7704](https://github.com/aquasecurity/trivy/issues/7704)) ([672e886](https://github.com/aquasecurity/trivy/commit/672e886aed152ae0f09a16941706746f3053ca94)) +* **cli:** add config name to skip-policy-update alias ([#7820](https://github.com/aquasecurity/trivy/issues/7820)) ([b661d68](https://github.com/aquasecurity/trivy/commit/b661d680ff0372c8e4beea0db13bf69d6a2203a8)) +* **db:** fix javadb downloading error handling ([#7642](https://github.com/aquasecurity/trivy/issues/7642)) ([2c87f0c](https://github.com/aquasecurity/trivy/commit/2c87f0cb794acd77446a273582ba1a45b9f18980)) +* enable usestdlibvars linter ([#7770](https://github.com/aquasecurity/trivy/issues/7770)) ([57e24aa](https://github.com/aquasecurity/trivy/commit/57e24aa85382f749df7f673e241caaf3fcbb45cb)) +* **go:** Do not trim v prefix from versions in Go Mod Analyzer ([#7733](https://github.com/aquasecurity/trivy/issues/7733)) ([e872ec0](https://github.com/aquasecurity/trivy/commit/e872ec006c0745a5a142728af0096c6d6bb9ddf3)) +* **helm:** properly handle multiple archived dependencies ([#7782](https://github.com/aquasecurity/trivy/issues/7782)) ([6fab88d](https://github.com/aquasecurity/trivy/commit/6fab88dd56c257ef2cc63b617c2a5decb1c4cf98)) +* **java:** correctly inherit `version` and `scope` from upper/root `depManagement` and `dependencies` into parents ([#7541](https://github.com/aquasecurity/trivy/issues/7541)) ([778df82](https://github.com/aquasecurity/trivy/commit/778df828eaad9827cb833c6285058a33aa2b83ca)) +* **k8s:** skip resources without misconfigs ([#7797](https://github.com/aquasecurity/trivy/issues/7797)) ([7882776](https://github.com/aquasecurity/trivy/commit/78827768a612ab305bf9c55409ce76d6774302a5)) +* **k8s:** support k8s multi container ([#7444](https://github.com/aquasecurity/trivy/issues/7444)) ([c434775](https://github.com/aquasecurity/trivy/commit/c4347759234dcb5f372b07f92fb4230ef391d710)) +* **k8s:** support kubernetes v1.31 ([#7810](https://github.com/aquasecurity/trivy/issues/7810)) ([7a4f4d8](https://github.com/aquasecurity/trivy/commit/7a4f4d8b12996687f3095a2042cdf2f5985332c9)) +* **license:** fix license normalization for Universal Permissive License ([#7766](https://github.com/aquasecurity/trivy/issues/7766)) ([f6acdf7](https://github.com/aquasecurity/trivy/commit/f6acdf713991f8ffdbe765178fcb8a9cde433cba)) +* **misconf:** change default ACL of digitalocean_spaces_bucket to private ([#7577](https://github.com/aquasecurity/trivy/issues/7577)) ([9da84f5](https://github.com/aquasecurity/trivy/commit/9da84f54fadbe6ad0d73983952e945ed63b666f3)) +* **misconf:** check if property is not nil before conversion ([#7578](https://github.com/aquasecurity/trivy/issues/7578)) ([c8c14d3](https://github.com/aquasecurity/trivy/commit/c8c14d36245623019f29d258f813d2325f7490f7)) +* **misconf:** fix for Azure Storage Account network acls adaptation ([#7602](https://github.com/aquasecurity/trivy/issues/7602)) ([35fd018](https://github.com/aquasecurity/trivy/commit/35fd018ae7ad86823f114f0ac2f1376726aee444)) +* **misconf:** properly expand dynamic blocks ([#7612](https://github.com/aquasecurity/trivy/issues/7612)) ([8d5dbc9](https://github.com/aquasecurity/trivy/commit/8d5dbc9fec3569b22ed81a03c40eaf732768718b)) +* **redhat:** include arch in PURL qualifiers ([#7654](https://github.com/aquasecurity/trivy/issues/7654)) ([a585e95](https://github.com/aquasecurity/trivy/commit/a585e95f3398631d9ad10505c5ff642fde21aef7)) +* **repo:** `git clone` output to Stderr ([#7561](https://github.com/aquasecurity/trivy/issues/7561)) ([fdf203c](https://github.com/aquasecurity/trivy/commit/fdf203cd209aeb40f454bd12d121a54d6ed7a542)) +* **report:** Fix invalid URI in SARIF report ([#7645](https://github.com/aquasecurity/trivy/issues/7645)) ([015bb88](https://github.com/aquasecurity/trivy/commit/015bb885ac414b91201fa9791eead395d878149c)) +* **sbom:** add options for DBs in private registries ([#7660](https://github.com/aquasecurity/trivy/issues/7660)) ([1f2e91b](https://github.com/aquasecurity/trivy/commit/1f2e91b02b3606dd11963002a8cfac7962f3478f)) +* **sbom:** use `Annotation` instead of `AttributionTexts` for `SPDX` formats ([#7811](https://github.com/aquasecurity/trivy/issues/7811)) ([f2bb9c6](https://github.com/aquasecurity/trivy/commit/f2bb9c6227743dd61f44eb591d4b15192fe110c6)) + ## [0.56.0](https://github.com/aquasecurity/trivy/compare/v0.55.0...v0.56.0) (2024-10-03) From 4da59bd7b621366b05480cb84ee01786bc95f2fd Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Mon, 4 Nov 2024 10:01:05 +0400 Subject: [PATCH 171/183] chore: bump golangci-lint to v1.61.0 (#7853) Signed-off-by: knqyf263 --- .github/workflows/test.yaml | 2 +- .golangci.yaml | 1 + magefiles/magefile.go | 2 +- pkg/fanal/walker/walk_test.go | 19 ++++++++++++------- pkg/plugin/index.go | 2 +- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 05edadf93331..c2af5eb66bbb 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -42,7 +42,7 @@ jobs: id: lint uses: golangci/golangci-lint-action@v6.0.1 with: - version: v1.59 + version: v1.61 args: --verbose --out-format=line-number if: matrix.operating-system == 'ubuntu-latest' diff --git a/.golangci.yaml b/.golangci.yaml index 40bfa36e1a64..b6dbc299be20 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -68,6 +68,7 @@ linters-settings: excludes: - G101 - G114 + - G115 - G204 - G304 - G402 diff --git a/magefiles/magefile.go b/magefiles/magefile.go index f70491bce2e8..5b08e907f0c0 100644 --- a/magefiles/magefile.go +++ b/magefiles/magefile.go @@ -77,7 +77,7 @@ func (Tool) Wire() error { // GolangciLint installs golangci-lint func (t Tool) GolangciLint() error { - const version = "v1.59.1" + const version = "v1.61.0" bin := filepath.Join(GOBIN, "golangci-lint") if exists(bin) && t.matchGolangciLintVersion(bin, version) { return nil diff --git a/pkg/fanal/walker/walk_test.go b/pkg/fanal/walker/walk_test.go index 09d55527c0fe..3c066529393f 100644 --- a/pkg/fanal/walker/walk_test.go +++ b/pkg/fanal/walker/walk_test.go @@ -1,7 +1,6 @@ package walker_test import ( - "fmt" "path/filepath" "testing" @@ -42,8 +41,11 @@ func TestSkipFile(t *testing.T) { }, }, { - name: "multiple skip files", - skipFiles: []string{"/etc/*/*", "/var/log/*.txt"}, + name: "multiple skip files", + skipFiles: []string{ + "/etc/*/*", + "/var/log/*.txt", + }, wants: map[string]bool{ "/etc/foo": false, "/etc/foo/bar": true, @@ -65,7 +67,7 @@ func TestSkipFile(t *testing.T) { for file, want := range tt.wants { file = filepath.ToSlash(filepath.Clean(file)) got := utils.SkipPath(file, utils.CleanSkipPaths(tt.skipFiles)) - assert.Equal(t, want, got, fmt.Sprintf("skipFiles: %s, file: %s", tt.skipFiles, file)) + assert.Equal(t, want, got, "skipFiles: %s, file: %s", tt.skipFiles, file) } }) } @@ -108,8 +110,11 @@ func TestSkipDir(t *testing.T) { }, }, { - name: "multiple dirs", - skipDirs: []string{"/etc/*/*", "/var/log/*"}, + name: "multiple dirs", + skipDirs: []string{ + "/etc/*/*", + "/var/log/*", + }, wants: map[string]bool{ "/etc/foo": false, "/etc/foo/bar": true, @@ -139,7 +144,7 @@ func TestSkipDir(t *testing.T) { for dir, want := range tt.wants { dir = filepath.ToSlash(filepath.Clean(dir)) got := utils.SkipPath(dir, utils.CleanSkipPaths(tt.skipDirs)) - assert.Equal(t, want, got, fmt.Sprintf("defaultSkipDirs: %s, dir: %s", tt.skipDirs, dir)) + assert.Equal(t, want, got, "defaultSkipDirs: %s, dir: %s", tt.skipDirs, dir) } }) } diff --git a/pkg/plugin/index.go b/pkg/plugin/index.go index 57c6f0260877..82e4cb076356 100644 --- a/pkg/plugin/index.go +++ b/pkg/plugin/index.go @@ -61,7 +61,7 @@ func (m *Manager) Search(ctx context.Context, keyword string) error { } } - if _, err = fmt.Fprintf(m.w, buf.String()); err != nil { + if _, err = fmt.Fprint(m.w, buf.String()); err != nil { return err } From a9b557d9ddb863cee4bb60130f62521875356796 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 4 Nov 2024 10:11:06 +0400 Subject: [PATCH 172/183] chore(deps): bump the github-actions group across 1 directory with 2 updates (#7854) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/reusable-release.yaml | 2 +- .github/workflows/test.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-release.yaml b/.github/workflows/reusable-release.yaml index 0f7064ee18e1..54fa746f768f 100644 --- a/.github/workflows/reusable-release.yaml +++ b/.github/workflows/reusable-release.yaml @@ -28,7 +28,7 @@ jobs: contents: read # Not required for public repositories, but for clarity steps: - name: Cosign install - uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 + uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da - name: Set up QEMU uses: docker/setup-qemu-action@v3 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index c2af5eb66bbb..1113a6a3a894 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -40,7 +40,7 @@ jobs: - name: Lint id: lint - uses: golangci/golangci-lint-action@v6.0.1 + uses: golangci/golangci-lint-action@v6.1.1 with: version: v1.61 args: --verbose --out-format=line-number From a6a45b346aede67af44e96c7b2b9abad1826890c Mon Sep 17 00:00:00 2001 From: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com> Date: Mon, 4 Nov 2024 12:14:05 +0600 Subject: [PATCH 173/183] test: save `containerd` image into archive and use in tests (#7816) --- .github/workflows/cache-test-images.yaml | 4 +- .github/workflows/test.yaml | 6 +- magefiles/fixture.go | 55 +++++++++++++------ pkg/fanal/test/integration/containerd_test.go | 7 ++- 4 files changed, 49 insertions(+), 23 deletions(-) diff --git a/.github/workflows/cache-test-images.yaml b/.github/workflows/cache-test-images.yaml index 4b73cc2fb5bc..dd3a76d10638 100644 --- a/.github/workflows/cache-test-images.yaml +++ b/.github/workflows/cache-test-images.yaml @@ -29,7 +29,7 @@ jobs: run: | source integration/testimages.ini IMAGE_LIST=$(skopeo list-tags docker://$TEST_IMAGES) - DIGEST=$(echo "$IMAGE_LIST" | sha256sum | cut -d' ' -f1) + DIGEST=$(echo "$IMAGE_LIST" | jq '.Tags += ["containerd"] | .Tags | sort' | sha256sum | cut -d' ' -f1) echo "digest=$DIGEST" >> $GITHUB_OUTPUT ## We need to work with test image cache only for main branch @@ -70,7 +70,7 @@ jobs: run: | source integration/testimages.ini IMAGE_LIST=$(skopeo list-tags docker://$TEST_VM_IMAGES) - DIGEST=$(echo "$IMAGE_LIST" | sha256sum | cut -d' ' -f1) + DIGEST=$(echo "$IMAGE_LIST" | jq '.Tags | sort' | sha256sum | cut -d' ' -f1) echo "digest=$DIGEST" >> $GITHUB_OUTPUT ## We need to work with test VM image cache only for main branch diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 1113a6a3a894..9c6c2f10ffba 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -93,7 +93,7 @@ jobs: run: | source integration/testimages.ini IMAGE_LIST=$(skopeo list-tags docker://$TEST_IMAGES) - DIGEST=$(echo "$IMAGE_LIST" | sha256sum | cut -d' ' -f1) + DIGEST=$(echo "$IMAGE_LIST" | jq '.Tags += ["containerd"] | .Tags | sort' | sha256sum | cut -d' ' -f1) echo "digest=$DIGEST" >> $GITHUB_OUTPUT - name: Restore test images from cache @@ -151,7 +151,7 @@ jobs: run: | source integration/testimages.ini IMAGE_LIST=$(skopeo list-tags docker://$TEST_IMAGES) - DIGEST=$(echo "$IMAGE_LIST" | sha256sum | cut -d' ' -f1) + DIGEST=$(echo "$IMAGE_LIST" | jq '.Tags += ["containerd"] | .Tags | sort' | sha256sum | cut -d' ' -f1) echo "digest=$DIGEST" >> $GITHUB_OUTPUT - name: Restore test images from cache @@ -190,7 +190,7 @@ jobs: run: | source integration/testimages.ini IMAGE_LIST=$(skopeo list-tags docker://$TEST_VM_IMAGES) - DIGEST=$(echo "$IMAGE_LIST" | sha256sum | cut -d' ' -f1) + DIGEST=$(echo "$IMAGE_LIST" | jq '.Tags | sort' | sha256sum | cut -d' ' -f1) echo "digest=$DIGEST" >> $GITHUB_OUTPUT - name: Restore test VM images from cache diff --git a/magefiles/fixture.go b/magefiles/fixture.go index 0112a8421133..e7a2c395157e 100644 --- a/magefiles/fixture.go +++ b/magefiles/fixture.go @@ -14,9 +14,11 @@ import ( "github.com/aquasecurity/trivy/internal/testutil" ) +const dir = "integration/testdata/fixtures/images/" + func fixtureContainerImages() error { var testImages = testutil.ImageName("", "", "") - const dir = "integration/testdata/fixtures/images/" + if err := os.MkdirAll(dir, 0750); err != nil { return err } @@ -24,26 +26,45 @@ func fixtureContainerImages() error { if err != nil { return err } + // Save all tags for trivy-test-images for _, tag := range tags { - fileName := tag + ".tar.gz" - filePath := filepath.Join(dir, fileName) - if exists(filePath) { - continue - } - fmt.Printf("Downloading %s...\n", tag) - imgName := fmt.Sprintf("%s:%s", testImages, tag) - img, err := crane.Pull(imgName) - if err != nil { - return err - } - tarPath := strings.TrimSuffix(filePath, ".gz") - if err = crane.Save(img, imgName, tarPath); err != nil { - return err - } - if err = sh.Run("gzip", tarPath); err != nil { + if err := saveImage("", tag); err != nil { return err } } + + // Save trivy-test-images/containerd image + if err := saveImage("containerd", "latest"); err != nil { + return err + } + return nil +} + +func saveImage(subpath, tag string) error { + fileName := tag + ".tar.gz" + imgName := testutil.ImageName("", tag, "") + if subpath != "" { + fileName = subpath + ".tar.gz" + imgName = testutil.ImageName(subpath, "", "") + } + filePath := filepath.Join(dir, fileName) + if exists(filePath) { + return nil + } + fmt.Printf("Downloading %s...\n", imgName) + + img, err := crane.Pull(imgName) + if err != nil { + return err + } + tarPath := strings.TrimSuffix(filePath, ".gz") + if err = crane.Save(img, imgName, tarPath); err != nil { + return err + } + if err = sh.Run("gzip", tarPath); err != nil { + return err + } + return nil } diff --git a/pkg/fanal/test/integration/containerd_test.go b/pkg/fanal/test/integration/containerd_test.go index 568af60528ea..420949cd42d3 100644 --- a/pkg/fanal/test/integration/containerd_test.go +++ b/pkg/fanal/test/integration/containerd_test.go @@ -76,9 +76,14 @@ func setupContainerd(t *testing.T, ctx context.Context, namespace string) *conta func startContainerd(t *testing.T, ctx context.Context, hostPath string) { t.Helper() t.Setenv("TESTCONTAINERS_RYUK_DISABLED", "true") + + // Load `containerd` image from tar file to avoid fetching it from remote registry + cli := testutil.NewDockerClient(t) + loadedImage := cli.ImageLoad(t, ctx, "../../../../integration/testdata/fixtures/images/containerd.tar.gz") + req := testcontainers.ContainerRequest{ Name: "containerd", - Image: testutil.ImageName("containerd", "latest", ""), + Image: loadedImage, Entrypoint: []string{ "/bin/sh", "-c", From 2529b58d4db8e73af977bbb601f966d9821c2367 Mon Sep 17 00:00:00 2001 From: Yeates Date: Tue, 5 Nov 2024 13:39:47 +0800 Subject: [PATCH 174/183] refactor(secret): optimize performance by moving ToLower operation outside loop (#7862) --- pkg/fanal/secret/scanner.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/fanal/secret/scanner.go b/pkg/fanal/secret/scanner.go index 33a3806f41b4..01283ea42a46 100644 --- a/pkg/fanal/secret/scanner.go +++ b/pkg/fanal/secret/scanner.go @@ -175,9 +175,9 @@ func (r *Rule) MatchKeywords(content []byte) bool { if len(r.Keywords) == 0 { return true } - + var contentLower = bytes.ToLower(content) for _, kw := range r.Keywords { - if bytes.Contains(bytes.ToLower(content), []byte(strings.ToLower(kw))) { + if bytes.Contains(contentLower, []byte(strings.ToLower(kw))) { return true } } From ed2288f1e7b1195db179191e51a1952272c2c064 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 05:40:34 +0000 Subject: [PATCH 175/183] chore(deps): bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1 (#7868) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index f4a034a8063a..fced18a28f4d 100644 --- a/go.mod +++ b/go.mod @@ -247,7 +247,7 @@ require ( github.com/goccy/go-yaml v1.9.5 // indirect github.com/gofrs/uuid v4.3.1+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/golang/snappy v0.0.4 // indirect diff --git a/go.sum b/go.sum index 5eadfbf83818..f116a5db3505 100644 --- a/go.sum +++ b/go.sum @@ -710,8 +710,9 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= +github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= From b1c7f5516fc39c6cbb76cbeae5c8677ccc9ce5dd Mon Sep 17 00:00:00 2001 From: afdesk Date: Wed, 6 Nov 2024 04:58:01 +0600 Subject: [PATCH 176/183] feat(k8s): add default commands for unknown platform (#7863) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index fced18a28f4d..c7bb5f608c47 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/aquasecurity/trivy-checks v1.2.2 github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1 github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 - github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20241029051843-2606b7e0f0b4 + github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20241101182546-89bffc3932bc github.com/aws/aws-sdk-go-v2 v1.31.0 github.com/aws/aws-sdk-go-v2/config v1.27.38 github.com/aws/aws-sdk-go-v2/credentials v1.17.36 diff --git a/go.sum b/go.sum index f116a5db3505..991cad7e2929 100644 --- a/go.sum +++ b/go.sum @@ -355,8 +355,8 @@ github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1 h1:G0gnacAOR github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1/go.mod h1:PYkSRx4dlgFATEt+okGwibvbxVEtqsOdH+vX/saACYE= github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 h1:JVgBIuIYbwG+ekC5lUHUpGJboPYiCcxiz06RCtz8neI= github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48/go.mod h1:Ldya37FLi0e/5Cjq2T5Bty7cFkzUDwTcPeQua+2M8i8= -github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20241029051843-2606b7e0f0b4 h1:i0Z0JS4xtMAcBVOpYSciS7slmIBi1SmjT6garbrJtcA= -github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20241029051843-2606b7e0f0b4/go.mod h1:ctlibFXOQyjWybeVVQI6NLG6GJoPWZJ4cIirQ/wPCQs= +github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20241101182546-89bffc3932bc h1:/mFBYIK9RY+L8s1CIbQbJ5B3v0YmoDSu5eAzavvMa+Y= +github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20241101182546-89bffc3932bc/go.mod h1:ctlibFXOQyjWybeVVQI6NLG6GJoPWZJ4cIirQ/wPCQs= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= From eda4d7660d8908705bc08a6edc55d8144d02806a Mon Sep 17 00:00:00 2001 From: Ben Foster Date: Wed, 6 Nov 2024 01:31:23 -0500 Subject: [PATCH 177/183] fix: Improve version comparisons when build identifiers are present (#7873) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c7bb5f608c47..93acd5cf9334 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798 github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 - github.com/aquasecurity/go-version v0.0.0-20240603093900-cf8a8d29271d + github.com/aquasecurity/go-version v0.0.0-20241105054539-1951e80d786f github.com/aquasecurity/table v1.8.0 github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8 github.com/aquasecurity/tml v0.6.1 diff --git a/go.sum b/go.sum index 991cad7e2929..f2112b2721ef 100644 --- a/go.sum +++ b/go.sum @@ -341,8 +341,8 @@ github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 h1: github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46/go.mod h1:olhPNdiiAAMiSujemd1O/sc6GcyePr23f/6uGKtthNg= github.com/aquasecurity/go-version v0.0.0-20201107203531-5e48ac5d022a/go.mod h1:9Beu8XsUNNfzml7WBf3QmyPToP1wm1Gj/Vc5UJKqTzU= github.com/aquasecurity/go-version v0.0.0-20210121072130-637058cfe492/go.mod h1:9Beu8XsUNNfzml7WBf3QmyPToP1wm1Gj/Vc5UJKqTzU= -github.com/aquasecurity/go-version v0.0.0-20240603093900-cf8a8d29271d h1:4zour5Sh9chOg+IqIinIcJ3qtr3cIf8FdFY6aArlXBw= -github.com/aquasecurity/go-version v0.0.0-20240603093900-cf8a8d29271d/go.mod h1:1cPOp4BaQZ1G2F5fnw4dFz6pkOyXJI9KTuak8ghIl3U= +github.com/aquasecurity/go-version v0.0.0-20241105054539-1951e80d786f h1:6mwfszC0VohA3NF75EX8pPStmmL0spZnTlkLp83M69c= +github.com/aquasecurity/go-version v0.0.0-20241105054539-1951e80d786f/go.mod h1:1cPOp4BaQZ1G2F5fnw4dFz6pkOyXJI9KTuak8ghIl3U= github.com/aquasecurity/table v1.8.0 h1:9ntpSwrUfjrM6/YviArlx/ZBGd6ix8W+MtojQcM7tv0= github.com/aquasecurity/table v1.8.0/go.mod h1:eqOmvjjB7AhXFgFqpJUEE/ietg7RrMSJZXyTN8E/wZw= github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8 h1:b43UVqYjz7qDqK+cVOtF2Lk6CxjytYItP6Pgf3wGsNE= From 6e3252b1d314ddcb4904e6f98abb8ac1e3d3cc94 Mon Sep 17 00:00:00 2001 From: Teppei Fukuda Date: Wed, 6 Nov 2024 11:32:43 +0400 Subject: [PATCH 178/183] chore: bump containerd to v2.0.0 (#7875) Signed-off-by: knqyf263 --- go.mod | 78 ++++---- go.sum | 180 ++++++++++-------- pkg/fanal/image/daemon/containerd.go | 56 +++--- pkg/fanal/test/integration/containerd_test.go | 19 +- 4 files changed, 180 insertions(+), 153 deletions(-) diff --git a/go.mod b/go.mod index 93acd5cf9334..566d5069c0b9 100644 --- a/go.mod +++ b/go.mod @@ -41,8 +41,10 @@ require ( github.com/bmatcuk/doublestar/v4 v4.6.1 github.com/cenkalti/backoff/v4 v4.3.0 github.com/cheggaaa/pb/v3 v3.1.5 - github.com/containerd/containerd v1.7.22 + github.com/containerd/containerd/v2 v2.0.0 + github.com/containerd/platforms v1.0.0-rc.0 github.com/csaf-poc/csaf_distribution/v3 v3.0.0 + github.com/distribution/reference v0.6.0 github.com/docker/cli v27.2.1+incompatible github.com/docker/docker v27.3.1+incompatible github.com/docker/go-connections v0.5.0 @@ -119,16 +121,16 @@ require ( github.com/zclconf/go-cty v1.15.0 github.com/zclconf/go-cty-yaml v1.0.3 go.etcd.io/bbolt v1.3.11 - golang.org/x/crypto v0.27.0 - golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa // indirect + golang.org/x/crypto v0.28.0 + golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 // indirect golang.org/x/mod v0.21.0 - golang.org/x/net v0.29.0 + golang.org/x/net v0.30.0 golang.org/x/sync v0.8.0 golang.org/x/term v0.25.0 - golang.org/x/text v0.18.0 + golang.org/x/text v0.19.0 golang.org/x/vuln v1.1.3 golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 - google.golang.org/protobuf v1.34.2 + google.golang.org/protobuf v1.35.1 gopkg.in/yaml.v3 v3.0.1 helm.sh/helm/v3 v3.16.1 k8s.io/api v0.31.2 @@ -139,12 +141,12 @@ require ( require ( cloud.google.com/go v0.112.1 // indirect - cloud.google.com/go/compute/metadata v0.3.0 // indirect + cloud.google.com/go/compute/metadata v0.5.0 // indirect cloud.google.com/go/iam v1.1.6 // indirect cloud.google.com/go/storage v1.39.1 // indirect dario.cat/mergo v1.0.1 // indirect - github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect - github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 // indirect + github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 // indirect + github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20231105174938-2b5cbb29f3e2 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 // indirect github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/Azure/go-autorest v14.2.0+incompatible // indirect @@ -162,7 +164,7 @@ require ( github.com/Masterminds/semver/v3 v3.3.0 // indirect github.com/Masterminds/squirrel v1.5.4 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/Microsoft/hcsshim v0.12.0 // indirect + github.com/Microsoft/hcsshim v0.12.9 // indirect github.com/OneOfOne/xxhash v1.2.8 // indirect github.com/ProtonMail/go-crypto v1.1.0-alpha.2 // indirect github.com/VividCortex/ewma v1.2.0 // indirect @@ -191,29 +193,29 @@ require ( github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect github.com/cloudflare/circl v1.3.8 // indirect - github.com/containerd/cgroups/v3 v3.0.2 // indirect - github.com/containerd/containerd/api v1.7.19 // indirect - github.com/containerd/continuity v0.4.3 // indirect - github.com/containerd/errdefs v0.1.0 // indirect + github.com/containerd/cgroups/v3 v3.0.3 // indirect + github.com/containerd/containerd v1.7.23 // indirect + github.com/containerd/containerd/api v1.8.0 // indirect + github.com/containerd/continuity v0.4.4 // indirect + github.com/containerd/errdefs v1.0.0 // indirect + github.com/containerd/errdefs/pkg v0.3.0 // indirect github.com/containerd/fifo v1.1.0 // indirect github.com/containerd/log v0.1.0 // indirect - github.com/containerd/platforms v0.2.1 // indirect + github.com/containerd/plugin v1.0.0 // indirect github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect - github.com/containerd/ttrpc v1.2.5 // indirect - github.com/containerd/typeurl/v2 v2.2.0 // indirect + github.com/containerd/ttrpc v1.2.6 // indirect + github.com/containerd/typeurl/v2 v2.2.2 // indirect github.com/cpuguy83/dockercfg v0.3.1 // indirect - github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect + github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 // indirect github.com/cyphar/filepath-securejoin v0.3.1 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect - github.com/distribution/reference v0.6.0 // indirect github.com/dlclark/regexp2 v1.4.0 // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.2 // indirect - github.com/docker/go-events v0.0.0-20190806004212-e31b211e4f1c // indirect github.com/docker/go-metrics v0.0.1 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 // indirect @@ -281,7 +283,7 @@ require ( github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect - github.com/klauspost/compress v1.17.9 // indirect + github.com/klauspost/compress v1.17.11 // indirect github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect github.com/letsencrypt/boulder v0.0.0-20231026200631-000cd05d5491 // indirect @@ -303,7 +305,7 @@ require ( github.com/moby/patternmatcher v0.6.0 // indirect github.com/moby/spdystream v0.4.0 // indirect github.com/moby/sys/mountinfo v0.7.2 // indirect - github.com/moby/sys/sequential v0.5.0 // indirect + github.com/moby/sys/sequential v0.6.0 // indirect github.com/moby/sys/signal v0.7.1 // indirect github.com/moby/sys/user v0.3.0 // indirect github.com/moby/sys/userns v0.1.0 // indirect @@ -318,16 +320,17 @@ require ( github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect github.com/oklog/ulid v1.3.1 // indirect github.com/opencontainers/runtime-spec v1.2.0 // indirect - github.com/opencontainers/selinux v1.11.0 // indirect + github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 // indirect + github.com/opencontainers/selinux v1.11.1 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect - github.com/pelletier/go-toml/v2 v2.2.2 // indirect + github.com/pelletier/go-toml/v2 v2.2.3 // indirect github.com/peterbourgon/diskv v2.0.1+incompatible // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect - github.com/prometheus/client_golang v1.20.2 // indirect + github.com/prometheus/client_golang v1.20.5 // indirect github.com/prometheus/client_model v0.6.1 // indirect github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect @@ -353,6 +356,7 @@ require ( github.com/spf13/afero v1.11.0 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/subosito/gotenv v1.6.0 // indirect + github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 // indirect github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d // indirect github.com/tchap/go-patricia/v2 v2.3.1 // indirect github.com/theupdateframework/go-tuf v0.7.0 // indirect @@ -375,25 +379,25 @@ require ( github.com/yusufpapurcu/wmi v1.2.4 // indirect go.mongodb.org/mongo-driver v1.14.0 // indirect go.opencensus.io v0.24.0 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/sdk v1.28.0 // indirect - go.opentelemetry.io/otel/trace v1.28.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect + go.opentelemetry.io/otel v1.31.0 // indirect + go.opentelemetry.io/otel/metric v1.31.0 // indirect + go.opentelemetry.io/otel/sdk v1.31.0 // indirect + go.opentelemetry.io/otel/trace v1.31.0 // indirect go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/oauth2 v0.22.0 // indirect golang.org/x/sys v0.26.0 // indirect golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 // indirect golang.org/x/time v0.6.0 // indirect golang.org/x/tools v0.24.0 // indirect google.golang.org/api v0.172.0 // indirect google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 // indirect - google.golang.org/grpc v1.66.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 // indirect + google.golang.org/grpc v1.67.1 // indirect gopkg.in/cheggaaa/pb.v1 v1.0.28 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect @@ -403,7 +407,7 @@ require ( gopkg.in/yaml.v2 v2.4.0 // indirect k8s.io/apiextensions-apiserver v0.31.0 // indirect k8s.io/apimachinery v0.31.2 // indirect - k8s.io/apiserver v0.31.0 // indirect + k8s.io/apiserver v0.31.2 // indirect k8s.io/cli-runtime v0.31.2 // indirect k8s.io/client-go v0.31.2 // indirect k8s.io/component-base v0.31.2 // indirect @@ -422,4 +426,6 @@ require ( sigs.k8s.io/kustomize/api v0.17.2 // indirect sigs.k8s.io/kustomize/kyaml v0.17.1 // indirect sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + tags.cncf.io/container-device-interface v0.8.0 // indirect + tags.cncf.io/container-device-interface/specs-go v0.8.0 // indirect ) diff --git a/go.sum b/go.sum index f2112b2721ef..7618669c665c 100644 --- a/go.sum +++ b/go.sum @@ -68,8 +68,8 @@ cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/compute v1.10.0/go.mod h1:ER5CLbMxl90o2jtNbGSbtfOpQKR0t15FOtRsugnLrlU= -cloud.google.com/go/compute/metadata v0.3.0 h1:Tz+eQXMEqDIKRsmY3cHTL6FVaynIjX2QxYC4trgAKZc= -cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k= +cloud.google.com/go/compute/metadata v0.5.0 h1:Zr0eK8JbFv6+Wi4ilXAR8FJ3wyNdpxHKJNPos6LTZOY= +cloud.google.com/go/compute/metadata v0.5.0/go.mod h1:aHnloV2TPI38yx4s9+wAZhHykWvVCfu7hQbF+9CWoiY= cloud.google.com/go/containeranalysis v0.5.1/go.mod h1:1D92jd8gRR/c0fGMlymRgxWD3Qw9C1ff6/T7mLgVL8I= cloud.google.com/go/containeranalysis v0.6.0/go.mod h1:HEJoiEIu+lEXM+k7+qLCci0h33lX3ZqoYFdmPcoO7s4= cloud.google.com/go/datacatalog v1.3.0/go.mod h1:g9svFY6tuR+j+hrTw3J2dNcmI0dzmSiyOzm8kpLq0a0= @@ -193,10 +193,10 @@ dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= -github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= -github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0 h1:59MxjQVfjXsBpLy+dbd2/ELV5ofnUkUZBvWSC85sheA= -github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20230306123547-8075edf89bb0/go.mod h1:OahwfttHWG6eJ0clwcfBAHoDI6X/LV/15hx/wlMZSrU= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk= +github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= +github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20231105174938-2b5cbb29f3e2 h1:dIScnXFlF784X79oi7MzVT6GWqr/W1uUt0pB5CsDs9M= +github.com/AdamKorcz/go-118-fuzz-build v0.0.0-20231105174938-2b5cbb29f3e2/go.mod h1:gCLVsLfv1egrcZu+GoJATN5ts75F2s62ih/457eWzOw= github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d h1:zjqpY4C7H15HjRPEenkS4SAn3Jy2eRRjkjZbGR30TOg= github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d/go.mod h1:XNqJ7hv2kY++g8XEHREpi+JqZo3+0l+CH2egBVN4yqM= github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0 h1:8+4G8JaejP8Xa6W46PzJEwisNgBXMvFcz78N6zG/ARw= @@ -266,8 +266,8 @@ github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA4 github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/Microsoft/hcsshim v0.12.0 h1:rbICA+XZFwrBef2Odk++0LjFvClNCJGRK+fsrP254Ts= -github.com/Microsoft/hcsshim v0.12.0/go.mod h1:RZV12pcHCXQ42XnlQ3pz6FZfmrC1C+R4gaOHhRNML1g= +github.com/Microsoft/hcsshim v0.12.9 h1:2zJy5KA+l0loz1HzEGqyNnjd3fyZA31ZBCGKacp6lLg= +github.com/Microsoft/hcsshim v0.12.9/go.mod h1:fJ0gkFAna6ukt0bLdKB8djt4XIJhF/vEPuoIWYVvZ8Y= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= @@ -480,36 +480,43 @@ github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb h1:EDmT6Q9Zs+SbUo github.com/codahale/rfc6979 v0.0.0-20141003034818-6a90f24967eb/go.mod h1:ZjrT6AXHbDs86ZSdt/osfBi5qfexBrKUdONk989Wnk4= github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be h1:J5BL2kskAlV9ckgEsNQXscjIaLiOYiZ75d4e94E6dcQ= github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be/go.mod h1:mk5IQ+Y0ZeO87b858TlA645sVcEcbiX6YqP98kt+7+w= -github.com/containerd/cgroups/v3 v3.0.2 h1:f5WFqIVSgo5IZmtTT3qVBo6TzI1ON6sycSBKkymb9L0= -github.com/containerd/cgroups/v3 v3.0.2/go.mod h1:JUgITrzdFqp42uI2ryGA+ge0ap/nxzYgkGmIcetmErE= -github.com/containerd/containerd v1.7.22 h1:nZuNnNRA6T6jB975rx2RRNqqH2k6ELYKDZfqTHqwyy0= -github.com/containerd/containerd v1.7.22/go.mod h1:e3Jz1rYRUZ2Lt51YrH9Rz0zPyJBOlSvB3ghr2jbVD8g= -github.com/containerd/containerd/api v1.7.19 h1:VWbJL+8Ap4Ju2mx9c9qS1uFSB1OVYr5JJrW2yT5vFoA= -github.com/containerd/containerd/api v1.7.19/go.mod h1:fwGavl3LNwAV5ilJ0sbrABL44AQxmNjDRcwheXDb6Ig= -github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= -github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= -github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM= -github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0= +github.com/containerd/cgroups/v3 v3.0.3 h1:S5ByHZ/h9PMe5IOQoN7E+nMc2UcLEM/V48DGDJ9kip0= +github.com/containerd/cgroups/v3 v3.0.3/go.mod h1:8HBe7V3aWGLFPd/k03swSIsGjZhHI2WzJmticMgVuz0= +github.com/containerd/containerd v1.7.23 h1:H2CClyUkmpKAGlhQp95g2WXHfLYc7whAuvZGBNYOOwQ= +github.com/containerd/containerd v1.7.23/go.mod h1:7QUzfURqZWCZV7RLNEn1XjUCQLEf0bkaK4GjUaZehxw= +github.com/containerd/containerd/api v1.8.0 h1:hVTNJKR8fMc/2Tiw60ZRijntNMd1U+JVMyTRdsD2bS0= +github.com/containerd/containerd/api v1.8.0/go.mod h1:dFv4lt6S20wTu/hMcP4350RL87qPWLVa/OHOwmmdnYc= +github.com/containerd/containerd/v2 v2.0.0 h1:qLDdFaAykQrIyLiqwQrNLLz95wiC36bAZVwioUwqShM= +github.com/containerd/containerd/v2 v2.0.0/go.mod h1:j25kDy9P48/ngb1sxWIFfK6GsnqOHoSqo1EpAod20VQ= +github.com/containerd/continuity v0.4.4 h1:/fNVfTJ7wIl/YPMHjf+5H32uFhl63JucB34PlCpMKII= +github.com/containerd/continuity v0.4.4/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= github.com/containerd/fifo v1.1.0 h1:4I2mbh5stb1u6ycIABlBw9zgtlK8viPI9QkQNRQEEmY= github.com/containerd/fifo v1.1.0/go.mod h1:bmC4NWMbXlt2EZ0Hc7Fx7QzTFxgPID13eH0Qu+MAb2o= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= -github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= -github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/containerd/platforms v1.0.0-rc.0 h1:GuHWSKgVVO3POn6nRBB4sH63uPOLa87yuuhsGLWaXAA= +github.com/containerd/platforms v1.0.0-rc.0/go.mod h1:T1XAzzOdYs3it7l073MNXyxRwQofJfqwi/8cRjufIk4= +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.15.1 h1:eXJjw9RbkLFgioVaTG+G/ZW/0kEe2oEKCdS/ZxIyoCU= github.com/containerd/stargz-snapshotter/estargz v0.15.1/go.mod h1:gr2RNwukQ/S9Nv33Lt6UC7xEx58C+LHRdoqbEKjz1Kk= -github.com/containerd/ttrpc v1.2.5 h1:IFckT1EFQoFBMG4c3sMdT8EP3/aKfumK1msY+Ze4oLU= -github.com/containerd/ttrpc v1.2.5/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o= -github.com/containerd/typeurl/v2 v2.2.0 h1:6NBDbQzr7I5LHgp34xAXYF5DOTQDn05X58lsPEmzLso= -github.com/containerd/typeurl/v2 v2.2.0/go.mod h1:8XOOxnyatxSWuG8OfsZXVnAF4iZfedjS/8UHSPJnX4g= +github.com/containerd/ttrpc v1.2.6 h1:zG+Kn5EZ6MUYCS1t2Hmt2J4tMVaLSFEJVOraDQwNPC4= +github.com/containerd/ttrpc v1.2.6/go.mod h1:YCXHsb32f+Sq5/72xHubdiJRQY9inL4a4ZQrAbN1q9o= +github.com/containerd/typeurl/v2 v2.2.2 h1:3jN/k2ysKuPCsln5Qv8bzR9cxal8XjkxPogJfSNO31k= +github.com/containerd/typeurl/v2 v2.2.2/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsxGtUBhJxIn7SCk= github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU= github.com/coreos/go-oidc/v3 v3.10.0/go.mod h1:5j11xcw0D3+SGxn6Z/WFADsgcWVMyNAlSQupk0KK3ac= github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= -github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0= github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= github.com/csaf-poc/csaf_distribution/v3 v3.0.0 h1:ob9+Fmpff0YWgTP3dYaw7G2hKQ9cegh9l3zksc+q3sM= @@ -638,8 +645,8 @@ github.com/go-ini/ini v1.67.0 h1:z6ZrTEZqSWOTyH2FlglNbNgARyHG8oLW9gMELqKr06A= github.com/go-ini/ini v1.67.0/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-jose/go-jose/v3 v3.0.3 h1:fFKWeig/irsp7XD2zBxvnmA/XaRWp5V3CBsZXJF7G7k= github.com/go-jose/go-jose/v3 v3.0.3/go.mod h1:5b+7YgP7ZICgJDBdfjZaIt+H/9L9T/YQrVfLAMboGkQ= -github.com/go-jose/go-jose/v4 v4.0.1 h1:QVEPDE3OluqXBQZDcnNvQrInro2h0e4eqNbnZSWqS6U= -github.com/go-jose/go-jose/v4 v4.0.1/go.mod h1:WVf9LFMHh/QVrmqrOfqun0C45tMe3RoiKJMPvgWwLfY= +github.com/go-jose/go-jose/v4 v4.0.4 h1:VsjPI33J0SB9vQM6PLmNjoHqMQNGPiZ0rHL7Ni7Q6/E= +github.com/go-jose/go-jose/v4 v4.0.4/go.mod h1:NKb5HO1EZccyMpiZNbdUw/14tiXNyUJh188dfnMCAfc= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= @@ -716,8 +723,8 @@ github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/glog v1.2.1 h1:OptwRhECazUx5ix5TTWC3EZhsZEHWcYWY4FQHTIubm4= -github.com/golang/glog v1.2.1/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= +github.com/golang/glog v1.2.2 h1:1+mZ9upx1Dh6FmUTFR1naJ77miKiXgALjWOZ3NVFPmY= +github.com/golang/glog v1.2.2/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -866,8 +873,8 @@ github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJr github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo= github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -956,8 +963,8 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.15.11/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= -github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= -github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f h1:GvCU5GXhHq+7LeOzx/haG7HSIZokl3/0GkoUFzsRJjg= github.com/knqyf263/go-apk-version v0.0.0-20200609155635-041fdbb8563f/go.mod h1:q59u9px8b7UTj0nIjEjvmTWekazka6xIt6Uogz5Dm+8= @@ -1064,6 +1071,7 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs= github.com/moby/buildkit v0.16.0 h1:wOVBj1o5YNVad/txPQNXUXdelm7Hs/i0PUFjzbK0VKE= github.com/moby/buildkit v0.16.0/go.mod h1:Xqx/5GlrqE1yIRORk0NSCVDFpQAU1WjlT6KHYZdisIQ= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= @@ -1076,8 +1084,8 @@ github.com/moby/spdystream v0.4.0 h1:Vy79D6mHeJJjiPdFEL2yku1kl0chZpJfZcPpb16BRl8 github.com/moby/spdystream v0.4.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg= github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= -github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= -github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= github.com/moby/sys/signal v0.7.1 h1:PrQxdvxcGijdo6UXXo/lU/TvHUWyPhj7UOpSo8tuvk0= github.com/moby/sys/signal v0.7.1/go.mod h1:Se1VGehYokAkrSQwL4tDzHvETwUZlnY7S5XtQ50mQp8= github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= @@ -1099,6 +1107,7 @@ github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mozillazg/docker-credential-acr-helper v0.3.0 h1:DVWFZ3/O8BP6Ue3iS/Olw+G07u1hCq1EOVCDZZjCIBI= github.com/mozillazg/docker-credential-acr-helper v0.3.0/go.mod h1:cZlu3tof523ujmLuiNUb6JsjtHcNA70u1jitrrdnuyA= +github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= @@ -1135,10 +1144,14 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/runtime-spec v1.0.3-0.20220825212826-86290f6a00fb/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk= github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0= -github.com/opencontainers/selinux v1.11.0 h1:+5Zbo97w3Lbmb3PeqQtpmTkMwsW5nRI3YaLpt7tQ7oU= -github.com/opencontainers/selinux v1.11.0/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= +github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626 h1:DmNGcqH3WDbV5k8OJ+esPWbqUOX5rMLR2PMvziDMJi0= +github.com/opencontainers/runtime-tools v0.9.1-0.20221107090550-2e043c6bd626/go.mod h1:BRHJJd0E+cx42OybVYSgUvZmU0B8P9gZuRXlZUP7TKI= +github.com/opencontainers/selinux v1.9.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= +github.com/opencontainers/selinux v1.11.1 h1:nHFvthhM0qY8/m+vfhJylliSshm8G1jJ2jDMcgULaH8= +github.com/opencontainers/selinux v1.11.1/go.mod h1:E5dMC3VPuVvVHDYmi78qvhJp8+M586T4DlDRYpFkyec= github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/openvex/discovery v0.1.1-0.20240802171711-7c54efc57553 h1:c4u0GIH0w2Q57Pm2Oldrq6EiHFnLCCnRs98A+ggj/YQ= @@ -1154,8 +1167,8 @@ github.com/package-url/packageurl-go v0.1.3 h1:4juMED3hHiz0set3Vq3KeQ75KD1avthoX github.com/package-url/packageurl-go v0.1.3/go.mod h1:nKAWB8E6uk1MHqiS/lQb9pYBGH2+mdJ2PJc2s50dQY0= github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= -github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= +github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M= +github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc= github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5 h1:Ii+DKncOVM8Cu1Hc+ETb5K+23HdAMvESYE3ZJ5b5cMI= @@ -1178,8 +1191,8 @@ github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjz github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= github.com/prometheus/client_golang v1.1.0/go.mod h1:I1FGZT9+L76gKKOs5djB6ezCbFQP1xR9D75/vuwEF3g= -github.com/prometheus/client_golang v1.20.2 h1:5ctymQzZlyOON1666svgwn3s6IKWgfbjsejTMiXIyjg= -github.com/prometheus/client_golang v1.20.2/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_golang v1.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y= +github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -1269,6 +1282,7 @@ github.com/sigstore/timestamp-authority v1.2.2 h1:X4qyutnCQqJ0apMewFyx+3t7Tws00J github.com/sigstore/timestamp-authority v1.2.2/go.mod h1:nEah4Eq4wpliDjlY342rXclGSO7Kb9hoRrl9tqLW13A= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= @@ -1317,6 +1331,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635 h1:kdXcSzyDtseVEc4yCz2qF8ZrQvIDBJLl4S1c3GCXmoI= +github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDdvS342BElfbETmL1Aiz3i2t0zfRj16Hs= github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48= github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes= @@ -1353,6 +1369,7 @@ github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4A github.com/ulikunitz/xz v0.5.10/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc= github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= +github.com/urfave/cli v1.19.1/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI= github.com/vbatts/tar-split v0.11.5 h1:3bHCTIheBm1qFTcgh9oPu+nNBtX+XJIupG/vacinCts= github.com/vbatts/tar-split v0.11.5/go.mod h1:yZbwRsSeGjusneWgA781EKej9HF8vme8okylkAeNKLk= @@ -1422,24 +1439,24 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6ZXmNPRR8ul6i3WgFURCHzaXjHdm0karRG/+dj3s= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0 h1:digkEZCJWobwBqMwC0cwCq8/wkkRy/OowZg5OArWZrM= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.21.0/go.mod h1:/OpE/y70qVkndM0TrxT4KBoN3RsFZP0QaofcfYrj76I= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0 h1:yMkBS9yViCc7U7yeLzJPM2XizlfdVvBRSmsQDWu6qc0= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.56.0/go.mod h1:n8MR6/liuGB5EmTETUBeU5ZgqMOlqKRxUaqPQBOANZ8= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM= +go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0 h1:K0XaT3DwHAcV4nKLzcQvwAgSyisUghWoY20I7huthMk= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.31.0/go.mod h1:B5Ki776z/MBnVha1Nzwp5arlzBbE3+1jk+pGmaP5HME= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.31.0 h1:FFeLy03iVTXP6ffeN2iXrxfGsZGCjVx0/4KlizjyBwU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.31.0/go.mod h1:TMu73/k1CP8nBUpDLc71Wj/Kf7ZS9FK5b53VapRsP9o= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0 h1:lUsI2TYsQw2r1IASwoROaCnjdj2cvC2+Jbxvk6nHnWU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.31.0/go.mod h1:2HpZxxQurfGxJlJDblybejHB6RX6pmExPNe517hREw4= +go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= +go.opentelemetry.io/otel/sdk v1.31.0 h1:xLY3abVHYZ5HSfOg3l2E5LUj2Cwva5Y7yGxnSW9H5Gk= +go.opentelemetry.io/otel/sdk v1.31.0/go.mod h1:TfRbMdhvxIIr/B2N2LQW2S5v9m3gOQ/08KsbbO5BPT0= +go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= @@ -1466,8 +1483,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0 golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1478,8 +1495,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= -golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa/go.mod h1:zk2irFbV9DP96SEBUUAy67IdHUaZuSnrz1n472HUCLE= +golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 h1:qCEDpW1G+vcj3Y7Fy52pEM1AWm3abj8WimGYejI3SC4= +golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1569,8 +1586,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1596,8 +1613,8 @@ golang.org/x/oauth2 v0.0.0-20220822191816-0ebed06d0094/go.mod h1:h4gKUeWbJ4rQPri golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.0.0-20221014153046-6fdb5e3db783/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg= golang.org/x/oauth2 v0.1.0/go.mod h1:G9FE4dLTsbXUu90h/Pf85g4w1D+SSAgR+q46nJZ8M4A= -golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= -golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= 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-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1638,6 +1655,7 @@ golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1734,8 +1752,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= -golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1973,10 +1991,10 @@ google.golang.org/genproto v0.0.0-20221014213838-99cd37c6964a/go.mod h1:1vXfmgAz google.golang.org/genproto v0.0.0-20221025140454-527a21cfbd71/go.mod h1:9qHF0xnpdSfF6knlcsnpzUu5y+rpwgbvsyGAZPBMg4s= google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 h1:ImUcDPHjTrAqNhlOkSocDLfG9rrNHH7w7uoKWPaWZ8s= google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7/go.mod h1:/3XmxOjePkvmKrHuBy4zNFw7IzxJXtAgdpXi8Ll990U= -google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094 h1:0+ozOGcrp+Y8Aq8TLNN2Aliibms5LEzsq99ZZmAGYm0= -google.golang.org/genproto/googleapis/api v0.0.0-20240701130421-f6361c86f094/go.mod h1:fJ/e3If/Q67Mj99hin0hMhiNyCRmt6BQ2aWIJshUSJw= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094 h1:BwIjyKYGsK9dMCBOorzRri8MQwmi7mT9rGHsCEinZkA= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240701130421-f6361c86f094/go.mod h1:Ue6ibwXGpU+dqIcODieyLOcgj7z8+IcskoNIgZxtrFY= +google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 h1:T6rh4haD3GVYsgEfWExoCZA2o2FmbNyKpTuAxbEFPTg= +google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9/go.mod h1:wp2WsuBYj6j8wUdo3ToZsdxxixbvQNAHqVJrTgi5E5M= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38 h1:zciRKQ4kBpFgpfC5QQCVtnnNAcLIqweL7plyZRQHVpI= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241021214115-324edc3d5d38/go.mod h1:GX3210XPVPUjJbTUbvwI8f2IpZDMZuPJWDzDuebbviI= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -2012,8 +2030,8 @@ google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACu google.golang.org/grpc v1.49.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.0/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= -google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= -google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= @@ -2030,8 +2048,8 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -2085,8 +2103,8 @@ k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24 k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= -k8s.io/apiserver v0.31.0 h1:p+2dgJjy+bk+B1Csz+mc2wl5gHwvNkC9QJV+w55LVrY= -k8s.io/apiserver v0.31.0/go.mod h1:KI9ox5Yu902iBnnyMmy7ajonhKnkeZYJhTZ/YI+WEMk= +k8s.io/apiserver v0.31.2 h1:VUzOEUGRCDi6kX1OyQ801m4A7AUPglpsmGvdsekmcI4= +k8s.io/apiserver v0.31.2/go.mod h1:o3nKZR7lPlJqkU5I3Ove+Zx3JuoFjQobGX1Gctw6XuE= k8s.io/cli-runtime v0.31.2 h1:7FQt4C4Xnqx8V1GJqymInK0FFsoC+fAZtbLqgXYVOLQ= k8s.io/cli-runtime v0.31.2/go.mod h1:XROyicf+G7rQ6FQJMbeDV9jqxzkWXTYD6Uxd15noe0Q= k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc= @@ -2148,3 +2166,7 @@ sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= software.sslmate.com/src/go-pkcs12 v0.4.0 h1:H2g08FrTvSFKUj+D309j1DPfk5APnIdAQAB8aEykJ5k= software.sslmate.com/src/go-pkcs12 v0.4.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= +tags.cncf.io/container-device-interface v0.8.0 h1:8bCFo/g9WODjWx3m6EYl3GfUG31eKJbaggyBDxEldRc= +tags.cncf.io/container-device-interface v0.8.0/go.mod h1:Apb7N4VdILW0EVdEMRYXIDVRZfNJZ+kmEUss2kRRQ6Y= +tags.cncf.io/container-device-interface/specs-go v0.8.0 h1:QYGFzGxvYK/ZLMrjhvY0RjpUavIn4KcmRmVP/JjdBTA= +tags.cncf.io/container-device-interface/specs-go v0.8.0/go.mod h1:BhJIkjjPh4qpys+qm4DAYtUyryaTDg9zris+AczXyws= diff --git a/pkg/fanal/image/daemon/containerd.go b/pkg/fanal/image/daemon/containerd.go index 109081d5bae5..faa5c8d98c3f 100644 --- a/pkg/fanal/image/daemon/containerd.go +++ b/pkg/fanal/image/daemon/containerd.go @@ -10,12 +10,12 @@ import ( "strings" "time" - "github.com/containerd/containerd" - "github.com/containerd/containerd/content" - "github.com/containerd/containerd/images/archive" - "github.com/containerd/containerd/namespaces" - "github.com/containerd/containerd/platforms" - refdocker "github.com/containerd/containerd/reference/docker" + "github.com/containerd/containerd/v2/client" + "github.com/containerd/containerd/v2/core/content" + "github.com/containerd/containerd/v2/core/images/archive" + "github.com/containerd/containerd/v2/pkg/namespaces" + "github.com/containerd/platforms" + "github.com/distribution/reference" api "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/container" "github.com/docker/go-connections/nat" @@ -52,12 +52,12 @@ func (n familiarNamed) String() string { return string(n) } -func imageWriter(client *containerd.Client, img containerd.Image, platform types.Platform) imageSave { +func imageWriter(c *client.Client, img client.Image, platform types.Platform) imageSave { return func(ctx context.Context, ref []string) (io.ReadCloser, error) { if len(ref) < 1 { return nil, xerrors.New("no image reference") } - imgOpts := archive.WithImage(client.ImageService(), ref[0]) + imgOpts := archive.WithImage(c.ImageService(), ref[0]) manifestOpts := archive.WithManifest(img.Target()) var platformMatchComparer platforms.MatchComparer @@ -69,7 +69,7 @@ func imageWriter(client *containerd.Client, img containerd.Image, platform types platOpts := archive.WithPlatform(platformMatchComparer) pr, pw := io.Pipe() go func() { - pw.CloseWithError(archive.Export(ctx, client.ContentStore(), pw, imgOpts, manifestOpts, platOpts)) + pw.CloseWithError(archive.Export(ctx, c.ContentStore(), pw, imgOpts, manifestOpts, platOpts)) }() return pr, nil } @@ -94,17 +94,17 @@ func ContainerdImage(ctx context.Context, imageName string, opts types.ImageOpti return nil, cleanup, err } - var options []containerd.ClientOpt + var options []client.Opt if opts.RegistryOptions.Platform.Platform != nil { ociPlatform, err := platforms.Parse(opts.RegistryOptions.Platform.String()) if err != nil { return nil, cleanup, err } - options = append(options, containerd.WithDefaultPlatform(platforms.OnlyStrict(ociPlatform))) + options = append(options, client.WithDefaultPlatform(platforms.OnlyStrict(ociPlatform))) } - client, err := containerd.New(addr, options...) + c, err := client.New(addr, options...) if err != nil { return nil, cleanup, xerrors.Errorf("failed to initialize a containerd client: %w", err) } @@ -116,7 +116,7 @@ func ContainerdImage(ctx context.Context, imageName string, opts types.ImageOpti ctx = namespaces.WithNamespace(ctx, namespace) - imgs, err := client.ListImages(ctx, searchFilters...) + imgs, err := c.ListImages(ctx, searchFilters...) if err != nil { return nil, cleanup, xerrors.Errorf("failed to list images from containerd client: %w", err) } @@ -133,7 +133,7 @@ func ContainerdImage(ctx context.Context, imageName string, opts types.ImageOpti } cleanup = func() { - _ = client.Close() + _ = c.Close() _ = f.Close() _ = os.Remove(f.Name()) } @@ -144,21 +144,21 @@ func ContainerdImage(ctx context.Context, imageName string, opts types.ImageOpti } return &image{ - opener: imageOpener(ctx, ref.String(), f, imageWriter(client, img, opts.RegistryOptions.Platform)), + opener: imageOpener(ctx, ref.String(), f, imageWriter(c, img, opts.RegistryOptions.Platform)), inspect: insp, history: history, }, cleanup, nil } -func parseReference(imageName string) (refdocker.Reference, []string, error) { - ref, err := refdocker.ParseAnyReference(imageName) +func parseReference(imageName string) (reference.Reference, []string, error) { + ref, err := reference.ParseAnyReference(imageName) if err != nil { return nil, nil, xerrors.Errorf("parse error: %w", err) } - d, isDigested := ref.(refdocker.Digested) - n, isNamed := ref.(refdocker.Named) - nt, isNamedAndTagged := ref.(refdocker.NamedTagged) + d, isDigested := ref.(reference.Digested) + n, isNamed := ref.(reference.Named) + nt, isNamedAndTagged := ref.(reference.NamedTagged) // a name plus a digest // example: name@sha256:41adb3ef... @@ -168,7 +168,7 @@ func parseReference(imageName string) (refdocker.Reference, []string, error) { // comma-separated filter is logically anded return ref, []string{ fmt.Sprintf(`name~="^%s(:|@).*",target.digest==%q`, n.Name(), dgst), - fmt.Sprintf(`name~="^%s(:|@).*",target.digest==%q`, refdocker.FamiliarName(n), dgst), + fmt.Sprintf(`name~="^%s(:|@).*",target.digest==%q`, reference.FamiliarName(n), dgst), }, nil } @@ -184,7 +184,7 @@ func parseReference(imageName string) (refdocker.Reference, []string, error) { tag := nt.Tag() return familiarNamed(imageName), []string{ fmt.Sprintf(`name=="%s:%s"`, nt.Name(), tag), - fmt.Sprintf(`name=="%s:%s"`, refdocker.FamiliarName(nt), tag), + fmt.Sprintf(`name=="%s:%s"`, reference.FamiliarName(nt), tag), }, nil } @@ -193,7 +193,7 @@ func parseReference(imageName string) (refdocker.Reference, []string, error) { // readImageConfig reads the config spec (`application/vnd.oci.image.config.v1+json`) for img.platform from content store. // ported from https://github.com/containerd/nerdctl/blob/7dfbaa2122628921febeb097e7a8a86074dc931d/pkg/imgutil/imgutil.go#L377-L393 -func readImageConfig(ctx context.Context, img containerd.Image) (ocispec.Image, ocispec.Descriptor, error) { +func readImageConfig(ctx context.Context, img client.Image) (ocispec.Image, ocispec.Descriptor, error) { var config ocispec.Image configDesc, err := img.Config(ctx) // aware of img.platform @@ -211,19 +211,19 @@ func readImageConfig(ctx context.Context, img containerd.Image) (ocispec.Image, } // ported from https://github.com/containerd/nerdctl/blob/d110fea18018f13c3f798fa6565e482f3ff03591/pkg/inspecttypes/dockercompat/dockercompat.go#L279-L321 -func inspect(ctx context.Context, img containerd.Image, ref refdocker.Reference) (api.ImageInspect, []v1.History, refdocker.Reference, error) { - if _, ok := ref.(refdocker.Digested); ok { +func inspect(ctx context.Context, img client.Image, ref reference.Reference) (api.ImageInspect, []v1.History, reference.Reference, error) { + if _, ok := ref.(reference.Digested); ok { ref = familiarNamed(img.Name()) } var tag string - if tagged, ok := ref.(refdocker.Tagged); ok { + if tagged, ok := ref.(reference.Tagged); ok { tag = tagged.Tag() } var repository string - if n, isNamed := ref.(refdocker.Named); isNamed { - repository = refdocker.FamiliarName(n) + if n, isNamed := ref.(reference.Named); isNamed { + repository = reference.FamiliarName(n) } imgConfig, imgConfigDesc, err := readImageConfig(ctx, img) diff --git a/pkg/fanal/test/integration/containerd_test.go b/pkg/fanal/test/integration/containerd_test.go index 420949cd42d3..b635c3913d9c 100644 --- a/pkg/fanal/test/integration/containerd_test.go +++ b/pkg/fanal/test/integration/containerd_test.go @@ -15,13 +15,12 @@ import ( "testing" "time" - "github.com/samber/lo" - - "github.com/containerd/containerd" - "github.com/containerd/containerd/images" - "github.com/containerd/containerd/namespaces" + "github.com/containerd/containerd/v2/client" + "github.com/containerd/containerd/v2/core/images" + "github.com/containerd/containerd/v2/pkg/namespaces" dockercontainer "github.com/docker/docker/api/types/container" v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/samber/lo" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/testcontainers/testcontainers-go" @@ -37,7 +36,7 @@ import ( "github.com/aquasecurity/trivy/pkg/fanal/types" ) -func setupContainerd(t *testing.T, ctx context.Context, namespace string) *containerd.Client { +func setupContainerd(t *testing.T, ctx context.Context, namespace string) *client.Client { t.Helper() tmpDir := t.TempDir() @@ -54,9 +53,9 @@ func setupContainerd(t *testing.T, ctx context.Context, namespace string) *conta startContainerd(t, ctx, tmpDir) // Retry up to 3 times until containerd is ready - var client *containerd.Client + var c *client.Client iteration, _, err := lo.AttemptWhileWithDelay(3, 1*time.Second, func(int, time.Duration) (error, bool) { - client, err = containerd.New(socketPath) + c, err = client.New(socketPath) if err != nil { if !errors.Is(err, os.ErrPermission) { return err, false // unexpected error @@ -64,13 +63,13 @@ func setupContainerd(t *testing.T, ctx context.Context, namespace string) *conta return err, true } t.Cleanup(func() { - require.NoError(t, client.Close()) + require.NoError(t, c.Close()) }) return nil, false }) require.NoErrorf(t, err, "attempted %d times ", iteration) - return client + return c } func startContainerd(t *testing.T, ctx context.Context, hostPath string) { From 601846134cb820c3e78324a44c7f0332d01b9fc6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Nov 2024 13:25:40 +0400 Subject: [PATCH 179/183] chore(deps): bump the common group across 1 directory with 20 updates (#7876) Signed-off-by: dependabot[bot] Signed-off-by: knqyf263 Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: knqyf263 --- go.mod | 71 ++++---- go.sum | 154 ++++++++++-------- integration/client_server_test.go | 2 +- integration/registry_test.go | 4 +- pkg/fanal/test/integration/containerd_test.go | 5 +- pkg/fanal/test/integration/registry_test.go | 2 +- 6 files changed, 123 insertions(+), 115 deletions(-) diff --git a/go.mod b/go.mod index 566d5069c0b9..c981c884a350 100644 --- a/go.mod +++ b/go.mod @@ -6,8 +6,8 @@ toolchain go1.22.4 require ( github.com/Azure/azure-sdk-for-go v68.0.0+incompatible - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 - github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 github.com/BurntSushi/toml v1.4.0 github.com/CycloneDX/cyclonedx-go v0.9.1 github.com/GoogleCloudPlatform/docker-credential-gcr v2.0.5+incompatible @@ -15,7 +15,7 @@ require ( github.com/NYTimes/gziphandler v1.1.1 github.com/alecthomas/chroma v0.10.0 github.com/alicebob/miniredis/v2 v2.33.0 - github.com/antchfx/htmlquery v1.3.2 + github.com/antchfx/htmlquery v1.3.3 github.com/apparentlymart/go-cidr v1.1.0 github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce @@ -29,26 +29,26 @@ require ( github.com/aquasecurity/trivy-db v0.0.0-20240910133327-7e0f4d2ed4c1 github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20241101182546-89bffc3932bc - github.com/aws/aws-sdk-go-v2 v1.31.0 - github.com/aws/aws-sdk-go-v2/config v1.27.38 - github.com/aws/aws-sdk-go-v2/credentials v1.17.36 - github.com/aws/aws-sdk-go-v2/service/ec2 v1.179.1 - github.com/aws/aws-sdk-go-v2/service/ecr v1.35.2 - github.com/aws/aws-sdk-go-v2/service/s3 v1.63.2 - github.com/aws/aws-sdk-go-v2/service/sts v1.31.2 // indirect - github.com/aws/smithy-go v1.21.0 + github.com/aws/aws-sdk-go-v2 v1.32.3 + github.com/aws/aws-sdk-go-v2/config v1.28.1 + github.com/aws/aws-sdk-go-v2/credentials v1.17.42 + github.com/aws/aws-sdk-go-v2/service/ec2 v1.187.0 + github.com/aws/aws-sdk-go-v2/service/ecr v1.36.3 + github.com/aws/aws-sdk-go-v2/service/s3 v1.66.2 + github.com/aws/aws-sdk-go-v2/service/sts v1.32.3 // indirect + github.com/aws/smithy-go v1.22.0 github.com/bitnami/go-version v0.0.0-20231130084017-bb00604d650c - github.com/bmatcuk/doublestar/v4 v4.6.1 + github.com/bmatcuk/doublestar/v4 v4.7.1 github.com/cenkalti/backoff/v4 v4.3.0 github.com/cheggaaa/pb/v3 v3.1.5 github.com/containerd/containerd/v2 v2.0.0 github.com/containerd/platforms v1.0.0-rc.0 github.com/csaf-poc/csaf_distribution/v3 v3.0.0 github.com/distribution/reference v0.6.0 - github.com/docker/cli v27.2.1+incompatible + github.com/docker/cli v27.3.1+incompatible github.com/docker/docker v27.3.1+incompatible github.com/docker/go-connections v0.5.0 - github.com/fatih/color v1.17.0 + github.com/fatih/color v1.18.0 github.com/go-git/go-git/v5 v5.12.0 github.com/go-openapi/runtime v0.28.0 // indirect github.com/go-openapi/strfmt v0.23.0 // indirect @@ -90,8 +90,8 @@ require ( github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/mitchellh/mapstructure v1.5.0 - github.com/moby/buildkit v0.16.0 - github.com/open-policy-agent/opa v0.68.1-0.20240903211041-76f7038ea2d1 + github.com/moby/buildkit v0.17.0 + github.com/open-policy-agent/opa v0.70.0 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 github.com/openvex/discovery v0.1.1-0.20240802171711-7c54efc57553 @@ -112,17 +112,17 @@ require ( github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.19.0 github.com/stretchr/testify v1.9.0 - github.com/testcontainers/testcontainers-go v0.33.0 - github.com/testcontainers/testcontainers-go/modules/localstack v0.33.0 - github.com/tetratelabs/wazero v1.8.0 + github.com/testcontainers/testcontainers-go v0.34.0 + github.com/testcontainers/testcontainers-go/modules/localstack v0.34.0 + github.com/tetratelabs/wazero v1.8.1 github.com/twitchtv/twirp v8.1.3+incompatible github.com/xeipuuv/gojsonschema v1.2.0 github.com/xlab/treeprint v1.2.0 github.com/zclconf/go-cty v1.15.0 - github.com/zclconf/go-cty-yaml v1.0.3 + github.com/zclconf/go-cty-yaml v1.1.0 go.etcd.io/bbolt v1.3.11 golang.org/x/crypto v0.28.0 - golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 // indirect + golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect golang.org/x/mod v0.21.0 golang.org/x/net v0.30.0 golang.org/x/sync v0.8.0 @@ -132,7 +132,7 @@ require ( golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 google.golang.org/protobuf v1.35.1 gopkg.in/yaml.v3 v3.0.1 - helm.sh/helm/v3 v3.16.1 + helm.sh/helm/v3 v3.16.2 k8s.io/api v0.31.2 k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 modernc.org/sqlite v1.33.1 @@ -169,22 +169,22 @@ require ( github.com/ProtonMail/go-crypto v1.1.0-alpha.2 // indirect github.com/VividCortex/ewma v1.2.0 // indirect github.com/agext/levenshtein v1.2.3 // indirect - github.com/agnivade/levenshtein v1.1.1 // indirect + github.com/agnivade/levenshtein v1.2.0 // indirect github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 // indirect - github.com/antchfx/xpath v1.3.1 // indirect + github.com/antchfx/xpath v1.3.2 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/aws/aws-sdk-go v1.55.5 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect github.com/aws/aws-sdk-go-v2/service/ebs v1.22.1 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.20 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.23.2 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.2 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.3 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect github.com/blang/semver v3.5.1+incompatible // indirect @@ -205,7 +205,7 @@ require ( github.com/containerd/stargz-snapshotter/estargz v0.15.1 // indirect github.com/containerd/ttrpc v1.2.6 // indirect github.com/containerd/typeurl/v2 v2.2.2 // indirect - github.com/cpuguy83/dockercfg v0.3.1 // indirect + github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect github.com/cyberphone/json-canonicalization v0.0.0-20231011164504-785e29786b46 // indirect github.com/cyphar/filepath-securejoin v0.3.1 // indirect @@ -328,6 +328,7 @@ require ( github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/errors v0.9.1 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/prometheus/client_golang v1.20.5 // indirect @@ -391,8 +392,8 @@ require ( golang.org/x/oauth2 v0.22.0 // indirect golang.org/x/sys v0.26.0 // indirect golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 // indirect - golang.org/x/time v0.6.0 // indirect - golang.org/x/tools v0.24.0 // indirect + golang.org/x/time v0.7.0 // indirect + golang.org/x/tools v0.25.0 // indirect google.golang.org/api v0.172.0 // indirect google.golang.org/genproto v0.0.0-20240311173647-c811ad7063a7 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241007155032-5fefd90f89a9 // indirect @@ -405,7 +406,7 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect - k8s.io/apiextensions-apiserver v0.31.0 // indirect + k8s.io/apiextensions-apiserver v0.31.1 // indirect k8s.io/apimachinery v0.31.2 // indirect k8s.io/apiserver v0.31.2 // indirect k8s.io/cli-runtime v0.31.2 // indirect diff --git a/go.sum b/go.sum index 7618669c665c..8df679b57a6b 100644 --- a/go.sum +++ b/go.sum @@ -203,10 +203,12 @@ github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo github.com/AliyunContainerService/ack-ram-tool/pkg/credentials/alibabacloudsdkgo/helper v0.2.0/go.mod h1:GgeIE+1be8Ivm7Sh4RgwI42aTtC9qrcj+Y9Y6CjJhJs= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible h1:fcYLmCpyNYRnvJbPerq7U0hS+6+I79yEDJBqVNcqUzU= github.com/Azure/azure-sdk-for-go v68.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0 h1:nyQWyZvwGTvunIMxi1Y9uXkcyr+I7TeNrr/foo4Kpk8= -github.com/Azure/azure-sdk-for-go/sdk/azcore v1.14.0/go.mod h1:l38EPgmsp71HHLq9j7De57JcKOWPyhrsW1Awm1JS6K0= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0 h1:tfLQ34V6F7tVSwoTf/4lH5sE0o6eCJuNDTmH09nDpbc= -github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.7.0/go.mod h1:9kIvujWAA58nmPmWB1m23fyWic1kYZMxD9CxaWn4Qpg= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0 h1:JZg6HRh6W6U4OLl6lk7BZ7BLisIzM9dG1R50zUk9C/M= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0/go.mod h1:YL1xnZ6QejvQHWJrX/AvhFl4WW4rqHVoKspWNVwFk0M= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0 h1:B/dfvscEQtew9dVuoxqxrUKKv8Ih2f55PydknDamU+g= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0/go.mod h1:fiPSssYvltE08HJchL04dOy+RD4hgrjph0cwGGMntdI= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0 h1:+m0M/LFxN43KvULkDNfdXOgrjtg6UYJPFBJyuEcRCAw= +github.com/Azure/azure-sdk-for-go/sdk/azidentity/cache v0.3.0/go.mod h1:PwOyop78lveYMRs6oCxjiVyBdyCgIYH6XHIVZO9/SFQ= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0 h1:ywEEhmNahHBihViHepv3xPBn1663uRv2t2q/ESv9seY= github.com/Azure/azure-sdk-for-go/sdk/internal v1.10.0/go.mod h1:iZDifYGJTIgIIkYRNWPENUnqx6bJ2xnSDFI2tjwZNuY= github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.1.0 h1:DRiANoJTiW6obBQe3SqZizkuV1PEgfiiGivmVocDy64= @@ -235,6 +237,8 @@ github.com/Azure/go-autorest/logger v0.2.1 h1:IG7i4p/mDa2Ce4TRyAO8IHnVhAVF3RFU+Z github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8= github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo= github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1 h1:WJTmL004Abzc5wDB5VtZG2PJk5ndYDgVacGqfirKxjM= +github.com/AzureAD/microsoft-authentication-extensions-for-go/cache v0.1.1/go.mod h1:tCcJZ0uHAmvjsVYzEFivsRTN00oz5BEsRgQHu5JZ9WE= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2 h1:XHOnouVk1mxXfQidrMEnLlPk9UMeRtyBTnEFtxkV0kU= github.com/AzureAD/microsoft-authentication-library-for-go v1.2.2/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -283,8 +287,8 @@ github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1o github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= -github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= -github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= +github.com/agnivade/levenshtein v1.2.0 h1:U9L4IOT0Y3i0TIlUIDJ7rVUziKi/zPbrJGaFrtYH3SY= +github.com/agnivade/levenshtein v1.2.0/go.mod h1:QVVI16kDrtSuwcpd0p1+xMC6Z/VfhtCyDIjcwga4/DU= github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek= github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -321,10 +325,10 @@ github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092 h1:aM1 github.com/anchore/go-struct-converter v0.0.0-20221118182256-c68fdcfa2092/go.mod h1:rYqSE9HbjzpHTI74vwPvae4ZVYZd1lue2ta6xHPdblA= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= -github.com/antchfx/htmlquery v1.3.2 h1:85YdttVkR1rAY+Oiv/nKI4FCimID+NXhDn82kz3mEvs= -github.com/antchfx/htmlquery v1.3.2/go.mod h1:1mbkcEgEarAokJiWhTfr4hR06w/q2ZZjnYLrDt6CTUk= -github.com/antchfx/xpath v1.3.1 h1:PNbFuUqHwWl0xRjvUPjJ95Agbmdj2uzzIwmQKgu4oCk= -github.com/antchfx/xpath v1.3.1/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= +github.com/antchfx/htmlquery v1.3.3 h1:x6tVzrRhVNfECDaVxnZi1mEGrQg3mjE/rxbH2Pe6dNE= +github.com/antchfx/htmlquery v1.3.3/go.mod h1:WeU3N7/rL6mb6dCwtE30dURBnBieKDC/fR8t6X+cKjU= +github.com/antchfx/xpath v1.3.2 h1:LNjzlsSjinu3bQpw9hWMY9ocB80oLOWuQqFvO6xt51U= +github.com/antchfx/xpath v1.3.2/go.mod h1:i54GszH55fYfBmoZXapTHN8T8tkcHfRgLyVwwqzXNcs= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apparentlymart/go-cidr v1.1.0 h1:2mAhrMoF+nhXqxTzSZMUzDHkLjmIHC+Zzn4tdgBZjnU= github.com/apparentlymart/go-cidr v1.1.0/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= @@ -366,44 +370,44 @@ github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2/go.mod h1:W github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU= github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= -github.com/aws/aws-sdk-go-v2 v1.31.0 h1:3V05LbxTSItI5kUqNwhJrrrY1BAXxXt0sN0l72QmG5U= -github.com/aws/aws-sdk-go-v2 v1.31.0/go.mod h1:ztolYtaEUtdpf9Wftr31CJfLVjOnD/CVRkKOOYgF8hA= -github.com/aws/aws-sdk-go-v2/config v1.27.38 h1:mMVyJJuSUdbD4zKXoxDgWrgM60QwlFEg+JhihCq6wCw= -github.com/aws/aws-sdk-go-v2/config v1.27.38/go.mod h1:6xOiNEn58bj/64MPKx89r6G/el9JZn8pvVbquSqTKK4= -github.com/aws/aws-sdk-go-v2/credentials v1.17.36 h1:zwI5WrT+oWWfzSKoTNmSyeBKQhsFRJRv+PGW/UZW+Yk= -github.com/aws/aws-sdk-go-v2/credentials v1.17.36/go.mod h1:3AG/sY1rc9NJrNWcN/3KPU4SIDPGTrd/qegKB0TnFdE= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14 h1:C/d03NAmh8C4BZXhuRNboF/DqhBkBCeDiJDcaqIT5pA= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.14/go.mod h1:7I0Ju7p9mCIdlrfS+JCgqcYD0VXz/N4yozsox+0o078= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18 h1:kYQ3H1u0ANr9KEKlGs/jTLrBFPo8P8NaH/w7A01NeeM= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.18/go.mod h1:r506HmK5JDUh9+Mw4CfGJGSSoqIiLCndAuqXuhbv67Y= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18 h1:Z7IdFUONvTcvS7YuhtVxN99v2cCoHRXOS4mTr0B/pUc= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.18/go.mod h1:DkKMmksZVVyat+Y+r1dEOgJEfUeA7UngIHWeKsi0yNc= +github.com/aws/aws-sdk-go-v2 v1.32.3 h1:T0dRlFBKcdaUPGNtkBSwHZxrtis8CQU17UpNBZYd0wk= +github.com/aws/aws-sdk-go-v2 v1.32.3/go.mod h1:2SK5n0a2karNTv5tbP1SjsX0uhttou00v/HpXKM1ZUo= +github.com/aws/aws-sdk-go-v2/config v1.28.1 h1:oxIvOUXy8x0U3fR//0eq+RdCKimWI900+SV+10xsCBw= +github.com/aws/aws-sdk-go-v2/config v1.28.1/go.mod h1:bRQcttQJiARbd5JZxw6wG0yIK3eLeSCPdg6uqmmlIiI= +github.com/aws/aws-sdk-go-v2/credentials v1.17.42 h1:sBP0RPjBU4neGpIYyx8mkU2QqLPl5u9cmdTWVzIpHkM= +github.com/aws/aws-sdk-go-v2/credentials v1.17.42/go.mod h1:FwZBfU530dJ26rv9saAbxa9Ej3eF/AK0OAY86k13n4M= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18 h1:68jFVtt3NulEzojFesM/WVarlFpCaXLKaBxDpzkQ9OQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18/go.mod h1:Fjnn5jQVIo6VyedMc0/EhPpfNlPl7dHV916O6B+49aE= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 h1:Jw50LwEkVjuVzE1NzkhNKkBf9cRN7MtE1F/b2cOKTUM= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22/go.mod h1:Y/SmAyPcOTmpeVaWSzSKiILfXTVJwrGmYZhcRbhWuEY= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 h1:981MHwBaRZM7+9QSR6XamDzF/o7ouUGxFzr+nVSIhrs= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22/go.mod h1:1RA1+aBEfn+CAB/Mh0MB6LsdCYCnjZm7tKXtnk499ZQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/service/ebs v1.22.1 h1:SeDJWG4pmye+/aO6k+zt9clPTUy1MXqUmkW8rbAddQg= github.com/aws/aws-sdk-go-v2/service/ebs v1.22.1/go.mod h1:wRzaW0v9GGQS0h//wpsVDw3Hah5gs5UP+NxoyGeZIGM= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.179.1 h1:TwFjSwRn1kR1i1qeq5cQBRwRaZ80JQS8BHsJTb6QBk8= -github.com/aws/aws-sdk-go-v2/service/ec2 v1.179.1/go.mod h1:W6sNzs5T4VpZn1Vy+FMKw8s24vt5k6zPJXcNOK0asBo= -github.com/aws/aws-sdk-go-v2/service/ecr v1.35.2 h1:bVNvja4oEB7v+VL1yP46hWthCPp+KYpZBLS2AifM5PY= -github.com/aws/aws-sdk-go-v2/service/ecr v1.35.2/go.mod h1:oRaGEExKI6Pqcow+Tt7wpJf73/Srcj/CUJv5Eb9QFhg= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.187.0 h1:cA4hWo269CN5RY7Arqt8BfzXF0KIN8DSNo/KcqHKkWk= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.187.0/go.mod h1:ossaD9Z1ugYb6sq9QIqQLEOorCGcqUoxlhud9M9yE70= +github.com/aws/aws-sdk-go-v2/service/ecr v1.36.3 h1:bqmoQEKpWFRDRxOv4lC5yZLc+N1cogZHPLeQACfVUJo= +github.com/aws/aws-sdk-go-v2/service/ecr v1.36.3/go.mod h1:KwOqlt4MOBK9EpOGkj8RU9fqfTEae5AOUHi1pDEZ3OQ= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2 h1:PpbXaecV3sLAS6rjQiaKw4/jyq3Z8gNzmoJupHAoBp0= github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.18.2/go.mod h1:fUHpGXr4DrXkEDpGAjClPsviWf+Bszeb0daKE0blxv8= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5 h1:QFASJGfT8wMXtuP3D5CRmMjARHv9ZmzFUMJznHDOY3w= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.5/go.mod h1:QdZ3OmoIjSX+8D1OPAzPxDfjXASbBMDsz9qvtyIhtik= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.20 h1:Xbwbmk44URTiHNx6PNo0ujDE6ERlsCKJD3u1zfnzAPg= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.20/go.mod h1:oAfOFzUB14ltPZj1rWwRc3d/6OgD76R8KlvU3EqM9Fg= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3 h1:qcxX0JYlgWH3hpPUnd6U0ikcl6LLA9sLkXE2w1fpMvY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3/go.mod h1:cLSNEmI45soc+Ef8K/L+8sEA3A3pYFEYf5B5UI+6bH4= github.com/aws/aws-sdk-go-v2/service/kms v1.30.0 h1:yS0JkEdV6h9JOo8sy2JSpjX+i7vsKifU8SIeHrqiDhU= github.com/aws/aws-sdk-go-v2/service/kms v1.30.0/go.mod h1:+I8VUUSVD4p5ISQtzpgSva4I8cJ4SQ4b1dcBcof7O+g= -github.com/aws/aws-sdk-go-v2/service/s3 v1.63.2 h1:1iXmXy8SJzQVMGvo40TSzBYS9ig6BSyXfRIMzLfmBfE= -github.com/aws/aws-sdk-go-v2/service/s3 v1.63.2/go.mod h1:NLTqRLe3pUNu3nTEHI6XlHLKYmc8fbHUdMxAB6+s41Q= -github.com/aws/aws-sdk-go-v2/service/sso v1.23.2 h1:yzi/y/vKlLyzOfG7pSu5ONNGRxHIgLeDrV4w2AMRCo0= -github.com/aws/aws-sdk-go-v2/service/sso v1.23.2/go.mod h1:XRlMvmad0ZNL+75C5FYdMvbbLkd6qiqz6foR1nA1PXY= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.2 h1:3gb6pYhYLjo8rB1h2Tqs61wpjRd3rQymYcVq/pp0yxI= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.27.2/go.mod h1:FnvDM4sfa+isJ3kDXIzAB9GAwVSzFzSy97uZ3IsHo4E= -github.com/aws/aws-sdk-go-v2/service/sts v1.31.2 h1:O6tyji8mXmBGsHvTCB0VIhrDw19lGTUSbKIyjnw79s8= -github.com/aws/aws-sdk-go-v2/service/sts v1.31.2/go.mod h1:yMWe0F+XG0DkRZK5ODZhG7BEFYhLXi2dqGsv6tX0cgI= -github.com/aws/smithy-go v1.21.0 h1:H7L8dtDRk0P1Qm6y0ji7MCYMQObJ5R9CRpyPhRUkLYA= -github.com/aws/smithy-go v1.21.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= +github.com/aws/aws-sdk-go-v2/service/s3 v1.66.2 h1:p9TNFL8bFUMd+38YIpTAXpoxyz0MxC7FlbFEH4P4E1U= +github.com/aws/aws-sdk-go-v2/service/s3 v1.66.2/go.mod h1:fNjyo0Coen9QTwQLWeV6WO2Nytwiu+cCcWaTdKCAqqE= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.3 h1:UTpsIf0loCIWEbrqdLb+0RxnTXfWh2vhw4nQmFi4nPc= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.3/go.mod h1:FZ9j3PFHHAR+w0BSEjK955w5YD2UwB/l/H0yAK3MJvI= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3 h1:2YCmIXv3tmiItw0LlYf6v7gEHebLY45kBEnPezbUKyU= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3/go.mod h1:u19stRyNPxGhj6dRm+Cdgu6N75qnbW7+QN0q0dsAk58= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.3 h1:wVnQ6tigGsRqSWDEEyH6lSAJ9OyFUsSnbaUWChuSGzs= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.3/go.mod h1:VZa9yTFyj4o10YGsmDO4gbQJUvvhY72fhumT8W4LqsE= +github.com/aws/smithy-go v1.22.0 h1:uunKnWlcoL3zO7q+gG2Pk53joueEOsnNB28QdMsmiMM= +github.com/aws/smithy-go v1.22.0/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8 h1:SoFYaT9UyGkR0+nogNyD/Lj+bsixB+SNuAS4ABlEs6M= github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20231024185945-8841054dbdb8/go.mod h1:2JF49jcDOrLStIXN/j/K1EKRq8a8R2qRnlZA6/o/c7c= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= @@ -418,8 +422,8 @@ github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdn github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ= -github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I= -github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= +github.com/bmatcuk/doublestar/v4 v4.7.1 h1:fdDeAqgT47acgwd9bd9HxJRDmc9UAmPpc+2m0CXv75Q= +github.com/bmatcuk/doublestar/v4 v4.7.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc= github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M= github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= github.com/briandowns/spinner v1.23.0 h1:alDF2guRWqa/FOZZYWjlMIx2L6H0wyewPxo/CH4Pt2A= @@ -511,8 +515,8 @@ github.com/containerd/typeurl/v2 v2.2.2/go.mod h1:95ljDnPfD3bAbDJRugOiShd/DlAAsx github.com/coreos/go-oidc v2.2.1+incompatible h1:mh48q/BqXqgjVHpy2ZY7WnWAbenxRjsz9N1i1YxjHAk= github.com/coreos/go-oidc/v3 v3.10.0 h1:tDnXHnLyiTVyT/2zLDGj09pFPkhND8Gl8lnTRhoEaJU= github.com/coreos/go-oidc/v3 v3.10.0/go.mod h1:5j11xcw0D3+SGxn6Z/WFADsgcWVMyNAlSQupk0KK3ac= -github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= -github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= @@ -537,8 +541,8 @@ github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWa github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= -github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= -github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54 h1:SG7nF6SRlWhcT7cNTs5R6Hk4V2lcmLz2NsG2VnInyNo= +github.com/dgryski/trifles v0.0.0-20230903005119-f50d829f2e54/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= github.com/digitorus/pkcs7 v0.0.0-20230713084857-e76b763bdc49/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc= github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 h1:ge14PCmCvPjpMQMIAH7uKg0lrtNSOdpYsRXlwk3QbaE= github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352/go.mod h1:SKVExuS+vpu2l9IoOc0RwqE7NYnb0JlcFHFnEJkVDzc= @@ -552,8 +556,8 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= github.com/dlclark/regexp2 v1.4.0 h1:F1rxgk7p4uKjwIQxBs9oAXe5CqrXlCduYEJvrF4u93E= github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= -github.com/docker/cli v27.2.1+incompatible h1:U5BPtiD0viUzjGAjV1p0MGB8eVA3L3cbIrnyWmSJI70= -github.com/docker/cli v27.2.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/cli v27.3.1+incompatible h1:qEGdFBF3Xu6SCvCYhc7CzaQTlBmqDuzxPDpigSyeKQQ= +github.com/docker/cli v27.3.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI= @@ -600,8 +604,8 @@ github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZM github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= -github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= -github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= +github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= @@ -959,6 +963,8 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6 h1:IsMZxCuZqKuao2vNdfD82fjjgPLfyHLpR41Z88viRWs= +github.com/keybase/go-keychain v0.0.0-20231219164618-57a3676c3af6/go.mod h1:3VeWNIJaW+O5xpRQbPp0Ybqu1vJd/pm7s2F473HRrkw= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= @@ -1072,8 +1078,8 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/mndrix/tap-go v0.0.0-20171203230836-629fa407e90b/go.mod h1:pzzDgJWZ34fGzaAZGFW22KVZDfyrYW+QABMrWnJBnSs= -github.com/moby/buildkit v0.16.0 h1:wOVBj1o5YNVad/txPQNXUXdelm7Hs/i0PUFjzbK0VKE= -github.com/moby/buildkit v0.16.0/go.mod h1:Xqx/5GlrqE1yIRORk0NSCVDFpQAU1WjlT6KHYZdisIQ= +github.com/moby/buildkit v0.17.0 h1:ZA/4AxwBbve1f3ZaNNJQiCBtTV62R6YweWNwq4A+sTc= +github.com/moby/buildkit v0.17.0/go.mod h1:ru8NFyDHD8HbuKaLXJIjK9nr3x6FZR+IWjtF07S+wdM= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= @@ -1138,8 +1144,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.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= -github.com/open-policy-agent/opa v0.68.1-0.20240903211041-76f7038ea2d1 h1:GQrryTKpunLNDc2NdhNL1FzfrbuNvo45s76anGdqz9k= -github.com/open-policy-agent/opa v0.68.1-0.20240903211041-76f7038ea2d1/go.mod h1:5E5SvaPwTpwt2WM177I9Z3eT7qUpmOGjk1ZdHs+TZ4w= +github.com/open-policy-agent/opa v0.70.0 h1:B3cqCN2iQAyKxK6+GI+N40uqkin+wzIrM7YA60t9x1U= +github.com/open-policy-agent/opa v0.70.0/go.mod h1:Y/nm5NY0BX0BqjBriKUiV81sCl8XOjjvqQG7dXrggtI= 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.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -1180,6 +1186,8 @@ github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjL github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo= +github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -1213,6 +1221,8 @@ github.com/quasilyte/go-ruleguard/dsl v0.3.22 h1:wd8zkOhSNr+I+8Qeciml08ivDt1pSXe github.com/quasilyte/go-ruleguard/dsl v0.3.22/go.mod h1:KeCP03KrjuSO0H1kTuZQCWlQPulDV6YMIXmpQss17rU= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 h1:N/ElC8H3+5XpJzTSTfLsJV/mx9Q9g7kxmchpfZyxgzM= github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/redis/go-redis/v9 v9.6.1 h1:HHDteefn6ZkTtY5fGUE8tj8uy85AHk6zP7CpzIAM0y4= +github.com/redis/go-redis/v9 v9.6.1/go.mod h1:0C0c6ycQsdpVNQpxb1njEQIqkx5UcsM8FJCQLgE9+RA= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= @@ -1339,12 +1349,12 @@ github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BG github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k= github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uRtcvYAPLCF15qguo= github.com/terminalstatic/go-xsd-validate v0.1.5/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw= -github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw= -github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8= -github.com/testcontainers/testcontainers-go/modules/localstack v0.33.0 h1:AhbUGUjneEnMyTV5aTsPYzDiAWrba1duPtiV+Z9CKdY= -github.com/testcontainers/testcontainers-go/modules/localstack v0.33.0/go.mod h1:J5vMq1fXXiTfwcJplMClHhn+j8+MbIMv7Lic4d9E8qU= -github.com/tetratelabs/wazero v1.8.0 h1:iEKu0d4c2Pd+QSRieYbnQC9yiFlMS9D+Jr0LsRmcF4g= -github.com/tetratelabs/wazero v1.8.0/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= +github.com/testcontainers/testcontainers-go v0.34.0 h1:5fbgF0vIN5u+nD3IWabQwRybuB4GY8G2HHgCkbMzMHo= +github.com/testcontainers/testcontainers-go v0.34.0/go.mod h1:6P/kMkQe8yqPHfPWNulFGdFHTD8HB2vLq/231xY2iPQ= +github.com/testcontainers/testcontainers-go/modules/localstack v0.34.0 h1:WkjVmea0XQyGTY10Er8fOsVjHQ77iJCmTExnx6fC3Tw= +github.com/testcontainers/testcontainers-go/modules/localstack v0.34.0/go.mod h1:rTo76O/BBeAtfazMQqLvfwBrntBBwDP7/+Z60dm3e9U= +github.com/tetratelabs/wazero v1.8.1 h1:NrcgVbWfkWvVc4UtT4LRLDf91PsOzDzefMdwhLfA550= +github.com/tetratelabs/wazero v1.8.1/go.mod h1:yAI0XTsMBhREkM/YDAK/zNou3GoiAce1P6+rp/wQhjs= github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg= github.com/thales-e-security/pool v0.0.2/go.mod h1:qtpMm2+thHtqhLzTwgDBj/OuNnMpupY8mv0Phz0gjhU= github.com/theupdateframework/go-tuf v0.7.0 h1:CqbQFrWo1ae3/I0UCblSbczevCCbS31Qvs5LdxRWqRI= @@ -1421,8 +1431,8 @@ github.com/zclconf/go-cty v1.15.0 h1:tTCRWxsexYUmtt/wVxgDClUe+uQusuI443uL6e+5sXQ github.com/zclconf/go-cty v1.15.0/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= -github.com/zclconf/go-cty-yaml v1.0.3 h1:og/eOQ7lvA/WWhHGFETVWNduJM7Rjsv2RRpx1sdFMLc= -github.com/zclconf/go-cty-yaml v1.0.3/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JAprQNgxSZ1Gyxs= +github.com/zclconf/go-cty-yaml v1.1.0 h1:nP+jp0qPHv2IhUVqmQSzjvqAWcObN0KBkUl2rWBdig0= +github.com/zclconf/go-cty-yaml v1.1.0/go.mod h1:9YLUH4g7lOhVWqUbctnVlZ5KLpg7JAprQNgxSZ1Gyxs= github.com/zeebo/errs v1.3.0 h1:hmiaKqgYZzcVgRL1Vkc1Mn2914BbzB0IBxs+ebeutGs= github.com/zeebo/errs v1.3.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4= go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ= @@ -1495,8 +1505,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611 h1:qCEDpW1G+vcj3Y7Fy52pEM1AWm3abj8WimGYejI3SC4= -golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= +golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -1757,8 +1767,8 @@ golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= -golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= +golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= @@ -1817,8 +1827,8 @@ golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps= -golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= +golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE= +golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg= golang.org/x/vuln v1.1.3 h1:NPGnvPOTgnjBc9HTaUx+nj+EaUYxl5SJOWqaDYGaFYw= golang.org/x/vuln v1.1.3/go.mod h1:7Le6Fadm5FOqE9C926BCD0g12NWyhg7cxV4BwcPFuNY= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -2088,8 +2098,8 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= -helm.sh/helm/v3 v3.16.1 h1:cER6tI/8PgUAsaJaQCVBUg3VI9KN4oVaZJgY60RIc0c= -helm.sh/helm/v3 v3.16.1/go.mod h1:r+xBHHP20qJeEqtvBXMf7W35QDJnzY/eiEBzt+TfHps= +helm.sh/helm/v3 v3.16.2 h1:Y9v7ry+ubQmi+cb5zw1Llx8OKHU9Hk9NQ/+P+LGBe2o= +helm.sh/helm/v3 v3.16.2/go.mod h1:SyTXgKBjNqi2NPsHCW5dDAsHqvGIu0kdNYNH9gQaw70= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= @@ -2099,8 +2109,8 @@ honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0= k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk= -k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= -k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= +k8s.io/apiextensions-apiserver v0.31.1 h1:L+hwULvXx+nvTYX/MKM3kKMZyei+UiSXQWciX/N6E40= +k8s.io/apiextensions-apiserver v0.31.1/go.mod h1:tWMPR3sgW+jsl2xm9v7lAyRF1rYEK71i9G5dRtkknoQ= k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw= k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= k8s.io/apiserver v0.31.2 h1:VUzOEUGRCDi6kX1OyQ801m4A7AUPglpsmGvdsekmcI4= diff --git a/integration/client_server_test.go b/integration/client_server_test.go index 4afed3fdc155..0df09c6ae051 100644 --- a/integration/client_server_test.go +++ b/integration/client_server_test.go @@ -559,7 +559,7 @@ func TestClientServerWithRedis(t *testing.T) { }) // Terminate the Redis container - require.NoError(t, redisC.Terminate(ctx)) + require.NoError(t, testcontainers.TerminateContainer(redisC)) t.Run("sad path", func(t *testing.T) { osArgs := setupClient(t, testArgs, addr, cacheDir) diff --git a/integration/registry_test.go b/integration/registry_test.go index 25ddaf5b2814..3f0469e2c396 100644 --- a/integration/registry_test.go +++ b/integration/registry_test.go @@ -132,7 +132,7 @@ func TestRegistry(t *testing.T) { // set up auth server authC, err := setupAuthServer(ctx, baseDir) require.NoError(t, err) - defer authC.Terminate(ctx) + testcontainers.CleanupContainer(t, authC) authURL, err := getURL(ctx, authC, authPort) require.NoError(t, err) @@ -140,7 +140,7 @@ func TestRegistry(t *testing.T) { // set up registry registryC, err := setupRegistry(ctx, baseDir, authURL) require.NoError(t, err) - defer registryC.Terminate(ctx) + testcontainers.CleanupContainer(t, registryC) registryURL, err := getURL(ctx, registryC, registryPort) require.NoError(t, err) diff --git a/pkg/fanal/test/integration/containerd_test.go b/pkg/fanal/test/integration/containerd_test.go index b635c3913d9c..375c5cd77c62 100644 --- a/pkg/fanal/test/integration/containerd_test.go +++ b/pkg/fanal/test/integration/containerd_test.go @@ -101,6 +101,7 @@ func startContainerd(t *testing.T, ctx context.Context, hostPath string) { Started: true, }) require.NoError(t, err) + testcontainers.CleanupContainer(t, containerdC) _, _, err = containerdC.Exec(ctx, []string{ "chmod", @@ -108,10 +109,6 @@ func startContainerd(t *testing.T, ctx context.Context, hostPath string) { "/run/containerd/containerd.sock", }) require.NoError(t, err) - - t.Cleanup(func() { - require.NoError(t, containerdC.Terminate(ctx)) - }) } // Each of these tests imports an image and tags it with the name found in the diff --git a/pkg/fanal/test/integration/registry_test.go b/pkg/fanal/test/integration/registry_test.go index 4bca93f0ccba..35a32536600e 100644 --- a/pkg/fanal/test/integration/registry_test.go +++ b/pkg/fanal/test/integration/registry_test.go @@ -73,7 +73,7 @@ func TestTLSRegistry(t *testing.T) { Started: true, }) require.NoError(t, err) - defer registryC.Terminate(ctx) + testcontainers.CleanupContainer(t, registryC) registryURL, err := getRegistryURL(ctx, registryC, registryPort) require.NoError(t, err) From ab32297e0a8220a427fa330025f8625281e02275 Mon Sep 17 00:00:00 2001 From: Pierre Guilleminot Date: Thu, 7 Nov 2024 11:22:29 +0100 Subject: [PATCH 180/183] fix(fs): add missing defered Cleanup() call to post analyzer fs (#7882) --- pkg/fanal/artifact/local/fs.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/fanal/artifact/local/fs.go b/pkg/fanal/artifact/local/fs.go index 2f5ef7fe4ecd..b6c2d46c839a 100644 --- a/pkg/fanal/artifact/local/fs.go +++ b/pkg/fanal/artifact/local/fs.go @@ -82,6 +82,7 @@ func (a Artifact) Inspect(ctx context.Context) (artifact.Reference, error) { if err != nil { return artifact.Reference{}, xerrors.Errorf("failed to prepare filesystem for post analysis: %w", err) } + defer composite.Cleanup() err = a.walker.Walk(a.rootPath, a.artifactOption.WalkerOption, func(filePath string, info os.FileInfo, opener analyzer.Opener) error { dir := a.rootPath From 99b2db3978562689cef956a71281abb84ff0ce47 Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Fri, 8 Nov 2024 07:21:49 +0600 Subject: [PATCH 181/183] fix(misconf): handle null properties in CloudFormation templates (#7813) Signed-off-by: nikpivkin --- .../cloudformation/parser/file_context.go | 10 ++++ .../scanners/cloudformation/parser/parser.go | 33 +++++++------ .../cloudformation/parser/parser_test.go | 49 +++++++++++++++++++ 3 files changed, 77 insertions(+), 15 deletions(-) diff --git a/pkg/iac/scanners/cloudformation/parser/file_context.go b/pkg/iac/scanners/cloudformation/parser/file_context.go index 949add1ca7c4..e1c8cfa87f40 100644 --- a/pkg/iac/scanners/cloudformation/parser/file_context.go +++ b/pkg/iac/scanners/cloudformation/parser/file_context.go @@ -1,6 +1,8 @@ package parser import ( + "github.com/samber/lo" + "github.com/aquasecurity/trivy/pkg/iac/ignore" iacTypes "github.com/aquasecurity/trivy/pkg/iac/types" ) @@ -71,3 +73,11 @@ func (t *FileContext) missingParameterValues() []string { } return missing } + +func (t *FileContext) stripNullProperties() { + for _, resource := range t.Resources { + resource.Inner.Properties = lo.OmitBy(resource.Inner.Properties, func(k string, v *Property) bool { + return v.IsNil() + }) + } +} diff --git a/pkg/iac/scanners/cloudformation/parser/parser.go b/pkg/iac/scanners/cloudformation/parser/parser.go index 696dfcf16349..24d85ba4bbbb 100644 --- a/pkg/iac/scanners/cloudformation/parser/parser.go +++ b/pkg/iac/scanners/cloudformation/parser/parser.go @@ -6,6 +6,7 @@ import ( "fmt" "io" "io/fs" + "path" "path/filepath" "strings" @@ -83,7 +84,7 @@ func (p *Parser) ParseFS(ctx context.Context, fsys fs.FS, dir string) (FileConte return contexts, nil } -func (p *Parser) ParseFile(ctx context.Context, fsys fs.FS, path string) (fctx *FileContext, err error) { +func (p *Parser) ParseFile(ctx context.Context, fsys fs.FS, filePath string) (fctx *FileContext, err error) { defer func() { if e := recover(); e != nil { err = fmt.Errorf("panic during parse: %s", e) @@ -105,15 +106,15 @@ func (p *Parser) ParseFile(ctx context.Context, fsys fs.FS, path string) (fctx * } sourceFmt := YamlSourceFormat - if strings.HasSuffix(strings.ToLower(path), ".json") { + if path.Ext(filePath) == ".json" { sourceFmt = JsonSourceFormat } - f, err := fsys.Open(filepath.ToSlash(path)) + f, err := fsys.Open(filePath) if err != nil { return nil, err } - defer func() { _ = f.Close() }() + defer f.Close() content, err := io.ReadAll(f) if err != nil { @@ -123,7 +124,7 @@ func (p *Parser) ParseFile(ctx context.Context, fsys fs.FS, path string) (fctx * lines := strings.Split(string(content), "\n") fctx = &FileContext{ - filepath: path, + filepath: filePath, lines: lines, SourceFormat: sourceFmt, } @@ -131,26 +132,28 @@ func (p *Parser) ParseFile(ctx context.Context, fsys fs.FS, path string) (fctx * switch sourceFmt { case YamlSourceFormat: if err := yaml.Unmarshal(content, fctx); err != nil { - return nil, NewErrInvalidContent(path, err) + return nil, NewErrInvalidContent(filePath, err) } - fctx.Ignores = ignore.Parse(string(content), path, "") + fctx.Ignores = ignore.Parse(string(content), filePath, "") case JsonSourceFormat: if err := jfather.Unmarshal(content, fctx); err != nil { - return nil, NewErrInvalidContent(path, err) + return nil, NewErrInvalidContent(filePath, err) } } + fctx.stripNullProperties() + fctx.overrideParameters(p.overridedParameters) if params := fctx.missingParameterValues(); len(params) > 0 { - p.logger.Warn("Missing parameter values", log.FilePath(path), log.String("parameters", strings.Join(params, ", "))) + p.logger.Warn("Missing parameter values", log.FilePath(filePath), log.String("parameters", strings.Join(params, ", "))) } fctx.lines = lines fctx.SourceFormat = sourceFmt - fctx.filepath = path + fctx.filepath = filePath - p.logger.Debug("Context loaded from source", log.FilePath(path)) + p.logger.Debug("Context loaded from source", log.FilePath(filePath)) // the context must be set to conditions before resources for _, c := range fctx.Conditions { @@ -158,7 +161,7 @@ func (p *Parser) ParseFile(ctx context.Context, fsys fs.FS, path string) (fctx * } for name, r := range fctx.Resources { - r.configureResource(name, fsys, path, fctx) + r.configureResource(name, fsys, filePath, fctx) } return fctx, nil @@ -190,10 +193,10 @@ func (p *Parser) parseParams() error { return nil } -func (p *Parser) parseParametersFile(path string) (Parameters, error) { - f, err := p.configsFS.Open(path) +func (p *Parser) parseParametersFile(filePath string) (Parameters, error) { + f, err := p.configsFS.Open(filePath) if err != nil { - return nil, fmt.Errorf("parameters file %q open error: %w", path, err) + return nil, fmt.Errorf("parameters file %q open error: %w", filePath, err) } var parameters Parameters diff --git a/pkg/iac/scanners/cloudformation/parser/parser_test.go b/pkg/iac/scanners/cloudformation/parser/parser_test.go index aa058c4df855..99dd62294eee 100644 --- a/pkg/iac/scanners/cloudformation/parser/parser_test.go +++ b/pkg/iac/scanners/cloudformation/parser/parser_test.go @@ -440,3 +440,52 @@ Conditions: require.NoError(t, err) require.Len(t, files, 1) } + +func Test_TemplateWithNullProperty(t *testing.T) { + src := `AWSTemplateFormatVersion: "2010-09-09" +Resources: + TestBucket: + Type: "AWS::S3::Bucket" + Properties: + BucketName:` + + fsys := testutil.CreateFS(t, map[string]string{ + "main.yaml": src, + }) + + files, err := New().ParseFS(context.TODO(), fsys, ".") + require.NoError(t, err) + require.Len(t, files, 1) + + file := files[0] + + res := file.GetResourceByLogicalID("TestBucket") + + assert.True(t, res.GetProperty("BucketName").IsNil()) +} + +func Test_TemplateWithNullNestedProperty(t *testing.T) { + src := `AWSTemplateFormatVersion: "2010-09-09" +Description: "BAD" +Resources: + TestBucket: + Type: "AWS::S3::Bucket" + Properties: + BucketName: test + PublicAccessBlockConfiguration: + BlockPublicAcls: null` + + fsys := testutil.CreateFS(t, map[string]string{ + "main.yaml": src, + }) + + files, err := New().ParseFS(context.TODO(), fsys, ".") + require.NoError(t, err) + require.Len(t, files, 1) + + file := files[0] + + res := file.GetResourceByLogicalID("TestBucket") + + assert.True(t, res.GetProperty("PublicAccessBlockConfiguration.BlockPublicAcls").IsNil()) +} From 611558e4ce61818330118684274534f26b1fda99 Mon Sep 17 00:00:00 2001 From: Alberto Donato Date: Fri, 8 Nov 2024 08:32:54 +0100 Subject: [PATCH 182/183] fix(terraform): set null value as fallback for missing variables (#7669) --- pkg/iac/scanners/terraform/parser/parser.go | 9 ++++++ .../scanners/terraform/parser/parser_test.go | 30 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/pkg/iac/scanners/terraform/parser/parser.go b/pkg/iac/scanners/terraform/parser/parser.go index 695cbee4fb25..866835d5f8a5 100644 --- a/pkg/iac/scanners/terraform/parser/parser.go +++ b/pkg/iac/scanners/terraform/parser/parser.go @@ -217,6 +217,7 @@ func (p *Parser) Load(ctx context.Context) (*evaluator, error) { "Variable values was not found in the environment or variable files. Evaluating may not work correctly.", log.String("variables", strings.Join(missingVars, ", ")), ) + setNullMissingVariableValues(inputVars, missingVars) } } @@ -268,6 +269,14 @@ func missingVariableValues(blocks terraform.Blocks, inputVars map[string]cty.Val return missing } +// Set null values for missing variables, to allow expressions using them to be +// still be possibly evaluated to a value different than null. +func setNullMissingVariableValues(inputVars map[string]cty.Value, missingVars []string) { + for _, missingVar := range missingVars { + inputVars[missingVar] = cty.NullVal(cty.DynamicPseudoType) + } +} + func (p *Parser) EvaluateAll(ctx context.Context) (terraform.Modules, cty.Value, error) { e, err := p.Load(ctx) diff --git a/pkg/iac/scanners/terraform/parser/parser_test.go b/pkg/iac/scanners/terraform/parser/parser_test.go index 540338afb57f..9c62b958a212 100644 --- a/pkg/iac/scanners/terraform/parser/parser_test.go +++ b/pkg/iac/scanners/terraform/parser/parser_test.go @@ -1801,6 +1801,36 @@ resource "test" "fileset-func" { assert.Equal(t, []string{"a.py", "path/b.py"}, attr.GetRawValue()) } +func TestExprWithMissingVar(t *testing.T) { + files := map[string]string{ + "main.tf": ` +variable "v" { + type = string +} + +resource "test" "values" { + s = "foo-${var.v}" + l1 = ["foo", var.v] + l2 = concat(["foo"], [var.v]) + d1 = {foo = var.v} + d2 = merge({"foo": "bar"}, {"baz": var.v}) +} +`, + } + + resources := parse(t, files).GetResourcesByType("test") + require.Len(t, resources, 1) + + s_attr := resources[0].GetAttribute("s") + require.NotNil(t, s_attr) + assert.Equal(t, "foo-", s_attr.GetRawValue()) + + for _, name := range []string{"l1", "l2", "d1", "d2"} { + attr := resources[0].GetAttribute(name) + require.NotNil(t, attr) + } +} + func TestVarTypeShortcut(t *testing.T) { files := map[string]string{ "main.tf": ` From bdfcc19f86e8b7da0b611fd42633086e4ebc48e4 Mon Sep 17 00:00:00 2001 From: Robiiin Date: Mon, 11 Nov 2024 12:55:55 +0800 Subject: [PATCH 183/183] chore(k8s): enhance k8s scan log (#6997) Co-authored-by: afdesk --- pkg/k8s/commands/run.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/k8s/commands/run.go b/pkg/k8s/commands/run.go index 6a20d04aee10..1650cfa1446f 100644 --- a/pkg/k8s/commands/run.go +++ b/pkg/k8s/commands/run.go @@ -86,6 +86,7 @@ func (r *runner) run(ctx context.Context, artifacts []*k8sArtifacts.Artifact) er r.flagOpts.ScanOptions.Scanners = scanners } var rpt report.Report + log.Info("Scanning K8s...", log.String("K8s", r.cluster)) rpt, err = s.Scan(ctx, artifacts) if err != nil { return xerrors.Errorf("k8s scan error: %w", err)