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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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.aaakk.us.kg.aquasecurity.trivy.pkg.iac.providers.aws.s3.Encryption" }, + "grants": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.providers.aws.s3.Grant" + } + }, "lifecycleconfiguration": { "type": "array", "items": { @@ -3713,6 +3720,43 @@ } } }, + "github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.providers.aws.s3.Grant": { + "type": "object", + "properties": { + "__defsec_metadata": { + "type": "object", + "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.Metadata" + }, + "grantee": { + "type": "object", + "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.providers.aws.s3.Grantee" + }, + "permissions": { + "type": "array", + "items": { + "type": "object", + "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.StringValue" + } + } + } + }, + "github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.providers.aws.s3.Grantee": { + "type": "object", + "properties": { + "__defsec_metadata": { + "type": "object", + "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.Metadata" + }, + "type": { + "type": "object", + "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.StringValue" + }, + "uri": { + "type": "object", + "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.StringValue" + } + } + }, "github.aaakk.us.kg.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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.Metadata" }, "end": { - "type": "integer" + "type": "object", + "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.IntValue" }, "start": { - "type": "integer" + "type": "object", + "$ref": "#/definitions/github.aaakk.us.kg.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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.StringValue" } }, + "fromport": { + "type": "object", + "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.IntValue" + }, "protocol": { "type": "object", "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.StringValue" }, + "toport": { + "type": "object", + "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.IntValue" + }, "type": { "type": "object", "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.StringValue" @@ -1677,6 +1685,18 @@ "description": { "type": "object", "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.StringValue" + }, + "fromport": { + "type": "object", + "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.IntValue" + }, + "protocol": { + "type": "object", + "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.StringValue" + }, + "toport": { + "type": "object", + "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.IntValue" } } }, @@ -6086,7 +6106,7 @@ "type": "array", "items": { "type": "object", - "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.IntValue" + "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.providers.google.compute.PortRange" } }, "protocol": { @@ -6218,6 +6238,23 @@ } } }, + "github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.providers.google.compute.PortRange": { + "type": "object", + "properties": { + "__defsec_metadata": { + "type": "object", + "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.Metadata" + }, + "end": { + "type": "object", + "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.IntValue" + }, + "start": { + "type": "object", + "$ref": "#/definitions/github.aaakk.us.kg.aquasecurity.trivy.pkg.iac.types.IntValue" + } + } + }, "github.aaakk.us.kg.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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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/127] 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 5dbdadfe4578288d5c3f2a5b625fff4a3580f8c5 Mon Sep 17 00:00:00 2001 From: Aqua Security automated builds <54269356+aqua-bot@users.noreply.github.com> Date: Thu, 3 Oct 2024 16:26:26 +0300 Subject: [PATCH 122/127] fix(db): fix javadb downloading error handling [backport: release/v0.56] (#7646) Signed-off-by: nikpivkin Co-authored-by: Nikita Pivkin --- 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 95dbf1152b2049a6ae2ae90a507630df01798bf1 Mon Sep 17 00:00:00 2001 From: Aqua Security automated builds <54269356+aqua-bot@users.noreply.github.com> Date: Thu, 3 Oct 2024 17:10:29 +0300 Subject: [PATCH 123/127] release: v0.56.1 [release/v0.56] (#7648) --- .release-please-manifest.json | 2 +- CHANGELOG.md | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 208746a81be3..50a55827b64f 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1 +1 @@ -{".":"0.56.0"} +{".":"0.56.1"} diff --git a/CHANGELOG.md b/CHANGELOG.md index afc44ba7a956..90a121cda211 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [0.56.1](https://github.com/aquasecurity/trivy/compare/v0.56.0...v0.56.1) (2024-10-03) + + +### Bug Fixes + +* **db:** fix javadb downloading error handling [backport: release/v0.56] ([#7646](https://github.com/aquasecurity/trivy/issues/7646)) ([5dbdadf](https://github.com/aquasecurity/trivy/commit/5dbdadfe4578288d5c3f2a5b625fff4a3580f8c5)) + ## [0.56.0](https://github.com/aquasecurity/trivy/compare/v0.55.0...v0.56.0) (2024-10-03) From 25d2540f12272603bf27eb67f4b3fba52b1ddab8 Mon Sep 17 00:00:00 2001 From: Aqua Security automated builds <54269356+aqua-bot@users.noreply.github.com> Date: Wed, 9 Oct 2024 15:32:01 +0300 Subject: [PATCH 124/127] fix(sbom): add options for DBs in private registries [backport: release/v0.56] (#7691) Signed-off-by: knqyf263 Co-authored-by: Teppei Fukuda --- 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 f6700ec10e819fb2fc0573782e87d2d31d2c50f1 Mon Sep 17 00:00:00 2001 From: Aqua Security automated builds <54269356+aqua-bot@users.noreply.github.com> Date: Thu, 10 Oct 2024 10:37:05 +0300 Subject: [PATCH 125/127] fix(redhat): include arch in PURL qualifiers [backport: release/v0.56] (#7702) Signed-off-by: knqyf263 Co-authored-by: Teppei Fukuda --- 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 f2252c833d4dee18546577f0c32ceb83c8bf20ae Mon Sep 17 00:00:00 2001 From: Aqua Security automated builds <54269356+aqua-bot@users.noreply.github.com> Date: Thu, 10 Oct 2024 11:53:12 +0300 Subject: [PATCH 126/127] release: v0.56.2 [release/v0.56] (#7694) --- .release-please-manifest.json | 2 +- CHANGELOG.md | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 50a55827b64f..4991af476c6a 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1 +1 @@ -{".":"0.56.1"} +{".":"0.56.2"} diff --git a/CHANGELOG.md b/CHANGELOG.md index 90a121cda211..6d6fb0c912be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [0.56.2](https://github.com/aquasecurity/trivy/compare/v0.56.1...v0.56.2) (2024-10-10) + + +### Bug Fixes + +* **redhat:** include arch in PURL qualifiers [backport: release/v0.56] ([#7702](https://github.com/aquasecurity/trivy/issues/7702)) ([f6700ec](https://github.com/aquasecurity/trivy/commit/f6700ec10e819fb2fc0573782e87d2d31d2c50f1)) +* **sbom:** add options for DBs in private registries [backport: release/v0.56] ([#7691](https://github.com/aquasecurity/trivy/issues/7691)) ([25d2540](https://github.com/aquasecurity/trivy/commit/25d2540f12272603bf27eb67f4b3fba52b1ddab8)) + ## [0.56.1](https://github.com/aquasecurity/trivy/compare/v0.56.0...v0.56.1) (2024-10-03) From ce2a08e5c81692e5561f235fe7a229a27f0c5257 Mon Sep 17 00:00:00 2001 From: Franco <48300215+fhielpos@users.noreply.github.com> Date: Fri, 20 Dec 2024 13:38:18 +0100 Subject: [PATCH 127/127] Make liveness probe configurable (#3) --- helm/trivy/templates/statefulset.yaml | 2 +- helm/trivy/values.yaml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/helm/trivy/templates/statefulset.yaml b/helm/trivy/templates/statefulset.yaml index 4a931d2ac0b0..fef41a47da3c 100644 --- a/helm/trivy/templates/statefulset.yaml +++ b/helm/trivy/templates/statefulset.yaml @@ -105,7 +105,7 @@ spec: scheme: HTTP path: /healthz port: trivy-http - initialDelaySeconds: 5 + initialDelaySeconds: {{ default 5 .Values.livenessProbe.initialDelaySeconds }} periodSeconds: 10 successThreshold: 1 failureThreshold: 10 diff --git a/helm/trivy/values.yaml b/helm/trivy/values.yaml index a969f10b7899..73d780d6a0b1 100644 --- a/helm/trivy/values.yaml +++ b/helm/trivy/values.yaml @@ -56,6 +56,11 @@ tolerations: [] ## Ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/ podAnnotations: {} +# Allow Trivy to download the database before being killed. In some cases the conection to gsoci can be slow and take longer than the default +# Maybe we can remove this once we have Zot +livenessProbe: + initialDelaySeconds: 300 + trivy: # debugMode the flag to enable Trivy debug mode debugMode: false