mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-23 11:34:44 -07:00
feat(core): add forbiddenPaths to GlobalSandboxOptions and refactor createSandboxManager (#23936)
This commit is contained in:
@@ -362,16 +362,21 @@ describe('LinuxSandboxManager', () => {
|
||||
});
|
||||
vi.mocked(fs.realpathSync).mockImplementation((p) => p.toString());
|
||||
|
||||
const bwrapArgs = await getBwrapArgs({
|
||||
command: 'ls',
|
||||
args: ['-la'],
|
||||
cwd: workspace,
|
||||
env: {},
|
||||
policy: {
|
||||
forbiddenPaths: ['/tmp/cache', '/opt/secret.txt'],
|
||||
},
|
||||
const customManager = new LinuxSandboxManager({
|
||||
workspace,
|
||||
forbiddenPaths: ['/tmp/cache', '/opt/secret.txt'],
|
||||
});
|
||||
|
||||
const bwrapArgs = await getBwrapArgs(
|
||||
{
|
||||
command: 'ls',
|
||||
args: ['-la'],
|
||||
cwd: workspace,
|
||||
env: {},
|
||||
},
|
||||
customManager,
|
||||
);
|
||||
|
||||
const cacheIndex = bwrapArgs.indexOf('/tmp/cache');
|
||||
expect(bwrapArgs[cacheIndex - 1]).toBe('--tmpfs');
|
||||
|
||||
@@ -389,16 +394,21 @@ describe('LinuxSandboxManager', () => {
|
||||
return p.toString();
|
||||
});
|
||||
|
||||
const bwrapArgs = await getBwrapArgs({
|
||||
command: 'ls',
|
||||
args: ['-la'],
|
||||
cwd: workspace,
|
||||
env: {},
|
||||
policy: {
|
||||
forbiddenPaths: ['/tmp/forbidden-symlink'],
|
||||
},
|
||||
const customManager = new LinuxSandboxManager({
|
||||
workspace,
|
||||
forbiddenPaths: ['/tmp/forbidden-symlink'],
|
||||
});
|
||||
|
||||
const bwrapArgs = await getBwrapArgs(
|
||||
{
|
||||
command: 'ls',
|
||||
args: ['-la'],
|
||||
cwd: workspace,
|
||||
env: {},
|
||||
},
|
||||
customManager,
|
||||
);
|
||||
|
||||
const secretIndex = bwrapArgs.indexOf('/opt/real-target.txt');
|
||||
expect(bwrapArgs[secretIndex - 2]).toBe('--ro-bind');
|
||||
expect(bwrapArgs[secretIndex - 1]).toBe('/dev/null');
|
||||
@@ -412,16 +422,21 @@ describe('LinuxSandboxManager', () => {
|
||||
});
|
||||
vi.mocked(fs.realpathSync).mockImplementation((p) => p.toString());
|
||||
|
||||
const bwrapArgs = await getBwrapArgs({
|
||||
command: 'ls',
|
||||
args: [],
|
||||
cwd: workspace,
|
||||
env: {},
|
||||
policy: {
|
||||
forbiddenPaths: ['/tmp/not-here.txt'],
|
||||
},
|
||||
const customManager = new LinuxSandboxManager({
|
||||
workspace,
|
||||
forbiddenPaths: ['/tmp/not-here.txt'],
|
||||
});
|
||||
|
||||
const bwrapArgs = await getBwrapArgs(
|
||||
{
|
||||
command: 'ls',
|
||||
args: [],
|
||||
cwd: workspace,
|
||||
env: {},
|
||||
},
|
||||
customManager,
|
||||
);
|
||||
|
||||
const idx = bwrapArgs.indexOf('/tmp/not-here.txt');
|
||||
expect(bwrapArgs[idx - 2]).toBe('--symlink');
|
||||
expect(bwrapArgs[idx - 1]).toBe('/dev/null');
|
||||
@@ -436,16 +451,21 @@ describe('LinuxSandboxManager', () => {
|
||||
return p.toString();
|
||||
});
|
||||
|
||||
const bwrapArgs = await getBwrapArgs({
|
||||
command: 'ls',
|
||||
args: [],
|
||||
cwd: workspace,
|
||||
env: {},
|
||||
policy: {
|
||||
forbiddenPaths: ['/tmp/dir-link'],
|
||||
},
|
||||
const customManager = new LinuxSandboxManager({
|
||||
workspace,
|
||||
forbiddenPaths: ['/tmp/dir-link'],
|
||||
});
|
||||
|
||||
const bwrapArgs = await getBwrapArgs(
|
||||
{
|
||||
command: 'ls',
|
||||
args: [],
|
||||
cwd: workspace,
|
||||
env: {},
|
||||
},
|
||||
customManager,
|
||||
);
|
||||
|
||||
const idx = bwrapArgs.indexOf('/opt/real-dir');
|
||||
expect(bwrapArgs[idx - 1]).toBe('--tmpfs');
|
||||
});
|
||||
@@ -456,17 +476,24 @@ describe('LinuxSandboxManager', () => {
|
||||
);
|
||||
vi.mocked(fs.realpathSync).mockImplementation((p) => p.toString());
|
||||
|
||||
const bwrapArgs = await getBwrapArgs({
|
||||
command: 'ls',
|
||||
args: ['-la'],
|
||||
cwd: workspace,
|
||||
env: {},
|
||||
policy: {
|
||||
allowedPaths: ['/tmp/conflict'],
|
||||
forbiddenPaths: ['/tmp/conflict'],
|
||||
},
|
||||
const customManager = new LinuxSandboxManager({
|
||||
workspace,
|
||||
forbiddenPaths: ['/tmp/conflict'],
|
||||
});
|
||||
|
||||
const bwrapArgs = await getBwrapArgs(
|
||||
{
|
||||
command: 'ls',
|
||||
args: ['-la'],
|
||||
cwd: workspace,
|
||||
env: {},
|
||||
policy: {
|
||||
allowedPaths: ['/tmp/conflict'],
|
||||
},
|
||||
},
|
||||
customManager,
|
||||
);
|
||||
|
||||
const bindTryIdx = bwrapArgs.indexOf('--bind-try');
|
||||
const tmpfsIdx = bwrapArgs.lastIndexOf('--tmpfs');
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ import {
|
||||
} from '../../services/environmentSanitization.js';
|
||||
import { debugLogger } from '../../utils/debugLogger.js';
|
||||
import { spawnAsync } from '../../utils/shell-utils.js';
|
||||
import { type SandboxPolicyManager } from '../../policy/sandboxPolicyManager.js';
|
||||
import {
|
||||
isStrictlyApproved,
|
||||
verifySandboxOverrides,
|
||||
@@ -134,20 +133,10 @@ function touch(filePath: string, isDirectory: boolean) {
|
||||
* A SandboxManager implementation for Linux that uses Bubblewrap (bwrap).
|
||||
*/
|
||||
|
||||
export interface LinuxSandboxOptions extends GlobalSandboxOptions {
|
||||
modeConfig?: {
|
||||
readonly?: boolean;
|
||||
network?: boolean;
|
||||
approvedTools?: string[];
|
||||
allowOverrides?: boolean;
|
||||
};
|
||||
policyManager?: SandboxPolicyManager;
|
||||
}
|
||||
|
||||
export class LinuxSandboxManager implements SandboxManager {
|
||||
private static maskFilePath: string | undefined;
|
||||
|
||||
constructor(private readonly options: LinuxSandboxOptions) {}
|
||||
constructor(private readonly options: GlobalSandboxOptions) {}
|
||||
|
||||
isKnownSafeCommand(args: string[]): boolean {
|
||||
return isKnownSafeCommand(args);
|
||||
@@ -333,7 +322,7 @@ export class LinuxSandboxManager implements SandboxManager {
|
||||
}
|
||||
}
|
||||
|
||||
const forbiddenPaths = sanitizePaths(req.policy?.forbiddenPaths) || [];
|
||||
const forbiddenPaths = sanitizePaths(this.options.forbiddenPaths) || [];
|
||||
for (const p of forbiddenPaths) {
|
||||
let resolved: string;
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user