fix(memory): guard prune_history against negative keep_days - #8569
Closed
mbajaj92 wants to merge 1 commit into
Closed
fix(memory): guard prune_history against negative keep_days#8569mbajaj92 wants to merge 1 commit into
mbajaj92 wants to merge 1 commit into
Conversation
A negative history_max_days in config.json (hand edit, bad import, or corruption) caused prune_history() to compute a cutoff in the future, making every history file appear 'old' and deleting the entire daily history silently. Negative keep_days can never be intentional. Fall back to the default retention of 365 days and emit a WARNING instead of deleting all files. Zero retains its current meaning (drop everything before today). The dashboard path already clamps to min 7; this fix closes the same gap on the file-config path that goes through heartbeat.py. Fixes kirodotdev#8245
Author
|
Closing as a duplicate — #8246 merged the same fix 3 hours before this PR was opened. |
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.
Problem / Motivation
MemoryStore.prune_history()trusts itskeep_daysargument without validation. A negativehistory_max_daysinconfig.json— caused by a hand edit, bad import, or file corruption — makes the heartbeat wipe the entire daily history on every tick.When
keep_daysis negative,timedelta(days=keep_days)computes a future date, so every existing history file appears "older than the cutoff" and gets unlinked.Why it matters
Silent, unrecoverable data loss. A single corrupted config value causes the periodic heartbeat to delete all daily history files with only an
INFOlog. The user sees empty memory with no warning.The dashboard settings path already clamps to min 7 (
dashboard/handlers/memory.py); this fix closes the same gap on the file-config path (heartbeat.py→prune_history).What changed (motivation → approach → change)
Negative
keep_days→ future cutoff date → all files appear old → everything deleted.A negative value can never be intentional (you cannot keep a negative number of days of history). Fall back to the default retention of 365 days and emit a
WARNINGlog so the operator knows their config value is invalid — instead of silently deleting all history.Zero retains its current meaning: drop everything before today.
Tests
Added
TestPruneHistoryclass intest/test_memory.pywith three tests:test_negative_keep_days_does_not_delete_recent_files—keep_days=-1falls back to 365; a 10-day-old file is kepttest_zero_keep_days_drops_files_older_than_today— zero keeps its existing semantics; yesterday's file is deletedtest_positive_keep_days_deletes_old_files— normal path still works; only files older than the threshold are deletedManual verification
N/A — unit coverage sufficient. The code path is
heartbeat._beat() → prune_history(keep_days=config.memory.history_max_days); the guard fires on any negative integer regardless of how it arrives.Related Issues
Fixes #8245
Pattern harvest
Rule candidate: lint
Pattern: integer config value passed directly to a time-delta calculation without a lower-bound guard
Checklist