test(#829): bind runtime launch to broker identity

This commit is contained in:
ms-lead-reviewer
2026-07-17 22:28:11 -05:00
parent 74fc62e4ee
commit 439f5f4bc9

View File

@@ -22,6 +22,7 @@ interface BrokerPaths {
const frameworkRoot = new URL('../../framework/', import.meta.url).pathname; const frameworkRoot = new URL('../../framework/', import.meta.url).pathname;
const daemonPath = join(frameworkRoot, 'tools/lease-broker/daemon.py'); const daemonPath = join(frameworkRoot, 'tools/lease-broker/daemon.py');
const gatePath = join(frameworkRoot, 'tools/lease-broker/mutator-gate.py'); const gatePath = join(frameworkRoot, 'tools/lease-broker/mutator-gate.py');
const launcherPath = join(frameworkRoot, 'tools/lease-broker/launch-runtime.py');
const claudeSettingsPath = join(frameworkRoot, 'runtime/claude/settings.json'); const claudeSettingsPath = join(frameworkRoot, 'runtime/claude/settings.json');
const piExtensionPath = join(frameworkRoot, 'runtime/pi/mosaic-extension.ts'); const piExtensionPath = join(frameworkRoot, 'runtime/pi/mosaic-extension.ts');
const children: ChildProcess[] = []; const children: ChildProcess[] = [];
@@ -288,6 +289,51 @@ describe('whole mutator-class lease gate', () => {
}); });
}); });
test('runtime launcher anchors broker identity before exec and fails closed without broker', async () => {
const { socket } = await startBroker();
const probe = [
'import json,os,socket',
's=socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)',
"s.connect(os.environ['MOSAIC_LEASE_BROKER_SOCKET'])",
"request={'action':'authorize_tool','session_id':os.environ['MOSAIC_LEASE_SESSION_ID'],'runtime_generation':int(os.environ['MOSAIC_RUNTIME_GENERATION']),'runtime':'claude','tool_name':'Read'}",
"s.sendall((json.dumps(request)+'\\n').encode())",
's.shutdown(socket.SHUT_WR)',
"print(json.dumps({'session_id':os.environ['MOSAIC_LEASE_SESSION_ID'],'reply':json.loads(s.recv(65536))}))",
].join(';');
const launched = spawnSync(
'python3',
[launcherPath, '--runtime', 'claude', '--', 'python3', '-c', probe],
{
encoding: 'utf8',
env: {
...process.env,
MOSAIC_LEASE_BROKER_SOCKET: socket,
MOSAIC_RUNTIME_GENERATION: '1',
},
},
);
expect(launched.status, launched.stderr).toBe(0);
expect(JSON.parse(launched.stdout)).toMatchObject({
session_id: expect.stringMatching(/^[a-f0-9]{64}$/),
reply: { ok: true, decision: 'allow' },
});
const unavailable = spawnSync(
'python3',
[launcherPath, '--runtime', 'claude', '--', 'python3', '-c', "print('EXECUTED')"],
{
encoding: 'utf8',
env: {
...process.env,
MOSAIC_LEASE_BROKER_SOCKET: join(tmpdir(), 'missing-mosaic-broker.sock'),
MOSAIC_RUNTIME_GENERATION: '1',
},
},
);
expect(unavailable.status).not.toBe(0);
expect(unavailable.stdout).not.toContain('EXECUTED');
});
test('Claude and Pi runtime adapters consult the broker for every tool class', async () => { test('Claude and Pi runtime adapters consult the broker for every tool class', async () => {
const { socket } = await startBroker(); const { socket } = await startBroker();
const sessionId = await register(socket); const sessionId = await register(socket);