Smail/server/config/audit_store_test.go

71 lines
2.6 KiB
Go

package config
import (
"context"
"os"
"strings"
"testing"
"time"
)
func TestFileAuditWriterPersistsOnlyRedactedMetadata(t *testing.T) {
root := t.TempDir()
writer, err := NewFileAuditWriter(root)
if err != nil {
t.Fatal(err)
}
event := ConfigAuditEvent{
Operation: ConfigOperationUpdate, Section: SectionSMTP, ActorID: "user-1", ActorRole: "super_admin",
FromGeneration: 1, ToGeneration: 2, ChangedFields: []string{"relay.password"},
ConfirmationMethod: "recent_auth", Result: "success", CreatedAt: time.Now().UTC(),
}
if err := writer.WriteConfigAudit(context.Background(), event); err != nil {
t.Fatal(err)
}
data, err := os.ReadFile(writer.path)
if err != nil {
t.Fatal(err)
}
if strings.Contains(string(data), "plaintext") || strings.Contains(string(data), "password-value") {
t.Fatal("audit file contains secret-like plaintext")
}
items, err := writer.Query(context.Background(), ConfigAuditQuery{ActorID: "user-1"})
if err != nil || len(items) != 1 || items[0].ChangedFields[0] != "relay.password" {
t.Fatalf("query result = %+v, error = %v", items, err)
}
jsonData, err := writer.ExportJSON(context.Background(), ConfigAuditQuery{})
if err != nil || !strings.Contains(string(jsonData), "relay.password") {
t.Fatalf("json export = %s, error = %v", jsonData, err)
}
csvData, err := writer.ExportCSV(context.Background(), ConfigAuditQuery{})
if err != nil || !strings.Contains(string(csvData), "changed_fields") {
t.Fatalf("csv export = %s, error = %v", csvData, err)
}
}
func TestFileAuditWriterCleanupKeepsRecentAndDeletesExpiredEvents(t *testing.T) {
root := t.TempDir()
writer, err := NewFileAuditWriter(root)
if err != nil {
t.Fatal(err)
}
now := time.Date(2026, 8, 26, 0, 0, 0, 0, time.UTC)
for index, createdAt := range []time.Time{now.Add(-ConfigAuditRetention - time.Nanosecond), now.Add(-ConfigAuditRetention + time.Nanosecond), now} {
event := ConfigAuditEvent{
Operation: ConfigOperationUpdate, Section: SectionEmail, ActorID: "user-" + string(rune('1'+index)), ActorRole: "super_admin",
FromGeneration: uint64(index + 1), ToGeneration: uint64(index + 2), Result: "success", CreatedAt: createdAt,
}
if err := writer.WriteConfigAudit(context.Background(), event); err != nil {
t.Fatal(err)
}
}
deleted, err := writer.Cleanup(context.Background(), now)
if err != nil || deleted != 1 {
t.Fatalf("cleanup deleted = %d, error = %v", deleted, err)
}
items, err := writer.Query(context.Background(), ConfigAuditQuery{})
if err != nil || len(items) != 2 {
t.Fatalf("remaining events = %d, error = %v", len(items), err)
}
}