Detailed changes
@@ -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:
@@ -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
@@ -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)
@@ -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)
@@ -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)
}
@@ -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
@@ -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.
@@ -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)
@@ -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()
@@ -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
@@ -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()
}
@@ -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)
@@ -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()
}
@@ -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
}
@@ -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
}
@@ -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)
}
@@ -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.
@@ -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
}
@@ -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"
)
@@ -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"
@@ -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 {
@@ -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 {
@@ -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)
}
@@ -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)
}
@@ -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)
@@ -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")
@@ -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
@@ -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
}
}()
@@ -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"
@@ -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
}
}
@@ -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()
@@ -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
@@ -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)
}
@@ -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()
@@ -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"
)
@@ -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.
@@ -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"
@@ -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{}
@@ -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"
)
@@ -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)
}
@@ -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{
@@ -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
@@ -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
}
}
@@ -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
}
@@ -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)
@@ -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
@@ -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
}