kanban gc: validate retention flags before the workspace sweep

(cherry picked from commit f7e6505fff08955ee0b46c9972002ab1c015e287)
This commit is contained in:
beardthelion
2026-09-21 21:38:01 -05:00
committed by kshitij
parent b01b1c8b5a
commit 4baff6fbaf
2 changed files with 22 additions and 4 deletions

View File

@@ -305,6 +305,10 @@ def _cmd_watch(args: argparse.Namespace) -> int:
def _cmd_gc(args: argparse.Namespace) -> int:
"""Remove archived tasks' scratch workspaces, old events, and old worker logs."""
import shutil
event_days = getattr(args, "event_retention_days", 30)
log_days = getattr(args, "log_retention_days", 30)
if event_days < 0 or log_days < 0:
return _err("kanban gc: retention days must be >= 0 (0 disables that sweep)", 2)
scratch_root = kb.workspaces_root()
removed_ws = 0
with kbc.connect_closing() as conn:
@@ -338,10 +342,6 @@ def _cmd_gc(args: argparse.Namespace) -> int:
shutil.rmtree(path, ignore_errors=True)
removed_ws += 1
event_days = getattr(args, "event_retention_days", 30)
log_days = getattr(args, "log_retention_days", 30)
if event_days < 0 or log_days < 0:
return _err("kanban gc: retention days must be >= 0 (0 disables that sweep)", 2)
removed_events = 0
if event_days:
with kbc.connect_closing() as conn:

View File

@@ -71,6 +71,24 @@ def test_cmd_gc_negative_days_errors_and_deletes_nothing(board, capsys):
assert log.exists()
def test_cmd_gc_negative_days_leaves_workspaces_untouched(board):
"""Invalid retention must refuse before ANY sweep: the workspace collection
runs first in the command body, so this fixture proves ordering, not just
event/log preservation."""
with kbc.connect_closing() as conn:
tid = kb.create_task(conn, title="archived with workspace")
with kb.write_txn(conn):
conn.execute(
"UPDATE tasks SET status='archived', workspace_kind='scratch' WHERE id=?",
(tid,),
)
ws = kb.workspaces_root() / tid
ws.mkdir(parents=True)
(ws / "scratch.txt").write_text("keep me")
assert kanban_ops._cmd_gc(_args(event_days=-1)) != 0
assert (ws / "scratch.txt").exists()
def test_cmd_gc_zero_days_disables_sweeps(board):
with kbc.connect_closing() as conn:
tid = _done_task_with_old_event(conn)