70 lines
2.0 KiB
JavaScript
70 lines
2.0 KiB
JavaScript
/** Permission + shell policy with no Bare imports (unit-testable on Node). */
|
|
|
|
const WRITE_TOOLS = new Set(['search_replace', 'write_file', 'run_terminal_cmd', 'use_tool']);
|
|
const ASK_TOOLS = new Set(['run_terminal_cmd', 'use_tool']);
|
|
// web_fetch, fetch_page, google_search, web_search, wiki_search, hn_search, and code_search are public reads; they do not prompt.
|
|
const SHELL_ALLOW = new Set([
|
|
'git', 'rg', 'grep', 'ls', 'cat', 'head', 'tail', 'pwd', 'echo', 'node', 'npm', 'npx',
|
|
'python3', 'python', 'cargo', 'go', 'make', 'bare', 'wc', 'sort', 'uniq', 'find', 'sed', 'awk',
|
|
]);
|
|
const SHELL_UNSAFE = /[;|`$()<>\n]|&&|\|\|/;
|
|
const SHELL_REMEMBER_PREFIXES = ['git status', 'git diff'];
|
|
|
|
function needsPermission(toolName, mode) {
|
|
if (mode === 'always-approve') return false;
|
|
if (mode === 'allowlist') return ASK_TOOLS.has(toolName);
|
|
return WRITE_TOOLS.has(toolName) || ASK_TOOLS.has(toolName);
|
|
}
|
|
|
|
function shellName(command) {
|
|
const c = String(command || '').trim();
|
|
const first = c.split(/\s+/)[0] || '';
|
|
return first.replace(/^["']|["']$/g, '').split(/[/\\]/).pop();
|
|
}
|
|
|
|
function shellAllowlisted(command) {
|
|
return SHELL_ALLOW.has(shellName(command));
|
|
}
|
|
|
|
function shellSafe(command) {
|
|
const c = String(command || '');
|
|
if (!c.trim()) return false;
|
|
if (SHELL_UNSAFE.test(c)) return false;
|
|
return shellAllowlisted(c);
|
|
}
|
|
|
|
function shellPrefix(command, n) {
|
|
return String(command || '')
|
|
.trim()
|
|
.split(/\s+/)
|
|
.slice(0, n || 2)
|
|
.join(' ');
|
|
}
|
|
|
|
function matchesCommandPrefix(command, pattern) {
|
|
const c = String(command || '').trim();
|
|
const p = String(pattern || '').trim();
|
|
if (!p) return false;
|
|
if (c === p) return true;
|
|
if (c.indexOf(p + ' ') === 0) return true;
|
|
return false;
|
|
}
|
|
|
|
function isRememberableShell(command) {
|
|
return SHELL_REMEMBER_PREFIXES.some((p) => matchesCommandPrefix(command, p));
|
|
}
|
|
|
|
module.exports = {
|
|
WRITE_TOOLS,
|
|
ASK_TOOLS,
|
|
SHELL_ALLOW,
|
|
SHELL_REMEMBER_PREFIXES,
|
|
needsPermission,
|
|
shellName,
|
|
shellAllowlisted,
|
|
shellSafe,
|
|
shellPrefix,
|
|
matchesCommandPrefix,
|
|
isRememberableShell,
|
|
};
|