mirror of
https://github.com/usestrix/strix.git
synced 2026-10-11 03:37:54 +00:00
strix --resume with no run name now lists the runs in ./strix_runs inline in the terminal (started, target, status, findings, run name), newest first, with arrow-key selection, type-to-search and esc to cancel. Picking a run continues through the same path as --resume <name>. Headless or non-TTY launches error with the run list instead.
111 lines
3.6 KiB
Python
111 lines
3.6 KiB
Python
"""Tests for `strix --resume` without a run name."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import importlib
|
|
import json
|
|
import sys
|
|
from typing import TYPE_CHECKING, Any
|
|
|
|
import pytest
|
|
|
|
|
|
if TYPE_CHECKING:
|
|
from pathlib import Path
|
|
|
|
|
|
cli_main: Any = importlib.import_module("strix.interface.main")
|
|
|
|
|
|
def _write_run(base: Path, name: str, *, state: bool = True) -> None:
|
|
run_dir = base / name
|
|
(run_dir / ".state").mkdir(parents=True)
|
|
(run_dir / "run.json").write_text(
|
|
json.dumps(
|
|
{
|
|
"run_name": name,
|
|
"status": "completed",
|
|
"start_time": "2026-10-04T10:00:00+00:00",
|
|
"targets_info": [
|
|
{
|
|
"type": "web_application",
|
|
"details": {"target_url": "https://example.com"},
|
|
"original": "https://example.com",
|
|
}
|
|
],
|
|
}
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
if state:
|
|
(run_dir / ".state" / "agents.json").write_text("{}", encoding="utf-8")
|
|
|
|
|
|
def test_bare_resume_defers_to_the_picker(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None:
|
|
monkeypatch.chdir(tmp_path)
|
|
_write_run(tmp_path / "strix_runs", "example-com_1111")
|
|
monkeypatch.setattr(sys, "argv", ["strix", "--resume"])
|
|
|
|
args = cli_main.parse_arguments()
|
|
|
|
assert args.resume is None
|
|
assert args.resume_picker is True
|
|
assert args.needs_setup is False
|
|
assert args.resume is None
|
|
assert args.targets_info == []
|
|
|
|
|
|
def test_bare_resume_with_no_runs_is_an_error(
|
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
monkeypatch.chdir(tmp_path)
|
|
monkeypatch.setattr(sys, "argv", ["strix", "--resume"])
|
|
|
|
with pytest.raises(SystemExit):
|
|
cli_main.parse_arguments()
|
|
|
|
assert "no runs in ./strix_runs" in capsys.readouterr().err
|
|
|
|
|
|
def test_bare_resume_headless_lists_the_runs_instead_of_prompting(
|
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
monkeypatch.chdir(tmp_path)
|
|
_write_run(tmp_path / "strix_runs", "example-com_1111")
|
|
_write_run(tmp_path / "strix_runs", "example-com_2222", state=False)
|
|
monkeypatch.setattr(sys, "argv", ["strix", "-n", "--resume"])
|
|
|
|
with pytest.raises(SystemExit):
|
|
cli_main.parse_arguments()
|
|
|
|
err = capsys.readouterr().err
|
|
assert "--resume needs a run name in headless mode" in err
|
|
assert "example-com_1111 completed 2026-10-04T10:00:00 https://example.com" in err
|
|
assert "example-com_2222 completed 2026-10-04T10:00:00 https://example.com" in err
|
|
assert "example-com_2222" in err
|
|
|
|
|
|
def test_bare_resume_still_rejects_targets(
|
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
monkeypatch.chdir(tmp_path)
|
|
_write_run(tmp_path / "strix_runs", "example-com_1111")
|
|
monkeypatch.setattr(sys, "argv", ["strix", "--resume", "-t", "https://example.com"])
|
|
|
|
with pytest.raises(SystemExit):
|
|
cli_main.parse_arguments()
|
|
|
|
assert "Cannot combine --resume with --target" in capsys.readouterr().err
|
|
|
|
|
|
def test_named_resume_without_agent_state_is_an_error(
|
|
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
|
|
) -> None:
|
|
monkeypatch.chdir(tmp_path)
|
|
_write_run(tmp_path / "strix_runs", "example-com_1111", state=False)
|
|
monkeypatch.setattr(sys, "argv", ["strix", "--resume", "example-com_1111"])
|
|
|
|
with pytest.raises(SystemExit):
|
|
cli_main.parse_arguments()
|
|
|
|
assert "never reached its first agent snapshot" in capsys.readouterr().err
|