RBAC (api/internal/authz) is live on /query and /dashboards, backed by a new enterprise/ module (session issuance, audit logging, RBAC storage, OIDC/SAML protocol wiring) that core never imports -- only calls over HTTP. Found and fixed a real cross-tenant vulnerability in dashboards (no tenant_id filtering at all) while writing the threat model doc. Two things are explicitly NOT done, documented rather than hidden: tenant isolation for log data itself (/query still shares one ClickHouse connection and Tantivy index across every tenant -- RBAC controls who can query, not what a query can see), and human SSO login (protocol wiring exists, no HTTP handler calls it yet). See docs/security/threat-model.md and docs/phase-4-runbook.md. Also adds deploy/ (Go Operator + Helm chart, validated offline only -- no cluster was reachable in this environment).
43 lines
1.1 KiB
Go
43 lines
1.1 KiB
Go
package audit
|
|
|
|
import (
|
|
"context"
|
|
"path/filepath"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestFileSinkRoundTrip(t *testing.T) {
|
|
path := filepath.Join(t.TempDir(), "checkpoints.jsonl")
|
|
sink := NewFileSink(path)
|
|
ctx := context.Background()
|
|
|
|
none, err := sink.LastCheckpoint(ctx)
|
|
if err != nil {
|
|
t.Fatalf("LastCheckpoint on a nonexistent file: %v", err)
|
|
}
|
|
if none != nil {
|
|
t.Fatalf("expected nil for a nonexistent checkpoint file, got %+v", none)
|
|
}
|
|
|
|
cp1 := Checkpoint{FromID: 1, ToID: 10, Hash: "hash1", CreatedAt: time.Now().UTC().Truncate(time.Second)}
|
|
if err := sink.Write(ctx, cp1); err != nil {
|
|
t.Fatalf("Write: %v", err)
|
|
}
|
|
cp2 := Checkpoint{FromID: 11, ToID: 20, PrevCheckpointHash: "hash1", Hash: "hash2", CreatedAt: time.Now().UTC().Truncate(time.Second)}
|
|
if err := sink.Write(ctx, cp2); err != nil {
|
|
t.Fatalf("Write: %v", err)
|
|
}
|
|
|
|
last, err := sink.LastCheckpoint(ctx)
|
|
if err != nil {
|
|
t.Fatalf("LastCheckpoint: %v", err)
|
|
}
|
|
if last == nil {
|
|
t.Fatalf("expected a checkpoint, got nil")
|
|
}
|
|
if last.ToID != cp2.ToID || last.Hash != cp2.Hash {
|
|
t.Fatalf("got %+v, want the most recently written checkpoint %+v", last, cp2)
|
|
}
|
|
}
|