# The test sandbox is enforced via four-layer rules (FR1-FR4) — see the styleguide ## The 4-Layer Model | Layer | Mechanism | Where | Default-on? | |---|---|---|---| | Layer 1 | Python runtime file-I/O guard (`sys.addaudithook`) | `tests/conftest.py:_sandbox_audit_hook` | Yes | | Layer 2 | `isolate_workspace` autouse + `pyproject.toml --basetemp` | `tests/conftest.py` + `pyproject.toml` | Yes | | Layer 3 | OS-level restricted-token PowerShell wrapper | `scripts/run_tests_sandboxed.ps1` | **Opt-in** | | Layer 4 | Static audit script (CI gate) | `scripts/audit_test_sandbox_violations.py` | Yes (informational) / opt-in (`--strict`) | Layer 1 + Layer 2 + Layer 4 are file-presence-on = enabled (delete the relevant file to disable). Layer 3 requires explicit invocation. ## The `--config` CLI Flag (replaces `SLOP_CONFIG`) The historical `SLOP_CONFIG` env var has been removed from `src/paths.py`. The CLI flag `--config ` is now the ONLY supported mechanism for overriding the default `/config.toml` location. ```bash # Use the default /config.toml uv run python sloppy.py # Override uv run python sloppy.py --config /path/to/your/config.toml ``` `sloppy.py` calls `paths.set_config_override(Path(args.config).resolve())` AFTER `parse_args()` and BEFORE any `from src.gui_2 import App` import. This is the only way to override the config path in production. ## The `--basetemp` Rule `pyproject.toml` sets `addopts = "--basetemp=tests/artifacts/_pytest_tmp"`. This redirects pytest's `tmp_path` and `tmp_path_factory` fixtures (which default to `%TEMP%\pytest-of-\` on Windows) into `./tests/artifacts/`. This is what allows the Layer 1 allowlist to be a single rule: "anything under `./tests/` is allowed." ## Layer 1 Audit Hook Contract `tests/conftest.py:_sandbox_audit_hook` is a `sys.addaudithook` callback. It fires on every `open()` call. Behavior: - **Reads** (mode `r`, `rb`): pass through, no check - **Writes** (mode contains `w`, `a`, `x`, `+`): check path - **Allowed** if path resolves under: - `/tests/` - Path contains `.pytest_cache`, `__pycache__`, `.coverage`, `.slop_cache`, or `.ruff_cache` - Original path string starts with `\\.\` (Windows device namespace) or `/dev/` (Unix device namespace) - **Blocked** otherwise: raises `RuntimeError("TEST_SANDBOX_VIOLATION: attempted to write to ...")`