blob: 3a71c43e52dbfa01aa9ddf2b5d561f1e1150757a [file]
import assert from 'node:assert/strict';
import { describe, test } from 'node:test';
import { SHELL_RUN_SOURCE_TOOL_CALL_ID_MAX_BYTES } from '@maka/core/shell-run';
import { type ShellRunSnapshotResult, type ShellRunUpdate } from '@maka/core/events';
import { RuntimeHostProtocolError } from '../protocol/errors.js';
import {
decodeSubscriptionFrame,
SESSION_RUNTIME_RESOURCE_CHANGES_MAX,
} from '../protocol/session-continuity.js';
import {
decodeRuntimeResourceControllerControlInput,
decodeRuntimeResourceQueryInput,
decodeRuntimeResourceQueryResult,
decodeRuntimeResourceStopResult,
RUNTIME_RESOURCE_CONTROL_INPUT_MAX_BYTES,
RUNTIME_RESOURCE_MAX_CONTROL_SEQUENCE,
RUNTIME_RESOURCE_CURSOR_MAX_BYTES,
RUNTIME_RESOURCE_PAGE_MAX_ITEMS,
RUNTIME_RESOURCE_RESULT_MAX_BYTES,
} from '../protocol/runtime-resource.js';
const revision = `sha256:${'a'.repeat(64)}` as const;
const runtimeRef = 'maka://runtime/background-tasks/shell-1';
type PipeShellSnapshot = Extract<ShellRunSnapshotResult, { mode: 'pipes' }>;
describe('Runtime Resource protocol', () => {
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));
});
});
test('Runtime Resource invalidations batch lightweight unique identities', () => {
const resources = Array.from({ length: SESSION_RUNTIME_RESOURCE_CHANGES_MAX }, (_, index) => ({
sourceSessionId: 'source-session',
ref: `maka://runtime/background-tasks/shell-${index}`,
}));
assert.deepEqual(
decodeSubscriptionFrame({
kind: 'subscription.session_domain_changed',
hostEpoch: 'host-1',
subscriptionId: 'subscription-1',
sequence: 1,
sessionId: 'child-session',
domain: 'runtime_resource',
resources,
}),
{
kind: 'subscription.session_domain_changed',
hostEpoch: 'host-1',
subscriptionId: 'subscription-1',
sequence: 1,
sessionId: 'child-session',
domain: 'runtime_resource',
resources,
},
);
assertInvalid(() =>
decodeSubscriptionFrame({
kind: 'subscription.session_domain_changed',
hostEpoch: 'host-1',
subscriptionId: 'subscription-1',
sequence: 1,
sessionId: 'child-session',
domain: 'runtime_resource',
resources: [resources[0], resources[0]],
}),
);
});
test('Runtime Resource PTY data remains an ordered Session subscription frame', () => {
const frame = {
kind: 'subscription.runtime_resource_pty_data' as const,
hostEpoch: 'host-1',
subscriptionId: 'subscription-1',
sequence: 4,
sessionId: 'session-1',
ref: runtimeRef,
ptySequence: 9,
data: '\u001b[2Jready',
};
assert.deepEqual(decodeSubscriptionFrame(frame), frame);
assertInvalid(() => decodeSubscriptionFrame({ ...frame, ptySequence: 0 }));
});
function resourceUpdate(overrides: Partial<ShellRunUpdate> = {}): ShellRunUpdate {
return {
sessionId: 'session-1',
ownership: { kind: 'local' },
sourceTurnId: 'turn-1',
sourceToolCallId: 'call.1/part',
result: snapshot(),
...overrides,
};
}
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',
);
}