fix(#829): enforce repository-wide runtime launch choke point
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful

This commit is contained in:
ms-lead-reviewer
2026-07-17 23:39:46 -05:00
parent 7f3418fa8c
commit 1792b7934d
16 changed files with 446 additions and 17 deletions

View File

@@ -3,7 +3,7 @@
When spawning workers, include skill loading in the kickstart:
```bash
claude -p "Read ~/.config/mosaic/skills/nestjs-best-practices/SKILL.md then implement..."codex exec "Read ~/.config/mosaic/skills/nestjs-best-practices/SKILL.md then implement..."
mosaic claude -p "Read ~/.config/mosaic/skills/nestjs-best-practices/SKILL.md then implement..."codex exec "Read ~/.config/mosaic/skills/nestjs-best-practices/SKILL.md then implement..."
```
#### **MANDATORY**

View File

@@ -0,0 +1,217 @@
#!/usr/bin/env python3
"""Fail CI when production code launches Claude/Pi outside the lease gate."""
from __future__ import annotations
import argparse
import json
import re
import sys
from pathlib import Path
from typing import Final, NamedTuple, Sequence
SCANNED_ROOTS: Final = ("packages", "apps", "plugins", "tools")
SCANNED_SUFFIXES: Final = {
".bash",
".cjs",
".js",
".json",
".mjs",
".py",
".sh",
".ts",
".tsx",
".yaml",
".yml",
".zsh",
}
SKIPPED_DIRECTORIES: Final = {
".git",
".next",
".turbo",
"coverage",
"dist",
"node_modules",
}
# A launch line is gated only when it names the common wrapper, the TypeScript
# adapter that invokes that wrapper, or the `mosaic` runtime command that reaches
# the adapter. Merely mentioning a session ID or hook is not sufficient.
GATED_PATTERNS: Final = (
re.compile(r"\bexecLeaseGatedRuntime\s*\("),
re.compile(r"\blaunch-runtime\.(?:sh|py)\b"),
re.compile(
r"(?:\bexec\s+|\b(?:LAUNCH_COMMAND|launch_cmd)\s*=\s*\(?|\becho\s+[\"'])"
r"mosaic\s+(?:yolo\s+)?(?:claude|pi|claudex|[\"']?\$\{?runtime\}?[\"']?|[\"']?\$MOSAIC_AGENT_RUNTIME[\"']?)\b"
),
re.compile(r"\[\s*[\"']mosaic[\"']\s*,\s*(?:[\"']yolo[\"']\s*,\s*)?(?:runtime|[\"'](?:claude|pi|claudex)[\"'])"),
)
DIRECT_PATTERNS: Final = (
# Shell/process command forms, including here-doc command examples that an
# operator could execute verbatim.
re.compile(r"^\s*(?:claude|pi)(?:\s|$)"),
re.compile(r"(?:^|[;&|]\s*|\bexec\s+|\bcommand\s+)(?:claude|pi)\s+(?:-p\b|--dangerously\b|--print\b)"),
re.compile(r"\bexec\s+(?:claude|pi)(?:\s|$)"),
re.compile(r"\bexec\s+(?:/[^\s/]+)+/(?:claude|pi)(?:\s|$)"),
re.compile(r"\bexec\s+[\"']?\$(?:\{?runtime\}?|MOSAIC_AGENT_RUNTIME)\b"),
# JS/TS and Python process APIs with a literal runtime binary.
re.compile(
r"\b(?:spawn|spawnSync|exec|execSync|execFile|execFileSync|execv|execvp|execvpe|Popen|run|call|system|check_call|check_output)\s*\(\s*(?:\[\s*)?[\"'](?:claude|pi)(?:[\"']|\s)"
),
re.compile(
r"\b(?:spawn|spawnSync|exec|execSync|execFile|execFileSync|execv|execvp|execvpe|Popen|run|call|system|check_call|check_output)\s*\(\s*(?:\[\s*)?[\"'](?:/[^\"'/]+)+/(?:claude|pi)[\"']"
),
# Launch-command arrays and the prior @mosaicstack/coord dynamic default.
re.compile(r"\b(?:spawn|spawnSync|exec|execSync|execFile|execFileSync)\s*\(\s*runtime\b"),
re.compile(r"\b(?:command|launchCommand|LAUNCH_COMMAND)\s*=\s*(?:\(|\[)\s*[\"']?(?:claude|pi)\b"),
re.compile(r"\b(?:command|launchCommand|LAUNCH_COMMAND)\s*=\s*(?:\(|\[)\s*[\"']?\$(?:\{?runtime\}?|MOSAIC_AGENT_RUNTIME)\b"),
re.compile(r"\breturn\s*\[\s*runtime\s*,\s*[\"'](?:-p|--dangerously)"),
)
class LaunchSite(NamedTuple):
path: Path
line_number: int
line: str
classification: str
def is_test_path(path: Path) -> bool:
name = path.name.lower()
return (
"__tests__" in path.parts
or ".spec." in name
or ".test." in name
or name.endswith("_unittest.py")
or name.startswith("test-")
or name.startswith("test_")
)
def is_gated_line(line: str) -> bool:
return any(pattern.search(line) for pattern in GATED_PATTERNS)
def is_direct_line(line: str) -> bool:
return any(pattern.search(line) for pattern in DIRECT_PATTERNS)
def scan_text(path: Path, source: str) -> list[LaunchSite]:
violations: list[LaunchSite] = []
gated_continuation = False
for line_number, line in enumerate(source.splitlines(), start=1):
stripped = line.strip()
if not stripped or stripped.startswith(("#", "//", "*")):
gated_continuation = False
continue
gated = is_gated_line(line) or gated_continuation
if is_direct_line(line) and not gated:
violations.append(LaunchSite(path, line_number, line.rstrip(), "direct"))
gated_continuation = gated and line.rstrip().endswith("\\")
return violations
def source_files(root: Path):
for relative_root in SCANNED_ROOTS:
search_root = root / relative_root
if not search_root.is_dir():
continue
for path in search_root.rglob("*"):
if not path.is_file() or path.suffix.lower() not in SCANNED_SUFFIXES:
continue
if any(part in SKIPPED_DIRECTORIES for part in path.parts):
continue
if is_test_path(path):
continue
yield path
def scan_repository(root: Path) -> list[LaunchSite]:
violations: list[LaunchSite] = []
for path in source_files(root):
try:
source = path.read_text(encoding="utf-8")
except UnicodeDecodeError:
violations.append(LaunchSite(path, 0, "non-UTF-8 source", "unscannable"))
continue
violations.extend(scan_text(path.relative_to(root), source))
return violations
def inventory_repository(root: Path) -> list[LaunchSite]:
inventory: list[LaunchSite] = []
for path in source_files(root):
try:
lines = path.read_text(encoding="utf-8").splitlines()
except UnicodeDecodeError:
inventory.append(LaunchSite(path.relative_to(root), 0, "non-UTF-8 source", "unscannable"))
continue
gated_continuation = False
for line_number, line in enumerate(lines, start=1):
stripped = line.strip()
if not stripped or stripped.startswith(("#", "//", "*")):
gated_continuation = False
continue
line_is_gated = is_gated_line(line)
gated = line_is_gated or gated_continuation
if line_is_gated and not stripped.startswith("function execLeaseGatedRuntime"):
inventory.append(
LaunchSite(path.relative_to(root), line_number, line.rstrip(), "gated")
)
elif is_direct_line(line) and not gated:
inventory.append(
LaunchSite(path.relative_to(root), line_number, line.rstrip(), "direct")
)
gated_continuation = gated and line.rstrip().endswith("\\")
return inventory
def format_violation(violation: LaunchSite) -> str:
return f"{violation.path}:{violation.line_number}: {violation.classification}: {violation.line.strip()}"
def main(argv: Sequence[str] | None = None) -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--root", type=Path, default=Path.cwd())
parser.add_argument("--json", action="store_true")
arguments = parser.parse_args(argv)
root = arguments.root.resolve()
inventory = inventory_repository(root)
violations = [site for site in inventory if site.classification != "gated"]
if arguments.json:
print(
json.dumps(
{
"gated": sum(site.classification == "gated" for site in inventory),
"total": len(inventory),
"sites": [
{
"path": str(site.path),
"line": site.line_number,
"classification": site.classification,
"source": site.line.strip(),
}
for site in inventory
],
},
sort_keys=True,
)
)
else:
for site in inventory:
print(format_violation(site))
print(
f"runtime launch inventory: "
f"{len(inventory) - len(violations)} gated/{len(inventory)} total"
)
if violations:
print("ungated consequential runtime launch detected", file=sys.stderr)
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -32,7 +32,7 @@ Claude:
```json
{
"worker": {
"command_template": "claude -p \"Execute task {task_id}: {task_title}\""
"command_template": "mosaic claude -p \"Execute task {task_id}: {task_title}\""
}
}
```

View File

@@ -86,7 +86,8 @@ echo ""
cd "$PROJECT"
if [[ "$RUNTIME_CMD" == "claude" ]]; then
exec claude --dangerously-skip-permissions --append-system-prompt "$SYSTEM_PROMPT" "$KICKOFF"
exec python3 "$SCRIPT_DIR/../lease-broker/launch-runtime.py" --runtime claude -- \
claude --dangerously-skip-permissions --append-system-prompt "$SYSTEM_PROMPT" "$KICKOFF"
fi
if [[ "$RUNTIME_CMD" == "codex" ]]; then

View File

@@ -74,7 +74,8 @@ echo ""
cd "$PROJECT"
if [[ "$RUNTIME_CMD" == "claude" ]]; then
exec claude --dangerously-skip-permissions --append-system-prompt "$SYSTEM_PROMPT" "$KICKOFF"
exec python3 "$SCRIPT_DIR/../lease-broker/launch-runtime.py" --runtime claude -- \
claude --dangerously-skip-permissions --append-system-prompt "$SYSTEM_PROMPT" "$KICKOFF"
fi
if [[ "$RUNTIME_CMD" == "codex" ]]; then

View File

@@ -190,7 +190,7 @@ Pending QA validation
This report was created by the QA automation hook.
To process this report, run:
\`\`\`bash
claude -p "Use Task tool to launch universal-qa-agent for report: $REPORT_PATH"
python3 ~/.config/mosaic/tools/lease-broker/launch-runtime.py --runtime claude -- claude -p "Use Task tool to launch universal-qa-agent for report: $REPORT_PATH"
\`\`\`
EOF

View File

@@ -58,8 +58,8 @@ ACTIONS_PATH="$IN_PROGRESS_DIR/$ACTIONS_FILE"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Starting remediation: $ACTIONS_PATH" | tee -a "$LOG_FILE"
# Trigger remediation agent
claude -p "Use Task tool to launch auto-remediation-agent for:
# Trigger remediation agent through the authenticated lease-broker choke-point.
python3 "$(dirname "$0")/../lease-broker/launch-runtime.py" --runtime claude -- claude -p "Use Task tool to launch auto-remediation-agent for:
- Remediation Report: $IN_PROGRESS_DIR/$(basename "$REPORT_FILE")
- Actions File: $ACTIONS_PATH
- Max Iterations: 5