test(#829): bind runtime launch to broker identity
This commit is contained in:
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user