3"""Static image-lock mutations split from the aggregate convergence fixtures."""
5from __future__
import annotations
7from hil_convergence_safety_semantic_mutations
import process_authority_mutations
9Mutation = tuple[str, str, str, str]
12def _authority_mutations() -> tuple[Mutation, ...]:
13 """Return mutations of the duplicated canonical lock authority."""
16 "managed image lock default moved back into the sticky cache",
18 "dev_box_image_lock_dir: /var/cache/ra8-devcontainer-image-lock",
19 "dev_box_image_lock_dir: /var/cache/ra8-tools",
22 "script canonical image lock authority drifted",
24 'CANONICAL_IMAGE_LOCK_DIR="/var/cache/ra8-devcontainer-image-lock"',
25 'CANONICAL_IMAGE_LOCK_DIR="/var/cache/ra8-tools"',
28 "shell profile reintroduces a second image lock authority",
30 ' export RA8_CONTAINER_RUNTIME="{{ dev_box_container_runtime }}"\n',
31 ' export RA8_CONTAINER_RUNTIME="{{ dev_box_container_runtime }}"\n'
32 ' export RA8_IMAGE_LOCK_DIR="{{ dev_box_image_lock_dir }}"\n',
35 "managed image lock transaction include drifted",
37 "- name: Converge the managed devcontainer image lock authority\n"
38 " ansible.builtin.include_tasks: image_lock.yml\n",
39 "- name: Converge the managed devcontainer image lock authority\n"
40 " ansible.builtin.include_tasks: hil_runner.yml\n",
45def _ansible_proof_mutations() -> tuple[Mutation, ...]:
46 """Return Ansible post-stat and identity-proof mutations."""
48 *_ansible_stat_mutations(),
49 *_ansible_identity_mutations(),
53def _ansible_stat_mutations() -> tuple[Mutation, ...]:
54 """Return Ansible no-follow stat mutations."""
57 "managed image lock marker pre-stat follows links",
59 "- name: Inspect the managed image lock group marker without following links\n"
61 " ansible.builtin.stat:\n"
62 ' path: "{{ dev_box_image_lock_dir }}/devcontainer-image.gid"\n'
64 "- name: Inspect the managed image lock group marker without following links\n"
66 " ansible.builtin.stat:\n"
67 ' path: "{{ dev_box_image_lock_dir }}/devcontainer-image.gid"\n'
71 "managed image lock directory post-stat follows links",
73 "- name: Reinspect the converged managed image lock directory\n"
75 " ansible.builtin.stat:\n"
76 ' path: "{{ dev_box_image_lock_dir }}"\n'
78 "- name: Reinspect the converged managed image lock directory\n"
80 " ansible.builtin.stat:\n"
81 ' path: "{{ dev_box_image_lock_dir }}"\n'
85 "managed image lock file post-stat follows links",
87 "- name: Reinspect the converged managed image lock\n"
89 " ansible.builtin.stat:\n"
90 ' path: "{{ dev_box_image_lock_dir }}/devcontainer-image.lock"\n'
92 "- name: Reinspect the converged managed image lock\n"
94 " ansible.builtin.stat:\n"
95 ' path: "{{ dev_box_image_lock_dir }}/devcontainer-image.lock"\n'
101def _ansible_identity_mutations() -> tuple[Mutation, ...]:
102 """Return Ansible numeric identity-proof mutations."""
105 "managed image lock directory numeric owner proof weakened",
107 " - dev_box_image_lock_dir_after.stat.uid == 0",
108 " - dev_box_image_lock_dir_after.stat.uid >= 0",
111 "managed image lock numeric owner proof weakened",
113 " - dev_box_image_lock_after.stat.uid == 0",
114 " - dev_box_image_lock_after.stat.uid >= 0",
117 "managed image lock marker post-stat follows links",
119 "- name: Reinspect the converged managed image lock group marker\n"
121 " ansible.builtin.stat:\n"
122 ' path: "{{ dev_box_image_lock_dir }}/devcontainer-image.gid"\n'
124 "- name: Reinspect the converged managed image lock group marker\n"
126 " ansible.builtin.stat:\n"
127 ' path: "{{ dev_box_image_lock_dir }}/devcontainer-image.gid"\n'
131 "managed image lock marker numeric owner proof weakened",
133 " - dev_box_image_lock_gid_marker_after.stat.uid == 0",
134 " - dev_box_image_lock_gid_marker_after.stat.uid >= 0",
137 "managed image lock marker numeric group content proof removed",
139 " - dev_box_image_lock_dir_after.stat.gid == "
140 "(dev_box_image_lock_gid.stdout | int)\n"
141 " - dev_box_image_lock_after.stat.gid == "
142 "(dev_box_image_lock_gid.stdout | int)",
143 " - dev_box_image_lock_dir_after.stat.gid == "
144 "(dev_box_image_lock_gid.stdout | int)\n"
145 " - dev_box_image_lock_after.stat.gid >= 0",
150def _serialization_mutations() -> tuple[Mutation, ...]:
151 """Return no-create, inode, force, and selftest mutations."""
154 "managed image lock open can recreate a missing file",
155 "devcontainer_image",
156 ' exec 9<"$IMAGE_LOCK_FILE" || die "cannot open existing image lock: '
158 ' exec 9>>"$IMAGE_LOCK_FILE" || die "cannot open existing image lock: '
162 "managed image lock pre-flock opened-inode validation removed",
163 "devcontainer_image",
164 " validate_opened_image_lock 9\n if ! flock -n 9; then",
165 " # validate_opened_image_lock 9\n if ! flock -n 9; then",
168 "managed image lock post-flock opened-inode validation removed",
169 "devcontainer_image",
170 " flock 9\n fi\n validate_opened_image_lock 9",
171 " flock 9\n fi\n # validate_opened_image_lock 9",
174 "forced image rebuild bypasses serialization",
175 "devcontainer_image",
176 ' build_locked "$want" forced "" 1',
177 ' build_image "$want"',
180 "managed image lock strict flock refusal bypassed",
181 "devcontainer_image",
182 ' [[ "$IMAGE_LOCK_MANAGED" == "0" ]] ||',
183 ' true || [[ "$IMAGE_LOCK_MANAGED" == "0" ]] ||',
186 "managed image lock selftest dispatcher stranded",
187 "devcontainer_image_selftest_cases",
188 ' dispatch_image_lock_selftest suite "$tmp"',
189 ' # dispatch_image_lock_selftest suite "$tmp"',
192 "managed image lock top-level completion check removed",
193 "devcontainer_image",
195 ' if [[ "${1:-}" == "--selftest" || "${1:-}" == "--selftest-offline" ]]; then\n'
196 ' [[ "$SELFTEST_MAIN_COMPLETE" == "1" ]] || '
197 'die "selftest main returned before completion"\n'
202 "managed image lock ensure preflight stranded",
203 "devcontainer_image",
204 " managed_image_lock_preflight\n want=",
205 " # managed_image_lock_preflight\n want=",
210def _selftest_fallback_mutations() -> tuple[Mutation, ...]:
211 """Return controller fallback and escalation mutations."""
214 "image lock signal fallback removed",
215 "devcontainer_image_signal_selftest",
216 ' force_signal_controller_cleanup "$controller" "$case_dir" "$managed" ||\n'
217 ' die "selftest: handler-hang group fallback failed"',
221 "image lock fallback controller TERM removed",
222 "devcontainer_image_lock_selftest",
223 ' signal_owned_controller_group TERM "$controller" 2>/dev/null || return 1',
227 "image lock controller cleanup bound shortened below worker cleanup",
228 "devcontainer_image_lock_selftest",
229 "SELFTEST_CONTROLLER_CLEANUP_STEPS=1600",
230 "SELFTEST_CONTROLLER_CLEANUP_STEPS=50",
233 "image lock unready-controller fallback removed",
234 "devcontainer_image_signal_selftest",
235 ' force_signal_controller_cleanup "$controller" "$case_dir" "$managed" ||\n'
236 ' die "selftest: $signal unready-controller cleanup failed"',
242def _early_return_mutations(key: str, names: tuple[str, ...], indent: str) -> tuple[Mutation, ...]:
243 """Build early-success mutations for one exact shell authority."""
246 f
"image lock {name} early success refused",
248 f
"{indent}{name}() {{\n",
249 f
"{indent}{name}() {{\n{indent} return 0\n",
255def _receipt_early_return_mutations() -> tuple[Mutation, ...]:
256 """Return must-fire early-success mutations for every receipt boundary."""
258 "expected_image_lock_suite_receipts",
259 "scenario_receipt_value",
260 "validate_scenario_receipt_directory",
261 "write_scenario_receipt",
262 "require_scenario_receipt",
263 "verify_scenario_receipt_files",
264 "expected_cleanup_receipt",
265 "expected_force_cleanup_receipt",
266 "parent_lock_fd_is_closed",
267 "require_cleanup_receipt",
268 "require_force_cleanup_receipt",
269 "write_worker_cleanup_proof_file",
270 "require_worker_cleanup_proof_file",
271 "write_controller_cleanup_receipt_file",
272 "require_controller_cleanup_receipt_file",
277 "release_parent_lock",
279 "assert_no_surviving_descendants",
280 "cleanup_image_lock_case",
281 "force_signal_controller_cleanup",
282 "verify_signal_controller_cleanup",
283 "verify_image_lock_suite_receipts",
284 "run_image_lock_scenario",
285 "dispatch_image_lock_selftest",
286 "selftest_early_exit",
287 "selftest_pre_ready_hang",
288 "selftest_forced_build_contention",
289 "selftest_post_ready_hang",
292 *_early_return_mutations(
"devcontainer_image", (
"build_locked",
"main"),
" "),
293 *_early_return_mutations(
"devcontainer_image_lock_receipts", receipt_names,
""),
294 *_early_return_mutations(
"devcontainer_image_lock_selftest", helper_names,
""),
295 *_early_return_mutations(
"devcontainer_image_selftest_cases", (
"cmd_selftest",),
""),
296 *_early_return_mutations(
297 "devcontainer_image_signal_selftest",
298 (
"selftest_signal_ready_timeout",
"selftest_signal_cleanup"),
304def _receipt_semantic_mutations() -> tuple[Mutation, ...]:
305 """Return removals of the scenario facts that authorize final receipts."""
306 post_ready_negative = (
307 ' if wait_for_status_file "$SELFTEST_CASE_DIR/done.status" '
308 '"$SELFTEST_WORKER_PID"; then\n'
309 ' die "selftest: build-hang worker unexpectedly completed"\n'
312 ready_timeout_negative = (
313 ' if wait_for_status_file "$case_dir/controller-ready.status" "$controller"; then\n'
314 ' die "selftest: delayed signal controller unexpectedly became ready"\n'
318 " for ((attempt = 0; attempt < 20; ++attempt)); do\n"
319 ' [[ ! -e "$SELFTEST_CASE_DIR/build-entered.status" ]] ||\n'
320 ' die "selftest: forced rebuild bypassed the held lock"\n'
321 ' process_is_terminal "$SELFTEST_WORKER_PID" &&\n'
322 ' die "selftest: forced rebuild exited while the lock was held"\n'
327 ' [[ "$SELFTEST_REAP_STATUS" == "$expected" ]] ||\n'
328 ' die "selftest: $signal controller returned $SELFTEST_REAP_STATUS, '
329 'expected $expected"\n'
333 "image lock post-ready negative completion proof removed",
334 "devcontainer_image_lock_selftest",
339 "image lock post-ready proof stranded in comments",
340 "devcontainer_image_lock_selftest",
342 " # post-ready negative completion proof removed\n",
345 "image lock signal-ready negative deadline proof removed",
346 "devcontainer_image_signal_selftest",
347 ready_timeout_negative,
351 "image lock signal expected status proof removed",
352 "devcontainer_image_signal_selftest",
357 "image lock forced contention observation loop removed",
358 "devcontainer_image_lock_selftest",
365def _raw_return_mutations() -> tuple[Mutation, ...]:
366 """Return equivalent Bash success spellings rejected by the raw digest."""
367 opening =
"parent_lock_fd_is_closed() {\n"
369 (
"return plus-zero",
" return +0\n"),
370 (
"return double-zero",
" return 00\n"),
371 (
"arithmetic return",
' return "$((0))"\n'),
372 (
"command return",
" command return 0\n"),
373 (
"builtin return",
" builtin return 0\n"),
374 (
"exit success",
" exit 0\n"),
375 (
"inline success",
" true; return 0\n"),
379 f
"image lock raw digest rejects {label}",
380 "devcontainer_image_lock_receipts",
384 for label, payload
in variants
388def _raw_surface_mutations() -> tuple[Mutation, ...]:
389 """Return raw comment and alternate-definition mutations."""
392 "image lock entry raw-byte comment change",
393 "devcontainer_image",
394 "# Copyright (c) 2026 Brighton Sikarskie\n",
395 "# Copyright (c) 2026 Brighton Sikarskie \n",
398 "image lock helper raw-byte comment change",
399 "devcontainer_image_lock_selftest",
400 "# Copyright (c) 2026 Brighton Sikarskie\n",
401 "# Copyright (c) 2026 Brighton Sikarskie \n",
404 "image lock receipt helper raw-byte comment change",
405 "devcontainer_image_lock_receipts",
406 "# Copyright (c) 2026 Brighton Sikarskie\n",
407 "# Copyright (c) 2026 Brighton Sikarskie \n",
410 "image lock appended alternate function definition",
411 "devcontainer_image_lock_selftest",
412 " *) die \"unknown image-lock selftest dispatch '$command'\" ;;\n esac\n}\n",
413 " *) die \"unknown image-lock selftest dispatch '$command'\" ;;\n"
416 "parent_lock_fd_is_closed() {\n"
423def _raw_digest_mutations() -> tuple[Mutation, ...]:
424 """Return raw byte, alternate-definition, and stranded-proof attacks."""
426 *_raw_return_mutations(),
427 *_raw_surface_mutations(),
429 "image lock active cleanup proof replaced by no-op",
430 "devcontainer_image_lock_selftest",
431 " parent_lock_fd_is_closed || cleanup_failed=1\n",
435 "image lock cleanup proof stranded in a string",
436 "devcontainer_image_lock_selftest",
437 " parent_lock_fd_is_closed || cleanup_failed=1\n",
438 " printf '%s\\n' 'parent_lock_fd_is_closed' >/dev/null\n",
441 "image lock cleanup proof stranded in a comment",
442 "devcontainer_image_lock_selftest",
443 " parent_lock_fd_is_closed || cleanup_failed=1\n",
444 " # parent_lock_fd_is_closed || cleanup_failed=1\n",
447 "image lock signal-controller sleep inherits parent lock FD",
448 "devcontainer_image_lock_selftest",
449 ' if [[ "$readiness_mode" == "delay-controller-ready" ]]; then\n'
450 " while :; do sleep 1 8>&-; done\n"
452 ' if [[ "$readiness_mode" == "delay-controller-ready" ]]; then\n'
453 " while :; do sleep 1; done\n"
459def _selftest_semantic_attack_mutations() -> tuple[Mutation, ...]:
460 """Return managed-object semantic attack mutations."""
463 "missing managed group marker attack removed",
464 "devcontainer_image_lock_selftest",
465 'if (RA8_IMAGE_LOCK_DIR="$tmp/missing-marker" resolve_image_lock ',
466 "if (false && RA8_IMAGE_LOCK_DIR=unused resolve_image_lock ",
469 "symlinked managed group marker attack removed",
470 "devcontainer_image_lock_selftest",
471 ' die "selftest: symlinked managed image lock group marker passed"',
475 "hardlinked managed group marker attack removed",
476 "devcontainer_image_lock_selftest",
477 ' die "selftest: multiply-linked managed image lock group marker passed"',
481 "wrong managed directory group attack removed",
482 "devcontainer_image_lock_selftest",
483 ' die "selftest: wrong managed image lock directory group passed"',
487 "wrong managed lock group attack removed",
488 "devcontainer_image_lock_selftest",
489 ' die "selftest: wrong managed image lock file group passed"',
493 "wrong managed group marker owner attack removed",
494 "devcontainer_image_lock_selftest",
495 ' die "selftest: non-root managed image lock group marker passed"',
499 "wrong managed group marker mode attack removed",
500 "devcontainer_image_lock_selftest",
501 ' die "selftest: writable managed image lock group marker passed"',
505 "wrong managed group marker content attack removed",
506 "devcontainer_image_lock_selftest",
507 ' die "selftest: root group in managed image lock group marker passed"',
511 "binary managed group marker attack removed",
512 "devcontainer_image_lock_selftest",
513 ' die "selftest: binary managed image lock group marker passed"',
519def _extraction_authority_mutations() -> tuple[Mutation, ...]:
520 """Return load-bearing mutations for extracted supervisor responsibilities."""
523 "supervisor interruption-handler definition removed",
524 "devcontainer_image_selftest_supervisor",
525 "def _install_interruption_handlers(supervisor: BoundGroup) -> None:",
526 "def _install_interruption_handlers_disabled(supervisor: BoundGroup) -> None:",
529 "supervisor interruption-handler call removed",
530 "devcontainer_image_selftest_supervisor",
531 "_install_interruption_handlers(supervisor)",
532 "pass # mutation: handler install removed",
535 "closed-controller command definition removed",
536 "devcontainer_image_selftest_supervisor_cases",
537 "def _closed_controller_command(",
538 "def _closed_controller_command_disabled(",
541 "closed-controller command call removed",
542 "devcontainer_image_selftest_supervisor_cases",
543 "command = _closed_controller_command(\n"
544 " entry_authority, status, death_descriptor, root_descriptor, "
547 " child = subprocess.Popen(",
548 "child = subprocess.Popen(",
553def runtime_selftest_tail_mutations() -> tuple[Mutation, ...]:
554 """Return process-controller fallback and semantic attack mutations."""
556 *_selftest_fallback_mutations(),
557 *process_authority_mutations(),
558 *_extraction_authority_mutations(),
559 *_selftest_semantic_attack_mutations(),
563def runtime_readiness_mutations() -> tuple[Mutation, ...]:
564 """Return readiness, liveness, and cleanup-trap mutations."""
567 "forced-build readiness deadline removed",
568 "devcontainer_image_lock_selftest",
569 "wait_for_status_file() {\n"
570 ' local path="$1" pid="$2" attempt\n'
571 " for ((attempt = 0; attempt < SELFTEST_DEADLINE_STEPS; ++attempt)); do",
572 'wait_for_status_file() {\n local path="$1" pid="$2" attempt\n while true; do',
575 "forced-build readiness child-liveness check bypassed",
576 "devcontainer_image_lock_selftest",
577 ' if process_is_terminal "$pid"; then\n'
578 ' [[ -s "$path" ]] && return 0\n'
580 " if false; then\n return 0\n return 1",
583 "forced-build failure cleanup trap removed",
584 "devcontainer_image_lock_selftest",
585 " trap image_lock_case_exit EXIT",
591def runtime_worker_mutations() -> tuple[Mutation, ...]:
592 """Return isolated worker-group handshake mutations."""
595 "image lock worker process-group isolation removed",
596 "devcontainer_image_lock_selftest",
597 ' exec /usr/bin/setsid /bin/bash -p -- "$SELFTEST_IMAGE_ENTRY"',
598 ' exec /bin/bash -p -- "$SELFTEST_IMAGE_ENTRY"',
601 "image lock worker inherited parent lock close removed",
602 "devcontainer_image_lock_selftest",
603 " exec 8>&-\n trap '' HUP INT TERM\n"
604 ' exec /usr/bin/setsid /bin/bash -p -- "$SELFTEST_IMAGE_ENTRY"',
605 " :\n trap '' HUP INT TERM\n"
606 ' exec /usr/bin/setsid /bin/bash -p -- "$SELFTEST_IMAGE_ENTRY"',
609 "image lock worker verified group handshake removed",
610 "devcontainer_image_lock_selftest",
611 " if ! read_worker_group; then\n abort_bound_worker_spawn 1\n fi",
612 " if false; then\n abort_bound_worker_spawn 1\n fi",
615 "image lock worker group record moved after dispatch",
616 "devcontainer_image_lock_selftest",
617 ' record_worker_group "$case_dir" "$mode"\n'
618 ' wait_for_worker_ack "$case_dir" "$$" || exit 124',
619 ' wait_for_worker_ack "$case_dir" "$$" || exit 124\n'
620 ' record_worker_group "$case_dir" "$mode"',
623 "image lock worker pgid equality guard removed",
624 "devcontainer_image_lock_selftest",
625 ' [[ "$pgid" == "$pid" ]] || die "selftest isolated worker is not its group leader"',
629 "image lock worker own-group guard removed",
630 "devcontainer_image_lock_selftest",
631 ' [[ "$SELFTEST_WORKER_PGID" != "$own_pgid" ]]',
637def runtime_loader_mutations() -> tuple[Mutation, ...]:
638 """Return authenticated receipt and lock helper loader mutations."""
641 "managed image lock receipt helper source removed",
642 "devcontainer_image_selftest_cases",
643 ' source_approved_selftest_helper "$receipts" "$IMAGE_LOCK_RECEIPTS_RAW_SHA256"',
647 "managed image lock receipt source-only diagnostic weakened",
648 "devcontainer_image_selftest_cases",
649 ' "$output" == "error: devcontainer image lock receipt helper is source-only"',
653 "managed image lock selftest helper source removed",
654 "devcontainer_image_selftest_cases",
655 ' source_approved_selftest_helper "$helper" "$IMAGE_LOCK_SELFTEST_RAW_SHA256"',
659 "managed image lock receipt helper loaded after its consumer",
660 "devcontainer_image_selftest_cases",
661 ' source_approved_selftest_helper "$receipts" "$IMAGE_LOCK_RECEIPTS_RAW_SHA256"\n'
662 ' source_approved_selftest_helper "$helper" "$IMAGE_LOCK_SELFTEST_RAW_SHA256"',
663 ' source_approved_selftest_helper "$helper" "$IMAGE_LOCK_SELFTEST_RAW_SHA256"\n'
664 ' source_approved_selftest_helper "$receipts" "$IMAGE_LOCK_RECEIPTS_RAW_SHA256"',
669def mutations() -> tuple[Mutation, ...]:
670 """Return the split image-lock authority/proof/serialization mutations."""
672 *_authority_mutations(),
673 *_ansible_proof_mutations(),
674 *_serialization_mutations(),
675 *_receipt_early_return_mutations(),
676 *_receipt_semantic_mutations(),
677 *_raw_digest_mutations(),