c1263b2e69
- attachTerminalServer() upgrades /jobs/:id/terminal WS connections, verifying a short-lived job-scoped HMAC token (verifyTerminalToken) so the browser never holds the worker secret - Bridges the socket to a bash PTY via dockerode exec (Tty) in a persistent per-job shell container (spoon-agent-term-<id>) mounting the workspace; binary frames = stdin, JSON text frames = resize; idle containers reaped after 30m - New env: SPOON_AGENT_TERMINAL_IMAGE/SECRET/IDLE_MS (secret falls back to the shared worker internal token)
43 lines
1.5 KiB
TypeScript
43 lines
1.5 KiB
TypeScript
import { createHmac } from 'node:crypto';
|
|
import { describe, expect, test } from 'vitest';
|
|
|
|
import { verifyTerminalToken } from '../../src/terminal-token';
|
|
|
|
const mint = (jobId: string, expiresAt: number, secret: string) => {
|
|
const payload = `${expiresAt}.${jobId}`;
|
|
const sig = createHmac('sha256', secret).update(payload).digest('hex');
|
|
return `${payload}.${sig}`;
|
|
};
|
|
|
|
describe('verifyTerminalToken', () => {
|
|
const secret = 'test-secret';
|
|
|
|
test('accepts a valid, unexpired, job-matched token', () => {
|
|
const token = mint('job1', Date.now() + 60_000, secret);
|
|
expect(verifyTerminalToken(token, 'job1', secret)).toBe(true);
|
|
});
|
|
|
|
test('rejects an expired token', () => {
|
|
const token = mint('job1', Date.now() - 1, secret);
|
|
expect(verifyTerminalToken(token, 'job1', secret)).toBe(false);
|
|
});
|
|
|
|
test('rejects a token minted for another job', () => {
|
|
const token = mint('job1', Date.now() + 60_000, secret);
|
|
expect(verifyTerminalToken(token, 'job2', secret)).toBe(false);
|
|
});
|
|
|
|
test('rejects a token signed with a different secret', () => {
|
|
const token = mint('job1', Date.now() + 60_000, 'other-secret');
|
|
expect(verifyTerminalToken(token, 'job1', secret)).toBe(false);
|
|
});
|
|
|
|
test('rejects malformed input and an empty secret', () => {
|
|
expect(verifyTerminalToken('garbage', 'job1', secret)).toBe(false);
|
|
expect(verifyTerminalToken('', 'job1', secret)).toBe(false);
|
|
expect(
|
|
verifyTerminalToken(mint('job1', Date.now() + 1000, ''), 'job1', ''),
|
|
).toBe(false);
|
|
});
|
|
});
|