feat(mosaic): WI-2 mutator-class guard for directive-freshness (#837)
WI-2: mutator-class guard for the compaction directive-freshness mechanism — command-position parser (prefix x var-indirection unified) + primitive-anchored invariant backstop + all-tools-hook fail-close. Parser-complete on principle: realistic evasion matrix RED-regression-covered, residual exotic evasions proven backstop-caught (B-tests), lens-convergence reached. closes #829
This commit was merged in pull request #837.
This commit is contained in:
100
packages/mosaic/framework/tools/lease-broker/mutator-gate.py
Normal file
100
packages/mosaic/framework/tools/lease-broker/mutator-gate.py
Normal file
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Runtime-neutral whole mutator-class gate backed by the Mosaic lease broker."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import socket
|
||||
import sys
|
||||
from collections.abc import Callable, Mapping, Sequence
|
||||
from pathlib import Path
|
||||
from typing import BinaryIO, Final
|
||||
|
||||
MAX_FRAME: Final = 64 * 1024
|
||||
BROKER_TIMEOUT_SECONDS: Final = 1.5
|
||||
|
||||
|
||||
def deny(code: str) -> int:
|
||||
print(f"BLOCKED: Mosaic mutator gate denied this tool ({code}).", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
|
||||
def read_tool_name(stream: BinaryIO | None = None) -> str:
|
||||
source = sys.stdin.buffer if stream is None else stream
|
||||
raw = source.read(MAX_FRAME + 1)
|
||||
if len(raw) > MAX_FRAME:
|
||||
raise ValueError("INVALID_GATE_INPUT")
|
||||
value = json.loads(raw)
|
||||
if not isinstance(value, dict):
|
||||
raise ValueError("INVALID_GATE_INPUT")
|
||||
tool_name = value.get("tool_name")
|
||||
if not isinstance(tool_name, str) or not tool_name or len(tool_name) > 256:
|
||||
raise ValueError("INVALID_GATE_INPUT")
|
||||
return tool_name
|
||||
|
||||
|
||||
def broker_request(socket_path: Path, request: dict[str, object]) -> dict[str, object]:
|
||||
payload = (json.dumps(request, separators=(",", ":")) + "\n").encode()
|
||||
if len(payload) > MAX_FRAME:
|
||||
raise ValueError("INVALID_GATE_INPUT")
|
||||
response = bytearray()
|
||||
with socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) as connection:
|
||||
connection.settimeout(BROKER_TIMEOUT_SECONDS)
|
||||
connection.connect(str(socket_path))
|
||||
connection.sendall(payload)
|
||||
connection.shutdown(socket.SHUT_WR)
|
||||
while len(response) <= MAX_FRAME:
|
||||
chunk = connection.recv(min(4096, MAX_FRAME + 1 - len(response)))
|
||||
if not chunk:
|
||||
break
|
||||
response.extend(chunk)
|
||||
if len(response) > MAX_FRAME or not response.endswith(b"\n"):
|
||||
raise ValueError("INVALID_BROKER_REPLY")
|
||||
value = json.loads(response)
|
||||
if not isinstance(value, dict):
|
||||
raise ValueError("INVALID_BROKER_REPLY")
|
||||
return value
|
||||
|
||||
|
||||
def main(
|
||||
argv: Sequence[str] | None = None,
|
||||
*,
|
||||
environ: Mapping[str, str] | None = None,
|
||||
stream: BinaryIO | None = None,
|
||||
request: Callable[[Path, dict[str, object]], dict[str, object]] = broker_request,
|
||||
) -> int:
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("--runtime", required=True, choices=("claude", "pi"))
|
||||
arguments = parser.parse_args(argv)
|
||||
source_environment = os.environ if environ is None else environ
|
||||
|
||||
try:
|
||||
tool_name = read_tool_name(stream)
|
||||
socket_value = source_environment["MOSAIC_LEASE_BROKER_SOCKET"]
|
||||
session_id = source_environment["MOSAIC_LEASE_SESSION_ID"]
|
||||
generation = int(source_environment["MOSAIC_RUNTIME_GENERATION"])
|
||||
if generation < 0:
|
||||
raise ValueError("INVALID_GENERATION")
|
||||
reply = request(
|
||||
Path(socket_value),
|
||||
{
|
||||
"action": "authorize_tool",
|
||||
"session_id": session_id,
|
||||
"runtime_generation": generation,
|
||||
"runtime": arguments.runtime,
|
||||
"tool_name": tool_name,
|
||||
},
|
||||
)
|
||||
except (KeyError, ValueError, OSError, json.JSONDecodeError):
|
||||
return deny("GATE_UNAVAILABLE")
|
||||
|
||||
if reply.get("ok") is True and reply.get("decision") == "allow":
|
||||
return 0
|
||||
code = reply.get("code")
|
||||
return deny(code if isinstance(code, str) else "MUTATOR_UNVERIFIED")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user