From 7a6f71ac73b41a38e9982bea3d46a87c327bd77a Mon Sep 17 00:00:00 2001 From: Runxi Yu Date: Sat, 22 Mar 2025 13:17:55 +0800 Subject: [PATCH] Initial linting --- .golangci.yaml | 30 ++++++++++++++++++++++++++++++ fedauth.go | 11 +++++++---- git_hooks_handle.go | 13 +++++++------ git_misc.go | 15 +++++++++------ http_error_page.go | 6 +++--- http_handle_gc.go | 2 +- http_handle_group_index.go | 5 +++-- http_handle_index.go | 2 +- http_handle_login.go | 5 ++--- http_handle_repo_index.go | 6 ++++-- http_handle_repo_info.go | 4 ++-- http_handle_repo_log.go | 2 +- http_handle_users.go | 2 +- http_server.go | 4 +--- http_template_funcs.go | 2 +- irc.go | 2 +- main.go | 9 ++++++++- resources.go | 5 +++-- scripts/lint | 6 ------ ssh_handle_receive_pack.go | 4 +--- ssh_handle_upload_pack.go | 4 +--- ssh_server.go | 6 +++--- diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000000000000000000000000000000000000..71397ccb8f92aa2790e1ca57b93d122cdea96705 --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,30 @@ +linters: + enable-all: true + disable: + - tenv + - depguard + - err113 # dynamically defined errors are fine for our purposes + - forcetypeassert # type assertion failures are usually programming errors + - gochecknoglobals # doesn't matter since this isn't a library + - gochecknoinits # we use inits sparingly for good reasons + - godox # they're just used as markers for where needs improvements + - ireturn # doesn't work well with how we use generics + - lll # long lines are acceptable + - mnd # it's a bit ridiculous to replace all of them + - nakedret # patterns should be consistent + - nonamedreturns # i like named returns + - maintidx # e + - nestif # e + - gocognit # e + - gocyclo # e + - cyclop # e + - goconst # e + - funlen # e + - wsl # e + - nlreturn # e + - wrapcheck # e + - varnamelen # e + +issues: + max-issues-per-linter: 0 + max-same-issues: 0 diff --git a/fedauth.go b/fedauth.go index 3bd25d67ddba6fafef2d08ff31c8b5dd51d3f6a9..2012e19a4471ed76199c4c6e86d4da0dc45e5d8c 100644 --- a/fedauth.go +++ b/fedauth.go @@ -24,13 +24,13 @@ var req *http.Request switch service { case "sr.ht": - req, err = http.NewRequestWithContext(ctx, http.MethodGet, "https://meta.sr.ht/~" + usernameEscaped + ".keys", nil) + req, err = http.NewRequestWithContext(ctx, http.MethodGet, "https://meta.sr.ht/~"+usernameEscaped+".keys", nil) case "github": - req, err = http.NewRequestWithContext(ctx, http.MethodGet, "https://github.com/" + usernameEscaped + ".keys", nil) + req, err = http.NewRequestWithContext(ctx, http.MethodGet, "https://github.com/"+usernameEscaped+".keys", nil) case "codeberg": - req, err = http.NewRequestWithContext(ctx, http.MethodGet, "https://codeberg.org/" + usernameEscaped + ".keys", nil) + req, err = http.NewRequestWithContext(ctx, http.MethodGet, "https://codeberg.org/"+usernameEscaped+".keys", nil) case "tangled": - req, err = http.NewRequestWithContext(ctx, http.MethodGet, "https://tangled.sh/keys/" + usernameEscaped, nil) + req, err = http.NewRequestWithContext(ctx, http.MethodGet, "https://tangled.sh/keys/"+usernameEscaped, nil) // TODO: Don't rely on one webview default: return false, errors.New("unknown federated service") @@ -40,6 +40,9 @@ return false, err } resp, err := http.DefaultClient.Do(req) + if err != nil { + return false, err + } defer func() { _ = resp.Body.Close() }() diff --git a/git_hooks_handle.go b/git_hooks_handle.go index 6a447849e3befc7496e56e9cc9e46d02c2312c39..ca46d61f925a50487f333e2b3e298a1c6d27f6ea 100644 --- a/git_hooks_handle.go +++ b/git_hooks_handle.go @@ -55,7 +55,8 @@ } writeRedError(conn, "\nUnable to get peer credentials: %v", err) return } - if ucred.Uid != uint32(os.Getuid()) { + uint32uid := uint32(os.Getuid()) //#nosec G115 + if ucred.Uid != uint32uid { if _, err = conn.Write([]byte{1}); err != nil { return } @@ -92,7 +93,7 @@ writeRedError(sshStderr, "Failed to read argc: %v", err) return 1 } var args []string - for i := uint64(0); i < argc64; i++ { + for range argc64 { var arg bytes.Buffer for { b := make([]byte, 1) @@ -167,7 +168,7 @@ if pushOptCount == 0 { writeRedError(sshStderr, "This repo requires contributors to be either federated or registered users. You must supply your federated user ID as a push option. For example, git push -o fedid=sr.ht:runxiyu") return 1 } - for i := 0; i < pushOptCount; i++ { + for i := range pushOptCount { pushOpt, ok := gitEnv[fmt.Sprintf("GIT_PUSH_OPTION_%d", i)] if !ok { writeRedError(sshStderr, "Failed to get push option %d", i) @@ -241,10 +242,10 @@ if err != nil { writeRedError(sshStderr, "Error creating merge request: %v", err) return 1 } - merge_request_url := genHTTPRemoteURL(packPass.groupPath, packPass.repoName)+"/contrib/"+strconv.FormatUint(uint64(newMRID), 10)+"/" - fmt.Fprintln(sshStderr, ansiec.Blue+"Created merge request at", merge_request_url+ansiec.Reset) + mergeRequestWebURL := fmt.Sprintf("%s/contrib/%d/", genHTTPRemoteURL(packPass.groupPath, packPass.repoName), newMRID) + fmt.Fprintln(sshStderr, ansiec.Blue+"Created merge request at", mergeRequestWebURL+ansiec.Reset) select { - case ircSendBuffered <- "PRIVMSG #chat :New merge request at " + merge_request_url: + case ircSendBuffered <- "PRIVMSG #chat :New merge request at " + mergeRequestWebURL: default: clog.Error("IRC SendQ exceeded") } diff --git a/git_misc.go b/git_misc.go index 5b199650fd2d1b13e9000977bd3b0c9902fd4041..cd2930ea456d3ec63ee23aac8deff6cb9bfed8ce 100644 --- a/git_misc.go +++ b/git_misc.go @@ -74,7 +74,7 @@ } func makeDisplayTree(tree *object.Tree) (displayTree []displayTreeEntry) { for _, entry := range tree.Entries { - displayEntry := displayTreeEntry{} + displayEntry := displayTreeEntry{} //exhaustruct:ignore var err error var osMode os.FileMode @@ -135,7 +135,7 @@ func getRecentCommits(repo *git.Repository, headHash plumbing.Hash, numCommits int) (recentCommits []*object.Commit, err error) { var commitIter object.CommitIter var thisCommit *object.Commit - commitIter, err = repo.Log(&git.LogOptions{From: headHash}) + commitIter, err = repo.Log(&git.LogOptions{From: headHash}) //exhaustruct:ignore if err != nil { return nil, err } @@ -170,16 +170,17 @@ var parentCommit *object.Commit var commitTree *object.Tree parentCommit, err = commit.Parent(0) - if errors.Is(err, object.ErrParentNotFound) { + switch { + case errors.Is(err, object.ErrParentNotFound): if commitTree, err = commit.Tree(); err != nil { return } - if patch, err = (&object.Tree{}).Patch(commitTree); err != nil { + if patch, err = nullTree.Patch(commitTree); err != nil { return } - } else if err != nil { + case err != nil: return - } else { + default: parentCommitHash = parentCommit.Hash if patch, err = parentCommit.Patch(commit); err != nil { return @@ -187,3 +188,5 @@ } } return } + +var nullTree object.Tree diff --git a/http_error_page.go b/http_error_page.go index cb9e6ed7429d155829663a08e15cc6dde934245b..77fdc864ab0cbe133d8b2fe50f47ab10d619f195 100644 --- a/http_error_page.go +++ b/http_error_page.go @@ -8,18 +8,18 @@ "net/http" ) func errorPage404(w http.ResponseWriter, params map[string]any) { - w.WriteHeader(404) + w.WriteHeader(http.StatusNotFound) _ = templates.ExecuteTemplate(w, "404", params) } func errorPage400(w http.ResponseWriter, params map[string]any, msg string) { - w.WriteHeader(400) + w.WriteHeader(http.StatusBadRequest) params["complete_error_msg"] = msg _ = templates.ExecuteTemplate(w, "400", params) } func errorPage451(w http.ResponseWriter, params map[string]any, msg string) { - w.WriteHeader(451) + w.WriteHeader(http.StatusUnavailableForLegalReasons) params["complete_error_msg"] = msg _ = templates.ExecuteTemplate(w, "451", params) } diff --git a/http_handle_gc.go b/http_handle_gc.go index b00ef8aff2fbe64e40091bf9ff6fabf2ab3688e7..5f98d0e483da93f99d7b6a654bb57bc977d91ee5 100644 --- a/http_handle_gc.go +++ b/http_handle_gc.go @@ -8,7 +8,7 @@ "net/http" "runtime" ) -func httpHandleGC(w http.ResponseWriter, r *http.Request, params map[string]any) { +func httpHandleGC(w http.ResponseWriter, r *http.Request, _ map[string]any) { runtime.GC() http.Redirect(w, r, "/", http.StatusSeeOther) } diff --git a/http_handle_group_index.go b/http_handle_group_index.go index 22fb54845bac0f70271e80f7fb773fc2193c2dd3..27d71c52a9368e2958d890efb0dd1fe2f39980df 100644 --- a/http_handle_group_index.go +++ b/http_handle_group_index.go @@ -4,6 +4,7 @@ package main import ( + "errors" "net/http" "path/filepath" "strconv" @@ -54,7 +55,7 @@ `, pgtype.FlatArray[string](groupPath), ).Scan(&groupID, &groupDesc) - if err == pgx.ErrNoRows { + if errors.Is(err, pgx.ErrNoRows) { errorPage404(w, params) return } else if err != nil { @@ -76,7 +77,7 @@ return } directAccess := (count > 0) - if r.Method == "POST" { + if r.Method == http.MethodPost { if !directAccess { http.Error(w, "You do not have direct access to this group", http.StatusForbidden) return diff --git a/http_handle_index.go b/http_handle_index.go index 2fc99a68c4543751e2214259e8177f40e30383da..360c033013e0b120291c444a7bc35ad8a75d1b67 100644 --- a/http_handle_index.go +++ b/http_handle_index.go @@ -22,7 +22,7 @@ } params["groups"] = groups // Memory currently allocated - memstats := runtime.MemStats{} + memstats := runtime.MemStats{} //exhaustruct:ignore runtime.ReadMemStats(&memstats) params["mem"] = humanize.IBytes(memstats.Alloc) renderTemplate(w, "index", params) diff --git a/http_handle_login.go b/http_handle_login.go index 1c5c0661cb42f2082d8e81c4c29b0f0220867277..c6c1be1df4644cfe334f0f36a90f3b38abe36314 100644 --- a/http_handle_login.go +++ b/http_handle_login.go @@ -26,7 +26,7 @@ var now time.Time var expiry time.Time var cookie http.Cookie - if r.Method != "POST" { + if r.Method != http.MethodPost { renderTemplate(w, "login", params) return } @@ -80,8 +80,7 @@ HttpOnly: true, Secure: false, // TODO Expires: expiry, Path: "/", - // TODO: Expire - } + } //exhaustruct:ignore http.SetCookie(w, &cookie) diff --git a/http_handle_repo_index.go b/http_handle_repo_index.go index a22c75f9016937029e2e8aadd317d888480b5387..df1ee5e8b36828523da9e8726c4f8f45ab7e664d 100644 --- a/http_handle_repo_index.go +++ b/http_handle_repo_index.go @@ -14,7 +14,7 @@ "github.com/go-git/go-git/v5/plumbing/object" "github.com/go-git/go-git/v5/plumbing/storer" ) -func httpHandleRepoIndex(w http.ResponseWriter, r *http.Request, params map[string]any) { +func httpHandleRepoIndex(w http.ResponseWriter, _ *http.Request, params map[string]any) { var repo *git.Repository var repoName string var groupPath []string @@ -27,6 +27,7 @@ var tree *object.Tree var notes []string var branches []string var branchesIter storer.ReferenceIter + var logOptions git.LogOptions repo, repoName, groupPath = params["repo"].(*git.Repository), params["repo_name"].(string), params["group_path"].([]string) @@ -48,7 +49,8 @@ }) } params["branches"] = branches - if commitIter, err = repo.Log(&git.LogOptions{From: refHash}); err != nil { + logOptions = git.LogOptions{From: refHash} //exhaustruct:ignore + if commitIter, err = repo.Log(&logOptions); err != nil { goto no_ref } commitIterSeq, params["commits_err"] = commitIterSeqErr(commitIter) diff --git a/http_handle_repo_info.go b/http_handle_repo_info.go index abb971d2b53fa33bafadadc6cd868975a0bc3718..389936c32b9235e06a9e86d6f5d9d8235615a6cf 100644 --- a/http_handle_repo_info.go +++ b/http_handle_repo_info.go @@ -90,13 +90,13 @@ return nil } -// Taken from https://github.com/icyphox/legit, MIT license +// Taken from https://github.com/icyphox/legit, MIT license. func packLine(w io.Writer, s string) error { _, err := fmt.Fprintf(w, "%04x%s", len(s)+4, s) return err } -// Taken from https://github.com/icyphox/legit, MIT license +// Taken from https://github.com/icyphox/legit, MIT license. func packFlush(w io.Writer) error { _, err := fmt.Fprint(w, "0000") return err diff --git a/http_handle_repo_log.go b/http_handle_repo_log.go index 39be2313110ab69cd38e9bb00a53082460937424..2dec6bd8bf49a9274cbddf9a5813a699cf88b694 100644 --- a/http_handle_repo_log.go +++ b/http_handle_repo_log.go @@ -12,7 +12,7 @@ "github.com/go-git/go-git/v5/plumbing/object" ) // TODO: I probably shouldn't include *all* commits here... -func httpHandleRepoLog(w http.ResponseWriter, r *http.Request, params map[string]any) { +func httpHandleRepoLog(w http.ResponseWriter, _ *http.Request, params map[string]any) { var repo *git.Repository var refHash plumbing.Hash var err error diff --git a/http_handle_users.go b/http_handle_users.go index c657bad65d5b93f61002bffcb53b2710e9bbda9c..df0c99ac58f88e8a4105fabede587a7c66e70006 100644 --- a/http_handle_users.go +++ b/http_handle_users.go @@ -7,6 +7,6 @@ import ( "net/http" ) -func httpHandleUsers(w http.ResponseWriter, r *http.Request, params map[string]any) { +func httpHandleUsers(w http.ResponseWriter, _ *http.Request, _ map[string]any) { http.Error(w, "Not implemented", http.StatusNotImplemented) } diff --git a/http_server.go b/http_server.go index 584c48dec9f5525f3f46853651a11e411e205ea0..983f579a12567e398180c122294d66bd1fd993c7 100644 --- a/http_server.go +++ b/http_server.go @@ -36,9 +36,7 @@ params["global"] = globalData var userID int // 0 for none userID, params["username"], err = getUserFromRequest(r) params["user_id"] = userID - if errors.Is(err, http.ErrNoCookie) { - } else if errors.Is(err, pgx.ErrNoRows) { - } else if err != nil { + if err != nil && !errors.Is(err, http.ErrNoCookie) && !errors.Is(err, pgx.ErrNoRows) { http.Error(w, "Error getting user info from request: "+err.Error(), http.StatusInternalServerError) return } diff --git a/http_template_funcs.go b/http_template_funcs.go index 2a7d82670773202017d0056206699610527bc980..8d67aff0ded146be4e13c05074763cbb8bd91e84 100644 --- a/http_template_funcs.go +++ b/http_template_funcs.go @@ -30,7 +30,7 @@ func dereference[T any](p *T) T { return *p } -func dereference_or_zero[T any](p *T) T { +func dereferenceOrZero[T any](p *T) T { if p != nil { return *p } diff --git a/irc.go b/irc.go index e2b50373488f5e996df8a8b93dbd190bfd2c247d..4ca34d42b00deea48f72fb9be535035d15b40763 100644 --- a/irc.go +++ b/irc.go @@ -5,7 +5,7 @@ "crypto/tls" "net" "go.lindenii.runxiyu.org/lindenii-common/clog" - "go.lindenii.runxiyu.org/lindenii-irc" + irc "go.lindenii.runxiyu.org/lindenii-irc" ) var ( diff --git a/main.go b/main.go index d2b106946c234d2922d7fa5a2e033e76bd6cb414..1530d9097eb33b821b818dea45c143690a481c06 100644 --- a/main.go +++ b/main.go @@ -9,6 +9,7 @@ "flag" "net" "net/http" "syscall" + "time" "go.lindenii.runxiyu.org/lindenii-common/clog" ) @@ -86,9 +87,15 @@ } } else if err != nil { clog.Fatal(1, "Listening HTTP: "+err.Error()) } + server := http.Server{ + Handler: &forgeHTTPRouter{}, + ReadTimeout: 10 * time.Second, + WriteTimeout: 10 * time.Second, + IdleTimeout: 60 * time.Second, + } //exhaustruct:ignore clog.Info("Listening HTTP on " + config.HTTP.Net + " " + config.HTTP.Addr) go func() { - if err = http.Serve(httpListener, &forgeHTTPRouter{}); err != nil { + if err = server.Serve(httpListener); err != nil && !errors.Is(err, http.ErrServerClosed) { clog.Fatal(1, "Serving HTTP: "+err.Error()) } }() diff --git a/resources.go b/resources.go index fb67102b4701ae600d81762babb65f24eaa6aebd..dcfc2a56277a06dc54a691588b5f58fa672b0ea4 100644 --- a/resources.go +++ b/resources.go @@ -37,14 +37,15 @@ var templates *template.Template func loadTemplates() (err error) { m := minify.New() - m.Add("text/html", &html.Minifier{TemplateDelims: [2]string{"{{", "}}"}, KeepDefaultAttrVals: true}) + minifier := html.Minifier{TemplateDelims: [2]string{"{{", "}}"}, KeepDefaultAttrVals: true} //exhaustruct:ignore + m.Add("text/html", &minifier) templates = template.New("templates").Funcs(template.FuncMap{ "first_line": firstLine, "base_name": baseName, "path_escape": pathEscape, "query_escape": queryEscape, - "dereference_error": dereference_or_zero[error], + "dereference_error": dereferenceOrZero[error], }) err = fs.WalkDir(resourcesFS, "templates", func(path string, d fs.DirEntry, err error) error { diff --git a/scripts/lint b/scripts/lint deleted file mode 100755 index 14e50020ca92828ae4110adb62cb68c79026131c..0000000000000000000000000000000000000000 --- a/scripts/lint +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -# SPDX-License-Identifier: AGPL-3.0-only -# SPDX-FileContributor: Runxi Yu - -golangci-lint run . --enable-all --disable wsl,wrapcheck,nlreturn,nonamedreturns,mnd,lll,intrange,godox,gochecknoglobals,gochecknoinits,forcetypeassert,gofmt,gofumpt,revive,stylecheck,exhaustruct,godot,unparam,err113,depguard diff --git a/ssh_handle_receive_pack.go b/ssh_handle_receive_pack.go index ed1f765258e182c383577beb83759dec49245482..e42bca4e09b0ec492480631e91febfb2c8542590 100644 --- a/ssh_handle_receive_pack.go +++ b/ssh_handle_receive_pack.go @@ -124,9 +124,7 @@ return err } err = proc.Wait() - if exitError, ok := err.(*exec.ExitError); ok { - fmt.Fprintln(session.Stderr(), "Process exited with error", exitError.ExitCode()) - } else if err != nil { + if err != nil { fmt.Fprintln(session.Stderr(), "Error while waiting for process:", err) } diff --git a/ssh_handle_upload_pack.go b/ssh_handle_upload_pack.go index ab6253337bf4b8dff557eed1bd4b482d9e0099ed..f0edee2e19c861f715a59dcba5c4da6b9a5cfd0d 100644 --- a/ssh_handle_upload_pack.go +++ b/ssh_handle_upload_pack.go @@ -31,9 +31,7 @@ return err } err = proc.Wait() - if exitError, ok := err.(*exec.ExitError); ok { - fmt.Fprintln(session.Stderr(), "Process exited with error", exitError.ExitCode()) - } else if err != nil { + if err != nil { fmt.Fprintln(session.Stderr(), "Error while waiting for process:", err) } diff --git a/ssh_server.go b/ssh_server.go index 58a5acd40da67759d536e38502a4b2ae84f30d58..56ed501a7996bd19201c141abd661e04d767b8f6 100644 --- a/ssh_server.go +++ b/ssh_server.go @@ -79,13 +79,13 @@ fmt.Fprintln(session.Stderr(), err.Error()) return } }, - PublicKeyHandler: func(ctx gliderSSH.Context, key gliderSSH.PublicKey) bool { return true }, - KeyboardInteractiveHandler: func(ctx gliderSSH.Context, challenge goSSH.KeyboardInteractiveChallenge) bool { return true }, + PublicKeyHandler: func(_ gliderSSH.Context, _ gliderSSH.PublicKey) bool { return true }, + KeyboardInteractiveHandler: func(_ gliderSSH.Context, _ goSSH.KeyboardInteractiveChallenge) bool { return true }, // It is intentional that we do not check any credentials and accept all connections. // This allows all users to connect and clone repositories. However, the public key // is passed to handlers, so e.g. the push handler could check the key and reject the // push if it needs to. - } + } //exhaustruct:ignore server.AddHostKey(hostKey) -- 2.48.1