test(#829): extend guard evasion matrix and primitive invariant

This commit is contained in:
ms-lead-reviewer
2026-07-17 23:59:39 -05:00
parent 9582457228
commit 88a709a9f3
2 changed files with 21 additions and 0 deletions

View File

@@ -108,3 +108,5 @@ Carried authority chain also verified/read for the locked T-B gate contract: SPE
- Reproduced RIDER E exactly at head `1792b7934dda7eff64a207b8b0edb9c460d4164b`: a temporary production file containing `exec claude --dangerously-skip-permissions "terra-r3" # launch-runtime.py` made the guard exit 0 and report `1 gated/1 total`.
- Root cause: classification searched the unparsed physical line, and the broad gated regex treated any `launch-runtime.py` substring—including comments and inert arguments—as an invocation before the direct-launch finding was evaluated.
- Round-4 plan: add permanent RED cases for the exact comment evasion plus string-argument, echo, and unrelated-variable marker evasions; tokenize/strip comments by launcher syntax; recognize only command-position wrapper invocations with `--runtime` and the gated command separator; retain 14/14 real inventory; rerun guard coverage and all gates fresh.
- Mos Rider A/B decision: adopt **both** defenses. Command-position parsing remains necessary because a normal `claude -p` launch is consequential even without the dangerous flag. The primitive-location invariant is more mechanically robust for dangerous mode because it does not need to recognize a wrapper marker at all. Move the sole raw `--dangerously-skip-permissions` literal into `launch-runtime.py`; any occurrence in another production file is independently RED.
- Rider-A RED matrix adds heredoc body, backslash continuation, non-first `;`/`&&`/pipe commands, command substitution, `eval`, and variable-execution indirection in addition to the six marker/comment evasions. Before the augmented implementation, primitive ownership, command substitution, `eval`, variable execution, and the preserved 14-site inventory all fail.

View File

@@ -48,6 +48,14 @@ class RuntimeLaunchGuardTest(unittest.TestCase):
"marker-argument.sh": 'exec claude --dangerously-skip-permissions "launch-runtime.py"\n',
"marker-echo.sh": 'exec claude --dangerously-skip-permissions "prompt"; echo launch-runtime.py\n',
"marker-variable.sh": 'marker=launch-runtime.py; exec claude --dangerously-skip-permissions "prompt"\n',
"heredoc.sh": "cat <<'EOF'\nexec claude --dangerously-skip-permissions prompt # launch-runtime.py\nEOF\n",
"continued.sh": "exec \\\n claude --dangerously-skip-permissions prompt # launch-runtime.py\n",
"chain-semicolon.sh": "true; claude -p prompt\n",
"chain-and.sh": "true && claude -p prompt\n",
"chain-pipe.sh": "printf input | claude -p prompt\n",
"command-substitution.sh": "output=$(claude -p prompt)\n",
"eval.sh": "launcher='claude -p prompt'\neval \"$launcher\"\n",
"variable-exec.sh": "launcher=claude\n\"$launcher\" -p prompt\n",
}
for filename, source in cases.items():
with self.subTest(filename=filename):
@@ -65,6 +73,14 @@ class RuntimeLaunchGuardTest(unittest.TestCase):
with self.subTest(filename=filename):
self.assertEqual(GUARD.scan_text(Path(filename), source), [])
def test_dangerous_primitive_is_owned_only_by_the_choke_point(self) -> None:
primitive = "--dangerously-skip-permissions"
self.assertNotEqual(GUARD.scan_text(Path("caller.ts"), f"args = ['{primitive}'];\n"), [])
self.assertEqual(
GUARD.scan_text(Path("framework/tools/lease-broker/launch-runtime.py"), f'FLAG = "{primitive}"\n'),
[],
)
def test_repository_has_no_ungated_consequential_runtime_launch(self) -> None:
violations = GUARD.scan_repository(REPO_ROOT)
self.assertEqual(
@@ -72,6 +88,9 @@ class RuntimeLaunchGuardTest(unittest.TestCase):
[],
"\n".join(GUARD.format_violation(violation) for violation in violations),
)
inventory = GUARD.inventory_repository(REPO_ROOT)
self.assertEqual(len(inventory), 14)
self.assertTrue(all(site.classification == "gated" for site in inventory))
def test_repository_walk_skips_tests_build_outputs_and_reports_unscannable_source(self) -> None:
with tempfile.TemporaryDirectory() as directory: