diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index f38f78b..7254ccc 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -33,6 +33,8 @@ jobs: needs: setup steps: - uses: actions/checkout@v4.2.2 + with: + fetch-depth: 5 - name: Setup Go uses: actions/setup-go@v5.5.0 with: @@ -41,7 +43,6 @@ jobs: - name: Setup bridger id: setup run: | - echo "gcli_ver=$(grep 'golangci-lint-version' .golangci.yml | awk '{print $2}')" >> $GITHUB_OUTPUT echo "::group::godownload" make download echo "::endgroup::" @@ -50,7 +51,6 @@ jobs: with: go_version_file: "go.mod" reporter: github-pr-review - golangci_lint_version: "v${{ steps.setup.outputs.gcli_ver }}" cache: false fail_level: warning filter_mode: added diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..eda7e62 --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,56 @@ +--- +version: "2" +linters: + enable: + - bodyclose + - depguard + - durationcheck + - funlen + - gocognit + - gocritic + - gocyclo + - godox + - goheader + - gosec + - misspell + - mnd + - nakedret + - revive + - unconvert + settings: + errcheck: + check-type-assertions: true + check-blank: false + exclude-functions: + - (io.Closer).Close + depguard: + rules: + main: + list-mode: lax + allow: + - $gostd + deny: + - pkg: github.com/docker/distribution + desc: use the distribution package from github.com/distribution/distribution instead + - pkg: golang.org/x/crypto/ssh/terminal + desc: use the terminal package from golang.org/x/term instead +formatters: + enable: + - gofmt + - goimports +output: + formats: + text: + print-linter-name: true + junit-xml: + output: "reports/golangci-lint.xml" + sort-order: + - severity + - linter + - file +issues: + new: true +run: + tests: false + modules-download-mode: readonly + allow-parallel-runners: true diff --git a/.golangci.yml b/.golangci.yml deleted file mode 100644 index f9ce525..0000000 --- a/.golangci.yml +++ /dev/null @@ -1,31 +0,0 @@ ---- -linters: - enable: - - revive - - goimports - - gosec - - misspell - - unconvert - - gocyclo - - gocognit - - godox - - funlen - - gomnd - # enable for future - # - bodyclose - # - depguard - # - durationcheck - # - gocritic - # - gofmt - # - goheader - # - nakedret - # -run: - relative-path-mode: gomod - tests: false - timeout: 3m - out-format: colored-line-number - modules-download-mode: readonly - allow-parallel-runners: true -service: - golangci-lint-version: 1.55.2 diff --git a/cmd/bridgr/main.go b/cmd/bridgr/main.go index f4326da..cb6fafe 100644 --- a/cmd/bridgr/main.go +++ b/cmd/bridgr/main.go @@ -87,7 +87,7 @@ func main() { if err != nil { log.Error("Unable to open bridgr config \"%s\": %s", *configPtr, err) if configFile != nil { - configFile.Close() + _ = configFile.Close() } exit(cfgErr) } diff --git a/internal/bridgr/asset/dev.go b/internal/bridgr/asset/dev.go index 3c398d1..f42392c 100644 --- a/internal/bridgr/asset/dev.go +++ b/internal/bridgr/asset/dev.go @@ -1,3 +1,4 @@ +//go:build !dist // +build !dist package asset diff --git a/internal/bridgr/asset/main.go b/internal/bridgr/asset/main.go index 8aeacd0..f6696fb 100644 --- a/internal/bridgr/asset/main.go +++ b/internal/bridgr/asset/main.go @@ -6,7 +6,6 @@ package asset import ( "io" - "io/ioutil" "strings" "text/template" @@ -20,7 +19,7 @@ func Load(name string) (string, error) { return "", err } defer f.Close() - content, err := ioutil.ReadAll(f) + content, err := io.ReadAll(f) if err != nil { return "", err } diff --git a/internal/bridgr/bridgr.go b/internal/bridgr/bridgr.go index e6003cb..7786511 100644 --- a/internal/bridgr/bridgr.go +++ b/internal/bridgr/bridgr.go @@ -16,6 +16,11 @@ import ( log "unknwon.dev/clog/v2" ) +const ( + fileMode = 0644 + dirMode = 0750 +) + var ( // Verbose determines whether debug logging is printed Verbose = false @@ -28,6 +33,12 @@ var ( // FileTimeout is the duration used for HTTP/s file download overall timeout. Used in the transport object FileTimeout = time.Second * 20 + + // DefaultFilePerms are the permissions for files created by Bridgr workers + DefaultFilePerms = os.FileMode(fileMode) + + // DefaultDirPerms are the directory permissions for directories created by Bridgr workers + DefaultDirPerms = os.FileMode(dirMode) ) // BaseDir gives the runtime absolute directory of the base "packages" directory diff --git a/internal/bridgr/cmd/cmd.go b/internal/bridgr/cmd/cmd.go index f93dbfb..9b4ef70 100644 --- a/internal/bridgr/cmd/cmd.go +++ b/internal/bridgr/cmd/cmd.go @@ -103,7 +103,7 @@ func (b Bridgr) Execute(filter []string) error { } func contains(item string, list []string) bool { - if len(list) <= 0 || strings.ToLower(list[0]) == "all" { + if len(list) == 0 || strings.ToLower(list[0]) == "all" { return true } for _, x := range list { diff --git a/internal/bridgr/docker.go b/internal/bridgr/docker.go index b909012..039f4ef 100644 --- a/internal/bridgr/docker.go +++ b/internal/bridgr/docker.go @@ -120,7 +120,7 @@ func (d *Docker) Run() error { } else { re := regexp.MustCompile(`[:/]`) outFile := re.ReplaceAllString(reference.Path(img), "_") + ".tar" - out, err := os.Create(path.Join(d.dir(), outFile)) + out, err := os.Create(path.Join(d.dir(), outFile)) // #nosec G304, this is already rooted in the Docker worker's base directory if err != nil { log.Info("error creating %s for saving Docker image %s - %s", outFile, img.String(), err) continue @@ -140,7 +140,7 @@ func (d *Docker) Run() error { // Setup gets the environment ready to run the Docker worker func (d *Docker) Setup() error { log.Trace("Called Docker.Setup()") - _ = os.MkdirAll(d.dir(), os.ModePerm) + _ = os.MkdirAll(d.dir(), DefaultDirPerms) // filter nil images from parse errors filtered := d.Images[:0] @@ -198,7 +198,7 @@ type imageTagger interface { func (d *Docker) tagForRemote(cli imageTagger, local reference.Named) string { destReg := d.Destination - remoteTag := strings.Replace(local.String(), reference.Domain(local), destReg, -1) + remoteTag := strings.ReplaceAll(local.String(), reference.Domain(local), destReg) _ = cli.ImageTag(context.Background(), local.String(), remoteTag) return remoteTag diff --git a/internal/bridgr/file.go b/internal/bridgr/file.go index ec76c79..6dcadeb 100644 --- a/internal/bridgr/file.go +++ b/internal/bridgr/file.go @@ -152,7 +152,7 @@ func (f File) Run() error { // Setup only does the setup step of the Files worker func (f File) Setup() error { log.Trace("Called Files.Setup()") - _ = os.MkdirAll(f.dir(), os.ModePerm) + _ = os.MkdirAll(f.dir(), DefaultDirPerms) for _, item := range f { _ = item.Normalize(f.dir()) } @@ -160,7 +160,7 @@ func (f File) Setup() error { } func (ff *fileFetcher) fileFetch(source string, out io.WriteCloser) error { - in, openErr := os.Open(source) + in, openErr := os.Open(source) // #nosec G304 this is intended behavior, we want to read local files if openErr != nil { return openErr } @@ -204,7 +204,7 @@ func (ff *fileFetcher) httpFetch(httpClient *http.Client, source string, out io. func (ff *fileFetcher) s3Fetch(client s3iface.S3API, source *url.URL, out io.WriteCloser) error { defer out.Close() if client == (*s3.S3)(nil) { - return errors.New("Invalid S3 client, unable to copy file") + return errors.New("invalid S3 client, unable to copy file") } log.Trace("Downloading S3 file: %s", source.String()) resp, err := client.GetObject(&s3.GetObjectInput{ diff --git a/internal/bridgr/file_internal_test.go b/internal/bridgr/file_internal_test.go index e6a9782..fddea0c 100644 --- a/internal/bridgr/file_internal_test.go +++ b/internal/bridgr/file_internal_test.go @@ -4,7 +4,6 @@ import ( "bytes" "errors" "io" - "io/ioutil" "net/http" "net/url" "reflect" @@ -24,7 +23,7 @@ type httpMock struct { func (m httpMock) RoundTrip(req *http.Request) (*http.Response, error) { return &http.Response{ StatusCode: 200, - Body: ioutil.NopCloser(bytes.NewBufferString("OK")), + Body: io.NopCloser(bytes.NewBufferString("OK")), Header: make(http.Header), }, nil } diff --git a/internal/bridgr/git.go b/internal/bridgr/git.go index 5bdd649..457e553 100644 --- a/internal/bridgr/git.go +++ b/internal/bridgr/git.go @@ -108,7 +108,7 @@ func (g *Git) Hook() mapstructure.DecodeHookFunc { // Setup does any initial setup for the Git worker func (g *Git) Setup() error { - return os.MkdirAll(g.dir(), os.ModePerm) + return os.MkdirAll(g.dir(), DefaultDirPerms) } // Run executes the Git worker to fetch artifacts @@ -124,13 +124,13 @@ func (g *Git) Run() error { log.Info("Error cloning Git repository '%s': %s", item.URL.String(), err) } if item.Bare { - _ = os.MkdirAll(path.Join(dir, "info"), os.ModePerm) - _ = os.MkdirAll(path.Join(dir, "objects", "info"), os.ModePerm) - infoRefs, _ := os.Create(path.Join(dir, "info", "refs")) + _ = os.MkdirAll(path.Join(dir, "info"), DefaultDirPerms) + _ = os.MkdirAll(path.Join(dir, "objects", "info"), DefaultDirPerms) + infoRefs, _ := os.Create(path.Join(dir, "info", "refs")) // #nosec G304, this is already cleaned and rooted in the PrepDir function generateRefInfo(repo, infoRefs) infoRefs.Close() - infoPack, _ := os.Create(path.Join(dir, "objects", "info", "packs")) + infoPack, _ := os.Create(path.Join(dir, "objects", "info", "packs")) // #nosec G304, this is already cleaned and rooted in the PrepDir function generatePackInfo(repo, infoPack) infoPack.Close() } @@ -142,7 +142,7 @@ func (g *Git) Run() error { func (g *Git) prepDir(url *url.URL) string { dir := path.Base(url.Path) dir = strings.TrimSuffix(dir, git.GitDirName) - dir = path.Join(g.dir(), dir) + dir = path.Join(g.dir(), dir) // this roots the directory in the Git worker's base directory if _, err := os.Stat(dir); !os.IsNotExist(err) { log.Trace("%s exists, removing to allow new clone", dir) diff --git a/internal/bridgr/helm.go b/internal/bridgr/helm.go index fcdec00..0b42e73 100644 --- a/internal/bridgr/helm.go +++ b/internal/bridgr/helm.go @@ -38,7 +38,7 @@ func (h Helm) Setup() error { for _, chart := range h { chart.Normalize(h.dir()) } - return os.MkdirAll(h.dir(), os.ModePerm) + return os.MkdirAll(h.dir(), DefaultDirPerms) } // Run downloads the requested Helm charts, and creates an index for statically hosting them diff --git a/internal/bridgr/python.go b/internal/bridgr/python.go index dc2ec46..dcbcf5a 100644 --- a/internal/bridgr/python.go +++ b/internal/bridgr/python.go @@ -98,10 +98,10 @@ func (p *Python) Hook() mapstructure.DecodeHookFunc { // Setup creates the items that are needed to fetch artifacts for the Python worker. It does not actually fetch artifacts. func (p Python) Setup() error { log.Trace("Called Python Setup()") - _ = os.MkdirAll(p.dir(), os.ModePerm) + _ = os.MkdirAll(p.dir(), DefaultDirPerms) reqt, err := os.Create(path.Join(p.dir(), "requirements.txt")) if err != nil { - return fmt.Errorf("Unable to create Python requirements file: %s", err) + return fmt.Errorf("unable to create Python requirements file: %s", err) } return asset.RenderFile(pyReqt, p.Packages, reqt) diff --git a/internal/bridgr/ruby.go b/internal/bridgr/ruby.go index 03c82b4..ed6766d 100644 --- a/internal/bridgr/ruby.go +++ b/internal/bridgr/ruby.go @@ -111,11 +111,11 @@ func (r Ruby) Hook() mapstructure.DecodeHookFunc { // Setup creates the items that are needed to fetch artifacts for the Python worker. It does not actually fetch artifacts. func (r *Ruby) Setup() error { log.Trace("Called Ruby.Setup()") - _ = os.MkdirAll(r.dir(), os.ModePerm) + _ = os.MkdirAll(r.dir(), DefaultDirPerms) gemfile, err := os.Create(path.Join(r.dir(), "Gemfile")) if err != nil { - return fmt.Errorf("Unable to create Ruby Gemfile: %s", err) + return fmt.Errorf("unable to create Ruby Gemfile: %s", err) } return asset.RenderFile(rbGems, r, gemfile) @@ -128,7 +128,7 @@ func (r *Ruby) Run() error { return err } - shell, err := asset.Load("ruby.sh") //no parsing needed, so just Load is fine here + shell, err := asset.Load("ruby.sh") // no parsing needed, so just Load is fine here if err != nil { return err } diff --git a/internal/bridgr/server.go b/internal/bridgr/server.go index f0dc87e..b5d988f 100644 --- a/internal/bridgr/server.go +++ b/internal/bridgr/server.go @@ -9,6 +9,10 @@ import ( "time" ) +const ( + serverReadHeaderTimeout = 5 * time.Second +) + var ( logFmt = "2/Jan/2006:15:04:05 -0700" shutdownTimeout = 10 * time.Second @@ -54,7 +58,7 @@ func Serve(addr string, root http.FileSystem) error { fs := http.FileServer(root) handlerChain := logMiddleware(customHeaders(fs)) http.Handle("/", handlerChain) - server := &http.Server{Addr: addr} + server := &http.Server{Addr: addr, ReadHeaderTimeout: serverReadHeaderTimeout, Handler: http.DefaultServeMux} signal.Notify(quit, os.Interrupt) go shutdownHandler(server) @@ -83,7 +87,7 @@ func logMiddleware(next http.Handler) http.Handler { loggingRW := &loggingResponseWriter{ ResponseWriter: w, } - next.ServeHTTP(loggingRW, r) //continue with the response + next.ServeHTTP(loggingRW, r) // continue with the response // clog (used by the rest of bridgr) doesn't support changing the "prefix" of logging output // so, we use direct Printf here instead so the logs aren't "double formatted" - first by clog and then in CLF form diff --git a/internal/bridgr/yum.go b/internal/bridgr/yum.go index 2edb0ef..17169fb 100644 --- a/internal/bridgr/yum.go +++ b/internal/bridgr/yum.go @@ -108,11 +108,11 @@ func (y Yum) Run() error { // Setup only does the setup step of the YUM worker func (y Yum) Setup() error { log.Trace("Called Yum Setup()") - _ = os.MkdirAll(y.dir(), os.ModePerm) + _ = os.MkdirAll(y.dir(), DefaultDirPerms) repoFile, err := os.Create(path.Join(y.dir(), "bridgr.repo")) if err != nil { - return fmt.Errorf("Unable to create YUM repo file: %s", err) + return fmt.Errorf("unable to create YUM repo file: %s", err) } err = asset.RenderFile(yumRepo, y.Repos, repoFile)