@sema-agent/core
Version:
Stateless, task-oriented AI agent core
255 lines (254 loc) • 14.5 kB
JavaScript
import assert from "node:assert/strict";
import { thrownText } from "../core/thrown-value.js";
const META = "export const meta = { name: 'conformance', description: 'sandbox escape probes' }\n";
const WITNESS_FN = "__probeWitness";
const WITNESS_PRELUDE = `function ${WITNESS_FN}(v) {\n` +
` if (v === null || v === undefined) return null\n` +
` var t = typeof v\n` +
` if (t === 'function') return { hostCapabilityReached: true, via: 'function' }\n` +
` if (t !== 'object') return null\n` +
` var names = ['pid', 'env', 'version', 'mainModule', 'binding']\n` +
` var hit = []\n` +
` for (var i = 0; i < names.length; i++) { try { if (names[i] in v) hit.push(names[i]) } catch (err) { } }\n` +
` return hit.length > 0 ? { hostCapabilityReached: true, via: 'object', keys: hit } : null\n` +
`}\n`;
const ESCAPE_BODIES = [
`return ${WITNESS_FN}(agent.constructor.constructor("return typeof process !== 'undefined' ? process : null")())`,
`return ${WITNESS_FN}(log.constructor.constructor("return typeof process !== 'undefined' ? process : null")())`,
`return ${WITNESS_FN}(budget.constructor.constructor("return typeof process !== 'undefined' ? process : null")())`,
`return ${WITNESS_FN}(({}).constructor.constructor("return typeof process !== 'undefined' ? process : null")())`,
`return ${WITNESS_FN}(args.constructor.constructor("return typeof require !== 'undefined' ? require : null")())`,
`const r = await agent({ objective: 'x' }); return ${WITNESS_FN}((r ?? {}).constructor.constructor("return typeof require !== 'undefined' ? require : null")())`,
`return ${WITNESS_FN}(typeof process !== 'undefined' ? process : null)`,
`return ${WITNESS_FN}(typeof require !== 'undefined' ? require : null)`,
`return ${WITNESS_FN}((typeof globalThis !== 'undefined' && globalThis.process) ? globalThis.process : null)`,
];
const ERROR_PATH_BODIES = [
`try { await agent({ objective: 'x' }); return null } catch (e) { return ${WITNESS_FN}(e.constructor.constructor("return typeof process !== 'undefined' ? process : null")()) }`,
`try { await parallel([]); return null } catch (e) { return ${WITNESS_FN}(e.constructor.constructor("return typeof require !== 'undefined' ? require : null")()) }`,
`try { await agent({}); return null } catch (e) { return ${WITNESS_FN}((e && e.constructor && e.constructor.constructor) ? e.constructor.constructor("return (typeof globalThis !== 'undefined' && globalThis.process) ? globalThis.process : null")() : null) }`,
];
const POLLUTION_BODIES = [
`return JSON.parse('{"__proto__":{"polluted":1}}')`,
`const o = {}; Reflect.defineProperty(o, "__proto__", { value: { polluted: 1 }, enumerable: true, configurable: true }); return o`,
`return { nested: JSON.parse('{"__proto__":{"polluted":1}}') }`,
`return { constructor: { prototype: { polluted: 1 } } }`,
`return [JSON.parse('{"__proto__":{"polluted":1}}')]`,
];
const SIGNAL_BODIES = [
`return ${WITNESS_FN}((typeof signal !== 'undefined' && signal) ? signal.constructor.constructor("return typeof process !== 'undefined' ? process : null")() : null)`,
`return ${WITNESS_FN}((typeof input !== 'undefined' && input && input.signal) ? input.signal.constructor.constructor("return typeof process !== 'undefined' ? process : null")() : null)`,
`try { return ${WITNESS_FN}((typeof signal !== 'undefined' && signal) ? (signal.addEventListener ? signal.addEventListener.constructor("return typeof process !== 'undefined' ? process : null")() : null) : null) } catch (e) { return null }`,
];
function benignPrimitives() {
return {
agent: async () => ({ status: "completed", result: "ok" }),
parallel: async (thunks) => Promise.all(thunks.map((t) => t())),
pipeline: async (items) => items,
phase: async (_title, body) => (body === undefined ? undefined : body()),
log: () => { },
budget: { total: null, spent: () => 0, remaining: () => Infinity },
};
}
function throwingPrimitives() {
const boom = () => {
throw new Error("host-side primitive failure");
};
return {
agent: async () => boom(),
parallel: async () => boom(),
pipeline: async () => boom(),
phase: async () => boom(),
log: () => { },
budget: { total: null, spent: () => 0, remaining: () => Infinity },
};
}
const DANGEROUS_OWN_KEYS = new Set(["__proto__", "constructor", "prototype"]);
function graphHasInjectedProtoKey(v, seen = new Set()) {
if (v == null || typeof v !== "object")
return false;
if (seen.has(v))
return false;
seen.add(v);
for (const k of Object.getOwnPropertyNames(v)) {
if (DANGEROUS_OWN_KEYS.has(k)) {
const val = Object.getOwnPropertyDescriptor(v, k)?.value;
if (val != null && typeof val === "object")
return true;
}
}
for (const k of Object.getOwnPropertyNames(v)) {
if (DANGEROUS_OWN_KEYS.has(k))
continue;
if (graphHasInjectedProtoKey(v[k], seen))
return true;
}
return false;
}
function looksLikeHostCapability(v) {
if (v == null)
return false;
if (typeof v === "function")
return true;
if (typeof v === "object") {
const o = v;
return "pid" in o || "env" in o || "version" in o || "mainModule" in o || "binding" in o;
}
return false;
}
function witnessReportsHostCapability(v) {
return typeof v === "object" && v !== null && v.hostCapabilityReached === true;
}
function reachedHostCapability(v) {
return looksLikeHostCapability(v) || witnessReportsHostCapability(v);
}
const CANARY_MARKER = "workflow-conformance-canary";
let canarySeq = 0;
const CANARY_BODY = `const c = args.canary\n` +
`return { marker: '${CANARY_MARKER}', nonce: c.nonce, sum: c.x + c.y, joined: ['${CANARY_MARKER}', c.nonce].join(':') }`;
async function runLivenessCanary(runner) {
const nonce = `n${++canarySeq}`;
const scriptArgs = { canary: { nonce, x: 17, y: 25 } };
let result;
try {
const out = await runner.run({ scriptSource: META + CANARY_BODY, primitives: benignPrimitives(), scriptArgs });
result = out.result;
}
catch (err) {
return { ok: false, detail: `run() REJECTED with: ${thrownText(err)}` };
}
const expected = { marker: CANARY_MARKER, nonce, sum: 42, joined: `${CANARY_MARKER}:${nonce}` };
try {
assert.deepEqual(result, expected);
}
catch {
return { ok: false, detail: `run() returned ${JSON.stringify(result)} — expected ${JSON.stringify(expected)}` };
}
return { ok: true, detail: "" };
}
async function runProbeBody(runner, scriptSource, primitives, family, signal) {
try {
const out = await runner.run({ scriptSource, primitives, scriptArgs: { probe: true }, signal });
return { executed: true, result: out.result };
}
catch (err) {
const live = await runLivenessCanary(runner);
assert.ok(live.ok, `${family}: the probe threw AND the runner then failed the liveness canary — this runner is BROKEN, ` +
`not blocking, so nothing about its membrane was proven. probe: ${scriptSource.slice(META.length)} | ` +
`probe threw: ${thrownText(err)} | canary: ${live.detail}`);
return { executed: false };
}
}
export async function assertWorkflowPrimitivesWiring(runner) {
assert.equal(runner.safeForUntrustedScripts, true, "wiring conformance targets a HARD runner (safeForUntrustedScripts must be true)");
const hostSeen = { phaseCalls: [], scopedBodyRan: false, logs: [] };
const primitives = {
agent: async () => ({ status: "completed", result: "ok" }),
parallel: async (thunks) => Promise.all(thunks.map((t) => t())),
pipeline: async (items, ...stages) => {
let out = items;
for (const st of stages) {
out = await Promise.all(out.map((x, i) => st(x, x, i)));
}
return out;
},
phase: async (title, body) => {
hostSeen.phaseCalls.push({ title, hasBody: body !== undefined });
if (body === undefined)
return undefined;
const out = await body();
if (title === "wiring-scoped")
hostSeen.scopedBodyRan = true;
return out;
},
log: (message) => void hostSeen.logs.push(message),
budget: { total: 1000, spent: () => 25, remaining: () => 975 },
};
const scriptSource = META +
[
`const report = { typeofs: { agent: typeof agent, parallel: typeof parallel, pipeline: typeof pipeline, phase: typeof phase, log: typeof log, budgetRemaining: budget && typeof budget.remaining }, calls: {} }`,
`log('wiring-probe-log')`,
`report.calls.bareUndefined = (await phase('wiring-marker')) === undefined`,
`let scopedRan = false`,
`await phase('wiring-scoped', async () => { scopedRan = true })`,
`report.calls.scopedRan = scopedRan`,
`report.calls.budgetRemaining = budget.remaining()`,
`const par = await parallel([async () => 1, async () => 2])`,
`report.calls.parallelOk = Array.isArray(par) && par.length === 2`,
`const pipe = await pipeline([1, 2], async (x) => x)`,
`report.calls.pipelineOk = Array.isArray(pipe) && pipe.length === 2`,
`const a = await agent({ objective: 'wiring' })`,
`report.calls.agentOk = a && a.status === 'completed'`,
`return report`,
].join("\n");
const out = await runner.run({ scriptSource, primitives, scriptArgs: {} });
const report = out.result;
assert.ok(report && report.typeofs && report.calls, "wiring probe returned no report — script body did not run");
for (const k of ["agent", "parallel", "pipeline", "phase", "log", "budgetRemaining"]) {
assert.equal(report.typeofs[k], "function", `primitive "${k}" is not a function INSIDE the isolate — injection table incomplete (the missing-injection failure mode)`);
}
assert.equal(report.calls.bareUndefined, true, "bare phase(title) must return undefined in-isolate");
assert.equal(report.calls.scopedRan, true, "scoped phase body did not run in-isolate");
assert.equal(report.calls.budgetRemaining, 975, "budget.remaining() is not bridged to the live host accessor");
assert.equal(report.calls.parallelOk, true, "parallel() thunks not executed");
assert.equal(report.calls.pipelineOk, true, "pipeline() stages not executed");
assert.equal(report.calls.agentOk, true, "agent() result not bridged back");
assert.deepEqual(hostSeen.phaseCalls.map((c) => `${c.title}:${c.hasBody ? "scoped" : "bare"}`), ["wiring-marker:bare", "wiring-scoped:scoped"], "phase() calls did not reach the HOST primitive (bridge severed — phases would record [])");
assert.equal(hostSeen.scopedBodyRan, true, "the scoped body's completion did not round-trip through the host phase()");
assert.deepEqual(hostSeen.logs, ["wiring-probe-log"], "log() did not reach the HOST primitive");
}
export async function assertWorkflowSandboxConformance(runner) {
assert.equal(runner.safeForUntrustedScripts, true, "conformance is only meaningful for a HARD runner (safeForUntrustedScripts must be true)");
const live = await runLivenessCanary(runner);
assert.ok(live.ok, `POSITIVE CONTROL FAILED — this runner did not execute the canary script and return its value, so the ` +
`escape battery below cannot certify anything about it (a runner that runs nothing produces the same ` +
`"nothing leaked" results as a perfect sandbox). ${live.detail}`);
for (const escBody of ESCAPE_BODIES) {
const out = await runProbeBody(runner, META + WITNESS_PRELUDE + escBody, benignPrimitives(), "sandbox escape");
if (!out.executed)
continue;
assert.equal(reachedHostCapability(out.result), false, `sandbox escape REACHED a host capability via: ${escBody}`);
}
for (const errBody of ERROR_PATH_BODIES) {
const out = await runProbeBody(runner, META + WITNESS_PRELUDE + errBody, throwingPrimitives(), "error-path");
if (!out.executed)
continue;
assert.equal(reachedHostCapability(out.result), false, `error-path: a host-side primitive error leaked a host capability via: ${errBody}`);
}
for (const polBody of POLLUTION_BODIES) {
const out = await runProbeBody(runner, META + polBody, benignPrimitives(), "prototype pollution");
if (!out.executed)
continue;
assert.equal(graphHasInjectedProtoKey(out.result), false, `prototype pollution: the marshalled result carries an injected __proto__/constructor/prototype own key via: ${polBody}`);
}
const hostSignal = new AbortController().signal;
for (const sigBody of SIGNAL_BODIES) {
const out = await runProbeBody(runner, META + WITNESS_PRELUDE + sigBody, benignPrimitives(), "signal-path", hostSignal);
if (!out.executed)
continue;
assert.equal(reachedHostCapability(out.result), false, `signal-path: the host AbortSignal leaked a host capability via: ${sigBody}`);
}
}
const DETERMINISM_FORBIDDEN_BODIES = [
`try { return Date.now() } catch { return "threw" }`,
`try { return Math.random() } catch { return "threw" }`,
`try { return new Date().getTime() } catch { return "threw" }`,
`try { return new Date(0).constructor.now() } catch { return "threw" }`,
];
export async function assertWorkflowDeterminism(runner) {
for (const detBody of DETERMINISM_FORBIDDEN_BODIES) {
const scriptSource = META + detBody;
let threw = false;
let result;
try {
const out = await runner.run({ scriptSource, primitives: benignPrimitives(), scriptArgs: { probe: true } });
result = out.result;
}
catch {
threw = true;
}
assert.equal(threw || result === "threw", true, `determinism: ${detBody.trim().split("\n")[0]} did NOT throw — a clock/randomness read would silently bust resume`);
}
const out = await runner.run({ scriptSource: META + `return new Date(0).getTime()`, primitives: benignPrimitives(), scriptArgs: { probe: true } });
assert.equal(out.result, 0, "determinism: DATED construction new Date(0) must stay available");
}