blob: 76e8e16aa08b2d8f5d1dd5aa81818d7771017c05 [file]
import assert from 'node:assert/strict';
import { describe, test } from 'node:test';
import {
SHELL_RUN_SOURCE_TOOL_CALL_ID_MAX_BYTES,
type ShellRunSnapshotResult,
type ShellRunUpdate,
} from '@maka/core';
import { RuntimeHostProtocolError } from '../protocol/errors.js';
import {
decodeRuntimeResourceControllerAcquireInput,
decodeRuntimeResourceControllerAcquireResult,
decodeRuntimeResourceControllerControlInput,
decodeRuntimeResourceControllerControlResult,
decodeRuntimeResourceControllerReleaseInput,
decodeRuntimeResourceControllerReleaseResult,
decodeRuntimeResourceQueryInput,
decodeRuntimeResourceQueryResult,
decodeRuntimeResourceStopInput,
decodeRuntimeResourceStopResult,
RUNTIME_RESOURCE_CONTROL_INPUT_MAX_BYTES,
RUNTIME_RESOURCE_MAX_CONTROL_SEQUENCE,
RUNTIME_RESOURCE_CURSOR_MAX_BYTES,
RUNTIME_RESOURCE_OPERATION_SPECS,
RUNTIME_RESOURCE_PAGE_MAX_ITEMS,
RUNTIME_RESOURCE_RESULT_MAX_BYTES,
} from '../protocol/runtime-resource.js';
const revision = `sha256:${'a'.repeat(64)}` as const;
const nextRevision = `sha256:${'b'.repeat(64)}` as const;
const runtimeRef = 'maka://runtime/background-tasks/shell-1';
type PipeShellSnapshot = Extract<ShellRunSnapshotResult, { mode: 'pipes' }>;
describe('Runtime Resource protocol', () => {
test('declares the complete ready operation surface', () => {
assert.deepEqual(Object.keys(RUNTIME_RESOURCE_OPERATION_SPECS), [
'runtime.resource.query',
'runtime.resource.controller.acquire',
'runtime.resource.controller.control',
'runtime.resource.controller.release',
'runtime.resource.stop',
]);
assert.equal(RUNTIME_RESOURCE_OPERATION_SPECS['runtime.resource.query'].mode, 'query');
for (const [key, spec] of Object.entries(RUNTIME_RESOURCE_OPERATION_SPECS)) {
assert.equal(spec.availability, 'ready', key);
if (key !== 'runtime.resource.query') assert.equal(spec.mode, 'control', key);
}
});
test('round-trips every query, controller, and stop branch', () => {
const update = resourceUpdate();
const unavailable = resourceUpdate({
ownership: { kind: 'source_unavailable', sourceSessionId: 'source-session' },
result: compactState(),
});
for (const input of [
{ kind: 'list_start', sessionId: 'session-1' },
{ kind: 'list_continue', sessionId: 'session-1', revision, cursor: '2' },
{ kind: 'get', sessionId: 'session-1', ref: runtimeRef },
] as const) {
assert.deepEqual(decodeRuntimeResourceQueryInput(input), input);
}
for (const result of [
{
kind: 'page',
sessionId: 'session-1',
revision,
resources: [update, unavailable],
nextCursor: '1',
},
{ kind: 'revision_changed', expected: revision, actual: nextRevision },
{ kind: 'resource', sessionId: 'session-1', revision, resource: update },
{ kind: 'resource', sessionId: 'session-1', revision, resource: null },
] as const) {
assert.deepEqual(decodeRuntimeResourceQueryResult(result), result);
}
const identity = { sessionId: 'session-1', ref: runtimeRef, controllerId: 'client-1' };
assert.deepEqual(decodeRuntimeResourceControllerAcquireInput(identity), identity);
assert.deepEqual(decodeRuntimeResourceControllerReleaseInput(identity), identity);
assert.deepEqual(
decodeRuntimeResourceControllerAcquireResult({
controllerId: 'client-1',
nextSequence: 1,
resource: snapshot(),
}),
{ controllerId: 'client-1', nextSequence: 1, resource: snapshot() },
);
for (const control of [
{ kind: 'input', input: 'hello' },
{ kind: 'resize', cols: 80, rows: 24 },
{ kind: 'input_and_resize', input: 'hello', cols: 80, rows: 24 },
] as const) {
const input = { ...identity, sequence: 1, control };
assert.deepEqual(decodeRuntimeResourceControllerControlInput(input), input);
}
const controlled = { controllerId: 'client-1', sequence: 1, resource: snapshot() };
assert.deepEqual(decodeRuntimeResourceControllerControlResult(controlled), controlled);
assert.deepEqual(
decodeRuntimeResourceControllerReleaseResult({ controllerId: 'client-1', released: true }),
{ controllerId: 'client-1', released: true },
);
assert.deepEqual(decodeRuntimeResourceStopInput({ sessionId: 'session-1', ref: runtimeRef }), {
sessionId: 'session-1',
ref: runtimeRef,
});
assert.deepEqual(decodeRuntimeResourceStopResult({ resource: snapshot() }), {
resource: snapshot(),
});
});
test('rejects unknown fields and non-canonical snapshots', () => {
assertInvalid(() =>
decodeRuntimeResourceQueryInput({
kind: 'get',
sessionId: 'session-1',
ref: runtimeRef,
rawPath: '/private/shell-run.json',
}),
);
assertInvalid(() =>
decodeRuntimeResourceControllerControlInput({
sessionId: 'session-1',
ref: runtimeRef,
controllerId: 'client-1',
sequence: 1,
control: { kind: 'resize', cols: 80, rows: 24, force: true },
}),
);
for (const invalid of [
{ ...snapshot(), output: undefined },
{ ...snapshot(), operation: { kind: 'stop', applied: true } },
{ ...snapshot(), privatePid: 42 },
]) {
assertInvalid(() => decodeRuntimeResourceStopResult({ resource: invalid }));
}
});
test('enforces cursor, sequence, PTY control, item, and encoded result bounds', () => {
const maximumToolCallId = '😀'.repeat(SHELL_RUN_SOURCE_TOOL_CALL_ID_MAX_BYTES / 4);
assert.equal(
Buffer.byteLength(maximumToolCallId, 'utf8'),
SHELL_RUN_SOURCE_TOOL_CALL_ID_MAX_BYTES,
);
const maximumIdentity = {
kind: 'resource' as const,
sessionId: 'session-1',
revision,
resource: resourceUpdate({ sourceToolCallId: maximumToolCallId }),
};
const decodedMaximumIdentity = decodeRuntimeResourceQueryResult(maximumIdentity);
assert.equal(
decodedMaximumIdentity.kind === 'resource'
? decodedMaximumIdentity.resource?.sourceToolCallId
: undefined,
maximumToolCallId,
);
assertInvalid(() =>
decodeRuntimeResourceQueryResult({
...maximumIdentity,
resource: resourceUpdate({ sourceToolCallId: `${maximumToolCallId}x` }),
}),
);
for (const cursor of ['', '界'.repeat(Math.floor(RUNTIME_RESOURCE_CURSOR_MAX_BYTES / 3) + 1)]) {
assertInvalid(() =>
decodeRuntimeResourceQueryInput({
kind: 'list_continue',
sessionId: 'session-1',
revision,
cursor,
}),
);
}
for (const sequence of [0, -1, Number.MAX_SAFE_INTEGER + 1]) {
assertInvalid(() =>
decodeRuntimeResourceControllerControlInput({
sessionId: 'session-1',
ref: runtimeRef,
controllerId: 'client-1',
sequence,
control: { kind: 'input', input: 'x' },
}),
);
}
assertInvalid(() =>
decodeRuntimeResourceControllerControlInput({
sessionId: 'session-1',
ref: runtimeRef,
controllerId: 'client-1',
sequence: RUNTIME_RESOURCE_MAX_CONTROL_SEQUENCE + 1,
control: { kind: 'input', input: 'x' },
}),
);
for (const control of [
{ kind: 'input', input: '' },
{
kind: 'input',
input: '界'.repeat(Math.floor(RUNTIME_RESOURCE_CONTROL_INPUT_MAX_BYTES / 3) + 1),
},
{ kind: 'resize', cols: 1, rows: 24 },
{ kind: 'resize', cols: 80, rows: 101 },
]) {
assertInvalid(() =>
decodeRuntimeResourceControllerControlInput({
sessionId: 'session-1',
ref: runtimeRef,
controllerId: 'client-1',
sequence: 1,
control,
}),
);
}
const tooMany = Array.from({ length: RUNTIME_RESOURCE_PAGE_MAX_ITEMS + 1 }, resourceUpdate);
assertInvalid(() =>
decodeRuntimeResourceQueryResult({
kind: 'page',
sessionId: 'session-1',
revision,
resources: tooMany,
nextCursor: null,
}),
);
const oversized = {
resource: snapshot({
output: pipeOutput('x'.repeat(RUNTIME_RESOURCE_RESULT_MAX_BYTES)),
}),
};
assert.ok(
Buffer.byteLength(JSON.stringify(oversized), 'utf8') > RUNTIME_RESOURCE_RESULT_MAX_BYTES,
);
assertInvalid(() => decodeRuntimeResourceStopResult(oversized));
});
});
function resourceUpdate(overrides: Partial<ShellRunUpdate> = {}): ShellRunUpdate {
return {
sessionId: 'session-1',
ownership: { kind: 'local' },
sourceTurnId: 'turn-1',
sourceToolCallId: 'call.1/part',
result: snapshot(),
...overrides,
};
}
function compactState(): ShellRunUpdate['result'] {
const { output: _output, ...compact } = snapshot();
return compact;
}
function snapshot(overrides: Partial<PipeShellSnapshot> = {}): PipeShellSnapshot {
return {
kind: 'shell_run',
ref: runtimeRef,
mode: 'pipes',
status: 'running',
cwd: '/workspace',
cmd: 'printf done',
startedAt: 1,
updatedAt: 1,
revision: 1,
output: pipeOutput(''),
...overrides,
};
}
function pipeOutput(stdout: string): PipeShellSnapshot['output'] {
return {
mode: 'pipes',
stdout,
stderr: '',
stdoutTruncated: false,
stderrTruncated: false,
redacted: false,
};
}
function assertInvalid(action: () => unknown): void {
assert.throws(
action,
(error: unknown) => error instanceof RuntimeHostProtocolError && error.code === 'invalid_frame',
);
}