4"""Enforce the exhaustive typed first-party shell entry-point authority.
6NUL cleanup rejects forged input; paths/symlinks fail; same-UID writes are out of scope.
9from __future__
import annotations
19from pathlib
import Path
21sys.path.insert(0, str(Path(__file__).resolve().parent))
23from lint_targets
import files_for
24from privileged_startup_runtime_selftest
import (
28 run_privileged_wrapper_runtime_cases,
30from shell_entrypoint_policy
import (
43from shell_entrypoint_policy_ci
import CI_POLICY_ROWS
44from shell_entrypoint_policy_hil
import HIL_POLICY_ROWS
46REPO_ROOT = Path(__file__).resolve().parents[2]
52PRIVILEGED_BODY_OPEN =
'if [[ "$-" == *p* ]]; then'
53FAILED_CLEANUP_EXEC =
"_ra8_startup_refuse 'could not enter sanitized process'"
54PRIVILEGED_BODY_PREFIX = (
56 "unset -v BASH_ENV ENV",
57 "declare -a ra8_startup_env_unset=()",
58 "_ra8_startup_refuse() {",
59 " printf 'error: privileged startup %s\\n' \"$1\" >&2",
62 "ra8_startup_env_done_count=0",
63 "while IFS= read -r -d '' ra8_startup_env_row; do",
64 ' ra8_startup_env_name="${ra8_startup_env_row%%=*}"',
65 ' case "$ra8_startup_env_name" in',
66 " RA8_STARTUP_ENV_DONE)",
67 " ra8_startup_env_done_count=$((ra8_startup_env_done_count + 1))",
70 " BASH_FUNC_*%% | BASH_FUNC_*'()') ra8_startup_env_unset+=(-u \"$ra8_startup_env_name\") ;;",
73 " /usr/bin/env -u RA8_STARTUP_ENV_DONE -0 &&",
74 " /usr/bin/printf 'RA8_STARTUP_ENV_DONE=1\\0'",
77 "((ra8_startup_env_done_count == 1)) && "
78 '[[ "$ra8_startup_env_name" == RA8_STARTUP_ENV_DONE ]] || '
79 "_ra8_startup_refuse 'environment enumeration was incomplete'"
81 "if ((${#ra8_startup_env_unset[@]})); then",
82 " [[ -z \"${RA8_STARTUP_ENV_SCRUBBED-}\" ]] || _ra8_startup_refuse 'scrub did not converge'",
83 ' ra8_startup_reentry="$0"',
84 " [[ \"$ra8_startup_reentry\" == */* ]] || _ra8_startup_refuse 'requires a script path'",
85 ' if [[ "$ra8_startup_reentry" != /* ]]; then',
86 ' ra8_startup_reentry="$PWD/$ra8_startup_reentry"',
88 ' ra8_startup_check="$ra8_startup_reentry"',
89 ' while [[ "$ra8_startup_check" != "/" ]]; do',
90 " [[ ! -L \"$ra8_startup_check\" ]] || _ra8_startup_refuse 'refuses a symlinked path'",
91 ' ra8_startup_parent="${ra8_startup_check%/*}"',
92 ' [[ -n "$ra8_startup_parent" ]] || ra8_startup_parent="/"',
93 ' [[ "$ra8_startup_parent" != "$ra8_startup_check" ]] ||',
94 " _ra8_startup_refuse 'cannot validate its script path'",
95 ' ra8_startup_check="$ra8_startup_parent"',
97 " [[ -f \"$ra8_startup_reentry\" ]] || _ra8_startup_refuse 'refuses a non-regular path'",
98 ' if ! exec /usr/bin/env "${ra8_startup_env_unset[@]}" -u BASH_ENV -u ENV \\',
99 " -u RA8_STARTUP_ENV_DONE RA8_STARTUP_ENV_SCRUBBED=1 \\",
100 ' /bin/bash -p -- "$ra8_startup_reentry" "$@"; then',
101 f
" {FAILED_CLEANUP_EXEC}",
104 "unset -v ra8_startup_check ra8_startup_env_done_count",
105 "unset -v ra8_startup_env_name ra8_startup_env_row",
106 "unset -v ra8_startup_env_unset ra8_startup_parent ra8_startup_reentry",
107 "unset -v RA8_STARTUP_ENV_DONE",
108 "unset -v RA8_STARTUP_ENV_SCRUBBED",
109 "unset -f _ra8_startup_refuse",
111PRIVILEGED_DUAL_BODY_PREFIX = (
112 *PRIVILEGED_BODY_PREFIX[
113 : PRIVILEGED_BODY_PREFIX.index(
"if ((${#ra8_startup_env_unset[@]})); then") + 1
115 ' if [[ "${BASH_SOURCE[0]}" != "$0" ]]; then',
116 " printf 'error: sourced privileged entry refuses inherited Bash functions\\n' >&2",
117 " unset -v ra8_startup_env_done_count",
118 " unset -v ra8_startup_env_name ra8_startup_env_row ra8_startup_env_unset",
119 " unset -v RA8_STARTUP_ENV_DONE RA8_STARTUP_ENV_SCRUBBED",
120 " unset -f _ra8_startup_refuse",
123 *PRIVILEGED_BODY_PREFIX[
124 PRIVILEGED_BODY_PREFIX.index(
"if ((${#ra8_startup_env_unset[@]})); then") + 1 :
127PRIVILEGED_RIG_BODY_PREFIX = tuple(
128 " printf 'error: sourced rig contract refuses inherited Bash functions\\n' >&2"
130 ==
" printf 'error: sourced privileged entry refuses inherited Bash functions\\n' >&2"
132 for line
in PRIVILEGED_DUAL_BODY_PREFIX
134PRIVILEGED_BODY_CLOSE = (
"else",
'[[ "$-" == *p* ]]',
"fi")
135PRIVILEGED_RUNTIME_VARIANTS = tuple(
136 WrapperVariant(name, prefix, PRIVILEGED_BODY_CLOSE)
137 for name, prefix
in (
138 (
"plain", PRIVILEGED_BODY_PREFIX),
139 (
"dual", PRIVILEGED_DUAL_BODY_PREFIX),
140 (
"rig", PRIVILEGED_RIG_BODY_PREFIX),
143FORBIDDEN_REEXEC_TOKENS = (
144 "builtin unset BASH_ENV",
145 "builtin exec /bin/bash",
146 "command builtin unset BASH_ENV",
147 "command builtin exec /bin/bash",
149PINNED_INTERPRETER_BOUNDARIES = {
154 "# SPDX-License-Identifier: MIT",
155 "# Copyright (c) 2026 Brighton Sikarskie",
162def _shell_census() -> tuple[str, ...]:
163 """Return the canonical tracked-and-untracked first-party shell census."""
164 return tuple(files_for((
"shell",))[
"shell"])
167def _is_executable(path: Path) -> bool:
168 """Return whether any executable mode bit is set."""
169 return bool(path.stat().st_mode & (stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH))
172def _header(path: Path) -> tuple[str, ...]:
173 """Return the four-line combined preamble, or an empty tuple when unreadable."""
175 return tuple(path.read_text(encoding=
"utf-8").splitlines()[:4])
176 except (OSError, UnicodeError):
180def _header_matches(header: tuple[str, ...], expected: tuple[str, ...]) -> bool:
181 """Return whether ``header`` starts with the complete expected preamble."""
182 return header[: len(expected)] == expected
187 policies: dict[str, ShellPolicy],
189 """Return missing and stale typed-authority entries."""
190 missing = sorted(census - policies.keys())
191 findings = [f
"unclassified shell entry point: {path}" for path
in missing]
193 f
"stale shell entry-point authority: {path}" for path
in sorted(policies.keys() - census)
195 for path, policy
in sorted(policies.items()):
196 if policy.usage
is ShellUsage.SOURCED_ONLY
and policy.executable:
197 findings.append(f
"{path}: sourced-only policy cannot be executable")
198 if policy.source_requires_privileged_parent
and policy.usage
is ShellUsage.ENTRY:
199 findings.append(f
"{path}: entry-only policy cannot require a privileged source parent")
201 policy.security
is ShellSecurity.PRIVILEGED
202 and policy.usage
is not ShellUsage.ENTRY
203 and not policy.source_requires_privileged_parent
205 findings.append(f
"{path}: privileged sourced usage requires a privileged parent")
206 if policy.security
is ShellSecurity.PRIVILEGED
and policy.dialect
is not ShellDialect.BASH:
207 findings.append(f
"{path}: privileged policy requires the Bash dialect")
211def _path_findings(rel: str, policy: ShellPolicy) -> list[str]:
212 """Validate one path's exact shebang, reason, and executable mode."""
213 path = REPO_ROOT / rel
214 header = _header(path)
215 findings: list[str] = []
216 if policy.security
is ShellSecurity.PRIVILEGED:
217 expected_header = PINNED_INTERPRETER_BOUNDARIES[rel]
218 elif policy.dialect
is ShellDialect.POSIX_SH:
219 expected_header = (PORTABLE_SH_SHEBANG,)
221 expected_header = (PORTABLE_SHEBANG,)
222 if not _header_matches(header, expected_header):
224 f
"{rel}: {policy.security.value}/{policy.usage.value} header "
225 f
"must start with {expected_header!r}"
228 executable = _is_executable(path)
229 except OSError
as exc:
230 findings.append(f
"{rel}: cannot inspect executable mode: {exc}")
232 if executable != policy.executable:
234 f
"{rel}: executable={executable} disagrees with typed authority "
235 f
"executable={policy.executable}"
240def _active_lines(text: str) -> tuple[str, ...]:
241 """Return nonblank, noncomment physical lines stripped for guard checks."""
244 for line
in text.splitlines()
245 if line.strip()
and not line.lstrip().startswith(
"#")
249def _single_outer_if(text: str) -> bool:
250 """Return whether shfmt parses the whole program as one outer if."""
251 shfmt = shutil.which(
"shfmt", path=
"/usr/local/bin:/usr/bin:/opt/homebrew/bin:/opt/local/bin")
254 result = subprocess.run(
255 [shfmt,
"--to-json"],
261 if result.returncode != 0:
264 tree = json.loads(result.stdout)
265 except json.JSONDecodeError:
267 statements = tree.get(
"Stmts", [])
268 return len(statements) == 1
and statements[0].get(
"Cmd", {}).get(
"Type") ==
"IfClause"
271def privileged_body_findings(
274 policy: ShellPolicy |
None =
None,
276 """Require the complete real body to live in the privileged branch."""
277 active = _active_lines(text)
278 findings: list[str] = []
279 if rel ==
"scripts/hil/lib/rig_contract.sh":
280 prefix = PRIVILEGED_RIG_BODY_PREFIX
281 elif policy
is not None and policy.usage
is ShellUsage.DUAL_USE:
282 prefix = PRIVILEGED_DUAL_BODY_PREFIX
284 prefix = PRIVILEGED_BODY_PREFIX
285 if active[: len(prefix)] != tuple(line.strip()
for line
in prefix):
287 f
"{rel}: wrapper and complete descendant startup cleanup are not first active code"
289 if active[-len(PRIVILEGED_BODY_CLOSE) :] != PRIVILEGED_BODY_CLOSE:
290 findings.append(f
"{rel}: privileged-body wrapper does not close the entire real body")
291 if not _single_outer_if(text):
292 findings.append(f
"{rel}: active code escapes the outer privileged branch")
293 if any(token
in text
for token
in FORBIDDEN_REEXEC_TOKENS):
294 findings.append(f
"{rel}: unsafe in-script sanitization/re-exec remains")
298def _requires_privileged_body(rel: str, text: str, policy: ShellPolicy) -> bool:
299 """Derive wrappers exhaustively from the typed privilege/usage authority."""
302 policy.security
is ShellSecurity.PRIVILEGED
and policy.usage
is not ShellUsage.SOURCED_ONLY
306def scan() -> tuple[list[str], int, int, int, int]:
307 """Return findings and typed population counts."""
308 census = set(_shell_census())
309 findings = _policy_findings(census, SHELL_POLICIES)
310 for rel
in sorted(census & SHELL_POLICIES.keys()):
311 findings.extend(_path_findings(rel, SHELL_POLICIES[rel]))
313 for rel
in sorted(census & SHELL_POLICIES.keys()):
315 text = (REPO_ROOT / rel).read_text(encoding=
"utf-8")
316 except (OSError, UnicodeError)
as exc:
317 findings.append(f
"{rel}: cannot inspect privileged body: {exc}")
319 if _requires_privileged_body(rel, text, SHELL_POLICIES[rel]):
321 findings.extend(privileged_body_findings(rel, text, SHELL_POLICIES[rel]))
323 policy.security
is ShellSecurity.PRIVILEGED
for policy
in SHELL_POLICIES.values()
325 sourced = sum(policy.usage
is ShellUsage.SOURCED_ONLY
for policy
in SHELL_POLICIES.values())
326 return findings, len(census), privileged, sourced, guarded
330 body: str =
"printf 'BODY mode=%s\\n' \"$-\"",
332 cleanup: bool =
True,
333 prefix: tuple[str, ...] |
None =
None,
335 """Return one inert exact privileged-body fixture."""
337 prefix = PRIVILEGED_BODY_PREFIX
if cleanup
else (PRIVILEGED_BODY_OPEN,)
338 guarded =
"\n".join((prefix[0], *(f
" {line}" for line
in prefix[1:]), f
" {body}"))
340 f
"{PRIVILEGED_SHEBANG}\n"
341 "# SPDX-License-Identifier: MIT\n"
342 "# Copyright (c) 2026 Brighton Sikarskie\n"
343 f
"{PRIVILEGED_REASON}\n"
345 f
"{PRIVILEGED_BODY_CLOSE[0]}\n {PRIVILEGED_BODY_CLOSE[1]}\n"
346 f
"{PRIVILEGED_BODY_CLOSE[2]}\n"
350@dataclasses.dataclass(frozen=True)
352 """One hostile startup fixture driven through the governed wrapper."""
354 prefix: tuple[str, ...] |
None =
None
355 body_override: str |
None =
None
356 args: tuple[str, ...] = ()
357 extra_env: dict[str, str] |
None =
None
358 producer: str =
"live"
359 entry: str =
"direct"
360 raw_function: bool =
True
361 count_entries: bool =
False
362 timeout: float = 10.0
365SELFTEST_TALLY = {
"runtime": 0,
"structural_mutations": 0}
368def _producer_script(kind: str) -> str:
369 """Return a synthetic NUL-framed producer for one completeness attack."""
370 marker =
"RA8_STARTUP_ENV_DONE=1\\0"
372 "zero":
"#!/bin/sh\nexit 0\n",
373 "duplicate": f
"#!/bin/sh\nprintf '{marker}{marker}'\n",
374 "not-last": f
"#!/bin/sh\nprintf '{marker}AFTER=1\\0'\n",
375 "torn":
"#!/bin/sh\nprintf 'BASH_FUNC_probe%%%%=() { :; }\\0'\nexit 42\n",
376 "failed":
"#!/bin/sh\nexit 2\n",
381def _startup_fixture_text(root: Path, case: StartupCase, body: str |
None, cleanup: bool) -> str:
382 """Render one wrapper fixture, replacing its producer when requested."""
384 _fixture_text(cleanup=cleanup, prefix=case.prefix)
386 else _fixture_text(body, cleanup=cleanup, prefix=case.prefix)
388 if case.producer !=
"live":
389 producer = root /
"environment-producer"
390 producer.write_text(_producer_script(case.producer), encoding=
"ascii")
391 producer.chmod(0o700)
393 " /usr/bin/env -u RA8_STARTUP_ENV_DONE -0 &&\n"
394 " /usr/bin/printf 'RA8_STARTUP_ENV_DONE=1\\0'"
396 if fixture.count(live) != 1:
397 message =
"startup producer fixture no longer matches the governed wrapper"
398 raise RuntimeError(message)
399 fixture = fixture.replace(live, f
" {producer}", 1)
400 if case.count_entries:
401 entry =
'if [[ "$-" == *p* ]]; then\n'
402 counted = entry +
' /usr/bin/printf x >>"${RA8_STARTUP_ENTRY_LOG:?}"\n'
403 fixture = fixture.replace(entry, counted, 1)
407def _startup_bash_env(early_exit: bool, descendant: bool) -> str:
408 """Return hostile startup bytes for one runtime fixture."""
410 return "printf 'EARLY\\n'\nexit 43\n"
411 names = (
"command",
"builtin",
"unset",
"exec",
"exit",
"/bin/bash")
412 definitions = [
"shopt -s expand_aliases"]
413 for index, name
in enumerate(names):
414 definitions.append(f
"function {name} {{ printf 'HOSTILE-{index}\\n'; }}")
415 definitions.append(f
"alias {name}='printf ALIAS-{index}\\n'")
417 definitions.append(
"printf 'DESCENDANT-STARTUP\\n'")
418 return "\n".join(definitions) +
"\n"
421def _startup_argv(root: Path, script: Path, entry: str, privileged: bool) -> list[str]:
422 """Materialize and select one script-name shape."""
423 hardlink = root /
"hardlink.sh"
424 if entry ==
"hardlink":
425 os.link(script, hardlink)
426 leaf_link = root /
"leaf-link.sh"
427 if entry ==
"leaf-symlink":
428 leaf_link.symlink_to(script)
429 parent_link = root /
"parent-link"
430 if entry ==
"parent-symlink":
431 parent_link.symlink_to(root, target_is_directory=
True)
433 "absolute": [
"/bin/bash",
"-p", str(script)],
434 "relative": [
"./fixture.sh"],
435 "hardlink": [str(hardlink)],
436 "leaf-symlink": [str(leaf_link)],
437 "parent-symlink": [str(parent_link / script.name)],
438 "bare": [
"/bin/bash",
"-p", script.name],
439 "dev-fd": [
"/bin/bash",
"-p",
"-c", f
"exec /bin/bash -p <(cat {shlex_quote(str(script))})"],
444 f
". {shlex_quote(str(script))}; printf 'SOURCED_RC=%s\\n' \"$?\"",
447 return choices.get(entry, [str(script)]
if privileged
else [
"/bin/bash", str(script)])
454 descendant: bool =
False,
455 cleanup: bool =
True,
456 case: StartupCase |
None =
None,
457) -> subprocess.CompletedProcess[str]:
458 """Run the inert wrapper against hostile startup definitions."""
459 case = case
if case
is not None else StartupCase()
460 with tempfile.TemporaryDirectory(prefix=
"ra8-privileged-body-")
as raw:
464 root = Path(raw).resolve()
465 script = root /
"fixture.sh"
466 bash_env = root /
"bash-env"
468 '/bin/bash -c "type probe >/dev/null 2>&1 && '
469 "printf 'IMPORTED\\n' || printf 'CHILD\\n'\""
473 body = case.body_override
if case.body_override
is not None else body
474 fixture = _startup_fixture_text(root, case, body, cleanup)
475 script.write_text(fixture, encoding=
"utf-8")
477 bash_env.write_text(_startup_bash_env(early_exit, descendant), encoding=
"utf-8")
478 argv = _startup_argv(root, script, case.entry, privileged)
480 "BASH_ENV": str(bash_env),
481 "ENV": str(bash_env),
482 "PATH":
"/usr/bin:/bin",
485 if case.count_entries:
486 environment[
"RA8_STARTUP_ENTRY_LOG"] = str(root /
"entry-log")
487 if case.raw_function:
488 environment[
"BASH_FUNC_probe%%"] =
"() { printf 'RAW-FUNCTION\\n'; }"
489 environment.update(case.extra_env
or {})
490 SELFTEST_TALLY[
"runtime"] += 1
496 timeout=case.timeout,
501def shlex_quote(value: str) -> str:
502 """Quote one fixture-only path without adding a runtime dependency."""
503 return "'" + value.replace(
"'",
"'\\''") +
"'"
506def _authority_selftest_failures() -> list[str]:
507 """Exercise typed census and independent usage/security policies."""
508 failures: list[str] = []
509 policy = ShellPolicy(
510 ShellSecurity.PORTABLE,
514 source_requires_privileged_parent=
False,
516 if _policy_findings({
"a.sh"}, {
"a.sh": policy}):
517 failures.append(
"matching typed census was rejected")
518 if not _policy_findings({
"a.sh",
"new.sh"}, {
"a.sh": policy}):
519 failures.append(
"future unclassified shell was accepted")
520 if not _policy_findings({
"a.sh"}, {
"a.sh": policy,
"old.sh": policy}):
521 failures.append(
"stale authority entry was accepted")
522 sourced = ShellPolicy(
523 ShellSecurity.PRIVILEGED,
524 ShellUsage.SOURCED_ONLY,
527 source_requires_privileged_parent=
True,
529 if _policy_findings({
"lib.sh"}, {
"lib.sh": sourced}):
530 failures.append(
"valid privileged sourced-only policy was rejected")
531 failures.extend(_preamble_selftest_failures())
532 if not _policy_findings(
535 "lib.sh": ShellPolicy(
536 ShellSecurity.PRIVILEGED,
537 ShellUsage.SOURCED_ONLY,
540 source_requires_privileged_parent=
True,
544 failures.append(
"executable sourced-only policy was accepted")
546 ShellSecurity.PRIVILEGED,
550 source_requires_privileged_parent=
True,
552 if _policy_findings({
"dual.sh"}, {
"dual.sh": dual}):
553 failures.append(
"valid non-executable dual-use policy was rejected")
554 failures.extend(_privileged_parent_selftest_failures((sourced, dual)))
555 if len(SHELL_POLICIES) != len(set(SHELL_POLICIES)):
556 failures.append(
"aggregate policy authority contains duplicate paths")
557 for name, domain
in ((
"CI", CI_POLICY_ROWS), (
"HIL", HIL_POLICY_ROWS)):
558 if any(row[0]
not in SHELL_POLICIES
for row
in domain):
559 failures.append(f
"{name} domain policy rows were not merged")
561 merge_policy_tables({domain[0][0]: policy}, domain)
565 failures.append(f
"duplicate {name} domain policy path was accepted")
569def _privileged_parent_selftest_failures(
570 policies: tuple[ShellPolicy, ...],
572 """Reject privileged sourced policies without a privileged parent."""
573 failures: list[str] = []
574 for policy
in policies:
575 weakened = dataclasses.replace(policy, source_requires_privileged_parent=
False)
576 if _policy_findings({
"fixture.sh"}, {
"fixture.sh": weakened}):
579 f
"privileged {policy.usage.value} policy without a privileged parent was accepted"
584def _preamble_selftest_failures() -> list[str]:
585 """Exercise the combined privileged-shell preamble."""
586 failures: list[str] = []
587 protected = PINNED_INTERPRETER_BOUNDARIES[
"scripts/hil/all.sh"]
588 canonical_protected = (
590 "# SPDX-License-Identifier: MIT",
591 "# Copyright (c) 2026 Brighton Sikarskie",
592 "# SHEBANG-SECURITY: -p blocks BASH_ENV and exported-function startup injection.",
594 if not _header_matches(canonical_protected, protected):
595 failures.append(
"canonical combined privileged preamble was rejected")
599 "# SPDX-License-Identifier: MIT",
600 "# Copyright (c) 2026 Brighton Sikarskie",
602 if _header_matches(old_order, protected):
603 failures.append(
"security rationale before attribution was accepted")
604 wrong_reason = (*canonical_protected[:3],
"# SHEBANG-SECURITY: vague rationale.")
605 if _header_matches(wrong_reason, protected):
606 failures.append(
"non-canonical privileged security rationale was accepted")
610def _guard_structure_mutations(safe: str) -> tuple[str, ...]:
611 """Return independent weakenings of the exact wrapper."""
613 safe.replace(PRIVILEGED_BODY_OPEN,
'if [[ "$-" != *p* ]]; then', 1),
614 safe.replace(
" unset -v BASH_ENV ENV\n",
"", 1),
616 " BASH_FUNC_*%% | BASH_FUNC_*'()') "
617 'ra8_startup_env_unset+=(-u "$ra8_startup_env_name") ;;\n',
621 safe.replace(
" /usr/bin/env -u RA8_STARTUP_ENV_DONE -0 &&\n",
"", 1),
622 safe.replace(
" /usr/bin/printf 'RA8_STARTUP_ENV_DONE=1\\0'\n",
"", 1),
624 " ((ra8_startup_env_done_count == 1)) && "
625 '[[ "$ra8_startup_env_name" == RA8_STARTUP_ENV_DONE ]] || '
626 "_ra8_startup_refuse 'environment enumeration was incomplete'\n",
631 ' [[ -z "${RA8_STARTUP_ENV_SCRUBBED-}" ]] || '
632 "_ra8_startup_refuse 'scrub did not converge'\n",
637 ' [[ "$ra8_startup_reentry" == */* ]] || '
638 "_ra8_startup_refuse 'requires a script path'\n",
643 ' [[ ! -L "$ra8_startup_check" ]] || '
644 "_ra8_startup_refuse 'refuses a symlinked path'\n",
649 ' [[ -f "$ra8_startup_reentry" ]] || '
650 "_ra8_startup_refuse 'refuses a non-regular path'\n",
655 ' if ! exec /usr/bin/env "${ra8_startup_env_unset[@]}" -u BASH_ENV -u ENV \\\n',
659 safe.replace(f
" {FAILED_CLEANUP_EXEC}\n",
"", 1),
660 safe.replace(
"else\n",
"fi\nBODY_AFTER\nelse\n", 1),
661 safe +
"BODY_AFTER\n",
662 safe.replace(
' [[ "$-" == *p* ]]',
" command exit 1", 1),
663 safe.replace(
" printf",
" command builtin exec /bin/bash -p\n printf", 1),
667def _guard_structure_selftest_failures() -> list[str]:
668 """Exercise exact outer-wrapper structure in both directions."""
669 failures: list[str] = []
670 safe = _fixture_text()
671 if privileged_body_findings(
"fixture.sh", safe):
672 failures.append(
"exact privileged-body wrapper was rejected")
673 mutations = _guard_structure_mutations(safe)
674 SELFTEST_TALLY[
"structural_mutations"] += len(mutations)
675 if any(text == safe
for text
in mutations):
676 failures.append(
"a structural mutation did not change the fixture")
677 if any(
not privileged_body_findings(
"fixture.sh", text)
for text
in mutations):
678 failures.append(
"a weakened privileged-body wrapper was accepted")
682def _guard_runtime_selftest_failures() -> list[str]:
683 """Exercise weak startup and descendant-channel attacks at runtime."""
684 failures: list[str] = []
685 weak = _run_fixture(privileged=
False, early_exit=
False)
686 if weak.returncode == 0
or weak.stdout
or "BODY" in weak.stderr:
687 failures.append(
"weak Bash invocation reached output under hostile functions/aliases")
688 direct = _run_fixture(privileged=
True, early_exit=
True)
689 if direct.returncode != 0
or "BODY mode=" not in direct.stdout
or "EARLY" in direct.stdout:
690 failures.append(
"privileged shebang did not ignore hostile early-exit BASH_ENV")
691 early = _run_fixture(privileged=
False, early_exit=
True)
693 early.returncode != EARLY_EXIT_STATUS
694 or "BODY" in early.stdout
695 or "EARLY" not in early.stdout
697 failures.append(
"weak early-exit BASH_ENV behavior was reported dishonestly")
698 descendant = _run_fixture(privileged=
True, early_exit=
False, descendant=
True)
699 control = _run_fixture(privileged=
True, early_exit=
False, descendant=
True, cleanup=
False)
700 if descendant.returncode != 0
or descendant.stdout !=
"CHILD\n":
701 failures.append(
"privileged body leaked hostile startup channels to a child Bash")
702 if "DESCENDANT-STARTUP" not in control.stdout
or "IMPORTED" not in control.stdout:
703 failures.append(
"descendant startup/function control did not demonstrate both attacks")
707def _legacy_phantom_selftest_failures() -> list[str]:
708 """Prove the old line framing loops and NUL framing does not."""
710 PRIVILEGED_BODY_OPEN,
711 "unset -v BASH_ENV ENV",
712 "declare -a ra8_startup_env_unset=()",
713 "while IFS='=' read -r ra8_startup_env_name _; do",
714 'case "$ra8_startup_env_name" in',
715 'BASH_FUNC_*%%) ra8_startup_env_unset+=(-u "$ra8_startup_env_name") ;;',
717 "done < <(/usr/bin/env)",
718 "if ((${#ra8_startup_env_unset[@]})); then",
719 'exec /usr/bin/env "${ra8_startup_env_unset[@]}" -u BASH_ENV -u ENV \\',
720 '/bin/bash -p -- "$0" "$@"',
722 "unset -v ra8_startup_env_name ra8_startup_env_unset",
724 phantom = {
"RA8_STARTUP_PHANTOM":
"\nBASH_FUNC_phantom%%=() { :; }\n}"}
725 failures: list[str] = []
731 prefix=legacy_prefix,
737 except subprocess.TimeoutExpired:
740 failures.append(
"the legacy line-framed negative control did not loop")
742 fixed = _run_fixture(
745 case=StartupCase(extra_env=phantom, raw_function=
False),
747 if fixed.returncode != 0
or fixed.stdout.count(
"BODY mode=") != 1:
748 failures.append(
"an embedded-newline phantom row did not reach the body exactly once")
752def _producer_completion_selftest_failures() -> list[str]:
753 """Require zero, duplicate, misplaced, torn, and failed producers to refuse."""
754 failures: list[str] = []
755 for producer
in (
"zero",
"duplicate",
"not-last",
"torn",
"failed"):
756 result = _run_fixture(
759 case=StartupCase(producer=producer),
761 if result.returncode == 0
or "enumeration was incomplete" not in result.stderr:
762 failures.append(f
"the {producer} environment producer did not fail closed")
766def _startup_convergence_selftest_failures() -> list[str]:
767 """Prove NUL framing, bounded re-entry, argv, and producer completeness."""
769 *_legacy_phantom_selftest_failures(),
770 *_producer_completion_selftest_failures(),
772 sentinel = _run_fixture(
775 case=StartupCase(extra_env={
"RA8_STARTUP_ENV_SCRUBBED":
"attacker"}),
777 if sentinel.returncode == 0
or "did not converge" not in sentinel.stderr:
778 failures.append(
"an attacker-supplied scrub sentinel skipped the real enumeration")
780 counted = _run_fixture(
784 body_override=
'/usr/bin/wc -c <"${RA8_STARTUP_ENTRY_LOG:?}"',
788 if counted.returncode != 0
or counted.stdout.strip() !=
"2":
789 failures.append(
"function cleanup did not converge in exactly two process entries")
791 argv = (
"plain",
"",
"two words",
"tab\tvalue",
"line one\nline two")
793 roundtrip = _run_fixture(
797 body_override=f
"printf 'ARG:%s\\n' \"$@\"\n exit {roundtrip_status}",
801 expected =
"".join(f
"ARG:{value}\n" for value
in argv)
802 if roundtrip.returncode != roundtrip_status
or roundtrip.stdout != expected:
803 failures.append(
"the bounded cleanup re-entry corrupted argv or exit status")
807def _reentry_path_selftest_failures() -> list[str]:
808 """Exercise every supported and refused script-name shape."""
809 failures: list[str] = []
810 for entry
in (
"direct",
"absolute",
"relative",
"hardlink"):
811 result = _run_fixture(
814 case=StartupCase(entry=entry),
816 if result.returncode != 0
or result.stdout.count(
"BODY mode=") != 1:
817 failures.append(f
"the supported {entry} re-entry path was rejected")
818 for entry
in (
"leaf-symlink",
"parent-symlink",
"bare",
"dev-fd"):
819 result = _run_fixture(
822 case=StartupCase(entry=entry),
824 if result.returncode == 0
or "privileged startup" not in result.stderr:
825 failures.append(f
"the unsafe {entry} re-entry path was accepted")
829def _wrapper_variant_selftest_failures() -> list[str]:
830 """Run the plain, dual-use, and rig variants instead of pinning text only."""
831 failures: list[str] = []
832 dual_sourced = _run_fixture(
835 case=StartupCase(prefix=PRIVILEGED_DUAL_BODY_PREFIX, entry=
"sourced"),
837 if "SOURCED_RC=2" not in dual_sourced.stdout
or "BODY mode=" in dual_sourced.stdout:
838 failures.append(
"the sourced dual-use wrapper did not refuse inherited functions")
839 rig_sourced = _run_fixture(
842 case=StartupCase(prefix=PRIVILEGED_RIG_BODY_PREFIX, entry=
"sourced"),
844 if "SOURCED_RC=2" not in rig_sourced.stdout
or "sourced rig contract" not in rig_sourced.stderr:
845 failures.append(
"the sourced rig wrapper did not use its fail-closed branch")
846 for label, prefix
in (
847 (
"dual-use", PRIVILEGED_DUAL_BODY_PREFIX),
848 (
"rig", PRIVILEGED_RIG_BODY_PREFIX),
850 result = _run_fixture(
853 case=StartupCase(prefix=prefix),
855 if result.returncode != 0
or result.stdout.count(
"BODY mode=") != 1:
856 failures.append(f
"the directly executed {label} wrapper did not run exactly once")
860def _guard_derivation_selftest_failures() -> list[str]:
861 """Prove typed policy, not historical repair tokens, derives wrappers."""
862 failures: list[str] = []
863 weak_policy = ShellPolicy(
864 ShellSecurity.PRIVILEGED,
868 source_requires_privileged_parent=
False,
871 f
"{PRIVILEGED_SHEBANG}\n"
872 "# SPDX-License-Identifier: MIT\n"
873 "# Copyright (c) 2026 Brighton Sikarskie\n"
874 f
"{PRIVILEGED_REASON}\n"
875 'if [[ "$-" != *p* ]]; then\n'
876 ' exec /bin/bash -p "$0" "$@"\n'
877 "fi\nprintf 'BODY\\n'\n"
879 if not _requires_privileged_body(
"future.sh", weak_text, weak_policy):
880 failures.append(
"future privileged weak re-exec did not derive a body-wrapper requirement")
881 elif not privileged_body_findings(
"future.sh", weak_text):
882 failures.append(
"future privileged weak re-exec passed without the governed wrapper")
884 f
"{PRIVILEGED_SHEBANG}\n"
885 "# SPDX-License-Identifier: MIT\n"
886 "# Copyright (c) 2026 Brighton Sikarskie\n"
887 f
"{PRIVILEGED_REASON}\n"
888 "printf 'FUTURE BODY\\n'\n"
890 if not _requires_privileged_body(
"future.sh", no_repair_tokens, weak_policy):
891 failures.append(
"privileged entry without historical repair tokens escaped the wrapper")
892 portable_policy = ShellPolicy(
893 ShellSecurity.PORTABLE,
897 source_requires_privileged_parent=
False,
899 if _requires_privileged_body(
"portable.sh", no_repair_tokens, portable_policy):
900 failures.append(
"portable entry incorrectly inherited the privileged-body wrapper")
901 source_policy = ShellPolicy(
902 ShellSecurity.PRIVILEGED,
903 ShellUsage.SOURCED_ONLY,
906 source_requires_privileged_parent=
True,
908 if _requires_privileged_body(
"source.sh", no_repair_tokens, source_policy):
909 failures.append(
"sourced-only helper incorrectly became a launchable guarded entry")
913def _guard_selftest_failures() -> list[str]:
914 """Return all structural, runtime, and policy-derivation failures."""
916 _guard_structure_selftest_failures()
917 + _guard_runtime_selftest_failures()
918 + _startup_convergence_selftest_failures()
919 + _reentry_path_selftest_failures()
920 + _wrapper_variant_selftest_failures()
921 + _guard_derivation_selftest_failures()
924 with tempfile.TemporaryDirectory(prefix=
"ra8-wrapper-state-")
as temporary:
925 SELFTEST_TALLY[
"runtime"] += run_privileged_wrapper_runtime_cases(
926 Path(temporary), PRIVILEGED_RUNTIME_VARIANTS
928 except (OSError, RuntimeError, subprocess.SubprocessError)
as exc:
929 failures.append(f
"hostile wrapper state matrix failed: {exc}")
933def _selftest_failures() -> list[str]:
934 """Return every authority and full-body wrapper selftest failure."""
935 minimum_runtime_cases = 25 + (5 * len(PRIVILEGED_RUNTIME_VARIANTS))
936 minimum_structural_mutations = 15
937 minimum_privileged_paths = 81
938 minimum_guarded_paths = 71
939 SELFTEST_TALLY.update(runtime=0, structural_mutations=0)
940 failures = _authority_selftest_failures() + _guard_selftest_failures()
941 if SELFTEST_TALLY[
"runtime"] < minimum_runtime_cases:
942 failures.append(f
"the runtime attack matrix collapsed below {minimum_runtime_cases} cases")
943 if SELFTEST_TALLY[
"structural_mutations"] < minimum_structural_mutations:
944 failures.append(
"the structural mutation corpus collapsed below 15 cases")
946 _, _, privileged, _, guarded = scan()
947 except (OSError, subprocess.SubprocessError, UnicodeError)
as exc:
948 failures.append(f
"the live wrapper census could not be measured: {exc}")
950 if privileged < minimum_privileged_paths
or guarded < minimum_guarded_paths:
952 f
"the live wrapper census collapsed to {privileged} privileged/{guarded} guarded"
957def selftest() -> int:
958 """Run both-direction typed-authority and startup-attack fixtures."""
959 failures = _selftest_failures()
960 for failure
in failures:
961 print(f
"check_shebangs.py --selftest: FAIL: {failure}", file=sys.stderr)
965 "check_shebangs.py --selftest: PASS "
966 f
"({SELFTEST_TALLY['runtime']} runtime cases, "
967 f
"{SELFTEST_TALLY['structural_mutations']} structural mutations)"
972def main(argv: list[str]) -> int:
973 """Run the selftest or the exhaustive live authority scan."""
974 if argv[1:] == [
"--selftest"]:
977 print(
"usage: check_shebangs.py [--selftest]", file=sys.stderr)
980 findings, total, privileged, sourced, guarded = scan()
981 except (OSError, subprocess.SubprocessError, UnicodeError)
as exc:
982 print(f
"check_shebangs.py: FATAL: {exc}", file=sys.stderr)
985 print(
"check_shebangs.py: typed shell-entrypoint finding(s):", file=sys.stderr)
986 for finding
in findings:
987 print(f
" {finding}", file=sys.stderr)
989 portable = total - privileged
991 "check_shebangs.py: exhaustive authority clean "
992 f
"({total} shell files: {privileged} privileged, {portable} portable, "
993 f
"{sourced} sourced-only, {guarded} structurally guarded)"
998if __name__ ==
"__main__":
999 raise SystemExit(
main(sys.argv))
void main(void)
The application entry point Reset_Handler hands control to.