Files
stack/packages/cli/tests/grants-scope.test.mjs

75 lines
3.2 KiB
JavaScript

// Row 298/Q228: the real CLI parser and human-shell refusal. Transport is a
// recorder; no socket, config, credential or live grant is accessed.
import test from "node:test";
import assert from "node:assert/strict";
import { main } from "../src/cli.mjs";
import { humanEnv, io } from "./helpers.mjs";
const AGENT_MARKERS = ["MOSAIC_BUS_CAP", "MOSAIC_RUN_ID", "MOSAIC_AGENT_RUN", "CLAUDECODE", "CLAUDE_CODE_ENTRYPOINT", "CODEX_THREAD_ID", "PI_AGENT_DIR"];
const REVISION = "a".repeat(64);
const SCOPE = { gitea: { agents: ["coder"], projects: ["app"] } };
const READ = ["grants", "scope", "--business", "acme"];
const SET = ["grants", "scope", "set", "--business", "acme", "--revision", REVISION];
function setup(env = humanEnv(), stdin = JSON.stringify(SCOPE)) {
const x = io(env);
x.stdin.end(stdin);
const calls = [];
const deps = {
system: { dataRoot: "/nonexistent" },
transport: (business) => async (verb, args) => {
calls.push({ business, verb, args });
return { revision: REVISION, scope: SCOPE, fallback: false };
},
testerTransport: () => async () => { throw new Error("tester transport must never run"); },
};
return { x, calls, deps };
}
// Break caught: dropping scope dispatch or misrouting the writer's revision.
test("row 298 CLI: scope reads and scope set sends JSON and the observed revision", async () => {
const f = setup();
await main(READ, f.x, f.deps);
assert.deepEqual(f.calls, [{ business: "acme", verb: "grants.scope", args: {} }]);
assert.deepEqual(JSON.parse(f.x.out.text), { revision: REVISION, scope: SCOPE, fallback: false });
const w = setup();
await main(SET, w.x, w.deps);
assert.deepEqual(w.calls, [{ business: "acme", verb: "grants.scope.set", args: { revision: REVISION, scope: SCOPE } }]);
const empty = setup(humanEnv(), "{}");
await main(SET, empty.x, empty.deps);
assert.deepEqual(empty.calls[0].args.scope, {});
});
// Break caught: a new grants path bypassing access's refuseInsideAgent guard.
test("row 298 CLI: every access agent marker refuses scope set before transport", async () => {
for (const marker of AGENT_MARKERS) {
const f = setup({ ...humanEnv(), [marker]: "agent" });
await assert.rejects(main(SET, f.x, f.deps), (e) => e.exitCode === 3 && /human shell/.test(e.message), marker);
assert.deepEqual(f.calls, []);
assert.equal(f.x.out.text, "");
}
});
// Break caught: --tester selecting a nonhuman transport for this approval.
test("row 298 CLI: --tester cannot read or change the scope", async () => {
for (const args of [READ, SET]) {
const f = setup();
await assert.rejects(main([...args, "--tester"], f.x, f.deps), (e) => e.exitCode === 4);
assert.deepEqual(f.calls, []);
}
});
// Break caught: a missing revision or invalid stdin being sent as an approval.
test("row 298 CLI: missing revision and empty, invalid or oversized JSON refuse without a call", async () => {
for (const [args, input, code] of [
[SET.slice(0, -2), "{}", 4],
[SET, "", 4],
[SET, " \n", 4],
[SET, "{bad", 4],
[SET, " ".repeat(65537), 2],
]) {
const f = setup(humanEnv(), input);
await assert.rejects(main(args, f.x, f.deps), (e) => e.exitCode === code);
assert.deepEqual(f.calls, []);
}
});