feat: harden orchestrator execution runtime
This commit is contained in:
@@ -125,3 +125,96 @@ test('orchestrator HTTP API reports missing runs and observe-only violations', a
|
||||
assert.equal(rejected.status, 422);
|
||||
assert.equal((await rejected.json()).error.code, 'WORKFLOW_OBSERVE_ONLY_REQUIRED');
|
||||
});
|
||||
|
||||
test('executor worker HTTP protocol requires both service and worker credentials', async (t) => {
|
||||
const runtime = createLangGraphOrchestratorRuntime({
|
||||
checkpointer: new MemorySaver(),
|
||||
executionEnabled: true,
|
||||
enabledExecutors: ['goosed'],
|
||||
});
|
||||
const server = await listen(createOrchestratorApp({
|
||||
runtime,
|
||||
serviceToken: 'service-token',
|
||||
workerToken: 'worker-token',
|
||||
}));
|
||||
t.after(server.close);
|
||||
const serviceHeaders = {
|
||||
authorization: 'Bearer service-token',
|
||||
'content-type': 'application/json',
|
||||
};
|
||||
const submitted = await fetch(`${server.baseUrl}/v1/executor-jobs`, {
|
||||
method: 'POST',
|
||||
headers: serviceHeaders,
|
||||
body: JSON.stringify({
|
||||
jobId: 'http-worker-job-1',
|
||||
idempotencyKey: 'http-worker-idem-1',
|
||||
executor: 'goosed',
|
||||
task: {
|
||||
instruction: 'Run the canary',
|
||||
workspaceRef: { kind: 'workspace-alias', id: 'canary' },
|
||||
},
|
||||
subject: { tenantId: 'tenant-1', userId: 'user-1' },
|
||||
authorization: { executionAllowed: true },
|
||||
policy: { sideEffectsAllowed: true },
|
||||
}),
|
||||
});
|
||||
assert.equal(submitted.status, 202);
|
||||
assert.equal((await submitted.json()).job.status, 'queued');
|
||||
|
||||
const unauthorizedWorker = await fetch(`${server.baseUrl}/v1/workers/claim`, {
|
||||
method: 'POST',
|
||||
headers: serviceHeaders,
|
||||
body: JSON.stringify({ workerId: 'worker-1', executors: ['goosed'] }),
|
||||
});
|
||||
assert.equal(unauthorizedWorker.status, 401);
|
||||
assert.equal((await unauthorizedWorker.json()).error.code, 'WORKER_UNAUTHORIZED');
|
||||
|
||||
const workerHeaders = {
|
||||
...serviceHeaders,
|
||||
'x-orchestrator-worker-token': 'worker-token',
|
||||
};
|
||||
const claimResponse = await fetch(`${server.baseUrl}/v1/workers/claim`, {
|
||||
method: 'POST',
|
||||
headers: workerHeaders,
|
||||
body: JSON.stringify({ workerId: 'worker-1', executors: ['goosed'] }),
|
||||
});
|
||||
assert.equal(claimResponse.status, 200);
|
||||
const claim = await claimResponse.json();
|
||||
assert.equal(claim.job.request.task.instruction, 'Run the canary');
|
||||
|
||||
const started = await fetch(
|
||||
`${server.baseUrl}/v1/workers/jobs/http-worker-job-1/start`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: workerHeaders,
|
||||
body: JSON.stringify({ leaseToken: claim.leaseToken }),
|
||||
},
|
||||
);
|
||||
assert.equal(started.status, 200);
|
||||
|
||||
const completed = await fetch(
|
||||
`${server.baseUrl}/v1/workers/jobs/http-worker-job-1/complete`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: workerHeaders,
|
||||
body: JSON.stringify({
|
||||
leaseToken: claim.leaseToken,
|
||||
result: {
|
||||
summary: 'completed',
|
||||
artifactRefs: [{ kind: 'canary-result', id: 'result-1' }],
|
||||
},
|
||||
}),
|
||||
},
|
||||
);
|
||||
assert.equal(completed.status, 200);
|
||||
assert.equal((await completed.json()).status, 'succeeded');
|
||||
|
||||
const projected = await fetch(
|
||||
`${server.baseUrl}/v1/executor-jobs/http-worker-job-1`,
|
||||
{ headers: { authorization: 'Bearer service-token' } },
|
||||
);
|
||||
const projectedBody = await projected.json();
|
||||
assert.equal(projectedBody.status, 'succeeded');
|
||||
assert.equal('request' in projectedBody, false);
|
||||
assert.equal('token' in (projectedBody.lease ?? {}), false);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user