feat(audit): minimal slog AuditSink for capture I5 (#53)
Emits the request-level audit record to structured logs (scraped by the existing alloy/loki substrate) and surfaces security events at warn level. Placeholder behind the AuditSink interface — the classification- aware loki+buffer+reconcile sink (confidential fails closed, internal degrades) lands in #54 and replaces this without touching callers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
package audit_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"log/slog"
|
||||
"testing"
|
||||
|
||||
"github.com/mathiasbq/hyperguild/ingestion/internal/audit"
|
||||
"github.com/mathiasbq/hyperguild/ingestion/internal/capture"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSlogSinkRecordsEntryAndSecurityEvents(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
sink := audit.NewSlogSink(slog.New(slog.NewTextHandler(&buf, nil)))
|
||||
|
||||
err := sink.Record(context.Background(), capture.AuditEntry{
|
||||
Principal: "koala-cli",
|
||||
Harness: "claude-code",
|
||||
EffectiveClassification: "confidential",
|
||||
Items: []string{"insight:wiki/a/facts/x.md"},
|
||||
SecurityEvents: []string{"asserted-vs-derived origin mismatch"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
out := buf.String()
|
||||
assert.Contains(t, out, "capture audit")
|
||||
assert.Contains(t, out, "koala-cli")
|
||||
assert.Contains(t, out, "confidential")
|
||||
assert.Contains(t, out, "capture security event")
|
||||
assert.Contains(t, out, "asserted-vs-derived origin mismatch")
|
||||
}
|
||||
|
||||
func TestSlogSinkNilLoggerDefaults(t *testing.T) {
|
||||
// nil logger must not panic.
|
||||
require.NotPanics(t, func() {
|
||||
_ = audit.NewSlogSink(nil).Record(context.Background(), capture.AuditEntry{})
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user