From 5b58ec96b7dcf39e6be556312de0fc9fcab5dd18 Mon Sep 17 00:00:00 2001 From: anchore-oss-update-bot Date: Wed, 15 Apr 2026 10:01:39 -0400 Subject: [PATCH] chore(deps): update Go version (#4773) Signed-off-by: anchore-oss-update-bot Co-authored-by: anchore-oss-update-bot --- .github/actions/bootstrap/action.yaml | 10 +- cmd/syft/internal/commands/attest.go | 2 +- cmd/syft/internal/commands/cataloger_info.go | 14 +-- cmd/syft/internal/commands/convert.go | 2 +- cmd/syft/internal/commands/packages.go | 2 +- cmd/syft/internal/commands/packages_test.go | 12 +- cmd/syft/internal/commands/scan.go | 2 +- cmd/syft/internal/commands/scan_test.go | 2 +- cmd/syft/internal/options/catalog.go | 7 +- cmd/syft/internal/options/writer_test.go | 2 +- .../test/integration/catalog_packages_test.go | 8 +- .../package_cataloger_convention_test.go | 2 +- cmd/syft/internal/ui/log_writer_test.go | 24 ++-- go.mod | 2 +- internal/capabilities/evaluation.go | 10 +- internal/capabilities/evaluation_test.go | 104 +++++++++--------- .../generate/discover_app_config.go | 20 ++-- .../generate/discover_app_config_test.go | 4 +- .../generate/discover_catalogers.go | 4 +- internal/capabilities/generate/io.go | 4 +- .../internal/load_capabilities_test.go | 10 +- internal/file/getter_test.go | 4 +- internal/file/zip_file_manifest_test.go | 1 - internal/file/zip_file_traversal_test.go | 5 +- internal/jsonschema/main.go | 2 +- internal/log/log.go | 24 ++-- internal/packagemetadata/names_test.go | 74 ++++++------- internal/regex_helpers.go | 5 +- ...lude_binaries_by_file_ownership_overlap.go | 6 +- ...binaries_by_file_ownership_overlap_test.go | 1 - internal/sourcemetadata/names.go | 10 +- internal/string_helpers.go | 12 +- internal/tmpdir/tmpdir_test.go | 6 +- internal/tprint.go | 2 +- internal/unknown/coordinate_error.go | 8 +- syft/artifact/id.go | 2 +- syft/artifact/relationship.go | 2 +- syft/configuration_audit_trail.go | 6 +- syft/configuration_audit_trail_test.go | 4 +- syft/create_sbom_config.go | 2 +- syft/event/parsers/parsers.go | 4 +- .../common/spdxhelpers/to_format_model.go | 4 +- .../common/spdxhelpers/to_syft_model.go | 2 +- .../common/spdxhelpers/to_syft_model_test.go | 2 +- .../internal/model/github_dependency_api.go | 2 +- .../internal/cyclonedxutil/helpers/author.go | 2 +- .../cyclonedxutil/helpers/component.go | 4 +- .../internal/cyclonedxutil/helpers/decoder.go | 8 +- .../cyclonedxutil/helpers/description.go | 2 +- .../helpers/external_references.go | 2 +- .../internal/cyclonedxutil/helpers/group.go | 2 +- .../cyclonedxutil/helpers/properties.go | 6 +- .../cyclonedxutil/helpers/property_encoder.go | 4 +- .../helpers/property_encoder_test.go | 2 +- .../cyclonedxutil/helpers/publisher.go | 2 +- syft/format/syftjson/model/document.go | 2 +- .../syftjson/model/linux_release_test.go | 2 +- syft/format/syftjson/model/package.go | 2 +- syft/format/syftjson/model/package_test.go | 14 +-- syft/format/syftjson/model/relationship.go | 2 +- syft/format/syftjson/model/source.go | 4 +- syft/format/syftjson/schema_test.go | 7 +- syft/format/syftjson/to_format_model.go | 4 +- syft/format/syftjson/to_syft_model.go | 4 +- syft/format/syftjson/to_syft_model_test.go | 10 +- syft/format/template/encoder.go | 4 +- syft/get_source_test.go | 2 +- .../fileresolver/directory_indexer.go | 4 +- syft/internal/fileresolver/directory_test.go | 1 - .../fileresolver/filetree_resolver_test.go | 3 +- .../fileresolver/path_skipper_test.go | 2 +- .../fileresolver/unindexed_directory.go | 2 +- .../fileresolver/unindexed_directory_test.go | 1 - .../internal/unionreader/union_reader_test.go | 6 +- syft/pkg/apk.go | 8 +- syft/pkg/cataloger/ai/cataloger_test.go | 4 +- syft/pkg/cataloger/ai/parse_gguf.go | 4 +- syft/pkg/cataloger/ai/test_helpers_test.go | 2 +- syft/pkg/cataloger/arch/parse_alpm_db.go | 12 +- syft/pkg/cataloger/conda/cataloger_test.go | 2 +- syft/pkg/cataloger/debian/parse_dpkg_db.go | 8 +- .../cataloger/debian/parse_dpkg_db_test.go | 4 +- syft/pkg/cataloger/erlang/erlang_parser.go | 4 +- syft/pkg/cataloger/gentoo/license.go | 4 +- syft/pkg/cataloger/golang/upx.go | 7 +- .../pkg/cataloger/internal/cpegenerate/apk.go | 4 +- .../dictionary/index-generator/generate.go | 4 +- .../index-generator/nvd_api_client.go | 2 +- .../cataloger/internal/licenses/names_test.go | 1 - syft/pkg/cataloger/internal/pe/bundle.go | 2 +- syft/pkg/cataloger/internal/pe/pe.go | 2 +- .../internal/pkgtest/metadata_tracker.go | 18 ++- .../internal/pkgtest/observing_resolver.go | 7 +- .../internal/pkgtest/test_generic_parser.go | 6 +- .../pkg/cataloger/java/archive_parser_test.go | 5 +- .../pkg/cataloger/java/parse_java_manifest.go | 8 +- syft/pkg/cataloger/java/parse_pom_xml_test.go | 4 +- .../javascript/parse_package_json.go | 12 +- .../cataloger/javascript/parse_pnpm_lock.go | 8 +- syft/pkg/cataloger/lua/rockspec_parser.go | 2 +- syft/pkg/cataloger/python/package.go | 2 +- .../cataloger/python/parse_requirements.go | 10 +- syft/pkg/cataloger/ruby/parse_gemspec.go | 2 +- .../cataloger/swift/parse_package_resolved.go | 4 +- .../pkg/cataloger/swift/parse_podfile_lock.go | 4 +- syft/pkg/cataloger/wordpress/parse_plugin.go | 2 +- syft/pkg/gguf.go | 2 +- syft/pkg/package.go | 6 +- syft/sbom/sbom.go | 2 +- syft/source/description.go | 2 +- syft/source/snapsource/snap_source_test.go | 2 +- syft/source/snapsource/snapcraft_api_test.go | 2 +- test/cli/trait_assertions_test.go | 2 +- 113 files changed, 339 insertions(+), 394 deletions(-) diff --git a/.github/actions/bootstrap/action.yaml b/.github/actions/bootstrap/action.yaml index 150a1e458..5102777dc 100644 --- a/.github/actions/bootstrap/action.yaml +++ b/.github/actions/bootstrap/action.yaml @@ -1,11 +1,10 @@ name: "Bootstrap" - description: "Bootstrap all tools and dependencies" inputs: go-version: description: "Go version to install" required: true - default: "1.26.x" + default: "1.26.2" go-dependencies: description: "Download go dependencies" required: true @@ -24,7 +23,6 @@ inputs: bootstrap-apt-packages: description: "Space delimited list of tools to install via apt" default: "libxml2-utils" - runs: using: "composite" steps: @@ -34,7 +32,6 @@ runs: with: go-version: ${{ inputs.go-version }} check-latest: true - - name: Restore tool cache if: inputs.tools == 'true' id: tool-cache @@ -42,7 +39,6 @@ runs: with: path: ${{ github.workspace }}/.tool key: ${{ inputs.cache-key-prefix }}-${{ runner.os }}-tool-${{ hashFiles('.binny.yaml') }} - - name: Install project tools shell: bash if: inputs.tools == 'true' @@ -50,12 +46,10 @@ runs: make tools .tool/binny list .tool/binny check - - name: Install go dependencies if: inputs.go-dependencies == 'true' shell: bash run: make ci-bootstrap-go - - name: Install apt packages if: inputs.bootstrap-apt-packages != '' shell: bash @@ -64,14 +58,12 @@ runs: run: | IFS=' ' read -ra packages <<< "$APT_PACKAGES" DEBIAN_FRONTEND=noninteractive sudo apt update && sudo -E apt install -y "${packages[@]}" - - name: Restore ORAS cache from github actions if: inputs.download-test-fixture-cache == 'true' uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: ${{ github.workspace }}/.tmp/oras-cache key: ${{ inputs.cache-key-prefix }}-oras-cache - - name: Download test fixture cache if: inputs.download-test-fixture-cache == 'true' shell: bash diff --git a/cmd/syft/internal/commands/attest.go b/cmd/syft/internal/commands/attest.go index f538fa292..fcf56b016 100644 --- a/cmd/syft/internal/commands/attest.go +++ b/cmd/syft/internal/commands/attest.go @@ -59,7 +59,7 @@ func Attest(app clio.Application) *cobra.Command { Use: "attest --output [FORMAT] ", Short: "Generate an SBOM as an attestation for the given [SOURCE] container image", Long: "Generate a packaged-based Software Bill Of Materials (SBOM) from a container image as the predicate of an in-toto attestation that will be uploaded to the image registry", - Example: internal.Tprintf(attestHelp, map[string]interface{}{ + Example: internal.Tprintf(attestHelp, map[string]any{ "appName": id.Name, "command": "attest", }), diff --git a/cmd/syft/internal/commands/cataloger_info.go b/cmd/syft/internal/commands/cataloger_info.go index 87e01ba69..818d91d5d 100644 --- a/cmd/syft/internal/commands/cataloger_info.go +++ b/cmd/syft/internal/commands/cataloger_info.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" "os" + "slices" "sort" "strings" @@ -248,12 +249,7 @@ func renderCatalogerInfoJSON(doc *capabilities.Document, catalogers []capabiliti // isDeprecatedCataloger checks if a cataloger is deprecated based on its selectors func isDeprecatedCataloger(selectors []string) bool { - for _, selector := range selectors { - if selector == "deprecated" { - return true - } - } - return false + return slices.Contains(selectors, "deprecated") } // convertDetectorPackages converts detector package info to the JSON output format @@ -452,7 +448,7 @@ func extractArrayCapability(caps capabilities.CapabilitySet, name string) string if len(v) > 0 { return strings.Join(v, ", ") } - case []interface{}: + case []any: if len(v) > 0 { strs := make([]string, 0, len(v)) for _, item := range v { @@ -475,7 +471,7 @@ func extractNodesCapability(caps capabilities.CapabilitySet) string { switch v := cap.Default.(type) { case []string: return formatDepthStringArray(v) - case []interface{}: + case []any: return formatDepthInterfaceArray(v) } return noStyle.Render("·") @@ -496,7 +492,7 @@ func formatDepthStringArray(v []string) string { } // formatDepthInterfaceArray formats a []interface{} dependency depth value -func formatDepthInterfaceArray(v []interface{}) string { +func formatDepthInterfaceArray(v []any) string { if len(v) == 0 { return noStyle.Render("·") } diff --git a/cmd/syft/internal/commands/convert.go b/cmd/syft/internal/commands/convert.go index d10791969..0e411281e 100644 --- a/cmd/syft/internal/commands/convert.go +++ b/cmd/syft/internal/commands/convert.go @@ -40,7 +40,7 @@ func Convert(app clio.Application) *cobra.Command { Use: "convert [SOURCE-SBOM] -o [FORMAT]", Short: "Convert between SBOM formats", Long: "[Experimental] Convert SBOM files to, and from, SPDX, CycloneDX and Syft's format. For more info about data loss between formats see https://github.com/anchore/syft/wiki/format-conversion", - Example: internal.Tprintf(convertExample, map[string]interface{}{ + Example: internal.Tprintf(convertExample, map[string]any{ "appName": id.Name, "command": "convert", }), diff --git a/cmd/syft/internal/commands/packages.go b/cmd/syft/internal/commands/packages.go index 92f225d1d..203f76dc7 100644 --- a/cmd/syft/internal/commands/packages.go +++ b/cmd/syft/internal/commands/packages.go @@ -18,7 +18,7 @@ func Packages(app clio.Application, scanCmd *cobra.Command) *cobra.Command { Short: scanCmd.Short, Long: scanCmd.Long, Args: scanCmd.Args, - Example: internal.Tprintf(scanHelp, map[string]interface{}{ + Example: internal.Tprintf(scanHelp, map[string]any{ "appName": id.Name, "command": "packages", }), diff --git a/cmd/syft/internal/commands/packages_test.go b/cmd/syft/internal/commands/packages_test.go index 35d5241a2..af71570d1 100644 --- a/cmd/syft/internal/commands/packages_test.go +++ b/cmd/syft/internal/commands/packages_test.go @@ -29,7 +29,7 @@ func Test_filterExpressionErrors_expressionErrorsHelp(t *testing.T) { { name: "single non-expression error is retained", err: errors.New("foo"), - wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + wantErr: func(t assert.TestingT, err error, i ...any) bool { return assert.Equal(t, "foo", err.Error()) }, wantHelp: "", @@ -42,7 +42,7 @@ func Test_filterExpressionErrors_expressionErrorsHelp(t *testing.T) { err = multierror.Append(err, errors.New("bar")) return err }(), - wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + wantErr: func(t assert.TestingT, err error, i ...any) bool { // note: this is the default formatting from the hashicorp multierror object expected := `2 errors occurred: * foo @@ -64,7 +64,7 @@ func Test_filterExpressionErrors_expressionErrorsHelp(t *testing.T) { err = multierror.Append(err, errors.New("last")) return err }(), - wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + wantErr: func(t assert.TestingT, err error, i ...any) bool { expected := `5 errors occurred: * foo * invalid expression: "foo": tags are not allowed with this operation (must use exact names) @@ -103,7 +103,7 @@ func Test_filterExpressionErrors_expressionErrorsHelp(t *testing.T) { return fmt.Errorf("top: %w", fmt.Errorf("middle: %w", err)) }(), - wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + wantErr: func(t assert.TestingT, err error, i ...any) bool { expected := `top: middle: 4 errors occurred: * foo: bar: last * invalid expression: "foo": tags are not allowed with this operation (must use exact names) @@ -142,7 +142,7 @@ func Test_filterExpressionErrors_expressionErrorsHelp(t *testing.T) { // note we wrap the top error in a chain return fmt.Errorf("top: %w", fmt.Errorf("middle: %w", err)) }(), - wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + wantErr: func(t assert.TestingT, err error, i ...any) bool { expected := `top: middle: 4 errors occurred: * foo: bar: last * invalid expression: "foo": tags are not allowed with this operation (must use exact names) @@ -178,7 +178,7 @@ func Test_filterExpressionErrors_expressionErrorsHelp(t *testing.T) { return err }(), - wantErr: func(t assert.TestingT, err error, i ...interface{}) bool { + wantErr: func(t assert.TestingT, err error, i ...any) bool { // note: the errors are removed and the help text shows the enriched error help expected := `2 errors occurred: * invalid expression: "foo": tags are not allowed with this operation (must use exact names) diff --git a/cmd/syft/internal/commands/scan.go b/cmd/syft/internal/commands/scan.go index e669a46a8..d9147dace 100644 --- a/cmd/syft/internal/commands/scan.go +++ b/cmd/syft/internal/commands/scan.go @@ -92,7 +92,7 @@ func Scan(app clio.Application) *cobra.Command { Use: "scan [SOURCE]", Short: "Generate an SBOM", Long: "Generate a packaged-based Software Bill Of Materials (SBOM) from container images and filesystems", - Example: internal.Tprintf(scanHelp, map[string]interface{}{ + Example: internal.Tprintf(scanHelp, map[string]any{ "appName": id.Name, "command": "scan", }), diff --git a/cmd/syft/internal/commands/scan_test.go b/cmd/syft/internal/commands/scan_test.go index 73174d051..85575c18e 100644 --- a/cmd/syft/internal/commands/scan_test.go +++ b/cmd/syft/internal/commands/scan_test.go @@ -60,7 +60,7 @@ func Test_scanOptions_validateLegacyOptionsNotUsed(t *testing.T) { } func assertErrorContains(contains string) assert.ErrorAssertionFunc { - return func(t assert.TestingT, err error, i ...interface{}) bool { + return func(t assert.TestingT, err error, i ...any) bool { return assert.ErrorContains(t, err, contains, i...) } } diff --git a/cmd/syft/internal/options/catalog.go b/cmd/syft/internal/options/catalog.go index 0414e921f..bcb8ab66f 100644 --- a/cmd/syft/internal/options/catalog.go +++ b/cmd/syft/internal/options/catalog.go @@ -2,6 +2,7 @@ package options import ( "fmt" + "slices" "sort" "strings" @@ -313,10 +314,8 @@ func enrichmentEnabled(enrichDirectives []string, features ...string) *bool { directive = directive[1:] enable = false } - for _, feature := range features { - if directive == feature { - return &enable - } + if slices.Contains(features, directive) { + return &enable } } return nil diff --git a/cmd/syft/internal/options/writer_test.go b/cmd/syft/internal/options/writer_test.go index 036e49abe..44d2dc213 100644 --- a/cmd/syft/internal/options/writer_test.go +++ b/cmd/syft/internal/options/writer_test.go @@ -32,7 +32,7 @@ func Test_MakeSBOMWriter(t *testing.T) { { name: "unknown format", outputs: []string{"unknown"}, - wantErr: func(t assert.TestingT, err error, bla ...interface{}) bool { + wantErr: func(t assert.TestingT, err error, bla ...any) bool { return assert.ErrorContains(t, err, `unsupported output format "unknown", supported formats are:`) }, }, diff --git a/cmd/syft/internal/test/integration/catalog_packages_test.go b/cmd/syft/internal/test/integration/catalog_packages_test.go index 21948340e..53b0f4757 100644 --- a/cmd/syft/internal/test/integration/catalog_packages_test.go +++ b/cmd/syft/internal/test/integration/catalog_packages_test.go @@ -2,6 +2,7 @@ package integration import ( "context" + "slices" "strings" "testing" @@ -194,11 +195,8 @@ func assertPackages(t *testing.T, sbom sbom.SBOM, test testCase, observedLanguag } var foundLang bool - for _, lang := range strings.Split(test.pkgLanguage.String(), ",") { - if actualPkg.Language.String() == lang { - foundLang = true - break - } + if slices.Contains(strings.Split(test.pkgLanguage.String(), ","), actualPkg.Language.String()) { + foundLang = true } if !foundLang { t.Errorf("bad language (pkg=%+v): %+v", actualPkg.Name, actualPkg.Language) diff --git a/cmd/syft/internal/test/integration/package_cataloger_convention_test.go b/cmd/syft/internal/test/integration/package_cataloger_convention_test.go index 7b425c470..df0911364 100644 --- a/cmd/syft/internal/test/integration/package_cataloger_convention_test.go +++ b/cmd/syft/internal/test/integration/package_cataloger_convention_test.go @@ -329,7 +329,7 @@ func packageCatalogerExports(t *testing.T) map[string]exportTokenSet { } exportsPerPackage[pkg].Add(exportToken{ Name: decl.Name.Name, - Type: reflect.TypeOf(decl.Type).String(), + Type: reflect.TypeFor[*ast.FuncType]().String(), SignatureSize: len(decl.Type.Params.List), ReturnTypeNames: returnTypes, }) diff --git a/cmd/syft/internal/ui/log_writer_test.go b/cmd/syft/internal/ui/log_writer_test.go index 3ed48f8b5..2e0fd6bce 100644 --- a/cmd/syft/internal/ui/log_writer_test.go +++ b/cmd/syft/internal/ui/log_writer_test.go @@ -36,33 +36,33 @@ func Test_logWriter(t *testing.T) { type bufferLogger struct{ values []any } -func (l *bufferLogger) Tracef(_ string, _ ...interface{}) {} +func (l *bufferLogger) Tracef(_ string, _ ...any) {} -func (l *bufferLogger) Debugf(_ string, _ ...interface{}) {} +func (l *bufferLogger) Debugf(_ string, _ ...any) {} -func (l *bufferLogger) Infof(_ string, _ ...interface{}) {} +func (l *bufferLogger) Infof(_ string, _ ...any) {} -func (l *bufferLogger) Warnf(_ string, _ ...interface{}) {} +func (l *bufferLogger) Warnf(_ string, _ ...any) {} -func (l *bufferLogger) Errorf(_ string, _ ...interface{}) {} +func (l *bufferLogger) Errorf(_ string, _ ...any) {} -func (l *bufferLogger) Trace(vals ...interface{}) { +func (l *bufferLogger) Trace(vals ...any) { l.values = append(l.values, vals...) } -func (l *bufferLogger) Debug(_ ...interface{}) {} +func (l *bufferLogger) Debug(_ ...any) {} -func (l *bufferLogger) Info(_ ...interface{}) {} +func (l *bufferLogger) Info(_ ...any) {} -func (l *bufferLogger) Warn(vals ...interface{}) { +func (l *bufferLogger) Warn(vals ...any) { l.values = append(l.values, vals...) } -func (l *bufferLogger) Error(_ ...interface{}) {} +func (l *bufferLogger) Error(_ ...any) {} -func (l *bufferLogger) WithFields(_ ...interface{}) logger.MessageLogger { return l } +func (l *bufferLogger) WithFields(_ ...any) logger.MessageLogger { return l } -func (l *bufferLogger) Nested(_ ...interface{}) logger.Logger { return l } +func (l *bufferLogger) Nested(_ ...any) logger.Logger { return l } func (l *bufferLogger) SetOutput(_ io.Writer) {} diff --git a/go.mod b/go.mod index 3399b643d..806b0ead7 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/anchore/syft -go 1.25.8 +go 1.26.2 require ( github.com/BurntSushi/toml v1.6.0 diff --git a/internal/capabilities/evaluation.go b/internal/capabilities/evaluation.go index 0dfdc48d7..b71ab97f8 100644 --- a/internal/capabilities/evaluation.go +++ b/internal/capabilities/evaluation.go @@ -5,8 +5,8 @@ import "reflect" // EvaluateCapabilities evaluates a capability set against a given configuration // and returns the effective capability values as a flat map. // Example: {"license": false, "dependency.depth": ["direct", "indirect"]} -func EvaluateCapabilities(caps CapabilitySet, config map[string]interface{}) map[string]interface{} { - result := make(map[string]interface{}) +func EvaluateCapabilities(caps CapabilitySet, config map[string]any) map[string]any { + result := make(map[string]any) for _, capField := range caps { result[capField.Name] = EvaluateField(capField, config) } @@ -16,7 +16,7 @@ func EvaluateCapabilities(caps CapabilitySet, config map[string]interface{}) map // EvaluateField evaluates a single capability field against a configuration. // Conditions are evaluated in order, and the first matching condition's value is returned. // If no conditions match, the default value is returned. -func EvaluateField(capField CapabilityField, config map[string]interface{}) interface{} { +func EvaluateField(capField CapabilityField, config map[string]any) any { // check conditions in order (first match wins) for _, cond := range capField.Conditions { if ConditionMatches(cond.When, config) { @@ -30,7 +30,7 @@ func EvaluateField(capField CapabilityField, config map[string]interface{}) inte // ConditionMatches checks if a condition's when clause matches the given configuration. // All fields in the when clause must match the config (AND logic). // Returns true if all key-value pairs in when match the config. -func ConditionMatches(when map[string]interface{}, config map[string]interface{}) bool { +func ConditionMatches(when map[string]any, config map[string]any) bool { // all fields in when must match config (AND logic) for key, expectedValue := range when { actualValue, exists := config[key] @@ -46,7 +46,7 @@ func ConditionMatches(when map[string]interface{}, config map[string]interface{} // valuesEqual compares two values for equality, handling different types appropriately. // Uses reflect.DeepEqual for complex types like slices and maps. -func valuesEqual(a, b interface{}) bool { +func valuesEqual(a, b any) bool { // handle nil cases if a == nil && b == nil { return true diff --git a/internal/capabilities/evaluation_test.go b/internal/capabilities/evaluation_test.go index afcf72a67..3e476de9e 100644 --- a/internal/capabilities/evaluation_test.go +++ b/internal/capabilities/evaluation_test.go @@ -10,8 +10,8 @@ import ( func Test_valuesEqual(t *testing.T) { tests := []struct { name string - a interface{} - b interface{} + a any + b any want bool }{ { @@ -123,47 +123,47 @@ func Test_valuesEqual(t *testing.T) { func TestConditionMatches(t *testing.T) { tests := []struct { name string - when map[string]interface{} - config map[string]interface{} + when map[string]any + config map[string]any want bool }{ { name: "empty when clause matches anything", - when: map[string]interface{}{}, - config: map[string]interface{}{"key": "value"}, + when: map[string]any{}, + config: map[string]any{"key": "value"}, want: true, }, { name: "empty when clause with empty config", - when: map[string]interface{}{}, - config: map[string]interface{}{}, + when: map[string]any{}, + config: map[string]any{}, want: true, }, { name: "single key match", - when: map[string]interface{}{"SearchLocalModCacheLicenses": true}, - config: map[string]interface{}{"SearchLocalModCacheLicenses": true}, + when: map[string]any{"SearchLocalModCacheLicenses": true}, + config: map[string]any{"SearchLocalModCacheLicenses": true}, want: true, }, { name: "single key mismatch", - when: map[string]interface{}{"SearchLocalModCacheLicenses": true}, - config: map[string]interface{}{"SearchLocalModCacheLicenses": false}, + when: map[string]any{"SearchLocalModCacheLicenses": true}, + config: map[string]any{"SearchLocalModCacheLicenses": false}, want: false, }, { name: "key missing from config", - when: map[string]interface{}{"SearchLocalModCacheLicenses": true}, - config: map[string]interface{}{}, + when: map[string]any{"SearchLocalModCacheLicenses": true}, + config: map[string]any{}, want: false, }, { name: "multiple keys all match", - when: map[string]interface{}{ + when: map[string]any{ "SearchLocalModCacheLicenses": true, "UseNetwork": true, }, - config: map[string]interface{}{ + config: map[string]any{ "SearchLocalModCacheLicenses": true, "UseNetwork": true, "ExtraKey": "ignored", @@ -172,11 +172,11 @@ func TestConditionMatches(t *testing.T) { }, { name: "multiple keys one mismatch", - when: map[string]interface{}{ + when: map[string]any{ "SearchLocalModCacheLicenses": true, "UseNetwork": true, }, - config: map[string]interface{}{ + config: map[string]any{ "SearchLocalModCacheLicenses": true, "UseNetwork": false, }, @@ -184,31 +184,31 @@ func TestConditionMatches(t *testing.T) { }, { name: "multiple keys one missing", - when: map[string]interface{}{ + when: map[string]any{ "SearchLocalModCacheLicenses": true, "UseNetwork": true, }, - config: map[string]interface{}{ + config: map[string]any{ "SearchLocalModCacheLicenses": true, }, want: false, }, { name: "string value match", - when: map[string]interface{}{"mode": "fast"}, - config: map[string]interface{}{"mode": "fast"}, + when: map[string]any{"mode": "fast"}, + config: map[string]any{"mode": "fast"}, want: true, }, { name: "slice value match", - when: map[string]interface{}{"formats": []string{"json", "yaml"}}, - config: map[string]interface{}{"formats": []string{"json", "yaml"}}, + when: map[string]any{"formats": []string{"json", "yaml"}}, + config: map[string]any{"formats": []string{"json", "yaml"}}, want: true, }, { name: "slice value mismatch", - when: map[string]interface{}{"formats": []string{"json", "yaml"}}, - config: map[string]interface{}{"formats": []string{"json", "xml"}}, + when: map[string]any{"formats": []string{"json", "yaml"}}, + config: map[string]any{"formats": []string{"json", "xml"}}, want: false, }, } @@ -225,8 +225,8 @@ func TestEvaluateField(t *testing.T) { tests := []struct { name string capField CapabilityField - config map[string]interface{} - want interface{} + config map[string]any + want any }{ { name: "no conditions returns default", @@ -235,7 +235,7 @@ func TestEvaluateField(t *testing.T) { Default: false, Conditions: nil, }, - config: map[string]interface{}{}, + config: map[string]any{}, want: false, }, { @@ -245,7 +245,7 @@ func TestEvaluateField(t *testing.T) { Default: false, Conditions: []CapabilityCondition{}, }, - config: map[string]interface{}{}, + config: map[string]any{}, want: false, }, { @@ -260,7 +260,7 @@ func TestEvaluateField(t *testing.T) { }, }, }, - config: map[string]interface{}{"SearchLocalModCacheLicenses": true}, + config: map[string]any{"SearchLocalModCacheLicenses": true}, want: true, }, { @@ -275,7 +275,7 @@ func TestEvaluateField(t *testing.T) { }, }, }, - config: map[string]interface{}{"SearchLocalModCacheLicenses": false}, + config: map[string]any{"SearchLocalModCacheLicenses": false}, want: false, }, { @@ -294,7 +294,7 @@ func TestEvaluateField(t *testing.T) { }, }, }, - config: map[string]interface{}{ + config: map[string]any{ "SearchLocalModCacheLicenses": true, "SearchRemoteLicenses": true, }, @@ -316,7 +316,7 @@ func TestEvaluateField(t *testing.T) { }, }, }, - config: map[string]interface{}{ + config: map[string]any{ "SearchLocalModCacheLicenses": false, "SearchRemoteLicenses": true, }, @@ -338,7 +338,7 @@ func TestEvaluateField(t *testing.T) { }, }, }, - config: map[string]interface{}{ + config: map[string]any{ "SearchLocalModCacheLicenses": false, "SearchRemoteLicenses": false, }, @@ -351,7 +351,7 @@ func TestEvaluateField(t *testing.T) { Default: []string{"direct", "indirect"}, Conditions: nil, }, - config: map[string]interface{}{}, + config: map[string]any{}, want: []string{"direct", "indirect"}, }, { @@ -369,7 +369,7 @@ func TestEvaluateField(t *testing.T) { }, }, }, - config: map[string]interface{}{ + config: map[string]any{ "EnableFeatureA": true, "EnableFeatureB": true, }, @@ -390,7 +390,7 @@ func TestEvaluateField(t *testing.T) { }, }, }, - config: map[string]interface{}{ + config: map[string]any{ "EnableFeatureA": true, "EnableFeatureB": false, }, @@ -412,14 +412,14 @@ func TestEvaluateCapabilities(t *testing.T) { tests := []struct { name string caps CapabilitySet - config map[string]interface{} - want map[string]interface{} + config map[string]any + want map[string]any }{ { name: "empty capability set", caps: CapabilitySet{}, - config: map[string]interface{}{}, - want: map[string]interface{}{}, + config: map[string]any{}, + want: map[string]any{}, }, { name: "single capability no conditions", @@ -429,8 +429,8 @@ func TestEvaluateCapabilities(t *testing.T) { Default: false, }, }, - config: map[string]interface{}{}, - want: map[string]interface{}{ + config: map[string]any{}, + want: map[string]any{ "license": false, }, }, @@ -448,8 +448,8 @@ func TestEvaluateCapabilities(t *testing.T) { }, }, }, - config: map[string]interface{}{"SearchLocalModCacheLicenses": true}, - want: map[string]interface{}{ + config: map[string]any{"SearchLocalModCacheLicenses": true}, + want: map[string]any{ "license": true, }, }, @@ -475,8 +475,8 @@ func TestEvaluateCapabilities(t *testing.T) { Default: "flat", }, }, - config: map[string]interface{}{"SearchLocalModCacheLicenses": true}, - want: map[string]interface{}{ + config: map[string]any{"SearchLocalModCacheLicenses": true}, + want: map[string]any{ "license": true, "dependency.depth": []string{"direct", "indirect"}, "dependency.edges": "flat", @@ -512,11 +512,11 @@ func TestEvaluateCapabilities(t *testing.T) { Default: false, }, }, - config: map[string]interface{}{ + config: map[string]any{ "SearchLocalModCacheLicenses": false, "SearchRemoteLicenses": true, }, - want: map[string]interface{}{ + want: map[string]any{ "license": true, "dependency.depth": []string{"direct", "indirect"}, "dependency.edges": "flat", @@ -526,10 +526,10 @@ func TestEvaluateCapabilities(t *testing.T) { { name: "nil capability set", caps: nil, - config: map[string]interface{}{ + config: map[string]any{ "anything": true, }, - want: map[string]interface{}{}, + want: map[string]any{}, }, } diff --git a/internal/capabilities/generate/discover_app_config.go b/internal/capabilities/generate/discover_app_config.go index 0604d4c6d..2d2c40ed8 100644 --- a/internal/capabilities/generate/discover_app_config.go +++ b/internal/capabilities/generate/discover_app_config.go @@ -15,9 +15,9 @@ import ( // AppConfigField represents an application-level configuration field for catalogers type AppConfigField struct { - Key string // e.g., "golang.search-local-mod-cache-licenses" - Description string // extracted from DescribeFields() method - DefaultValue interface{} // extracted from Default*() functions + Key string // e.g., "golang.search-local-mod-cache-licenses" + Description string // extracted from DescribeFields() method + DefaultValue any // extracted from Default*() functions } // extractEcosystemConfigFieldsFromCatalog parses catalog.go and extracts the ecosystem-specific @@ -390,7 +390,7 @@ func extractDescriptionsFromDescribeFields(f *ast.File) map[string]string { } // extractNestedAppConfigs handles nested config structs like golang.MainModuleVersion -func extractNestedAppConfigs(f *ast.File, parentKey, parentFieldName string, fieldType ast.Expr, descriptions map[string]string, defaults map[string]interface{}) []AppConfigField { +func extractNestedAppConfigs(f *ast.File, parentKey, parentFieldName string, fieldType ast.Expr, descriptions map[string]string, defaults map[string]any) []AppConfigField { var configs []AppConfigField // find the nested struct type @@ -449,8 +449,8 @@ func extractNestedAppConfigs(f *ast.File, parentKey, parentFieldName string, fie description := descriptions[nestedPath] // try to get default value from nested defaults - var defaultValue interface{} - if nestedDefaults, ok := defaults[parentFieldName].(map[string]interface{}); ok { + var defaultValue any + if nestedDefaults, ok := defaults[parentFieldName].(map[string]any); ok { defaultValue = nestedDefaults[fieldName] } @@ -465,8 +465,8 @@ func extractNestedAppConfigs(f *ast.File, parentKey, parentFieldName string, fie } // extractAppDefaultValues extracts default values from the default*Config function -func extractAppDefaultValues(f *ast.File) map[string]interface{} { - defaults := make(map[string]interface{}) +func extractAppDefaultValues(f *ast.File) map[string]any { + defaults := make(map[string]any) for _, decl := range f.Decls { funcDecl, ok := decl.(*ast.FuncDecl) @@ -518,7 +518,7 @@ func extractAppDefaultValues(f *ast.File) map[string]interface{} { } // extractAppValue extracts a Go value from an AST expression -func extractAppValue(expr ast.Expr) interface{} { +func extractAppValue(expr ast.Expr) any { switch v := expr.(type) { case *ast.BasicLit: // string, int, bool literals @@ -543,7 +543,7 @@ func extractAppValue(expr ast.Expr) interface{} { } case *ast.CompositeLit: // nested struct literal - nested := make(map[string]interface{}) + nested := make(map[string]any) for _, elt := range v.Elts { kvExpr, ok := elt.(*ast.KeyValueExpr) if !ok { diff --git a/internal/capabilities/generate/discover_app_config_test.go b/internal/capabilities/generate/discover_app_config_test.go index 2c8bc3704..a64fa65cd 100644 --- a/internal/capabilities/generate/discover_app_config_test.go +++ b/internal/capabilities/generate/discover_app_config_test.go @@ -340,7 +340,7 @@ func TestExtractAppValue(t *testing.T) { tests := []struct { name string src string - want interface{} + want any }{ { name: "string literal", @@ -406,7 +406,7 @@ func TestExtractAppValue_NestedStruct(t *testing.T) { got := extractAppValue(compositeLit) // verify it's a map with the expected values - gotMap, ok := got.(map[string]interface{}) + gotMap, ok := got.(map[string]any) require.True(t, ok) require.Equal(t, "value", gotMap["Field1"]) require.Equal(t, true, gotMap["Field2"]) diff --git a/internal/capabilities/generate/discover_catalogers.go b/internal/capabilities/generate/discover_catalogers.go index b6f020c84..3dc5419c7 100644 --- a/internal/capabilities/generate/discover_catalogers.go +++ b/internal/capabilities/generate/discover_catalogers.go @@ -567,8 +567,8 @@ func resolveImportedConstant(pkgName, constName string, ctx *parseContext) strin // resolveImportPath converts an import path to a file system path func resolveImportPath(importPath, repoRoot string) string { // for github.com/anchore/syft/... imports, convert to repo-relative path - if strings.HasPrefix(importPath, "github.com/anchore/syft/") { - relPath := strings.TrimPrefix(importPath, "github.com/anchore/syft/") + if after, ok := strings.CutPrefix(importPath, "github.com/anchore/syft/"); ok { + relPath := after return filepath.Join(repoRoot, relPath) } diff --git a/internal/capabilities/generate/io.go b/internal/capabilities/generate/io.go index f9a3f2e70..762948618 100644 --- a/internal/capabilities/generate/io.go +++ b/internal/capabilities/generate/io.go @@ -214,7 +214,7 @@ func mapCatalogerToEcosystem(cat capabilities.CatalogerEntry) string { } // updateNodeTreeEcosystem updates an existing ecosystem YAML node tree -func updateNodeTreeEcosystem(rootNode *yaml.Node, doc interface{}) error { +func updateNodeTreeEcosystem(rootNode *yaml.Node, doc any) error { var newNode yaml.Node if err := newNode.Encode(doc); err != nil { return err @@ -242,7 +242,7 @@ func updateNodeTreeEcosystem(rootNode *yaml.Node, doc interface{}) error { } // updateNodeTreeAppConfig updates appconfig YAML node tree -func updateNodeTreeAppConfig(rootNode *yaml.Node, doc interface{}) error { +func updateNodeTreeAppConfig(rootNode *yaml.Node, doc any) error { return updateNodeTreeEcosystem(rootNode, doc) } diff --git a/internal/capabilities/internal/load_capabilities_test.go b/internal/capabilities/internal/load_capabilities_test.go index 80bfbae97..ee5293726 100644 --- a/internal/capabilities/internal/load_capabilities_test.go +++ b/internal/capabilities/internal/load_capabilities_test.go @@ -30,7 +30,7 @@ const requireParserObservations = false // metadataTypeCoverageExceptions lists metadata types that are allowed to not be represented in any cataloger var metadataTypeCoverageExceptions = strset.New( - reflect.TypeOf(pkg.MicrosoftKbPatch{}).Name(), + reflect.TypeFor[pkg.MicrosoftKbPatch]().Name(), ) // packageTypeCoverageExceptions lists package types that are allowed to not be represented in any cataloger @@ -408,7 +408,7 @@ func TestCapabilityValueTypes(t *testing.T) { } // validateCapabilityValueType checks if a value matches the expected type for a capability field -func validateCapabilityValueType(fieldPath string, value interface{}) error { +func validateCapabilityValueType(fieldPath string, value any) error { if value == nil { return nil // nil is acceptable } @@ -428,7 +428,7 @@ func validateCapabilityValueType(fieldPath string, value interface{}) error { switch v := value.(type) { case []string: // ok - case []interface{}: + case []any: // check each element is a string for i, elem := range v { if _, ok := elem.(string); !ok { @@ -829,7 +829,6 @@ func TestCapabilityEvidenceFieldReferences(t *testing.T) { // validate each evidence reference for _, ref := range allReferences { - ref := ref // capture for subtest // create test name testName := ref.catalogerName @@ -989,7 +988,6 @@ func validateCapabilitiesFilled(t *testing.T, catalogers []capabilities.Cataloge checkCompletenessTestsEnabled(t) for _, c := range catalogers { - c := c // capture loop variable for subtest t.Run(c.Name, func(t *testing.T) { if c.Type == "generic" { @@ -997,7 +995,6 @@ func validateCapabilitiesFilled(t *testing.T, catalogers []capabilities.Cataloge require.NotEmpty(t, c.Parsers, "generic cataloger must have at least one parser") for _, p := range c.Parsers { - p := p // capture loop variable for subtest t.Run(p.ParserFunction, func(t *testing.T) { require.NotEmpty(t, p.Capabilities, "parser must have at least one capability field defined") @@ -1120,7 +1117,6 @@ func TestCatalogerStructure(t *testing.T) { require.NoError(t, err) for _, c := range catalogerEntries { - c := c // capture loop variable for subtest t.Run(c.Name, func(t *testing.T) { // ecosystem must always be set (it's MANUAL) diff --git a/internal/file/getter_test.go b/internal/file/getter_test.go index a8f47ce81..7d2eb171e 100644 --- a/internal/file/getter_test.go +++ b/internal/file/getter_test.go @@ -151,11 +151,11 @@ func TestGetter_GetToDir_CertConcerns(t *testing.T) { } } -func assertUnknownAuthorityError(t assert.TestingT, err error, _ ...interface{}) bool { +func assertUnknownAuthorityError(t assert.TestingT, err error, _ ...any) bool { return assert.ErrorAs(t, err, &x509.UnknownAuthorityError{}) } -func assertErrNonArchiveSource(t assert.TestingT, err error, _ ...interface{}) bool { +func assertErrNonArchiveSource(t assert.TestingT, err error, _ ...any) bool { return assert.ErrorIs(t, err, ErrNonArchiveSource) } diff --git a/internal/file/zip_file_manifest_test.go b/internal/file/zip_file_manifest_test.go index e169e475e..50b798882 100644 --- a/internal/file/zip_file_manifest_test.go +++ b/internal/file/zip_file_manifest_test.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package file diff --git a/internal/file/zip_file_traversal_test.go b/internal/file/zip_file_traversal_test.go index bed493739..4fe960b66 100644 --- a/internal/file/zip_file_traversal_test.go +++ b/internal/file/zip_file_traversal_test.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package file @@ -242,8 +241,8 @@ func assertZipSourceFixtureContents(t testing.TB, actual map[string]string, expe } // looks like there isn't a helper for this yet? https://github.com/stretchr/testify/issues/497 -func assertErrorAs(expectedErr interface{}) assert.ErrorAssertionFunc { - return func(t assert.TestingT, actualErr error, i ...interface{}) bool { +func assertErrorAs(expectedErr any) assert.ErrorAssertionFunc { + return func(t assert.TestingT, actualErr error, i ...any) bool { return errors.As(actualErr, &expectedErr) } } diff --git a/internal/jsonschema/main.go b/internal/jsonschema/main.go index 55b718597..fcb7843fc 100644 --- a/internal/jsonschema/main.go +++ b/internal/jsonschema/main.go @@ -143,7 +143,7 @@ func build() *jsonschema.Schema { // srcMetadataContainer := assembleTypeContainer(sourcemetadata.AllTypes()) // srcMetadataContainerType := reflect.TypeOf(srcMetadataContainer) - documentSchema := reflector.ReflectFromType(reflect.TypeOf(&syftJsonModel.Document{})) + documentSchema := reflector.ReflectFromType(reflect.TypeFor[*syftJsonModel.Document]()) pkgMetadataSchema := reflector.ReflectFromType(reflect.TypeOf(pkgMetadataContainer)) // srcMetadataSchema := reflector.ReflectFromType(reflect.TypeOf(srcMetadataContainer)) diff --git a/internal/log/log.go b/internal/log/log.go index 5c557ee0d..a26a6f0e0 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -30,61 +30,61 @@ func Get() logger.Logger { } // Errorf takes a formatted template string and template arguments for the error logging level. -func Errorf(format string, args ...interface{}) { +func Errorf(format string, args ...any) { log.Errorf(format, args...) } // Error logs the given arguments at the error logging level. -func Error(args ...interface{}) { +func Error(args ...any) { log.Error(args...) } // Warnf takes a formatted template string and template arguments for the warning logging level. -func Warnf(format string, args ...interface{}) { +func Warnf(format string, args ...any) { log.Warnf(format, args...) } // Warn logs the given arguments at the warning logging level. -func Warn(args ...interface{}) { +func Warn(args ...any) { log.Warn(args...) } // Infof takes a formatted template string and template arguments for the info logging level. -func Infof(format string, args ...interface{}) { +func Infof(format string, args ...any) { log.Infof(format, args...) } // Info logs the given arguments at the info logging level. -func Info(args ...interface{}) { +func Info(args ...any) { log.Info(args...) } // Debugf takes a formatted template string and template arguments for the debug logging level. -func Debugf(format string, args ...interface{}) { +func Debugf(format string, args ...any) { log.Debugf(format, args...) } // Debug logs the given arguments at the debug logging level. -func Debug(args ...interface{}) { +func Debug(args ...any) { log.Debug(args...) } // Tracef takes a formatted template string and template arguments for the trace logging level. -func Tracef(format string, args ...interface{}) { +func Tracef(format string, args ...any) { log.Tracef(format, args...) } // Trace logs the given arguments at the trace logging level. -func Trace(args ...interface{}) { +func Trace(args ...any) { log.Trace(args...) } // WithFields returns a message logger with multiple key-value fields. -func WithFields(fields ...interface{}) logger.MessageLogger { +func WithFields(fields ...any) logger.MessageLogger { return log.WithFields(fields...) } // Nested returns a new logger with hard coded key-value pairs -func Nested(fields ...interface{}) logger.Logger { +func Nested(fields ...any) logger.Logger { return log.Nested(fields...) } diff --git a/internal/packagemetadata/names_test.go b/internal/packagemetadata/names_test.go index 74d436026..553d8237d 100644 --- a/internal/packagemetadata/names_test.go +++ b/internal/packagemetadata/names_test.go @@ -40,28 +40,28 @@ func TestReflectTypeFromJSONName(t *testing.T) { { name: "exact match on ID", lookup: "rust-cargo-lock-entry", - wantRecord: reflect.TypeOf(pkg.RustCargoLockEntry{}), + wantRecord: reflect.TypeFor[pkg.RustCargoLockEntry](), }, { name: "exact match on former name", lookup: "RustCargoPackageMetadata", - wantRecord: reflect.TypeOf(pkg.RustCargoLockEntry{}), + wantRecord: reflect.TypeFor[pkg.RustCargoLockEntry](), }, { name: "case insensitive on ID", lookup: "RUST-CARGO-lock-entrY", - wantRecord: reflect.TypeOf(pkg.RustCargoLockEntry{}), + wantRecord: reflect.TypeFor[pkg.RustCargoLockEntry](), }, { name: "case insensitive on alias", lookup: "rusTcArgopacKagEmEtadATa", - wantRecord: reflect.TypeOf(pkg.RustCargoLockEntry{}), + wantRecord: reflect.TypeFor[pkg.RustCargoLockEntry](), }, { name: "consistent override", // there are two correct answers for this -- we should always get the same answer. lookup: "HackageMetadataType", - wantRecord: reflect.TypeOf(pkg.HackageStackYamlLockEntry{}), + wantRecord: reflect.TypeFor[pkg.HackageStackYamlLockEntry](), }, } for _, tt := range tests { @@ -83,142 +83,142 @@ func TestReflectTypeFromJSONName_LegacyValues(t *testing.T) { { name: "map pkg.AlpmDBEntry struct type", input: "AlpmMetadata", - expected: reflect.TypeOf(pkg.AlpmDBEntry{}), + expected: reflect.TypeFor[pkg.AlpmDBEntry](), }, { name: "map pkg.ApkDBEntry struct type", input: "ApkMetadata", - expected: reflect.TypeOf(pkg.ApkDBEntry{}), + expected: reflect.TypeFor[pkg.ApkDBEntry](), }, { name: "map pkg.BinarySignature struct type", input: "BinaryMetadata", - expected: reflect.TypeOf(pkg.BinarySignature{}), + expected: reflect.TypeFor[pkg.BinarySignature](), }, { name: "map pkg.CocoaPodfileLockEntry struct type", input: "CocoapodsMetadataType", - expected: reflect.TypeOf(pkg.CocoaPodfileLockEntry{}), + expected: reflect.TypeFor[pkg.CocoaPodfileLockEntry](), }, { name: "map pkg.ConanLockEntry struct type", input: "ConanLockMetadataType", - expected: reflect.TypeOf(pkg.ConanV1LockEntry{}), + expected: reflect.TypeFor[pkg.ConanV1LockEntry](), }, { name: "map pkg.ConanfileEntry struct type", input: "ConanMetadataType", - expected: reflect.TypeOf(pkg.ConanfileEntry{}), + expected: reflect.TypeFor[pkg.ConanfileEntry](), }, { name: "map pkg.DartPubspecLockEntry struct type", input: "DartPubMetadata", - expected: reflect.TypeOf(pkg.DartPubspecLockEntry{}), + expected: reflect.TypeFor[pkg.DartPubspecLockEntry](), }, { name: "map pkg.DotnetDepsEntry struct type", input: "DotnetDepsMetadata", - expected: reflect.TypeOf(pkg.DotnetDepsEntry{}), + expected: reflect.TypeFor[pkg.DotnetDepsEntry](), }, { name: "map pkg.DpkgDBEntry struct type", input: "DpkgMetadata", - expected: reflect.TypeOf(pkg.DpkgDBEntry{}), + expected: reflect.TypeFor[pkg.DpkgDBEntry](), }, { name: "map pkg.RubyGemspec struct type", input: "GemMetadata", - expected: reflect.TypeOf(pkg.RubyGemspec{}), + expected: reflect.TypeFor[pkg.RubyGemspec](), }, { name: "map pkg.GolangBinaryBuildinfoEntry struct type", input: "GolangBinMetadata", - expected: reflect.TypeOf(pkg.GolangBinaryBuildinfoEntry{}), + expected: reflect.TypeFor[pkg.GolangBinaryBuildinfoEntry](), }, { name: "map pkg.GolangModuleEntry struct type", input: "GolangModMetadata", - expected: reflect.TypeOf(pkg.GolangModuleEntry{}), + expected: reflect.TypeFor[pkg.GolangModuleEntry](), }, { name: "map pkg.JavaArchive struct type", input: "JavaMetadata", - expected: reflect.TypeOf(pkg.JavaArchive{}), + expected: reflect.TypeFor[pkg.JavaArchive](), }, { name: "map pkg.MicrosoftKbPatch struct type", input: "KbPatchMetadata", - expected: reflect.TypeOf(pkg.MicrosoftKbPatch{}), + expected: reflect.TypeFor[pkg.MicrosoftKbPatch](), }, { name: "map pkg.LinuxKernel struct type", input: "LinuxKernel", - expected: reflect.TypeOf(pkg.LinuxKernel{}), + expected: reflect.TypeFor[pkg.LinuxKernel](), }, { name: "map pkg.LinuxKernelModule struct type", input: "LinuxKernelModule", - expected: reflect.TypeOf(pkg.LinuxKernelModule{}), + expected: reflect.TypeFor[pkg.LinuxKernelModule](), }, { name: "map pkg.ElixirMixLockEntry struct type", input: "MixLockMetadataType", - expected: reflect.TypeOf(pkg.ElixirMixLockEntry{}), + expected: reflect.TypeFor[pkg.ElixirMixLockEntry](), }, { name: "map pkg.NixStoreEntry struct type", input: "NixStoreMetadata", - expected: reflect.TypeOf(pkg.NixStoreEntry{}), + expected: reflect.TypeFor[pkg.NixStoreEntry](), }, { name: "map pkg.NpmPackage struct type", input: "NpmPackageJsonMetadata", - expected: reflect.TypeOf(pkg.NpmPackage{}), + expected: reflect.TypeFor[pkg.NpmPackage](), }, { name: "map pkg.NpmPackageLockEntry struct type", input: "NpmPackageLockJsonMetadata", - expected: reflect.TypeOf(pkg.NpmPackageLockEntry{}), + expected: reflect.TypeFor[pkg.NpmPackageLockEntry](), }, { name: "map pkg.PortageEntry struct type", input: "PortageMetadata", - expected: reflect.TypeOf(pkg.PortageEntry{}), + expected: reflect.TypeFor[pkg.PortageEntry](), }, { name: "map pkg.PythonPackage struct type", input: "PythonPackageMetadata", - expected: reflect.TypeOf(pkg.PythonPackage{}), + expected: reflect.TypeFor[pkg.PythonPackage](), }, { name: "map pkg.PythonPipfileLockEntry struct type", input: "PythonPipfileLockMetadata", - expected: reflect.TypeOf(pkg.PythonPipfileLockEntry{}), + expected: reflect.TypeFor[pkg.PythonPipfileLockEntry](), }, { name: "map pkg.PythonRequirementsEntry struct type", input: "PythonRequirementsMetadata", - expected: reflect.TypeOf(pkg.PythonRequirementsEntry{}), + expected: reflect.TypeFor[pkg.PythonRequirementsEntry](), }, { name: "map pkg.PhpPeclEntry struct type", input: "PhpPeclMetadata", - expected: reflect.TypeOf(pkg.PhpPeclEntry{}), + expected: reflect.TypeFor[pkg.PhpPeclEntry](), }, { name: "map pkg.ErlangRebarLockEntry struct type", input: "RebarLockMetadataType", - expected: reflect.TypeOf(pkg.ErlangRebarLockEntry{}), + expected: reflect.TypeFor[pkg.ErlangRebarLockEntry](), }, { name: "map pkg.RDescription struct type", input: "RDescriptionFileMetadataType", - expected: reflect.TypeOf(pkg.RDescription{}), + expected: reflect.TypeFor[pkg.RDescription](), }, { name: "map pkg.RpmDBEntry struct type", input: "RpmdbMetadata", - expected: reflect.TypeOf(pkg.RpmDBEntry{}), + expected: reflect.TypeFor[pkg.RpmDBEntry](), }, // these cases are 1:many { @@ -228,28 +228,28 @@ func TestReflectTypeFromJSONName_LegacyValues(t *testing.T) { // from a data-shape perspective either would be equally correct // however, the RPMDBMetadata has been around longer and may have been more widely used // so we'll map to that type for backwards compatibility. - expected: reflect.TypeOf(pkg.RpmDBEntry{}), + expected: reflect.TypeFor[pkg.RpmDBEntry](), }, { name: "map pkg.HackageStackYamlLockEntry struct type - overlap with HackageStack*Metadata", input: "HackageMetadataType", // this used to be shared as a use case for both HackageStackYamlLockEntry and HackageStackYamlEntry // but the HackageStackYamlLockEntry maps most closely to the original data shape. - expected: reflect.TypeOf(pkg.HackageStackYamlLockEntry{}), + expected: reflect.TypeFor[pkg.HackageStackYamlLockEntry](), }, { name: "map pkg.PhpComposerLockEntry struct type", input: "PhpComposerJsonMetadata", // this used to be shared as a use case for both PhpComposerLockEntry and PhpComposerInstalledEntry // neither of these is more correct over the other. These parsers were also introduced at the same time. - expected: reflect.TypeOf(pkg.PhpComposerLockEntry{}), + expected: reflect.TypeFor[pkg.PhpComposerLockEntry](), }, { name: "map pkg.RustCargoLockEntry struct type", input: "RustCargoPackageMetadata", // this used to be shared as a use case for both RustCargoLockEntry and RustBinaryAuditEntry // neither of these is more correct over the other. - expected: reflect.TypeOf(pkg.RustCargoLockEntry{}), + expected: reflect.TypeFor[pkg.RustCargoLockEntry](), }, } diff --git a/internal/regex_helpers.go b/internal/regex_helpers.go index dce1d3496..45b4a1cd5 100644 --- a/internal/regex_helpers.go +++ b/internal/regex_helpers.go @@ -92,10 +92,7 @@ func processReaderInChunks(rdr io.Reader, chunkSize int, handler func(data []byt lastRead := 0 for { - offset := half - if lastRead < half { - offset = lastRead - } + offset := min(lastRead, half) start := half - offset if lastRead > 0 { copy(buf[start:], buf[half+offset:half+lastRead]) diff --git a/internal/relationship/exclude_binaries_by_file_ownership_overlap.go b/internal/relationship/exclude_binaries_by_file_ownership_overlap.go index 646ffec22..ee7c977c6 100644 --- a/internal/relationship/exclude_binaries_by_file_ownership_overlap.go +++ b/internal/relationship/exclude_binaries_by_file_ownership_overlap.go @@ -26,9 +26,9 @@ var ( pkg.BitnamiPkg, } binaryMetadataTypes = []string{ - reflect.TypeOf(pkg.ELFBinaryPackageNoteJSONPayload{}).Name(), - reflect.TypeOf(pkg.BinarySignature{}).Name(), - reflect.TypeOf(pkg.JavaVMInstallation{}).Name(), + reflect.TypeFor[pkg.ELFBinaryPackageNoteJSONPayload]().Name(), + reflect.TypeFor[pkg.BinarySignature]().Name(), + reflect.TypeFor[pkg.JavaVMInstallation]().Name(), } ) diff --git a/internal/relationship/exclude_binaries_by_file_ownership_overlap_test.go b/internal/relationship/exclude_binaries_by_file_ownership_overlap_test.go index def556cf5..2b86ea728 100644 --- a/internal/relationship/exclude_binaries_by_file_ownership_overlap_test.go +++ b/internal/relationship/exclude_binaries_by_file_ownership_overlap_test.go @@ -15,7 +15,6 @@ func TestExcludeByFileOwnershipOverlap(t *testing.T) { packageC := pkg.Package{Name: "package-c", Type: pkg.BinaryPkg, Metadata: pkg.ELFBinaryPackageNoteJSONPayload{Type: "rpm"}} packageD := pkg.Package{Name: "package-d", Type: pkg.BitnamiPkg} for _, p := range []*pkg.Package{&packageA, &packageB, &packageC, &packageD} { - p := p p.SetID() } diff --git a/internal/sourcemetadata/names.go b/internal/sourcemetadata/names.go index 6db43ba81..ede193e8b 100644 --- a/internal/sourcemetadata/names.go +++ b/internal/sourcemetadata/names.go @@ -8,11 +8,11 @@ import ( ) var jsonNameFromType = map[reflect.Type][]string{ - reflect.TypeOf(source.DirectoryMetadata{}): {"directory", "dir"}, - reflect.TypeOf(source.FileMetadata{}): {"file"}, - reflect.TypeOf(source.ImageMetadata{}): {"image"}, - reflect.TypeOf(source.SnapMetadata{}): {"snap"}, - reflect.TypeOf(source.OCIModelMetadata{}): {"oci-model"}, + reflect.TypeFor[source.DirectoryMetadata](): {"directory", "dir"}, + reflect.TypeFor[source.FileMetadata](): {"file"}, + reflect.TypeFor[source.ImageMetadata](): {"image"}, + reflect.TypeFor[source.SnapMetadata](): {"snap"}, + reflect.TypeFor[source.OCIModelMetadata](): {"oci-model"}, } func AllTypeNames() []string { diff --git a/internal/string_helpers.go b/internal/string_helpers.go index 8977ceb5b..0f00ffd8c 100644 --- a/internal/string_helpers.go +++ b/internal/string_helpers.go @@ -1,6 +1,9 @@ package internal -import "strings" +import ( + "slices" + "strings" +) // HasAnyOfPrefixes returns an indication if the given string has any of the given prefixes. func HasAnyOfPrefixes(input string, prefixes ...string) bool { @@ -32,12 +35,7 @@ func TruncateMiddleEllipsis(input string, maxLen int) string { } func StringInSlice(a string, list []string) bool { - for _, b := range list { - if b == a { - return true - } - } - return false + return slices.Contains(list, a) } func SplitAny(s string, seps string) []string { diff --git a/internal/tmpdir/tmpdir_test.go b/internal/tmpdir/tmpdir_test.go index 99da49d13..aeb208403 100644 --- a/internal/tmpdir/tmpdir_test.go +++ b/internal/tmpdir/tmpdir_test.go @@ -198,7 +198,7 @@ func TestConcurrentNewChildAndNewFile(t *testing.T) { errs := make(chan error, goroutines) paths := make(chan string, goroutines) - for i := 0; i < goroutines; i++ { + for i := range goroutines { go func(i int) { if i%2 == 0 { child, cleanup, err := td.NewChild("concurrent") @@ -223,7 +223,7 @@ func TestConcurrentNewChildAndNewFile(t *testing.T) { } seen := make(map[string]bool) - for i := 0; i < goroutines; i++ { + for range goroutines { err := <-errs require.NoError(t, err) } @@ -250,7 +250,7 @@ func TestConcurrentNewChildDuringCleanup(t *testing.T) { close(done) }() // try creating children concurrently with cleanup — should get errors, not panics - for i := 0; i < 10; i++ { + for range 10 { _, c, _ := td.NewChild("race") if c != nil { c() diff --git a/internal/tprint.go b/internal/tprint.go index 43d57cba5..6a86a5bd6 100644 --- a/internal/tprint.go +++ b/internal/tprint.go @@ -6,7 +6,7 @@ import ( ) // Tprintf renders a string from a given template string and field values -func Tprintf(tmpl string, data map[string]interface{}) string { +func Tprintf(tmpl string, data map[string]any) string { t := template.Must(template.New("").Parse(tmpl)) buf := &bytes.Buffer{} if err := t.Execute(buf, data); err != nil { diff --git a/internal/unknown/coordinate_error.go b/internal/unknown/coordinate_error.go index 46bc53e11..caa0a160e 100644 --- a/internal/unknown/coordinate_error.go +++ b/internal/unknown/coordinate_error.go @@ -3,6 +3,7 @@ package unknown import ( "errors" "fmt" + "slices" "strings" "github.com/anchore/syft/internal/log" @@ -155,12 +156,7 @@ func containsErr(out []error, err error) bool { log.Tracef("error comparing errors: %v", err) } }() - for _, e := range out { - if e == err { - return true - } - } - return false + return slices.Contains(out, err) } // visitErrors visits every wrapped error. the returned error replaces the provided error, null errors are omitted from diff --git a/syft/artifact/id.go b/syft/artifact/id.go index f8b229eb8..b8af30033 100644 --- a/syft/artifact/id.go +++ b/syft/artifact/id.go @@ -13,7 +13,7 @@ type Identifiable interface { ID() ID } -func IDByHash(obj interface{}) (ID, error) { +func IDByHash(obj any) (ID, error) { f, err := hashstructure.Hash(obj, &hashstructure.HashOptions{ ZeroNil: true, SlicesAsSets: true, diff --git a/syft/artifact/relationship.go b/syft/artifact/relationship.go index eee7f316e..ed0043c4c 100644 --- a/syft/artifact/relationship.go +++ b/syft/artifact/relationship.go @@ -38,5 +38,5 @@ type Relationship struct { From Identifiable To Identifiable Type RelationshipType - Data interface{} + Data any } diff --git a/syft/configuration_audit_trail.go b/syft/configuration_audit_trail.go index ece571581..aa7a51f4d 100644 --- a/syft/configuration_audit_trail.go +++ b/syft/configuration_audit_trail.go @@ -41,7 +41,7 @@ func (cfg configurationAuditTrail) MarshalJSON() ([]byte, error) { return nil, err } - var dataMap map[string]interface{} + var dataMap map[string]any if err := json.Unmarshal(initialJSON, &dataMap); err != nil { return nil, err } @@ -55,13 +55,13 @@ func (cfg configurationAuditTrail) MarshalJSON() ([]byte, error) { } // marshalSorted recursively marshals a map with sorted keys -func marshalSorted(m interface{}) ([]byte, error) { +func marshalSorted(m any) ([]byte, error) { if reflect.TypeOf(m).Kind() != reflect.Map { return json.Marshal(m) } val := reflect.ValueOf(m) - sortedMap := make(map[string]interface{}) + sortedMap := make(map[string]any) for _, key := range val.MapKeys() { value := val.MapIndex(key).Interface() diff --git a/syft/configuration_audit_trail_test.go b/syft/configuration_audit_trail_test.go index 56e9a20d7..ade7bbbf4 100644 --- a/syft/configuration_audit_trail_test.go +++ b/syft/configuration_audit_trail_test.go @@ -33,7 +33,7 @@ func Test_configurationAuditTrail_StructTags(t *testing.T) { } -func getJSONTags(t *testing.T, v interface{}) []string { +func getJSONTags(t *testing.T, v any) []string { var tags []string err := collectJSONTags(t, reflect.ValueOf(v), &tags, "", "") require.NoError(t, err) @@ -142,7 +142,7 @@ func Test_collectJSONTags(t *testing.T) { tests := []struct { name string - v interface{} + v any want []string wantErr require.ErrorAssertionFunc }{ diff --git a/syft/create_sbom_config.go b/syft/create_sbom_config.go index 2e737f6f2..1a84c14b6 100644 --- a/syft/create_sbom_config.go +++ b/syft/create_sbom_config.go @@ -34,7 +34,7 @@ type CreateSBOMConfig struct { // audit what tool is being used to generate the SBOM ToolName string ToolVersion string - ToolConfiguration interface{} + ToolConfiguration any packageTaskFactories task.Factories packageCatalogerReferences []pkgcataloging.CatalogerReference diff --git a/syft/event/parsers/parsers.go b/syft/event/parsers/parsers.go index f30340667..b6cecbb96 100644 --- a/syft/event/parsers/parsers.go +++ b/syft/event/parsers/parsers.go @@ -17,14 +17,14 @@ import ( type ErrBadPayload struct { Type partybus.EventType Field string - Value interface{} + Value any } func (e *ErrBadPayload) Error() string { return fmt.Sprintf("event='%s' has bad event payload field=%q: %q", string(e.Type), e.Field, e.Value) } -func newPayloadErr(t partybus.EventType, field string, value interface{}) error { +func newPayloadErr(t partybus.EventType, field string, value any) error { return &ErrBadPayload{ Type: t, Field: field, diff --git a/syft/format/common/spdxhelpers/to_format_model.go b/syft/format/common/spdxhelpers/to_format_model.go index 113f5c876..12e67ec5c 100644 --- a/syft/format/common/spdxhelpers/to_format_model.go +++ b/syft/format/common/spdxhelpers/to_format_model.go @@ -310,9 +310,9 @@ func toRootPackage(s source.Description) *spdx.Package { func toSPDXID(identifiable artifact.Identifiable) spdx.ElementID { id := string(identifiable.ID()) - if strings.HasPrefix(id, "SPDXRef-") { + if after, ok := strings.CutPrefix(id, "SPDXRef-"); ok { // this is already an SPDX ID, no need to change it (except for the prefix) - return spdx.ElementID(helpers.SanitizeElementID(strings.TrimPrefix(id, "SPDXRef-"))) + return spdx.ElementID(helpers.SanitizeElementID(after)) } maxLen := 40 switch it := identifiable.(type) { diff --git a/syft/format/common/spdxhelpers/to_syft_model.go b/syft/format/common/spdxhelpers/to_syft_model.go index e1bf640a7..80bbbf964 100644 --- a/syft/format/common/spdxhelpers/to_syft_model.go +++ b/syft/format/common/spdxhelpers/to_syft_model.go @@ -479,7 +479,7 @@ func toSyftLocation(f *spdx.File) file.Location { return l } -func requireAndTrimPrefix(val interface{}, prefix string) string { +func requireAndTrimPrefix(val any, prefix string) string { if v, ok := val.(string); ok { if i := strings.Index(v, prefix); i == 0 { return strings.Replace(v, prefix, "", 1) diff --git a/syft/format/common/spdxhelpers/to_syft_model_test.go b/syft/format/common/spdxhelpers/to_syft_model_test.go index e07bcca5b..23a8177ca 100644 --- a/syft/format/common/spdxhelpers/to_syft_model_test.go +++ b/syft/format/common/spdxhelpers/to_syft_model_test.go @@ -119,7 +119,7 @@ func Test_extractMetadata(t *testing.T) { oneTwoThreeFour := 1234 tests := []struct { pkg spdx.Package - meta interface{} + meta any }{ { pkg: spdx.Package{ diff --git a/syft/format/github/internal/model/github_dependency_api.go b/syft/format/github/internal/model/github_dependency_api.go index 56ab7657d..bfb2faaff 100644 --- a/syft/format/github/internal/model/github_dependency_api.go +++ b/syft/format/github/internal/model/github_dependency_api.go @@ -73,6 +73,6 @@ type DependencyGraph map[string]DependencyNode type ISO8601Date = string -type Scalar interface{} // should be: null | boolean | string | number +type Scalar any // should be: null | boolean | string | number type Metadata map[string]Scalar diff --git a/syft/format/internal/cyclonedxutil/helpers/author.go b/syft/format/internal/cyclonedxutil/helpers/author.go index 3b6de7726..a040aaaa0 100644 --- a/syft/format/internal/cyclonedxutil/helpers/author.go +++ b/syft/format/internal/cyclonedxutil/helpers/author.go @@ -31,7 +31,7 @@ func encodeAuthor(p pkg.Package) string { return "" } -func decodeAuthor(author string, metadata interface{}) { +func decodeAuthor(author string, metadata any) { switch meta := metadata.(type) { case *pkg.NpmPackage: meta.Author = author diff --git a/syft/format/internal/cyclonedxutil/helpers/component.go b/syft/format/internal/cyclonedxutil/helpers/component.go index 4a681db3e..588c20ee8 100644 --- a/syft/format/internal/cyclonedxutil/helpers/component.go +++ b/syft/format/internal/cyclonedxutil/helpers/component.go @@ -202,7 +202,7 @@ func setPackageName(p *pkg.Package, c *cyclonedx.Component) { } func decodeLocations(vals map[string]string) file.LocationSet { - v := Decode(reflect.TypeOf([]file.Location{}), vals, "syft:location", CycloneDXFields) + v := Decode(reflect.TypeFor[[]file.Location](), vals, "syft:location", CycloneDXFields) out, ok := v.([]file.Location) if !ok { out = nil @@ -210,7 +210,7 @@ func decodeLocations(vals map[string]string) file.LocationSet { return file.NewLocationSet(out...) } -func decodePackageMetadata(vals map[string]string, c *cyclonedx.Component, typeName string) interface{} { +func decodePackageMetadata(vals map[string]string, c *cyclonedx.Component, typeName string) any { if typeName != "" && c.Properties != nil { metadataType := packagemetadata.ReflectTypeFromJSONName(typeName) if metadataType == nil { diff --git a/syft/format/internal/cyclonedxutil/helpers/decoder.go b/syft/format/internal/cyclonedxutil/helpers/decoder.go index 43470494b..0f1783362 100644 --- a/syft/format/internal/cyclonedxutil/helpers/decoder.go +++ b/syft/format/internal/cyclonedxutil/helpers/decoder.go @@ -26,7 +26,7 @@ func ToSyftModel(bom *cyclonedx.BOM) (*sbom.SBOM, error) { Descriptor: extractDescriptor(bom.Metadata), } - idMap := make(map[string]interface{}) + idMap := make(map[string]any) if err := collectBomPackages(bom, s, idMap); err != nil { return nil, err @@ -37,7 +37,7 @@ func ToSyftModel(bom *cyclonedx.BOM) (*sbom.SBOM, error) { return s, nil } -func collectBomPackages(bom *cyclonedx.BOM, s *sbom.SBOM, idMap map[string]interface{}) error { +func collectBomPackages(bom *cyclonedx.BOM, s *sbom.SBOM, idMap map[string]any) error { componentsPresent := false if bom.Components != nil { for i := range *bom.Components { @@ -58,7 +58,7 @@ func collectBomPackages(bom *cyclonedx.BOM, s *sbom.SBOM, idMap map[string]inter return nil } -func collectPackages(component *cyclonedx.Component, s *sbom.SBOM, idMap map[string]interface{}) { +func collectPackages(component *cyclonedx.Component, s *sbom.SBOM, idMap map[string]any) { switch component.Type { case cyclonedx.ComponentTypeOS: case cyclonedx.ComponentTypeContainer: @@ -168,7 +168,7 @@ func getPropertyValue(component *cyclonedx.Component, name string) string { return "" } -func collectRelationships(bom *cyclonedx.BOM, s *sbom.SBOM, idMap map[string]interface{}) { +func collectRelationships(bom *cyclonedx.BOM, s *sbom.SBOM, idMap map[string]any) { if bom.Dependencies == nil { return } diff --git a/syft/format/internal/cyclonedxutil/helpers/description.go b/syft/format/internal/cyclonedxutil/helpers/description.go index 976bbbc1e..17e2fd2c4 100644 --- a/syft/format/internal/cyclonedxutil/helpers/description.go +++ b/syft/format/internal/cyclonedxutil/helpers/description.go @@ -14,7 +14,7 @@ func encodeDescription(p pkg.Package) string { return "" } -func decodeDescription(description string, metadata interface{}) { +func decodeDescription(description string, metadata any) { switch meta := metadata.(type) { case *pkg.ApkDBEntry: meta.Description = description diff --git a/syft/format/internal/cyclonedxutil/helpers/external_references.go b/syft/format/internal/cyclonedxutil/helpers/external_references.go index 349d966a8..4f7762142 100644 --- a/syft/format/internal/cyclonedxutil/helpers/external_references.go +++ b/syft/format/internal/cyclonedxutil/helpers/external_references.go @@ -100,7 +100,7 @@ func toCycloneDXAlgorithm(algorithm string) cyclonedx.HashAlgorithm { return validMap[strings.ToLower(algorithm)] } -func decodeExternalReferences(c *cyclonedx.Component, metadata interface{}) { +func decodeExternalReferences(c *cyclonedx.Component, metadata any) { if c.ExternalReferences == nil { return } diff --git a/syft/format/internal/cyclonedxutil/helpers/group.go b/syft/format/internal/cyclonedxutil/helpers/group.go index 65b993707..114116ee0 100644 --- a/syft/format/internal/cyclonedxutil/helpers/group.go +++ b/syft/format/internal/cyclonedxutil/helpers/group.go @@ -11,7 +11,7 @@ func encodeGroup(p pkg.Package) string { return "" } -func decodeGroup(group string, metadata interface{}) { +func decodeGroup(group string, metadata any) { if meta, ok := metadata.(*pkg.JavaArchive); ok { if meta.PomProperties == nil { meta.PomProperties = &pkg.JavaPomProperties{} diff --git a/syft/format/internal/cyclonedxutil/helpers/properties.go b/syft/format/internal/cyclonedxutil/helpers/properties.go index 3ef1acd0d..feb6db419 100644 --- a/syft/format/internal/cyclonedxutil/helpers/properties.go +++ b/syft/format/internal/cyclonedxutil/helpers/properties.go @@ -10,7 +10,7 @@ var ( CycloneDXFields = RequiredTag("cyclonedx") ) -func EncodeProperties(obj interface{}, prefix string) (out []cyclonedx.Property) { +func EncodeProperties(obj any, prefix string) (out []cyclonedx.Property) { for _, p := range Sorted(Encode(obj, prefix, CycloneDXFields)) { out = append(out, cyclonedx.Property{ Name: p.Name, @@ -23,8 +23,8 @@ func EncodeProperties(obj interface{}, prefix string) (out []cyclonedx.Property) func decodeProperties(properties []cyclonedx.Property, prefix string) map[string]string { labels := make(map[string]string) for _, property := range properties { - if strings.HasPrefix(property.Name, prefix) { - labelName := strings.TrimPrefix(property.Name, prefix) + if after, ok := strings.CutPrefix(property.Name, prefix); ok { + labelName := after labels[labelName] = property.Value } } diff --git a/syft/format/internal/cyclonedxutil/helpers/property_encoder.go b/syft/format/internal/cyclonedxutil/helpers/property_encoder.go index cfa7e2697..dd442f6e3 100644 --- a/syft/format/internal/cyclonedxutil/helpers/property_encoder.go +++ b/syft/format/internal/cyclonedxutil/helpers/property_encoder.go @@ -300,8 +300,8 @@ func decode(vals map[string]string, value reflect.Value, prefix string, fn Field // NOTE: this will not work for nested maps for key := range vals { // test for map prefix - if strings.HasPrefix(key, str) { - keyVals[key] = strings.TrimPrefix(key, str) + if after, ok := strings.CutPrefix(key, str); ok { + keyVals[key] = after // create new placeholder and decode key newKeyType := keyType if keyType.Kind() == reflect.Ptr { diff --git a/syft/format/internal/cyclonedxutil/helpers/property_encoder_test.go b/syft/format/internal/cyclonedxutil/helpers/property_encoder_test.go index 19f87d1ae..6b16c937c 100644 --- a/syft/format/internal/cyclonedxutil/helpers/property_encoder_test.go +++ b/syft/format/internal/cyclonedxutil/helpers/property_encoder_test.go @@ -46,7 +46,7 @@ func Test_EncodeDecodeCycle(t *testing.T) { tests := []struct { name string - value interface{} + value any }{ { name: "all values", diff --git a/syft/format/internal/cyclonedxutil/helpers/publisher.go b/syft/format/internal/cyclonedxutil/helpers/publisher.go index ed4441d5c..02df2b31c 100644 --- a/syft/format/internal/cyclonedxutil/helpers/publisher.go +++ b/syft/format/internal/cyclonedxutil/helpers/publisher.go @@ -18,7 +18,7 @@ func encodePublisher(p pkg.Package) string { return "" } -func decodePublisher(publisher string, metadata interface{}) { +func decodePublisher(publisher string, metadata any) { switch meta := metadata.(type) { case *pkg.ApkDBEntry: meta.Maintainer = publisher diff --git a/syft/format/syftjson/model/document.go b/syft/format/syftjson/model/document.go index 0ac446805..9672ac3e5 100644 --- a/syft/format/syftjson/model/document.go +++ b/syft/format/syftjson/model/document.go @@ -44,7 +44,7 @@ type Descriptor struct { Version string `json:"version"` // Configuration contains the tool configuration used during SBOM generation. - Configuration interface{} `json:"configuration,omitempty"` + Configuration any `json:"configuration,omitempty"` } // Schema specifies the JSON schema version and URL reference that defines the structure and validation rules for this document format. diff --git a/syft/format/syftjson/model/linux_release_test.go b/syft/format/syftjson/model/linux_release_test.go index 66487f59d..220ddbc57 100644 --- a/syft/format/syftjson/model/linux_release_test.go +++ b/syft/format/syftjson/model/linux_release_test.go @@ -11,7 +11,7 @@ import ( func TestIDLikes_UnmarshalJSON(t *testing.T) { tests := []struct { name string - data interface{} + data any expected IDLikes }{ { diff --git a/syft/format/syftjson/model/package.go b/syft/format/syftjson/model/package.go index eb59e78a7..e2fb53722 100644 --- a/syft/format/syftjson/model/package.go +++ b/syft/format/syftjson/model/package.go @@ -205,7 +205,7 @@ func unpackPkgMetadata(p *Package, unpacker packageMetadataUnpacker) error { if typ == nil { // capture unknown metadata as a generic struct if len(unpacker.Metadata) > 0 { - var val interface{} + var val any if err := json.Unmarshal(unpacker.Metadata, &val); err != nil { return err } diff --git a/syft/format/syftjson/model/package_test.go b/syft/format/syftjson/model/package_test.go index 778b7b237..928cb8685 100644 --- a/syft/format/syftjson/model/package_test.go +++ b/syft/format/syftjson/model/package_test.go @@ -207,7 +207,7 @@ func Test_UnmarshalJSON(t *testing.T) { `), assert: func(p *Package) { assert.Equal(t, pkg.RpmPkg, p.Type) - assert.Equal(t, reflect.TypeOf(pkg.RpmDBEntry{}).Name(), reflect.TypeOf(p.Metadata).Name()) + assert.Equal(t, reflect.TypeFor[pkg.RpmDBEntry]().Name(), reflect.TypeOf(p.Metadata).Name()) }, }, { @@ -248,7 +248,7 @@ func Test_UnmarshalJSON(t *testing.T) { `), assert: func(p *Package) { assert.Equal(t, pkg.RpmPkg, p.Type) - assert.Equal(t, reflect.TypeOf(pkg.RpmArchive{}).Name(), reflect.TypeOf(p.Metadata).Name()) + assert.Equal(t, reflect.TypeFor[pkg.RpmArchive]().Name(), reflect.TypeOf(p.Metadata).Name()) }, }, { @@ -287,7 +287,7 @@ func Test_UnmarshalJSON(t *testing.T) { }`), assert: func(p *Package) { assert.Equal(t, pkg.HackagePkg, p.Type) - assert.Equal(t, reflect.TypeOf(pkg.HackageStackYamlEntry{}).Name(), reflect.TypeOf(p.Metadata).Name()) + assert.Equal(t, reflect.TypeFor[pkg.HackageStackYamlEntry]().Name(), reflect.TypeOf(p.Metadata).Name()) }, }, { @@ -327,7 +327,7 @@ func Test_UnmarshalJSON(t *testing.T) { }`), assert: func(p *Package) { assert.Equal(t, pkg.HackagePkg, p.Type) - assert.Equal(t, reflect.TypeOf(pkg.HackageStackYamlLockEntry{}).Name(), reflect.TypeOf(p.Metadata).Name()) + assert.Equal(t, reflect.TypeFor[pkg.HackageStackYamlLockEntry]().Name(), reflect.TypeOf(p.Metadata).Name()) }, }, { @@ -355,7 +355,7 @@ func Test_UnmarshalJSON(t *testing.T) { }`), assert: func(p *Package) { assert.Equal(t, pkg.HackagePkg, p.Type) - assert.Equal(t, reflect.TypeOf(pkg.RustCargoLockEntry{}).Name(), reflect.TypeOf(p.Metadata).Name()) + assert.Equal(t, reflect.TypeFor[pkg.RustCargoLockEntry]().Name(), reflect.TypeOf(p.Metadata).Name()) }, }, { @@ -383,7 +383,7 @@ func Test_UnmarshalJSON(t *testing.T) { }`), assert: func(p *Package) { assert.Equal(t, pkg.HackagePkg, p.Type) - assert.Equal(t, reflect.TypeOf(pkg.RustBinaryAuditEntry{}).Name(), reflect.TypeOf(p.Metadata).Name()) + assert.Equal(t, reflect.TypeFor[pkg.RustBinaryAuditEntry]().Name(), reflect.TypeOf(p.Metadata).Name()) }, }, { @@ -654,7 +654,7 @@ func Test_unpackMetadata(t *testing.T) { } }`), wantErr: require.Error, - wantMetadata: map[string]interface{}{ + wantMetadata: map[string]any{ "thing": "thing-1", }, }, diff --git a/syft/format/syftjson/model/relationship.go b/syft/format/syftjson/model/relationship.go index e17a5bd97..69bd646c3 100644 --- a/syft/format/syftjson/model/relationship.go +++ b/syft/format/syftjson/model/relationship.go @@ -12,5 +12,5 @@ type Relationship struct { Type string `json:"type"` // Metadata contains additional relationship-specific metadata. - Metadata interface{} `json:"metadata,omitempty"` + Metadata any `json:"metadata,omitempty"` } diff --git a/syft/format/syftjson/model/source.go b/syft/format/syftjson/model/source.go index 83a2d87f0..b061d2a8c 100644 --- a/syft/format/syftjson/model/source.go +++ b/syft/format/syftjson/model/source.go @@ -30,7 +30,7 @@ type Source struct { Type string `json:"type"` // Metadata contains additional source-specific metadata. - Metadata interface{} `json:"metadata"` + Metadata any `json:"metadata"` } // sourceUnpacker is used to unmarshal Source objects @@ -97,7 +97,7 @@ func cleanPreSchemaV9MetadataType(t string) string { return t } -func extractPreSchemaV9Metadata(t string, target []byte) (interface{}, error) { +func extractPreSchemaV9Metadata(t string, target []byte) (any, error) { switch t { case "directory", "dir": cleanTarget, err := strconv.Unquote(string(target)) diff --git a/syft/format/syftjson/schema_test.go b/syft/format/syftjson/schema_test.go index 2e0a28e72..d0347de30 100644 --- a/syft/format/syftjson/schema_test.go +++ b/syft/format/syftjson/schema_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "os" "path/filepath" + "slices" "testing" "github.com/iancoleman/strcase" @@ -79,10 +80,8 @@ func isFollowingConvention(path, fieldName string) (bool, string) { result := exp == fieldName exception := func(exceptions ...string) (bool, string) { - for _, e := range exceptions { - if e == fieldName { - return true, fieldName - } + if slices.Contains(exceptions, fieldName) { + return true, fieldName } return result, exp } diff --git a/syft/format/syftjson/to_format_model.go b/syft/format/syftjson/to_format_model.go index 38274b209..5eeaf3f47 100644 --- a/syft/format/syftjson/to_format_model.go +++ b/syft/format/syftjson/to_format_model.go @@ -21,11 +21,11 @@ import ( ) // MetadataType infers the metadata type value based on the pkg.Metadata payload. -func MetadataType(metadata interface{}) string { +func MetadataType(metadata any) string { return metadataType(metadata, false) } -func metadataType(metadata interface{}, legacy bool) string { +func metadataType(metadata any, legacy bool) string { if legacy { return packagemetadata.JSONLegacyName(metadata) } diff --git a/syft/format/syftjson/to_syft_model.go b/syft/format/syftjson/to_syft_model.go index e7266b934..ee227b00c 100644 --- a/syft/format/syftjson/to_syft_model.go +++ b/syft/format/syftjson/to_syft_model.go @@ -223,7 +223,7 @@ func toInternalLinuxRelease(d model.LinuxRelease) *linux.Release { } func toSyftRelationships(doc *model.Document, catalog *pkg.Collection, relationships []model.Relationship, idAliases map[string]string) ([]artifact.Relationship, []error) { - idMap := make(map[string]interface{}) + idMap := make(map[string]any) for _, p := range catalog.Sorted() { idMap[string(p.ID())] = p @@ -263,7 +263,7 @@ func toSyftSource(s model.Source) source.Source { return source.FromDescription(*description) } -func toSyftRelationship(idMap map[string]interface{}, relationship model.Relationship, idAliases map[string]string) (*artifact.Relationship, error) { +func toSyftRelationship(idMap map[string]any, relationship model.Relationship, idAliases map[string]string) (*artifact.Relationship, error) { id := func(id string) string { aliased, ok := idAliases[id] if ok { diff --git a/syft/format/syftjson/to_syft_model_test.go b/syft/format/syftjson/to_syft_model_test.go index d369f7ed4..ed4b7b59b 100644 --- a/syft/format/syftjson/to_syft_model_test.go +++ b/syft/format/syftjson/to_syft_model_test.go @@ -448,7 +448,7 @@ func Test_toSyftRelationship(t *testing.T) { parentPackage := packageWithId("some-parent-id") tests := []struct { name string - idMap map[string]interface{} + idMap map[string]any idAliases map[string]string relationships model.Relationship want *artifact.Relationship @@ -456,7 +456,7 @@ func Test_toSyftRelationship(t *testing.T) { }{ { name: "one relationship no warnings", - idMap: map[string]interface{}{ + idMap: map[string]any{ "some-child-id": childPackage, "some-parent-id": parentPackage, }, @@ -474,7 +474,7 @@ func Test_toSyftRelationship(t *testing.T) { }, { name: "relationship unknown type one warning", - idMap: map[string]interface{}{ + idMap: map[string]any{ "some-child-id": childPackage, "some-parent-id": parentPackage, }, @@ -490,7 +490,7 @@ func Test_toSyftRelationship(t *testing.T) { }, { name: "relationship missing child ID one warning", - idMap: map[string]interface{}{ + idMap: map[string]any{ "some-parent-id": parentPackage, }, idAliases: map[string]string{}, @@ -505,7 +505,7 @@ func Test_toSyftRelationship(t *testing.T) { }, { name: "relationship missing parent ID one warning", - idMap: map[string]interface{}{ + idMap: map[string]any{ "some-child-id": childPackage, }, idAliases: map[string]string{}, diff --git a/syft/format/template/encoder.go b/syft/format/template/encoder.go index 8723e1630..e387601c3 100644 --- a/syft/format/template/encoder.go +++ b/syft/format/template/encoder.go @@ -34,7 +34,7 @@ func NewFormatEncoder(cfg EncoderConfig) (sbom.FormatEncoder, error) { // TODO: revisit this... should no template file be an error or simply render an empty result? or render the json output? // Note: do not check for the existence of the template file here, as the default encoder cannot provide one. f := sprig.HermeticTxtFuncMap() - f["getLastIndex"] = func(collection interface{}) int { + f["getLastIndex"] = func(collection any) int { if v := reflect.ValueOf(collection); v.Kind() == reflect.Slice { return v.Len() - 1 } @@ -42,7 +42,7 @@ func NewFormatEncoder(cfg EncoderConfig) (sbom.FormatEncoder, error) { return 0 } // Checks if a field is defined - f["hasField"] = func(obj interface{}, field string) bool { + f["hasField"] = func(obj any, field string) bool { t := reflect.TypeOf(obj) _, ok := t.FieldByName(field) return ok diff --git a/syft/get_source_test.go b/syft/get_source_test.go index 612e5c3a4..9abdbdef1 100644 --- a/syft/get_source_test.go +++ b/syft/get_source_test.go @@ -148,7 +148,7 @@ func TestValidateSourcePlatform_UnsupportedMetadataTypes(t *testing.T) { tests := []struct { name string - metadata interface{} + metadata any }{ { name: "string metadata", diff --git a/syft/internal/fileresolver/directory_indexer.go b/syft/internal/fileresolver/directory_indexer.go index bc3d8a5f2..4ae58702c 100644 --- a/syft/internal/fileresolver/directory_indexer.go +++ b/syft/internal/fileresolver/directory_indexer.go @@ -385,8 +385,8 @@ func (r directoryIndexer) addSymlinkToIndex(p string, info os.FileInfo) (string, // we cannot directly concatenate ".." to "/root/symlink",however, // the parent directory of linkTarget should be "/root" for strings.HasPrefix(dir, "..") { - if strings.HasPrefix(dir, "../") { - dir = strings.TrimPrefix(dir, "../") + if after, ok := strings.CutPrefix(dir, "../"); ok { + dir = after } else { dir = strings.TrimPrefix(dir, "..") } diff --git a/syft/internal/fileresolver/directory_test.go b/syft/internal/fileresolver/directory_test.go index 7aaff77ff..9c7eac57b 100644 --- a/syft/internal/fileresolver/directory_test.go +++ b/syft/internal/fileresolver/directory_test.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package fileresolver diff --git a/syft/internal/fileresolver/filetree_resolver_test.go b/syft/internal/fileresolver/filetree_resolver_test.go index 48af879bb..55a7e6cc7 100644 --- a/syft/internal/fileresolver/filetree_resolver_test.go +++ b/syft/internal/fileresolver/filetree_resolver_test.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package fileresolver @@ -1355,7 +1354,7 @@ func (t testFileInfo) IsDir() bool { panic("implement me") } -func (t testFileInfo) Sys() interface{} { +func (t testFileInfo) Sys() any { panic("implement me") } diff --git a/syft/internal/fileresolver/path_skipper_test.go b/syft/internal/fileresolver/path_skipper_test.go index 14b6b3b00..133de54d4 100644 --- a/syft/internal/fileresolver/path_skipper_test.go +++ b/syft/internal/fileresolver/path_skipper_test.go @@ -426,7 +426,7 @@ func assertSkipErr() assert.ErrorAssertionFunc { } func assertErrorIs(want error) assert.ErrorAssertionFunc { - return func(t assert.TestingT, got error, msgAndArgs ...interface{}) bool { + return func(t assert.TestingT, got error, msgAndArgs ...any) bool { return assert.ErrorIs(t, got, want, msgAndArgs...) } } diff --git a/syft/internal/fileresolver/unindexed_directory.go b/syft/internal/fileresolver/unindexed_directory.go index ccc604588..f2435ff0d 100644 --- a/syft/internal/fileresolver/unindexed_directory.go +++ b/syft/internal/fileresolver/unindexed_directory.go @@ -300,7 +300,7 @@ func (u UnindexedDirectory) resolveLinks(filePath string) []string { resolvedPath := "" parts := strings.Split(filePath, "/") - for i := 0; i < len(parts); i++ { + for i := range parts { part := parts[i] if resolvedPath == "" { resolvedPath = part diff --git a/syft/internal/fileresolver/unindexed_directory_test.go b/syft/internal/fileresolver/unindexed_directory_test.go index 8d92dc353..a6d76a02f 100644 --- a/syft/internal/fileresolver/unindexed_directory_test.go +++ b/syft/internal/fileresolver/unindexed_directory_test.go @@ -1,5 +1,4 @@ //go:build !windows -// +build !windows package fileresolver diff --git a/syft/internal/unionreader/union_reader_test.go b/syft/internal/unionreader/union_reader_test.go index 961e4561c..b18b8fcc6 100644 --- a/syft/internal/unionreader/union_reader_test.go +++ b/syft/internal/unionreader/union_reader_test.go @@ -168,7 +168,7 @@ func TestReaderAtAdapter_ReadAt(t *testing.T) { adapter := newReaderAtAdapter(reader) // read the same data multiple times - for i := 0; i < 3; i++ { + for i := range 3 { buf := make([]byte, 5) n, err := adapter.ReadAt(buf, 7) @@ -194,12 +194,12 @@ func TestReaderAtAdapter_ReadAt(t *testing.T) { var wg sync.WaitGroup results := make(chan bool, numGoroutines*numReads) - for i := 0; i < numGoroutines; i++ { + for i := range numGoroutines { wg.Add(1) go func(goroutineID int) { defer wg.Done() - for j := 0; j < numReads; j++ { + for range numReads { offset := int64(goroutineID % len(td)) buf := make([]byte, 1) diff --git a/syft/pkg/apk.go b/syft/pkg/apk.go index 6fe2a923c..1649b49e4 100644 --- a/syft/pkg/apk.go +++ b/syft/pkg/apk.go @@ -71,11 +71,11 @@ type spaceDelimitedStringSlice []string func (m *ApkDBEntry) UnmarshalJSON(data []byte) error { var fields []reflect.StructField - t := reflect.TypeOf(ApkDBEntry{}) + t := reflect.TypeFor[ApkDBEntry]() for i := 0; i < t.NumField(); i++ { f := t.Field(i) if f.Name == "Dependencies" { - f.Type = reflect.TypeOf(spaceDelimitedStringSlice{}) + f.Type = reflect.TypeFor[spaceDelimitedStringSlice]() } fields = append(fields, f) } @@ -89,7 +89,7 @@ func (m *ApkDBEntry) UnmarshalJSON(data []byte) error { } func (a *spaceDelimitedStringSlice) UnmarshalJSON(data []byte) error { - var jsonObj interface{} + var jsonObj any if err := json.Unmarshal(data, &jsonObj); err != nil { return err @@ -103,7 +103,7 @@ func (a *spaceDelimitedStringSlice) UnmarshalJSON(data []byte) error { *a = strings.Split(obj, " ") } return nil - case []interface{}: + case []any: s := make([]string, 0, len(obj)) for _, v := range obj { value, ok := v.(string) diff --git a/syft/pkg/cataloger/ai/cataloger_test.go b/syft/pkg/cataloger/ai/cataloger_test.go index f3a99e9e2..d8c28d6d0 100644 --- a/syft/pkg/cataloger/ai/cataloger_test.go +++ b/syft/pkg/cataloger/ai/cataloger_test.go @@ -76,7 +76,7 @@ func TestGGUFCataloger(t *testing.T) { GGUFVersion: 3, TensorCount: 0, MetadataKeyValuesHash: "6e3d368066455ce4", - RemainingKeyValues: map[string]interface{}{ + RemainingKeyValues: map[string]any{ "general.some_random_kv": "foobar", }, }, @@ -113,7 +113,7 @@ func TestGGUFCataloger(t *testing.T) { GGUFVersion: 3, TensorCount: 0, MetadataKeyValuesHash: "9dc6f23591062a27", - RemainingKeyValues: map[string]interface{}{ + RemainingKeyValues: map[string]any{ "gpt2.context_length": "1024", "gpt2.embedding_length": uint32(768), }, diff --git a/syft/pkg/cataloger/ai/parse_gguf.go b/syft/pkg/cataloger/ai/parse_gguf.go index 3a1eb473f..3150110a3 100644 --- a/syft/pkg/cataloger/ai/parse_gguf.go +++ b/syft/pkg/cataloger/ai/parse_gguf.go @@ -46,8 +46,8 @@ func copyHeader(w io.Writer, r io.Reader) error { } // Helper to convert gguf_parser metadata to simpler types -func convertGGUFMetadataKVs(kvs gguf_parser.GGUFMetadataKVs) map[string]interface{} { - result := make(map[string]interface{}) +func convertGGUFMetadataKVs(kvs gguf_parser.GGUFMetadataKVs) map[string]any { + result := make(map[string]any) for _, kv := range kvs { // Skip standard fields that are extracted separately diff --git a/syft/pkg/cataloger/ai/test_helpers_test.go b/syft/pkg/cataloger/ai/test_helpers_test.go index aeca0dc63..195e90d92 100644 --- a/syft/pkg/cataloger/ai/test_helpers_test.go +++ b/syft/pkg/cataloger/ai/test_helpers_test.go @@ -35,7 +35,7 @@ type testGGUFBuilder struct { type testKVPair struct { key string valueType uint32 - value interface{} + value any } func newTestGGUFBuilder() *testGGUFBuilder { diff --git a/syft/pkg/cataloger/arch/parse_alpm_db.go b/syft/pkg/cataloger/arch/parse_alpm_db.go index c030f60b0..6e409824b 100644 --- a/syft/pkg/cataloger/arch/parse_alpm_db.go +++ b/syft/pkg/cataloger/arch/parse_alpm_db.go @@ -153,7 +153,7 @@ func newScanner(reader io.Reader) *bufio.Scanner { scanner := bufio.NewScanner(reader) scanner.Buffer(bufScan, maxScannerCapacity) onDoubleLF := func(data []byte, atEOF bool) (advance int, token []byte, err error) { - for i := 0; i < len(data); i++ { + for i := range data { if i > 0 && data[i-1] == '\n' && data[i] == '\n' { return i + 1, data[:i-1], nil } @@ -188,7 +188,7 @@ func getLocation(path string, resolver file.Resolver) (file.Location, error) { func parseDatabase(b *bufio.Scanner) (*parsedData, error) { var err error - pkgFields := make(map[string]interface{}) + pkgFields := make(map[string]any) for b.Scan() { fields := strings.SplitN(b.Text(), "\n", 2) @@ -213,12 +213,12 @@ func parseDatabase(b *bufio.Scanner) (*parsedData, error) { } pkgFields[key] = files case "backup": - var backup []map[string]interface{} + var backup []map[string]any for _, f := range strings.Split(value, "\n") { fields := strings.SplitN(f, "\t", 2) p := fmt.Sprintf("/%s", fields[0]) if ok := ignoredFiles[p]; !ok { - backup = append(backup, map[string]interface{}{ + backup = append(backup, map[string]any{ "path": p, "digests": []file.Digest{{ Algorithm: "md5", @@ -257,7 +257,7 @@ func processLibrarySpecs(value string) []string { return librarySpecs } -func parsePkgFiles(pkgFields map[string]interface{}) (*parsedData, error) { +func parsePkgFiles(pkgFields map[string]any) (*parsedData, error) { var entry parsedData if err := mapstructure.Decode(pkgFields, &entry); err != nil { return nil, fmt.Errorf("unable to parse ALPM metadata: %w", err) @@ -292,7 +292,7 @@ func parseMtree(r io.Reader) ([]pkg.AlpmFileRecord, error) { for _, f := range specDh.Entries { var entry pkg.AlpmFileRecord entry.Digests = make([]file.Digest, 0) - fileFields := make(map[string]interface{}) + fileFields := make(map[string]any) if ok := ignoredFiles[f.Name]; ok { continue } diff --git a/syft/pkg/cataloger/conda/cataloger_test.go b/syft/pkg/cataloger/conda/cataloger_test.go index 74d630403..9a5c89da6 100644 --- a/syft/pkg/cataloger/conda/cataloger_test.go +++ b/syft/pkg/cataloger/conda/cataloger_test.go @@ -195,7 +195,7 @@ func Test_CondaCataloger(t *testing.T) { name: "badly formatted conda meta json file", fixture: "testdata/conda-meta-bad-json", expectedPackages: nil, - wantErr: func(t require.TestingT, err error, msgAndArgs ...interface{}) { + wantErr: func(t require.TestingT, err error, msgAndArgs ...any) { require.Error(t, err) require.Contains(t, err.Error(), "failed to parse conda-meta package file at conda-meta/package-1.2.3-pyhd8ed1ab_0.json") require.Contains(t, err.Error(), "invalid character") diff --git a/syft/pkg/cataloger/debian/parse_dpkg_db.go b/syft/pkg/cataloger/debian/parse_dpkg_db.go index 27dc0978d..1a2e72e50 100644 --- a/syft/pkg/cataloger/debian/parse_dpkg_db.go +++ b/syft/pkg/cataloger/debian/parse_dpkg_db.go @@ -194,8 +194,8 @@ func splitPkgList(pkgList string) (ret []string) { return ret } -func extractAllFields(reader *bufio.Reader) (map[string]interface{}, error) { - dpkgFields := make(map[string]interface{}) +func extractAllFields(reader *bufio.Reader) (map[string]any, error) { + dpkgFields := make(map[string]any) var key string for { @@ -234,7 +234,7 @@ func extractAllFields(reader *bufio.Reader) (map[string]interface{}, error) { dpkgFields[key] = val default: // parse a new key - var val interface{} + var val any key, val, err = handleNewKeyValue(line) if err != nil { log.Tracef("parsing dpkg status: extracting key-value from line: %s err: %v", line, err) @@ -259,7 +259,7 @@ func extractSourceVersion(source string) (string, string) { } // handleNewKeyValue parse a new key-value pair from the given unprocessed line -func handleNewKeyValue(line string) (key string, val interface{}, err error) { +func handleNewKeyValue(line string) (key string, val any, err error) { if i := strings.Index(line, ":"); i > 0 { key = strings.TrimSpace(line[0:i]) // mapstruct cant handle "-" diff --git a/syft/pkg/cataloger/debian/parse_dpkg_db_test.go b/syft/pkg/cataloger/debian/parse_dpkg_db_test.go index 49851d596..1cca3d9f6 100644 --- a/syft/pkg/cataloger/debian/parse_dpkg_db_test.go +++ b/syft/pkg/cataloger/debian/parse_dpkg_db_test.go @@ -339,7 +339,7 @@ func TestSourceVersionExtract(t *testing.T) { } func requireAs(expected error) require.ErrorAssertionFunc { - return func(t require.TestingT, err error, i ...interface{}) { + return func(t require.TestingT, err error, i ...any) { require.ErrorAs(t, err, &expected) } } @@ -413,7 +413,7 @@ func Test_handleNewKeyValue(t *testing.T) { name string line string wantKey string - wantVal interface{} + wantVal any wantErr require.ErrorAssertionFunc }{ { diff --git a/syft/pkg/cataloger/erlang/erlang_parser.go b/syft/pkg/cataloger/erlang/erlang_parser.go index 83aeb8f01..ae22589b4 100644 --- a/syft/pkg/cataloger/erlang/erlang_parser.go +++ b/syft/pkg/cataloger/erlang/erlang_parser.go @@ -10,7 +10,7 @@ import ( ) type erlangNode struct { - value interface{} + value any } var errSkipComments = errors.New("") @@ -39,7 +39,7 @@ func (e erlangNode) Get(index int) erlangNode { return erlangNode{} } -func node(value interface{}) erlangNode { +func node(value any) erlangNode { return erlangNode{ value: value, } diff --git a/syft/pkg/cataloger/gentoo/license.go b/syft/pkg/cataloger/gentoo/license.go index d1453f12d..ee23c0372 100644 --- a/syft/pkg/cataloger/gentoo/license.go +++ b/syft/pkg/cataloger/gentoo/license.go @@ -143,9 +143,9 @@ func replaceLicenseGroups(licenses []string, groups map[string][]string) []strin result := make([]string, 0, len(licenses)) for _, license := range licenses { - if strings.HasPrefix(license, "@") { + if after, ok := strings.CutPrefix(license, "@"); ok { // this is a license group... - name := strings.TrimPrefix(license, "@") + name := after if expandedLicenses, ok := groups[name]; ok { result = append(result, expandedLicenses...) } else { diff --git a/syft/pkg/cataloger/golang/upx.go b/syft/pkg/cataloger/golang/upx.go index 2e15b64af..e3b5d882f 100644 --- a/syft/pkg/cataloger/golang/upx.go +++ b/syft/pkg/cataloger/golang/upx.go @@ -346,7 +346,7 @@ func parseELFPTLoadOffsets(elfHeader []byte) []uint64 { phnum := binary.LittleEndian.Uint16(elfHeader[0x38:0x3a]) var offsets []uint64 - for i := uint16(0); i < phnum; i++ { + for i := range phnum { phStart := phoff + uint64(i)*uint64(phentsize) if phStart+uint64(phentsize) > uint64(len(elfHeader)) { break @@ -499,10 +499,7 @@ func decompressLZMA(compressedData []byte, uncompressedSize uint32) ([]byte, err // it may be that the dictionary size was not considered properly in this code. const minDictSize = 64 * 1024 // 64KB minimum const maxDictSize = 128 * 1024 * 1024 // 128MB maximum - dictSize := nextPowerOf2(uncompressedSize) - if dictSize < minDictSize { - dictSize = minDictSize - } + dictSize := max(nextPowerOf2(uncompressedSize), minDictSize) if dictSize > maxDictSize { dictSize = maxDictSize } diff --git a/syft/pkg/cataloger/internal/cpegenerate/apk.go b/syft/pkg/cataloger/internal/cpegenerate/apk.go index fa5f78cb1..deb9061c7 100644 --- a/syft/pkg/cataloger/internal/cpegenerate/apk.go +++ b/syft/pkg/cataloger/internal/cpegenerate/apk.go @@ -42,8 +42,8 @@ func upstreamCandidates(m pkg.ApkDBEntry) (candidates []upstreamCandidate) { } for prefix, typ := range prefixesToPackageType { - if strings.HasPrefix(name, prefix) { - t := strings.TrimPrefix(name, prefix) + if after, ok0 := strings.CutPrefix(name, prefix); ok0 { + t := after if t != "" { candidates = append(candidates, upstreamCandidate{Name: t, Type: typ}) return candidates diff --git a/syft/pkg/cataloger/internal/cpegenerate/dictionary/index-generator/generate.go b/syft/pkg/cataloger/internal/cpegenerate/dictionary/index-generator/generate.go index cc04633dd..0028343f2 100644 --- a/syft/pkg/cataloger/internal/cpegenerate/dictionary/index-generator/generate.go +++ b/syft/pkg/cataloger/internal/cpegenerate/dictionary/index-generator/generate.go @@ -260,8 +260,8 @@ func addEntryForNPMPackage(indexed *dictionary.Indexed, ref string, cpeItemName } func phpExtensionPackageFromURLFragment(ref string) string { - if strings.HasPrefix(ref, "package/") { // package/HTML_QuickForm/download - ref = strings.TrimPrefix(ref, "package/") + if after, ok := strings.CutPrefix(ref, "package/"); ok { // package/HTML_QuickForm/download + ref = after components := strings.Split(ref, "/") if len(components) < 1 { diff --git a/syft/pkg/cataloger/internal/cpegenerate/dictionary/index-generator/nvd_api_client.go b/syft/pkg/cataloger/internal/cpegenerate/dictionary/index-generator/nvd_api_client.go index 0c8084efe..0859d31b1 100644 --- a/syft/pkg/cataloger/internal/cpegenerate/dictionary/index-generator/nvd_api_client.go +++ b/syft/pkg/cataloger/internal/cpegenerate/dictionary/index-generator/nvd_api_client.go @@ -206,7 +206,7 @@ func (c *NVDAPIClient) fetchDateRange(ctx context.Context, start, end time.Time) func (c *NVDAPIClient) fetchPage(ctx context.Context, startIndex int, start, end time.Time) (NVDProductsResponse, error) { var lastErr error - for attempt := 0; attempt < maxRetries; attempt++ { + for attempt := range maxRetries { // wait for rate limiter if err := c.rateLimiter.Wait(ctx); err != nil { return NVDProductsResponse{}, fmt.Errorf("rate limiter error: %w", err) diff --git a/syft/pkg/cataloger/internal/licenses/names_test.go b/syft/pkg/cataloger/internal/licenses/names_test.go index e8fa4ac12..855f0f06f 100644 --- a/syft/pkg/cataloger/internal/licenses/names_test.go +++ b/syft/pkg/cataloger/internal/licenses/names_test.go @@ -33,7 +33,6 @@ func Test_IsLicenseFile(t *testing.T) { } for _, tt := range tests { - tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() got := IsLicenseFile(tt.input) diff --git a/syft/pkg/cataloger/internal/pe/bundle.go b/syft/pkg/cataloger/internal/pe/bundle.go index 2fefc0acb..a360441d5 100644 --- a/syft/pkg/cataloger/internal/pe/bundle.go +++ b/syft/pkg/cataloger/internal/pe/bundle.go @@ -206,7 +206,7 @@ func readDepsJSONAtOffset(r io.ReadSeeker, offset, size int64) (string, error) { // findDepsJSONInManifest parses manifest entries to find deps.json (for V1 bundles or fallback) func findDepsJSONInManifest(r io.ReadSeeker, numFiles int32, majorVersion uint32) (string, error) { - for i := int32(0); i < numFiles; i++ { + for range numFiles { var offset, size int64 if err := binary.Read(r, binary.LittleEndian, &offset); err != nil { diff --git a/syft/pkg/cataloger/internal/pe/pe.go b/syft/pkg/cataloger/internal/pe/pe.go index d81923ffc..c389d55bd 100644 --- a/syft/pkg/cataloger/internal/pe/pe.go +++ b/syft/pkg/cataloger/internal/pe/pe.go @@ -422,7 +422,7 @@ func parseResourceDirectory(sec *extractedSection, dirs *u32set.Set, fields map[ return fmt.Errorf("invalid number of entries in resource directory: %d", numEntries) } - for i := 0; i < numEntries; i++ { + for i := range numEntries { var entry peImageResourceDirectoryEntry entryOffset := offset + int64(binary.Size(directoryHeader)) + int64(i*binary.Size(entry)) diff --git a/syft/pkg/cataloger/internal/pkgtest/metadata_tracker.go b/syft/pkg/cataloger/internal/pkgtest/metadata_tracker.go index 84921a129..bed764b35 100644 --- a/syft/pkg/cataloger/internal/pkgtest/metadata_tracker.go +++ b/syft/pkg/cataloger/internal/pkgtest/metadata_tracker.go @@ -7,6 +7,7 @@ import ( "os" "path/filepath" "reflect" + "slices" "sort" "sync" "time" @@ -322,7 +323,7 @@ func (t *MetadataTracker) RecordCatalogerObservations( // getMetadataTypeName returns the fully qualified type name of metadata (e.g., "pkg.ApkDBEntry"). // extracts just the last package path segment to keep names concise. -func getMetadataTypeName(metadata interface{}) string { +func getMetadataTypeName(metadata any) string { if metadata == nil { return "" } @@ -361,7 +362,7 @@ func lastPathSegment(path string) string { // hasIntegrityHash checks if metadata contains an integrity hash field. // note: this uses a best-effort approach checking common field names. // DO NOT depend on these values in auto-generated capabilities definitions - use for test validation only. -func hasIntegrityHash(metadata interface{}) bool { +func hasIntegrityHash(metadata any) bool { v := dereferenceToStruct(metadata) if !v.IsValid() || v.Kind() != reflect.Struct { return false @@ -378,7 +379,7 @@ func hasIntegrityHash(metadata interface{}) bool { // hasFileDigests checks if metadata contains file records with digests. // note: uses a best-effort approach for detection. // DO NOT depend on these values in auto-generated capabilities definitions - use for test validation only. -func hasFileDigests(metadata interface{}) bool { +func hasFileDigests(metadata any) bool { v := dereferenceToStruct(metadata) if !v.IsValid() || v.Kind() != reflect.Struct { return false @@ -400,7 +401,7 @@ func hasFileDigests(metadata interface{}) bool { // dereferenceToStruct handles pointer dereferencing and returns the underlying value. // returns an invalid value if the input is nil or not convertible to a struct. -func dereferenceToStruct(v interface{}) reflect.Value { +func dereferenceToStruct(v any) reflect.Value { if v == nil { return reflect.Value{} } @@ -460,12 +461,7 @@ func countDependencyRelationships(relationships []artifact.Relationship) int { // contains checks if a string slice contains a specific string. func contains(slice []string, item string) bool { - for _, s := range slice { - if s == item { - return true - } - } - return false + return slices.Contains(slice, item) } // ===== Result Writing ===== @@ -494,7 +490,7 @@ func (t *MetadataTracker) WriteResults() error { } // writeJSONFile writes data as pretty-printed JSON to the specified path. -func writeJSONFile(path string, data interface{}) error { +func writeJSONFile(path string, data any) error { file, err := os.Create(path) if err != nil { return err diff --git a/syft/pkg/cataloger/internal/pkgtest/observing_resolver.go b/syft/pkg/cataloger/internal/pkgtest/observing_resolver.go index 52eb6e478..8fca2ce58 100644 --- a/syft/pkg/cataloger/internal/pkgtest/observing_resolver.go +++ b/syft/pkg/cataloger/internal/pkgtest/observing_resolver.go @@ -6,6 +6,7 @@ import ( "context" "fmt" "io" + "slices" "sort" "github.com/scylladb/go-set/strset" @@ -43,10 +44,8 @@ func NewObservingResolver(resolver file.Resolver) *ObservingResolver { // ObservedPathQuery checks if a specific path pattern was queried. func (r *ObservingResolver) ObservedPathQuery(input string) bool { for _, queries := range r.pathQueries { - for _, query := range queries { - if query == input { - return true - } + if slices.Contains(queries, input) { + return true } } return false diff --git a/syft/pkg/cataloger/internal/pkgtest/test_generic_parser.go b/syft/pkg/cataloger/internal/pkgtest/test_generic_parser.go index c66f6a1d2..e74a3a06e 100644 --- a/syft/pkg/cataloger/internal/pkgtest/test_generic_parser.go +++ b/syft/pkg/cataloger/internal/pkgtest/test_generic_parser.go @@ -498,7 +498,7 @@ func stringPackage(p pkg.Package) string { } // getFunctionName extracts the function name from a function pointer using reflection -func getFunctionName(fn interface{}) string { +func getFunctionName(fn any) string { // get the function pointer ptr := reflect.ValueOf(fn).Pointer() @@ -532,7 +532,7 @@ func getCatalogerName(_ *testing.T, cataloger pkg.Cataloger) string { // getPackagePath extracts the package path from a function name // e.g., "github.com/anchore/syft/syft/pkg/cataloger/python.parseRequirementsTxt" -> "python" -func getPackagePath(fn interface{}) string { +func getPackagePath(fn any) string { ptr := reflect.ValueOf(fn).Pointer() funcForPC := runtime.FuncForPC(ptr) if funcForPC == nil { @@ -566,7 +566,7 @@ func getPackagePath(fn interface{}) string { func getPackagePathFromCataloger(_ pkg.Cataloger) string { // walk up the call stack to find the test file // we're looking for a file in the cataloger directory structure - for i := 0; i < 10; i++ { + for i := range 10 { _, file, _, ok := runtime.Caller(i) if !ok { break diff --git a/syft/pkg/cataloger/java/archive_parser_test.go b/syft/pkg/cataloger/java/archive_parser_test.go index 6afa74528..5ff522eaa 100644 --- a/syft/pkg/cataloger/java/archive_parser_test.go +++ b/syft/pkg/cataloger/java/archive_parser_test.go @@ -395,7 +395,6 @@ func TestParseJar(t *testing.T) { var parent *pkg.Package for _, a := range actual { - a := a if strings.Contains(a.Name, "example-") { parent = &a } @@ -682,7 +681,6 @@ func TestParseNestedJar(t *testing.T) { actualNameVersionPairSet := strset.New() for _, a := range actual { - a := a key := makeKey(&a) actualNameVersionPairSet.Add(key) if !expectedNameVersionPairSet.Has(key) { @@ -701,7 +699,6 @@ func TestParseNestedJar(t *testing.T) { } for _, a := range actual { - a := a actualKey := makeKey(&a) metadata := a.Metadata.(pkg.JavaArchive) @@ -1493,7 +1490,7 @@ func Test_deterministicMatchingPomProperties(t *testing.T) { t.Run(test.fixture, func(t *testing.T) { fixturePath := generateJavaMetadataJarFixture(t, test.fixture, "jar") - for i := 0; i < 5; i++ { + for range 5 { func() { fixture, err := os.Open(fixturePath) require.NoError(t, err) diff --git a/syft/pkg/cataloger/java/parse_java_manifest.go b/syft/pkg/cataloger/java/parse_java_manifest.go index 1d06c5d62..cb7945eca 100644 --- a/syft/pkg/cataloger/java/parse_java_manifest.go +++ b/syft/pkg/cataloger/java/parse_java_manifest.go @@ -58,14 +58,14 @@ func parseJavaManifest(path string, reader io.Reader) (*pkg.JavaManifest, error) } // this is a new key-value pair - idx := strings.Index(line, ":") - if idx == -1 { + before, after, ok := strings.Cut(line, ":") + if !ok { log.Debugf("java manifest %q: unable to split java manifest key-value pairs: %q", path, line) continue } - key := strings.TrimSpace(line[0:idx]) - value := strings.TrimSpace(line[idx+1:]) + key := strings.TrimSpace(before) + value := strings.TrimSpace(after) if key == "" { // don't attempt to add new keys or sections unless there is a non-empty key diff --git a/syft/pkg/cataloger/java/parse_pom_xml_test.go b/syft/pkg/cataloger/java/parse_pom_xml_test.go index 8a622b086..44dc5da05 100644 --- a/syft/pkg/cataloger/java/parse_pom_xml_test.go +++ b/syft/pkg/cataloger/java/parse_pom_xml_test.go @@ -446,7 +446,7 @@ func Test_resolveLicenses(t *testing.T) { require.Equal(t, "child-one", child1.Name) got := child1.Licenses.ToSlice() - for i := 0; i < len(got); i++ { + for i := range got { // ignore locations, just check license text (&got[i]).Locations = file.LocationSet{} } @@ -810,7 +810,7 @@ func expectedTransientPackageData() expected { } pkgs := make([]pkg.Package, len(allPackages)) - for i := 0; i < len(allPackages); i++ { + for i := range allPackages { pkgs[i] = *allPackages[i] } diff --git a/syft/pkg/cataloger/javascript/parse_package_json.go b/syft/pkg/cataloger/javascript/parse_package_json.go index 926f765c5..582791dd3 100644 --- a/syft/pkg/cataloger/javascript/parse_package_json.go +++ b/syft/pkg/cataloger/javascript/parse_package_json.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "regexp" + "slices" "strings" "github.com/go-viper/mapstructure/v2" @@ -95,7 +96,7 @@ func (p *person) UnmarshalJSON(b []byte) error { } } else { // it's a map that may contain fields of various data types (not just strings) - var fields map[string]interface{} + var fields map[string]any if err := json.Unmarshal(b, &fields); err != nil { return fmt.Errorf("unable to parse package.json author: %w", err) } @@ -210,12 +211,7 @@ func licensesFromJSON(b []byte) ([]npmPackageLicense, error) { var filepathSeparator = regexp.MustCompile(`[\\/]`) func pathContainsNodeModulesDirectory(p string) bool { - for _, subPath := range filepathSeparator.Split(p, -1) { - if subPath == "node_modules" { - return true - } - } - return false + return slices.Contains(filepathSeparator.Split(p, -1), "node_modules") } func (p *people) UnmarshalJSON(b []byte) error { @@ -242,7 +238,7 @@ func (p *people) UnmarshalJSON(b []byte) error { } // Try to unmarshal as an array of objects - var authorObjs []map[string]interface{} + var authorObjs []map[string]any if err := json.Unmarshal(b, &authorObjs); err == nil { // Successfully parsed as an array of objects auths := make([]person, len(authorObjs)) diff --git a/syft/pkg/cataloger/javascript/parse_pnpm_lock.go b/syft/pkg/cataloger/javascript/parse_pnpm_lock.go index 29001b9a6..ddba32244 100644 --- a/syft/pkg/cataloger/javascript/parse_pnpm_lock.go +++ b/syft/pkg/cataloger/javascript/parse_pnpm_lock.go @@ -41,7 +41,7 @@ type pnpmV6PackageEntry struct { // pnpmV6LockYaml represents the structure of pnpm lockfiles for versions < 9.0. type pnpmV6LockYaml struct { - Dependencies map[string]interface{} `yaml:"dependencies"` + Dependencies map[string]any `yaml:"dependencies"` Packages map[string]pnpmV6PackageEntry `yaml:"packages"` } @@ -61,7 +61,7 @@ type pnpmV9PackageEntry struct { // pnpmV9LockYaml represents the structure of pnpm lockfiles for versions >= 9.0. type pnpmV9LockYaml struct { LockfileVersion string `yaml:"lockfileVersion"` - Importers map[string]interface{} `yaml:"importers"` // Using interface{} for forward compatibility + Importers map[string]any `yaml:"importers"` // Using interface{} for forward compatibility Packages map[string]pnpmV9PackageEntry `yaml:"packages"` Snapshots map[string]pnpmV9SnapshotEntry `yaml:"snapshots"` } @@ -214,11 +214,11 @@ func (a genericPnpmLockAdapter) parsePnpmLock(ctx context.Context, resolver file } // parseVersionField extracts the version string from a dependency entry. -func parseVersionField(name string, info interface{}) (string, error) { +func parseVersionField(name string, info any) (string, error) { switch v := info.(type) { case string: return v, nil - case map[string]interface{}: + case map[string]any: if ver, ok := v["version"].(string); ok { // e.g., "1.2.3(react@17.0.0)" -> "1.2.3" return strings.SplitN(ver, "(", 2)[0], nil diff --git a/syft/pkg/cataloger/lua/rockspec_parser.go b/syft/pkg/cataloger/lua/rockspec_parser.go index 067ce4c44..89c730923 100644 --- a/syft/pkg/cataloger/lua/rockspec_parser.go +++ b/syft/pkg/cataloger/lua/rockspec_parser.go @@ -14,7 +14,7 @@ type rockspec struct { type rockspecNode struct { key string - value interface{} + value any } func (r rockspecNode) Slice() []rockspecNode { diff --git a/syft/pkg/cataloger/python/package.go b/syft/pkg/cataloger/python/package.go index 506584fca..2932d9d4e 100644 --- a/syft/pkg/cataloger/python/package.go +++ b/syft/pkg/cataloger/python/package.go @@ -37,7 +37,7 @@ func newPackageForIndex(ctx context.Context, lr pythonLicenseResolver, name, ver return p } -func newPackageForIndexWithMetadata(ctx context.Context, lr pythonLicenseResolver, name, version string, metadata interface{}, locations ...file.Location) pkg.Package { +func newPackageForIndexWithMetadata(ctx context.Context, lr pythonLicenseResolver, name, version string, metadata any, locations ...file.Location) pkg.Package { name = normalize(name) licenseSet := lr.getLicenses(ctx, name, version) diff --git a/syft/pkg/cataloger/python/parse_requirements.go b/syft/pkg/cataloger/python/parse_requirements.go index 21c69cc74..b35940abc 100644 --- a/syft/pkg/cataloger/python/parse_requirements.go +++ b/syft/pkg/cataloger/python/parse_requirements.go @@ -111,9 +111,9 @@ func (rp requirementsParser) parseRequirementsTxt(ctx context.Context, _ file.Re } // remove line continuations... smashes the file into a single line - if strings.HasSuffix(line, "\\") { + if before, ok := strings.CutSuffix(line, "\\"); ok { // this line is a continuation of the previous line - lastLine += strings.TrimSuffix(line, "\\") + lastLine += before continue } @@ -255,12 +255,12 @@ func removeTrailingComment(line string) string { } func removeExtras(packageName string) string { - start := strings.Index(packageName, "[") - if start == -1 { + before, _, ok := strings.Cut(packageName, "[") + if !ok { return packageName } - return strings.TrimSpace(packageName[:start]) + return strings.TrimSpace(before) } func parseExtras(packageName string) []string { diff --git a/syft/pkg/cataloger/ruby/parse_gemspec.go b/syft/pkg/cataloger/ruby/parse_gemspec.go index 16f0f7d4b..b14cee704 100644 --- a/syft/pkg/cataloger/ruby/parse_gemspec.go +++ b/syft/pkg/cataloger/ruby/parse_gemspec.go @@ -68,7 +68,7 @@ func processList(s string) []string { // parseGemSpecEntries parses the gemspec file and returns the packages and relationships found. func parseGemSpecEntries(ctx context.Context, resolver file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { var pkgs []pkg.Package - var fields = make(map[string]interface{}) + var fields = make(map[string]any) scanner := bufio.NewScanner(reader) for scanner.Scan() { diff --git a/syft/pkg/cataloger/swift/parse_package_resolved.go b/syft/pkg/cataloger/swift/parse_package_resolved.go index 68211b72d..594beb12d 100644 --- a/syft/pkg/cataloger/swift/parse_package_resolved.go +++ b/syft/pkg/cataloger/swift/parse_package_resolved.go @@ -61,7 +61,7 @@ type packageState struct { // parsePackageResolved is a parser for the contents of a Package.resolved file, which is generated by Xcode after it's resolved Swift Package Manger packages. func parsePackageResolved(_ context.Context, _ file.Resolver, _ *generic.Environment, reader file.LocationReadCloser) ([]pkg.Package, []artifact.Relationship, error) { dec := json.NewDecoder(reader) - var packageResolvedData map[string]interface{} + var packageResolvedData map[string]any for { if err := dec.Decode(&packageResolvedData); errors.Is(err, io.EOF) { break @@ -101,7 +101,7 @@ func parsePackageResolved(_ context.Context, _ file.Resolver, _ *generic.Environ return pkgs, nil, unknown.IfEmptyf(pkgs, "unable to determine packages") } -func pinsForVersion(data map[string]interface{}, version float64) ([]packagePin, error) { +func pinsForVersion(data map[string]any, version float64) ([]packagePin, error) { var genericPins []packagePin switch version { case 1: diff --git a/syft/pkg/cataloger/swift/parse_podfile_lock.go b/syft/pkg/cataloger/swift/parse_podfile_lock.go index fb39c13e6..d8d094186 100644 --- a/syft/pkg/cataloger/swift/parse_podfile_lock.go +++ b/syft/pkg/cataloger/swift/parse_podfile_lock.go @@ -17,7 +17,7 @@ import ( var _ generic.Parser = parsePodfileLock type podfileLock struct { - Pods []interface{} `yaml:"PODS"` + Pods []any `yaml:"PODS"` Dependencies []string `yaml:"DEPENDENCIES"` SpecRepos map[string][]string `yaml:"SPEC REPOS"` SpecChecksums map[string]string `yaml:"SPEC CHECKSUMS"` @@ -36,7 +36,7 @@ func parsePodfileLock(_ context.Context, _ file.Resolver, _ *generic.Environment for _, podInterface := range podfile.Pods { var podBlob string switch v := podInterface.(type) { - case map[string]interface{}: + case map[string]any: for k := range v { podBlob = k } diff --git a/syft/pkg/cataloger/wordpress/parse_plugin.go b/syft/pkg/cataloger/wordpress/parse_plugin.go index 17832cade..4956dc6f8 100644 --- a/syft/pkg/cataloger/wordpress/parse_plugin.go +++ b/syft/pkg/cataloger/wordpress/parse_plugin.go @@ -94,7 +94,7 @@ func parseWordpressPluginFiles(ctx context.Context, resolver file.Resolver, _ *g } func extractFields(in string) map[string]any { - var fields = make(map[string]interface{}) + var fields = make(map[string]any) for field, pattern := range patterns { matchMap := internal.MatchNamedCaptureGroups(pattern, in) diff --git a/syft/pkg/gguf.go b/syft/pkg/gguf.go index 512c8873c..867dc4367 100644 --- a/syft/pkg/gguf.go +++ b/syft/pkg/gguf.go @@ -26,7 +26,7 @@ type GGUFFileHeader struct { // RemainingKeyValues contains the remaining key-value pairs from the GGUF header that are not already // represented as typed fields above. This preserves additional metadata fields for reference // (namespaced with general.*, llama.*, etc.) while avoiding duplication. - RemainingKeyValues map[string]interface{} `json:"header,omitempty" cyclonedx:"header"` + RemainingKeyValues map[string]any `json:"header,omitempty" cyclonedx:"header"` // MetadataKeyValuesHash is a xx64 hash of all key-value pairs from the GGUF header metadata. // This hash is computed over the complete header metadata (including the fields extracted diff --git a/syft/pkg/package.go b/syft/pkg/package.go index 546c91f5c..28452c070 100644 --- a/syft/pkg/package.go +++ b/syft/pkg/package.go @@ -105,17 +105,13 @@ func IsValid(p *Package) bool { return p != nil && p.Name != "" } -//nolint:gocognit func Less(i, j Package) bool { if i.Name == j.Name { if i.Version == j.Version { iLocations := i.Locations.ToSlice() jLocations := j.Locations.ToSlice() if i.Type == j.Type { - maxLen := len(iLocations) - if len(jLocations) > maxLen { - maxLen = len(jLocations) - } + maxLen := max(len(jLocations), len(iLocations)) for l := 0; l < maxLen; l++ { if len(iLocations) < l+1 || len(jLocations) < l+1 { if len(iLocations) == len(jLocations) { diff --git a/syft/sbom/sbom.go b/syft/sbom/sbom.go index 1c8cbc60f..58e56fc0c 100644 --- a/syft/sbom/sbom.go +++ b/syft/sbom/sbom.go @@ -33,7 +33,7 @@ type Artifacts struct { type Descriptor struct { Name string Version string - Configuration interface{} + Configuration any } // RelationshipsSorted returns a sorted slice of all relationships diff --git a/syft/source/description.go b/syft/source/description.go index 04bb983fc..155776e46 100644 --- a/syft/source/description.go +++ b/syft/source/description.go @@ -6,5 +6,5 @@ type Description struct { Name string `hash:"ignore"` Version string `hash:"ignore"` Supplier string `hash:"ignore"` - Metadata interface{} + Metadata any } diff --git a/syft/source/snapsource/snap_source_test.go b/syft/source/snapsource/snap_source_test.go index f74f59e57..99e8da7dc 100644 --- a/syft/source/snapsource/snap_source_test.go +++ b/syft/source/snapsource/snap_source_test.go @@ -57,7 +57,7 @@ func TestNewFromLocal(t *testing.T) { setup: func(fs afero.Fs) { require.NoError(t, createMockSquashfsFile(fs, "/test/local.snap")) }, - wantErr: func(t assert.TestingT, err error, msgAndArgs ...interface{}) bool { + wantErr: func(t assert.TestingT, err error, msgAndArgs ...any) bool { return assert.Error(t, err, msgAndArgs...) && assert.Contains(t, err.Error(), "architecture cannot be specified for local snap files", msgAndArgs...) }, wantRequest: "/test/local.snap", diff --git a/syft/source/snapsource/snapcraft_api_test.go b/syft/source/snapsource/snapcraft_api_test.go index a9473a88c..032825a59 100644 --- a/syft/source/snapsource/snapcraft_api_test.go +++ b/syft/source/snapsource/snapcraft_api_test.go @@ -609,7 +609,7 @@ func TestSnapcraftClient_GetSnapDownloadURL_DoesntExist(t *testing.T) { }, }, expectedURL: "https://api.snapcraft.io/api/v1/snaps/download/TKebVGcPeDKoOqAmNmczU2oWLtsojKD5_249.snap", - expectError: func(t require.TestingT, err error, msgAndArgs ...interface{}) { + expectError: func(t require.TestingT, err error, msgAndArgs ...any) { require.EqualError(t, err, "no matching snap found for etcd:248") }, }, diff --git a/test/cli/trait_assertions_test.go b/test/cli/trait_assertions_test.go index a0c17096c..6f54d6c8e 100644 --- a/test/cli/trait_assertions_test.go +++ b/test/cli/trait_assertions_test.go @@ -35,7 +35,7 @@ func assertFileOutput(tb testing.TB, path string, assertions ...traitAssertion) func assertJsonReport(tb testing.TB, stdout, _ string, _ int) { tb.Helper() - var data interface{} + var data any if err := json.Unmarshal([]byte(stdout), &data); err != nil { tb.Errorf("expected to find a JSON report, but was unmarshalable: %+v", err)