chore(lint): fix lint issues

Ayman Bagabas created

Change summary

.golangci.yml                  |  2 
cmd/soft/main.go               |  4 +-
cmd/soft/serve/serve.go        |  6 ++--
git/attr.go                    |  4 +-
git/config.go                  |  4 +-
git/tree.go                    |  6 ---
pkg/access/access.go           |  2 
pkg/backend/lfs.go             |  2 
pkg/backend/repo.go            |  2 
pkg/config/config.go           |  6 ++--
pkg/config/file.go             |  2 
pkg/config/file_test.go        |  2 
pkg/cron/cron.go               |  2 
pkg/daemon/conn.go             |  6 ++--
pkg/daemon/daemon.go           | 15 +++++----
pkg/daemon/daemon_test.go      |  7 ++--
pkg/db/logger.go               |  8 ++++-
pkg/db/migrate/migrate.go      |  8 ++--
pkg/git/git.go                 |  2 
pkg/git/lfs.go                 |  2 
pkg/git/lfs_auth.go            |  2 
pkg/git/lfs_log.go             |  2 
pkg/git/service.go             |  2 
pkg/lfs/basic_transfer.go      |  4 +-
pkg/lfs/http_client.go         | 10 +++---
pkg/lfs/pointer.go             |  4 +-
pkg/lfs/scanner.go             | 16 +++++-----
pkg/ssh/cmd/git.go             |  2 
pkg/ssh/cmd/token.go           |  2 
pkg/ssh/middleware.go          |  4 +-
pkg/ssh/session_test.go        |  7 ++--
pkg/ssh/ssh.go                 | 15 ++++------
pkg/storage/local.go           |  2 
pkg/test/test.go               |  2 
pkg/ui/common/format.go        |  2 
pkg/ui/common/style.go         |  2 
pkg/ui/pages/repo/refs.go      |  5 ++-
pkg/ui/pages/repo/repo.go      |  2 
pkg/ui/pages/repo/stashitem.go |  2 
pkg/web/git.go                 | 10 +++---
pkg/web/git_lfs.go             | 10 +++---
pkg/web/logging.go             | 15 ++++-----
pkg/web/util.go                |  2 
pkg/webhook/ssrf_test.go       |  2 
pkg/webhook/validator.go       | 10 +++++-
pkg/webhook/webhook.go         |  6 ++--
testscript/script_test.go      | 51 ++++++++++++++++-------------------
47 files changed, 143 insertions(+), 142 deletions(-)

Detailed changes

.golangci.yml 🔗

@@ -19,7 +19,6 @@ linters:
     # - revive
     - rowserrcheck
     - sqlclosecheck
-    - staticcheck
     - tparallel
     # - unconvert
     # - unparam
@@ -29,6 +28,7 @@ linters:
     - errcheck
     - ineffassign
     - unused
+    - staticcheck
   exclusions:
     generated: lax
     presets:

cmd/soft/main.go 🔗

