All checks were successful
check / check (push) Successful in 2m19s
Security: - Add channel membership check before PRIVMSG (prevents non-members from sending) - Add membership check on history endpoint (channels require membership, DMs scoped to own nick) - Enforce MaxBytesReader on all POST request bodies - Fix rand.Read error being silently ignored in token generation Data integrity: - Fix TOCTOU race in GetOrCreateChannel using INSERT OR IGNORE + SELECT Build: - Add CGO_ENABLED=0 to golangci-lint install in Dockerfile (fixes alpine build) Linting: - Strict .golangci.yml: only wsl disabled (deprecated in v2) - Re-enable exhaustruct, depguard, godot, wrapcheck, varnamelen - Fix linters-settings -> linters.settings for v2 config format - Fix ALL lint findings in actual code (no linter config weakening) - Wrap all external package errors (wrapcheck) - Fill struct fields or add targeted nolint:exhaustruct where appropriate - Rename short variables (ts->timestamp, n->bufIndex, etc.) - Add depguard deny policy for io/ioutil and math/rand - Exclude G704 (SSRF) in gosec config (CLI client takes user-configured URLs) Tests: - Add security tests (TestNonMemberCannotSend, TestHistoryNonMember) - Split TestInsertAndPollMessages for reduced complexity - Fix parallel test safety (viper global state prevents parallelism) - Use t.Context() instead of context.Background() in tests Docker build verified passing locally.
61 lines
1.1 KiB
Go
61 lines
1.1 KiB
Go
package db
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
"log/slog"
|
|
"sync/atomic"
|
|
)
|
|
|
|
//nolint:gochecknoglobals // test counter
|
|
var testDBCounter atomic.Int64
|
|
|
|
// NewTestDatabase creates an in-memory database for testing.
|
|
func NewTestDatabase() (*Database, error) {
|
|
counter := testDBCounter.Add(1)
|
|
|
|
dsn := fmt.Sprintf(
|
|
"file:testdb%d?mode=memory"+
|
|
"&cache=shared&_pragma=foreign_keys(1)",
|
|
counter,
|
|
)
|
|
|
|
conn, err := sql.Open("sqlite", dsn)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("open test db: %w", err)
|
|
}
|
|
|
|
database := &Database{ //nolint:exhaustruct // test helper, params not needed
|
|
conn: conn,
|
|
log: slog.Default(),
|
|
}
|
|
|
|
err = database.runMigrations(context.Background())
|
|
if err != nil {
|
|
closeErr := conn.Close()
|
|
if closeErr != nil {
|
|
return nil, fmt.Errorf(
|
|
"close after migration failure: %w",
|
|
closeErr,
|
|
)
|
|
}
|
|
|
|
return nil, fmt.Errorf(
|
|
"run test migrations: %w", err,
|
|
)
|
|
}
|
|
|
|
return database, nil
|
|
}
|
|
|
|
// Close closes the underlying database connection.
|
|
func (database *Database) Close() error {
|
|
err := database.conn.Close()
|
|
if err != nil {
|
|
return fmt.Errorf("close database: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|