mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-06-15 22:07:29 -07:00
918d7d3803
Co-authored-by: Christian Gunderman <gundermanc@gmail.com>
120 lines
3.5 KiB
TypeScript
120 lines
3.5 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2026 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import { describe, it, expect, beforeEach } from 'vitest';
|
|
import { PolicyEngine } from './policy-engine.js';
|
|
import { loadPoliciesFromToml } from './toml-loader.js';
|
|
import { PolicyDecision, ApprovalMode } from './types.js';
|
|
import path from 'node:path';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
describe('Memory Manager Policy', () => {
|
|
let engine: PolicyEngine;
|
|
|
|
beforeEach(async () => {
|
|
const policiesDir = path.join(__dirname, 'policies');
|
|
const result = await loadPoliciesFromToml([policiesDir], () => 1);
|
|
engine = new PolicyEngine({
|
|
rules: result.rules,
|
|
approvalMode: ApprovalMode.DEFAULT,
|
|
});
|
|
});
|
|
|
|
it('should allow save_memory to read ~/.gemini/GEMINI.md', async () => {
|
|
const toolCall = {
|
|
name: 'read_file',
|
|
args: { file_path: '~/.gemini/GEMINI.md' },
|
|
};
|
|
const result = await engine.check(
|
|
toolCall,
|
|
undefined,
|
|
undefined,
|
|
'save_memory',
|
|
);
|
|
expect(result.decision).toBe(PolicyDecision.ALLOW);
|
|
});
|
|
|
|
it('should allow save_memory to write ~/.gemini/GEMINI.md', async () => {
|
|
const toolCall = {
|
|
name: 'write_file',
|
|
args: { file_path: '~/.gemini/GEMINI.md', content: 'test' },
|
|
};
|
|
const result = await engine.check(
|
|
toolCall,
|
|
undefined,
|
|
undefined,
|
|
'save_memory',
|
|
);
|
|
expect(result.decision).toBe(PolicyDecision.ALLOW);
|
|
});
|
|
|
|
it('should allow save_memory to list ~/.gemini/', async () => {
|
|
const toolCall = {
|
|
name: 'list_directory',
|
|
args: { dir_path: '~/.gemini/' },
|
|
};
|
|
const result = await engine.check(
|
|
toolCall,
|
|
undefined,
|
|
undefined,
|
|
'save_memory',
|
|
);
|
|
expect(result.decision).toBe(PolicyDecision.ALLOW);
|
|
});
|
|
|
|
it('should fall through to global allow rule for save_memory reading non-.gemini files', async () => {
|
|
const toolCall = {
|
|
name: 'read_file',
|
|
args: { file_path: '/etc/passwd' },
|
|
};
|
|
const result = await engine.check(
|
|
toolCall,
|
|
undefined,
|
|
undefined,
|
|
'save_memory',
|
|
);
|
|
// The memory-manager policy only matches .gemini/ paths.
|
|
// Other paths fall through to the global read_file allow rule (priority 50).
|
|
expect(result.decision).toBe(PolicyDecision.ALLOW);
|
|
});
|
|
|
|
it('should not match paths where .gemini is a substring (e.g. not.gemini)', async () => {
|
|
const toolCall = {
|
|
name: 'read_file',
|
|
args: { file_path: '/tmp/not.gemini/evil' },
|
|
};
|
|
const result = await engine.check(
|
|
toolCall,
|
|
undefined,
|
|
undefined,
|
|
'save_memory',
|
|
);
|
|
// The tighter argsPattern requires .gemini/ to be preceded by start-of-string
|
|
// or a path separator, so "not.gemini/" should NOT match the memory-manager rule.
|
|
// It falls through to the global read_file allow rule instead.
|
|
expect(result.decision).toBe(PolicyDecision.ALLOW);
|
|
});
|
|
|
|
it('should fall through to global allow rule for other agents accessing ~/.gemini/', async () => {
|
|
const toolCall = {
|
|
name: 'read_file',
|
|
args: { file_path: '~/.gemini/GEMINI.md' },
|
|
};
|
|
const result = await engine.check(
|
|
toolCall,
|
|
undefined,
|
|
undefined,
|
|
'other_agent',
|
|
);
|
|
// The memory-manager policy rule (priority 100) only applies to 'save_memory'.
|
|
// Other agents fall through to the global read_file allow rule (priority 50).
|
|
expect(result.decision).toBe(PolicyDecision.ALLOW);
|
|
});
|
|
});
|