mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-22 19:14:33 -07:00
feat(plan): document and validate Plan Mode policy overrides (#18825)
This commit is contained in:
@@ -951,4 +951,107 @@ name = "invalid-name"
|
||||
|
||||
vi.doUnmock('node:fs/promises');
|
||||
});
|
||||
|
||||
it('should allow overriding Plan Mode deny with user policy', async () => {
|
||||
const actualFs =
|
||||
await vi.importActual<typeof import('node:fs/promises')>(
|
||||
'node:fs/promises',
|
||||
);
|
||||
|
||||
const mockReaddir = vi.fn(
|
||||
async (
|
||||
path: string | Buffer | URL,
|
||||
options?: Parameters<typeof actualFs.readdir>[1],
|
||||
) => {
|
||||
const normalizedPath = nodePath.normalize(path.toString());
|
||||
if (normalizedPath.includes(nodePath.normalize('.gemini/policies'))) {
|
||||
return [
|
||||
{
|
||||
name: 'user-plan.toml',
|
||||
isFile: () => true,
|
||||
isDirectory: () => false,
|
||||
},
|
||||
] as unknown as Awaited<ReturnType<typeof actualFs.readdir>>;
|
||||
}
|
||||
return actualFs.readdir(
|
||||
path,
|
||||
options as Parameters<typeof actualFs.readdir>[1],
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
const mockReadFile = vi.fn(
|
||||
async (
|
||||
path: Parameters<typeof actualFs.readFile>[0],
|
||||
options: Parameters<typeof actualFs.readFile>[1],
|
||||
) => {
|
||||
const normalizedPath = nodePath.normalize(path.toString());
|
||||
if (normalizedPath.includes('user-plan.toml')) {
|
||||
return `
|
||||
[[rule]]
|
||||
toolName = "run_shell_command"
|
||||
commandPrefix = ["git status", "git diff"]
|
||||
decision = "allow"
|
||||
priority = 100
|
||||
modes = ["plan"]
|
||||
|
||||
[[rule]]
|
||||
toolName = "codebase_investigator"
|
||||
decision = "allow"
|
||||
priority = 100
|
||||
modes = ["plan"]
|
||||
`;
|
||||
}
|
||||
return actualFs.readFile(path, options);
|
||||
},
|
||||
);
|
||||
|
||||
vi.doMock('node:fs/promises', () => ({
|
||||
...actualFs,
|
||||
default: { ...actualFs, readFile: mockReadFile, readdir: mockReaddir },
|
||||
readFile: mockReadFile,
|
||||
readdir: mockReaddir,
|
||||
}));
|
||||
|
||||
vi.resetModules();
|
||||
const { createPolicyEngineConfig } = await import('./config.js');
|
||||
|
||||
const settings: PolicySettings = {};
|
||||
const config = await createPolicyEngineConfig(
|
||||
settings,
|
||||
ApprovalMode.PLAN,
|
||||
nodePath.join(__dirname, 'policies'),
|
||||
);
|
||||
|
||||
const shellRules = config.rules?.filter(
|
||||
(r) =>
|
||||
r.toolName === 'run_shell_command' &&
|
||||
r.decision === PolicyDecision.ALLOW &&
|
||||
r.modes?.includes(ApprovalMode.PLAN) &&
|
||||
r.argsPattern,
|
||||
);
|
||||
expect(shellRules).toHaveLength(2);
|
||||
expect(
|
||||
shellRules?.some((r) => r.argsPattern?.test('{"command":"git status"}')),
|
||||
).toBe(true);
|
||||
expect(
|
||||
shellRules?.some((r) => r.argsPattern?.test('{"command":"git diff"}')),
|
||||
).toBe(true);
|
||||
expect(
|
||||
shellRules?.every(
|
||||
(r) => !r.argsPattern?.test('{"command":"git commit"}'),
|
||||
),
|
||||
).toBe(true);
|
||||
|
||||
const subagentRule = config.rules?.find(
|
||||
(r) =>
|
||||
r.toolName === 'codebase_investigator' &&
|
||||
r.decision === PolicyDecision.ALLOW &&
|
||||
r.modes?.includes(ApprovalMode.PLAN),
|
||||
);
|
||||
expect(subagentRule).toBeDefined();
|
||||
expect(subagentRule?.priority).toBeCloseTo(2.1, 5);
|
||||
|
||||
vi.doUnmock('node:fs/promises');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user