From 4fb4f36f68a6b43fe52ecde1602ac4517640d769 Mon Sep 17 00:00:00 2001 From: Amolith Date: Sat, 27 Sep 2025 17:19:18 -0600 Subject: [PATCH] fix: resolve wrapcheck linter errors Co-Authored-By: Crush --- cmd/willow.go | 8 ++++---- db/db.go | 16 ++++++++++++--- db/migrations.go | 5 ++++- db/project.go | 19 ++++++++++++------ db/release.go | 10 +++++++--- db/users.go | 34 +++++++++++++++++++++++--------- git/git.go | 16 +++++++-------- project/project.go | 14 ++++++------- rss/rss.go | 2 +- users/users.go | 49 ++++++++++++++++++++++++++++++++++++---------- 10 files changed, 121 insertions(+), 52 deletions(-) diff --git a/cmd/willow.go b/cmd/willow.go index 01c432e81a1240381985c464baf2e906fb4238f0..64f580a34b02dd250096a774168f16e1672a7b9f 100644 --- a/cmd/willow.go +++ b/cmd/willow.go @@ -169,27 +169,27 @@ Listen = "%s"`, defaultDBConn, defaultFetchInterval, defaultFetchInterval, defau if os.IsNotExist(err) { file, err = os.Create(*flagConfig) if err != nil { - return err + return fmt.Errorf("failed to create file: %w", err) } defer file.Close() _, err = file.WriteString(defaultConfig) if err != nil { - return err + return fmt.Errorf("failed to write to file: %w", err) } fmt.Println("Config file created at", *flagConfig) fmt.Println("Please edit it and restart the server") os.Exit(0) } else { - return err + return fmt.Errorf("failed to open config file: %w", err) } } defer file.Close() _, err = toml.DecodeFile(*flagConfig, &config) if err != nil { - return err + return fmt.Errorf("failed to decode TOML file: %w", err) } if config.FetchInterval < defaultFetchInterval { diff --git a/db/db.go b/db/db.go index b409f515ef62368681a766aaf09aeca33fd0daea..f9ac8226cb211ab27e5445c4e3c8926a5690d0fa 100644 --- a/db/db.go +++ b/db/db.go @@ -8,6 +8,7 @@ import ( "database/sql" _ "embed" "errors" + "fmt" "sync" _ "modernc.org/sqlite" @@ -20,7 +21,12 @@ var mutex = &sync.Mutex{} // Open opens a connection to the SQLite database. func Open(dbPath string) (*sql.DB, error) { - return sql.Open("sqlite", "file:"+dbPath+"?_pragma=journal_mode%3DWAL") + db, err := sql.Open("sqlite", "file:"+dbPath+"?_pragma=journal_mode%3DWAL") + if err != nil { + return nil, fmt.Errorf("failed to open database: %w", err) + } + + return db, nil } // VerifySchema checks whether the schema has been initialised and initialises it @@ -34,11 +40,15 @@ func InitialiseDatabase(dbConn *sql.DB) error { defer mutex.Unlock() if _, err := dbConn.Exec(schema); err != nil { - return err + return fmt.Errorf("failed to execute SQL: %w", err) } return nil } - return err + if err != nil { + return fmt.Errorf("failed to scan row: %w", err) + } + + return nil } diff --git a/db/migrations.go b/db/migrations.go index a51a94bf44f16b0a594d7370cb2b130210aee509..863628480f4892c50f227a2727828d0116845233 100644 --- a/db/migrations.go +++ b/db/migrations.go @@ -166,6 +166,9 @@ func updateSchemaVersion(tx *sql.Tx, version int) error { } _, err := tx.Exec(`UPDATE schema_migrations SET version = @version;`, sql.Named("version", version)) + if err != nil { + return fmt.Errorf("failed to execute SQL: %w", err) + } - return err + return nil } diff --git a/db/project.go b/db/project.go index c28f921e437b2af214e5c1cf4aa360624314c928..085fbc1075ac92c8de47a869dc211e981967ef5c 100644 --- a/db/project.go +++ b/db/project.go @@ -6,6 +6,7 @@ package db import ( "database/sql" + "fmt" "sync" ) @@ -16,12 +17,15 @@ func DeleteProject(db *sql.DB, mu *sync.Mutex, id string) error { _, err := db.Exec("DELETE FROM projects WHERE id = ?", id) if err != nil { - return err + return fmt.Errorf("failed to execute SQL: %w", err) } _, err = db.Exec("DELETE FROM releases WHERE project_id = ?", id) + if err != nil { + return fmt.Errorf("failed to execute SQL: %w", err) + } - return err + return nil } // GetProject returns a project from the database. @@ -30,7 +34,7 @@ func GetProject(db *sql.DB, id string) (map[string]string, error) { err := db.QueryRow("SELECT name, forge, url, version FROM projects WHERE id = ?", id).Scan(&name, &forge, &url, &version) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to scan row: %w", err) } project := map[string]string{ @@ -56,15 +60,18 @@ func UpsertProject(db *sql.DB, mu *sync.Mutex, id, url, name, forge, running str name = excluded.name, forge = excluded.forge, version = excluded.version;`, id, url, name, forge, running) + if err != nil { + return fmt.Errorf("failed to execute SQL: %w", err) + } - return err + return nil } // GetProjects returns a list of all projects in the database. func GetProjects(db *sql.DB) ([]map[string]string, error) { rows, err := db.Query("SELECT id, name, url, forge, version FROM projects") if err != nil { - return nil, err + return nil, fmt.Errorf("failed to query database: %w", err) } defer rows.Close() @@ -74,7 +81,7 @@ func GetProjects(db *sql.DB) ([]map[string]string, error) { err = rows.Scan(&id, &name, &url, &forge, &version) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to scan row: %w", err) } project := map[string]string{ diff --git a/db/release.go b/db/release.go index d88ba3a638e9b32cf0dfbf1a2e88367a9276dbd7..e8c21a68535b6879d8fdf274060be2da86a3be3d 100644 --- a/db/release.go +++ b/db/release.go @@ -6,6 +6,7 @@ package db import ( "database/sql" + "fmt" "sync" ) @@ -24,15 +25,18 @@ func UpsertRelease(db *sql.DB, mu *sync.Mutex, id, projectID, url, tag, content, tag = excluded.tag, content = excluded.content, date = excluded.date;`, id, projectID, url, tag, content, date) + if err != nil { + return fmt.Errorf("failed to execute SQL: %w", err) + } - return err + return nil } // GetReleases returns all releases for a project with a given id from the database. func GetReleases(db *sql.DB, projectID string) ([]map[string]string, error) { rows, err := db.Query(`SELECT id, url, tag, content, date FROM releases WHERE project_id = ?`, projectID) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to query database: %w", err) } defer rows.Close() @@ -48,7 +52,7 @@ func GetReleases(db *sql.DB, projectID string) ([]map[string]string, error) { err := rows.Scan(&id, &url, &tag, &content, &date) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to scan row: %w", err) } releases = append(releases, map[string]string{ diff --git a/db/users.go b/db/users.go index 7d4753601b79da076a9021f025d4e7d607d01c20..5cb7e1af8bf9ef8d5a730f590f4b979aa40f1728 100644 --- a/db/users.go +++ b/db/users.go @@ -6,6 +6,7 @@ package db import ( "database/sql" + "fmt" "time" ) @@ -16,8 +17,11 @@ func DeleteUser(db *sql.DB, user string) error { defer mutex.Unlock() _, err := db.Exec("DELETE FROM users WHERE username = ?", user) + if err != nil { + return fmt.Errorf("failed to execute SQL: %w", err) + } - return err + return nil } // CreateUser creates a new user in the database and returns an error if it fails. @@ -26,8 +30,11 @@ func CreateUser(db *sql.DB, username, hash, salt string) error { defer mutex.Unlock() _, err := db.Exec("INSERT INTO users (username, hash, salt) VALUES (?, ?, ?)", username, hash, salt) + if err != nil { + return fmt.Errorf("failed to execute SQL: %w", err) + } - return err + return nil } // GetUser returns a user's hash and salt from the database as strings and @@ -36,8 +43,11 @@ func GetUser(db *sql.DB, username string) (string, string, error) { var hash, salt string err := db.QueryRow("SELECT hash, salt FROM users WHERE username = ?", username).Scan(&hash, &salt) + if err != nil { + return "", "", fmt.Errorf("failed to scan row: %w", err) + } - return hash, salt, err + return hash, salt, nil } // GetUsers returns a list of all users in the database as a slice of strings @@ -45,7 +55,7 @@ func GetUser(db *sql.DB, username string) (string, string, error) { func GetUsers(db *sql.DB) ([]string, error) { rows, err := db.Query("SELECT username FROM users") if err != nil { - return nil, err + return nil, fmt.Errorf("failed to query database: %w", err) } defer rows.Close() @@ -55,7 +65,7 @@ func GetUsers(db *sql.DB) ([]string, error) { err = rows.Scan(&user) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to scan row: %w", err) } users = append(users, user) @@ -74,12 +84,12 @@ func GetSession(db *sql.DB, session string) (string, time.Time, error) { err := db.QueryRow("SELECT username, expires FROM sessions WHERE token = ?", session).Scan(&username, &expiresString) if err != nil { - return "", time.Time{}, err + return "", time.Time{}, fmt.Errorf("failed to scan row: %w", err) } expires, err := time.Parse(time.RFC3339, expiresString) if err != nil { - return "", time.Time{}, err + return "", time.Time{}, fmt.Errorf("failed to parse time: %w", err) } return username, expires, nil @@ -92,8 +102,11 @@ func InvalidateSession(db *sql.DB, session string, expiry time.Time) error { defer mutex.Unlock() _, err := db.Exec("UPDATE sessions SET expires = ? WHERE token = ?", expiry.Format(time.RFC3339), session) + if err != nil { + return fmt.Errorf("failed to execute SQL: %w", err) + } - return err + return nil } // CreateSession creates a new session in the database and returns an error if @@ -103,6 +116,9 @@ func CreateSession(db *sql.DB, username, token string, expiry time.Time) error { defer mutex.Unlock() _, err := db.Exec("INSERT INTO sessions (token, username, expires) VALUES (?, ?, ?)", token, username, expiry.Format(time.RFC3339)) + if err != nil { + return fmt.Errorf("failed to execute SQL: %w", err) + } - return err + return nil } diff --git a/git/git.go b/git/git.go index 5d56ae26731dd4e20f1e09dd8b2cfbfaeda34da9..ec9abee36559fe33cc9847c1a1e9a2ffc4bb2963 100644 --- a/git/git.go +++ b/git/git.go @@ -47,7 +47,7 @@ func GetReleases(gitURI, forge string) ([]Release, error) { tagRefs, err := r.Tags() if err != nil { - return nil, err + return nil, fmt.Errorf("failed to get repository tags: %w", err) } parsedURI, err := url.Parse(gitURI) @@ -73,7 +73,7 @@ func GetReleases(gitURI, forge string) ([]Release, error) { if errors.Is(err, plumbing.ErrObjectNotFound) { commitTag, err := r.CommitObject(tagRef.Hash()) if err != nil { - return err + return fmt.Errorf("failed to get commit object: %w", err) } message = commitTag.Message @@ -106,7 +106,7 @@ func GetReleases(gitURI, forge string) ([]Release, error) { return nil }) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to iterate references: %w", err) } return releases, nil @@ -142,9 +142,9 @@ func minimalClone(url string) (r *git.Repository, err error) { return r, nil } - return r, err + return r, fmt.Errorf("failed to fetch repository: %w", err) } else if !errors.Is(err, git.ErrRepositoryNotExists) { - return nil, err + return nil, fmt.Errorf("failed to fetch repository: %w", err) } r, err = git.PlainClone(path, false, &git.CloneOptions{ @@ -170,7 +170,7 @@ func minimalClone(url string) (r *git.Repository, err error) { Shared: false, }) - return r, err + return r, fmt.Errorf("failed to clone repository: %w", err) } // RemoveRepo removes a repository from the local filesystem. @@ -182,7 +182,7 @@ func RemoveRepo(url string) (err error) { err = os.RemoveAll(path) if err != nil { - return err + return fmt.Errorf("failed to remove directory: %w", err) } path = path[:strings.LastIndex(path, "/")] @@ -214,7 +214,7 @@ func stringifyRepo(url string) (path string, err error) { ep, err := transport.NewEndpoint(url) if err != nil { - return "", err + return "", fmt.Errorf("failed to create git endpoint: %w", err) } switch ep.Protocol { diff --git a/project/project.go b/project/project.go index 073e2303ebc4bc9025b51c89d6b1576b8514ab3c..66363ee0aa813286640b204a470c4a9d1a8a89c3 100644 --- a/project/project.go +++ b/project/project.go @@ -49,7 +49,7 @@ func GetReleases(dbConn *sql.DB, mu *sync.Mutex, proj Project) (Project, error) ret, err := db.GetReleases(dbConn, proj.ID) if err != nil { - return proj, err + return proj, fmt.Errorf("failed to get releases from database: %w", err) } if len(ret) == 0 { @@ -81,7 +81,7 @@ func fetchReleases(dbConn *sql.DB, mu *sync.Mutex, p Project) (Project, error) { rssReleases, err := rss.GetReleases(p.URL) if err != nil { fmt.Println("Error getting RSS releases:", err) - return p, err + return p, fmt.Errorf("failed to get releases from RSS feed: %w", err) } for _, release := range rssReleases { @@ -103,7 +103,7 @@ func fetchReleases(dbConn *sql.DB, mu *sync.Mutex, p Project) (Project, error) { default: gitReleases, err := git.GetReleases(p.URL, p.Forge) if err != nil { - return p, err + return p, fmt.Errorf("failed to get releases from git: %w", err) } for _, release := range gitReleases { @@ -153,7 +153,7 @@ func upsertReleases(dbConn *sql.DB, mu *sync.Mutex, projID string, releases []Re err := db.UpsertRelease(dbConn, mu, release.ID, projID, release.URL, release.Tag, release.Content, date) if err != nil { log.Printf("Error upserting release: %v", err) - return err + return fmt.Errorf("failed to upsert release: %w", err) } } @@ -261,7 +261,7 @@ func GetProject(dbConn *sql.DB, proj Project) (Project, error) { if err != nil && errors.Is(err, sql.ErrNoRows) { return proj, nil } else if err != nil { - return proj, err + return proj, fmt.Errorf("failed to get project from database: %w", err) } p := Project{ @@ -273,7 +273,7 @@ func GetProject(dbConn *sql.DB, proj Project) (Project, error) { Releases: nil, } - return p, err + return p, nil } // GetProjectWithReleases returns a single project from the database along with its releases. @@ -290,7 +290,7 @@ func GetProjectWithReleases(dbConn *sql.DB, mu *sync.Mutex, proj Project) (Proje func GetProjects(dbConn *sql.DB) ([]Project, error) { projectsDB, err := db.GetProjects(dbConn) if err != nil { - return nil, err + return nil, fmt.Errorf("failed to get projects from database: %w", err) } projects := make([]Project, len(projectsDB)) diff --git a/rss/rss.go b/rss/rss.go index b7cc8037eceb600c01e08c2ef97a7a5940411174..3569ff1a26b8a72040cb81e32f24e83c516d860e 100644 --- a/rss/rss.go +++ b/rss/rss.go @@ -31,7 +31,7 @@ func GetReleases(feedURL string) ([]Release, error) { feed, err := fp.ParseURL(strings.TrimSuffix(feedURL, "/") + "/releases.atom") if err != nil { fmt.Println(err) - return nil, err + return nil, fmt.Errorf("failed to parse RSS feed: %w", err) } releases := make([]Release, 0) diff --git a/users/users.go b/users/users.go index a8a3923bfe9b0bd5d7345ac9a3d3603dbab056cd..1a42e53acf42bf004ce03b3fa98099246bf2d891 100644 --- a/users/users.go +++ b/users/users.go @@ -8,6 +8,7 @@ import ( "crypto/rand" "database/sql" "encoding/base64" + "fmt" "time" "git.sr.ht/~amolith/willow/db" @@ -28,7 +29,7 @@ const ( func argonHash(password, salt string) (string, error) { decodedSalt, err := base64.StdEncoding.DecodeString(salt) if err != nil { - return "", err + return "", fmt.Errorf("failed to decode base64: %w", err) } return base64.StdEncoding.EncodeToString(argon2.IDKey([]byte(password), decodedSalt, argon2Time, argon2Memory, argon2Threads, argon2KeyLen)), nil @@ -41,7 +42,7 @@ func generateSalt() (string, error) { _, err := rand.Read(salt) if err != nil { - return "", err + return "", fmt.Errorf("failed to generate random bytes: %w", err) } return base64.StdEncoding.EncodeToString(salt), nil @@ -60,18 +61,30 @@ func Register(dbConn *sql.DB, username, password string) error { return err } - return db.CreateUser(dbConn, username, hash, salt) + err = db.CreateUser(dbConn, username, hash, salt) + if err != nil { + return fmt.Errorf("failed to create user: %w", err) + } + + return nil } // Delete removes a user from the database. -func Delete(dbConn *sql.DB, username string) error { return db.DeleteUser(dbConn, username) } +func Delete(dbConn *sql.DB, username string) error { + err := db.DeleteUser(dbConn, username) + if err != nil { + return fmt.Errorf("failed to delete user: %w", err) + } + + return nil +} // UserAuthorised accepts a username string, a token string, and returns true if the // user is authorised, false if not, and an error if one is encountered. func UserAuthorised(dbConn *sql.DB, username, token string) (bool, error) { dbHash, dbSalt, err := db.GetUser(dbConn, username) if err != nil { - return false, err + return false, fmt.Errorf("failed to get user: %w", err) } providedHash, err := argonHash(token, dbSalt) @@ -86,8 +99,12 @@ func UserAuthorised(dbConn *sql.DB, username, token string) (bool, error) { // valid and false if not. func SessionAuthorised(dbConn *sql.DB, session string) (bool, error) { dbResult, expiry, err := db.GetSession(dbConn, session) - if dbResult == "" || expiry.Before(time.Now()) || err != nil { - return false, err + if err != nil { + return false, fmt.Errorf("failed to get session: %w", err) + } + + if dbResult == "" || expiry.Before(time.Now()) { + return false, nil } return true, nil @@ -95,7 +112,12 @@ func SessionAuthorised(dbConn *sql.DB, session string) (bool, error) { // InvalidateSession invalidates a session by setting the expiration date to now. func InvalidateSession(dbConn *sql.DB, session string) error { - return db.InvalidateSession(dbConn, session, time.Now()) + err := db.InvalidateSession(dbConn, session, time.Now()) + if err != nil { + return fmt.Errorf("failed to invalidate session: %w", err) + } + + return nil } // CreateSession accepts a username, generates a token, stores it in the @@ -110,11 +132,18 @@ func CreateSession(dbConn *sql.DB, username string) (string, time.Time, error) { err = db.CreateSession(dbConn, username, token, expiry) if err != nil { - return "", time.Time{}, err + return "", time.Time{}, fmt.Errorf("failed to create session: %w", err) } return token, expiry, nil } // GetUsers returns a list of all users in the database as a slice of strings. -func GetUsers(dbConn *sql.DB) ([]string, error) { return db.GetUsers(dbConn) } +func GetUsers(dbConn *sql.DB) ([]string, error) { + users, err := db.GetUsers(dbConn) + if err != nil { + return nil, fmt.Errorf("failed to get users: %w", err) + } + + return users, nil +}