feat(#829): enforce whole mutator-class lease gate
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful

This commit is contained in:
ms-lead-reviewer
2026-07-17 22:35:18 -05:00
parent 439f5f4bc9
commit 77b137ccc0
12 changed files with 476 additions and 19 deletions

View File

@@ -115,7 +115,7 @@ function auditClaudeSettings(): SettingsAudit {
// Check required hooks
const hooks = settings['hooks'] as Record<string, unknown[]> | undefined;
const requiredPreToolUse = ['prevent-memory-write.sh'];
const requiredPreToolUse = ['mutator-gate.py', 'prevent-memory-write.sh'];
const requiredPostToolUse = ['qa-hook-stdin.sh', 'typecheck-hook.sh'];
const preHooks = (hooks?.['PreToolUse'] ?? []) as Array<Record<string, unknown>>;
@@ -763,7 +763,7 @@ function launchRuntime(runtime: RuntimeName, args: string[], yolo: boolean): nev
cliArgs.push(...args);
}
console.log(`[mosaic] Launching ${label}${modeStr}${missionStr}...`);
execRuntime('claude', cliArgs);
execLeaseGatedRuntime('claude', cliArgs);
break;
}
@@ -798,7 +798,7 @@ function launchRuntime(runtime: RuntimeName, args: string[], yolo: boolean): nev
cliArgs.push(...args);
}
console.log(`[mosaic] Launching ${label}${modeStr}${missionStr}...`);
execRuntime('pi', cliArgs);
execLeaseGatedRuntime('pi', cliArgs);
break;
}
}
@@ -806,6 +806,23 @@ function launchRuntime(runtime: RuntimeName, args: string[], yolo: boolean): nev
process.exit(0); // Unreachable but satisfies never
}
function defaultLeaseBrokerSocket(env: NodeJS.ProcessEnv = process.env): string {
if (env['MOSAIC_LEASE_BROKER_SOCKET']) return env['MOSAIC_LEASE_BROKER_SOCKET'];
const runtimeDir = env['XDG_RUNTIME_DIR'];
if (runtimeDir) return join(runtimeDir, 'mosaic-lease', 'broker.sock');
const uid = typeof process.getuid === 'function' ? process.getuid() : 0;
return join('/run/user', String(uid), 'mosaic-lease', 'broker.sock');
}
function execLeaseGatedRuntime(runtime: 'claude' | 'pi', args: string[]): void {
const launcher = resolveTool('lease-broker', 'launch-runtime.py');
execRuntime('python3', [launcher, '--runtime', runtime, '--', runtime, ...args], {
...process.env,
MOSAIC_LEASE_BROKER_SOCKET: defaultLeaseBrokerSocket(),
MOSAIC_RUNTIME_GENERATION: process.env['MOSAIC_RUNTIME_GENERATION'] ?? '1',
});
}
/** exec into the runtime, replacing the current process. */
function execRuntime(cmd: string, args: string[], env: NodeJS.ProcessEnv = process.env): void {
try {