test/claude-worker-policy.test.js
Rama main · réplica de lectura del repositorio original.
var test = require("node:test");
var assert = require("node:assert/strict");
var fs = require("node:fs");
var path = require("node:path");
var createPolicyBroker = require("../lib/yoke/adapters/claude-worker-policy").createPolicyBroker;
function abortSignal(alreadyAborted) {
var listener = null;
return {
aborted: alreadyAborted === true,
addEventListener: function (name, fn) { if (name === "abort") listener = fn; },
removeEventListener: function (name, fn) { if (name === "abort" && listener === fn) listener = null; },
abort: function () { this.aborted = true; if (listener) listener(); },
};
}
test("worker policy registers before send so a synchronous response resolves", async function () {
var broker;
broker = createPolicyBroker({
timeoutMs: 20,
send: function (message) {
broker.respond({ requestId: message.requestId, result: { behavior: "allow", updatedInput: { safe: true } } });
return true;
},
});
var result = await broker.request({ requestId: "sync-1" });
assert.equal(result.behavior, "allow");
assert.equal(broker.pendingCount(), 0);
});
test("worker policy fails closed on send refusal and send throw", async function () {
var refused = createPolicyBroker({ send: function () { return false; } });
var refusedResult = await refused.request({ requestId: "refused-1" });
assert.equal(refusedResult.behavior, "deny");
assert.match(refusedResult.message, /unavailable/);
assert.equal(refused.pendingCount(), 0);
var thrown = createPolicyBroker({ send: function () { throw new Error("closed"); } });
var thrownResult = await thrown.request({ requestId: "throw-1" });
assert.equal(thrownResult.behavior, "deny");
assert.match(thrownResult.message, /unavailable/);
assert.equal(thrown.pendingCount(), 0);
});
test("worker policy times out and ignores a late response", async function () {
var broker = createPolicyBroker({ timeoutMs: 5, send: function () { return true; } });
var result = await broker.request({ requestId: "timeout-1" });
assert.equal(result.behavior, "deny");
assert.match(result.message, /timed out/);
assert.equal(broker.respond({ requestId: "timeout-1", result: { behavior: "allow" } }), false);
assert.equal(broker.pendingCount(), 0);
});
test("worker policy handles already-aborted and later-aborted requests without sending", async function () {
var sends = 0;
var broker = createPolicyBroker({ timeoutMs: 20, send: function () { sends++; return true; } });
var already = await broker.request({ requestId: "abort-1" }, abortSignal(true));
assert.equal(already.behavior, "deny");
assert.equal(sends, 0);
var signal = abortSignal(false);
var pending = broker.request({ requestId: "abort-2" }, signal);
assert.equal(sends, 1);
signal.abort();
var later = await pending;
assert.equal(later.behavior, "deny");
assert.match(later.message, /cancelled/);
assert.equal(broker.pendingCount(), 0);
});
test("worker policy cleanup denies every outstanding request", async function () {
var broker = createPolicyBroker({ timeoutMs: 50, send: function () { return true; } });
var first = broker.request({ requestId: "clear-1" });
var second = broker.request({ requestId: "clear-2" });
broker.clear("Permission policy query ended.");
assert.match((await first).message, /query ended/);
assert.match((await second).message, /query ended/);
assert.equal(broker.pendingCount(), 0);
});
test("Claude worker wires the broker into guarded hooks and both cleanup paths", function () {
var source = fs.readFileSync(path.join(__dirname, "../lib/yoke/adapters/claude-worker.js"), "utf8");
assert.match(source, /preToolPolicyBroker\.request\(/);
assert.match(source, /hookOpts && hookOpts\.signal/);
assert.match(source, /preToolPolicyBroker\.clear\("Permission policy query ended\."\)/);
assert.match(source, /preToolPolicyBroker\.clear\("Permission policy worker closed\."\)/);
});