diff --git a/.golangci.yml b/.golangci.yml index 656ed04..bc75751 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,7 +1,7 @@ --- run: concurrency: 6 - deadline: 5m + timeout: 5m issues: exclude-rules: # counterfeiter fakes are usually named 'fake_.go' @@ -10,6 +10,12 @@ issues: - gocritic - golint - dupl + + # 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 linters: disable-all: true enable: @@ -17,7 +23,6 @@ linters: - asciicheck - bidichk - bodyclose - - containedctx - contextcheck - decorder - dogsled @@ -25,7 +30,11 @@ linters: - durationcheck - errcheck - errchkjson + - errname - execinquery + - ginkgolinter + - gocheckcompilerdirectives + - gochecksumtype - goconst - gocritic - gocyclo @@ -37,37 +46,47 @@ linters: - gomoddirectives - gomodguard - goprintffuncname + - gosec - gosimple + - gosmopolitan - govet - grouper - importas - ineffassign - - interfacebloat - - ireturn - - logrlint - - maintidx + - loggercheck - makezero + - mirror - misspell + - musttag - nakedret - - nilnil + - nolintlint - nosprintfhostport + - perfsprint - prealloc - predeclared - promlinter + - protogetter - reassign + - revive - rowserrcheck + - sloglint - sqlclosecheck - staticcheck - stylecheck + - tagalign - tenv + - testableexamples - typecheck - unconvert - unparam - unused - usestdlibvars - whitespace + - zerologlint + # - containedctx # - cyclop - # - errname + # - depguard + # - dupword # - errorlint # - exhaustive # - exhaustruct @@ -82,16 +101,19 @@ linters: # - godot # - goerr113 # - gomnd - # - gosec + # - inamedparam + # - interfacebloat + # - ireturn # - lll + # - maintidx # - nestif # - nilerr + # - nilnil # - nlreturn # - noctx - # - nolintlint # - nonamedreturns # - paralleltest - # - revive + # - testifylint # - tagliatelle # - testpackage # - thelper @@ -101,6 +123,8 @@ linters: # - wrapcheck # - wsl linters-settings: + gocyclo: + min-complexity: 40 godox: keywords: - BUG @@ -111,114 +135,119 @@ linters-settings: check-blank: true gocritic: enabled-checks: - # Diagnostic - appendAssign + - appendCombine - argOrder + - assignOp - badCall - badCond - badLock - badRegexp - badSorting + - boolExprSimplify + - builtinShadow - builtinShadowDecl + - captLocal - caseOrder - codegenComment + - commentFormatting - commentedOutCode + - commentedOutImport + - defaultCaseOrder - deferInLoop + - deferUnlambda - deprecatedComment + - docStub - dupArg - dupBranchBody - dupCase + - dupImport - dupSubExpr - dynamicFmtString + - elseif - emptyDecl + - emptyFallthrough + - emptyStringTest + - equalFold - evalOrder - exitAfterDefer + - exposedSyncMutex - externalErrorReassign - filepathJoin - flagDeref - flagName + - hexLiteral + - httpNoBody + - hugeParam + - ifElseChain + - importShadow + - indexAlloc + - initClause - mapKey + - methodExprCall + - nestingReduce + - newDeref - nilValReturn + - octalLiteral - offBy1 - - regexpPattern - - returnAfterHttpError - - sloppyReassign - - sloppyTypeAssert - - sortSlice - - sprintfQuotedString - - sqlQuery - - syncMapLoadAndDelete - - truncateCmp - - unnecessaryDefer - - weakCond - - # Performance - - appendCombine - - equalFold - - hugeParam - - indexAlloc + - paramTypeCombine - preferDecodeRune + - preferFilepathJoin - preferFprint - preferStringWriter - preferWriteByte + - ptrToRefParam - rangeExprCopy - rangeValCopy - - sliceClear - - stringXbytes - - # Style - - assignOp - - boolExprSimplify - - captLocal - - commentFormatting - - commentedOutImport - - defaultCaseOrder - - deferUnlambda - - docStub - - dupImport - - elseif - - emptyFallthrough - - emptyStringTest - - exposedSyncMutex - - hexLiteral - - httpNoBody - - ifElseChain - - methodExprCall - - newDeref - - octalLiteral - - preferFilepathJoin - redundantSprint - regexpMust + - regexpPattern - regexpSimplify + - returnAfterHttpError - ruleguard - singleCaseSwitch + - sliceClear - sloppyLen + - sloppyReassign + - sloppyTypeAssert + - sortSlice + - sprintfQuotedString + - sqlQuery - stringConcatSimplify + - stringXbytes - stringsCompare - switchTrue + - syncMapLoadAndDelete - timeCmpSimplify - timeExprSimplify - - todoCommentWithoutDetail - tooManyResultsChecker + - truncateCmp - typeAssertChain - typeDefFirst - typeSwitchVar + - typeUnparen + - uncheckedInlineErr - underef - unlabelStmt - unlambda + - unnamedResult + - unnecessaryBlock + - unnecessaryDefer - unslice - valSwap + - weakCond - wrapperFunc - yodaStyleExpr - # - whyNoLint - - # Opinionated - - builtinShadow - - importShadow - - initClause - - nestingReduce - - paramTypeCombine - - ptrToRefParam - - typeUnparen - - unnamedResult - - unnecessaryBlock + nolintlint: + # Enable to ensure that nolint directives are all used. Default is true. + allow-unused: false + # Disable to ensure that nolint directives don't have a leading space. Default is true. + # TODO(lint): Enforce machine-readable `nolint` directives + allow-leading-space: true + # Exclude following linters from requiring an explanation. Default is []. + allow-no-explanation: [] + # Enable to require an explanation of nonzero length after each nolint directive. Default is false. + # TODO(lint): Enforce explanations for `nolint` directives + require-explanation: false + # Enable to require nolint directives to mention the specific linter being suppressed. Default is false. + require-specific: true \ No newline at end of file diff --git a/command/command.go b/command/command.go index 690399a..bfb85d8 100644 --- a/command/command.go +++ b/command/command.go @@ -58,7 +58,7 @@ type Status struct { } // Stream combines standard output and error -type Stream struct { +type Stream struct { //nolint: errname stdOut string stdErr string } @@ -195,7 +195,7 @@ func (c *Command) RunSuccessOutput() (output *Stream, err error) { // RunSuccess starts the command and waits for it to finish. It returns an // error if the command execution was not successful. func (c *Command) RunSuccess() error { - _, err := c.RunSuccessOutput() // nolint: errcheck + _, err := c.RunSuccessOutput() //nolint: errcheck return err } @@ -242,7 +242,7 @@ func (c *Command) RunSilentSuccessOutput() (output *Stream, err error) { // an error if the command execution was not successful. This method does not // print the output of the command during its execution. func (c *Command) RunSilentSuccess() error { - _, err := c.RunSilentSuccessOutput() // nolint: errcheck + _, err := c.RunSilentSuccessOutput() //nolint: errcheck return err } diff --git a/command/global.go b/command/global.go index d75387f..687e707 100644 --- a/command/global.go +++ b/command/global.go @@ -26,7 +26,7 @@ var atomicInt int32 // SetGlobalVerbose sets the global command verbosity to the specified value func SetGlobalVerbose(to bool) { - var i int32 = 0 + var i int32 if to { i = 1 } diff --git a/dependencies.yaml b/dependencies.yaml index c092c1c..830bf30 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -1,14 +1,14 @@ dependencies: # golangci/golangci-lint - name: "golangci-lint" - version: 1.54.2 + version: 1.55.1 refPaths: - - path: mage/golang.go + - path: mage/golangci-lint.go match: defaultGolangCILintVersion\s+=\s+"v(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?" # ko - name: "ko" - version: 0.14.1 + version: 0.15.0 refPaths: - path: mage/ko.go match: defaultKoVersion\s+=\s+"(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?" diff --git a/editor/editor.go b/editor/editor.go index 52de712..db0d61e 100644 --- a/editor/editor.go +++ b/editor/editor.go @@ -101,7 +101,7 @@ func (e Editor) args(path string) []string { last := args[len(args)-1] args[len(args)-1] = fmt.Sprintf("%s %q", last, path) } else { - args = append(args, path) // nolint: makezero + args = append(args, path) //nolint: makezero } return args } @@ -117,7 +117,8 @@ func (e Editor) Launch(path string) error { return err } args := e.args(abs) - cmd := exec.Command(args[0], args[1:]...) + // TODO: check to validate the args and maybe sabitize those + cmd := exec.Command(args[0], args[1:]...) //nolint: gosec cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr cmd.Stdin = os.Stdin diff --git a/hash/hash.go b/hash/hash.go index 1c0d6b6..2cdde6f 100644 --- a/hash/hash.go +++ b/hash/hash.go @@ -17,7 +17,7 @@ limitations under the License. package hash import ( - "crypto/sha1" + "crypto/sha1" //nolint: gosec "crypto/sha256" "crypto/sha512" "encoding/hex" @@ -41,8 +41,9 @@ func SHA256ForFile(filename string) (string, error) { } // SHA1ForFile returns the hex-encoded sha1 hash for the provided filename. +// TODO: check if we can remove this function func SHA1ForFile(filename string) (string, error) { - return ForFile(filename, sha1.New()) + return ForFile(filename, sha1.New()) //nolint: gosec } // ForFile returns the hex-encoded hash for the provided filename and hasher. diff --git a/hash/hash_test.go b/hash/hash_test.go index bfc9aa9..3d5043d 100644 --- a/hash/hash_test.go +++ b/hash/hash_test.go @@ -17,7 +17,7 @@ limitations under the License. package hash_test import ( - "crypto/sha1" + "crypto/sha1" //nolint: gosec "crypto/sha256" "hash" "os" @@ -154,7 +154,7 @@ func TestForFile(t *testing.T) { _, err = f.WriteString("test") require.Nil(t, err) - return f.Name(), sha1.New() + return f.Name(), sha1.New() //nolint: gosec }, expected: "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", shouldError: false, diff --git a/mage/golang.go b/mage/golangci-lint.go similarity index 98% rename from mage/golang.go rename to mage/golangci-lint.go index 1a0fc5a..95595ec 100644 --- a/mage/golang.go +++ b/mage/golangci-lint.go @@ -37,7 +37,7 @@ import ( const ( // golangci-lint - defaultGolangCILintVersion = "v1.54.2" + defaultGolangCILintVersion = "v1.55.1" golangciCmd = "golangci-lint" golangciConfig = ".golangci.yml" golangciURLBase = "https://raw.githubusercontent.com/golangci/golangci-lint" @@ -188,7 +188,7 @@ func testGo(verbose bool, tags string, pkgs ...string) error { // VerifyGoMod runs `go mod tidy` and `git diff --exit-code go.*` to ensure // all module updates have been checked in. -func VerifyGoMod(scriptDir string) error { +func VerifyGoMod() error { minGoVersion := env.Default("MIN_GO_VERSION", defaultMinGoVersion) if err := shx.RunV( "go", "mod", "tidy", fmt.Sprintf("-compat=%s", minGoVersion), diff --git a/mage/ko.go b/mage/ko.go index 11e0ed6..b7e90d2 100644 --- a/mage/ko.go +++ b/mage/ko.go @@ -25,7 +25,7 @@ import ( "github.com/uwu-tools/magex/pkg/downloads" ) -const defaultKoVersion = "0.14.1" +const defaultKoVersion = "0.15.0" // EnsureKO func EnsureKO(version string) error { diff --git a/magefile.go b/magefile.go index 2e6ce7d..781e774 100644 --- a/magefile.go +++ b/magefile.go @@ -72,7 +72,7 @@ func Verify() error { } fmt.Println("Running go module linter...") - if err := mage.VerifyGoMod(scriptDir); err != nil { + if err := mage.VerifyGoMod(); err != nil { return err } diff --git a/tar/tar.go b/tar/tar.go index a326c8a..470f85b 100644 --- a/tar/tar.go +++ b/tar/tar.go @@ -141,13 +141,19 @@ func Extract(tarFilePath, destinationPath string) error { func(reader *tar.Reader, header *tar.Header) (stop bool, err error) { switch header.Typeflag { case tar.TypeDir: - targetDir := filepath.Join(destinationPath, header.Name) + targetDir, err := SanitizeArchivePath(destinationPath, header.Name) + if err != nil { + return false, fmt.Errorf("SanitizeArchivePath: %w", err) + } logrus.Tracef("Creating directory %s", targetDir) if err := os.MkdirAll(targetDir, os.FileMode(0o755)); err != nil { return false, fmt.Errorf("create target directory: %w", err) } case tar.TypeSymlink: - targetFile := filepath.Join(destinationPath, header.Name) + targetFile, err := SanitizeArchivePath(destinationPath, header.Name) + if err != nil { + return false, fmt.Errorf("SanitizeArchivePath: %w", err) + } logrus.Tracef( "Creating symlink %s -> %s", header.Linkname, targetFile, ) @@ -161,8 +167,11 @@ func Extract(tarFilePath, destinationPath string) error { } // tar.TypeRegA has been deprecated since Go 1.11 // should we just remove? - case tar.TypeReg, tar.TypeRegA: //nolint: staticcheck - targetFile := filepath.Join(destinationPath, header.Name) + case tar.TypeReg: + targetFile, err := SanitizeArchivePath(destinationPath, header.Name) + if err != nil { + return false, fmt.Errorf("SanitizeArchivePath: %w", err) + } logrus.Tracef("Creating file %s", targetFile) if err := os.MkdirAll( @@ -196,6 +205,17 @@ func Extract(tarFilePath, destinationPath string) error { ) } +// Sanitize archive file pathing from "G305: Zip Slip vulnerability" +// https://security.snyk.io/research/zip-slip-vulnerability +func SanitizeArchivePath(d, t string) (v string, err error) { + v = filepath.Join(d, t) + if strings.HasPrefix(v, filepath.Clean(d)) { + return v, nil + } + + return "", fmt.Errorf("%s: %s", "content filepath is tainted", t) +} + // ReadFileFromGzippedTar opens a tarball and reads contents of a file inside. func ReadFileFromGzippedTar( tarPath, filePath string, diff --git a/util/common.go b/util/common.go index af5a638..29b8646 100644 --- a/util/common.go +++ b/util/common.go @@ -39,10 +39,10 @@ const ( ) var ( - regexpCRLF *regexp.Regexp = regexp.MustCompile(`\015$`) - regexpCtrlChar *regexp.Regexp = regexp.MustCompile(`\x1B[\[(](\d{1,2}(;\d{1,2})?)?[mKB]`) - regexpOauthToken *regexp.Regexp = regexp.MustCompile(`[a-f0-9]{40}:x-oauth-basic`) - regexpGitToken *regexp.Regexp = regexp.MustCompile(`git:[a-f0-9]{35,40}@github\.com`) + regexpCRLF = regexp.MustCompile(`\015$`) + regexpCtrlChar = regexp.MustCompile(`\x1B[\[(](\d{1,2}(;\d{1,2})?)?[mKB]`) + regexpOauthToken = regexp.MustCompile(`[a-f0-9]{40}:x-oauth-basic`) + regexpGitToken = regexp.MustCompile(`git:[a-f0-9]{35,40}@github\.com`) ) // UserInputError a custom error to handle more user input info diff --git a/util/common_test.go b/util/common_test.go index 7458394..90aa25d 100644 --- a/util/common_test.go +++ b/util/common_test.go @@ -459,7 +459,7 @@ func TestTrimTagPrefix(t *testing.T) { } func TestWrapText(t *testing.T) { - //nolint + //nolint: misspell longText := `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Ut molestie accumsan orci, id congue nibh sollicitudin in. Nulla condimentum arcu eu est hendrerit tempus. Nunc risus nibh, aliquam in ultrices fringilla, aliquet ac purus. Aenean non nibh magna. Nunc lacinia suscipit malesuada. Vivamus porta a leo vel ornare. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi pellentesque orci magna, sed semper nulla fringilla at. Nam elementum ipsum maximus lectus tempor faucibus. Donec eu enim nulla. Integer egestas venenatis tristique. Curabitur id purus sem. Vivamus nec mollis lorem.` wrappedText := "Lorem ipsum dolor sit amet, consectetur\n" wrappedText += "adipiscing elit. Ut molestie accumsan\n" @@ -471,7 +471,7 @@ func TestWrapText(t *testing.T) { wrappedText += "suscipit malesuada. Vivamus porta a leo\n" wrappedText += "vel ornare. Orci varius natoque\n" wrappedText += "penatibus et magnis dis parturient\n" - wrappedText += "montes, nascetur ridiculus mus. Morbi\n" //nolint + wrappedText += "montes, nascetur ridiculus mus. Morbi\n" //nolint: misspell wrappedText += "pellentesque orci magna, sed semper\n" wrappedText += "nulla fringilla at. Nam elementum ipsum\n" wrappedText += "maximus lectus tempor faucibus. Donec eu\n" @@ -538,7 +538,7 @@ func TestCleanLogFile(t *testing.T) { line5 := "\nControl Chars: " // Create a token line - originalTokenLine := "7aa33bd2186c40849c4c2df321241e241def98ca:x-oauth-basic" + originalTokenLine := "7aa33bd2186c40849c4c2df321241e241def98ca:x-oauth-basic" //nolint: gosec sanitizedTokenLine := string(StripSensitiveData([]byte(originalTokenLine))) require.NotEqual(t, originalTokenLine, sanitizedTokenLine)