From 5d7812a093f717d28b7f09c50438d5f06b814f20 Mon Sep 17 00:00:00 2001 From: kolaente Date: Thu, 11 Jun 2026 21:33:08 +0200 Subject: [PATCH] fix(audit): handle reopen failure after a failed rotation If both the rename and the reopen fail, logFile stayed nil while initialized was still true, panicking on the next write. Propagate the reopen error and retry the open on the next write so it self-heals. --- pkg/audit/writer.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/pkg/audit/writer.go b/pkg/audit/writer.go index 548c380fe..feccdb6f3 100644 --- a/pkg/audit/writer.go +++ b/pkg/audit/writer.go @@ -18,6 +18,7 @@ package audit import ( "encoding/json" + "errors" "fmt" "os" "path/filepath" @@ -132,6 +133,15 @@ func WriteAuditEvent(entry *Entry) error { return err } + // A failed rotation can leave us without an open file — retry the open + // here so writes self-heal via the router's retries instead of panicking. + if logFile == nil { + if err := openLogFileLocked(); err != nil { + mu.Unlock() + return err + } + } + written, err := logFile.Write(append(line, '\n')) currentSize += int64(written) if err == nil && time.Since(lastSync) > time.Second { @@ -159,7 +169,9 @@ func rotateIfNeededLocked(addition int64) error { rotatedPath := rotatedFileName(logfilePath, time.Now().UTC()) if err := os.Rename(logfilePath, rotatedPath); err != nil { // Reopen the original so logging continues even if rotation failed. - _ = openLogFileLocked() + if openErr := openLogFileLocked(); openErr != nil { + return errors.Join(fmt.Errorf("could not rotate audit log: %w", err), openErr) + } return fmt.Errorf("could not rotate audit log: %w", err) }