3"""Enforce idle-runner and whole-converge HIL exclusion boundaries."""
5from __future__
import annotations
11from typing
import cast
13import hil_convergence_check_mode
as check_mode
14import hil_convergence_safety_image_harness_policy
as image_harness_policy
15import hil_convergence_safety_image_lock_digest
as image_lock_digest
16import hil_convergence_safety_policy
as policy
17import hil_convergence_safety_python_authority
as python_authority
18import hil_convergence_safety_roles
as roles
19import hil_convergence_safety_selftest
as selftest
20import hil_convergence_safety_v8
as v8
21import hil_convergence_safety_v9
as v9
22import hil_convergence_safety_wsl
as wsl
24from hil_convergence_safety_ast
import (
25 assignment
as _assignment,
27from hil_convergence_safety_ast
import (
28 function
as _function,
30from hil_convergence_safety_ast
import (
31 same_statement
as _same_statement,
33from hil_convergence_safety_ast
import (
34 statement_index
as _statement_index,
37REQUIRED_THAW_CALLS = 2
39CONTROLLER_AUTH_ARGC = 10
43class FixtureError(ValueError):
44 """A structural selftest no longer has one exact mutation target."""
47def _tasks(source: str, label: str) -> tuple[list[dict[str, object]], list[str]]:
48 """Parse one role task list with attribution."""
50 value = yaml.safe_load(source)
51 except yaml.YAMLError:
52 return [], [f
"{label}: malformed YAML"]
53 if not isinstance(value, list)
or any(
not isinstance(item, dict)
for item
in value):
54 return [], [f
"{label}: expected a task list"]
55 return cast(list[dict[str, object]], value), []
58def _named(tasks: list[dict[str, object]], name: str) -> tuple[int, dict[str, object]]:
59 """Return one uniquely named top-level task."""
60 matches = [(index, task)
for index, task
in enumerate(tasks)
if task.get(
"name") == name]
62 message = f
"task {name!r} is missing or duplicated"
63 raise FixtureError(message)
67def _normalized(value: object) -> str:
68 """Collapse presentation whitespace without weakening expression bytes."""
69 return " ".join(str(value).split())
72def _conditions(task: dict[str, object]) -> tuple[str, ...]:
73 """Return normalized Ansible assert conditions, or an empty tuple."""
74 assertion = task.get(
"ansible.builtin.assert")
75 values = assertion.get(
"that")
if isinstance(assertion, dict)
else None
76 if not isinstance(values, list)
or any(
not isinstance(value, str)
for value
in values):
78 return tuple(_normalized(value)
for value
in values)
81def _fact_value(task: object, key: str) -> str:
82 """Return one normalized set_fact value, empty on shape drift."""
83 fact = task.get(
"ansible.builtin.set_fact")
if isinstance(task, dict)
else None
84 value = fact.get(key)
if isinstance(fact, dict)
else None
85 return _normalized(value)
88def _listener_state_errors(
89 load: dict[str, object],
90 activity: dict[str, object],
91 refusal: dict[str, object],
93 """Require exact read-only service state evidence."""
95 load_command = load.get(
"ansible.builtin.command")
96 load_argv = load_command.get(
"argv")
if isinstance(load_command, dict)
else None
97 activity_command = activity.get(
"ansible.builtin.command")
98 activity_argv = activity_command.get(
"argv")
if isinstance(activity_command, dict)
else None
100 "/usr/bin/systemctl",
102 "--property=LoadState",
104 "{{ dev_box_hil_runner_service }}",
106 errors.append(
"dev_box/tasks/main.yml: listener load-state proof is not exact")
107 expected_activity = [
108 "/usr/bin/systemctl",
110 "--property=ActiveState",
112 "{{ dev_box_hil_runner_service }}",
114 if activity_argv != expected_activity:
115 errors.append(
"dev_box/tasks/main.yml: listener active-state proof is not exact")
116 proof_keys = (
"changed_when",
"failed_when",
"check_mode")
117 if any(any(task.get(key)
is not False for key
in proof_keys)
for task
in (load, activity)):
118 errors.append(
"dev_box/tasks/main.yml: listener state proof is not read-only")
119 expected = _normalized(
120 """ansible_check_mode or
121 (dev_box_hil_runner_initial_load.rc == 0 and
122 dev_box_hil_runner_initial_activity.rc == 0 and
123 ((dev_box_hil_runner_initial_load.stdout | trim == 'not-found' and
124 dev_box_hil_runner_initial_activity.stdout | trim == 'inactive') or
125 (dev_box_hil_runner_initial_load.stdout | trim == 'loaded' and
126 dev_box_hil_runner_initial_activity.stdout | trim in ['inactive', 'failed'])))"""
128 if _conditions(refusal) != (expected,):
129 errors.append(
"dev_box/tasks/main.yml: listener state decision is not fail closed")
133def _dev_binding_errors(block: list[object]) -> list[str]:
134 """Require both controller payload and canonical kernel-lock proofs."""
136 "Authenticate the controller and immutable fleet dev-box payload",
137 "Authenticate the canonical delegated kernel-held bench lock",
139 if tuple(task.get(
"name")
for task
in block
if isinstance(task, dict)) != expected_names:
140 return [
"dev_box/tasks/main.yml: delegated live-capability sequence is not exact"]
141 by_name = {task.get(
"name"): task
for task
in block
if isinstance(task, dict)}
142 local = by_name[expected_names[0]]
143 remote = by_name[expected_names[1]]
144 errors = _transaction_command_errors(local,
"dev_box",
"localhost")
146 _kernel_command_errors(remote,
"{{ dev_box_hil_runner_bench_alias }}",
"delegated")
151def _command_argv(task: object) -> list[object]:
152 """Return one command argv or an empty list on structural drift."""
153 command = task.get(
"ansible.builtin.command")
if isinstance(task, dict)
else None
154 argv = command.get(
"argv")
if isinstance(command, dict)
else None
155 return argv
if isinstance(argv, list)
else []
158def _transaction_command_errors(task: dict[str, object], role: str, delegate: str) -> list[str]:
159 """Require exact local transaction-auth executable and capability arguments."""
160 argv = _command_argv(task)
162 "{{ hil_bench_maintenance_lock_id }}",
163 "{{ hil_bench_maintenance_holder_pid | string }}",
164 "{{ hil_bench_maintenance_holder_start_ticks | string }}",
165 "{{ hil_bench_maintenance_holder_target }}",
167 fixed = [
"{{ playbook_dir }}/../../../.venv/bin/python3",
"-I"]
170 task.get(
"delegate_to") != delegate
171 or task.get(
"become")
is not False
172 or task.get(
"changed_when")
is not False
173 or len(argv) != CONTROLLER_AUTH_ARGC
175 or argv[2] !=
"{{ playbook_dir }}/../../../scripts/dev/fleet_transaction_auth.py"
176 or argv[3] !=
"{{ inventory_hostname }}"
178 or argv[6:] != expected_tail
180 errors.append(f
"{role} role: controller transaction authentication command is not exact")
181 payload = str(argv[5])
if len(argv) == CONTROLLER_AUTH_ARGC
else ""
182 keys = re.findall(
r"'([a-z0-9_]+)'\s*:", payload)
183 prefix =
"dev_box_hil_runner_" if role ==
"dev_box" else "hil_bench_"
184 expected_count = 25
if role ==
"dev_box" else 18
185 required_keys = {
"dev_box_hil_runner_bench_repo_dir"}
if role ==
"dev_box" else set()
187 len(keys) != expected_count
188 or len(keys) != len(set(keys))
189 or any(
not key.startswith(prefix)
for key
in keys)
190 or not required_keys.issubset(keys)
192 errors.append(f
"{role} role: immutable fleet payload key set is not exact")
196def _kernel_command_errors(task: dict[str, object], delegate: str |
None, label: str) -> list[str]:
197 """Require the by-value kernel verifier and reviewed-holder digest binding."""
198 argv = _command_argv(task)
201 task.get(
"delegate_to") != delegate
202 or task.get(
"changed_when")
is not False
203 or argv[:4] != [
"/usr/bin/python3",
"-I",
"-S",
"-c"]
204 or len(argv) != REMOTE_VERIFY_ARGC
205 or argv[5:7] != [
"{{ hil_bench_maintenance_lock_id }}",
"wrapped"]
207 errors.append(f
"{label} role: canonical kernel-lock verifier command is not exact")
209 source_lookup = _normalized(argv[4])
210 digest_lookup = _normalized(argv[7])
211 broker_digest_lookup = _normalized(argv[8])
212 expected_source = _normalized(
213 "{{ lookup('ansible.builtin.file', "
214 "playbook_dir ~ '/../../../scripts/hil/lib/bench_lock_verify.py', rstrip=false) }}"
216 expected_digest = _normalized(
217 "{{ lookup('ansible.builtin.file', "
218 "playbook_dir ~ '/../../../scripts/hil/lib/bench_host.sh', "
219 "rstrip=false) | hash('sha256') }}"
221 expected_broker_digest = _normalized(
222 "{{ lookup('ansible.builtin.file', "
223 "playbook_dir ~ '/../../../scripts/hil/lib/bench_lock_broker.py', rstrip=false) "
224 "| hash('sha256') }}"
226 if source_lookup != expected_source:
227 errors.append(f
"{label} role: verifier bytes are not sourced from the reviewed tree")
228 if digest_lookup != expected_digest:
229 errors.append(f
"{label} role: holder digest is not sourced from the reviewed tree")
230 if broker_digest_lookup != expected_broker_digest:
231 errors.append(f
"{label} role: broker digest is not sourced from the reviewed tree")
235def _bench_hold_errors(hold: dict[str, object], binding: dict[str, object]) -> list[str]:
236 """Require the capability and exact remote holder binding."""
237 hold_expected = _normalized(
238 """ansible_check_mode or
239 ((hil_bench_maintenance_lock_id | default(''))
240 is match('^[0-9a-f]{16}$') and
241 dev_box_hil_runner_bench_alias | length > 0)"""
244 if _conditions(hold) != (hold_expected,):
245 errors.append(
"dev_box/tasks/main.yml: bench hold requirement is not exact")
246 block = binding.get(
"block")
247 if binding.get(
"when") !=
"not ansible_check_mode" or not isinstance(block, list):
248 return [*errors,
"dev_box/tasks/main.yml: delegated holder block is not exact"]
249 return errors + _dev_binding_errors(block)
252def _dev_invocation_errors(tasks: list[dict[str, object]]) -> list[str]:
253 """Require exact safe service state and live bench hold before mutation."""
255 "Read native HIL listener load state before any dev-box mutation",
256 "Read native HIL listener activity before any dev-box mutation",
257 "Refuse every dev-box mutation without an exact safe listener state",
258 "Require a live wrapped bench hold before every dev-box mutation",
259 "Bind this dev-box apply to the exact live wrapped bench holder",
262 found = [_named(tasks, name)
for name
in names]
263 except ValueError
as exc:
264 return [f
"dev_box/tasks/main.yml: {exc}"]
265 indices = [index
for index, _
in found]
266 load, activity, refusal, hold, binding = (task
for _, task
in found)
267 errors = _listener_state_errors(load, activity, refusal)
268 errors.extend(_bench_hold_errors(hold, binding))
269 if indices != list(range(5)):
270 errors.append(
"dev_box/tasks/main.yml: service/hold proof is not the role prefix")
274def _include_guard_errors(
275 tasks: list[dict[str, object]],
278 expected: dict[str, object],
281 """Require one exact always-tagged authenticated include at task zero."""
282 if not tasks
or tasks[0].get(
"name") != name:
283 return [f
"{label}: authenticated guard is not the role/task prefix"]
285 if task.get(module) != expected
or task.get(
"tags") != [
"always"]:
286 return [f
"{label}: authenticated guard include is not exact"]
290def _dev_order_errors(tasks: list[dict[str, object]], source: str, handler: str) -> list[str]:
291 """Require the HIL subrole to start with identity, not a mutation."""
294 apt_at, _ = _named(tasks,
"Install the official runner's Debian runtime dependencies")
295 _, start = _named(tasks,
"Enable and start the dedicated HIL listener")
296 except ValueError
as exc:
297 return [f
"hil_runner.yml: {exc}"]
298 include_errors = _include_guard_errors(
300 "Re-authenticate the mutation boundary for direct HIL task inclusion",
301 "ansible.builtin.include_tasks",
302 {
"file":
"hil_mutation_guard.yml",
"apply": {
"tags": [
"always"]}},
306 errors.extend(include_errors)
308 tasks[2].get(
"name") !=
"Require the fleet-derived native HIL declaration"
309 or apt_at != EXPECTED_APT_INDEX
311 errors.append(
"hil_runner.yml: identity proof does not precede its first mutator")
312 service = start.get(
"ansible.builtin.systemd_service")
313 if not isinstance(service, dict)
or service.get(
"state") !=
"started":
314 errors.append(
"hil_runner.yml: final listener start is missing")
316 "Restart the HIL Actions runner" in source
317 or "state: restarted" in source
318 or "Restart the HIL Actions runner" in handler
319 or "state: restarted" in handler
321 errors.append(
"dev_box: an unguarded listener restart path remains")
322 errors.extend(check_mode.errors(tasks))
326def _dev_role_errors(main_source: str, source: str, handler: str, guard_source: str) -> list[str]:
327 """Require idle proof before all dev-box and native-listener mutations."""
328 main_tasks, errors = _tasks(main_source,
"dev_box/tasks/main.yml")
331 tasks, errors = _tasks(source,
"hil_runner.yml")
334 guard_tasks, errors = _tasks(guard_source,
"hil_mutation_guard.yml")
337 main_errors = _include_guard_errors(
339 "Authenticate the HIL and bench mutation boundary before this role",
340 "ansible.builtin.include_tasks",
341 {
"file":
"hil_mutation_guard.yml",
"apply": {
"tags": [
"always"]}},
342 "dev_box/tasks/main.yml",
346 + _dev_invocation_errors(guard_tasks)
347 + _dev_order_errors(tasks, source, handler)
351def _idle_transaction_errors(idle: ast.FunctionDef) -> list[str]:
352 """Require the exact executable freeze/inspect/stop/thaw transaction."""
353 transaction = [node
for node
in idle.body
if isinstance(node, ast.Try)]
354 if len(transaction) != 1:
355 return [
"idle-stop helper: transaction try/finally is missing or duplicated"]
356 body = transaction[0].body
358 "freeze_may_have_landed = True",
359 'control.command("freeze", service)',
360 'freezer = control.command("show", "--property=FreezerState", "--value", service)',
361 'if freezer != "frozen":\n'
362 ' message = f"{service} did not enter the frozen state"\n'
363 " raise IdleStopError(message)",
364 'group = control.command("show", "--property=ControlGroup", "--value", service)',
365 "if any(_is_worker(proc_root, pid) for pid in "
366 "_cgroup_pids(_cgroup_path(cgroup_root, group))):\n"
367 ' message = "Runner.Worker is active; refusing to stop the listener"\n'
368 " raise IdleStopError(message)",
369 'control.command("stop", "--no-block", service)',
370 "_wait_stop_committed(control, service, stop_commit_timeout_s)",
371 'control.command("thaw", service, accept=(0, 1))',
372 "freeze_may_have_landed = False",
373 "_wait_inactive(control, service, 30)",
377 if len(body) != len(expected)
or any(
378 not _same_statement(node, statement)
379 for node, statement
in zip(body, expected, strict=
False)
381 errors.append(
"idle-stop helper: executable transaction shape is not exact")
382 final = transaction[0].finalbody
383 final_source =
'if freeze_may_have_landed:\n control.command("thaw", service, accept=(0, 1))'
384 if len(final) != 1
or not _same_statement(final[0], final_source):
385 errors.append(
"idle-stop helper: fail-safe thaw is not exact")
389def _helper_entry_errors(tree: ast.Module, gate_source: str) -> list[str]:
390 """Require signal unwinding and an executable semantic helper selftest."""
391 main = _function(tree,
"main")
393 return [
"idle-stop helper: main is missing or duplicated"]
395 "signal.signal(signal.SIGTERM, _interrupt)",
396 "signal.signal(signal.SIGHUP, _interrupt)",
399 if any(_statement_index(main, statement) < 0
for statement
in required):
400 errors.append(
"idle-stop helper: signal unwinding is not executable and exact")
402 "python3 infra/ansible/roles/dev_box/files/"
403 "ra8-hil-runner-idle-stop.py --selftest ignored.service"
405 executable = [line.strip()
for line
in gate_source.splitlines()
if line.strip()]
406 if executable.count(invocation) != 1:
407 errors.append(
"checks.sh: exact idle-stop semantic selftest is not executable")
411def _helper_errors(source: str, gate_source: str) -> list[str]:
412 """Require exact executable helper control flow, not source tokens."""
414 tree = ast.parse(source)
416 return [
"idle-stop helper: invalid Python"]
417 idle = _function(tree,
"idle_stop")
419 return [
"idle-stop helper: idle_stop is missing or duplicated"]
421 'load_state = control.command("show", "--property=LoadState", "--value", service)',
422 'if load_state == "not-found":\n return False',
423 'if load_state != "loaded":\n'
424 ' message = f"{service} has unsafe load state {load_state!r}"\n'
425 " raise IdleStopError(message)",
427 errors = _idle_transaction_errors(idle) + _helper_entry_errors(tree, gate_source)
428 if any(_statement_index(idle, statement) < 0
for statement
in prefix):
429 errors.append(
"idle-stop helper: absent and unsafe unit decisions are not exact")
430 worker = _function(tree,
"_is_worker")
431 worker_return =
'return executable == "Runner.Worker" or comm == "Runner.Worker"'
432 if worker
is None or _statement_index(worker, worker_return) < 0:
433 errors.append(
"idle-stop helper: exact Runner.Worker identity proof is missing")
437def _converge_ast_errors(tree: ast.Module) -> list[str]:
438 """Require the live wrapper and preview in executable statement order."""
439 function = _function(tree,
"cmd_converge")
441 return [
"fleet.py: cmd_converge is missing or duplicated"]
443 "guard = _bench_guard_argv(host, plays, args)",
445 "if guard:\n guardian = _bench_guard_subprocess_kwargs("
446 "args.command, fml.guardian_subprocess_kwargs)\n"
447 " return _run(guard, cwd=fm.REPO_ROOT, subprocess_kwargs=guardian)"
449 "typed_vars = _typed_vars_for_converge(args, host)",
450 "rc = cmd_inventory(data, argparse.Namespace(stdout=False))",
451 "maintenance = _prepare_native_runner(request)",
452 "if not maintenance.proceed:\n return maintenance.status",
453 "rc = _run_converge_transport(request)",
455 indices = [_statement_index(function, statement)
for statement
in expected]
456 if -1
in indices
or indices != sorted(indices):
457 return [
"fleet.py: executable lock/preflight/idle-stop/transport order is not exact"]
461def _fleet_selftest_errors(tree: ast.Module) -> list[str]:
462 """Require the semantic lock, WSL, and maintenance selftests to execute."""
463 function = _function(tree,
"cmd_selftest")
465 "failures = (ftv.run_selftest() + fw.run_selftest(data) + fb.run_selftest() + "
466 "frm.run_selftest() + fml.run_selftest() + fcc.run_selftest(data) + "
467 "_bench_guard_inheritance_selftest() + _inventory_publication_selftest() + "
468 "fm.controller_inventory_selftest(data) + fb.parser_selftest(_parser))"
470 if function
is None or _statement_index(function, statement) < 0:
471 return [
"fleet.py: executable HIL transaction selftests are not exact"]
475def _runtime_directory_helper_errors(tree: ast.Module) -> list[str]:
476 """Require exact validation for selectively inherited runtime directories."""
477 helper = _function(tree,
"_private_runtime_directory")
479 '"""Return one explicitly supplied, private Ansible runtime directory."""',
480 "value = environment.get(key)",
481 "if value is None:\n return None",
482 "path = Path(value)",
483 'if not path.is_absolute():\n message = f"{key} is not an absolute path"\n'
484 " raise MaintenanceError(message)",
485 'resolved = _require_real_directory(path, f"{key} directory")',
486 "metadata = resolved.stat()",
487 "if metadata.st_uid != os.getuid() or "
488 "stat.S_IMODE(metadata.st_mode) != PRIVATE_DIRECTORY_MODE:\n"
489 ' message = f"{key} is not owned by this account with mode 0700"\n'
490 " raise MaintenanceError(message)",
491 "return str(resolved)",
493 mode = _assignment(tree,
"PRIVATE_DIRECTORY_MODE")
494 wanted_mode = ast.parse(
"0o700", mode=
"eval").body
498 or len(helper.body) != len(expected)
500 not _same_statement(node, statement)
501 for node, statement
in zip(helper.body, expected, strict=
True)
504 errors.append(
"fleet runner maintenance: runtime directory validator is not exact")
505 if mode
is None or ast.dump(mode, include_attributes=
False) != ast.dump(
506 wanted_mode, include_attributes=
False
508 errors.append(
"fleet runner maintenance: private runtime directory mode is not exact")
512def _runner_environment_errors(tree: ast.Module) -> list[str]:
513 """Require fixed environment plus two validated runtime-directory controls."""
514 function = _function(tree,
"ansible_environment")
516 'resolved_cwd = _require_real_directory(ansible_cwd, "Ansible working directory")',
517 'repo_root = _require_real_directory(resolved_cwd.parents[1], "repository root")',
518 'config = _require_real_file(resolved_cwd / "ansible.cfg", "repository Ansible config")',
519 'collection_parent = _require_real_directory(repo_root / ".ansible", "collection parent")',
520 "collections = _require_real_directory(collection_parent / "
521 "'collections', 'collection root')",
522 "link_errors = fpa.confined_link_errors(collections)",
523 'clean = {"HOME": pwd.getpwuid(os.getuid()).pw_dir, "LANG": "C.UTF-8", '
524 '"LC_ALL": "C.UTF-8", "PATH": "/usr/bin:/bin"}',
525 'clean["ANSIBLE_CONFIG"] = str(config)',
526 'clean["ANSIBLE_COLLECTIONS_PATH"] = str(collections)',
527 'clean["ANSIBLE_COLLECTIONS_SCAN_SYS_PATH"] = "false"',
528 'clean["PYTHONNOUSERSITE"] = "1"',
529 'for key in ("ANSIBLE_LOCAL_TEMP", "ANSIBLE_SSH_CONTROL_PATH_DIR"):\n'
530 " value = _private_runtime_directory(environment, key)\n"
531 " if value is not None:\n"
532 " clean[key] = value",
535 errors = _runtime_directory_helper_errors(tree)
536 if function
is None or any(_statement_index(function, item) < 0
for item
in expected):
537 errors.append(
"fleet runner maintenance: Ansible environment sanitizer is not exact")
541def _runner_environment_input_errors(inputs: dict[str, str]) -> list[str]:
542 """Check only the fleet-runner environment contract for focused mutations."""
544 tree = ast.parse(inputs[
"fleet_runner"])
546 return [
"fleet runner maintenance: invalid Python"]
547 return _runner_environment_errors(tree)
550def _playbook_environment_errors(tree: ast.Module) -> list[str]:
551 """Require Ansible to run as a module under the active locked Python."""
552 function = _function(tree,
"playbook_argv")
554 return [
"fleet.py: locked Ansible module decision is not exact"]
555 argv = _assignment(function,
"argv")
556 first = argv.elts[0]
if isinstance(argv, ast.List)
and argv.elts
else None
557 prefix = first.value
if isinstance(first, ast.Starred)
else None
558 wanted = ast.parse(
"playbook_prefix(sys.executable)", mode=
"eval").body
559 if prefix
is None or ast.dump(prefix, include_attributes=
False) != ast.dump(
560 wanted, include_attributes=
False
562 return [
"fleet.py: playbook argv does not use locked Python module execution"]
566def _runner_prepare_errors(tree: ast.Module) -> list[str]:
567 """Require executable fail-closed no-op and idle-stop decisions."""
568 function = _function(tree,
"prepare")
570 return [
"fleet runner maintenance: prepare is missing or duplicated"]
572 "if not has_changes:\n"
573 ' print("fleet: native HIL listener is already converged; leaving it running")\n'
574 " return MaintenanceDecision(proceed=False, status=0)"
576 decision =
"return MaintenanceDecision(proceed=stop.returncode == 0, status=stop.returncode)"
577 if _statement_index(function, no_op) < 0
or _statement_index(function, decision) < 0:
578 return [
"fleet runner maintenance: executable no-op/idle-stop decision is not exact"]
582def _converge_env_errors(tree: ast.Module) -> list[str]:
583 """Require every native play to use the exact sanitized environment."""
584 function = _function(tree,
"_converge_ssh")
586 return [
"fleet.py: native converge transport is missing or duplicated"]
589 for node
in ast.walk(function)
590 if isinstance(node, ast.Call)
and isinstance(node.func, ast.Name)
and node.func.id ==
"_run"
593 return [
"fleet.py: native converge runner call is missing or duplicated"]
594 env = next((keyword.value
for keyword
in calls[0].keywords
if keyword.arg ==
"env"),
None)
595 expected = ast.parse(
"frm.ansible_environment(os.environ, fm.ANSIBLE_DIR)", mode=
"eval").body
596 if env
is None or ast.dump(env, include_attributes=
False) != ast.dump(
597 expected, include_attributes=
False
599 return [
"fleet.py: actual Ansible environment is not exact"]
603def _wsl_mode_errors(tree: ast.Module) -> list[str]:
604 """Require the validated operation mode to reach the WSL toolchain."""
605 function = _function(tree,
"_run_converge_transport")
609 for node
in ast.walk(function)
610 if isinstance(node, ast.Call)
611 and isinstance(node.func, ast.Attribute)
612 and isinstance(node.func.value, ast.Name)
613 and node.func.value.id ==
"fw"
614 and node.func.attr ==
"ConvergeSpec"
616 if function
is not None
619 wanted = ast.parse(
"request.args.mode", mode=
"eval").body
621 if len(calls) != 1
or len(calls[0].args) <= mode_arg:
622 return [
"fleet.py: WSL convergence mode binding is absent"]
623 if ast.dump(calls[0].args[mode_arg], include_attributes=
False) != ast.dump(
624 wanted, include_attributes=
False
626 return [
"fleet.py: WSL convergence mode binding is not exact"]
630def _infra_uv_execution_errors(source: str) -> list[str]:
631 """Require infra lock verification to execute only authenticated uv bytes."""
632 expected =
"""verify_managed_python_environment() {
635 UV_PROJECT_ENVIRONMENT="$MANAGED_VENV" UV_PYTHON_DOWNLOADS=never \\
636 UV_CACHE_DIR="$ROOT/.tools/uv" \\
637 /usr/bin/python3 -I -S "$ROOT/scripts/dev/bootstrap_uv.py" \\
638 --run --no-config sync --locked --all-groups --no-install-project \\
639 --python /usr/bin/python3 --check
643if ! verify_managed_python_environment; then
644 echo "error: repository .venv does not exactly match pyproject.toml and uv.lock" >&2
647 function = re.search(
r"(?ms)^verify_managed_python_environment\(\) \{.*?^fi$", source)
648 if function
is None or function.group(0) != expected:
649 return [
"infra.sh: dependency verification bypasses authenticated uv execution"]
653def _wsl_cache_errors(wsl_tree: ast.Module, stage_tree: ast.Module) -> list[str]:
654 """Require cache ownership before reuse and a Windows-safe receiver."""
655 errors: list[str] = []
656 sync_image = _function(wsl_tree,
"_sync_runner_image")
658 "rc = run([*target_ssh, fm.remote_shell(target)], stdin=fws.cache_prepare_script())"
660 prepare_at = _statement_index(sync_image, cache_prepare)
if sync_image
is not None else -1
662 if sync_image
is not None:
663 cache_probe_at = next(
666 for index, node
in enumerate(sync_image.body)
667 if isinstance(node, ast.Assign)
668 and isinstance(node.value, ast.Call)
669 and isinstance(node.value.func, ast.Name)
670 and node.value.func.id ==
"_command_output"
672 isinstance(target, ast.Tuple)
674 isinstance(name, ast.Name)
and name.id ==
"cache_rc" for name
in target.elts
676 for target
in node.targets
681 if prepare_at < 0
or cache_probe_at < 0
or prepare_at >= cache_probe_at:
682 errors.append(
"fleet WSL: runner cache ownership is not proven before reuse")
683 receiver = _function(stage_tree,
"cache_receive_command")
684 tokens = _assignment(receiver,
"tokens")
if receiver
is not None else None
685 expected = ast.parse(
686 '["wsl", "-d", distro, "-u", "root", "-e", "/usr/bin/env", "-i", '
687 '"HOME=/root", "PATH=/usr/bin:/bin", "/usr/bin/dd", f"of={part}", '
688 '"bs=4M", "conv=fsync,excl", "status=none"]',
692 "if any(not token or any(character not in safe for character in token) "
693 "for token in tokens):\n"
694 ' message = "runner-image receiver cannot be represented safely for Windows"\n'
695 " raise ValueError(message)"
699 or ast.dump(tokens, include_attributes=
False)
700 != ast.dump(expected, include_attributes=
False)
702 or _statement_index(receiver, refusal) < 0
704 errors.append(
"fleet WSL stage: runner-cache receiver is not exclusive and inert")
708def _wsl_stage_errors(wsl_tree: ast.Module, stage_tree: ast.Module) -> list[str]:
709 """Require executable owned-stage/cache selftests and publication order."""
710 errors = _wsl_cache_errors(wsl_tree, stage_tree)
711 wsl_selftest = _function(wsl_tree,
"run_selftest")
712 stage_selftest_call =
"stage_failures = fws.run_selftest()"
713 if wsl_selftest
is None or _statement_index(wsl_selftest, stage_selftest_call) < 0:
714 errors.append(
"fleet WSL: owned stage/cache semantic selftest is not executable")
715 converge = _function(wsl_tree,
"converge")
716 push_call =
"rc, generation = fws.prepare(data, name, spec.mode, run)"
720 for node
in ast.walk(converge)
721 if isinstance(node, ast.Assign)
and _same_statement(node, push_call)
723 if converge
is not None
726 if len(push_matches) != 1:
727 errors.append(
"fleet WSL: owned stage publication is not executable")
728 stage_selftest = _function(stage_tree,
"run_selftest")
729 expected_selftests = (
730 "failures = (_stage_selftest(root) + _cache_selftest(root) + _link_selftest(root) + "
731 "_probe_selftest(root) + _transaction_lock_selftest(root) + "
732 "_cache_receiver_selftest())"
737 for node
in ast.walk(stage_selftest)
738 if isinstance(node, ast.Assign)
and _same_statement(node, expected_selftests)
740 if stage_selftest
is not None
743 if len(selftest_matches) != 1:
744 errors.append(
"fleet WSL stage: ownership semantic selftests are not exact")
745 push = _function(stage_tree,
"prepare")
747 "tar_rc, archive = _stage_archive(mode)",
748 'if tar_rc:\n return tar_rc, ""',
750 if push
is None or any(_statement_index(push, statement) < 0
for statement
in required):
751 errors.append(
"fleet WSL stage: local archive is not proven before remote mutation")
755def _reconcile_activation_errors(tree: ast.Module) -> list[str]:
756 """Require ARC activation proof at zero before the sole capacity restore."""
757 activation = _function(tree,
"_activate_arc")
758 apply_host = _function(tree,
"apply_host")
760 'activation = run(fleet_command(host, "activate"))',
761 "clean, changed = inspect_activation_host(data, host, run)",
762 'restore = run(fleet_command(host, "restore"))',
766 [_statement_index(activation, statement)
for statement
in sequence]
767 if activation
is not None
771 'if host_class.capacity_kind == "k8s":\n'
772 " return _activate_arc(data, host, run, expected_check_changes)"
775 len(indices) != len(sequence)
777 or indices != sorted(indices)
778 or apply_host
is None
779 or _statement_index(apply_host, arc_branch) < 0
781 return [
"fleet reconciliation: ARC activation/check/restore order is not exact"]
785def _fleet_split_module_errors(
786 fleet_tree: ast.Module,
787 capacity_tree: ast.Module,
788 reconcile_tree: ast.Module,
789 process_tree: ast.Module,
790 arc_selftest_tree: ast.Module,
792 """Require split runtime imports and executable owned selftests."""
794 (fleet_tree,
"fleet_capacity_client",
"fcc"),
795 (reconcile_tree,
"fleet_reconcile_process",
"frp"),
796 (reconcile_tree,
"fleet_reconcile_arc_selftest",
"fras"),
800 isinstance(node, ast.Import)
801 and len(node.names) == 1
802 and node.names[0].name == module
803 and node.names[0].asname == alias
804 for node
in tree.body
807 for tree, module, alias
in required_imports
810 if not imports_exact:
811 errors.append(
"fleet split modules: runtime imports are not exact")
812 reconcile_selftest = _function(reconcile_tree,
"selftest")
814 _function(capacity_tree,
"run_selftest")
is None
815 or _function(process_tree,
"run_selftest")
is None
816 or _function(arc_selftest_tree,
"run")
is None
817 or reconcile_selftest
is None
818 or _statement_index(reconcile_selftest,
"failures.extend(frp.run_selftest())") < 0
819 or _statement_index(reconcile_selftest,
"failures.extend(fras.run(apply_host))") < 0
821 errors.append(
"fleet split modules: executable selftests are not exact")
825def _fleet_errors(inputs: dict[str, str]) -> list[str]:
826 """Require structural lock and exact Ansible environment boundaries."""
828 tree = ast.parse(inputs[
"fleet"])
829 ast.parse(inputs[
"fleet_bench"])
830 capacity_tree = ast.parse(inputs[
"fleet_capacity_client"])
831 reconcile_tree = ast.parse(inputs[
"fleet_reconcile"])
832 process_tree = ast.parse(inputs[
"fleet_reconcile_process"])
833 arc_selftest_tree = ast.parse(inputs[
"fleet_reconcile_arc_selftest"])
834 runner_tree = ast.parse(inputs[
"fleet_runner"])
835 wsl_tree = ast.parse(inputs[
"fleet_wsl"])
836 wsl_stage_tree = ast.parse(inputs[
"fleet_wsl_stage"])
838 return [
"fleet bench guard: invalid Python"]
839 errors = _converge_ast_errors(tree) + _fleet_selftest_errors(tree)
841 _fleet_split_module_errors(
842 tree, capacity_tree, reconcile_tree, process_tree, arc_selftest_tree
845 errors.extend(_reconcile_activation_errors(reconcile_tree))
846 errors.extend(_playbook_environment_errors(runner_tree))
847 errors.extend(_runner_environment_errors(runner_tree))
848 errors.extend(_runner_prepare_errors(runner_tree))
849 errors.extend(_converge_env_errors(tree))
850 errors.extend(_wsl_mode_errors(tree))
851 errors.extend(wsl.environment_errors(wsl_tree))
852 errors.extend(wsl.clock_errors(inputs[
"wsl_role"]))
853 errors.extend(wsl.autostart_errors(inputs[
"wsl_role"]))
854 errors.extend(_wsl_stage_errors(wsl_tree, wsl_stage_tree))
855 gate_lines = [line.strip()
for line
in inputs[
"gate"].splitlines()
if line.strip()]
856 if gate_lines.count(
"python3 scripts/dev/fleet.py selftest") != 1:
857 errors.append(
"checks.sh: exact fleet transaction semantic selftest is not executable")
861def _scan(inputs: dict[str, str]) -> list[str]:
862 """Return every convergence-safety defect."""
864 image_lock_digest.source_errors(
866 inputs[
"devcontainer_image"],
867 inputs[
"devcontainer_image_lock_receipts"],
868 inputs[
"devcontainer_image_lock_selftest"],
869 inputs[
"devcontainer_image_selftest"],
870 inputs[
"devcontainer_image_bound_exit_selftest"],
871 inputs[
"devcontainer_image_selftest_cases"],
872 inputs[
"devcontainer_image_signal_selftest"],
873 inputs[
"devcontainer_image_selftest_process"],
874 inputs[
"devcontainer_image_selftest_supervisor"],
875 inputs[
"devcontainer_image_selftest_supervisor_cases"],
876 inputs[
"raw_digest_controls"],
878 inputs[
"image_lock_digest"],
883 inputs[
"dev_handler"],
886 + _helper_errors(inputs[
"idle_helper"], inputs[
"gate"])
887 + _fleet_errors(inputs)
888 + image_harness_policy.errors(inputs)
889 + _infra_uv_execution_errors(inputs[
"infra_sh"])
890 + python_authority.uv_helper_deployment_errors(inputs)
891 + python_authority.hil_python_authority_errors(inputs[
"bench_role"])
892 + roles.errors(inputs)
893 + policy.workflow_errors(inputs[
"workflow"], inputs[
"declaration"])
899def main(argv: list[str] |
None =
None) -> int:
900 """Run the live scan or the mutation selftest."""
901 parser = argparse.ArgumentParser(description=__doc__)
902 parser.add_argument(
"--selftest", action=
"store_true")
903 args = parser.parse_args(argv)
905 return selftest.run(_scan, _runner_environment_input_errors)
906 raw_errors = image_lock_digest.live_errors(policy.REPO_ROOT)
908 for error
in raw_errors:
909 print(error, file=sys.stderr)
911 f
"check_hil_convergence_safety.py: {len(raw_errors)} raw-byte error(s)",
915 errors = _scan(policy.load_inputs(policy.REPO_ROOT)) + v9.semantic_errors()
917 print(error, file=sys.stderr)
919 print(f
"check_hil_convergence_safety.py: {len(errors)} error(s)", file=sys.stderr)
921 print(
"check_hil_convergence_safety.py: PASS")
925if __name__ ==
"__main__":
926 raise SystemExit(
main())
void main(void)
The application entry point Reset_Handler hands control to.