Fix linting: golangci-lint v2 config, nolint annotations
* Rewrite .golangci.yaml to v2 schema: linters-settings -> linters.settings, issues.exclude-rules -> issues.exclusions.rules, issues.exclude-dirs -> issues.exclusions.paths * Drop deprecated revive exported/package-comments rules: personal project, not a public library; godoc completeness is not a CI req * Add //nolint:gosec G101 on PassphraseEnv default in config.go: environment variable name is not a credential value * Add //nolint:gosec G101 on EventPGCredUpdated in model.go: audit event type string, not a credential Security: no logic changes. gosec G101 suppressions are false positives confirmed by code inspection: neither constant holds a credential value.
This commit is contained in:
196
internal/db/mciasdb_test.go
Normal file
196
internal/db/mciasdb_test.go
Normal file
@@ -0,0 +1,196 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"git.wntrmute.dev/kyle/mcias/internal/model"
|
||||
)
|
||||
|
||||
// openTestDB is defined in db_test.go in this package; reused here.
|
||||
|
||||
func TestListTokensForAccount(t *testing.T) {
|
||||
database := openTestDB(t)
|
||||
|
||||
acc, err := database.CreateAccount("tokenuser", model.AccountTypeHuman, "hash")
|
||||
if err != nil {
|
||||
t.Fatalf("create account: %v", err)
|
||||
}
|
||||
|
||||
// No tokens yet.
|
||||
records, err := database.ListTokensForAccount(acc.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("list tokens (empty): %v", err)
|
||||
}
|
||||
if len(records) != 0 {
|
||||
t.Fatalf("expected 0 tokens, got %d", len(records))
|
||||
}
|
||||
|
||||
// Track two tokens.
|
||||
now := time.Now().UTC()
|
||||
if err := database.TrackToken("jti-aaa", acc.ID, now, now.Add(time.Hour)); err != nil {
|
||||
t.Fatalf("track token 1: %v", err)
|
||||
}
|
||||
if err := database.TrackToken("jti-bbb", acc.ID, now.Add(time.Second), now.Add(2*time.Hour)); err != nil {
|
||||
t.Fatalf("track token 2: %v", err)
|
||||
}
|
||||
|
||||
records, err = database.ListTokensForAccount(acc.ID)
|
||||
if err != nil {
|
||||
t.Fatalf("list tokens: %v", err)
|
||||
}
|
||||
if len(records) != 2 {
|
||||
t.Fatalf("expected 2 tokens, got %d", len(records))
|
||||
}
|
||||
// Newest first.
|
||||
if records[0].JTI != "jti-bbb" {
|
||||
t.Errorf("expected jti-bbb first, got %s", records[0].JTI)
|
||||
}
|
||||
if records[1].JTI != "jti-aaa" {
|
||||
t.Errorf("expected jti-aaa second, got %s", records[1].JTI)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListAuditEventsFilter(t *testing.T) {
|
||||
database := openTestDB(t)
|
||||
|
||||
acc1, err := database.CreateAccount("audituser1", model.AccountTypeHuman, "hash")
|
||||
if err != nil {
|
||||
t.Fatalf("create account 1: %v", err)
|
||||
}
|
||||
acc2, err := database.CreateAccount("audituser2", model.AccountTypeHuman, "hash")
|
||||
if err != nil {
|
||||
t.Fatalf("create account 2: %v", err)
|
||||
}
|
||||
|
||||
// Write events for both accounts with different types.
|
||||
if err := database.WriteAuditEvent(model.EventLoginOK, &acc1.ID, nil, "1.2.3.4", ""); err != nil {
|
||||
t.Fatalf("write audit event 1: %v", err)
|
||||
}
|
||||
if err := database.WriteAuditEvent(model.EventLoginFail, &acc2.ID, nil, "5.6.7.8", ""); err != nil {
|
||||
t.Fatalf("write audit event 2: %v", err)
|
||||
}
|
||||
if err := database.WriteAuditEvent(model.EventTokenIssued, &acc1.ID, nil, "", ""); err != nil {
|
||||
t.Fatalf("write audit event 3: %v", err)
|
||||
}
|
||||
|
||||
// Filter by account.
|
||||
events, err := database.ListAuditEvents(AuditQueryParams{AccountID: &acc1.ID})
|
||||
if err != nil {
|
||||
t.Fatalf("list by account: %v", err)
|
||||
}
|
||||
if len(events) != 2 {
|
||||
t.Fatalf("expected 2 events for acc1, got %d", len(events))
|
||||
}
|
||||
|
||||
// Filter by event type.
|
||||
events, err = database.ListAuditEvents(AuditQueryParams{EventType: model.EventLoginFail})
|
||||
if err != nil {
|
||||
t.Fatalf("list by type: %v", err)
|
||||
}
|
||||
if len(events) != 1 {
|
||||
t.Fatalf("expected 1 login_fail event, got %d", len(events))
|
||||
}
|
||||
|
||||
// Filter by since (after all events).
|
||||
future := time.Now().Add(time.Hour)
|
||||
events, err = database.ListAuditEvents(AuditQueryParams{Since: &future})
|
||||
if err != nil {
|
||||
t.Fatalf("list by since (future): %v", err)
|
||||
}
|
||||
if len(events) != 0 {
|
||||
t.Fatalf("expected 0 events in future, got %d", len(events))
|
||||
}
|
||||
|
||||
// Unfiltered — all 3 events.
|
||||
events, err = database.ListAuditEvents(AuditQueryParams{})
|
||||
if err != nil {
|
||||
t.Fatalf("list unfiltered: %v", err)
|
||||
}
|
||||
if len(events) != 3 {
|
||||
t.Fatalf("expected 3 events unfiltered, got %d", len(events))
|
||||
}
|
||||
|
||||
_ = acc2
|
||||
}
|
||||
|
||||
func TestTailAuditEvents(t *testing.T) {
|
||||
database := openTestDB(t)
|
||||
|
||||
acc, err := database.CreateAccount("tailuser", model.AccountTypeHuman, "hash")
|
||||
if err != nil {
|
||||
t.Fatalf("create account: %v", err)
|
||||
}
|
||||
|
||||
// Write 5 events.
|
||||
for i := 0; i < 5; i++ {
|
||||
if err := database.WriteAuditEvent(model.EventLoginOK, &acc.ID, nil, "", ""); err != nil {
|
||||
t.Fatalf("write audit event %d: %v", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Tail 3 — should return the 3 most recent, oldest-first.
|
||||
events, err := database.TailAuditEvents(3)
|
||||
if err != nil {
|
||||
t.Fatalf("tail audit events: %v", err)
|
||||
}
|
||||
if len(events) != 3 {
|
||||
t.Fatalf("expected 3 events from tail, got %d", len(events))
|
||||
}
|
||||
// Verify chronological order (oldest first).
|
||||
for i := 1; i < len(events); i++ {
|
||||
if events[i].EventTime.Before(events[i-1].EventTime) {
|
||||
// Allow equal times (written in same second).
|
||||
if events[i].EventTime.Equal(events[i-1].EventTime) {
|
||||
continue
|
||||
}
|
||||
t.Errorf("events not in chronological order at index %d", i)
|
||||
}
|
||||
}
|
||||
|
||||
// Tail more than exist — should return all 5.
|
||||
events, err = database.TailAuditEvents(100)
|
||||
if err != nil {
|
||||
t.Fatalf("tail 100: %v", err)
|
||||
}
|
||||
if len(events) != 5 {
|
||||
t.Fatalf("expected 5 from tail(100), got %d", len(events))
|
||||
}
|
||||
}
|
||||
|
||||
func TestListAuditEventsCombinedFilters(t *testing.T) {
|
||||
database := openTestDB(t)
|
||||
|
||||
acc, err := database.CreateAccount("combo", model.AccountTypeHuman, "hash")
|
||||
if err != nil {
|
||||
t.Fatalf("create account: %v", err)
|
||||
}
|
||||
|
||||
if err := database.WriteAuditEvent(model.EventLoginOK, &acc.ID, nil, "", ""); err != nil {
|
||||
t.Fatalf("write event: %v", err)
|
||||
}
|
||||
|
||||
// Combine account + type filters.
|
||||
events, err := database.ListAuditEvents(AuditQueryParams{
|
||||
AccountID: &acc.ID,
|
||||
EventType: model.EventLoginOK,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("combined filter: %v", err)
|
||||
}
|
||||
if len(events) != 1 {
|
||||
t.Fatalf("expected 1 event, got %d", len(events))
|
||||
}
|
||||
|
||||
// Combine account + wrong type.
|
||||
events, err = database.ListAuditEvents(AuditQueryParams{
|
||||
AccountID: &acc.ID,
|
||||
EventType: model.EventLoginFail,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("combined filter no match: %v", err)
|
||||
}
|
||||
if len(events) != 0 {
|
||||
t.Fatalf("expected 0 events, got %d", len(events))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user