@@ -7,8 +7,8 @@ import (
 	"runtime/debug"
 	"strconv"
 
-	"github.com/charmbracelet/colorprofile"
 	"charm.land/log/v2"
+	"github.com/charmbracelet/colorprofile"
 	"github.com/charmbracelet/soft-serve/cmd/soft/admin"
 	"github.com/charmbracelet/soft-serve/cmd/soft/browse"
 	"github.com/charmbracelet/soft-serve/cmd/soft/hook"
@@ -118,7 +118,7 @@ func main() {
 
 	ctx = log.WithContext(ctx, logger)
 	if f != nil {
-		defer f.Close() // nolint: errcheck
+		defer f.Close() //nolint: errcheck
 	}
 
 	// Set global logger

cmd/soft/serve/serve.go 🔗

@@ -50,10 +50,10 @@ var (
 			// Create custom hooks directory if it doesn't exist
 			customHooksPath := filepath.Join(cfg.DataPath, "hooks")
 			if _, err := os.Stat(customHooksPath); err != nil && os.IsNotExist(err) {
-				os.MkdirAll(customHooksPath, os.ModePerm) // nolint: errcheck
+				os.MkdirAll(customHooksPath, os.ModePerm) //nolint: errcheck
 				// Generate update hook example without executable permissions
 				hookPath := filepath.Join(customHooksPath, "update.sample")
-				// nolint: gosec
+				//nolint: gosec
 				if err := os.WriteFile(hookPath, []byte(updateHookExample), 0o744); err != nil {
 					return fmt.Errorf("failed to generate update hook example: %w", err)
 				}
@@ -62,7 +62,7 @@ var (
 			// Create log directory if it doesn't exist
 			logPath := filepath.Join(cfg.DataPath, "log")
 			if _, err := os.Stat(logPath); err != nil && os.IsNotExist(err) {
-				os.MkdirAll(logPath, os.ModePerm) // nolint: errcheck
+				os.MkdirAll(logPath, os.ModePerm) //nolint: errcheck
 			}
 
 			db := db.FromContext(ctx)

git/attr.go 🔗

@@ -18,10 +18,10 @@ type Attribute struct {
 // CheckAttributes checks the attributes of the given ref and path.
 func (r *Repository) CheckAttributes(ref *Reference, path string) ([]Attribute, error) {
 	rnd := rand.NewSource(time.Now().UnixNano())
-	fn := "soft-serve-index-" + strconv.Itoa(rand.New(rnd).Int()) // nolint: gosec
+	fn := "soft-serve-index-" + strconv.Itoa(rand.New(rnd).Int()) //nolint: gosec
 	tmpindex := filepath.Join(os.TempDir(), fn)
 
-	defer os.Remove(tmpindex) // nolint: errcheck
+	defer os.Remove(tmpindex) //nolint: errcheck
 
 	readTree := NewCommand("read-tree", "--reset", "-i", ref.Name().String()).
 		AddEnvs("GIT_INDEX_FILE=" + tmpindex)

git/config.go 🔗

@@ -15,7 +15,7 @@ func (r *Repository) Config() (*gcfg.Config, error) {
 		return nil, err
 	}
 
-	defer f.Close() // nolint: errcheck
+	defer f.Close() //nolint: errcheck
 	d := gcfg.NewDecoder(f)
 	cfg := gcfg.New()
 	if err := d.Decode(cfg); err != nil {
@@ -33,7 +33,7 @@ func (r *Repository) SetConfig(cfg *gcfg.Config) error {
 		return err
 	}
 
-	defer f.Close() // nolint: errcheck
+	defer f.Close() //nolint: errcheck
 	e := gcfg.NewEncoder(f)
 	return e.Encode(cfg)
 }

git/tree.go 🔗

@@ -128,11 +128,7 @@ const sniffLen = 8000
 func IsBinary(r io.Reader) (bool, error) {
 	reader := bufio.NewReader(r)
 	c := 0
-	for {
-		if c == sniffLen {
-			break
-		}
-
+	for c < sniffLen {
 		b, err := reader.ReadByte()
 		if err == io.EOF {
 			break

pkg/access/access.go 🔗

@@ -6,7 +6,7 @@ import (
 )
 
 // AccessLevel is the level of access allowed to a repo.
-type AccessLevel int // nolint: revive
+type AccessLevel int //nolint: revive
 
 const (
 	// NoAccess does not allow access to the repo.

pkg/backend/lfs.go 🔗

@@ -39,7 +39,7 @@ func StoreRepoMissingLFSObjects(ctx context.Context, repo proto.Repository, dbx
 				return objectError
 			}
 
-			defer content.Close() // nolint: errcheck
+			defer content.Close() //nolint: errcheck
 			return dbx.TransactionContext(ctx, func(tx *db.Tx) error {
 				if err := store.CreateLFSObject(ctx, tx, repo.ID(), p.Oid, p.Size); err != nil {
 					return db.WrapError(err)

pkg/backend/repo.go 🔗

@@ -753,7 +753,7 @@ func readOneline(path string) (string, error) {
 		return "", err
 	}
 
-	defer f.Close() // nolint: errcheck
+	defer f.Close() //nolint: errcheck
 	s := bufio.NewScanner(f)
 	s.Scan()
 	return s.Text(), s.Err()

pkg/config/config.go 🔗

@@ -246,7 +246,7 @@ func parseFile(cfg *Config, path string) error {
 		return err
 	}
 
-	defer f.Close() // nolint: errcheck
+	defer f.Close() //nolint: errcheck
 	if err := yaml.NewDecoder(f).Decode(cfg); err != nil {
 		return fmt.Errorf("decode config: %w", err)
 	}
@@ -301,7 +301,7 @@ func writeConfig(cfg *Config, path string) error {
 	if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
 		return err
 	}
-	return os.WriteFile(path, []byte(newConfigFile(cfg)), 0o644) // nolint: errcheck, gosec
+	return os.WriteFile(path, []byte(newConfigFile(cfg)), 0o644) //nolint: errcheck, gosec
 }
 
 // WriteConfig writes the configuration to the default file.
@@ -322,7 +322,7 @@ func DefaultDataPath() string {
 }
 
 // ConfigPath returns the path to the config file.
-func (c *Config) ConfigPath() string { // nolint:revive
+func (c *Config) ConfigPath() string { //nolint:revive
 	// If we have a custom config location set, then use that.
 	if path := os.Getenv("SOFT_SERVE_CONFIG_LOCATION"); exist(path) {
 		return path

pkg/config/file.go 🔗

@@ -151,6 +151,6 @@ jobs:
 
 func newConfigFile(cfg *Config) string {
 	var b bytes.Buffer
-	configFileTmpl.Execute(&b, cfg) // nolint: errcheck
+	configFileTmpl.Execute(&b, cfg) //nolint: errcheck
 	return b.String()
 }

pkg/config/file_test.go 🔗

@@ -6,7 +6,7 @@ func TestNewConfigFile(t *testing.T) {
 	for _, cfg := range []*Config{
 		nil,
 		DefaultConfig(),
-		&Config{},
+		{},
 	} {
 		if s := newConfigFile(cfg); s == "" {
 			t.Errorf("newConfigFile(nil) => %q, want non-empty string", s)

pkg/cron/cron.go 🔗

@@ -39,7 +39,7 @@ func NewScheduler(ctx context.Context) *Scheduler {
 
 // Shutdonw gracefully shuts down the Scheduler.
 func (s *Scheduler) Shutdown() {
-	ctx, cancel := context.WithTimeout(s.Cron.Stop(), 30*time.Second)
+	ctx, cancel := context.WithTimeout(s.Cron.Stop(), 30*time.Second) //nolint:staticcheck
 	defer func() { cancel() }()
 	<-ctx.Done()
 }

pkg/daemon/conn.go 🔗

@@ -91,15 +91,15 @@ func (c *serverConn) updateDeadline() {
 		initTimeout := time.Now().Add(c.initTimeout)
 		c.initTimeout = 0
 		if initTimeout.Unix() < c.maxDeadline.Unix() || c.maxDeadline.IsZero() {
-			c.Conn.SetDeadline(initTimeout) // nolint: errcheck
+			c.Conn.SetDeadline(initTimeout) //nolint: errcheck
 			return
 		}
 	case c.idleTimeout > 0:
 		idleDeadline := time.Now().Add(c.idleTimeout)
 		if idleDeadline.Unix() < c.maxDeadline.Unix() || c.maxDeadline.IsZero() {
-			c.Conn.SetDeadline(idleDeadline) // nolint: errcheck
+			c.Conn.SetDeadline(idleDeadline) //nolint: errcheck
 			return
 		}
 	}
-	c.Conn.SetDeadline(c.maxDeadline) // nolint: errcheck
+	c.Conn.SetDeadline(c.maxDeadline) //nolint: errcheck
 }

pkg/daemon/daemon.go 🔗

@@ -58,7 +58,7 @@ type GitDaemon struct {
 	liMu      sync.Mutex
 }
 
-// NewDaemon returns a new Git daemon.
+// NewGitDaemon returns a new Git daemon.
 func NewGitDaemon(ctx context.Context) (*GitDaemon, error) {
 	cfg := config.FromContext(ctx)
 	addr := cfg.Git.ListenAddr
@@ -79,7 +79,8 @@ func (d *GitDaemon) ListenAndServe() error {
 	if d.done.Load() {
 		return ErrServerClosed
 	}
-	listener, err := net.Listen("tcp", d.addr)
+	var cfg net.ListenConfig
+	listener, err := cfg.Listen(d.ctx, "tcp", d.addr)
 	if err != nil {
 		return err
 	}
@@ -108,7 +109,7 @@ func (d *GitDaemon) Serve(listener net.Listener) error {
 			default:
 				d.logger.Debugf("git: error accepting connection: %v", err)
 			}
-			if ne, ok := err.(net.Error); ok && ne.Temporary() { // nolint: staticcheck
+			if ne, ok := err.(net.Error); ok && ne.Temporary() {
 				if tempDelay == 0 {
 					tempDelay = 5 * time.Millisecond
 				} else {
@@ -139,7 +140,7 @@ func (d *GitDaemon) Serve(listener net.Listener) error {
 }
 
 func (d *GitDaemon) fatal(c net.Conn, err error) {
-	git.WritePktlineErr(c, err) // nolint: errcheck
+	git.WritePktlineErr(c, err) //nolint: errcheck
 	if err := c.Close(); err != nil {
 		d.logger.Debugf("git: error closing connection: %v", err)
 	}
@@ -160,7 +161,7 @@ func (d *GitDaemon) handleClient(conn net.Conn) {
 	}
 	d.conns.Add(c)
 	defer func() {
-		d.conns.Close(c) // nolint: errcheck
+		d.conns.Close(c) //nolint: errcheck
 	}()
 
 	errc := make(chan error, 1)
@@ -213,7 +214,7 @@ func (d *GitDaemon) handleClient(conn net.Conn) {
 
 		opts := bytes.SplitN(split[1], []byte{0}, 3)
 		if len(opts) < 2 {
-			d.fatal(c, git.ErrInvalidRequest) // nolint: errcheck
+			d.fatal(c, git.ErrInvalidRequest) //nolint: errcheck
 			return
 		}
 
@@ -317,7 +318,7 @@ func (d *GitDaemon) handleClient(conn net.Conn) {
 // Close closes the underlying listener.
 func (d *GitDaemon) Close() error {
 	err := d.closeListener()
-	d.conns.CloseAll() // nolint: errcheck
+	d.conns.CloseAll() //nolint: errcheck
 	return err
 }
 

pkg/daemon/daemon_test.go 🔗

@@ -45,7 +45,7 @@ func TestMain(m *testing.M) {
 	if err != nil {
 		log.Fatal(err)
 	}
-	defer dbx.Close() // nolint: errcheck
+	defer dbx.Close() //nolint: errcheck
 	if err := migrate.Migrate(ctx, dbx); err != nil {
 		log.Fatal(err)
 	}
@@ -74,8 +74,9 @@ func TestIdleTimeout(t *testing.T) {
 	var err error
 	var c net.Conn
 	var tries int
+	var dialer net.Dialer
 	for {
-		c, err = net.Dial("tcp", testDaemon.addr)
+		c, err = dialer.DialContext(t.Context(), "tcp", testDaemon.addr)
 		if err != nil && tries >= 3 {
 			t.Fatalf("failed to connect to daemon after %d tries: %v", tries, err)
 		}
@@ -93,7 +94,7 @@ func TestIdleTimeout(t *testing.T) {
 }
 
 func TestInvalidRepo(t *testing.T) {
-	c, err := net.Dial("tcp", testDaemon.addr)
+	c, err := net.Dial("tcp", testDaemon.addr) //nolint:noctx
 	if err != nil {
 		t.Fatalf("failed to connect to daemon: %v", err)
 	}

pkg/db/logger.go 🔗

@@ -43,9 +43,11 @@ func (d *DB) QueryRowx(query string, args ...interface{}) *sqlx.Row {
 }
 
 // Exec is a wrapper around sqlx.Exec that logs the query and arguments.
+//
+// Deprecated: Use [DB.ExecContext] instead.
 func (d *DB) Exec(query string, args ...interface{}) (sql.Result, error) {
 	trace(d.logger, query, args...)
-	return d.DB.Exec(query, args...)
+	return d.DB.Exec(query, args...) //nolint:noctx
 }
 
 // SelectContext is a wrapper around sqlx.SelectContext that logs the query and arguments.
@@ -103,9 +105,11 @@ func (t *Tx) QueryRowx(query string, args ...interface{}) *sqlx.Row {
 }
 
 // Exec is a wrapper around sqlx.Exec that logs the query and arguments.
+//
+// Deprecated: Use [Tx.ExecContext] instead.
 func (t *Tx) Exec(query string, args ...interface{}) (sql.Result, error) {
 	trace(t.logger, query, args...)
-	return t.Tx.Exec(query, args...)
+	return t.Tx.Exec(query, args...) //nolint:noctx
 }
 
 // SelectContext is a wrapper around sqlx.SelectContext that logs the query and arguments.

pkg/db/migrate/migrate.go 🔗

@@ -11,7 +11,7 @@ import (
 )
 
 // MigrateFunc is a function that executes a migration.
-type MigrateFunc func(ctx context.Context, tx *db.Tx) error // nolint:revive
+type MigrateFunc func(ctx context.Context, tx *db.Tx) error //nolint:revive
 
 // Migration is a struct that contains the name of the migration and the
 // function to execute it.
@@ -64,7 +64,7 @@ func Migrate(ctx context.Context, dbx *db.DB) error {
 	logger := log.FromContext(ctx).WithPrefix("migrate")
 	return dbx.TransactionContext(ctx, func(tx *db.Tx) error {
 		if !hasTable(tx, "migrations") {
-			if _, err := tx.Exec(Migrations{}.schema(tx.DriverName())); err != nil {
+			if _, err := tx.ExecContext(ctx, Migrations{}.schema(tx.DriverName())); err != nil {
 				return err
 			}
 		}
@@ -86,7 +86,7 @@ func Migrate(ctx context.Context, dbx *db.DB) error {
 				return err
 			}
 
-			if _, err := tx.Exec(tx.Rebind("INSERT INTO migrations (name, version) VALUES (?, ?)"), m.Name, m.Version); err != nil {
+			if _, err := tx.ExecContext(ctx, tx.Rebind("INSERT INTO migrations (name, version) VALUES (?, ?)"), m.Name, m.Version); err != nil {
 				return err
 			}
 		}
@@ -116,7 +116,7 @@ func Rollback(ctx context.Context, dbx *db.DB) error {
 			return err
 		}
 
-		if _, err := tx.Exec(tx.Rebind("DELETE FROM migrations WHERE version = ?"), migrs.Version); err != nil {
+		if _, err := tx.ExecContext(ctx, tx.Rebind("DELETE FROM migrations WHERE version = ?"), migrs.Version); err != nil {
 			return err
 		}
 

pkg/git/git.go 🔗

@@ -8,8 +8,8 @@ import (
 	"path/filepath"
 	"strings"
 
-	gitm "github.com/aymanbagabas/git-module"
 	"charm.land/log/v2"
+	gitm "github.com/aymanbagabas/git-module"
 	"github.com/charmbracelet/soft-serve/git"
 	"github.com/go-git/go-git/v5/plumbing/format/pktline"
 )

pkg/git/lfs.go 🔗

@@ -11,8 +11,8 @@ import (
 	"strconv"
 	"time"
 
-	"github.com/charmbracelet/git-lfs-transfer/transfer"
 	"charm.land/log/v2"
+	"github.com/charmbracelet/git-lfs-transfer/transfer"
 	"github.com/charmbracelet/soft-serve/pkg/config"
 	"github.com/charmbracelet/soft-serve/pkg/db"
 	"github.com/charmbracelet/soft-serve/pkg/db/models"

pkg/git/lfs_auth.go 🔗

@@ -15,7 +15,7 @@ import (
 	"github.com/golang-jwt/jwt/v5"
 )
 
-// LFSAuthenticate implements teh Git LFS SSH authentication command.
+// LFSAuthenticate implements the Git LFS SSH authentication command.
 // Context must have *config.Config, *log.Logger, proto.User.
 // cmd.Args should have the repo path and operation as arguments.
 func LFSAuthenticate(ctx context.Context, cmd ServiceCommand) error {

pkg/git/lfs_log.go 🔗

@@ -1,8 +1,8 @@
 package git
 
 import (
-	"github.com/charmbracelet/git-lfs-transfer/transfer"
 	"charm.land/log/v2"
+	"github.com/charmbracelet/git-lfs-transfer/transfer"
 )
 
 type lfsLogger struct {

pkg/git/service.go 🔗

@@ -124,7 +124,7 @@ func gitServiceHandler(ctx context.Context, svc Service, scmd ServiceCommand) er
 	// stdin
 	if scmd.Stdin != nil {
 		go func() {
-			defer stdin.Close() // nolint: errcheck
+			defer stdin.Close() //nolint: errcheck
 			if _, err := io.Copy(stdin, scmd.Stdin); err != nil {
 				log.Errorf("gitServiceHandler: failed to copy stdin: %v", err)
 			}

pkg/lfs/basic_transfer.go 🔗

@@ -105,11 +105,11 @@ func (a *BasicTransferAdapter) performRequest(ctx context.Context, method string
 }
 
 func handleErrorResponse(resp *http.Response) error {
-	defer resp.Body.Close() // nolint: errcheck
+	defer resp.Body.Close() //nolint: errcheck
 
 	er, err := decodeResponseError(resp.Body)
 	if err != nil {
-		return fmt.Errorf("Request failed with status %s", resp.Status)
+		return fmt.Errorf("request failed with status %s", resp.Status)
 	}
 	return errors.New(er.Message)
 }

pkg/lfs/http_client.go 🔗

@@ -86,10 +86,10 @@ func (c *httpClient) batch(ctx context.Context, operation string, objects []Poin
 		logger.Errorf("Error while processing request: %v", err)
 		return nil, err
 	}
-	defer res.Body.Close() // nolint: errcheck
+	defer res.Body.Close() //nolint: errcheck
 
 	if res.StatusCode != http.StatusOK {
-		return nil, fmt.Errorf("Unexpected server response: %s", res.Status)
+		return nil, fmt.Errorf("unexpected server response: %s", res.Status)
 	}
 
 	var response BatchResponse
@@ -152,7 +152,7 @@ func (c *httpClient) performOperation(ctx context.Context, objects []Pointer, dc
 			link, ok := object.Actions[ActionUpload]
 			if !ok {
 				logger.Debugf("%+v", object)
-				return errors.New("Missing action 'upload'")
+				return errors.New("missing action 'upload'")
 			}
 
 			content, err := uc(object.Pointer, nil)
@@ -162,7 +162,7 @@ func (c *httpClient) performOperation(ctx context.Context, objects []Pointer, dc
 
 			err = transferAdapter.Upload(ctx, object.Pointer, content, link)
 
-			content.Close() // nolint: errcheck
+			content.Close() //nolint: errcheck
 
 			if err != nil {
 				return err
@@ -178,7 +178,7 @@ func (c *httpClient) performOperation(ctx context.Context, objects []Pointer, dc
 			link, ok := object.Actions[ActionDownload]
 			if !ok {
 				logger.Debugf("%+v", object)
-				return errors.New("Missing action 'download'")
+				return errors.New("missing action 'download'")
 			}
 
 			content, err := transferAdapter.Download(ctx, object.Pointer, link)

pkg/lfs/pointer.go 🔗

@@ -28,10 +28,10 @@ const (
 
 var (
 	// ErrMissingPrefix occurs if the content lacks the LFS prefix
-	ErrMissingPrefix = errors.New("Content lacks the LFS prefix")
+	ErrMissingPrefix = errors.New("content lacks the LFS prefix")
 
 	// ErrInvalidStructure occurs if the content has an invalid structure
-	ErrInvalidStructure = errors.New("Content has an invalid structure")
+	ErrInvalidStructure = errors.New("content has an invalid structure")
 
 	// ErrInvalidOIDFormat occurs if the oid has an invalid format
 	ErrInvalidOIDFormat = errors.New("OID has an invalid format")

pkg/lfs/scanner.go 🔗

@@ -51,7 +51,7 @@ func SearchPointerBlobs(ctx context.Context, repo *git.Repository, pointerChan c
 
 func createPointerResultsFromCatFileBatch(ctx context.Context, catFileBatchReader *io.PipeReader, wg *sync.WaitGroup, pointerChan chan<- PointerBlob) {
 	defer wg.Done()
-	defer catFileBatchReader.Close() // nolint: errcheck
+	defer catFileBatchReader.Close() //nolint: errcheck
 
 	bufferedReader := bufio.NewReader(catFileBatchReader)
 	buf := make([]byte, 1025)
@@ -104,8 +104,8 @@ loop:
 
 func catFileBatch(ctx context.Context, shasToBatchReader *io.PipeReader, catFileBatchWriter *io.PipeWriter, wg *sync.WaitGroup, basePath string) {
 	defer wg.Done()
-	defer shasToBatchReader.Close()  // nolint: errcheck
-	defer catFileBatchWriter.Close() // nolint: errcheck
+	defer shasToBatchReader.Close()  //nolint: errcheck
+	defer catFileBatchWriter.Close() //nolint: errcheck
 
 	stderr := new(bytes.Buffer)
 	var errbuf strings.Builder
@@ -122,7 +122,7 @@ func catFileBatch(ctx context.Context, shasToBatchReader *io.PipeReader, catFile
 
 func blobsLessThan1024FromCatFileBatchCheck(catFileCheckReader *io.PipeReader, shasToBatchWriter *io.PipeWriter, wg *sync.WaitGroup) {
 	defer wg.Done()
-	defer catFileCheckReader.Close() // nolint: errcheck
+	defer catFileCheckReader.Close() //nolint: errcheck
 	scanner := bufio.NewScanner(catFileCheckReader)
 	defer func() {
 		_ = shasToBatchWriter.CloseWithError(scanner.Err())
@@ -154,8 +154,8 @@ func blobsLessThan1024FromCatFileBatchCheck(catFileCheckReader *io.PipeReader, s
 
 func catFileBatchCheck(ctx context.Context, shasToCheckReader *io.PipeReader, catFileCheckWriter *io.PipeWriter, wg *sync.WaitGroup, basePath string) {
 	defer wg.Done()
-	defer shasToCheckReader.Close()  // nolint: errcheck
-	defer catFileCheckWriter.Close() // nolint: errcheck
+	defer shasToCheckReader.Close()  //nolint: errcheck
+	defer catFileCheckWriter.Close() //nolint: errcheck
 
 	stderr := new(bytes.Buffer)
 	var errbuf strings.Builder
@@ -172,7 +172,7 @@ func catFileBatchCheck(ctx context.Context, shasToCheckReader *io.PipeReader, ca
 
 func blobsFromRevListObjects(revListReader *io.PipeReader, shasToCheckWriter *io.PipeWriter, wg *sync.WaitGroup) {
 	defer wg.Done()
-	defer revListReader.Close() // nolint: errcheck
+	defer revListReader.Close() //nolint: errcheck
 	scanner := bufio.NewScanner(revListReader)
 	defer func() {
 		_ = shasToCheckWriter.CloseWithError(scanner.Err())
@@ -201,7 +201,7 @@ func blobsFromRevListObjects(revListReader *io.PipeReader, shasToCheckWriter *io
 
 func revListAllObjects(ctx context.Context, revListWriter *io.PipeWriter, wg *sync.WaitGroup, basePath string, errChan chan<- error) {
 	defer wg.Done()
-	defer revListWriter.Close() // nolint: errcheck
+	defer revListWriter.Close() //nolint: errcheck
 
 	stderr := new(bytes.Buffer)
 	var errbuf strings.Builder

pkg/ssh/cmd/git.go 🔗

@@ -250,7 +250,7 @@ func gitRunE(cmd *cobra.Command, args []string) error {
 			defer func() {
 				if repo == nil {
 					// If the repo was created, but the request failed, delete it.
-					be.DeleteRepository(ctx, name) // nolint: errcheck
+					be.DeleteRepository(ctx, name) //nolint: errcheck
 				}
 			}()
 

pkg/ssh/cmd/token.go 🔗

@@ -5,8 +5,8 @@ import (
 	"strings"
 	"time"
 
-	"github.com/caarlos0/duration"
 	"charm.land/lipgloss/v2/table"
+	"github.com/caarlos0/duration"
 	"github.com/charmbracelet/soft-serve/pkg/backend"
 	"github.com/charmbracelet/soft-serve/pkg/proto"
 	"github.com/dustin/go-humanize"

pkg/ssh/middleware.go 🔗

@@ -5,6 +5,7 @@ import (
 	"time"
 
 	"charm.land/log/v2"
+	"charm.land/wish/v2"
 	"github.com/charmbracelet/soft-serve/pkg/backend"
 	"github.com/charmbracelet/soft-serve/pkg/config"
 	"github.com/charmbracelet/soft-serve/pkg/db"
@@ -13,7 +14,6 @@ import (
 	"github.com/charmbracelet/soft-serve/pkg/sshutils"
 	"github.com/charmbracelet/soft-serve/pkg/store"
 	"github.com/charmbracelet/ssh"
-	"charm.land/wish/v2"
 	"github.com/prometheus/client_golang/prometheus"
 	"github.com/prometheus/client_golang/prometheus/promauto"
 	"github.com/spf13/cobra"
@@ -135,7 +135,7 @@ func CommandMiddleware(sh ssh.Handler) ssh.Handler {
 		rootCmd.SetContext(ctx)
 
 		if err := rootCmd.ExecuteContext(ctx); err != nil {
-			s.Exit(1) // nolint: errcheck
+			s.Exit(1) //nolint: errcheck
 			return
 		}
 	}

pkg/ssh/session_test.go 🔗

@@ -9,6 +9,8 @@ import (
 	"time"
 
 	"charm.land/log/v2"
+	bm "charm.land/wish/v2/bubbletea"
+	"charm.land/wish/v2/testsession"
 	"github.com/charmbracelet/soft-serve/pkg/backend"
 	"github.com/charmbracelet/soft-serve/pkg/config"
 	"github.com/charmbracelet/soft-serve/pkg/db"
@@ -17,8 +19,6 @@ import (
 	"github.com/charmbracelet/soft-serve/pkg/store/database"
 	"github.com/charmbracelet/soft-serve/pkg/test"
 	"github.com/charmbracelet/ssh"
-	bm "charm.land/wish/v2/bubbletea"
-	"charm.land/wish/v2/testsession"
 	"github.com/matryer/is"
 	gossh "golang.org/x/crypto/ssh"
 	_ "modernc.org/sqlite" // sqlite driver
@@ -36,7 +36,7 @@ func TestSession(t *testing.T) {
 		go func() {
 			time.Sleep(1 * time.Second)
 			// s.Signal(gossh.SIGTERM)
-			s.Close() // nolint: errcheck
+			s.Close() //nolint: errcheck
 		}()
 		t.Log("waiting for session to exit")
 		_, err = s.Output("test")
@@ -76,7 +76,6 @@ func setup(tb testing.TB) (*gossh.Session, func() error) {
 	dbstore := database.New(ctx, dbx)
 	ctx = store.WithContext(ctx, dbstore)
 	be := backend.New(ctx, cfg, dbx, dbstore)
-	ctx = backend.WithContext(ctx, be)
 	return testsession.New(tb, &ssh.Server{
 		Handler: ContextMiddleware(cfg, dbx, dbstore, be, log.Default())(bm.MiddlewareWithProgramHandler(SessionHandler)(func(s ssh.Session) {
 			_, _, active := s.Pty()

pkg/ssh/ssh.go 🔗

@@ -8,17 +8,17 @@ import (
 	"strconv"
 	"time"
 
-	"github.com/charmbracelet/keygen"
 	"charm.land/log/v2"
+	"charm.land/wish/v2"
+	bm "charm.land/wish/v2/bubbletea"
+	rm "charm.land/wish/v2/recover"
+	"github.com/charmbracelet/keygen"
 	"github.com/charmbracelet/soft-serve/pkg/backend"
 	"github.com/charmbracelet/soft-serve/pkg/config"
 	"github.com/charmbracelet/soft-serve/pkg/db"
 	"github.com/charmbracelet/soft-serve/pkg/proto"
 	"github.com/charmbracelet/soft-serve/pkg/store"
 	"github.com/charmbracelet/ssh"
-	"charm.land/wish/v2"
-	bm "charm.land/wish/v2/bubbletea"
-	rm "charm.land/wish/v2/recover"
 	"github.com/prometheus/client_golang/prometheus"
 	"github.com/prometheus/client_golang/prometheus/promauto"
 	gossh "golang.org/x/crypto/ssh"
@@ -41,7 +41,7 @@ var (
 )
 
 // SSHServer is a SSH server that implements the git protocol.
-type SSHServer struct { // nolint: revive
+type SSHServer struct { //nolint: revive
 	srv    *ssh.Server
 	cfg    *config.Config
 	be     *backend.Backend
@@ -157,12 +157,9 @@ func initializePermissions(ctx ssh.Context) {
 	if perms.Extensions == nil {
 		perms.Extensions = make(map[string]string)
 	}
-	if perms.Permissions.Extensions == nil {
-		perms.Permissions.Extensions = make(map[string]string)
-	}
 }
 
-// PublicKeyAuthHandler handles public key authentication.
+// PublicKeyHandler handles public key authentication.
 func (s *SSHServer) PublicKeyHandler(ctx ssh.Context, pk ssh.PublicKey) (allowed bool) {
 	if pk == nil {
 		return false

pkg/storage/local.go 🔗

@@ -51,7 +51,7 @@ func (l *LocalStorage) Put(name string, r io.Reader) (int64, error) {
 	if err != nil {
 		return 0, err
 	}
-	defer f.Close() // nolint: errcheck
+	defer f.Close() //nolint: errcheck
 	return io.Copy(f, r)
 }
 

pkg/test/test.go 🔗

@@ -13,7 +13,7 @@ var (
 // RandomPort returns a random port number.
 // This is mainly used for testing.
 func RandomPort() int {
-	addr, _ := net.Listen("tcp", ":0") //nolint:gosec
+	addr, _ := net.Listen("tcp", ":0") //nolint:gosec,noctx
 	_ = addr.Close()
 	port := addr.Addr().(*net.TCPAddr).Port
 	lock.Lock()

pkg/ui/common/format.go 🔗

@@ -5,8 +5,8 @@ import (
 	"strconv"
 	"strings"
 
-	"github.com/alecthomas/chroma/v2/lexers"
 	gansi "charm.land/glamour/v2/ansi"
+	"github.com/alecthomas/chroma/v2/lexers"
 	"github.com/charmbracelet/soft-serve/pkg/ui/styles"
 )
 

pkg/ui/common/style.go 🔗

@@ -1,9 +1,9 @@
 package common
 
 import (
-	"github.com/charmbracelet/colorprofile"
 	gansi "charm.land/glamour/v2/ansi"
 	"charm.land/glamour/v2/styles"
+	"github.com/charmbracelet/colorprofile"
 )
 
 // DefaultColorProfile is the default color profile used by the SSH server.

pkg/ui/pages/repo/refs.go 🔗

@@ -64,9 +64,10 @@ func (r *Refs) Path() string {
 
 // TabName returns the name of the tab.
 func (r *Refs) TabName() string {
-	if r.refPrefix == git.RefsHeads {
+	switch r.refPrefix {
+	case git.RefsHeads:
 		return "Branches"
-	} else if r.refPrefix == git.RefsTags {
+	case git.RefsTags:
 		return "Tags"
 	}
 	return "Refs"

pkg/ui/pages/repo/repo.go 🔗

@@ -32,7 +32,7 @@ type EmptyRepoMsg struct{}
 type CopyURLMsg struct{}
 
 // RepoMsg is a message that contains a git.Repository.
-type RepoMsg proto.Repository // nolint:revive
+type RepoMsg proto.Repository //nolint:revive
 
 // GoBackMsg is a message to go back to the previous view.
 type GoBackMsg struct{}

pkg/ui/pages/repo/stashitem.go 🔗

@@ -4,10 +4,10 @@ import (
 	"fmt"
 	"io"
 
-	gitm "github.com/aymanbagabas/git-module"
 	"charm.land/bubbles/v2/key"
 	"charm.land/bubbles/v2/list"
 	tea "charm.land/bubbletea/v2"
+	gitm "github.com/aymanbagabas/git-module"
 	"github.com/charmbracelet/soft-serve/pkg/ui/common"
 )
 

pkg/web/git.go 🔗

@@ -434,7 +434,7 @@ func serviceRpc(w http.ResponseWriter, r *http.Request) {
 			renderInternalServerError(w, r)
 			return
 		}
-		defer reader.Close() // nolint: errcheck
+		defer reader.Close() //nolint: errcheck
 	}
 
 	cmd.Stdin = reader
@@ -459,7 +459,7 @@ type flushResponseWriter struct {
 }
 
 func (f *flushResponseWriter) ReadFrom(r io.Reader) (int64, error) {
-	flusher := http.NewResponseController(f.ResponseWriter) // nolint: bodyclose
+	flusher := http.NewResponseController(f.ResponseWriter)
 
 	var n int64
 	p := make([]byte, 1024)
@@ -537,12 +537,12 @@ func getInfoRefs(w http.ResponseWriter, r *http.Request) {
 		w.Header().Set("Content-Type", fmt.Sprintf("application/x-%s-advertisement", service))
 		w.WriteHeader(http.StatusOK)
 		if version < 2 {
-			git.WritePktline(w, "# service="+service.String()) // nolint: errcheck
+			git.WritePktline(w, "# service="+service.String()) //nolint: errcheck
 		}
-		w.Write(refs.Bytes()) // nolint: errcheck
+		w.Write(refs.Bytes()) //nolint: errcheck
 	} else {
 		// Dumb HTTP
-		updateServerInfo(ctx, dir) // nolint: errcheck
+		updateServerInfo(ctx, dir) //nolint: errcheck
 		hdrNocache(w)
 		sendFile("text/plain; charset=utf-8", w, r)
 	}

pkg/web/git_lfs.go 🔗

@@ -41,7 +41,7 @@ func serviceLfsBatch(w http.ResponseWriter, r *http.Request) {
 	}
 
 	var batchRequest lfs.BatchRequest
-	defer r.Body.Close() // nolint: errcheck
+	defer r.Body.Close() //nolint: errcheck
 	if err := json.NewDecoder(r.Body).Decode(&batchRequest); err != nil {
 		logger.Errorf("error decoding json: %s", err)
 		renderJSON(w, http.StatusUnprocessableEntity, lfs.ErrorResponse{
@@ -282,7 +282,7 @@ func serviceLfsBasicDownload(w http.ResponseWriter, r *http.Request) {
 
 	w.Header().Set("Content-Type", "application/octet-stream")
 	w.Header().Set("Content-Length", strconv.FormatInt(obj.Size, 10))
-	defer f.Close() // nolint: errcheck
+	defer f.Close() //nolint: errcheck
 	if _, err := io.Copy(w, f); err != nil {
 		logger.Error("error copying object to response", "oid", oid, "err", err)
 		renderJSON(w, http.StatusInternalServerError, lfs.ErrorResponse{
@@ -313,7 +313,7 @@ func serviceLfsBasicUpload(w http.ResponseWriter, r *http.Request) {
 	strg := storage.NewLocalStorage(filepath.Join(cfg.DataPath, "lfs", repoID))
 	name := mux.Vars(r)["repo"]
 
-	defer r.Body.Close() // nolint: errcheck
+	defer r.Body.Close() //nolint: errcheck
 	repo, err := be.Repository(ctx, name)
 	if err != nil {
 		renderJSON(w, http.StatusNotFound, lfs.ErrorResponse{
@@ -326,7 +326,7 @@ func serviceLfsBasicUpload(w http.ResponseWriter, r *http.Request) {
 	// partial error, so we need to skip existing objects.
 	if _, err := datastore.GetLFSObjectByOid(ctx, dbx, repo.ID(), oid); err == nil {
 		// Object exists, skip request
-		io.Copy(io.Discard, r.Body) // nolint: errcheck
+		io.Copy(io.Discard, r.Body) //nolint: errcheck
 		renderStatus(http.StatusOK)(w, nil)
 		return
 	} else if !errors.Is(err, db.ErrRecordNotFound) {
@@ -385,7 +385,7 @@ func serviceLfsBasicVerify(w http.ResponseWriter, r *http.Request) {
 		return
 	}
 
-	defer r.Body.Close() // nolint: errcheck
+	defer r.Body.Close() //nolint: errcheck
 	if err := json.NewDecoder(r.Body).Decode(&pointer); err != nil {
 		logger.Error("error decoding json", "err", err)
 		renderJSON(w, http.StatusBadRequest, lfs.ErrorResponse{

pkg/web/logging.go 🔗

@@ -18,13 +18,12 @@ type logWriter struct {
 	code, bytes int
 }
 
-var _ http.ResponseWriter = (*logWriter)(nil)
-
-var _ http.Flusher = (*logWriter)(nil)
-
-var _ http.Hijacker = (*logWriter)(nil)
-
-var _ http.CloseNotifier = (*logWriter)(nil) // nolint: staticcheck
+var (
+	_ http.ResponseWriter = (*logWriter)(nil)
+	_ http.Flusher        = (*logWriter)(nil)
+	_ http.Hijacker       = (*logWriter)(nil)
+	_ http.CloseNotifier  = (*logWriter)(nil)
+)
 
 // Write implements http.ResponseWriter.
 func (r *logWriter) Write(p []byte) (int, error) {
@@ -54,7 +53,7 @@ func (r *logWriter) Flush() {
 
 // CloseNotify implements http.CloseNotifier.
 func (r *logWriter) CloseNotify() <-chan bool {
-	if cn, ok := r.ResponseWriter.(http.CloseNotifier); ok { // nolint: staticcheck
+	if cn, ok := r.ResponseWriter.(http.CloseNotifier); ok {
 		return cn.CloseNotify()
 	}
 	return nil

pkg/web/util.go 🔗

@@ -9,6 +9,6 @@ import (
 func renderStatus(code int) http.HandlerFunc {
 	return func(w http.ResponseWriter, _ *http.Request) {
 		w.WriteHeader(code)
-		io.WriteString(w, fmt.Sprintf("%d %s", code, http.StatusText(code))) // nolint: errcheck
+		io.WriteString(w, fmt.Sprintf("%d %s", code, http.StatusText(code))) //nolint: errcheck
 	}
 }

pkg/webhook/ssrf_test.go 🔗

@@ -158,7 +158,7 @@ func TestDialContextBlocksPrivateIPs(t *testing.T) {
 // sendWebhookWithContext is a test helper that doesn't require database.
 func sendWebhookWithContext(ctx context.Context, w models.Webhook, _ Event, _ any) error {
 	// This is a simplified version for testing that just attempts the HTTP connection
-	req, err := http.NewRequest("POST", w.URL, nil)
+	req, err := http.NewRequestWithContext(ctx, "POST", w.URL, nil)
 	if err != nil {
 		return err //nolint:wrapcheck
 	}

pkg/webhook/validator.go 🔗

@@ -1,6 +1,7 @@
 package webhook
 
 import (
+	"context"
 	"errors"
 	"fmt"
 	"net"
@@ -60,13 +61,13 @@ func ValidateWebhookURL(rawURL string) error {
 	}
 
 	// Resolve hostname to IP addresses
-	ips, err := net.LookupIP(hostname)
+	ips, err := net.DefaultResolver.LookupIPAddr(context.Background(), hostname)
 	if err != nil {
 		return fmt.Errorf("%w: cannot resolve hostname: %v", ErrInvalidURL, err)
 	}
 
 	// Check all resolved IPs
-	if slices.ContainsFunc(ips, isPrivateOrInternalIP) {
+	if slices.ContainsFunc(ips, isPrivateOrInternalIPAddr) {
 		return ErrPrivateIP
 	}
 
@@ -81,6 +82,11 @@ func isLocalhost(hostname string) bool {
 		strings.HasSuffix(hostname, ".localhost")
 }
 
+// isPrivateOrInternalIPAddr is a helper function that users net.IPAddr instead of net.IP.
+func isPrivateOrInternalIPAddr(ipAddr net.IPAddr) bool {
+	return isPrivateOrInternalIP(ipAddr.IP)
+}
+
 // isPrivateOrInternalIP checks if an IP address is private, internal, or reserved.
 func isPrivateOrInternalIP(ip net.IP) bool {
 	// Loopback addresses (127.0.0.0/8, ::1)

pkg/webhook/webhook.go 🔗

@@ -109,7 +109,7 @@ func SendWebhook(ctx context.Context, w models.Webhook, event Event, payload int
 		if err != nil {
 			return err
 		}
-		buf.WriteString(v.Encode()) // nolint: errcheck
+		buf.WriteString(v.Encode()) //nolint: errcheck
 	default:
 		return ErrInvalidContentType
 	}
@@ -129,7 +129,7 @@ func SendWebhook(ctx context.Context, w models.Webhook, event Event, payload int
 	reqBody := buf.String()
 	if w.Secret != "" {
 		sig := hmac.New(sha256.New, []byte(w.Secret))
-		sig.Write([]byte(reqBody)) // nolint: errcheck
+		sig.Write([]byte(reqBody)) //nolint: errcheck
 		headers.Add("X-SoftServe-Signature", "sha256="+hex.EncodeToString(sig.Sum(nil)))
 	}
 
@@ -150,7 +150,7 @@ func SendWebhook(ctx context.Context, w models.Webhook, event Event, payload int
 		}
 
 		if res.Body != nil {
-			defer res.Body.Close() // nolint: errcheck
+			defer res.Body.Close() //nolint: errcheck
 			b, err := io.ReadAll(res.Body)
 			if err != nil {
 				return err

testscript/script_test.go 🔗

@@ -38,9 +38,9 @@ func PrepareBuildCommand(binPath string) *exec.Cmd {
 	_, disableRaceSet := os.LookupEnv("SOFT_SERVE_DISABLE_RACE_CHECKS")
 	if disableRaceSet {
 		// don't add the -race flag
-		return exec.Command("go", "build", "-cover", "-o", binPath, filepath.Join("..", "cmd", "soft"))
+		return exec.Command("go", "build", "-cover", "-o", binPath, filepath.Join("..", "cmd", "soft")) //nolint:noctx
 	}
-	return exec.Command("go", "build", "-race", "-cover", "-o", binPath, filepath.Join("..", "cmd", "soft"))
+	return exec.Command("go", "build", "-race", "-cover", "-o", binPath, filepath.Join("..", "cmd", "soft")) //nolint:noctx
 }
 
 func TestMain(m *testing.M) {
@@ -167,7 +167,7 @@ func TestScript(t *testing.T) {
 			// Override the database data source if we're using postgres
 			// so we can create a temporary database for the tests.
 			if cfg.DB.Driver == "postgres" {
-				err, cleanup := setupPostgres(e.T(), cfg)
+				cleanup, err := setupPostgres(e.T(), cfg)
 				if err != nil {
 					return err
 				}
@@ -263,7 +263,7 @@ func cmdUI(key ssh.Signer) func(ts *testscript.TestScript, neg bool, args []stri
 					break
 				}
 				check(ts, err, neg)
-				stdin.Write([]byte(string(r))) // nolint: errcheck
+				_, _ = io.WriteString(stdin, string(r))
 
 				// Wait for the UI to process the input
 				time.Sleep(100 * time.Millisecond)
@@ -381,7 +381,7 @@ func cmdNewWebhook(ts *testscript.TestScript, neg bool, args []string) {
 	}
 
 	const whSite = "https://webhook.site"
-	req, err := http.NewRequest(http.MethodPost, whSite+"/token", nil)
+	req, err := http.NewRequest(http.MethodPost, whSite+"/token", nil) //nolint:noctx
 	check(ts, err, neg)
 
 	resp, err := http.DefaultClient.Do(req)
@@ -409,7 +409,7 @@ func cmdCurl(ts *testscript.TestScript, neg bool, args []string) {
 				return err
 			}
 
-			req, err := http.NewRequest(method, url.String(), nil)
+			req, err := http.NewRequest(method, url.String(), nil) //nolint:noctx
 			if err != nil {
 				return err
 			}
@@ -494,7 +494,7 @@ func cmdEnsureServerRunning(ts *testscript.TestScript, neg bool, args []string)
 	// verify that the server is up
 	addr := net.JoinHostPort("localhost", port)
 	for {
-		conn, _ := net.DialTimeout(
+		conn, _ := net.DialTimeout( //nolint:noctx
 			"tcp",
 			addr,
 			time.Second,
@@ -519,29 +519,26 @@ func cmdEnsureServerNotRunning(ts *testscript.TestScript, neg bool, args []strin
 
 	// verify that the server is not up
 	addr := net.JoinHostPort("localhost", port)
-	for {
-		conn, _ := net.DialTimeout(
-			"tcp",
-			addr,
-			time.Second,
-		)
-		if conn != nil {
-			ts.Fatalf("server is running on port %s while it should not be running", port)
-			conn.Close()
-		}
-		break
+	conn, _ := net.DialTimeout( //nolint:noctx
+		"tcp",
+		addr,
+		time.Second,
+	)
+	if conn != nil {
+		ts.Fatalf("server is running on port %s while it should not be running", port)
+		conn.Close()
 	}
 }
 
 func cmdStopserver(ts *testscript.TestScript, neg bool, args []string) {
 	// stop the server
-	resp, err := http.DefaultClient.Head(fmt.Sprintf("%s/__stop", ts.Getenv("SOFT_SERVE_HTTP_PUBLIC_URL")))
+	resp, err := http.DefaultClient.Head(fmt.Sprintf("%s/__stop", ts.Getenv("SOFT_SERVE_HTTP_PUBLIC_URL"))) //nolint:noctx
 	check(ts, err, neg)
 	resp.Body.Close()
 	time.Sleep(time.Second * 2) // Allow some time for the server to stop
 }
 
-func setupPostgres(t testscript.T, cfg *config.Config) (error, func()) {
+func setupPostgres(t testscript.T, cfg *config.Config) (func(), error) {
 	// Indicates postgres
 	// Create a disposable database
 	rnd := rand.New(rand.NewSource(time.Now().UnixNano()))
@@ -553,7 +550,7 @@ func setupPostgres(t testscript.T, cfg *config.Config) (error, func()) {
 
 	dbUrl, err := url.Parse(cfg.DB.DataSource)
 	if err != nil {
-		return err, nil
+		return nil, err
 	}
 
 	scheme := dbUrl.Scheme
@@ -598,21 +595,21 @@ func setupPostgres(t testscript.T, cfg *config.Config) (error, func()) {
 	// Create the database
 	dbx, err := db.Open(context.TODO(), cfg.DB.Driver, connInfo)
 	if err != nil {
-		return err, nil
+		return nil, err
 	}
 
-	if _, err := dbx.Exec("CREATE DATABASE " + dbName); err != nil {
-		return err, nil
+	if _, err := dbx.ExecContext(context.TODO(), "CREATE DATABASE "+dbName); err != nil {
+		return nil, err
 	}
 
-	return nil, func() {
+	return func() {
 		dbx, err := db.Open(context.TODO(), cfg.DB.Driver, connInfo)
 		if err != nil {
 			t.Fatal("failed to open database", dbName, err)
 		}
 
-		if _, err := dbx.Exec("DROP DATABASE " + dbName); err != nil {
+		if _, err := dbx.ExecContext(context.TODO(), "DROP DATABASE "+dbName); err != nil {
 			t.Fatal("failed to drop database", dbName, err)
 		}
-	}
+	}, nil
 }