diff --git a/go.mod b/go.mod index 115681f53a..6eaf82bd47 100644 --- a/go.mod +++ b/go.mod @@ -453,9 +453,10 @@ require ( golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sys v0.34.0 // indirect - golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 // indirect + golang.org/x/telemetry v0.0.0-20250417124945-06ef541f3fa3 // indirect golang.org/x/time v0.12.0 // indirect - golang.org/x/tools v0.34.0 // indirect + golang.org/x/tools v0.34.1-0.20250610205101-c26dd3ba555e // indirect + golang.org/x/tools/gopls v0.19.1 // indirect google.golang.org/api v0.228.0 // indirect google.golang.org/genproto v0.0.0-20250303144028-a0af3efb3deb // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect @@ -497,5 +498,6 @@ tool ( github.com/magefile/mage github.com/twitchtv/twirp/protoc-gen-twirp golang.org/x/tools/cmd/goyacc + golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize sigs.k8s.io/kind ) diff --git a/go.sum b/go.sum index 4c09d6cf19..c5d3eddc17 100644 --- a/go.sum +++ b/go.sum @@ -2469,8 +2469,8 @@ golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE= -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/telemetry v0.0.0-20250417124945-06ef541f3fa3 h1:RXY2+rSHXvxO2Y+gKrPjYVaEoGOqh3VEXFhnWAt1Irg= +golang.org/x/telemetry v0.0.0-20250417124945-06ef541f3fa3/go.mod h1:RoaXAWDwS90j6FxVKwJdBV+0HCU+llrKUGgJaxiKl6M= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -2585,8 +2585,10 @@ golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= 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.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= -golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= -golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools v0.34.1-0.20250610205101-c26dd3ba555e h1:XnjOegqwH6kBJoae6InSGbIFPHcLtUT/Eq8HjrZKbmQ= +golang.org/x/tools v0.34.1-0.20250610205101-c26dd3ba555e/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= +golang.org/x/tools/gopls v0.19.1 h1:Yodhp3rnpnag60lVZrYPYbGMxTlTCIAj/B2Rv7AKuhA= +golang.org/x/tools/gopls v0.19.1/go.mod h1:wckRFPbJWrG05Cw01SpRSl1vVzIhtK9Yfq60NE3U9Wo= golang.org/x/vuln v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I= golang.org/x/vuln v1.1.4/go.mod h1:F+45wmU18ym/ca5PLTPLsSzr2KppzswxPP603ldA67s= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/magefiles/magefile.go b/magefiles/magefile.go index 93c546d6d9..1adb7c973c 100644 --- a/magefiles/magefile.go +++ b/magefiles/magefile.go @@ -339,15 +339,21 @@ func (t Test) E2e() error { type Lint mg.Namespace // Run runs linters -func (Lint) Run() error { - mg.Deps(Tool{}.GolangciLint) - return sh.RunV("golangci-lint", "run", "--build-tags=integration") +func (l Lint) Run() error { + mg.Deps(Tool{}.GolangciLint, Tool{}.Install) + if err := sh.RunV("golangci-lint", "run", "--build-tags=integration"); err != nil { + return err + } + return sh.RunV("modernize", "./...") } // Fix auto fixes linters -func (Lint) Fix() error { - mg.Deps(Tool{}.GolangciLint) - return sh.RunV("golangci-lint", "run", "--fix", "--build-tags=integration") +func (l Lint) Fix() error { + mg.Deps(Tool{}.GolangciLint, Tool{}.Install) + if err := sh.RunV("golangci-lint", "run", "--fix", "--build-tags=integration"); err != nil { + return err + } + return sh.RunV("modernize", "-fix", "./...") } // Fmt formats Go code diff --git a/magefiles/terraformplan.go b/magefiles/terraformplan.go index de3d9016b6..d0b571e5b6 100644 --- a/magefiles/terraformplan.go +++ b/magefiles/terraformplan.go @@ -80,7 +80,6 @@ func fixtureTerraformPlanSnapshots(ctx context.Context) error { g.SetLimit(terraformParallelLimit) for _, workingDir := range workingDirs { - workingDir := workingDir g.Go(func() error { if err := os.Remove(tfplanFile); err != nil && !errors.Is(err, os.ErrNotExist) { return err diff --git a/pkg/cache/fs_test.go b/pkg/cache/fs_test.go index 3729a0763e..c4f2670d94 100644 --- a/pkg/cache/fs_test.go +++ b/pkg/cache/fs_test.go @@ -227,9 +227,7 @@ func TestFSCache_PutBlob(t *testing.T) { "Packages": [ { "Name": "musl", - "Version": "1.1.22-r3", - "Identifier": {}, - "Layer": {} + "Version": "1.1.22-r3" } ] } @@ -241,15 +239,11 @@ func TestFSCache_PutBlob(t *testing.T) { "Packages": [ { "Name":"guzzlehttp/guzzle", - "Version":"6.2.0", - "Identifier": {}, - "Layer": {} + "Version":"6.2.0" }, { "Name":"guzzlehttp/promises", - "Version":"v1.3.1", - "Identifier": {}, - "Layer": {} + "Version":"v1.3.1" } ] } @@ -347,9 +341,7 @@ func TestFSCache_PutArtifact(t *testing.T) { "HistoryPackages": [ { "Name": "musl", - "Version": "1.2.3", - "Identifier": {}, - "Layer": {} + "Version": "1.2.3" } ] } diff --git a/pkg/cache/redis_test.go b/pkg/cache/redis_test.go index 528939cfa9..2c7da6f563 100644 --- a/pkg/cache/redis_test.go +++ b/pkg/cache/redis_test.go @@ -472,7 +472,7 @@ func TestRedisCache_Clear(t *testing.T) { require.NoError(t, err) defer s.Close() - for i := 0; i < 200; i++ { + for i := range 200 { s.Set(fmt.Sprintf("fanal::key%d", i), "value") } s.Set("foo", "bar") @@ -482,7 +482,7 @@ func TestRedisCache_Clear(t *testing.T) { require.NoError(t, err) require.NoError(t, c.Clear()) - for i := 0; i < 200; i++ { + for i := range 200 { assert.False(t, s.Exists(fmt.Sprintf("fanal::key%d", i))) } assert.True(t, s.Exists("foo")) diff --git a/pkg/commands/app.go b/pkg/commands/app.go index d9c0008b35..06a9a35dd2 100644 --- a/pkg/commands/app.go +++ b/pkg/commands/app.go @@ -125,7 +125,6 @@ func loadPluginCommands() []*cobra.Command { return nil } for _, p := range plugins { - p := p cmd := &cobra.Command{ Use: fmt.Sprintf("%s [flags]", p.Name), Short: p.Summary, diff --git a/pkg/compliance/report/testdata/all.json b/pkg/compliance/report/testdata/all.json index 8c39673c8a..79e099ef19 100644 --- a/pkg/compliance/report/testdata/all.json +++ b/pkg/compliance/report/testdata/all.json @@ -18,14 +18,7 @@ "Misconfigurations": [ { "AVDID": "AVD-KSV012", - "Status": "FAIL", - "Layer": {}, - "CauseMetadata": { - "Code": { - "Lines": null - }, - "RenderedCause": {} - } + "Status": "FAIL" } ] } @@ -42,14 +35,7 @@ "Misconfigurations": [ { "AVDID": "AVD-KSV013", - "Status": "FAIL", - "Layer": {}, - "CauseMetadata": { - "Code": { - "Lines": null - }, - "RenderedCause": {} - } + "Status": "FAIL" } ] } diff --git a/pkg/compliance/spec/compliance.go b/pkg/compliance/spec/compliance.go index 794d244ca9..66ac81e66b 100644 --- a/pkg/compliance/spec/compliance.go +++ b/pkg/compliance/spec/compliance.go @@ -88,8 +88,8 @@ func GetComplianceSpec(specNameOrPath, cacheDir string) (ComplianceSpec, error) var b []byte var err error - if strings.HasPrefix(specNameOrPath, "@") { // load user specified spec from disk - b, err = os.ReadFile(strings.TrimPrefix(specNameOrPath, "@")) + if after, ok := strings.CutPrefix(specNameOrPath, "@"); ok { // load user specified spec from disk + b, err = os.ReadFile(after) if err != nil { return ComplianceSpec{}, fmt.Errorf("error retrieving compliance spec from path: %w", err) } diff --git a/pkg/compliance/spec/compliance_test.go b/pkg/compliance/spec/compliance_test.go index b49f169ac7..4a80eba739 100644 --- a/pkg/compliance/spec/compliance_test.go +++ b/pkg/compliance/spec/compliance_test.go @@ -2,7 +2,7 @@ package spec_test import ( "path/filepath" - "sort" + "slices" "testing" "github.com/stretchr/testify/assert" @@ -129,9 +129,7 @@ func TestComplianceSpec_Scanners(t *testing.T) { if !tt.wantErr(t, err, "Scanners()") { return } - sort.Slice(got, func(i, j int) bool { - return got[i] < got[j] - }) // for consistency + slices.Sort(got) // for consistency assert.Equalf(t, tt.want, got, "Scanners()") }) } diff --git a/pkg/dependency/parser/java/pom/var.go b/pkg/dependency/parser/java/pom/var.go index 7f1853f657..dc179151ee 100644 --- a/pkg/dependency/parser/java/pom/var.go +++ b/pkg/dependency/parser/java/pom/var.go @@ -29,8 +29,8 @@ func evaluateVariable(s string, props map[string]string, seenProps []string) str // env.X: https://maven.apache.org/pom.html#Properties // e.g. env.PATH - if strings.HasPrefix(m[1], "env.") { - newValue = os.Getenv(strings.TrimPrefix(m[1], "env.")) + if after, ok := strings.CutPrefix(m[1], "env."); ok { + newValue = os.Getenv(after) } else { // might include another property. // e.g. ${skipTests} diff --git a/pkg/dependency/parser/python/poetry/parse.go b/pkg/dependency/parser/python/poetry/parse.go index ca74a533d5..6617417119 100644 --- a/pkg/dependency/parser/python/poetry/parse.go +++ b/pkg/dependency/parser/python/poetry/parse.go @@ -2,7 +2,6 @@ package poetry import ( "slices" - "sort" "github.com/BurntSushi/toml" "golang.org/x/xerrors" @@ -101,9 +100,7 @@ func (p *Parser) parseDependencies(deps map[string]any, pkgVersions map[string][ dependsOn = append(dependsOn, dep) } } - sort.Slice(dependsOn, func(i, j int) bool { - return dependsOn[i] < dependsOn[j] - }) + slices.Sort(dependsOn) return dependsOn } diff --git a/pkg/dependency/parser/utils/utils.go b/pkg/dependency/parser/utils/utils.go index 36afd90253..2e494d1d49 100644 --- a/pkg/dependency/parser/utils/utils.go +++ b/pkg/dependency/parser/utils/utils.go @@ -48,8 +48,6 @@ func MergeMaps(parent, child map[string]string) map[string]string { } // Clone parent map to avoid shadow overwrite newParent := maps.Clone(parent) - for k, v := range child { - newParent[k] = v - } + maps.Copy(newParent, child) return newParent } diff --git a/pkg/detector/library/compare/compare.go b/pkg/detector/library/compare/compare.go index 9f6f82c26d..a7b7dffbcb 100644 --- a/pkg/detector/library/compare/compare.go +++ b/pkg/detector/library/compare/compare.go @@ -1,6 +1,7 @@ package compare import ( + "slices" "strings" "golang.org/x/xerrors" @@ -20,10 +21,8 @@ type matchVersion func(currentVersion, constraint string) (bool, error) // IsVulnerable checks if the package version is vulnerable to the advisory. func IsVulnerable(pkgVer string, advisory dbTypes.Advisory, match matchVersion) bool { // If one of vulnerable/patched versions is empty, we should detect it anyway. - for _, v := range append(advisory.VulnerableVersions, advisory.PatchedVersions...) { - if v == "" { - return true - } + if slices.Contains(append(advisory.VulnerableVersions, advisory.PatchedVersions...), "") { + return true } var matched bool var err error diff --git a/pkg/digest/digest.go b/pkg/digest/digest.go index 3b55321161..7139934684 100644 --- a/pkg/digest/digest.go +++ b/pkg/digest/digest.go @@ -55,10 +55,7 @@ func (d Digest) String() string { } func (d Digest) sepIndex() int { - i := strings.Index(string(d), ":") - if i < 0 { - i = 0 - } + i := max(strings.Index(string(d), ":"), 0) return i } diff --git a/pkg/fanal/artifact/artifact.go b/pkg/fanal/artifact/artifact.go index cde1a3ea61..8c98dff30d 100644 --- a/pkg/fanal/artifact/artifact.go +++ b/pkg/fanal/artifact/artifact.go @@ -2,6 +2,7 @@ package artifact import ( "context" + "slices" "sort" "github.com/google/go-containerregistry/pkg/v1" @@ -73,9 +74,7 @@ func (o *Option) ConfigAnalyzerOptions() analyzer.ConfigAnalyzerOptions { } func (o *Option) Sort() { - sort.Slice(o.DisabledAnalyzers, func(i, j int) bool { - return o.DisabledAnalyzers[i] < o.DisabledAnalyzers[j] - }) + slices.Sort(o.DisabledAnalyzers) sort.Strings(o.WalkerOption.SkipFiles) sort.Strings(o.WalkerOption.SkipDirs) sort.Strings(o.FilePatterns) diff --git a/pkg/fanal/artifact/image/remote_sbom_test.go b/pkg/fanal/artifact/image/remote_sbom_test.go index 036a4b3a68..427f4dfcba 100644 --- a/pkg/fanal/artifact/image/remote_sbom_test.go +++ b/pkg/fanal/artifact/image/remote_sbom_test.go @@ -223,7 +223,7 @@ func TestArtifact_inspectOCIReferrerSBOM(t *testing.T) { }, wantBlobs: []cachetest.WantBlob{ { - ID: "sha256:a06ed679a3289fba254040e1ce8f3467fadcc454ee3d0d4720f6978065f56684", + ID: "sha256:2171d8ccf798e94d09aca9c6abf15d28abd3236def1caa4a394b6f0a69c4266d", BlobInfo: types.BlobInfo{ SchemaVersion: types.BlobJSONSchemaVersion, Applications: []types.Application{ @@ -267,9 +267,9 @@ func TestArtifact_inspectOCIReferrerSBOM(t *testing.T) { want: artifact.Reference{ Name: registry + "/test/image:10", Type: types.TypeCycloneDX, - ID: "sha256:a06ed679a3289fba254040e1ce8f3467fadcc454ee3d0d4720f6978065f56684", + ID: "sha256:2171d8ccf798e94d09aca9c6abf15d28abd3236def1caa4a394b6f0a69c4266d", BlobIDs: []string{ - "sha256:a06ed679a3289fba254040e1ce8f3467fadcc454ee3d0d4720f6978065f56684", + "sha256:2171d8ccf798e94d09aca9c6abf15d28abd3236def1caa4a394b6f0a69c4266d", }, }, }, diff --git a/pkg/fanal/artifact/vm/vm_test.go b/pkg/fanal/artifact/vm/vm_test.go index 1ad1b7b3ec..7e49b828be 100644 --- a/pkg/fanal/artifact/vm/vm_test.go +++ b/pkg/fanal/artifact/vm/vm_test.go @@ -118,16 +118,16 @@ func TestArtifact_Inspect(t *testing.T) { rootDir: "testdata/alpine", wantBlobs: []cachetest.WantBlob{ { - ID: "sha256:9ca6dbba47cea74d3f9b0bf0472314735d06f42d3ccf8cfe7c021f61a3420973", + ID: "sha256:c2baf06cb25f7b62686b169df5729402f0c50420bfcbdce8347f84c4bf623ab9", BlobInfo: expectedBlobInfo, }, }, want: artifact.Reference{ Name: "rawdata.img", Type: types.TypeVM, - ID: "sha256:9ca6dbba47cea74d3f9b0bf0472314735d06f42d3ccf8cfe7c021f61a3420973", + ID: "sha256:c2baf06cb25f7b62686b169df5729402f0c50420bfcbdce8347f84c4bf623ab9", BlobIDs: []string{ - "sha256:9ca6dbba47cea74d3f9b0bf0472314735d06f42d3ccf8cfe7c021f61a3420973", + "sha256:c2baf06cb25f7b62686b169df5729402f0c50420bfcbdce8347f84c4bf623ab9", }, }, }, diff --git a/pkg/fanal/test/integration/docker/docker.go b/pkg/fanal/test/integration/docker/docker.go index 7d7ad2865c..cda7f9f3e6 100644 --- a/pkg/fanal/test/integration/docker/docker.go +++ b/pkg/fanal/test/integration/docker/docker.go @@ -42,7 +42,7 @@ func (c RegistryConfig) GetRegistryAuth() (string, error) { } func (c RegistryConfig) GetBasicAuthorization() string { - return fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", c.Username, c.Password)))) + return fmt.Sprintf("Basic %s", base64.StdEncoding.EncodeToString(fmt.Appendf(nil, "%s:%s", c.Username, c.Password))) } type Docker struct { diff --git a/pkg/fanal/types/artifact.go b/pkg/fanal/types/artifact.go index 82cb97890c..bb721956fd 100644 --- a/pkg/fanal/types/artifact.go +++ b/pkg/fanal/types/artifact.go @@ -177,7 +177,7 @@ type BlobInfo struct { WhiteoutFiles []string `json:",omitempty"` // Analysis result - OS OS `json:",omitempty"` + OS OS `json:",omitzero"` Repository *Repository `json:",omitempty"` PackageInfos []PackageInfo `json:",omitempty"` Applications []Application `json:",omitempty"` @@ -206,7 +206,7 @@ func (b BlobInfo) Layer() Layer { // ArtifactDetail represents the analysis result. type ArtifactDetail struct { - OS OS `json:",omitempty"` + OS OS `json:",omitzero"` Repository *Repository `json:",omitempty"` Packages Packages `json:",omitempty"` Applications Applications `json:",omitempty"` diff --git a/pkg/fanal/types/license.go b/pkg/fanal/types/license.go index a168b1983b..b9d259ad52 100644 --- a/pkg/fanal/types/license.go +++ b/pkg/fanal/types/license.go @@ -27,7 +27,7 @@ type LicenseFile struct { FilePath string PkgName string Findings LicenseFindings - Layer Layer `json:",omitempty"` + Layer Layer `json:",omitzero"` } type LicenseFindings []LicenseFinding diff --git a/pkg/fanal/types/misconf.go b/pkg/fanal/types/misconf.go index 70201e33fd..82f7393d0b 100644 --- a/pkg/fanal/types/misconf.go +++ b/pkg/fanal/types/misconf.go @@ -13,15 +13,15 @@ type Misconfiguration struct { Successes MisconfResults `json:",omitempty"` Warnings MisconfResults `json:",omitempty"` Failures MisconfResults `json:",omitempty"` - Layer Layer `json:",omitempty"` + Layer Layer `json:",omitzero"` } type MisconfResult struct { Namespace string `json:",omitempty"` Query string `json:",omitempty"` Message string `json:",omitempty"` - PolicyMetadata `json:",omitempty"` - CauseMetadata `json:",omitempty"` + PolicyMetadata `json:",omitzero"` + CauseMetadata `json:",omitzero"` // For debugging Traces []string `json:",omitempty"` @@ -35,9 +35,9 @@ type CauseMetadata struct { Service string `json:",omitempty"` StartLine int `json:",omitempty"` EndLine int `json:",omitempty"` - Code Code `json:",omitempty"` + Code Code `json:",omitzero"` Occurrences []Occurrence `json:",omitempty"` - RenderedCause RenderedCause `json:",omitempty"` + RenderedCause RenderedCause `json:",omitzero"` } type Occurrence struct { diff --git a/pkg/fanal/types/package.go b/pkg/fanal/types/package.go index 340ad868b1..a7be8c574c 100644 --- a/pkg/fanal/types/package.go +++ b/pkg/fanal/types/package.go @@ -179,7 +179,7 @@ type BuildInfo struct { type Package struct { ID string `json:",omitempty"` Name string `json:",omitempty"` - Identifier PkgIdentifier `json:",omitempty"` + Identifier PkgIdentifier `json:",omitzero"` Version string `json:",omitempty"` Release string `json:",omitempty"` Epoch int `json:",omitempty"` @@ -203,7 +203,7 @@ type Package struct { // Note: it may have interdependencies, which may lead to infinite loops. DependsOn []string `json:",omitempty"` - Layer Layer `json:",omitempty"` + Layer Layer `json:",omitzero"` // Each package metadata have the file path, while the package from lock files does not have. FilePath string `json:",omitempty"` diff --git a/pkg/fanal/types/secret.go b/pkg/fanal/types/secret.go index a2747cad75..2771f56389 100644 --- a/pkg/fanal/types/secret.go +++ b/pkg/fanal/types/secret.go @@ -16,5 +16,5 @@ type SecretFinding struct { EndLine int Code Code Match string - Layer Layer `json:",omitempty"` + Layer Layer `json:",omitzero"` } diff --git a/pkg/fanal/walker/tar.go b/pkg/fanal/walker/tar.go index 0c7d0bee9d..228b1b7f3d 100644 --- a/pkg/fanal/walker/tar.go +++ b/pkg/fanal/walker/tar.go @@ -54,8 +54,8 @@ func (w LayerTar) Walk(layer io.Reader, analyzeFn WalkFunc) ([]string, []string, continue } // etc/.wh.hostname - if strings.HasPrefix(fileName, wh) { - name := strings.TrimPrefix(fileName, wh) + if after, ok := strings.CutPrefix(fileName, wh); ok { + name := after fpath := path.Join(fileDir, name) whFiles = append(whFiles, fpath) continue diff --git a/pkg/iac/detection/detect_test.go b/pkg/iac/detection/detect_test.go index a0c907ea24..3ed40e36ff 100644 --- a/pkg/iac/detection/detect_test.go +++ b/pkg/iac/detection/detect_test.go @@ -515,8 +515,8 @@ func BenchmarkIsType_SmallFile(b *testing.B) { require.NoError(b, err) b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { + + for b.Loop() { _ = IsType(fmt.Sprintf("./testdata/%s", "small.file"), bytes.NewReader(data), FileTypeAzureARM) } } @@ -526,8 +526,8 @@ func BenchmarkIsType_BigFile(b *testing.B) { require.NoError(b, err) b.ReportAllocs() - b.ResetTimer() - for i := 0; i < b.N; i++ { + + for b.Loop() { _ = IsType(fmt.Sprintf("./testdata/%s", "big.file"), bytes.NewReader(data), FileTypeAzureARM) } } diff --git a/pkg/iac/rego/load_test.go b/pkg/iac/rego/load_test.go index 955496a162..348f48ce0e 100644 --- a/pkg/iac/rego/load_test.go +++ b/pkg/iac/rego/load_test.go @@ -237,7 +237,7 @@ func Test_FallbackErrorWithoutLocation(t *testing.T) { }, } - for i := 0; i < ast.CompileErrorLimitDefault+1; i++ { + for i := range ast.CompileErrorLimitDefault + 1 { src := `# METADATA # schemas: # - input: schema["fooschema"] @@ -247,7 +247,7 @@ deny { input.evil == "foo bar" }` fsys[fmt.Sprintf("policies/my-check%d.rego", i)] = &fstest.MapFile{ - Data: []byte(fmt.Sprintf(src, i)), + Data: fmt.Appendf(nil, src, i), } } @@ -330,7 +330,7 @@ func TestIsMinimumTrivyVersion(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { fsys := fstest.MapFS{ - "check.rego": &fstest.MapFile{Data: []byte(fmt.Sprintf(`# METADATA + "check.rego": &fstest.MapFile{Data: fmt.Appendf(nil, `# METADATA # title: "dummy title" # description: "some description" # scope: package @@ -341,7 +341,7 @@ func TestIsMinimumTrivyVersion(t *testing.T) { package builtin.foo.ABC123 deny { input.evil -}`, tc.MinimumTrivyVersion))}, +}`, tc.MinimumTrivyVersion)}, } scanner := rego.NewScanner( rego.WithPolicyDirs("."), diff --git a/pkg/iac/scan/rule.go b/pkg/iac/scan/rule.go index f75a252ff4..93042b2bbd 100755 --- a/pkg/iac/scan/rule.go +++ b/pkg/iac/scan/rule.go @@ -3,6 +3,7 @@ package scan import ( "fmt" "regexp" + "slices" "strings" "golang.org/x/text/cases" @@ -66,12 +67,7 @@ func (r Rule) HasID(id string) bool { if r.AVDID == id || r.LongID() == id { return true } - for _, alias := range r.Aliases { - if alias == id { - return true - } - } - return false + return slices.Contains(r.Aliases, id) } func (r Rule) LongID() string { diff --git a/pkg/iac/scanners/azure/arm/parser/armjson/bench_test.go b/pkg/iac/scanners/azure/arm/parser/armjson/bench_test.go index 1437a9b83b..627607a5b4 100644 --- a/pkg/iac/scanners/azure/arm/parser/armjson/bench_test.go +++ b/pkg/iac/scanners/azure/arm/parser/armjson/bench_test.go @@ -34,7 +34,7 @@ func BenchmarkUnmarshal_JFather(b *testing.B) { } }`) - for n := 0; n < b.N; n++ { + for b.Loop() { metadata := types.NewTestMetadata() require.NoError(b, Unmarshal(input, &target, &metadata)) } @@ -65,7 +65,7 @@ func BenchmarkUnmarshal_Traditional(b *testing.B) { } }`) - for n := 0; n < b.N; n++ { + for b.Loop() { require.NoError(b, json.Unmarshal(input, &target)) } } diff --git a/pkg/iac/scanners/azure/arm/parser/armjson/reader_test.go b/pkg/iac/scanners/azure/arm/parser/armjson/reader_test.go index 8017f30f9f..f7a1f5d488 100644 --- a/pkg/iac/scanners/azure/arm/parser/armjson/reader_test.go +++ b/pkg/iac/scanners/azure/arm/parser/armjson/reader_test.go @@ -16,7 +16,7 @@ func Test_Peeker(t *testing.T) { var b rune var err error - for i := 0; i < 30; i++ { + for range 30 { b, err = peeker.Peek() require.NoError(t, err) assert.Equal(t, ('a'), b) @@ -34,7 +34,7 @@ func Test_Peeker(t *testing.T) { require.NoError(t, err) assert.Equal(t, ('c'), b) - for i := 0; i < 5; i++ { + for i := range 5 { b, err = peeker.Next() require.NoError(t, err) assert.Equal(t, []rune(input)[2+i], b) @@ -47,7 +47,7 @@ func Test_Peeker(t *testing.T) { b, err = peeker.Next() require.NoError(t, err) assert.Equal(t, ('h'), b) - for i := 0; i < 18; i++ { + for i := range 18 { b, err = peeker.Next() require.NoError(t, err) assert.Equal(t, []rune(input)[8+i], b) diff --git a/pkg/iac/scanners/azure/functions/contains.go b/pkg/iac/scanners/azure/functions/contains.go index 3d735c95c2..859a89a22a 100644 --- a/pkg/iac/scanners/azure/functions/contains.go +++ b/pkg/iac/scanners/azure/functions/contains.go @@ -2,6 +2,7 @@ package functions import ( "fmt" + "slices" "strings" ) @@ -23,11 +24,7 @@ func Contains(args ...any) any { return strings.Contains(strings.ToLower(cType), fmt.Sprintf("%d", iType)) } case []any: - for _, item := range cType { - if item == itemToFind { - return true - } - } + return slices.Contains(cType, itemToFind) case map[string]any: for key := range cType { if key == itemToFind { diff --git a/pkg/iac/scanners/azure/functions/equals.go b/pkg/iac/scanners/azure/functions/equals.go index 2034e18bc0..a52499bea9 100644 --- a/pkg/iac/scanners/azure/functions/equals.go +++ b/pkg/iac/scanners/azure/functions/equals.go @@ -12,7 +12,7 @@ func Equals(args ...any) any { if len(slice1) != len(slice2) { return false } - for i := 0; i < len(slice1); i++ { + for i := range slice1 { if slice1[i] != slice2[i] { return false } diff --git a/pkg/iac/scanners/azure/functions/intersection.go b/pkg/iac/scanners/azure/functions/intersection.go index 590ebfaf68..d32db89d45 100644 --- a/pkg/iac/scanners/azure/functions/intersection.go +++ b/pkg/iac/scanners/azure/functions/intersection.go @@ -1,6 +1,9 @@ package functions -import "sort" +import ( + "maps" + "sort" +) func Intersection(args ...any) any { @@ -54,9 +57,7 @@ func intersectionArray(args ...any) any { func intersectionMap(args ...any) any { hash := make(map[string]any) - for k, v := range args[0].(map[string]any) { - hash[k] = v - } + maps.Copy(hash, args[0].(map[string]any)) for i := 1; i < len(args); i++ { workingHash := make(map[string]any) diff --git a/pkg/iac/scanners/azure/functions/pick_zones.go b/pkg/iac/scanners/azure/functions/pick_zones.go index 696cfe5a18..25d26205a5 100644 --- a/pkg/iac/scanners/azure/functions/pick_zones.go +++ b/pkg/iac/scanners/azure/functions/pick_zones.go @@ -7,10 +7,7 @@ func PickZones(args ...any) any { numOfZones := 1 if len(args) > 3 { - numOfZones = args[3].(int) - if numOfZones > 3 { - numOfZones = 3 - } + numOfZones = min(args[3].(int), 3) } var zones []int diff --git a/pkg/iac/scanners/azure/functions/union.go b/pkg/iac/scanners/azure/functions/union.go index 0f55b0b90c..ba3b295dce 100644 --- a/pkg/iac/scanners/azure/functions/union.go +++ b/pkg/iac/scanners/azure/functions/union.go @@ -1,6 +1,9 @@ package functions -import "sort" +import ( + "maps" + "sort" +) func Union(args ...any) any { if len(args) == 0 { @@ -26,9 +29,7 @@ func unionMap(args ...any) any { for _, arg := range args { if iType, ok := arg.(map[string]any); ok { - for k, v := range iType { - result[k] = v - } + maps.Copy(result, iType) } } diff --git a/pkg/iac/scanners/azure/value.go b/pkg/iac/scanners/azure/value.go index 1e216de9d4..64fe46399f 100644 --- a/pkg/iac/scanners/azure/value.go +++ b/pkg/iac/scanners/azure/value.go @@ -1,6 +1,7 @@ package azure import ( + "maps" "slices" "strings" "time" @@ -70,9 +71,7 @@ func NewValue(value any, metadata types.Metadata) Value { case map[string]Value: v.Kind = KindObject v.rMap = make(map[string]Value) - for key, val := range ty { - v.rMap[key] = val - } + maps.Copy(v.rMap, ty) case string: v.Kind = KindString v.rLit = ty diff --git a/pkg/iac/scanners/cloudformation/parser/fn_and.go b/pkg/iac/scanners/cloudformation/parser/fn_and.go index a155120e41..0030d0761a 100644 --- a/pkg/iac/scanners/cloudformation/parser/fn_and.go +++ b/pkg/iac/scanners/cloudformation/parser/fn_and.go @@ -16,7 +16,7 @@ func ResolveAnd(property *Property) (resolved *Property, success bool) { } results := make([]bool, len(refValue)) - for i := 0; i < len(refValue); i++ { + for i := range refValue { r := false if refValue[i].IsBool() { diff --git a/pkg/iac/scanners/cloudformation/parser/fn_builtin.go b/pkg/iac/scanners/cloudformation/parser/fn_builtin.go index 6859fa0f4f..7e4101ec4a 100644 --- a/pkg/iac/scanners/cloudformation/parser/fn_builtin.go +++ b/pkg/iac/scanners/cloudformation/parser/fn_builtin.go @@ -52,7 +52,7 @@ func calculateCidrs(ipaddress string, count, bit int, original *Property) ([]*Pr return nil, err } - for i := 0; i < count; i++ { + for i := range count { next, err := cidr.Subnet(network, bit, i) if err != nil { return nil, errors.New("failed to create cidr blocks") diff --git a/pkg/iac/scanners/cloudformation/parser/fn_or.go b/pkg/iac/scanners/cloudformation/parser/fn_or.go index 48fd802d10..da13774e71 100644 --- a/pkg/iac/scanners/cloudformation/parser/fn_or.go +++ b/pkg/iac/scanners/cloudformation/parser/fn_or.go @@ -16,7 +16,7 @@ func ResolveOr(property *Property) (resolved *Property, success bool) { } results := make([]bool, len(refValue)) - for i := 0; i < len(refValue); i++ { + for i := range refValue { r := false if refValue[i].IsBool() { diff --git a/pkg/iac/scanners/helm/parser/vals.go b/pkg/iac/scanners/helm/parser/vals.go index 891cae957c..7e5a343fbe 100644 --- a/pkg/iac/scanners/helm/parser/vals.go +++ b/pkg/iac/scanners/helm/parser/vals.go @@ -3,6 +3,7 @@ package parser import ( "fmt" "io" + "maps" "net/url" "os" "strings" @@ -73,9 +74,7 @@ func (opts *ValueOptions) MergeValues() (map[string]any, error) { func mergeMaps(a, b map[string]any) map[string]any { out := make(map[string]any, len(a)) - for k, v := range a { - out[k] = v - } + maps.Copy(out, a) for k, v := range b { if v, ok := v.(map[string]any); ok { if bv, ok := out[k]; ok { diff --git a/pkg/iac/scanners/helm/scanner.go b/pkg/iac/scanners/helm/scanner.go index fc6173d980..8a5cf08f87 100644 --- a/pkg/iac/scanners/helm/scanner.go +++ b/pkg/iac/scanners/helm/scanner.go @@ -122,7 +122,6 @@ func (s *Scanner) getScanResults(ctx context.Context, path string, target fs.FS) } for _, file := range chartFiles { - file := file s.logger.Debug("Processing rendered chart file", log.FilePath(file.TemplateFilePath)) ignoreRules := ignore.Parse(file.ManifestContent, file.TemplateFilePath, "") diff --git a/pkg/iac/scanners/terraform/deterministic_test.go b/pkg/iac/scanners/terraform/deterministic_test.go index c0e45fa8d8..fb2503b509 100644 --- a/pkg/iac/scanners/terraform/deterministic_test.go +++ b/pkg/iac/scanners/terraform/deterministic_test.go @@ -32,7 +32,7 @@ locals { `, }) - for i := 0; i < 100; i++ { + for range 100 { results, err := scanFS(fsys, ".", rego.WithPolicyReader(strings.NewReader(emptyBucketCheck)), rego.WithPolicyNamespaces("user"), diff --git a/pkg/iac/scanners/terraform/parser/ctylist_test.go b/pkg/iac/scanners/terraform/parser/ctylist_test.go index 874d3a217e..70be3db752 100644 --- a/pkg/iac/scanners/terraform/parser/ctylist_test.go +++ b/pkg/iac/scanners/terraform/parser/ctylist_test.go @@ -93,7 +93,6 @@ func Test_insertTupleElement(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() diff --git a/pkg/iac/scanners/terraform/parser/evaluator.go b/pkg/iac/scanners/terraform/parser/evaluator.go index 53e469eba5..ba66cadef5 100644 --- a/pkg/iac/scanners/terraform/parser/evaluator.go +++ b/pkg/iac/scanners/terraform/parser/evaluator.go @@ -171,7 +171,7 @@ func (e *evaluator) evaluateSubmodules(ctx context.Context, parent *terraform.Mo e.logger.Debug("Starting submodules evaluation...") - for i := 0; i < maxContextIterations; i++ { + for i := range maxContextIterations { changed := false for _, sm := range submodules { changed = changed || e.evaluateSubmodule(ctx, sm) @@ -196,9 +196,7 @@ func (e *evaluator) evaluateSubmodules(ctx context.Context, parent *terraform.Mo } modules = append(modules, sm.modules...) - for k, v := range sm.fsMap { - fsMap[k] = v - } + maps.Copy(fsMap, sm.fsMap) } e.logger.Debug("Finished processing submodule(s).", log.Int("count", len(modules))) @@ -268,7 +266,7 @@ func (e *evaluator) evaluateSubmodule(ctx context.Context, sm *submodule) bool { func (e *evaluator) evaluateSteps() { var lastContext hcl.EvalContext - for i := 0; i < maxContextIterations; i++ { + for i := range maxContextIterations { e.logger.Debug("Starting iteration", log.Int("iteration", i)) e.evaluateStep() @@ -281,9 +279,7 @@ func (e *evaluator) evaluateSteps() { if len(e.ctx.Inner().Variables) != len(lastContext.Variables) { lastContext.Variables = make(map[string]cty.Value, len(e.ctx.Inner().Variables)) } - for k, v := range e.ctx.Inner().Variables { - lastContext.Variables[k] = v - } + maps.Copy(lastContext.Variables, e.ctx.Inner().Variables) } } diff --git a/pkg/iac/scanners/terraform/parser/funcs/ip.go b/pkg/iac/scanners/terraform/parser/funcs/ip.go index d1cf0352e9..6bdd0feb00 100644 --- a/pkg/iac/scanners/terraform/parser/funcs/ip.go +++ b/pkg/iac/scanners/terraform/parser/funcs/ip.go @@ -68,7 +68,7 @@ var IPv4 = stdnet.IPv4 // Parse IPv4 address (d.d.d.d). func parseIPv4(s string) IP { var p [IPv4len]byte - for i := 0; i < IPv4len; i++ { + for i := range IPv4len { if len(s) == 0 { // Missing octets. return nil diff --git a/pkg/iac/scanners/terraform/parser/load_vars.go b/pkg/iac/scanners/terraform/parser/load_vars.go index 58f67ce939..622c9df162 100644 --- a/pkg/iac/scanners/terraform/parser/load_vars.go +++ b/pkg/iac/scanners/terraform/parser/load_vars.go @@ -3,6 +3,7 @@ package parser import ( "fmt" "io/fs" + "maps" "os" "path/filepath" "strings" @@ -35,9 +36,7 @@ func loadTFVars(srcFS fs.FS, filenames []string) (map[string]cty.Value, error) { if err != nil { return nil, fmt.Errorf("failed to load tfvars from %s: %w", filename, err) } - for k, v := range vars { - combinedVars[k] = v - } + maps.Copy(combinedVars, vars) } return combinedVars, nil diff --git a/pkg/iac/scanners/terraform/parser/parser_test.go b/pkg/iac/scanners/terraform/parser/parser_test.go index b12c9db3cb..07faa5c117 100644 --- a/pkg/iac/scanners/terraform/parser/parser_test.go +++ b/pkg/iac/scanners/terraform/parser/parser_test.go @@ -1979,7 +1979,6 @@ func TestModuleParents(t *testing.T) { modSet := set.New[*terraform.Module]() var root *terraform.Module for _, mod := range modules { - mod := mod modChildren[mod] = make([]*terraform.Module, 0) modSet.Append(mod) diff --git a/pkg/iac/scanners/terraform/performance_test.go b/pkg/iac/scanners/terraform/performance_test.go index 640facb603..a10d5ebeb9 100644 --- a/pkg/iac/scanners/terraform/performance_test.go +++ b/pkg/iac/scanners/terraform/performance_test.go @@ -20,8 +20,7 @@ func BenchmarkCalculate(b *testing.B) { b.Fatal(err) } - b.ResetTimer() - for i := 0; i < b.N; i++ { + for b.Loop() { p := parser.New(f, "", parser.OptionStopOnHCLError(true)) require.NoError(b, p.ParseFS(b.Context(), "project")) modules, err := p.EvaluateAll(b.Context()) diff --git a/pkg/iac/severity/severity.go b/pkg/iac/severity/severity.go index 45e9e1740d..69d9b63eea 100755 --- a/pkg/iac/severity/severity.go +++ b/pkg/iac/severity/severity.go @@ -1,6 +1,7 @@ package severity import ( + "slices" "strings" ) @@ -19,12 +20,7 @@ var ValidSeverity = []Severity{ } func (s *Severity) IsValid() bool { - for _, severity := range ValidSeverity { - if severity == *s { - return true - } - } - return false + return slices.Contains(ValidSeverity, *s) } func (s *Severity) Valid() []Severity { diff --git a/pkg/iac/terraform/block.go b/pkg/iac/terraform/block.go index e474fd4bc1..a1bc3e7fd3 100644 --- a/pkg/iac/terraform/block.go +++ b/pkg/iac/terraform/block.go @@ -183,7 +183,7 @@ func (b *Block) Clone(index cty.Value) *Block { if len(clone.hclBlock.Labels) > 0 { position := len(clone.hclBlock.Labels) - 1 labels := make([]string, len(clone.hclBlock.Labels)) - for i := 0; i < len(labels); i++ { + for i := range labels { labels[i] = clone.hclBlock.Labels[i] } if index.IsKnown() && !index.IsNull() { diff --git a/pkg/iac/terraform/context/context.go b/pkg/iac/terraform/context/context.go index be7acb7af9..ad50005def 100644 --- a/pkg/iac/terraform/context/context.go +++ b/pkg/iac/terraform/context/context.go @@ -1,6 +1,7 @@ package context import ( + "maps" "strings" "github.com/hashicorp/hcl/v2" @@ -126,9 +127,7 @@ func mergeVars(src cty.Value, parts []string, value cty.Value) cty.Value { func mergeObjects(a, b cty.Value) cty.Value { output := make(map[string]cty.Value) - for key, val := range a.AsValueMap() { - output[key] = val - } + maps.Copy(output, a.AsValueMap()) b.ForEachElement(func(key, val cty.Value) (stop bool) { k := key.AsString() old := output[k] diff --git a/pkg/iac/terraform/value_functions.go b/pkg/iac/terraform/value_functions.go index 1071a608e3..e6406493f5 100644 --- a/pkg/iac/terraform/value_functions.go +++ b/pkg/iac/terraform/value_functions.go @@ -3,6 +3,7 @@ package terraform import ( "fmt" "regexp" + "slices" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/gocty" @@ -45,17 +46,9 @@ func executeFunction(functionName string, criteriaValues, testValue any) bool { func isAny(criteriaValues, testValue any) bool { switch t := criteriaValues.(type) { case []any: - for _, v := range t { - if v == testValue { - return true - } - } + return slices.Contains(t, testValue) case []string: - for _, v := range t { - if v == testValue.(string) { - return true - } - } + return slices.Contains(t, testValue.(string)) } return false } diff --git a/pkg/iac/types/fskey.go b/pkg/iac/types/fskey.go index a8b57af817..35db93d2af 100644 --- a/pkg/iac/types/fskey.go +++ b/pkg/iac/types/fskey.go @@ -10,5 +10,5 @@ func CreateFSKey(filesystem fs.FS) string { if filesystem == nil { return "" } - return fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprintf("%s%#[1]v", filesystem)))) + return fmt.Sprintf("%x", sha256.Sum256(fmt.Appendf(nil, "%s%#[1]v", filesystem))) } diff --git a/pkg/iac/types/string.go b/pkg/iac/types/string.go index 0e6ba02113..739ade38a0 100755 --- a/pkg/iac/types/string.go +++ b/pkg/iac/types/string.go @@ -2,6 +2,7 @@ package types import ( "encoding/json" + "slices" "strings" ) @@ -87,12 +88,7 @@ func (s StringValue) IsOneOf(values ...string) bool { if s.metadata.isUnresolvable { return false } - for _, value := range values { - if value == s.value { - return true - } - } - return false + return slices.Contains(values, s.value) } func (s StringValue) GetMetadata() Metadata { diff --git a/pkg/k8s/report/summary.go b/pkg/k8s/report/summary.go index 05ba3645d8..3f9b065963 100644 --- a/pkg/k8s/report/summary.go +++ b/pkg/k8s/report/summary.go @@ -199,7 +199,7 @@ func configureHeader(s SummaryWriter, t *table.Table, columnHeading []string) { table.AlignLeft, table.AlignLeft, } - for i := 0; i < count; i++ { + for range count { headerRow = append(headerRow, s.SeverityHeadings...) colSpan = append(colSpan, sevCount) headerAlignment = append(headerAlignment, table.AlignCenter) diff --git a/pkg/licensing/normalize.go b/pkg/licensing/normalize.go index d87cfab4b4..81c8664101 100644 --- a/pkg/licensing/normalize.go +++ b/pkg/licensing/normalize.go @@ -620,10 +620,7 @@ func isLicenseText(str string) bool { func TrimLicenseText(text string) string { s := strings.Split(text, " ") - n := len(s) - if n > 3 { - n = 3 - } + n := min(len(s), 3) return strings.Join(s[:n], " ") + "..." } diff --git a/pkg/misconf/scanner.go b/pkg/misconf/scanner.go index 5f1e978fa4..72939aa531 100644 --- a/pkg/misconf/scanner.go +++ b/pkg/misconf/scanner.go @@ -451,7 +451,7 @@ func CreateDataFS(dataPaths []string, opts ...string) (fs.FS, []string, error) { if err := fsys.MkdirAll("system", 0o700); err != nil { return nil, nil, err } - data := []byte(fmt.Sprintf(`{"k8s": {"version": %q}}`, k8sVersion)) + data := fmt.Appendf(nil, `{"k8s": {"version": %q}}`, k8sVersion) if err := fsys.WriteVirtualFile("system/k8s-version.json", data, 0o600); err != nil { return nil, nil, err } diff --git a/pkg/report/template.go b/pkg/report/template.go index ed145cf392..a2b4407fc0 100644 --- a/pkg/report/template.go +++ b/pkg/report/template.go @@ -6,6 +6,7 @@ import ( "encoding/xml" "html" "io" + "maps" "os" "strings" "text/template" @@ -29,8 +30,8 @@ type TemplateWriter struct { // NewTemplateWriter is the factory method to return TemplateWriter object func NewTemplateWriter(output io.Writer, outputTemplate, appVersion string) (*TemplateWriter, error) { - if strings.HasPrefix(outputTemplate, "@") { - buf, err := os.ReadFile(strings.TrimPrefix(outputTemplate, "@")) + if after, ok := strings.CutPrefix(outputTemplate, "@"); ok { + buf, err := os.ReadFile(after) if err != nil { return nil, xerrors.Errorf("error retrieving template from path: %w", err) } @@ -60,9 +61,7 @@ func NewTemplateWriter(output io.Writer, outputTemplate, appVersion string) (*Te } // Overwrite functions - for k, v := range CustomTemplateFuncMap { - templateFuncMap[k] = v - } + maps.Copy(templateFuncMap, CustomTemplateFuncMap) tmpl, err := template.New("output template").Funcs(templateFuncMap).Parse(outputTemplate) if err != nil { diff --git a/pkg/report/template_test.go b/pkg/report/template_test.go index c8098a5d76..07efd13272 100644 --- a/pkg/report/template_test.go +++ b/pkg/report/template_test.go @@ -180,8 +180,7 @@ func TestReportWriter_Template(t *testing.T) { "PkgIdentifier": { "PURL": "pkg:npm/foobar@1.2.3" }, - "Status": "affected", - "Layer": {} + "Status": "affected" }`, }, { diff --git a/pkg/result/ignore.go b/pkg/result/ignore.go index 4c17691f4e..99d62fca9a 100644 --- a/pkg/result/ignore.go +++ b/pkg/result/ignore.go @@ -272,8 +272,8 @@ func parseIgnore(ignoreFile string) (IgnoreFindings, error) { func getExpirationDate(fields []string) (time.Time, error) { for _, field := range fields { - if strings.HasPrefix(field, "exp:") { - return time.Parse("2006-01-02", strings.TrimPrefix(field, "exp:")) + if after, ok := strings.CutPrefix(field, "exp:"); ok { + return time.Parse("2006-01-02", after) } } diff --git a/pkg/sbom/cyclonedx/marshal.go b/pkg/sbom/cyclonedx/marshal.go index 7260ad5032..2b172e2262 100644 --- a/pkg/sbom/cyclonedx/marshal.go +++ b/pkg/sbom/cyclonedx/marshal.go @@ -303,10 +303,10 @@ func (m *Marshaler) Licenses(licenses []string) *cdx.Licenses { func (m *Marshaler) normalizeLicense(license string) cdx.LicenseChoice { // Save text license as licenseChoice.license.name - if strings.HasPrefix(license, licensing.LicenseTextPrefix) { + if after, ok := strings.CutPrefix(license, licensing.LicenseTextPrefix); ok { return cdx.LicenseChoice{ License: &cdx.License{ - Name: strings.TrimPrefix(license, licensing.LicenseTextPrefix), + Name: after, }, } } diff --git a/pkg/sbom/spdx/marshal.go b/pkg/sbom/spdx/marshal.go index e2aa9860e8..3af2fbb80e 100644 --- a/pkg/sbom/spdx/marshal.go +++ b/pkg/sbom/spdx/marshal.go @@ -419,8 +419,8 @@ func (m *Marshaler) normalizeLicenses(licenses []string) (string, []*spdx.OtherL // We need to save text licenses before normalization, // because it is impossible to handle all cases possible in the text. // as an example, parse a license with 2 consecutive tokens (see https://github.com/aquasecurity/trivy/issues/8465) - if strings.HasPrefix(license, licensing.LicenseTextPrefix) { - license = strings.TrimPrefix(license, licensing.LicenseTextPrefix) + if after, ok := strings.CutPrefix(license, licensing.LicenseTextPrefix); ok { + license = after otherLicense := m.newOtherLicense(license, true) otherLicenses[otherLicense.LicenseIdentifier] = otherLicense return otherLicense.LicenseIdentifier diff --git a/pkg/scan/local/service.go b/pkg/scan/local/service.go index c61be47eba..ea700dc772 100644 --- a/pkg/scan/local/service.go +++ b/pkg/scan/local/service.go @@ -431,8 +431,8 @@ 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) + if after, ok := strings.CutPrefix(license, licensing.LicenseTextPrefix); ok { // License text + licenseText = after category, severity = scanner.ScanTextLicense(licenseText) license = licensing.CustomLicensePrefix + ": " + licensing.TrimLicenseText(licenseText) // Use `CUSTOM LICENSE: *...` format for text licenses } else { // License name diff --git a/pkg/types/misconfiguration.go b/pkg/types/misconfiguration.go index ebd21a23d3..877d641c08 100644 --- a/pkg/types/misconfiguration.go +++ b/pkg/types/misconfiguration.go @@ -17,8 +17,8 @@ type DetectedMisconfiguration struct { PrimaryURL string `json:",omitempty"` References []string `json:",omitempty"` Status MisconfStatus `json:",omitempty"` - Layer ftypes.Layer `json:",omitempty"` - CauseMetadata ftypes.CauseMetadata `json:",omitempty"` + Layer ftypes.Layer `json:",omitzero"` + CauseMetadata ftypes.CauseMetadata `json:",omitzero"` // For debugging Traces []string `json:",omitempty"` diff --git a/pkg/types/report.go b/pkg/types/report.go index c8ce90aeb4..c10e1d3eb8 100644 --- a/pkg/types/report.go +++ b/pkg/types/report.go @@ -12,10 +12,10 @@ import ( // Report represents a scan result type Report struct { SchemaVersion int `json:",omitempty"` - CreatedAt time.Time `json:",omitempty"` + CreatedAt time.Time `json:",omitzero"` ArtifactName string `json:",omitempty"` ArtifactType ftypes.ArtifactType `json:",omitempty"` - Metadata Metadata `json:",omitempty"` + Metadata Metadata `json:",omitzero"` Results Results `json:",omitempty"` // parsed SBOM @@ -32,7 +32,7 @@ type Metadata struct { DiffIDs []string `json:",omitempty"` RepoTags []string `json:",omitempty"` RepoDigests []string `json:",omitempty"` - ImageConfig v1.ConfigFile `json:",omitempty"` + ImageConfig v1.ConfigFile `json:",omitzero"` Layers ftypes.Layers `json:",omitzero"` } diff --git a/pkg/types/scan.go b/pkg/types/scan.go index 4db3e5e8ef..633a640a90 100644 --- a/pkg/types/scan.go +++ b/pkg/types/scan.go @@ -88,12 +88,7 @@ func (scanners *Scanners) Enabled(s Scanner) bool { // 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 + return slices.ContainsFunc(ss, scanners.Enabled) } // ScanTarget holds the attributes for scanning. diff --git a/pkg/types/vulnerability.go b/pkg/types/vulnerability.go index 68914b8835..51f76f999d 100644 --- a/pkg/types/vulnerability.go +++ b/pkg/types/vulnerability.go @@ -12,11 +12,11 @@ type DetectedVulnerability struct { PkgID string `json:",omitempty"` // It is used to construct dependency graph. PkgName string `json:",omitempty"` PkgPath string `json:",omitempty"` // This field is populated in the case of language-specific packages such as egg/wheel and gemspec - PkgIdentifier ftypes.PkgIdentifier `json:",omitempty"` + PkgIdentifier ftypes.PkgIdentifier `json:",omitzero"` InstalledVersion string `json:",omitempty"` FixedVersion string `json:",omitempty"` Status types.Status `json:",omitempty"` - Layer ftypes.Layer `json:",omitempty"` + Layer ftypes.Layer `json:",omitzero"` SeveritySource types.SourceID `json:",omitempty"` PrimaryURL string `json:",omitempty"` diff --git a/pkg/x/http/trace.go b/pkg/x/http/trace.go index ee55b10898..89c9a08c7e 100644 --- a/pkg/x/http/trace.go +++ b/pkg/x/http/trace.go @@ -284,7 +284,7 @@ func redactQueryParams(u *url.URL) *url.URL { func (tt *traceTransport) redactBody(body []byte, contentType string) []byte { // Check if body is too large if len(body) > maxBodySize { - return []byte(fmt.Sprintf("", len(body))) + return fmt.Appendf(nil, "", len(body)) } // Check if body is binary