3"""Environment and runner mutation cases for the HIL safety self-test."""
5from __future__
import annotations
7from collections.abc
import Callable
9Scan = Callable[[dict[str, str]], list[str]]
10Mutate = Callable[[dict[str, str], str, str, str], dict[str, str]]
11RemoveManifestMember = Callable[[dict[str, str], str], dict[str, str]]
12RemoveLoopMember = Callable[[dict[str, str], str, str, str], dict[str, str]]
15class EnvironmentCaseError(ValueError):
16 """A structural environment self-test no longer has its expected cases."""
19def runner_runtime_directory_cases(
20 inputs: dict[str, str], scan: Scan, mutate: Mutate
21) -> list[tuple[str, bool]]:
22 """Return runtime-directory validation and allowlist mutations."""
25 "relative Ansible runtime directory acceptance",
26 "if not path.is_absolute():",
30 "Ansible runtime directory owner-check removal",
31 "metadata.st_uid != os.getuid()",
35 "Ansible runtime directory mode-check removal",
36 "stat.S_IMODE(metadata.st_mode) != PRIVATE_DIRECTORY_MODE",
40 "private Ansible runtime mode widening",
41 "PRIVATE_DIRECTORY_MODE = 0o700",
42 "PRIVATE_DIRECTORY_MODE = 0o755",
45 "Ansible runtime environment allowlist widening",
46 '("ANSIBLE_LOCAL_TEMP", "ANSIBLE_SSH_CONTROL_PATH_DIR")',
47 '("ANSIBLE_LOCAL_TEMP", "ANSIBLE_SSH_CONTROL_PATH_DIR", "TMPDIR")',
50 "Ansible runtime directory validator bypass",
51 "value = _private_runtime_directory(environment, key)",
52 "value = environment.get(key)",
56 (label, bool(scan(mutate(inputs,
"fleet_runner", old, new))))
57 for label, old, new
in mutations
61def _environment_variable_cases(
62 inputs: dict[str, str], scan: Scan, mutate: Mutate
63) -> list[tuple[str, bool]]:
64 """Return environment-variable sanitizer mutations."""
67 "HIL caller-selected tool venv fires",
73 'export RA8_TOOL_VENV := ""',
74 'export RA8_TOOL_VENV := env("RA8_TOOL_VENV", "")',
80 "Ansible setup sanitizer removal fires",
86 "unset PYTHONHOME PYTHONPATH RA8_TOOL_VENV",
87 ": # sanitizer removed",
93 "toolchain provision TMPDIR sanitizer removal fires",
98 "provision_toolchain",
99 "unset PYTHONHOME PYTHONPATH RA8_TOOL_VENV TMPDIR",
100 "unset PYTHONHOME PYTHONPATH RA8_TOOL_VENV",
108def _environment_path_cases(
109 inputs: dict[str, str], scan: Scan, mutate: Mutate
110) -> list[tuple[str, bool]]:
111 """Return fixed-path interpreter and shell mutations."""
114 "HIL caller PATH inheritance fires",
120 "export PATH := `/bin/bash -p "
121 "scripts/ci/lib/host_tool_path.sh --print-path`",
122 'export PATH := env("PATH", "")',
128 "toolchain provision PATH poisoning fires",
133 "provision_toolchain",
134 "PATH=/usr/local/bin:/usr/bin:/bin",
141 "infra bootstrap PATH Bash fires",
147 '/bin/bash -p "${ROOT}/scripts/dev/setup_ansible.sh"',
148 'bash "${ROOT}/scripts/dev/setup_ansible.sh"',
156def _environment_sanitizer_cases(
157 inputs: dict[str, str], scan: Scan, mutate: Mutate
158) -> list[tuple[str, bool]]:
159 """Return every public environment-sanitizer mutation."""
160 return _environment_variable_cases(inputs, scan, mutate) + _environment_path_cases(
165def _authenticated_uv_runner_cases(
166 inputs: dict[str, str], scan: Scan, mutate: Mutate
167) -> list[tuple[str, bool]]:
168 """Return authenticated uv-runner mutations."""
171 "infra authenticated uv runner removal fires",
177 "--run --no-config sync",
184 "WSL authenticated uv runner removal fires",
191 '--verify-cache "$@"',
199def _container_helper_cases(
200 inputs: dict[str, str], scan: Scan, mutate: Mutate
201) -> list[tuple[str, bool]]:
202 """Return devcontainer uv-helper mutations."""
205 "devcontainer uv helper allowlist removal fires",
211 "!scripts/dev/bootstrap_uv_exec.py\n",
218 "devcontainer uv helper COPY removal fires",
224 " scripts/dev/bootstrap_uv_exec.py \\\n",
231 "devcontainer uv helper canonical-input removal fires",
236 "devcontainer_image",
237 "644 scripts/dev/bootstrap_uv_exec.py\n",
246def _runner_helper_cases(
247 inputs: dict[str, str],
249 remove_manifest_member: RemoveManifestMember,
250 remove_loop_member: RemoveLoopMember,
251) -> list[tuple[str, bool]]:
252 """Return HIL and CI runner uv-helper mutations."""
255 "HIL uv helper staging removal fires",
256 bool(scan(remove_manifest_member(inputs,
"bootstrap_uv_exec.py"))),
259 "CI runner uv helper readback removal fires",
265 "Read back every staged root-context authority byte-for-byte",
266 "scripts/dev/bootstrap_uv_exec.py",
272 "CI runner uv helper presence-proof removal fires",
278 "Assert both Dockerfiles and every locked Python input arrived",
279 "scripts/dev/bootstrap_uv_exec.py",
287def _wsl_helper_cases(inputs: dict[str, str], scan: Scan, mutate: Mutate) -> list[tuple[str, bool]]:
288 """Return WSL uv-helper archive and path-proof mutations."""
291 "WSL uv helper archive removal fires",
297 ' "scripts/dev/bootstrap_uv_exec.py",\n',
304 "WSL uv helper path-proof removal fires",
310 ' f"{stage}/scripts/dev/bootstrap_uv_exec.py",\n',
320 inputs: dict[str, str],
323 remove_manifest_member: RemoveManifestMember,
324 remove_loop_member: RemoveLoopMember,
325) -> list[tuple[str, bool]]:
326 """Return public environment and installer-boundary mutations."""
327 sanitizer_cases = _environment_sanitizer_cases(inputs, scan, mutate)
328 uv_runner_cases = _authenticated_uv_runner_cases(inputs, scan, mutate)
329 container_cases = _container_helper_cases(inputs, scan, mutate)
330 runner_cases = _runner_helper_cases(inputs, scan, remove_manifest_member, remove_loop_member)
331 wsl_cases = _wsl_helper_cases(inputs, scan, mutate)
332 if not all((sanitizer_cases, uv_runner_cases, container_cases, runner_cases, wsl_cases)):
333 message =
"environment case helper returned no mutation cases"
334 raise EnvironmentCaseError(message)
335 return sanitizer_cases + uv_runner_cases + container_cases + runner_cases + wsl_cases