fix(cli): refuse autoroute up when a stale backup exists from a crash

The pid-record check only catches a still-live duplicate process; a
SIGKILL'd `up` leaves no live pid but does leave AUTOROUTE_BACKUP_PATH
behind. Without this guard, a fresh `up` overwrote that backup with
the currently-patched Claude settings instead of the true originals,
so `down`/Ctrl-C would restore the wrong content permanently. up.py's
`lite up` already guards the analogous case; mirror it here.
This commit is contained in:
Krrish Dholakia 2026-07-15 12:55:04 -07:00
parent cb978a570d
commit 7e49429eca
2 changed files with 26 additions and 0 deletions

View file

@ -83,6 +83,12 @@ def up() -> None:
"Run `lite autoroute down` first."
)
if AUTOROUTE_BACKUP_PATH.exists():
raise click.ClickException(
f"{AUTOROUTE_BACKUP_PATH} already exists -- `lite autoroute up` looks like it's already "
"running (or crashed without cleanup). Run `lite autoroute down` first."
)
master_key = _mint_and_embed_master_key()
port = allocate_free_port()
base_url = f"http://127.0.0.1:{port}"

View file

@ -71,6 +71,26 @@ class TestUpCommand:
assert "lite autoroute down" in result.output
assert config_path.read_text() == yaml.safe_dump({"model_list": []})
def test_refuses_when_backup_exists_after_an_unclean_crash(self, monkeypatch, tmp_path):
"""A prior `up` that was SIGKILL'd leaves no live pid but does leave a stale backup file.
Without this guard, a fresh `up` would overwrite that backup with the currently-patched
(not original) Claude settings, so `down`/Ctrl-C would restore the wrong content forever.
"""
config_path, _log_path, claude_settings_path, backup_path, _pid_record_path = _patch_paths(
monkeypatch, tmp_path
)
config_path.write_text(yaml.safe_dump({"model_list": []}))
claude_settings_path.write_text(json.dumps({"env": {"ANTHROPIC_AUTH_TOKEN": "stale-patched-token"}}))
write_backup(ClaudeBackupRecord(existed=True, content={"theme": "dark"}), backup_path)
result = self.runner.invoke(up)
assert result.exit_code != 0
assert "already exists" in result.output
assert "lite autoroute down" in result.output
assert json.loads(backup_path.read_text())["content"] == {"theme": "dark"}
def test_happy_path_patches_settings_then_restores_everything_on_stop(self, monkeypatch, tmp_path):
config_path, log_path, claude_settings_path, backup_path, pid_record_path = _patch_paths(monkeypatch, tmp_path)
config_path.write_text(yaml.safe_dump({"model_list": []}))