124 lines
3.2 KiB
TypeScript
124 lines
3.2 KiB
TypeScript
/**
|
|
* Política de solo lectura para agentes con `acceptanceRole: read-only`.
|
|
*
|
|
* Lista de comandos bash considerados seguros (solo lectura). Cualquier
|
|
* comando destructivo se bloquea aunque contenga un comando seguro como
|
|
* subcadena (p. ej. `cat fichero && rm -rf /`).
|
|
*/
|
|
|
|
const DESTRUCTIVE_PATTERNS: RegExp[] = [
|
|
/\brm\b/i,
|
|
/\brmdir\b/i,
|
|
/\bmv\b/i,
|
|
/\bcp\b/i,
|
|
/\bmkdir\b/i,
|
|
/\btouch\b/i,
|
|
/\bchmod\b/i,
|
|
/\bchown\b/i,
|
|
/\bchgrp\b/i,
|
|
/\bln\b/i,
|
|
/\btee\b/i,
|
|
/\btruncate\b/i,
|
|
/\bdd\b/i,
|
|
/\bshred\b/i,
|
|
/(^|[^<])\s*>\s*[^&]/,
|
|
/\s>>\s/,
|
|
/\bnpm\s+(install|uninstall|update|ci|link|publish|patch)/i,
|
|
/\byarn\s+(add|remove|install|publish)/i,
|
|
/\bpnpm\s+(add|remove|install|publish)/i,
|
|
/\bbun\s+(add|remove|install|pm)/i,
|
|
/\bpip\s+(install|uninstall)/i,
|
|
/\buv\s+(pip\s+)?(install|sync|add)/i,
|
|
/\bapt(-get)?\s+(install|remove|purge|update|upgrade)/i,
|
|
/\bbrew\s+(install|uninstall|upgrade|update)/i,
|
|
/\bgit\s+(add|commit|push|pull|merge|rebase|reset|checkout|branch\s+-[dD]|stash|cherry-pick|revert|tag|init|clone|restore|apply)/i,
|
|
/\bsudo\b/i,
|
|
/\bsu\b/i,
|
|
/\bkill\b/i,
|
|
/\bpkill\b/i,
|
|
/\bkillall\b/i,
|
|
/\breboot\b/i,
|
|
/\bshutdown\b/i,
|
|
/\bsystemctl\s+(start|stop|restart|enable|disable)/i,
|
|
/\bservice\s+\S+\s+(start|stop|restart)/i,
|
|
/\b(vim?|nano|emacs|code|subl|helix)\b/i,
|
|
];
|
|
|
|
const SAFE_PATTERNS: RegExp[] = [
|
|
/^\s*cat\b/,
|
|
/^\s*head\b/,
|
|
/^\s*tail\b/,
|
|
/^\s*less\b/,
|
|
/^\s*more\b/,
|
|
/^\s*grep\b/,
|
|
/^\s*find\b/,
|
|
/^\s*fd\b/,
|
|
/^\s*rg\b/,
|
|
/^\s*ls\b/,
|
|
/^\s*pwd\b/,
|
|
/^\s*echo\b/,
|
|
/^\s*printf\b/,
|
|
/^\s*wc\b/,
|
|
/^\s*sort\b/,
|
|
/^\s*uniq\b/,
|
|
/^\s*diff\b/,
|
|
/^\s*file\b/,
|
|
/^\s*stat\b/,
|
|
/^\s*du\b/,
|
|
/^\s*df\b/,
|
|
/^\s*tree\b/,
|
|
/^\s*which\b/,
|
|
/^\s*whereis\b/,
|
|
/^\s*type\b/,
|
|
/^\s*env\b/,
|
|
/^\s*printenv\b/,
|
|
/^\s*uname\b/,
|
|
/^\s*whoami\b/,
|
|
/^\s*id\b/,
|
|
/^\s*date\b/,
|
|
/^\s*cal\b/,
|
|
/^\s*uptime\b/,
|
|
/^\s*ps\b/,
|
|
/^\s*top\b/,
|
|
/^\s*htop\b/,
|
|
/^\s*free\b/,
|
|
/^\s*bat\b/,
|
|
/^\s*eza\b/,
|
|
/^\s*jq\b/,
|
|
/^\s*sed\s+-n/i,
|
|
/^\s*awk\b/,
|
|
/^\s*git\s+(status|log|diff|show|branch|remote|config\s+--get|blame|shortlog|describe|ls-files|ls-remote|fetch\s+--dry-run)/i,
|
|
/^\s*git\s+ls-/i,
|
|
/^\s*npm\s+(list|ls|view|info|search|outdated|audit|explain)/i,
|
|
/^\s*yarn\s+(list|info|why|audit)/i,
|
|
/^\s*node\s+--version/i,
|
|
/^\s*python[0-9.]*\s+--version/i,
|
|
/^\s*curl\s+[^\n]*(\s--\s*$|\s-[A-Za-z]*I|\s--head|\s--location.*--remote-header-name)/i,
|
|
/^\s*wget\s+-O\s*-|\s*wget\s+--spider/i,
|
|
/^\s*jq\b/,
|
|
];
|
|
|
|
/**
|
|
* Redirecciones inocuas que no deben contarse como destructivas:
|
|
* duplicación de descriptores (`2>&1`, `>&2`) y envío a /dev/null
|
|
* (`2>/dev/null`, `>>/dev/null`).
|
|
*/
|
|
function stripHarmlessRedirects(command: string): string {
|
|
return command
|
|
.replace(/(\d*)>{1,2}\s*\/dev\/null/g, " ")
|
|
.replace(/(\d*)>\s*&\d+/g, " ");
|
|
}
|
|
|
|
/**
|
|
* true si el comando bash es seguro en modo solo lectura:
|
|
* coincide con la lista de comandos seguros y no contiene nada destructivo.
|
|
*/
|
|
export function isReadOnlySafeCommand(command: string): boolean {
|
|
const normalized = command.trim();
|
|
if (!normalized) return false;
|
|
const stripped = stripHarmlessRedirects(normalized);
|
|
const isDestructive = DESTRUCTIVE_PATTERNS.some((p) => p.test(stripped));
|
|
if (isDestructive) return false;
|
|
return SAFE_PATTERNS.some((p) => p.test(normalized));
|
|
}
|