test(cli): verify packaged policy revocation
This commit is contained in:
parent
7a4cfb4fbd
commit
3d71737dc9
|
|
@ -1,7 +1,26 @@
|
|||
import { describe, expect, it, vi } from "vitest";
|
||||
import { execFile } from "node:child_process";
|
||||
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
import {
|
||||
readProjectPermissionStore,
|
||||
writeProjectPermissionStore,
|
||||
} from "../src/application/ProjectPermissionStore.js";
|
||||
import { approvePolicyRevocation } from "../src/cliPolicyCommands.js";
|
||||
|
||||
const execute = promisify(execFile);
|
||||
const roots: string[] = [];
|
||||
|
||||
afterEach(async () => {
|
||||
await Promise.all(
|
||||
roots.splice(0).map((root) => rm(root, { recursive: true, force: true })),
|
||||
);
|
||||
});
|
||||
|
||||
describe("policy revocation approval", () => {
|
||||
it("accepts --yes without invoking the interactive prompt", async () => {
|
||||
const confirm = vi.fn<() => Promise<boolean>>();
|
||||
|
|
@ -50,4 +69,87 @@ describe("policy revocation approval", () => {
|
|||
expect(confirm).toHaveBeenCalledWith("grant-1");
|
||||
},
|
||||
);
|
||||
|
||||
it("keeps the packaged project store unchanged until --yes is supplied", async () => {
|
||||
const project = await mkdtemp(join(tmpdir(), "rea-policy-cli-"));
|
||||
roots.push(project);
|
||||
const store = join(project, ".rea", "permissions.json");
|
||||
const grant = {
|
||||
grant_id: "project:revoke-me",
|
||||
capability: "evidence_read" as const,
|
||||
roots: [project],
|
||||
executables: [],
|
||||
environment_names: [],
|
||||
network: "none" as const,
|
||||
mount: false,
|
||||
lifetime: "project" as const,
|
||||
operation_identity: null,
|
||||
expires_at: null,
|
||||
};
|
||||
expect(
|
||||
await writeProjectPermissionStore(store, project, [grant]),
|
||||
).toMatchObject({
|
||||
ok: true,
|
||||
value: { grants: [grant] },
|
||||
});
|
||||
const before = await readFile(store);
|
||||
const environment = {
|
||||
...process.env,
|
||||
REA_PERMISSION_PROJECT_ROOT: project,
|
||||
REA_PERMISSION_PROJECT_STORE: store,
|
||||
};
|
||||
|
||||
const denied = await runCli(
|
||||
["policy", "revoke", grant.grant_id, "--json"],
|
||||
environment,
|
||||
);
|
||||
expect(denied.status).toBe(1);
|
||||
expect(denied.output).toEqual({
|
||||
error:
|
||||
"Policy revoke requires confirmation. Rerun interactively or with --yes.",
|
||||
grant_id: grant.grant_id,
|
||||
});
|
||||
expect(await readFile(store)).toEqual(before);
|
||||
|
||||
const approved = await runCli(
|
||||
["policy", "revoke", grant.grant_id, "--yes", "--json"],
|
||||
environment,
|
||||
);
|
||||
expect(approved).toEqual({
|
||||
status: 0,
|
||||
output: {
|
||||
revoked: grant.grant_id,
|
||||
reload: "Send SIGHUP to the REA MCP process",
|
||||
},
|
||||
});
|
||||
expect(await readProjectPermissionStore(store, project)).toMatchObject({
|
||||
ok: true,
|
||||
value: { grants: [] },
|
||||
});
|
||||
}, 40_000);
|
||||
});
|
||||
|
||||
const runCli = async (
|
||||
arguments_: readonly string[],
|
||||
environment: NodeJS.ProcessEnv,
|
||||
): Promise<{ readonly status: number; readonly output: unknown }> => {
|
||||
try {
|
||||
const { stdout } = await execute(
|
||||
process.execPath,
|
||||
["scripts/rea.mjs", ...arguments_],
|
||||
{ cwd: process.cwd(), env: environment },
|
||||
);
|
||||
return { status: 0, output: JSON.parse(stdout) };
|
||||
} catch (cause: unknown) {
|
||||
if (
|
||||
typeof cause === "object" &&
|
||||
cause !== null &&
|
||||
"code" in cause &&
|
||||
typeof cause.code === "number" &&
|
||||
"stdout" in cause &&
|
||||
typeof cause.stdout === "string"
|
||||
)
|
||||
return { status: cause.code, output: JSON.parse(cause.stdout) };
|
||||
throw cause;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue