Repository navigation
feat(api): configurable audit-event retention - #14
Merged
Merged
Conversation
Audit events accumulated in the audit_events table with no way to bound
growth — a documented beta limitation ("no retention policy yet"). On a
long-lived install the table grows unbounded.
Add an opt-in retention window: --audit-retention-days (env
GAMEPLANE_AUDIT_RETENTION_DAYS), 0 = keep forever (default, preserves
current behaviour). When positive, a background sweep runs on API
startup and daily thereafter, deleting events older than the window.
- audit.Prune deletes rows whose ts predates a cutoff. ts is stored as
RFC3339 (fixed-width, zero-padded, UTC), so a lexicographic "ts < ?"
comparison is also chronological — no per-row parsing and the query
stays portable across the sqlite/pgx drivers.
- audit.RunRetention mirrors the telemetry goroutine lifecycle: sweeps
immediately, then every interval, returning on ctx cancel; a
non-positive window is a no-op.
- Surface it through the Helm chart as api.audit.retentionDays.
- Update the README known-limitations to reflect retention now exists
(external sink is still deferred).
Tests cover prune boundaries, the disabled no-op, and the start-up sweep.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
TestRunRetention_SweepsOnStart cancelled the context before calling RunRetention, but the start-up sweep's Prune uses that context for the DELETE — a pre-cancelled context makes the sweep a no-op (correct shutdown behaviour), so nothing was pruned and the test failed. Run RunRetention in a goroutine with a live context, poll until the start-up sweep prunes, then cancel and join. Production code unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: valgulnecron <39313199+ValgulNecron@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Closes part of a documented beta limitation — "audit events are stored in the database; there is no … retention policy yet." The
audit_eventstable previously grew unbounded on long-lived installs.Adds an opt-in retention window:
--audit-retention-days(envGAMEPLANE_AUDIT_RETENTION_DAYS), surfaced through the Helm chart asapi.audit.retentionDays. Default0= keep forever, preserving today's behaviour. When positive, a background sweep deletes events older than the window on API startup and once a day after.How
audit.Prune(ctx, cutoff)—DELETE FROM audit_events WHERE ts < ?.tsis stored as RFC3339 (fixed-width, zero-padded, UTC), so a lexicographic<is also chronological — no per-row time parsing, and the query stays portable across the sqlite/pgx drivers (matching the codebase's existing?-placeholder convention).audit.RunRetention(ctx, retention, interval, logger)— mirrors the existingtelemetry.Run(ctx)goroutine lifecycle: sweeps immediately on start, then every interval, returns onctxcancel; a non-positive window is an immediate no-op.serve()next to telemetry; newenvOrInthelper for the int env default.api.audit.retentionDaysrenders the flag only when> 0.Tests
audit_test.go: prune boundary (old pruned / recent kept), nothing-older-than-cutoff, disabled-is-no-op, and the start-up sweep. Verifiedhelm templaterenders the flag atretentionDays=30and omits it at the0default.Notes
No schema migration (retention is config + delete, not a schema change). No Pencil pass (no dashboard surface). Independent of #13 (disjoint
api/vsoperator/files).🤖 Generated with Claude Code