diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a787e8ec1f..9e5297d1a2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -168,9 +168,9 @@ jobs: run: sudo apt install -y libgpgme-dev libbtrfs-dev libdevmapper-dev - name: Run golangci-lint - uses: golangci/golangci-lint-action@v6 + uses: golangci/golangci-lint-action@v8 with: - version: v1.61.0 + version: v2.3 args: --verbose --timeout 5m0s shellcheck: diff --git a/.golangci.yml b/.golangci.yml index 2df885f419..d644d7fd08 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,29 +1,68 @@ --- -linters-settings: - govet: - disable: - - shadow # default value recommended by golangci - - composites - gosec: - excludes: - - G101 +version: "2" +run: + build-tags: + - integration linters: enable: - gosec - -run: - build-tags: - - integration - timeout: 5m + - gomoddirectives + - staticcheck + settings: + gosec: + excludes: + - G101 + govet: + disable: + # default value recommended by golangci + - shadow + - composites + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling + rules: + - linters: + - gosec + path: ^(images/)?(pkg|internal)/.*_test\.go$ + # unnecessary field selector + - linters: + - staticcheck + text: "QF1008" + # error strings should not be capitalized + - linters: + - staticcheck + text: "ST1005" + # unicode control character + - linters: + - staticcheck + path: ^(images/)?(pkg|internal)/.*_test\.go$ + text: "ST1018" + # possible nil pointer dereference (many false alerts when t.Skip is used) + - linters: + - staticcheck + path: ^(images/)?(pkg|internal|internal/test)/(.*_test|helpers)\.go$ + text: "SA5011" + paths: + - third_party$ + - builtin$ + - examples$ issues: # Maximum issues count per one linter. Set to 0 to disable. Default is 50. max-issues-per-linter: 0 - # Maximum count of issues with the same text. Set to 0 to disable. Default # is 3. max-same-issues: 0 - exclude-rules: - - path: ^(images/)?(pkg|internal)/.*_test\.go$ - linters: ["gosec"] + +formatters: + exclusions: + generated: lax + paths: + - third_party$ + - builtin$ + - examples$ diff --git a/cmd/build/main.go b/cmd/build/main.go index 401378a112..b951667e2c 100644 --- a/cmd/build/main.go +++ b/cmd/build/main.go @@ -22,7 +22,7 @@ import ( ) func u(s string) string { - return strings.Replace(s, "-", "_", -1) + return strings.ReplaceAll(s, "-", "_") } func run() error { diff --git a/cmd/gen-manifests/main.go b/cmd/gen-manifests/main.go index 37497b9693..3fca750ab0 100644 --- a/cmd/gen-manifests/main.go +++ b/cmd/gen-manifests/main.go @@ -375,7 +375,7 @@ func filterRepos(repos []rpmmd.RepoConfig, typeName string) []rpmmd.RepoConfig { } func u(s string) string { - return strings.Replace(s, "-", "_", -1) + return strings.ReplaceAll(s, "-", "_") } func main() { diff --git a/cmd/otk/osbuild-make-partition-stages/main_test.go b/cmd/otk/osbuild-make-partition-stages/main_test.go index 12aabf3a60..a92526f0e8 100644 --- a/cmd/otk/osbuild-make-partition-stages/main_test.go +++ b/cmd/otk/osbuild-make-partition-stages/main_test.go @@ -113,7 +113,7 @@ func TestIntegration(t *testing.T) { func TestModificationFname(t *testing.T) { input := minimalInputBase input.Tree.Const.Filename = "mydisk.img2" - expectedStages := strings.Replace(minimalExpectedStages, `"disk.img"`, `"mydisk.img2"`, -1) + expectedStages := strings.ReplaceAll(minimalExpectedStages, `"disk.img"`, `"mydisk.img2"`) inpJSON, err := json.Marshal(&input) assert.NoError(t, err) diff --git a/internal/assertx/testify_extensions.go b/internal/assertx/testify_extensions.go index 8a85644c04..aa0874bb4c 100644 --- a/internal/assertx/testify_extensions.go +++ b/internal/assertx/testify_extensions.go @@ -10,9 +10,7 @@ import ( // needed until https://github.com/stretchr/testify/issues/1304 is fixed func PanicsWithErrorRegexp(t assert.TestingT, reg *regexp.Regexp, f assert.PanicTestFunc) (assertOk bool) { defer func() { - var message interface{} // nolint: gosimple - - message = recover() + message := recover() if message == nil { return } diff --git a/internal/common/pointers_test.go b/internal/common/pointers_test.go index 43c6d7073c..920f251fd5 100644 --- a/internal/common/pointers_test.go +++ b/internal/common/pointers_test.go @@ -7,19 +7,19 @@ import ( ) func TestToPtr(t *testing.T) { - var valueInt int = 42 + valueInt := 42 gotInt := ToPtr(valueInt) assert.Equal(t, valueInt, *gotInt) - var valueBool bool = true + valueBool := true gotBool := ToPtr(valueBool) assert.Equal(t, valueBool, *gotBool) - var valueUint64 uint64 = 1 + valueUint64 := uint64(1) gotUint64 := ToPtr(valueUint64) assert.Equal(t, valueUint64, *gotUint64) - var valueStr string = "the-greatest-test-value" + valueStr := "the-greatest-test-value" gotStr := ToPtr(valueStr) assert.Equal(t, valueStr, *gotStr) diff --git a/internal/testregistry/testregistry.go b/internal/testregistry/testregistry.go index b8205a2798..f01f3aa390 100644 --- a/internal/testregistry/testregistry.go +++ b/internal/testregistry/testregistry.go @@ -290,11 +290,12 @@ func (reg *Registry) ServeHTTP(w http.ResponseWriter, req *http.Request) { return } - if cmd == "manifests" { + switch cmd { + case "manifests": repo.ServeManifest(ref, w, req) - } else if cmd == "blobs" { + case "blobs": repo.ServeBlob(ref, w, req) - } else { + default: http.NotFound(w, req) } } diff --git a/pkg/distro/defs/loader.go b/pkg/distro/defs/loader.go index 7c733a670f..9e3e594056 100644 --- a/pkg/distro/defs/loader.go +++ b/pkg/distro/defs/loader.go @@ -42,7 +42,7 @@ var defaultDataFS fs.FS = distrodefs.Data func dataFS() fs.FS { // XXX: this is a short term measure, pass a set of // searchPaths down the stack instead - var dataFS fs.FS = defaultDataFS + dataFS := defaultDataFS if overrideDir := experimentalflags.String("yamldir"); overrideDir != "" { olog.Printf("WARNING: using experimental override dir %q", overrideDir) dataFS = os.DirFS(overrideDir) diff --git a/pkg/distro/generic/fedora_test.go b/pkg/distro/generic/fedora_test.go index 217db2cfe0..d2be429f6b 100644 --- a/pkg/distro/generic/fedora_test.go +++ b/pkg/distro/generic/fedora_test.go @@ -507,17 +507,18 @@ func TestFedoraDistro_ManifestError(t *testing.T) { Size: imgType.Size(0), } _, _, err := imgType.Manifest(&bp, imgOpts, nil, nil) - if imgTypeName == "iot-commit" || imgTypeName == "iot-container" || imgTypeName == "iot-bootable-container" { + switch imgTypeName { + case "iot-commit", "iot-container", "iot-bootable-container": assert.EqualError(t, err, "kernel boot parameter customizations are not supported for ostree types") - } else if imgTypeName == "iot-installer" || imgTypeName == "iot-simplified-installer" { + case "iot-installer", "iot-simplified-installer": assert.EqualError(t, err, fmt.Sprintf("boot ISO image type \"%s\" requires specifying a URL from which to retrieve the OSTree commit", imgTypeName)) - } else if imgTypeName == "minimal-installer" { + case "minimal-installer": assert.EqualError(t, err, fmt.Sprintf(distro.UnsupportedCustomizationError, imgTypeName, "User, Group, FIPS, Installer, Timezone, Locale")) - } else if imgTypeName == "workstation-live-installer" { + case "workstation-live-installer": assert.EqualError(t, err, fmt.Sprintf(distro.NoCustomizationsAllowedError, imgTypeName)) - } else if imgTypeName == "iot-raw-xz" || imgTypeName == "iot-qcow2" { + case "iot-raw-xz", "iot-qcow2": assert.EqualError(t, err, fmt.Sprintf(distro.UnsupportedCustomizationError, imgTypeName, "User, Group, Directories, Files, Services, FIPS")) - } else { + default: assert.NoError(t, err) } }) diff --git a/pkg/distro/generic/options.go b/pkg/distro/generic/options.go index 6863bd4633..1c63afbf65 100644 --- a/pkg/distro/generic/options.go +++ b/pkg/distro/generic/options.go @@ -188,7 +188,7 @@ func checkOptionsRhel9(t *imageType, bp *blueprint.Blueprint, options distro.Ima } if (mountpoints != nil || partitioning != nil) && t.RPMOSTree && (t.Name() == "edge-container" || t.Name() == "edge-commit") { return warnings, fmt.Errorf("custom mountpoints and partitioning are not supported for ostree types") - } else if (mountpoints != nil || partitioning != nil) && t.RPMOSTree && !(t.Name() == "edge-container" || t.Name() == "edge-commit") { + } else if (mountpoints != nil || partitioning != nil) && t.RPMOSTree && (t.Name() != "edge-container" && t.Name() != "edge-commit") { //customization allowed for edge-raw-image,edge-ami,edge-vsphere,edge-simplified-installer err := blueprint.CheckMountpointsPolicy(mountpoints, policies.OstreeMountpointPolicies) if err != nil { diff --git a/pkg/distro/generic/rhel8_test.go b/pkg/distro/generic/rhel8_test.go index 71fec318a2..711c61b45b 100644 --- a/pkg/distro/generic/rhel8_test.go +++ b/pkg/distro/generic/rhel8_test.go @@ -481,13 +481,14 @@ func TestRH8_Distro_ManifestError(t *testing.T) { Size: imgType.Size(0), } _, _, err := imgType.Manifest(&bp, imgOpts, nil, nil) - if imgTypeName == "edge-commit" || imgTypeName == "edge-container" { + switch imgTypeName { + case "edge-commit", "edge-container": assert.EqualError(t, err, "kernel boot parameter customizations are not supported for ostree types") - } else if imgTypeName == "edge-raw-image" { + case "edge-raw-image": assert.EqualError(t, err, fmt.Sprintf("%q images require specifying a URL from which to retrieve the OSTree commit", imgTypeName)) - } else if imgTypeName == "edge-installer" || imgTypeName == "edge-simplified-installer" { + case "edge-installer", "edge-simplified-installer": assert.EqualError(t, err, fmt.Sprintf("boot ISO image type %q requires specifying a URL from which to retrieve the OSTree commit", imgTypeName)) - } else { + default: assert.NoError(t, err) } } diff --git a/pkg/distro/generic/rhel9_test.go b/pkg/distro/generic/rhel9_test.go index b1d0ef88fe..2ea642242b 100644 --- a/pkg/distro/generic/rhel9_test.go +++ b/pkg/distro/generic/rhel9_test.go @@ -480,15 +480,16 @@ func TestRhel9_Distro_ManifestError(t *testing.T) { Size: imgType.Size(0), } _, _, err := imgType.Manifest(&bp, imgOpts, nil, nil) - if imgTypeName == "edge-commit" || imgTypeName == "edge-container" { + switch imgTypeName { + case "edge-commit", "edge-container": assert.EqualError(t, err, "kernel boot parameter customizations are not supported for ostree types") - } else if imgTypeName == "edge-raw-image" || imgTypeName == "edge-ami" || imgTypeName == "edge-vsphere" { + case "edge-raw-image", "edge-ami", "edge-vsphere": assert.EqualError(t, err, fmt.Sprintf("\"%s\" images require specifying a URL from which to retrieve the OSTree commit", imgTypeName)) - } else if imgTypeName == "edge-installer" || imgTypeName == "edge-simplified-installer" { + case "edge-installer", "edge-simplified-installer": assert.EqualError(t, err, fmt.Sprintf("boot ISO image type \"%s\" requires specifying a URL from which to retrieve the OSTree commit", imgTypeName)) - } else if imgTypeName == "azure-cvm" { + case "azure-cvm": assert.EqualError(t, err, fmt.Sprintf("kernel customizations are not supported for %q", imgTypeName)) - } else { + default: assert.NoError(t, err) } } diff --git a/pkg/dnfjson/dnfjson.go b/pkg/dnfjson/dnfjson.go index 6daead5097..6cb8437622 100644 --- a/pkg/dnfjson/dnfjson.go +++ b/pkg/dnfjson/dnfjson.go @@ -693,7 +693,7 @@ func (r *Request) Hash() string { for _, repo := range r.Arguments.Repos { h.Write([]byte(repo.Hash())) } - h.Write([]byte(fmt.Sprintf("%T", r.Arguments.Search.Latest))) + fmt.Fprintf(h, "%T", r.Arguments.Search.Latest) h.Write([]byte(strings.Join(r.Arguments.Search.Packages, ""))) return fmt.Sprintf("%x", h.Sum(nil)) @@ -849,7 +849,7 @@ func parseError(data []byte, repos []repoConfig) Error { if len(repo.Name) > 0 { nameURL = fmt.Sprintf("%s: %s", repo.Name, nameURL) } - e.Reason = strings.Replace(e.Reason, idstr, fmt.Sprintf("%s [%s]", idstr, nameURL), -1) + e.Reason = strings.ReplaceAll(e.Reason, idstr, fmt.Sprintf("%s [%s]", idstr, nameURL)) } return e diff --git a/pkg/manifest/anaconda_installer_iso_tree.go b/pkg/manifest/anaconda_installer_iso_tree.go index f2480a79c4..84f0bd2153 100644 --- a/pkg/manifest/anaconda_installer_iso_tree.go +++ b/pkg/manifest/anaconda_installer_iso_tree.go @@ -434,7 +434,8 @@ func (p *AnacondaInstallerISOTree) serialize() osbuild.Pipeline { default: } - if p.ISOBoot == SyslinuxISOBoot { + switch p.ISOBoot { + case SyslinuxISOBoot: options := &osbuild.ISOLinuxStageOptions{ Product: osbuild.ISOLinuxProduct{ Name: p.anacondaPipeline.product, @@ -449,14 +450,13 @@ func (p *AnacondaInstallerISOTree) serialize() osbuild.Pipeline { stage := osbuild.NewISOLinuxStage(options, p.anacondaPipeline.Name()) pipeline.AddStage(stage) - } else if p.ISOBoot == Grub2ISOBoot { + case Grub2ISOBoot: var grub2config *osbuild.Grub2Config if p.anacondaPipeline.InstallerCustomizations.DefaultMenu > 0 { grub2config = &osbuild.Grub2Config{ Default: p.anacondaPipeline.InstallerCustomizations.DefaultMenu, } } - options := &osbuild.Grub2ISOLegacyStageOptions{ Product: osbuild.Product{ Name: p.anacondaPipeline.product, diff --git a/pkg/manifest/iso.go b/pkg/manifest/iso.go index af7c1da065..ca0b1212fc 100644 --- a/pkg/manifest/iso.go +++ b/pkg/manifest/iso.go @@ -60,14 +60,15 @@ func xorrisofsStageOptions(filename, isolabel string, isoboot ISOBootType) *osbu ISOLevel: 3, } - if isoboot == SyslinuxISOBoot { + switch isoboot { + case SyslinuxISOBoot: // Syslinux BIOS ISO creation options.Boot = &osbuild.XorrisofsBoot{ Image: "isolinux/isolinux.bin", Catalog: "isolinux/boot.cat", } options.IsohybridMBR = "/usr/share/syslinux/isohdpfx.bin" - } else if isoboot == Grub2ISOBoot { + case Grub2ISOBoot: // grub2 BIOS ISO creation options.Boot = &osbuild.XorrisofsBoot{ Image: "images/eltorito.img", diff --git a/pkg/osbuild/curl_source.go b/pkg/osbuild/curl_source.go index 0334e8c0c3..c98398ca86 100644 --- a/pkg/osbuild/curl_source.go +++ b/pkg/osbuild/curl_source.go @@ -37,11 +37,12 @@ func NewCurlPackageItem(pkg rpmmd.PackageSpec) (CurlSourceItem, error) { } item := new(CurlSourceOptions) item.URL = pkg.RemoteLocation - if pkg.Secrets == "org.osbuild.rhsm" { + switch pkg.Secrets { + case "org.osbuild.rhsm": item.Secrets = &URLSecrets{ Name: "org.osbuild.rhsm", } - } else if pkg.Secrets == "org.osbuild.mtls" { + case "org.osbuild.mtls": item.Secrets = &URLSecrets{ Name: "org.osbuild.mtls", } diff --git a/pkg/osbuild/disk.go b/pkg/osbuild/disk.go index da66fc7175..88756c2ef8 100644 --- a/pkg/osbuild/disk.go +++ b/pkg/osbuild/disk.go @@ -85,15 +85,16 @@ func GenImagePrepareStages(pt *disk.PartitionTable, filename string, partTool Pa }, ) - if partTool == PTSfdisk { + switch partTool { + case PTSfdisk: sfOptions := sfdiskStageOptions(pt) sfdisk := NewSfdiskStage(sfOptions, loopback) stages = append(stages, sfdisk) - } else if partTool == PTSgdisk { + case PTSgdisk: sgOptions := sgdiskStageOptions(pt) sgdisk := NewSgdiskStage(sgOptions, loopback) stages = append(stages, sgdisk) - } else { + default: panic("programming error: unknown PartTool: " + partTool) } diff --git a/pkg/osbuild/librepo_source.go b/pkg/osbuild/librepo_source.go index e2eac05a15..2028956b5c 100644 --- a/pkg/osbuild/librepo_source.go +++ b/pkg/osbuild/librepo_source.go @@ -47,11 +47,12 @@ func (source *LibrepoSource) AddPackage(pkg rpmmd.PackageSpec, repos []rpmmd.Rep if mirror.Insecure && !pkg.IgnoreSSL { return fmt.Errorf("inconsistent SSL configuration: package %v requires SSL but mirror %v is configured to ignore SSL", pkg.Name, mirror.URL) } - if pkg.Secrets == "org.osbuild.rhsm" { + switch pkg.Secrets { + case "org.osbuild.rhsm": mirror.Secrets = &URLSecrets{ Name: "org.osbuild.rhsm", } - } else if pkg.Secrets == "org.osbuild.mtls" { + case "org.osbuild.mtls": mirror.Secrets = &URLSecrets{ Name: "org.osbuild.mtls", } diff --git a/pkg/osbuild/mkfs_fat_stage.go b/pkg/osbuild/mkfs_fat_stage.go index 5e28694aec..3fd084eedc 100644 --- a/pkg/osbuild/mkfs_fat_stage.go +++ b/pkg/osbuild/mkfs_fat_stage.go @@ -31,5 +31,5 @@ func isFATVolID(id string) bool { // when generating the mkfs stage in mkfs_stage.go. This check removes all // dashes to determine if the given id is a valid vfat volid. volidre := regexp.MustCompile(fatVolIDRegex) - return volidre.MatchString(strings.Replace(id, "-", "", -1)) + return volidre.MatchString(strings.ReplaceAll(id, "-", "")) } diff --git a/pkg/osbuild/mkfs_stage.go b/pkg/osbuild/mkfs_stage.go index 1db54f2d8a..61eae63125 100644 --- a/pkg/osbuild/mkfs_stage.go +++ b/pkg/osbuild/mkfs_stage.go @@ -39,7 +39,7 @@ func GenFsStages(pt *disk.PartitionTable, filename string) []*Stage { stages = append(stages, NewMkfsXfsStage(options, stageDevices)) case "vfat": options := &MkfsFATStageOptions{ - VolID: strings.Replace(e.UUID, "-", "", -1), + VolID: strings.ReplaceAll(e.UUID, "-", ""), Label: e.Label, } stages = append(stages, NewMkfsFATStage(options, stageDevices)) diff --git a/pkg/osbuild/result_test.go b/pkg/osbuild/result_test.go index a3500a0ecb..b768d42c23 100644 --- a/pkg/osbuild/result_test.go +++ b/pkg/osbuild/result_test.go @@ -166,11 +166,12 @@ func TestUnmarshalV2Success(t *testing.T) { // check metadata for _, pipeline := range result.Metadata { for stageType, stageMetadata := range pipeline { - if stageType == "org.osbuild.rpm" { + switch stageType { + case "org.osbuild.rpm": rpmMd, convOk := stageMetadata.(*RPMStageMetadata) assert.True(convOk) assert.Greater(len(rpmMd.Packages), 0) - } else if stageType == "org.osbuild.ostree.commit" { + case "org.osbuild.ostree.commit": commitMd, convOk := stageMetadata.(*OSTreeCommitStageMetadata) assert.True(convOk) assert.NotEmpty(commitMd.Compose.Ref) diff --git a/pkg/rhsm/secrets.go b/pkg/rhsm/secrets.go index 88edcd5a27..8d086e8c43 100644 --- a/pkg/rhsm/secrets.go +++ b/pkg/rhsm/secrets.go @@ -181,8 +181,8 @@ func parseRepoFile(content []byte) ([]subscription, error) { func (s *Subscriptions) GetSecretsForBaseurl(baseurls []string, arch, releasever string) (*RHSMSecrets, error) { for _, subs := range s.available { for _, baseurl := range baseurls { - url := strings.Replace(subs.baseurl, "$basearch", arch, -1) - url = strings.Replace(url, "$releasever", releasever, -1) + url := strings.ReplaceAll(subs.baseurl, "$basearch", arch) + url = strings.ReplaceAll(url, "$releasever", releasever) if url == baseurl { return &RHSMSecrets{ SSLCACert: subs.sslCACert, diff --git a/pkg/shutil/shlex_quote.go b/pkg/shutil/shlex_quote.go index 1046b00ca1..b2a73fb807 100644 --- a/pkg/shutil/shlex_quote.go +++ b/pkg/shutil/shlex_quote.go @@ -9,5 +9,5 @@ import ( func Quote(s string) string { // use single quotes, and put single quotes into double quotes // the string $'b is then quoted as '$'"'"'b' - return `'` + strings.Replace(s, `'`, `'"'"'`, -1) + `'` + return `'` + strings.ReplaceAll(s, `'`, `'"'"'`) + `'` } diff --git a/pkg/upload/koji/koji.go b/pkg/upload/koji/koji.go index 4fa635179c..e6d30c42d5 100644 --- a/pkg/upload/koji/koji.go +++ b/pkg/upload/koji/koji.go @@ -402,7 +402,7 @@ func createCustomRetryableClient(logger rh.LeveledLogger) *rh.Client { } } - if logger != nil && (!shouldRetry && !(resp.StatusCode >= 200 && resp.StatusCode < 300)) { + if logger != nil && (!shouldRetry && (resp.StatusCode < 200 || resp.StatusCode >= 300)) { logger.Info(fmt.Sprintf("Not retrying: %v", resp.Status)) }