Merge origin/main into feature/contextual-safety-review

Integration fixes the merge required:
- guard tools after the strict-schema downgrade, so the copy
  dataclasses.replace returns is the object the safety wrapper mutates
- await _ctx_client, which main made async for the Caido bootstrap handle
- pass main's extra_files through with the isolated local sources
- keep DEFAULT_SAFETY_MODE alongside main's new report/state imports
- rebuild the committed viewer bundle from the merged frontend sources
- pin the browser-session safety phrase in test_safety_prompt so it no
  longer matches unrelated prompt text, and stamp safety_mode on the
  workspace-file resume record
This commit is contained in:
Ahmed Allam
2026-08-24 10:48:22 +00:00
124 changed files with 10387 additions and 463 deletions
+81
View File
@@ -129,6 +129,69 @@ def test_resume_restores_a_target_less_workspace_mount(
assert args.instruction == "audit the auth flow"
def test_resume_revalidates_persisted_workspace_files(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Resume places the same files again, and drops ones that went away."""
work = tmp_path / "project"
work.mkdir()
kept = tmp_path / "wordlist.txt"
kept.write_text("admin\n", encoding="utf-8")
monkeypatch.chdir(tmp_path)
_write_run_record(
tmp_path / "strix_runs",
"pentest_abcd",
{
"run_name": "pentest_abcd",
"targets_info": [],
"local_sources": [],
"workspace_mount": str(work),
"workspace_files": [
{"source_path": str(kept), "workspace_path": "/workspace/lists/words.txt"},
{"source_path": str(tmp_path / "gone.txt"), "workspace_path": "/workspace/g.txt"},
],
"safety_mode": "guarded",
},
)
monkeypatch.setattr(sys, "argv", ["strix", "--resume", "pentest_abcd"])
args = cli_main.parse_arguments()
assert args.workspace_files == [
{"source_path": str(kept), "workspace_path": "/workspace/lists/words.txt"}
]
def test_resume_rejects_an_edited_workspace_file_path(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
) -> None:
"""A hand-edited record cannot place a file outside the workspace."""
work = tmp_path / "project"
work.mkdir()
source = tmp_path / "wordlist.txt"
source.write_text("admin\n", encoding="utf-8")
monkeypatch.chdir(tmp_path)
_write_run_record(
tmp_path / "strix_runs",
"pentest_abcd",
{
"run_name": "pentest_abcd",
"targets_info": [],
"local_sources": [],
"workspace_mount": str(work),
"workspace_files": [
{"source_path": str(source), "workspace_path": "/etc/cron.d/payload"}
],
},
)
monkeypatch.setattr(sys, "argv", ["strix", "--resume", "pentest_abcd"])
with pytest.raises(SystemExit):
cli_main.parse_arguments()
assert "invalid workspace file" in capsys.readouterr().err
def test_resume_reports_a_missing_workspace_directory(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
) -> None:
@@ -166,3 +229,21 @@ def test_resume_still_requires_targets_or_a_workspace(
cli_main.parse_arguments()
assert "has no targets_info" in capsys.readouterr().err
def test_resume_non_object_run_json_exits(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str]
) -> None:
monkeypatch.chdir(tmp_path)
run_dir = tmp_path / "strix_runs" / "pentest_abcd"
run_dir.mkdir(parents=True)
(run_dir / "run.json").write_text("[]", encoding="utf-8")
monkeypatch.setattr(sys, "argv", ["strix", "--resume", "pentest_abcd"])
with pytest.raises(SystemExit) as exc_info:
cli_main.parse_arguments()
assert exc_info.value.code == 2
captured = capsys.readouterr()
assert "run.json unreadable" in captured.err
assert "not an object" in captured.err