mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-08-03 21:51:11 -07:00
fix(cli): fall back to embedded macOS seatbelt profiles if missing (#28551)
This commit is contained in:
@@ -103,7 +103,10 @@ vi.mock('../utils.js', () => ({
|
||||
|
||||
describe('extensions install command', () => {
|
||||
it('should fail if no source is provided', () => {
|
||||
const validationParser = yargs([]).command(installCommand).fail(false);
|
||||
const validationParser = yargs([])
|
||||
.locale('en')
|
||||
.command(installCommand)
|
||||
.fail(false);
|
||||
expect(() => validationParser.parse('install')).toThrow(
|
||||
'Not enough non-option arguments: got 0, need at least 1',
|
||||
);
|
||||
|
||||
@@ -27,7 +27,10 @@ vi.mock('../utils.js', () => ({
|
||||
|
||||
describe('extensions validate command', () => {
|
||||
it('should fail if no path is provided', () => {
|
||||
const validationParser = yargs([]).command(validateCommand).fail(false);
|
||||
const validationParser = yargs([])
|
||||
.locale('en')
|
||||
.command(validateCommand)
|
||||
.fail(false);
|
||||
expect(() => validationParser.parse('validate')).toThrow(
|
||||
'Not enough non-option arguments: got 0, need at least 1',
|
||||
);
|
||||
|
||||
@@ -17,7 +17,7 @@ describe('mcp command', () => {
|
||||
});
|
||||
|
||||
it('should show help when no subcommand is provided', async () => {
|
||||
const yargsInstance = yargs();
|
||||
const yargsInstance = yargs().locale('en');
|
||||
(mcpCommand.builder as (y: Argv) => Argv)(yargsInstance);
|
||||
|
||||
const parser = yargsInstance.command(mcpCommand).help();
|
||||
|
||||
@@ -292,6 +292,140 @@ describe('sandbox', () => {
|
||||
await expect(start_sandbox(config)).rejects.toThrow(FatalSandboxError);
|
||||
});
|
||||
|
||||
it('should fall back to embedded profile if the .sb file is missing on disk', async () => {
|
||||
vi.mocked(os.platform).mockReturnValue('darwin');
|
||||
vi.mocked(fs.existsSync).mockImplementation((p) =>
|
||||
String(p).includes(
|
||||
'gemini-sandbox-macos-permissive-open-a1b2c3d4e5f6.sb',
|
||||
),
|
||||
);
|
||||
|
||||
const config: SandboxConfig = createMockSandboxConfig({
|
||||
command: 'sandbox-exec',
|
||||
image: 'some-image',
|
||||
});
|
||||
|
||||
const onSpy = vi.spyOn(process, 'on');
|
||||
const offSpy = vi.spyOn(process, 'off');
|
||||
|
||||
interface MockProcess extends EventEmitter {
|
||||
stdout: EventEmitter;
|
||||
stderr: EventEmitter;
|
||||
}
|
||||
const mockSpawnProcess = new EventEmitter() as MockProcess;
|
||||
mockSpawnProcess.stdout = new EventEmitter();
|
||||
mockSpawnProcess.stderr = new EventEmitter();
|
||||
vi.mocked(spawn).mockReturnValue(
|
||||
mockSpawnProcess as unknown as ReturnType<typeof spawn>,
|
||||
);
|
||||
|
||||
const promise = start_sandbox(config, [], undefined, ['arg1']);
|
||||
|
||||
setTimeout(() => {
|
||||
mockSpawnProcess.emit('close', 0);
|
||||
}, 10);
|
||||
|
||||
await expect(promise).resolves.toBe(0);
|
||||
|
||||
// Verify fs.writeFileSync was called with the temp profile file, content, and 0o600 permissions
|
||||
expect(fs.writeFileSync).toHaveBeenCalledWith(
|
||||
expect.stringContaining(
|
||||
'gemini-sandbox-macos-permissive-open-a1b2c3d4e5f6.sb',
|
||||
),
|
||||
expect.stringContaining('deny default'),
|
||||
expect.objectContaining({
|
||||
encoding: 'utf8',
|
||||
mode: 0o600,
|
||||
}),
|
||||
);
|
||||
|
||||
// Verify spawn was called with the temp profile file
|
||||
expect(spawn).toHaveBeenCalledWith(
|
||||
'sandbox-exec',
|
||||
expect.arrayContaining([
|
||||
'-f',
|
||||
expect.stringContaining(
|
||||
'gemini-sandbox-macos-permissive-open-a1b2c3d4e5f6.sb',
|
||||
),
|
||||
]),
|
||||
expect.objectContaining({ stdio: 'inherit' }),
|
||||
);
|
||||
|
||||
// Verify process on/off hooks were called for exit, SIGINT, and SIGTERM cleanups
|
||||
expect(onSpy).toHaveBeenCalledWith('exit', expect.any(Function));
|
||||
expect(onSpy).toHaveBeenCalledWith('SIGINT', expect.any(Function));
|
||||
expect(onSpy).toHaveBeenCalledWith('SIGTERM', expect.any(Function));
|
||||
|
||||
expect(offSpy).toHaveBeenCalledWith('exit', expect.any(Function));
|
||||
expect(offSpy).toHaveBeenCalledWith('SIGINT', expect.any(Function));
|
||||
expect(offSpy).toHaveBeenCalledWith('SIGTERM', expect.any(Function));
|
||||
|
||||
// Verify fs.unlinkSync was called to clean up the temp file
|
||||
expect(fs.unlinkSync).toHaveBeenCalledWith(
|
||||
expect.stringContaining(
|
||||
'gemini-sandbox-macos-permissive-open-a1b2c3d4e5f6.sb',
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it.each([
|
||||
'permissive-open',
|
||||
'permissive-closed',
|
||||
'permissive-proxied',
|
||||
'restrictive-open',
|
||||
'restrictive-closed',
|
||||
'restrictive-proxied',
|
||||
'strict-open',
|
||||
'strict-proxied',
|
||||
])(
|
||||
'should fall back to embedded content successfully for profile "%s"',
|
||||
async (profile) => {
|
||||
vi.mocked(os.platform).mockReturnValue('darwin');
|
||||
// Mock existsSync to return false for the profile file but true for temp directories
|
||||
vi.mocked(fs.existsSync).mockImplementation((p) =>
|
||||
String(p).includes('gemini-sandbox-macos-'),
|
||||
);
|
||||
|
||||
vi.stubEnv('SEATBELT_PROFILE', profile);
|
||||
|
||||
const config: SandboxConfig = createMockSandboxConfig({
|
||||
command: 'sandbox-exec',
|
||||
image: 'some-image',
|
||||
});
|
||||
|
||||
interface MockProcess extends EventEmitter {
|
||||
stdout: EventEmitter;
|
||||
stderr: EventEmitter;
|
||||
}
|
||||
const mockSpawnProcess = new EventEmitter() as MockProcess;
|
||||
mockSpawnProcess.stdout = new EventEmitter();
|
||||
mockSpawnProcess.stderr = new EventEmitter();
|
||||
vi.mocked(spawn).mockReturnValue(
|
||||
mockSpawnProcess as unknown as ReturnType<typeof spawn>,
|
||||
);
|
||||
|
||||
const promise = start_sandbox(config, [], undefined, ['arg1']);
|
||||
|
||||
setTimeout(() => {
|
||||
mockSpawnProcess.emit('close', 0);
|
||||
}, 10);
|
||||
|
||||
await expect(promise).resolves.toBe(0);
|
||||
|
||||
// Verify fs.writeFileSync was called with the correct file mode and content for the profile
|
||||
expect(fs.writeFileSync).toHaveBeenCalledWith(
|
||||
expect.stringContaining(`gemini-sandbox-macos-${profile}-`),
|
||||
expect.stringContaining('deny default'),
|
||||
expect.objectContaining({
|
||||
encoding: 'utf8',
|
||||
mode: 0o600,
|
||||
}),
|
||||
);
|
||||
|
||||
vi.unstubAllEnvs();
|
||||
},
|
||||
);
|
||||
|
||||
it('should handle Docker execution', async () => {
|
||||
const config: SandboxConfig = createMockSandboxConfig({
|
||||
command: 'docker',
|
||||
|
||||
+212
-149
@@ -39,6 +39,7 @@ import {
|
||||
SANDBOX_PROXY_NAME,
|
||||
BUILTIN_SEATBELT_PROFILES,
|
||||
} from './sandboxUtils.js';
|
||||
import { BUILTIN_SEATBELT_PROFILE_CONTENTS } from './sandboxBuiltinProfiles.js';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
const execFileAsync = promisify(execFile);
|
||||
@@ -56,6 +57,41 @@ export async function start_sandbox(
|
||||
patcher.patch();
|
||||
|
||||
let stopProxy: (() => void) | undefined = undefined;
|
||||
let tempProfileFile: string | null = null;
|
||||
|
||||
const cleanup = () => {
|
||||
if (tempProfileFile && fs.existsSync(tempProfileFile)) {
|
||||
try {
|
||||
fs.unlinkSync(tempProfileFile);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
tempProfileFile = null;
|
||||
}
|
||||
if (stopProxy) {
|
||||
try {
|
||||
stopProxy();
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const sigintHandler = () => {
|
||||
cleanup();
|
||||
process.off('SIGINT', sigintHandler);
|
||||
process.kill(process.pid, 'SIGINT');
|
||||
};
|
||||
|
||||
const sigtermHandler = () => {
|
||||
cleanup();
|
||||
process.off('SIGTERM', sigtermHandler);
|
||||
process.kill(process.pid, 'SIGTERM');
|
||||
};
|
||||
|
||||
process.on('exit', cleanup);
|
||||
process.on('SIGINT', sigintHandler);
|
||||
process.on('SIGTERM', sigtermHandler);
|
||||
|
||||
try {
|
||||
if (config.command === 'sandbox-exec') {
|
||||
@@ -81,161 +117,193 @@ export async function start_sandbox(
|
||||
profileFile = fs.existsSync(userProfileFile)
|
||||
? userProfileFile
|
||||
: projectProfileFile;
|
||||
}
|
||||
if (!fs.existsSync(profileFile)) {
|
||||
throw new FatalSandboxError(
|
||||
`Missing macos seatbelt profile file '${profileFile}'`,
|
||||
);
|
||||
}
|
||||
debugLogger.log(`using macos seatbelt (profile: ${profile}) ...`);
|
||||
// if DEBUG is set, convert to --inspect-brk in NODE_OPTIONS
|
||||
const nodeOptions = [
|
||||
...(process.env['DEBUG'] ? ['--inspect-brk'] : []),
|
||||
...nodeArgs,
|
||||
].join(' ');
|
||||
|
||||
const args = [
|
||||
'-D',
|
||||
`TARGET_DIR=${fs.realpathSync(process.cwd())}`,
|
||||
'-D',
|
||||
`TMP_DIR=${fs.realpathSync(os.tmpdir())}`,
|
||||
'-D',
|
||||
`HOME_DIR=${fs.realpathSync(homedir())}`,
|
||||
'-D',
|
||||
`CACHE_DIR=${fs.realpathSync((await execAsync('getconf DARWIN_USER_CACHE_DIR')).stdout.trim())}`,
|
||||
];
|
||||
|
||||
// Add included directories from the workspace context
|
||||
// Always add 5 INCLUDE_DIR parameters to ensure .sb files can reference them
|
||||
const MAX_INCLUDE_DIRS = 5;
|
||||
const targetDir = fs.realpathSync(cliConfig?.getTargetDir() || '');
|
||||
const includedDirs: string[] = [];
|
||||
|
||||
if (cliConfig) {
|
||||
const workspaceContext = cliConfig.getWorkspaceContext();
|
||||
const directories = workspaceContext.getDirectories();
|
||||
|
||||
// Filter out TARGET_DIR
|
||||
for (const dir of directories) {
|
||||
const realDir = fs.realpathSync(dir);
|
||||
if (realDir !== targetDir) {
|
||||
includedDirs.push(realDir);
|
||||
} else {
|
||||
// For builtin profiles, if the file doesn't exist on disk (e.g. bundled or bazel environments),
|
||||
// write the embedded profile content to a temporary file.
|
||||
if (!fs.existsSync(profileFile)) {
|
||||
const content = BUILTIN_SEATBELT_PROFILE_CONTENTS[profile];
|
||||
if (content) {
|
||||
try {
|
||||
const tempDir = fs.realpathSync(os.tmpdir());
|
||||
const rand = randomBytes(8).toString('hex');
|
||||
tempProfileFile = path.join(
|
||||
tempDir,
|
||||
`gemini-sandbox-macos-${profile}-${rand}.sb`,
|
||||
);
|
||||
fs.writeFileSync(tempProfileFile, content, {
|
||||
encoding: 'utf8',
|
||||
mode: 0o600,
|
||||
});
|
||||
profileFile = tempProfileFile;
|
||||
} catch (err) {
|
||||
debugLogger.warn(
|
||||
`Failed to write temporary seatbelt profile: ${err}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add custom allowed paths from config
|
||||
if (config.allowedPaths) {
|
||||
for (const hostPath of config.allowedPaths) {
|
||||
if (
|
||||
hostPath &&
|
||||
path.isAbsolute(hostPath) &&
|
||||
fs.existsSync(hostPath)
|
||||
) {
|
||||
const realDir = fs.realpathSync(hostPath);
|
||||
if (!includedDirs.includes(realDir) && realDir !== targetDir) {
|
||||
try {
|
||||
if (!fs.existsSync(profileFile)) {
|
||||
throw new FatalSandboxError(
|
||||
`Missing macos seatbelt profile file '${profileFile}'`,
|
||||
);
|
||||
}
|
||||
debugLogger.log(`using macos seatbelt (profile: ${profile}) ...`);
|
||||
// if DEBUG is set, convert to --inspect-brk in NODE_OPTIONS
|
||||
const nodeOptions = [
|
||||
...(process.env['DEBUG'] ? ['--inspect-brk'] : []),
|
||||
...nodeArgs,
|
||||
].join(' ');
|
||||
|
||||
const args = [
|
||||
'-D',
|
||||
`TARGET_DIR=${fs.realpathSync(process.cwd())}`,
|
||||
'-D',
|
||||
`TMP_DIR=${fs.realpathSync(os.tmpdir())}`,
|
||||
'-D',
|
||||
`HOME_DIR=${fs.realpathSync(homedir())}`,
|
||||
'-D',
|
||||
`CACHE_DIR=${fs.realpathSync((await execAsync('getconf DARWIN_USER_CACHE_DIR')).stdout.trim())}`,
|
||||
];
|
||||
|
||||
// Add included directories from the workspace context
|
||||
// Always add 5 INCLUDE_DIR parameters to ensure .sb files can reference them
|
||||
const MAX_INCLUDE_DIRS = 5;
|
||||
const targetDir = fs.realpathSync(cliConfig?.getTargetDir() || '');
|
||||
const includedDirs: string[] = [];
|
||||
|
||||
if (cliConfig) {
|
||||
const workspaceContext = cliConfig.getWorkspaceContext();
|
||||
const directories = workspaceContext.getDirectories();
|
||||
|
||||
// Filter out TARGET_DIR
|
||||
for (const dir of directories) {
|
||||
const realDir = fs.realpathSync(dir);
|
||||
if (realDir !== targetDir) {
|
||||
includedDirs.push(realDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < MAX_INCLUDE_DIRS; i++) {
|
||||
let dirPath = '/dev/null'; // Default to a safe path that won't cause issues
|
||||
|
||||
if (i < includedDirs.length) {
|
||||
dirPath = includedDirs[i];
|
||||
}
|
||||
|
||||
args.push('-D', `INCLUDE_DIR_${i}=${dirPath}`);
|
||||
}
|
||||
|
||||
const finalArgv = cliArgs;
|
||||
|
||||
args.push(
|
||||
'-f',
|
||||
profileFile,
|
||||
'sh',
|
||||
'-c',
|
||||
[
|
||||
`SANDBOX=sandbox-exec`,
|
||||
`NODE_OPTIONS="${nodeOptions}"`,
|
||||
...finalArgv.map((arg) => quote([arg])),
|
||||
].join(' '),
|
||||
);
|
||||
// start and set up proxy if GEMINI_SANDBOX_PROXY_COMMAND is set
|
||||
const proxyCommand = process.env['GEMINI_SANDBOX_PROXY_COMMAND'];
|
||||
let proxyProcess: ChildProcess | undefined = undefined;
|
||||
let sandboxProcess: ChildProcess | undefined = undefined;
|
||||
const sandboxEnv = { ...process.env };
|
||||
if (proxyCommand) {
|
||||
const proxy =
|
||||
process.env['HTTPS_PROXY'] ||
|
||||
process.env['https_proxy'] ||
|
||||
process.env['HTTP_PROXY'] ||
|
||||
process.env['http_proxy'] ||
|
||||
'http://localhost:8877';
|
||||
sandboxEnv['HTTPS_PROXY'] = proxy;
|
||||
sandboxEnv['https_proxy'] = proxy; // lower-case can be required, e.g. for curl
|
||||
sandboxEnv['HTTP_PROXY'] = proxy;
|
||||
sandboxEnv['http_proxy'] = proxy;
|
||||
const noProxy = process.env['NO_PROXY'] || process.env['no_proxy'];
|
||||
if (noProxy) {
|
||||
sandboxEnv['NO_PROXY'] = noProxy;
|
||||
sandboxEnv['no_proxy'] = noProxy;
|
||||
}
|
||||
proxyProcess = spawn(proxyCommand, {
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
shell: true,
|
||||
detached: true,
|
||||
});
|
||||
// install handlers to stop proxy on exit/signal
|
||||
stopProxy = () => {
|
||||
debugLogger.log('stopping proxy ...');
|
||||
if (proxyProcess?.pid) {
|
||||
try {
|
||||
process.kill(-proxyProcess.pid, 'SIGTERM');
|
||||
} catch {
|
||||
// ignore
|
||||
// Add custom allowed paths from config
|
||||
if (config.allowedPaths) {
|
||||
for (const hostPath of config.allowedPaths) {
|
||||
if (
|
||||
hostPath &&
|
||||
path.isAbsolute(hostPath) &&
|
||||
fs.existsSync(hostPath)
|
||||
) {
|
||||
const realDir = fs.realpathSync(hostPath);
|
||||
if (!includedDirs.includes(realDir) && realDir !== targetDir) {
|
||||
includedDirs.push(realDir);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
process.on('exit', stopProxy);
|
||||
process.on('SIGINT', stopProxy);
|
||||
process.on('SIGTERM', stopProxy);
|
||||
}
|
||||
|
||||
// commented out as it disrupts ink rendering
|
||||
// proxyProcess.stdout?.on('data', (data) => {
|
||||
// console.info(data.toString());
|
||||
// });
|
||||
proxyProcess.stderr?.on('data', (data) => {
|
||||
debugLogger.debug(`[PROXY STDERR]: ${data.toString().trim()}`);
|
||||
});
|
||||
proxyProcess.on('close', (code, signal) => {
|
||||
if (sandboxProcess?.pid) {
|
||||
process.kill(-sandboxProcess.pid, 'SIGTERM');
|
||||
for (let i = 0; i < MAX_INCLUDE_DIRS; i++) {
|
||||
let dirPath = '/dev/null'; // Default to a safe path that won't cause issues
|
||||
|
||||
if (i < includedDirs.length) {
|
||||
dirPath = includedDirs[i];
|
||||
}
|
||||
throw new FatalSandboxError(
|
||||
`Proxy command '${proxyCommand}' exited with code ${code}, signal ${signal}`,
|
||||
);
|
||||
});
|
||||
debugLogger.log('waiting for proxy to start ...');
|
||||
await execAsync(
|
||||
`until timeout 0.25 curl -s http://localhost:8877; do sleep 0.25; done`,
|
||||
|
||||
args.push('-D', `INCLUDE_DIR_${i}=${dirPath}`);
|
||||
}
|
||||
|
||||
const finalArgv = cliArgs;
|
||||
|
||||
args.push(
|
||||
'-f',
|
||||
profileFile,
|
||||
'sh',
|
||||
'-c',
|
||||
[
|
||||
`SANDBOX=sandbox-exec`,
|
||||
'NODE_OPTIONS=' + quote([nodeOptions]),
|
||||
...finalArgv.map((arg) => quote([arg])),
|
||||
].join(' '),
|
||||
);
|
||||
}
|
||||
// spawn child and let it inherit stdio
|
||||
process.stdin.pause();
|
||||
sandboxProcess = spawn(config.command, args, {
|
||||
stdio: 'inherit',
|
||||
});
|
||||
return await new Promise((resolve, reject) => {
|
||||
sandboxProcess?.on('error', reject);
|
||||
sandboxProcess?.on('close', (code) => {
|
||||
process.stdin.resume();
|
||||
resolve(code ?? 1);
|
||||
// start and set up proxy if GEMINI_SANDBOX_PROXY_COMMAND is set
|
||||
const proxyCommand = process.env['GEMINI_SANDBOX_PROXY_COMMAND'];
|
||||
let proxyProcess: ChildProcess | undefined = undefined;
|
||||
let sandboxProcess: ChildProcess | undefined = undefined;
|
||||
const sandboxEnv = { ...process.env };
|
||||
if (proxyCommand) {
|
||||
const proxy =
|
||||
process.env['HTTPS_PROXY'] ||
|
||||
process.env['https_proxy'] ||
|
||||
process.env['HTTP_PROXY'] ||
|
||||
process.env['http_proxy'] ||
|
||||
'http://localhost:8877';
|
||||
sandboxEnv['HTTPS_PROXY'] = proxy;
|
||||
sandboxEnv['https_proxy'] = proxy; // lower-case can be required, e.g. for curl
|
||||
sandboxEnv['HTTP_PROXY'] = proxy;
|
||||
sandboxEnv['http_proxy'] = proxy;
|
||||
const noProxy = process.env['NO_PROXY'] || process.env['no_proxy'];
|
||||
if (noProxy) {
|
||||
sandboxEnv['NO_PROXY'] = noProxy;
|
||||
sandboxEnv['no_proxy'] = noProxy;
|
||||
}
|
||||
proxyProcess = spawn(proxyCommand, {
|
||||
stdio: ['ignore', 'pipe', 'pipe'],
|
||||
shell: true,
|
||||
detached: true,
|
||||
});
|
||||
// install handlers to stop proxy on exit/signal
|
||||
stopProxy = () => {
|
||||
debugLogger.log('stopping proxy ...');
|
||||
if (proxyProcess?.pid) {
|
||||
try {
|
||||
process.kill(-proxyProcess.pid, 'SIGTERM');
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// commented out as it disrupts ink rendering
|
||||
// proxyProcess.stdout?.on('data', (data) => {
|
||||
// console.info(data.toString());
|
||||
// });
|
||||
proxyProcess.stderr?.on('data', (data) => {
|
||||
debugLogger.debug(`[PROXY STDERR]: ${data.toString().trim()}`);
|
||||
});
|
||||
proxyProcess.on('close', (code, signal) => {
|
||||
if (sandboxProcess?.pid) {
|
||||
process.kill(-sandboxProcess.pid, 'SIGTERM');
|
||||
}
|
||||
throw new FatalSandboxError(
|
||||
`Proxy command '${proxyCommand}' exited with code ${code}, signal ${signal}`,
|
||||
);
|
||||
});
|
||||
debugLogger.log('waiting for proxy to start ...');
|
||||
await execAsync(
|
||||
`until timeout 0.25 curl -s http://localhost:8877; do sleep 0.25; done`,
|
||||
);
|
||||
}
|
||||
// spawn child and let it inherit stdio
|
||||
process.stdin.pause();
|
||||
sandboxProcess = spawn(config.command, args, {
|
||||
stdio: 'inherit',
|
||||
});
|
||||
});
|
||||
return await new Promise((resolve, reject) => {
|
||||
sandboxProcess?.on('error', (err) => {
|
||||
cleanup();
|
||||
reject(err);
|
||||
});
|
||||
sandboxProcess?.on('close', (code) => {
|
||||
process.stdin.resume();
|
||||
cleanup();
|
||||
resolve(code ?? 1);
|
||||
});
|
||||
});
|
||||
} catch (err) {
|
||||
cleanup();
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
if (config.command === 'lxc') {
|
||||
@@ -768,9 +836,6 @@ export async function start_sandbox(
|
||||
// ignore
|
||||
}
|
||||
};
|
||||
process.on('exit', stopProxy);
|
||||
process.on('SIGINT', stopProxy);
|
||||
process.on('SIGTERM', stopProxy);
|
||||
|
||||
// commented out as it disrupts ink rendering
|
||||
// proxyProcess.stdout?.on('data', (data) => {
|
||||
@@ -821,12 +886,10 @@ export async function start_sandbox(
|
||||
});
|
||||
});
|
||||
} finally {
|
||||
if (stopProxy) {
|
||||
stopProxy();
|
||||
process.off('exit', stopProxy);
|
||||
process.off('SIGINT', stopProxy);
|
||||
process.off('SIGTERM', stopProxy);
|
||||
}
|
||||
process.off('exit', cleanup);
|
||||
process.off('SIGINT', sigintHandler);
|
||||
process.off('SIGTERM', sigtermHandler);
|
||||
cleanup();
|
||||
patcher.cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,555 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
export const BUILTIN_SEATBELT_PROFILE_CONTENTS: Record<string, string> = {
|
||||
'permissive-open': `(version 1)
|
||||
(deny default)
|
||||
(allow file-read*)
|
||||
(allow process-exec)
|
||||
(allow process-fork)
|
||||
(allow signal (target self))
|
||||
(allow sysctl-read
|
||||
(sysctl-name "hw.activecpu")
|
||||
(sysctl-name "hw.busfrequency_compat")
|
||||
(sysctl-name "hw.byteorder")
|
||||
(sysctl-name "hw.cacheconfig")
|
||||
(sysctl-name "hw.cachelinesize_compat")
|
||||
(sysctl-name "hw.cpufamily")
|
||||
(sysctl-name "hw.cpufrequency_compat")
|
||||
(sysctl-name "hw.cputype")
|
||||
(sysctl-name "hw.l1dcachesize_compat")
|
||||
(sysctl-name "hw.l1icachesize_compat")
|
||||
(sysctl-name "hw.l2cachesize_compat")
|
||||
(sysctl-name "hw.l3cachesize_compat")
|
||||
(sysctl-name "hw.logicalcpu_max")
|
||||
(sysctl-name "hw.machine")
|
||||
(sysctl-name "hw.ncpu")
|
||||
(sysctl-name "hw.nperflevels")
|
||||
(sysctl-name "hw.optional.arm.FEAT_BF16")
|
||||
(sysctl-name "hw.optional.arm.FEAT_DotProd")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FCMA")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FHM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FP16")
|
||||
(sysctl-name "hw.optional.arm.FEAT_I8MM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_JSCVT")
|
||||
(sysctl-name "hw.optional.arm.FEAT_LSE")
|
||||
(sysctl-name "hw.optional.arm.FEAT_RDM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_SHA512")
|
||||
(sysctl-name "hw.optional.armv8_2_sha512")
|
||||
(sysctl-name "hw.packages")
|
||||
(sysctl-name "hw.pagesize_compat")
|
||||
(sysctl-name "hw.physicalcpu_max")
|
||||
(sysctl-name "hw.tbfrequency_compat")
|
||||
(sysctl-name "hw.vectorunit")
|
||||
(sysctl-name "kern.hostname")
|
||||
(sysctl-name "kern.maxfilesperproc")
|
||||
(sysctl-name "kern.osproductversion")
|
||||
(sysctl-name "kern.osrelease")
|
||||
(sysctl-name "kern.ostype")
|
||||
(sysctl-name "kern.osvariant_status")
|
||||
(sysctl-name "kern.osversion")
|
||||
(sysctl-name "kern.secure_kernel")
|
||||
(sysctl-name "kern.usrstack64")
|
||||
(sysctl-name "kern.version")
|
||||
(sysctl-name "sysctl.proc_cputype")
|
||||
(sysctl-name-prefix "hw.perflevel")
|
||||
)
|
||||
(allow file-write*
|
||||
(subpath (param "TARGET_DIR"))
|
||||
(subpath (param "TMP_DIR"))
|
||||
(subpath (param "CACHE_DIR"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.gemini"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.npm"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.cache"))
|
||||
(subpath (param "INCLUDE_DIR_0"))
|
||||
(subpath (param "INCLUDE_DIR_1"))
|
||||
(subpath (param "INCLUDE_DIR_2"))
|
||||
(subpath (param "INCLUDE_DIR_3"))
|
||||
(subpath (param "INCLUDE_DIR_4"))
|
||||
(literal "/dev/stdout")
|
||||
(literal "/dev/stderr")
|
||||
(literal "/dev/null")
|
||||
(literal "/dev/ptmx")
|
||||
(regex #"^/dev/ttys[0-9]*$")
|
||||
)
|
||||
(allow mach-lookup
|
||||
(global-name "com.apple.sysmond")
|
||||
(global-name "com.apple.system.opendirectoryd.libinfo")
|
||||
(global-name "com.apple.system.opendirectoryd.membership")
|
||||
(global-name "com.apple.bsd.dirhelper")
|
||||
(global-name "com.apple.SecurityServer")
|
||||
(global-name "com.apple.networkd")
|
||||
(global-name "com.apple.ocspd")
|
||||
(global-name "com.apple.trustd")
|
||||
(global-name "com.apple.trustd.agent")
|
||||
(global-name "com.apple.mDNSResponder")
|
||||
(global-name "com.apple.mDNSResponderHelper")
|
||||
(global-name "com.apple.SystemConfiguration.DNSConfiguration")
|
||||
(global-name "com.apple.SystemConfiguration.configd")
|
||||
)
|
||||
(allow system-socket
|
||||
(require-all
|
||||
(socket-domain AF_SYSTEM)
|
||||
(socket-protocol 2)
|
||||
)
|
||||
)
|
||||
(allow file-ioctl (regex #"^/dev/tty.*"))
|
||||
(allow network-inbound (local ip "*:*"))
|
||||
(allow network-bind (local ip "*:*"))
|
||||
(allow network-outbound)`,
|
||||
|
||||
'permissive-proxied': `(version 1)
|
||||
(deny default)
|
||||
(allow file-read*)
|
||||
(allow process-exec)
|
||||
(allow process-fork)
|
||||
(allow signal (target self))
|
||||
(allow sysctl-read
|
||||
(sysctl-name "hw.activecpu")
|
||||
(sysctl-name "hw.busfrequency_compat")
|
||||
(sysctl-name "hw.byteorder")
|
||||
(sysctl-name "hw.cacheconfig")
|
||||
(sysctl-name "hw.cachelinesize_compat")
|
||||
(sysctl-name "hw.cpufamily")
|
||||
(sysctl-name "hw.cpufrequency_compat")
|
||||
(sysctl-name "hw.cputype")
|
||||
(sysctl-name "hw.l1dcachesize_compat")
|
||||
(sysctl-name "hw.l1icachesize_compat")
|
||||
(sysctl-name "hw.l2cachesize_compat")
|
||||
(sysctl-name "hw.l3cachesize_compat")
|
||||
(sysctl-name "hw.logicalcpu_max")
|
||||
(sysctl-name "hw.machine")
|
||||
(sysctl-name "hw.ncpu")
|
||||
(sysctl-name "hw.nperflevels")
|
||||
(sysctl-name "hw.optional.arm.FEAT_BF16")
|
||||
(sysctl-name "hw.optional.arm.FEAT_DotProd")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FCMA")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FHM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FP16")
|
||||
(sysctl-name "hw.optional.arm.FEAT_I8MM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_JSCVT")
|
||||
(sysctl-name "hw.optional.arm.FEAT_LSE")
|
||||
(sysctl-name "hw.optional.arm.FEAT_RDM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_SHA512")
|
||||
(sysctl-name "hw.optional.armv8_2_sha512")
|
||||
(sysctl-name "hw.packages")
|
||||
(sysctl-name "hw.pagesize_compat")
|
||||
(sysctl-name "hw.physicalcpu_max")
|
||||
(sysctl-name "hw.tbfrequency_compat")
|
||||
(sysctl-name "hw.vectorunit")
|
||||
(sysctl-name "kern.hostname")
|
||||
(sysctl-name "kern.maxfilesperproc")
|
||||
(sysctl-name "kern.osproductversion")
|
||||
(sysctl-name "kern.osrelease")
|
||||
(sysctl-name "kern.ostype")
|
||||
(sysctl-name "kern.osvariant_status")
|
||||
(sysctl-name "kern.osversion")
|
||||
(sysctl-name "kern.secure_kernel")
|
||||
(sysctl-name "kern.usrstack64")
|
||||
(sysctl-name "kern.version")
|
||||
(sysctl-name "sysctl.proc_cputype")
|
||||
(sysctl-name-prefix "hw.perflevel")
|
||||
)
|
||||
(allow file-write*
|
||||
(subpath (param "TARGET_DIR"))
|
||||
(subpath (param "TMP_DIR"))
|
||||
(subpath (param "CACHE_DIR"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.gemini"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.npm"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.cache"))
|
||||
(subpath (param "INCLUDE_DIR_0"))
|
||||
(subpath (param "INCLUDE_DIR_1"))
|
||||
(subpath (param "INCLUDE_DIR_2"))
|
||||
(subpath (param "INCLUDE_DIR_3"))
|
||||
(subpath (param "INCLUDE_DIR_4"))
|
||||
(literal "/dev/stdout")
|
||||
(literal "/dev/stderr")
|
||||
(literal "/dev/null")
|
||||
(literal "/dev/ptmx")
|
||||
(regex #"^/dev/ttys[0-9]*$")
|
||||
)
|
||||
(allow mach-lookup
|
||||
(global-name "com.apple.sysmond")
|
||||
(global-name "com.apple.system.opendirectoryd.libinfo")
|
||||
(global-name "com.apple.system.opendirectoryd.membership")
|
||||
(global-name "com.apple.bsd.dirhelper")
|
||||
(global-name "com.apple.SecurityServer")
|
||||
(global-name "com.apple.networkd")
|
||||
(global-name "com.apple.ocspd")
|
||||
(global-name "com.apple.trustd")
|
||||
(global-name "com.apple.trustd.agent")
|
||||
(global-name "com.apple.mDNSResponder")
|
||||
(global-name "com.apple.mDNSResponderHelper")
|
||||
(global-name "com.apple.SystemConfiguration.DNSConfiguration")
|
||||
(global-name "com.apple.SystemConfiguration.configd")
|
||||
)
|
||||
(allow system-socket
|
||||
(require-all
|
||||
(socket-domain AF_SYSTEM)
|
||||
(socket-protocol 2)
|
||||
)
|
||||
)
|
||||
(allow file-ioctl (regex #"^/dev/tty.*"))
|
||||
(allow network-inbound (local ip "localhost:9229"))
|
||||
(allow network-bind (local ip "*:*"))
|
||||
(allow network-outbound (remote tcp "localhost:8877"))`,
|
||||
|
||||
'restrictive-open': `(version 1)
|
||||
(deny default)
|
||||
(allow file-read*)
|
||||
(allow process-exec)
|
||||
(allow process-fork)
|
||||
(allow signal (target self))
|
||||
(allow sysctl-read
|
||||
(sysctl-name "hw.activecpu")
|
||||
(sysctl-name "hw.busfrequency_compat")
|
||||
(sysctl-name "hw.byteorder")
|
||||
(sysctl-name "hw.cacheconfig")
|
||||
(sysctl-name "hw.cachelinesize_compat")
|
||||
(sysctl-name "hw.cpufamily")
|
||||
(sysctl-name "hw.cpufrequency_compat")
|
||||
(sysctl-name "hw.cputype")
|
||||
(sysctl-name "hw.l1dcachesize_compat")
|
||||
(sysctl-name "hw.l1icachesize_compat")
|
||||
(sysctl-name "hw.l2cachesize_compat")
|
||||
(sysctl-name "hw.l3cachesize_compat")
|
||||
(sysctl-name "hw.logicalcpu_max")
|
||||
(sysctl-name "hw.machine")
|
||||
(sysctl-name "hw.ncpu")
|
||||
(sysctl-name "hw.nperflevels")
|
||||
(sysctl-name "hw.optional.arm.FEAT_BF16")
|
||||
(sysctl-name "hw.optional.arm.FEAT_DotProd")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FCMA")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FHM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FP16")
|
||||
(sysctl-name "hw.optional.arm.FEAT_I8MM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_JSCVT")
|
||||
(sysctl-name "hw.optional.arm.FEAT_LSE")
|
||||
(sysctl-name "hw.optional.arm.FEAT_RDM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_SHA512")
|
||||
(sysctl-name "hw.optional.armv8_2_sha512")
|
||||
(sysctl-name "hw.packages")
|
||||
(sysctl-name "hw.pagesize_compat")
|
||||
(sysctl-name "hw.physicalcpu_max")
|
||||
(sysctl-name "hw.tbfrequency_compat")
|
||||
(sysctl-name "hw.vectorunit")
|
||||
(sysctl-name "kern.hostname")
|
||||
(sysctl-name "kern.maxfilesperproc")
|
||||
(sysctl-name "kern.osproductversion")
|
||||
(sysctl-name "kern.osrelease")
|
||||
(sysctl-name "kern.ostype")
|
||||
(sysctl-name "kern.osvariant_status")
|
||||
(sysctl-name "kern.osversion")
|
||||
(sysctl-name "kern.secure_kernel")
|
||||
(sysctl-name "kern.usrstack64")
|
||||
(sysctl-name "kern.version")
|
||||
(sysctl-name "sysctl.proc_cputype")
|
||||
(sysctl-name-prefix "hw.perflevel")
|
||||
)
|
||||
(allow file-write*
|
||||
(subpath (param "TARGET_DIR"))
|
||||
(subpath (param "TMP_DIR"))
|
||||
(subpath (param "CACHE_DIR"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.gemini"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.npm"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.cache"))
|
||||
(subpath (param "INCLUDE_DIR_0"))
|
||||
(subpath (param "INCLUDE_DIR_1"))
|
||||
(subpath (param "INCLUDE_DIR_2"))
|
||||
(subpath (param "INCLUDE_DIR_3"))
|
||||
(subpath (param "INCLUDE_DIR_4"))
|
||||
(literal "/dev/stdout")
|
||||
(literal "/dev/stderr")
|
||||
(literal "/dev/null")
|
||||
)
|
||||
(allow mach-lookup (global-name "com.apple.sysmond"))
|
||||
(allow file-ioctl (regex #"^/dev/tty.*"))
|
||||
(allow network-inbound (local ip "localhost:9229"))
|
||||
(allow network-outbound)`,
|
||||
|
||||
'restrictive-proxied': `(version 1)
|
||||
(deny default)
|
||||
(allow file-read*)
|
||||
(allow process-exec)
|
||||
(allow process-fork)
|
||||
(allow signal (target self))
|
||||
(allow sysctl-read
|
||||
(sysctl-name "hw.activecpu")
|
||||
(sysctl-name "hw.busfrequency_compat")
|
||||
(sysctl-name "hw.byteorder")
|
||||
(sysctl-name "hw.cacheconfig")
|
||||
(sysctl-name "hw.cachelinesize_compat")
|
||||
(sysctl-name "hw.cpufamily")
|
||||
(sysctl-name "hw.cpufrequency_compat")
|
||||
(sysctl-name "hw.cputype")
|
||||
(sysctl-name "hw.l1dcachesize_compat")
|
||||
(sysctl-name "hw.l1icachesize_compat")
|
||||
(sysctl-name "hw.l2cachesize_compat")
|
||||
(sysctl-name "hw.l3cachesize_compat")
|
||||
(sysctl-name "hw.logicalcpu_max")
|
||||
(sysctl-name "hw.machine")
|
||||
(sysctl-name "hw.ncpu")
|
||||
(sysctl-name "hw.nperflevels")
|
||||
(sysctl-name "hw.optional.arm.FEAT_BF16")
|
||||
(sysctl-name "hw.optional.arm.FEAT_DotProd")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FCMA")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FHM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FP16")
|
||||
(sysctl-name "hw.optional.arm.FEAT_I8MM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_JSCVT")
|
||||
(sysctl-name "hw.optional.arm.FEAT_LSE")
|
||||
(sysctl-name "hw.optional.arm.FEAT_RDM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_SHA512")
|
||||
(sysctl-name "hw.optional.armv8_2_sha512")
|
||||
(sysctl-name "hw.packages")
|
||||
(sysctl-name "hw.pagesize_compat")
|
||||
(sysctl-name "hw.physicalcpu_max")
|
||||
(sysctl-name "hw.tbfrequency_compat")
|
||||
(sysctl-name "hw.vectorunit")
|
||||
(sysctl-name "kern.hostname")
|
||||
(sysctl-name "kern.maxfilesperproc")
|
||||
(sysctl-name "kern.osproductversion")
|
||||
(sysctl-name "kern.osrelease")
|
||||
(sysctl-name "kern.ostype")
|
||||
(sysctl-name "kern.osvariant_status")
|
||||
(sysctl-name "kern.osversion")
|
||||
(sysctl-name "kern.secure_kernel")
|
||||
(sysctl-name "kern.usrstack64")
|
||||
(sysctl-name "kern.version")
|
||||
(sysctl-name "sysctl.proc_cputype")
|
||||
(sysctl-name-prefix "hw.perflevel")
|
||||
)
|
||||
(allow file-write*
|
||||
(subpath (param "TARGET_DIR"))
|
||||
(subpath (param "TMP_DIR"))
|
||||
(subpath (param "CACHE_DIR"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.gemini"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.npm"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.cache"))
|
||||
(subpath (param "INCLUDE_DIR_0"))
|
||||
(subpath (param "INCLUDE_DIR_1"))
|
||||
(subpath (param "INCLUDE_DIR_2"))
|
||||
(subpath (param "INCLUDE_DIR_3"))
|
||||
(subpath (param "INCLUDE_DIR_4"))
|
||||
(literal "/dev/stdout")
|
||||
(literal "/dev/stderr")
|
||||
(literal "/dev/null")
|
||||
)
|
||||
(allow mach-lookup (global-name "com.apple.sysmond"))
|
||||
(allow file-ioctl (regex #"^/dev/tty.*"))
|
||||
(allow network-inbound (local ip "localhost:9229"))
|
||||
(allow network-outbound (remote tcp "localhost:8877"))`,
|
||||
|
||||
'strict-open': `(version 1)
|
||||
(deny default)
|
||||
(allow file-read*
|
||||
(literal "/")
|
||||
(subpath (param "TARGET_DIR"))
|
||||
(subpath (param "TMP_DIR"))
|
||||
(subpath (param "CACHE_DIR"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.gemini"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.npm"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.cache"))
|
||||
(literal (string-append (param "HOME_DIR") "/.gitconfig"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.nvm"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.fnm"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.node"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.config"))
|
||||
(subpath (param "INCLUDE_DIR_0"))
|
||||
(subpath (param "INCLUDE_DIR_1"))
|
||||
(subpath (param "INCLUDE_DIR_2"))
|
||||
(subpath (param "INCLUDE_DIR_3"))
|
||||
(subpath (param "INCLUDE_DIR_4"))
|
||||
(subpath "/usr")
|
||||
(subpath "/bin")
|
||||
(subpath "/sbin")
|
||||
(subpath "/Library")
|
||||
(subpath "/System")
|
||||
(subpath "/private")
|
||||
(subpath "/dev")
|
||||
(subpath "/etc")
|
||||
(subpath "/opt")
|
||||
(subpath "/Applications")
|
||||
)
|
||||
(allow file-read-metadata)
|
||||
(allow process-exec)
|
||||
(allow process-fork)
|
||||
(allow signal (target self))
|
||||
(allow sysctl-read
|
||||
(sysctl-name "hw.activecpu")
|
||||
(sysctl-name "hw.busfrequency_compat")
|
||||
(sysctl-name "hw.byteorder")
|
||||
(sysctl-name "hw.cacheconfig")
|
||||
(sysctl-name "hw.cachelinesize_compat")
|
||||
(sysctl-name "hw.cpufamily")
|
||||
(sysctl-name "hw.cpufrequency_compat")
|
||||
(sysctl-name "hw.cputype")
|
||||
(sysctl-name "hw.l1dcachesize_compat")
|
||||
(sysctl-name "hw.l1icachesize_compat")
|
||||
(sysctl-name "hw.l2cachesize_compat")
|
||||
(sysctl-name "hw.l3cachesize_compat")
|
||||
(sysctl-name "hw.logicalcpu_max")
|
||||
(sysctl-name "hw.machine")
|
||||
(sysctl-name "hw.ncpu")
|
||||
(sysctl-name "hw.nperflevels")
|
||||
(sysctl-name "hw.optional.arm.FEAT_BF16")
|
||||
(sysctl-name "hw.optional.arm.FEAT_DotProd")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FCMA")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FHM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FP16")
|
||||
(sysctl-name "hw.optional.arm.FEAT_I8MM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_JSCVT")
|
||||
(sysctl-name "hw.optional.arm.FEAT_LSE")
|
||||
(sysctl-name "hw.optional.arm.FEAT_RDM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_SHA512")
|
||||
(sysctl-name "hw.optional.armv8_2_sha512")
|
||||
(sysctl-name "hw.packages")
|
||||
(sysctl-name "hw.pagesize_compat")
|
||||
(sysctl-name "hw.physicalcpu_max")
|
||||
(sysctl-name "hw.tbfrequency_compat")
|
||||
(sysctl-name "hw.vectorunit")
|
||||
(sysctl-name "kern.hostname")
|
||||
(sysctl-name "kern.maxfilesperproc")
|
||||
(sysctl-name "kern.osproductversion")
|
||||
(sysctl-name "kern.osrelease")
|
||||
(sysctl-name "kern.ostype")
|
||||
(sysctl-name "kern.osvariant_status")
|
||||
(sysctl-name "kern.osversion")
|
||||
(sysctl-name "kern.secure_kernel")
|
||||
(sysctl-name "kern.usrstack64")
|
||||
(sysctl-name "kern.version")
|
||||
(sysctl-name "sysctl.proc_cputype")
|
||||
(sysctl-name-prefix "hw.perflevel")
|
||||
)
|
||||
(allow file-write*
|
||||
(subpath (param "TARGET_DIR"))
|
||||
(subpath (param "TMP_DIR"))
|
||||
(subpath (param "CACHE_DIR"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.gemini"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.npm"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.cache"))
|
||||
(subpath (param "INCLUDE_DIR_0"))
|
||||
(subpath (param "INCLUDE_DIR_1"))
|
||||
(subpath (param "INCLUDE_DIR_2"))
|
||||
(subpath (param "INCLUDE_DIR_3"))
|
||||
(subpath (param "INCLUDE_DIR_4"))
|
||||
(literal "/dev/stdout")
|
||||
(literal "/dev/stderr")
|
||||
(literal "/dev/null")
|
||||
)
|
||||
(allow mach-lookup (global-name "com.apple.sysmond"))
|
||||
(allow file-ioctl (regex #"^/dev/tty.*"))
|
||||
(allow network-inbound (local ip "localhost:9229"))
|
||||
(allow network-outbound)`,
|
||||
|
||||
'strict-proxied': `(version 1)
|
||||
(deny default)
|
||||
(allow file-read*
|
||||
(literal "/")
|
||||
(subpath (param "TARGET_DIR"))
|
||||
(subpath (param "TMP_DIR"))
|
||||
(subpath (param "CACHE_DIR"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.gemini"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.npm"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.cache"))
|
||||
(literal (string-append (param "HOME_DIR") "/.gitconfig"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.nvm"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.fnm"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.node"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.config"))
|
||||
(subpath (param "INCLUDE_DIR_0"))
|
||||
(subpath (param "INCLUDE_DIR_1"))
|
||||
(subpath (param "INCLUDE_DIR_2"))
|
||||
(subpath (param "INCLUDE_DIR_3"))
|
||||
(subpath (param "INCLUDE_DIR_4"))
|
||||
(subpath "/usr")
|
||||
(subpath "/bin")
|
||||
(subpath "/sbin")
|
||||
(subpath "/Library")
|
||||
(subpath "/System")
|
||||
(subpath "/private")
|
||||
(subpath "/dev")
|
||||
(subpath "/etc")
|
||||
(subpath "/opt")
|
||||
(subpath "/Applications")
|
||||
)
|
||||
(allow file-read-metadata)
|
||||
(allow process-exec)
|
||||
(allow process-fork)
|
||||
(allow signal (target self))
|
||||
(allow sysctl-read
|
||||
(sysctl-name "hw.activecpu")
|
||||
(sysctl-name "hw.busfrequency_compat")
|
||||
(sysctl-name "hw.byteorder")
|
||||
(sysctl-name "hw.cacheconfig")
|
||||
(sysctl-name "hw.cachelinesize_compat")
|
||||
(sysctl-name "hw.cpufamily")
|
||||
(sysctl-name "hw.cpufrequency_compat")
|
||||
(sysctl-name "hw.cputype")
|
||||
(sysctl-name "hw.l1dcachesize_compat")
|
||||
(sysctl-name "hw.l1icachesize_compat")
|
||||
(sysctl-name "hw.l2cachesize_compat")
|
||||
(sysctl-name "hw.l3cachesize_compat")
|
||||
(sysctl-name "hw.logicalcpu_max")
|
||||
(sysctl-name "hw.machine")
|
||||
(sysctl-name "hw.ncpu")
|
||||
(sysctl-name "hw.nperflevels")
|
||||
(sysctl-name "hw.optional.arm.FEAT_BF16")
|
||||
(sysctl-name "hw.optional.arm.FEAT_DotProd")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FCMA")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FHM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_FP16")
|
||||
(sysctl-name "hw.optional.arm.FEAT_I8MM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_JSCVT")
|
||||
(sysctl-name "hw.optional.arm.FEAT_LSE")
|
||||
(sysctl-name "hw.optional.arm.FEAT_RDM")
|
||||
(sysctl-name "hw.optional.arm.FEAT_SHA512")
|
||||
(sysctl-name "hw.optional.armv8_2_sha512")
|
||||
(sysctl-name "hw.packages")
|
||||
(sysctl-name "hw.pagesize_compat")
|
||||
(sysctl-name "hw.physicalcpu_max")
|
||||
(sysctl-name "hw.tbfrequency_compat")
|
||||
(sysctl-name "hw.vectorunit")
|
||||
(sysctl-name "kern.hostname")
|
||||
(sysctl-name "kern.maxfilesperproc")
|
||||
(sysctl-name "kern.osproductversion")
|
||||
(sysctl-name "kern.osrelease")
|
||||
(sysctl-name "kern.ostype")
|
||||
(sysctl-name "kern.osvariant_status")
|
||||
(sysctl-name "kern.osversion")
|
||||
(sysctl-name "kern.secure_kernel")
|
||||
(sysctl-name "kern.usrstack64")
|
||||
(sysctl-name "kern.version")
|
||||
(sysctl-name "sysctl.proc_cputype")
|
||||
(sysctl-name-prefix "hw.perflevel")
|
||||
)
|
||||
(allow file-write*
|
||||
(subpath (param "TARGET_DIR"))
|
||||
(subpath (param "TMP_DIR"))
|
||||
(subpath (param "CACHE_DIR"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.gemini"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.npm"))
|
||||
(subpath (string-append (param "HOME_DIR") "/.cache"))
|
||||
(subpath (param "INCLUDE_DIR_0"))
|
||||
(subpath (param "INCLUDE_DIR_1"))
|
||||
(subpath (param "INCLUDE_DIR_2"))
|
||||
(subpath (param "INCLUDE_DIR_3"))
|
||||
(subpath (param "INCLUDE_DIR_4"))
|
||||
(literal "/dev/stdout")
|
||||
(literal "/dev/stderr")
|
||||
(literal "/dev/null")
|
||||
)
|
||||
(allow mach-lookup (global-name "com.apple.sysmond"))
|
||||
(allow file-ioctl (regex #"^/dev/tty.*"))
|
||||
(allow network-inbound (local ip "localhost:9229"))
|
||||
(allow network-outbound (remote tcp "localhost:8877"))`,
|
||||
};
|
||||
|
||||
// Map standard 'closed' profiles to their strict counterparts for backward compatibility and fallback support
|
||||
BUILTIN_SEATBELT_PROFILE_CONTENTS['permissive-closed'] =
|
||||
BUILTIN_SEATBELT_PROFILE_CONTENTS['strict-open'];
|
||||
BUILTIN_SEATBELT_PROFILE_CONTENTS['restrictive-closed'] =
|
||||
BUILTIN_SEATBELT_PROFILE_CONTENTS['strict-proxied'];
|
||||
@@ -15,8 +15,10 @@ export const SANDBOX_NETWORK_NAME = 'gemini-cli-sandbox';
|
||||
export const SANDBOX_PROXY_NAME = 'gemini-cli-sandbox-proxy';
|
||||
export const BUILTIN_SEATBELT_PROFILES = [
|
||||
'permissive-open',
|
||||
'permissive-closed',
|
||||
'permissive-proxied',
|
||||
'restrictive-open',
|
||||
'restrictive-closed',
|
||||
'restrictive-proxied',
|
||||
'strict-open',
|
||||
'strict-proxied',
|
||||
|
||||
Reference in New Issue
Block a user