Files
memind/services/orchestrator/executor-gateway.test.mjs
john 6df82818c5 feat(orchestrator): harden zero-impact shadow rollout
Gate and bound Portal shadow observations while preserving Native execution. Add fail-closed service boundaries, terminal retention controls, Canary readiness telemetry, ops visibility, and isolated regression coverage.
2026-07-25 07:28:37 +08:00

240 lines
8.7 KiB
JavaScript

import assert from 'node:assert/strict';
import test from 'node:test';
import {
buildExecutorJobEvent,
createExecutorAdapterRegistry,
createExecutorGateway,
createInMemoryExecutorJobStore,
createPhase3ExecutorAdapterRegistry,
createPhase5ExecutorAdapterRegistry,
normalizeExecutorJobRequest,
} from './executor-gateway.mjs';
function request(overrides = {}) {
return {
jobId: 'job-1',
idempotencyKey: 'run-1:node-execute:attempt-1',
executor: 'aider',
task: {
type: 'code_change',
instruction: 'Fix the login form validation',
workspaceRef: { kind: 'mindspace-workspace', id: 'workspace-1' },
},
subject: { userId: 'user-1' },
authorization: { executionAllowed: true, actorId: 'user-1' },
policy: { sideEffectsAllowed: true, networkAllowed: false },
controls: {
timeoutMs: 20_000,
cancellationAllowed: true,
fallbackExecutor: 'goosed',
},
...overrides,
};
}
test('executor job contract uses resource references and bounded controls', () => {
const normalized = normalizeExecutorJobRequest(request({
task: {
instruction: 'x'.repeat(40_000),
workspaceRef: { kind: 'workspace', id: 'workspace-1' },
inputRefs: [
{ kind: 'artifact', id: 'artifact-1' },
{ kind: '', id: 'invalid' },
],
},
controls: { timeoutMs: 100, fallbackExecutor: 'openhands' },
}));
assert.equal(normalized.version, 'executor-job-request-v1');
assert.equal(normalized.task.instruction.length, 32_000);
assert.deepEqual(normalized.task.workspaceRef, { kind: 'workspace', id: 'workspace-1' });
assert.deepEqual(normalized.task.inputRefs, [{ kind: 'artifact', id: 'artifact-1' }]);
assert.equal(normalized.controls.timeoutMs, 500);
assert.equal(normalized.controls.fallbackExecutor, 'openhands');
assert.equal('cwd' in normalized.task, false);
assert.throws(
() => normalizeExecutorJobRequest(request({ jobId: '../unsafe' })),
(error) => error.code === 'EXECUTOR_JOB_ID_INVALID',
);
const event = buildExecutorJobEvent({
eventId: 'event-1',
jobId: 'job-1',
sequence: 1,
type: 'executor_job_blocked',
timestamp: 1234,
data: { status: 'blocked' },
});
assert.equal(event.version, 'executor-job-event-v1');
assert.equal(event.sequence, 1);
assert.deepEqual(event.data, { status: 'blocked' });
});
test('Phase 3 executor catalog exposes disabled Goosed, Aider and OpenHands adapters', () => {
const registry = createPhase3ExecutorAdapterRegistry();
assert.deepEqual(
registry.list().map((adapter) => adapter.id),
['goosed', 'aider', 'openhands'],
);
for (const adapter of registry.list()) {
assert.equal(adapter.enabled, false);
assert.equal(adapter.dispatchImplemented, false);
assert.equal(adapter.status, 'contract-only');
}
});
test('executor adapter registry rejects incomplete and duplicate adapters', () => {
const registry = createExecutorAdapterRegistry();
assert.throws(() => registry.register({ id: 'broken' }), /missing method/);
const adapter = {
id: 'custom',
submit() {},
cancel() {},
getState() {},
async *streamEvents() {},
};
registry.register(adapter);
assert.throws(() => registry.register(adapter), /already registered/);
});
test('Executor Gateway records a blocked idempotent job without calling an adapter', async () => {
let now = 1000;
const gateway = createExecutorGateway({
store: createInMemoryExecutorJobStore(),
nowMs: () => now,
});
const preview = await gateway.preview(request());
assert.equal(preview.executor, 'aider');
assert.equal(preview.fallbackExecutor, 'goosed');
assert.equal(preview.fallbackRegistered, true);
assert.equal(preview.fallbackAvailable, false);
assert.equal(preview.dispatchAllowed, false);
assert.equal(preview.gates.implementation, true);
assert.equal(preview.gates.serviceEnabled, false);
assert.equal(preview.gates.adapterEnabled, false);
const first = await gateway.createJob(request());
assert.equal(first.created, true);
assert.equal(first.job.status, 'blocked');
assert.equal(first.job.attempts, 0);
assert.equal(first.job.reason, 'executor_execution_disabled');
now = 2000;
const repeated = await gateway.createJob(request());
assert.equal(repeated.created, false);
assert.equal(repeated.job.jobId, first.job.jobId);
assert.equal(repeated.job.createdAt, 1000);
const eventPage = await gateway.listEvents('job-1');
assert.deepEqual(eventPage.events.map((event) => event.type), ['executor_job_blocked']);
assert.equal(eventPage.nextCursor, 1);
});
test('Executor Gateway rejects idempotency key reuse with a different payload', async () => {
const gateway = createExecutorGateway();
await gateway.createJob(request());
await assert.rejects(
() => gateway.createJob(request({
jobId: 'job-2',
task: {
type: 'code_change',
instruction: 'A different instruction',
workspaceRef: { kind: 'mindspace-workspace', id: 'workspace-1' },
},
})),
(error) => error.code === 'EXECUTOR_IDEMPOTENCY_CONFLICT',
);
});
test('Executor Gateway cancellation is idempotent and never invokes a disabled adapter', async () => {
let now = 1000;
const gateway = createExecutorGateway({ nowMs: () => now });
await gateway.createJob(request());
now = 1500;
const cancelled = await gateway.cancel('job-1', { reason: 'user_cancelled' });
assert.equal(cancelled.status, 'cancelled');
assert.equal(cancelled.reason, 'user_cancelled');
assert.equal(cancelled.completedAt, 1500);
assert.deepEqual(await gateway.cancel('job-1'), cancelled);
assert.equal(await gateway.cancel('missing-job'), null);
const eventPage = await gateway.listEvents('job-1', { after: 1 });
assert.deepEqual(eventPage.events.map((event) => event.type), ['executor_job_cancelled']);
assert.equal(eventPage.events[0].sequence, 2);
assert.equal(eventPage.nextCursor, 2);
assert.equal(await gateway.listEvents('missing-job'), null);
});
test('Executor Gateway deletes only terminal jobs and their private request state', async () => {
const gateway = createExecutorGateway();
await gateway.createJob(request());
assert.equal(await gateway.deleteJob('job-1'), true);
assert.equal(await gateway.getJob('job-1'), null);
assert.equal(await gateway.listEvents('job-1'), null);
assert.equal(await gateway.deleteJob('job-1'), false);
const activeGateway = createExecutorGateway({
registry: createPhase5ExecutorAdapterRegistry({ enabledExecutors: ['aider'] }),
executionEnabled: true,
});
await activeGateway.createJob(request());
await assert.rejects(
() => activeGateway.deleteJob('job-1'),
(error) => error.code === 'EXECUTOR_JOB_NOT_TERMINAL' && error.status === 409,
);
});
test('Executor Gateway exposes only terminal workflow-linked retention candidates', async () => {
let now = 1000;
const gateway = createExecutorGateway({ nowMs: () => now });
await gateway.createJob(request({
metadata: { workflowRunId: 'run-retention-1' },
}));
assert.deepEqual(
await gateway.listRetentionCandidates({ before: 999 }),
[],
);
assert.deepEqual(
await gateway.listRetentionCandidates({ before: 1000 }),
[{
jobId: 'job-1',
workflowRunId: 'run-retention-1',
completedAt: 1000,
}],
);
now = 2000;
await gateway.createJob(request({
jobId: 'job-without-link',
idempotencyKey: 'without-link',
metadata: {},
}));
assert.equal((await gateway.listRetentionCandidates({ before: 3000 })).length, 1);
});
test('Executor Gateway reports implemented capability while execution remains disabled', () => {
const status = createExecutorGateway().status();
assert.equal(status.version, 'executor-gateway-status-v1');
assert.equal(status.dispatchImplemented, true);
assert.equal(status.executionEnabled, false);
assert.deepEqual(status.store, { kind: 'memory', durable: false });
});
test('Executor Gateway queues only explicitly enabled and authorized worker jobs', async () => {
const gateway = createExecutorGateway({
registry: createPhase5ExecutorAdapterRegistry({ enabledExecutors: ['aider'] }),
executionEnabled: true,
});
const created = await gateway.createJob(request());
assert.equal(created.job.status, 'queued');
assert.equal(created.job.reason, 'queued_for_worker');
assert.equal(created.job.dispatchAllowed, true);
assert.equal(created.job.maxAttempts, 3);
assert.equal(created.job.request.task.instruction, 'Fix the login form validation');
const projected = await gateway.getJob('job-1');
assert.equal('request' in projected, false);
assert.equal('requestFingerprint' in projected, false);
assert.deepEqual(
(await gateway.listEvents('job-1')).events.map((event) => event.type),
['executor_job_queued'],
);
});