Documentation
¶
Overview ¶
Package auditlog provides the dedicated audit-event stream for SpeechKit.
Audit events are separate from the runtime log (cmd/speechkit/logging.go): the runtime log is for operator troubleshooting (debug-level slog JSON); the audit log is the customer's source of truth for SOC 2 / ISO 27001 / BSI C5 evidence and DSGVO Art. 30 verification.
Schema is documented in docs/compliance/audit-event-catalog.md and versioned via the _schema_version field. Major-version bumps require a CHANGELOG entry with SIEM-ingestion migration notes.
Usage:
if err := auditlog.AppendEvent(ctx, auditlog.Record{
Event: auditlog.EventProviderSelected,
Actor: auditlog.Actor{UserSID: sid},
Resource: map[string]any{
"provider_name": "whisper-cpp",
"provider_kind": "stt",
"endpoint_host": "127.0.0.1:8123",
"strategy": "local-only",
},
Outcome: auditlog.OutcomeSuccess,
}); err != nil {
slog.Warn("audit-log append failed", "err", err)
}
AppendEvent never returns an error that should crash the call site; it reports the failure via the returned error so the runtime log captures it. Call sites log-and-continue rather than abort the user action.
Index ¶
- Constants
- func AppendEvent(ctx context.Context, ev Record) error
- func CloseEventLog()
- func Configure(enabled_ bool, dir string, retentionDays_ int, eventLogEnabled bool)
- func ConfigureFromOptions(opts ConfigOptions) error
- func ConfigureOTLP(endpoint, certFile, keyFile, caFile string) error
- func InstallEventLogSource() error
- func OpenEventLog() error
- func ResetForTests()
- func ShutdownOTLP()
- type Actor
- type ConfigOptions
- type Event
- type Outcome
- type Record
Constants ¶
const SchemaVersion = "1"
SchemaVersion is bumped when the audit-event JSON shape changes in a way that breaks downstream SIEM ingestion. Increment requires a CHANGELOG.md entry under "## Audit-Log Schema" with migration notes.
Variables ¶
This section is empty.
Functions ¶
func AppendEvent ¶
AppendEvent serialises one Record and appends it to today's audit log. Returns an error if the write fails; callers MUST log-and-continue rather than abort the user action.
The ctx parameter is reserved for future trace propagation; the current implementation ignores it.
func Configure ¶
Configure is a backward-compatible wrapper around ConfigureFromOptions. Prefer ConfigureFromOptions for new call sites. When eventLogEnabled = true, each AppendEvent call also mirrors the record to the Windows Event Log source "kombify SpeechKit" (no-op on non-Windows). The source must be registered first via InstallEventLogSource (admin-required).
func ConfigureFromOptions ¶
func ConfigureFromOptions(opts ConfigOptions) error
ConfigureFromOptions configures the audit-log package from a ConfigOptions value. Must be called once during startup before any AppendEvent call. When Enabled = false, all subsequent AppendEvent calls are no-ops. The file sink is always the canonical sink; Event Log and OTLP are mirrors. Failure to open optional sinks (Event Log, OTLP) is non-fatal and is logged at slog.Warn; the file sink remains active regardless.
func ConfigureOTLP ¶
ConfigureOTLP creates an OTLP exporter targeting endpoint with optional mTLS. Returns nil when endpoint is empty (sink disabled). Idempotent: re-calling shuts down the previous provider and starts a new one.
Endpoint format: hostname:port (e.g. "loki.internal.example:4318"). HTTPS with mTLS is used when certFile + keyFile are provided. Plain HTTP (no TLS) is used when no cert files are present — suitable for dev/test deployments behind an authenticating proxy.
caFile is optional; when non-empty its PEM certificate(s) are added to the root CA pool for server-certificate verification.
func InstallEventLogSource ¶
func InstallEventLogSource() error
InstallEventLogSource is a no-op on non-Windows platforms.
func ResetForTests ¶
func ResetForTests()
ResetForTests releases the current file handle and clears all package state. INTENDED FOR TEST USE ONLY. Call from internal/auditlogtest.Reset (not directly from outside this module). A direct production call silently destroys the audit stream — a compliance bug.
func ShutdownOTLP ¶
func ShutdownOTLP()
ShutdownOTLP flushes pending records and closes the provider. Called from ResetForTests and during graceful shutdown. Safe to call when not configured.
Types ¶
type Actor ¶
type Actor struct {
UserSID string `json:"user_sid,omitempty"`
SessionID string `json:"session_id,omitempty"`
}
Actor identifies who or what triggered the audited action.
type ConfigOptions ¶
type ConfigOptions struct {
// Enabled gates the entire audit log. When false, AppendEvent is a no-op.
Enabled bool
// Dir is the directory under which audit-YYYY-MM-DD.log files are written.
Dir string
// RetentionDays is the number of days to keep audit files. Zero → 90 days.
RetentionDays int
// EventLogEnabled mirrors records to the Windows Event Log source
// "kombify SpeechKit". No-op on non-Windows.
EventLogEnabled bool
// OTLPEndpoint is the host:port of the OTLP HTTP log receiver. Empty
// disables the OTLP sink.
OTLPEndpoint string
// OTLPCertFile and OTLPKeyFile enable mTLS for the OTLP sink when both
// are non-empty. OTLPCAFile is optional and adds to the root CA pool.
OTLPCertFile string
OTLPKeyFile string
OTLPCAFile string
}
ConfigOptions holds all configuration for the audit-log package. Use ConfigureFromOptions instead of the older positional-arg Configure. The options struct scales for additional sinks (Phase 3+) without growing the positional-arg list further.
type Event ¶
type Event string
Event is the namespaced identifier of an audit event type. Every event used in code MUST appear here and in docs/compliance/audit-event-catalog.md.
const ( EventProviderSelected Event = "provider.selected" EventVoiceAgentSessionStart Event = "voiceagent.session.start" EventVoiceAgentSessionEnd Event = "voiceagent.session.end" EventSettingsChanged Event = "settings.changed" EventUpdateInstalled Event = "update.installed" EventAuthFailed Event = "auth.failed" EventPrivacyExport Event = "privacy.export" EventPrivacyDelete Event = "privacy.delete" // EventPolicyApplied is emitted once at startup after config is loaded, // when registry policy values are present. Resource fields: "source" // (registry hive that first contributed a value) and "keys_locked_count" // (total number of registry values that overrode config.toml). EventPolicyApplied Event = "policy.applied" // EventBYOKKeyUpdated is emitted when the customer sets a new BYOK API key // for any provider (OpenAI, Groq, Google, HuggingFace). Resource fields: // "provider_name" (string), "region" (string, empty for non-regional // providers), "fingerprint_truncated" (first 16 hex chars of SHA-256 of the // key — correlates events without leaking the key itself). EventBYOKKeyUpdated Event = "byok.key_updated" // EventModeStart is emitted when a SpeechKit mode runtime transitions to // Running (Outcome=success) or to Failed from Starting (Outcome=failure). // Source: subscribers of pkg/speechkit/lifecycle.Registry. Resource // fields: "mode" (string), "requires" (array of SharedDepKey, omitted // when empty), "error" (string, only on failure). See // docs/compliance/audit-event-catalog.md "mode.start" for the full // contract incl. the mode.start/mode.stop pairing rule. EventModeStart Event = "mode.start" // EventModeStop is emitted when a SpeechKit mode runtime transitions to // Stopped (Outcome=success) or to Failed from Stopping (Outcome=failure). // Resource fields mirror EventModeStart with "released" instead of // "requires" — the shared deps the runtime relinquished as it stopped. EventModeStop Event = "mode.stop" )
type Record ¶
type Record struct {
SchemaVersion string `json:"_schema_version"`
Timestamp time.Time `json:"ts"`
Event Event `json:"event"`
Actor Actor `json:"actor"`
Resource map[string]any `json:"resource,omitempty"`
Outcome Outcome `json:"outcome"`
TraceID string `json:"trace_id,omitempty"`
}
Record is the serialised shape of one audit-log line.