Conversation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the
📝 WalkthroughWalkthroughThis change introduces audit log retention functionality by extending configuration structures to include Changes
Sequence Diagram(s)sequenceDiagram
participant Config as Configuration Loader
participant Store as File Audit Store
participant Cleaner as Background Cleaner
participant Server as Frontend Server
Config->>Store: New(baseDir, retentionDays)
Store->>Cleaner: newCleaner(baseDir, retentionDays)
Cleaner->>Cleaner: Start 24-hour ticker loop
Cleaner-->>Store: Running in background
Store-->>Config: Return Store instance
Config->>Server: Initialize with audit store
Note over Server: auditStore holds Store reference
Server->>Server: Graceful shutdown triggered
Server->>Store: Close()
Store->>Cleaner: Stop via stopCh
Cleaner->>Cleaner: Exit loop, cleanup
Cleaner-->>Store: Stopped
Store-->>Server: Cleanup complete
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@internal/persis/fileaudit/cleaner_test.go`:
- Line 109: Update the misspelled word "unparseable" to the standard spelling
"unparsable" in the test description strings found in
internal/persis/fileaudit/cleaner_test.go (e.g. the string "jsonl file with
unparseable date name should not be deleted" and the two other occurrences
flagged by static analysis). Make the exact string replacements in the test
cases so all three assertions/readable messages use "unparsable" consistently.
In `@internal/persis/fileaudit/cleaner.go`:
- Around line 56-75: The purgeExpiredFiles cutoff currently uses
AddDate(0,0,-c.retentionDays) making retentionDays=7 keep 8 days; update the
cutoff computation in cleaner.purgeExpiredFiles (where cutoff is set) to
AddDate(0,0,-c.retentionDays+1) so files dated on the cutoff day are considered
expired (i.e., keep exactly retentionDays including today), or instead add a
clarifying comment on the inclusive/exclusive boundary if you intend to keep the
current behavior.
In `@internal/service/frontend/server.go`:
- Around line 805-809: The signal handler in setupGracefulShutdown currently
calls srv.httpServer.Shutdown(shutdownCtx) and thus skips coordinated cleanup;
change it to invoke srv.Shutdown(shutdownCtx) so the server's full shutdown path
runs (which calls auditStore.Close, syncService.Stop, sseHub.Shutdown, etc.).
Ensure setupGracefulShutdown uses the same shutdownCtx and error handling when
calling srv.Shutdown and remove or avoid directly calling
srv.httpServer.Shutdown so all cleanup in srv.Shutdown executes on
SIGINT/SIGTERM.
🧹 Nitpick comments (6)
internal/cmn/config/config.go (1)
131-134: Consider validatingRetentionDaysis non-negative.A negative
RetentionDayswould silently behave like0(keep forever) since the store only creates a cleaner whenretentionDays > 0. This is safe but could mask a configuration mistake. Consider adding validation inValidate()or clamping in the loader.internal/cmn/config/loader_test.go (1)
1189-1234: Missing test coverage forRetentionDaysconfiguration.The
TestLoad_Auditsuite only tests theEnabledtoggle. Consider adding sub-tests that verifyRetentionDayscan be set via YAML (audit.retentionDays: 30) and overridden via theDAGU_AUDIT_RETENTION_DAYSenvironment variable, similar to how other config fields are tested in this file.internal/service/frontend/server.go (1)
70-70: Holding a concrete*fileaudit.Storecouples the server to the file-based implementation.The
auditStorefield is typed as*fileaudit.Storerather than an interface (e.g.,io.Closer). Since the server only needs to callClose()on it, consider usingio.Closerto keep the server decoupled from the persistence layer. This is a minor point given the current architecture.internal/persis/fileaudit/store.go (1)
42-61: Cleaner goroutine starts eagerly in constructor — consider implications.
newCleaner(line 57) spawns a goroutine immediately. Two things to note:
- The cleaner's
purgeExpiredFilesdoesos.Removeon files thatQuerymight be reading concurrently. This is safe only becausereadEntriesFromFilealready handlesos.ErrNotExistgracefully (line 146). Worth a brief comment near the cleaner field or construction to document this intentional design.- If
Close()is never called (e.g., error paths in the caller), the goroutine leaks. Consider whether the caller (server wiring) covers all error/shutdown paths.Neither is a blocker — just flagging for awareness.
internal/persis/fileaudit/cleaner.go (2)
20-30: No panic recovery on the background goroutine.If
purgeExpiredFilesever panics (e.g., an unexpected runtime error), it would crash the entire process. Consider wrapping the goroutine body with a deferred recover, or at minimum logging the panic before re-raising.This is low-risk since the current implementation only does I/O and parsing, but it's a defensive practice for long-lived background goroutines.
49-54:stop()doesn't wait for the goroutine to exit.
Close()→stop()signals the goroutine but returns immediately. If shutdown code subsequently removes or inspects the audit directory, the goroutine may still be mid-purge. Consider adding async.WaitGroupor adonechannel if you need deterministic shutdown ordering.Not a blocker for the current use case, but worth noting.
Example with WaitGroup for deterministic shutdown
type cleaner struct { baseDir string retentionDays int stopCh chan struct{} stopOnce sync.Once + wg sync.WaitGroup } func newCleaner(baseDir string, retentionDays int) *cleaner { c := &cleaner{ baseDir: baseDir, retentionDays: retentionDays, stopCh: make(chan struct{}), } + c.wg.Add(1) go c.run() return c } func (c *cleaner) run() { + defer c.wg.Done() c.purgeExpiredFiles() // ... } func (c *cleaner) stop() { c.stopOnce.Do(func() { close(c.stopCh) }) + c.wg.Wait() }
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #1640 +/- ##
==========================================
+ Coverage 69.79% 69.87% +0.07%
==========================================
Files 331 332 +1
Lines 37248 37322 +74
==========================================
+ Hits 25999 26080 +81
+ Misses 9185 9173 -12
- Partials 2064 2069 +5
... and 13 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
Summary by CodeRabbit
Release Notes
AUDIT_RETENTION_DAYSenvironment variable or configuration. Default is 7 days; use 0 to retain logs indefinitely.