aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRunxi Yu <me@runxiyu.org>2025-03-22 13:17:55 +0800
committerRunxi Yu <me@runxiyu.org>2025-03-22 13:32:35 +0800
commit7a6f71ac73b41a38e9982bea3d46a87c327bd77a (patch)
tree92d5b637f57080af40c2f42834282df58a4e21a3
parentfedauth: Use NewRequestWithContext (diff)
downloadforge-7a6f71ac73b41a38e9982bea3d46a87c327bd77a.tar.gz
forge-7a6f71ac73b41a38e9982bea3d46a87c327bd77a.tar.zst
forge-7a6f71ac73b41a38e9982bea3d46a87c327bd77a.zip
Initial linting
-rw-r--r--.golangci.yaml30
-rw-r--r--fedauth.go11
-rw-r--r--git_hooks_handle.go13
-rw-r--r--git_misc.go15
-rw-r--r--http_error_page.go6
-rw-r--r--http_handle_gc.go2
-rw-r--r--http_handle_group_index.go5
-rw-r--r--http_handle_index.go2
-rw-r--r--http_handle_login.go5
-rw-r--r--http_handle_repo_index.go6
-rw-r--r--http_handle_repo_info.go4
-rw-r--r--http_handle_repo_log.go2
-rw-r--r--http_handle_users.go2
-rw-r--r--http_server.go4
-rw-r--r--http_template_funcs.go2
-rw-r--r--irc.go2
-rw-r--r--main.go9
-rw-r--r--resources.go5
-rwxr-xr-xscripts/lint6
-rw-r--r--ssh_handle_receive_pack.go4
-rw-r--r--ssh_handle_upload_pack.go4
-rw-r--r--ssh_server.go6
22 files changed, 90 insertions, 55 deletions
diff --git a/.golangci.yaml b/.golangci.yaml
new file mode 100644
index 0000000..71397cc
--- /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 3bd25d6..2012e19 100644
--- a/fedauth.go
+++ b/fedauth.go
@@ -24,13 +24,13 @@ func fedauth(ctx context.Context, userID int, service, remoteUsername, pubkey st
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 @@ func fedauth(ctx context.Context, userID int, service, remoteUsername, pubkey st
}
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 6a44784..ca46d61 100644
--- a/git_hooks_handle.go
+++ b/git_hooks_handle.go
@@ -55,7 +55,8 @@ func hooksHandler(conn net.Conn) {
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 @@ func hooksHandler(conn net.Conn) {
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 @@ func hooksHandler(conn net.Conn) {
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 @@ func hooksHandler(conn net.Conn) {
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 5b19965..cd2930e 100644
--- a/git_misc.go
+++ b/git_misc.go
@@ -74,7 +74,7 @@ type displayTreeEntry struct {
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 i
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 @@ func fmtCommitAsPatch(commit *object.Commit) (parentCommitHash plumbing.Hash, pa
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 @@ func fmtCommitAsPatch(commit *object.Commit) (parentCommitHash plumbing.Hash, pa
}
return
}
+
+var nullTree object.Tree
diff --git a/http_error_page.go b/http_error_page.go
index cb9e6ed..77fdc86 100644
--- a/http_error_page.go
+++ b/http_error_page.go
@@ -8,18 +8,18 @@ import (
)
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 b00ef8a..5f98d0e 100644
--- a/http_handle_gc.go
+++ b/http_handle_gc.go
@@ -8,7 +8,7 @@ import (
"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 22fb548..27d71c5 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 @@ func httpHandleGroupIndex(w http.ResponseWriter, r *http.Request, params map[str
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 @@ func httpHandleGroupIndex(w http.ResponseWriter, r *http.Request, params map[str
}
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 2fc99a6..360c033 100644
--- a/http_handle_index.go
+++ b/http_handle_index.go
@@ -22,7 +22,7 @@ func httpHandleIndex(w http.ResponseWriter, r *http.Request, params map[string]a
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 1c5c066..c6c1be1 100644
--- a/http_handle_login.go
+++ b/http_handle_login.go
@@ -26,7 +26,7 @@ func httpHandleLogin(w http.ResponseWriter, r *http.Request, params map[string]a
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 @@ func httpHandleLogin(w http.ResponseWriter, r *http.Request, params map[string]a
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 a22c75f..df1ee5e 100644
--- a/http_handle_repo_index.go
+++ b/http_handle_repo_index.go
@@ -14,7 +14,7 @@ import (
"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 @@ func httpHandleRepoIndex(w http.ResponseWriter, r *http.Request, params map[stri
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 @@ func httpHandleRepoIndex(w http.ResponseWriter, r *http.Request, params map[stri
}
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 abb971d..389936c 100644
--- a/http_handle_repo_info.go
+++ b/http_handle_repo_info.go
@@ -90,13 +90,13 @@ func httpHandleRepoInfo(w http.ResponseWriter, r *http.Request, params map[strin
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 39be231..2dec6bd 100644
--- a/http_handle_repo_log.go
+++ b/http_handle_repo_log.go
@@ -12,7 +12,7 @@ import (
)
// 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 c657bad..df0c99a 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 584c48d..983f579 100644
--- a/http_server.go
+++ b/http_server.go
@@ -36,9 +36,7 @@ func (router *forgeHTTPRouter) ServeHTTP(w http.ResponseWriter, r *http.Request)
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 2a7d826..8d67aff 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 e2b5037..4ca34d4 100644
--- a/irc.go
+++ b/irc.go
@@ -5,7 +5,7 @@ import (
"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 d2b1069..1530d90 100644
--- a/main.go
+++ b/main.go
@@ -9,6 +9,7 @@ import (
"net"
"net/http"
"syscall"
+ "time"
"go.lindenii.runxiyu.org/lindenii-common/clog"
)
@@ -86,9 +87,15 @@ func main() {
} 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 fb67102..dcfc2a5 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 14e5002..0000000
--- a/scripts/lint
+++ /dev/null
@@ -1,6 +0,0 @@
-#!/bin/sh
-
-# SPDX-License-Identifier: AGPL-3.0-only
-# SPDX-FileContributor: Runxi Yu <https://runxiyu.org>
-
-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 ed1f765..e42bca4 100644
--- a/ssh_handle_receive_pack.go
+++ b/ssh_handle_receive_pack.go
@@ -124,9 +124,7 @@ func sshHandleRecvPack(session gliderSSH.Session, pubkey, repoIdentifier string)
}
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 ab62533..f0edee2 100644
--- a/ssh_handle_upload_pack.go
+++ b/ssh_handle_upload_pack.go
@@ -31,9 +31,7 @@ func sshHandleUploadPack(session glider_ssh.Session, pubkey, repoIdentifier stri
}
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 58a5acd..56ed501 100644
--- a/ssh_server.go
+++ b/ssh_server.go
@@ -79,13 +79,13 @@ func serveSSH(listener net.Listener) 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)