feat: vendor permission system source

This commit is contained in:
云服务部-叶林立
2026-08-19 14:35:19 +08:00
parent 198584daf8
commit 410c50a3e5
809 changed files with 157793 additions and 139 deletions
@@ -0,0 +1,128 @@
import { describe, expect, it } from "vitest";
import { PermissionManager } from "#src/permission-manager";
import type { ScopeConfig } from "#src/types";
import { createInMemoryPolicyLoader } from "#test/helpers/manager-harness";
/**
* yolo mode as recorded authority (#526): when the injected reader reports
* true, `check()` rewrites every matched `ask` to `allow` tagged
* `origin: "yolo"`. Display surfaces (`getComposedConfigRules`,
* `getToolPermission`) stay yolo-free.
*/
function makeManager(
global: Record<string, unknown>,
isYoloEnabled: () => boolean,
project?: ScopeConfig,
): PermissionManager {
return new PermissionManager({
policyLoader: createInMemoryPolicyLoader({
global: { permission: global } as ScopeConfig,
project,
}),
isYoloEnabled,
});
}
describe("PermissionManager yolo rewrite", () => {
it("rewrites a would-be-ask tool check to allow with origin 'yolo'", () => {
const manager = makeManager({ bash: "ask" }, () => true);
const result = manager.check({
kind: "tool",
surface: "bash",
input: { command: "rm -rf /tmp/x" },
});
expect(result.state).toBe("allow");
expect(result.origin).toBe("yolo");
});
it("rewrites the synthesized universal-default ask to allow with origin 'yolo'", () => {
// No rule for the surface; falls through to the universal "*" default (ask).
const manager = makeManager({}, () => true);
const result = manager.check({
kind: "tool",
surface: "someExtensionTool",
input: {},
});
expect(result.state).toBe("allow");
expect(result.origin).toBe("yolo");
});
it("preserves explicit deny under yolo (hard denies survive)", () => {
const manager = makeManager({ bash: "deny" }, () => true);
const result = manager.check({
kind: "tool",
surface: "bash",
input: { command: "rm -rf /" },
});
expect(result.state).toBe("deny");
expect(result.origin).not.toBe("yolo");
});
it("passes an explicit allow through unchanged (not tagged yolo)", () => {
const manager = makeManager({ read: "allow" }, () => true);
const result = manager.check({
kind: "tool",
surface: "read",
input: { path: "/tmp/x" },
});
expect(result.state).toBe("allow");
expect(result.origin).not.toBe("yolo");
});
it("does not rewrite when yolo is disabled (state stays ask)", () => {
const manager = makeManager({ bash: "ask" }, () => false);
const result = manager.check({
kind: "tool",
surface: "bash",
input: { command: "rm -rf /tmp/x" },
});
expect(result.state).toBe("ask");
expect(result.origin).not.toBe("yolo");
});
it("leaves display surfaces yolo-free even when yolo is enabled", () => {
const manager = makeManager({ bash: "ask" }, () => true);
// getComposedConfigRules shows the configured action, not the rewrite.
const bashRule = manager
.getComposedConfigRules()
.find((r) => r.surface === "bash");
expect(bashRule?.action).toBe("ask");
expect(bashRule?.origin).not.toBe("yolo");
// getToolPermission reports the configured surface state.
expect(manager.getToolPermission("bash")).toBe("ask");
});
});
describe("PermissionManager fail-closed clamp under yolo (#646)", () => {
it("yolo re-permits a fail-closed floored allow (allow→ask→allow)", () => {
// Invalid project scope floors global's `allow` to `ask` at composition;
// yolo then rewrites the `ask` back to `allow`. yolo is an explicit
// full-permissive opt-in, so yolo users are unaffected by the clamp.
const manager = makeManager({ bash: "allow" }, () => true, {
invalid: true,
});
const result = manager.check({
kind: "tool",
surface: "bash",
input: { command: "echo hi" },
});
expect(result.state).toBe("allow");
expect(result.origin).toBe("yolo");
});
it("preserves a hard deny under yolo even with an invalid scope", () => {
const manager = makeManager({ bash: "deny" }, () => true, {
invalid: true,
});
const result = manager.check({
kind: "tool",
surface: "bash",
input: { command: "rm -rf /" },
});
expect(result.state).toBe("deny");
expect(result.origin).not.toBe("yolo");
});
});