docs(containment): complete CLI reference

Document both containment flags and clarify the resume and alias guard behavior.

DOPS-1172

👽 Directed by Chrispy <chris@akuru.com.au>
Authored by LLM gpt-5.6-sol -- Ranger
This commit is contained in:
👽 Chrispy 2026-09-03 10:11:32 +10:00
parent 8594b7d0fc
commit 1c17472d5b
No known key found for this signature in database
4 changed files with 31 additions and 8 deletions

View file

@ -17,7 +17,7 @@ strix (--target <target> | --target-list <path>) [options]
When the target is an API spec, Strix copies it into the agent's workspace and authorizes the base URLs it declares (including those resolved from a Postman environment) as in-scope hosts - so the agent reads the contract and tests the full declared surface instead of discovering endpoints by crawling. Pair the spec with the deployed base URL (e.g. `--target ./openapi.yaml --target https://api.example.com`) so the agent has a reachable host to attack.
<Note>
A local directory is mounted into the sandbox live and **writable**, so the agent edits your real files (`.git` excepted). Commit or stash first.
By default, a local directory is mounted into the sandbox live and **writable**, so the agent edits your real files (`.git` excepted). Commit or stash first, or use `--read-only-local-targets` with a separate `--workspace-mount` for immutable evidence.
</Note>
<Note>
@ -44,6 +44,19 @@ strix (--target <target> | --target-list <path>) [options]
[Workspace files](/usage/instructions#workspace-files).
</ParamField>
<ParamField path="--read-only-local-targets" type="boolean">
Mount every local-code target read-only as immutable evidence. Backends that
cannot enforce read-only bind mounts reject the run instead of silently
making the target writable. Pair this option with `--workspace-mount` when
the agent should produce remediation changes.
</ParamField>
<ParamField path="--workspace-mount" type="string">
Mount an existing host directory as a writable working area separate from
scan targets. It grants no assessment scope. The path must not be the same as,
contain, or be contained by a read-only local target.
</ParamField>
<ParamField path="--scan-mode, -m" type="string" default="deep">
Scan depth: `quick`, `standard`, or `deep`.
</ParamField>

View file

@ -376,11 +376,15 @@ Examples:
"--resume picks up where the prior run left off, including the "
"original target list."
)
if args.workspace_mount or args.read_only_local_targets:
if args.workspace_mount:
parser.error(
"Cannot combine --resume with --workspace-mount or "
"--read-only-local-targets. Resume restores the original "
"containment configuration."
"Cannot combine --resume with --workspace-mount. Resume restores "
"the original containment configuration."
)
if args.read_only_local_targets:
parser.error(
"Cannot combine --resume with --read-only-local-targets. Resume "
"restores the original containment configuration."
)
_load_resume_state(args, parser)
agents_path = runtime_state_dir(run_dir_for(args.resume)) / "agents.json"

View file

@ -216,6 +216,8 @@ def _same_location(left: Path, right: Path) -> bool:
def _reject_workspace_overlap(workspace: Path, local_sources: list[dict[str, Any]]) -> None:
workspace = workspace.expanduser().resolve()
for source in local_sources:
# Only immutable evidence needs an alias guard. Two writable views do
# not weaken the containment contract.
if not source.get("read_only"):
continue
evidence = Path(str(source["source_path"])).expanduser().resolve()

View file

@ -97,15 +97,19 @@ def test_parse_arguments_rejects_resume_with_containment_overrides(
if flag == "workspace":
workspace = tmp_path / "remediation"
workspace.mkdir()
argv.extend(["--workspace-mount", str(workspace)])
expected_flag = "--workspace-mount"
argv.extend([expected_flag, str(workspace)])
else:
argv.append("--read-only-local-targets")
expected_flag = "--read-only-local-targets"
argv.append(expected_flag)
monkeypatch.setattr(sys, "argv", argv)
with pytest.raises(SystemExit):
cli_main.parse_arguments()
assert "Resume restores the original containment configuration" in capsys.readouterr().err
error = capsys.readouterr().err
assert expected_flag in error
assert "Resume restores the original containment configuration" in error
def _write_run_record(runs_dir: Path, run_name: str, record: dict[str, Any]) -> None: