test: isolate ordinary unit runs from ambient credentials and provider I/O
Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a1468b-63fa-7710-85dc-8f2e16b3ebfa
This commit is contained in:
parent
922c26da0f
commit
b593c87983
14 changed files with 592 additions and 6 deletions
64
docs/development/safe-unit-tests.md
Normal file
64
docs/development/safe-unit-tests.md
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
# Safe unit-test entry point
|
||||
|
||||
Use `make test`, or `.venv/bin/python -I scripts/run_unit_tests.py`. Dependencies
|
||||
must already be installed; this path does not run uv, synchronize or download.
|
||||
`UNIT_PYTHON` may select another existing interpreter. `PHASE_MEMORY_REPO` remains
|
||||
an explicit local source option. Pass pytest options with `TEST_ARGS`, for example
|
||||
`make test TEST_ARGS='-q tests/test_safe_unit_runner.py'`.
|
||||
|
||||
The launcher creates an empty temporary HOME and temporary fixture root and starts
|
||||
an isolated (`-I`) Python interpreter with a constructed environment. Caller token,
|
||||
proxy, Python, pytest, XDG and Warden configuration variables are never copied or
|
||||
inventoried. Third-party pytest plugin autoload is disabled. Tests can explicitly
|
||||
introduce synthetic variables with monkeypatch, but allowed children always get
|
||||
the original temporary HOME and a fresh environment, never those variables.
|
||||
|
||||
Before pytest import/collection, a Python audit hook and subprocess wrapper:
|
||||
|
||||
- deny file opens outside the selected source roots, installed interpreter/library
|
||||
roots and fixture root; writes through open are limited to the fixture root;
|
||||
- deny sockets, DNS and process creation except the closed fixture inventory;
|
||||
- refuse shell, executable, preexec and inherited-FD overrides outside that inventory;
|
||||
- install the same file/socket/process denial before executing every allowed
|
||||
Python child, including BrowserInputs' exact validator code and reverified copied
|
||||
module hashes. Validator children cannot start further processes.
|
||||
|
||||
The process inventory in `scripts/run_unit_tests.py` is intentionally small:
|
||||
BrowserInputs validation, four metadata-checker scripts with fixed argument shapes,
|
||||
the exact original-intent restart probe, the synthetic containment print, and
|
||||
closed guard-regression probes. Metadata checkers receive only fixture output
|
||||
paths. Only the generated-artifact checker child can run the exact read-only Git
|
||||
log/status queries for this repository's catalog, with global/system config and
|
||||
optional locks disabled, hooks disabled and fsmonitor disabled. Those local Git
|
||||
commands are not provider operations.
|
||||
|
||||
Two reviewed non-Python cases remain: exact-byte, temporary contract-double scripts
|
||||
with a closed argv list, and five exact fixed `printf` commands used by existing
|
||||
transport tests. They run Bash without profile/rc startup and without inherited
|
||||
environment; no arbitrary shell text, provider binary, SSH, kubectl or OpenBao
|
||||
command is permitted. Default unit selection excludes four integration-marked
|
||||
SSH-keygen tests. Selecting them explicitly does not grant their native commands.
|
||||
|
||||
Only `test_desk.py::test_approve_flow_http_dry` receives a network lease. It may
|
||||
bind `127.0.0.1:0` and connect to the endpoint actually allocated to that test's
|
||||
socket. DNS is replaced by numeric fixture resolution. Another loopback service
|
||||
(e.g. the real Hub on port 8000), Unix sockets and remote endpoints stay denied.
|
||||
The lease and registered endpoints are cleared after the test.
|
||||
|
||||
Coverage tests now use the explicit public declaration projection snapshot in
|
||||
`tests/fixtures/workload-coverage`, with provenance hashes. They compare the
|
||||
published source snapshot rather than silently consulting the workstation HOME.
|
||||
Run the existing coverage report separately with an explicit estate root when
|
||||
measuring current estate state. Tests of the acknowledged NetKingdom source use
|
||||
`--netkingdom-root` (default: sibling source checkout), never a HOME symlink. The
|
||||
optional Phase Memory library's one existing public coordination-profile fixture
|
||||
is explicitly readable alongside its source; no runtime memory store is inherited.
|
||||
|
||||
This is an accident guard for trusted unit tests, not a security sandbox for
|
||||
hostile Python, native extensions or hostile installed dependencies. It does not
|
||||
revoke already-open descriptors, prevent every filesystem mutation syscall, or
|
||||
provide OS process/network isolation. Fixed Bash/Git fixture processes rely on
|
||||
the reviewed executable and source/argument shapes; Python audit hooks do not run
|
||||
inside those binaries. Do not run untrusted test code under a privileged runtime.
|
||||
Direct `pytest` bypasses this launcher and is not equivalent validation. No
|
||||
production Warden boundary, grant, catalog, source pin or owner credential changes.
|
||||
Loading…
Add table
Add a link
Reference in a new issue