test(#830): bound promote lost-ack residual
All checks were successful
ci/woodpecker/pr/ci Pipeline was successful

This commit is contained in:
ms-lead-reviewer
2026-07-18 02:45:34 -05:00
parent 5e5b971d8a
commit f400830738
2 changed files with 70 additions and 0 deletions

View File

@@ -450,6 +450,66 @@ describe('whole mutator-class lease gate', () => {
});
});
test('promote-lease-lost-ACK orphaned VERIFIED lease is caught by observer revoke and by monotonic TTL expiry (D2-v5 backstop)', async () => {
const { socket } = await startBroker();
const observerSessionId = await register(socket);
const observerPending = await beginVerification(socket, observerSessionId, 'claude');
await promote(socket, observerSessionId, observerPending.promotion_token!);
expect(await authorize(socket, observerSessionId, 'claude', 'Bash')).toMatchObject({
ok: true,
decision: 'allow',
state: 'VERIFIED',
});
const retriedPromotion = await promote(
socket,
observerSessionId,
observerPending.promotion_token!,
);
expect(retriedPromotion.ok).toBe(false);
expect(['PROMOTION_TOKEN_MISMATCH', 'INVALID_LEASE_TRANSITION']).toContain(
retriedPromotion.code,
);
const revoked = spawnSync(
'python3',
[revokerPath, '--runtime', 'claude', '--reason', 'session-start-compact'],
{
encoding: 'utf8',
env: {
...process.env,
MOSAIC_LEASE_BROKER_SOCKET: socket,
MOSAIC_LEASE_SESSION_ID: observerSessionId,
MOSAIC_RUNTIME_GENERATION: '1',
},
},
);
expect(revoked.status, revoked.stderr).toBe(0);
expect(await authorize(socket, observerSessionId, 'claude', 'Write')).toMatchObject({
ok: false,
code: 'MUTATOR_UNVERIFIED',
decision: 'deny',
});
const { socket: expirySocket } = await startBroker();
const expirySessionId = await register(expirySocket);
expect(expirySessionId).not.toBe(observerSessionId);
const expiryPending = await beginVerification(expirySocket, expirySessionId, 'claude', 1, 1);
await promote(expirySocket, expirySessionId, expiryPending.promotion_token!);
expect(await authorize(expirySocket, expirySessionId, 'claude', 'Bash')).toMatchObject({
ok: true,
decision: 'allow',
state: 'VERIFIED',
});
await new Promise((resolve) => setTimeout(resolve, 1_100));
expect(await authorize(expirySocket, expirySessionId, 'claude', 'Bash')).toMatchObject({
ok: false,
code: 'LEASE_EXPIRED',
decision: 'deny',
});
});
test('a fired observer fences the old lease even while broker transport is unavailable', async () => {
const { socket } = await startBroker();
const sessionId = await register(socket);