/** * Configuration for the "prevent-destructive-commands" extension. * * Faithful port of the Claude hook `prevent-destructive-commands.py`: * all blacklists and behavior flags live here, so modifying this single * file is enough to tune the protection. */ // ============================================================================= // Command Categories // ============================================================================= /** * Commands that receive paths as arguments: their targets are validated * against the current working directory. */ export const PATH_SENSITIVE_COMMANDS: ReadonlySet = new Set([ "rm", "unlink", "rmdir", "shred", "del", "erase", ]); /** * Commands that read file content: used to detect access to sensitive * files (e.g., `.env`, SSH keys, credentials). */ export const FILE_READING_COMMANDS: ReadonlySet = new Set([ "cat", "less", "more", "head", "tail", "grep", "egrep", "fgrep", "awk", "sed", "cut", "sort", "uniq", "xxd", "hexdump", "strings", "base64", "openssl", "jq", "yq", "bat", "tac", "nl", "od", "rev", ]); /** * File name patterns considered sensitive. Matching is case-insensitive * and checks both `includes` and `endsWith`, as in the original Claude plugin. */ export const SENSITIVE_FILE_PATTERNS: readonly string[] = [ // Environment files ".env", ".env.local", ".env.production", ".env.development", ".env.test", ".env.staging", ".envrc", // SSH keys "id_rsa", "id_dsa", "id_ecdsa", "id_ed25519", "id_rsa.pub", "id_dsa.pub", "id_ecdsa.pub", "id_ed25519.pub", "authorized_keys", "known_hosts", // AWS credentials "credentials", "config", // Database credentials ".pgpass", ".my.cnf", ".netrc", // Package registry ".npmrc", ".pypirc", "pip.conf", // Other secrets ".htpasswd", "vault-password", "secret", "secrets", "secret.json", "secrets.json", "secret.yaml", "secrets.yaml", "secret.yml", "secrets.yml", // Private keys ".key", ".pem", ".p12", ".pfx", ".pkcs12", "private_key", "private-key", ]; // ============================================================================= // AWS / Docker Destructive Operations // ============================================================================= /** * Destructive AWS CLI subcommands, matched as " ". */ export const AWS_DESTRUCTIVE_SUBCOMMANDS: ReadonlySet = new Set([ "s3 rm", "s3 mv", "s3 rb", "s3api delete-object", "s3api delete-objects", "s3api delete-bucket", "ec2 terminate-instances", "ec2 delete-security-group", "ec2 delete-vpc", "ec2 delete-subnet", "ec2 delete-volume", "ec2 delete-snapshot", "ec2 delete-key-pair", "rds delete-db-instance", "rds delete-db-cluster", "rds delete-db-snapshot", "rds delete-db-cluster-snapshot", "rds delete-db-parameter-group", "rds delete-db-subnet-group", "rds delete-db-security-group", "rds delete-global-cluster", "dynamodb delete-table", "lambda delete-function", "lambda delete-alias", "lambda delete-event-source-mapping", "lambda delete-layer-version", "lambda delete-provisioned-concurrency-config", "lambda delete-function-concurrency", "lambda delete-function-url-config", "lambda delete-code-signing-config", "iam delete-user", "iam delete-role", "iam delete-policy", "cloudformation delete-stack", "cloudformation delete-stack-instances", "cloudformation delete-stack-set", "cloudformation delete-change-set", "eks delete-cluster", "ecs delete-cluster", "ecs delete-service", "secretsmanager delete-secret", "kms schedule-key-deletion", "kms disable-key", "sns delete-topic", "sqs delete-queue", ]); /** Destructive Docker subcommands in legacy form (`docker rm`). */ export const DOCKER_DESTRUCTIVE_SUBCOMMANDS: ReadonlySet = new Set(["rm", "rmi"]); /** Destructive Docker subcommands in modern form (`docker container rm`). */ export const DOCKER_DESTRUCTIVE_COMPOUND: ReadonlySet = new Set([ "container rm", "image rm", "volume rm", "network rm", "container prune", "image prune", "volume prune", "network prune", "system prune", "builder prune", ]); // ============================================================================= // Wrapper / Delegation Commands // ============================================================================= /** * Wrapper commands that delegate to the real command in the next token * (e.g., `sudo rm`, `env -i rm`, `timeout 10 rm`). These are skipped during analysis. */ export const WRAPPER_COMMANDS: ReadonlySet = new Set([ "sudo", "env", "nice", "nohup", "timeout", "ionice", "time", ]); /** * Commands that execute the first non-flag positional argument as a command, * given as a quoted string to be re-tokenized (e.g., `watch "rm foo"`). */ export const QUOTED_COMMAND_WRAPPERS: ReadonlySet = new Set([ "watch", "strace", "ltrace", ]); /** Shell invocations within which to recurse for the `-c` argument. */ export const SHELL_COMMANDS: ReadonlySet = new Set([ "bash", "sh", "zsh", "fish", "dash", "ksh", ]); /** Commands that pipe their arguments as a new command. */ export const DELEGATION_COMMANDS: ReadonlySet = new Set(["xargs", "parallel"]); /** * Commands for which a heredoc on the command line means the body is *executed* * (as a shell script, program, editor script, remote command, …) rather than * being consumed as plain data. When one of these appears on a command line * that carries a heredoc, the body is still analyzed as a command; otherwise * the body is treated as data and skipped. Shells and delegation commands are * included automatically. Kept deliberately generous: listing a harmless * command here only costs some analysis of the body, never a bypass. */ export const HEREDOC_EXECUTOR_COMMANDS: ReadonlySet = new Set([ ...SHELL_COMMANDS, ...DELEGATION_COMMANDS, ".", "eval", "exec", "source", "awk", "sed", "ed", "ex", "python", "python2", "python3", "node", "ruby", "perl", "php", "lua", "Rscript", "osascript", "powershell", "pwsh", "expect", "ssh", "crontab", "sqlite3", "psql", "mysql", ]); /** `find` flags that delegate execution. */ export const FIND_EXEC_FLAGS: ReadonlySet = new Set([ "-exec", "-execdir", "-ok", "-okdir", ]); /** * Shell operators recognized as token separators by the tokenizer. * Must stay aligned with `tokenizer.ts`. * * `{` and `}` are deliberately excluded: forcing them to always split as * standalone tokens broke the `find -exec ... {} \;` placeholder, which * must survive tokenization as a single `"{}"` token (real shells only * treat `{`/`}` specially as whitespace-delimited reserved words starting * a compound command, not when glued together like this). */ export const SHELL_OPERATORS: ReadonlySet = new Set([ "|", ";", "&&", "||", "&", "(", ")", ">", "<", ">>", "<<", "2>", "2>>", ]); // ============================================================================= // Behavior Flags // ============================================================================= /** * If `true`, also blocks `git add` and `git commit`. * Consistent with projects where the agent should not create commits autonomously. */ export const ENABLE_GIT_ADD_COMMIT_BLOCK = true; /** * If `true`, blocks file reading commands (`cat`, `grep`, ...) when they * target sensitive files (`.env`, SSH keys, credentials). * * Disabled by default: the original plugin's substring matching is very noisy * in a coding workflow (e.g., "config" matches tsconfig, vite.config, next.config; * ".env" matches .environment.ts). Enable only if needed, aware of the false * positives, or refine the patterns below (e.g., remove generic "config"/"secret" * and keep only forms with extensions). */ export const ENABLE_SENSITIVE_FILE_CHECK = false; /** Maximum nesting depth before considering the command obfuscated. */ export const MAX_NESTING_DEPTH = 5; // ─── Protezione path in scrittura ──────────────────────────────────────────── /** * Path (relativi alla working directory) protetti dalla scrittura: nessuno * strumento di scrittura (write/edit/apply_patch) né comando bash deve * modificarli, sovrascriverli o crearli. Pensati per asset immutabili come le * documentazione immutabile. Il match è per prefisso normalizzato contro * il cwd: qualunque path che risolva sotto uno di questi viene bloccato. */ export const WRITE_PROTECTED_PATHS: readonly string[] = ["docs/specs/guards"]; /** * Se `true`, attiva la protezione in scrittura dei path in * WRITE_PROTECTED_PATHS sia per i tool di scrittura che per i comandi bash. */ export const ENABLE_WRITE_PROTECTION = true; /** * Comandi bash che scrivono/sovrascrivono/modificano file: i loro argomenti * path vengono validati contro WRITE_PROTECTED_PATHS. Il controllo è su tutti * gli argomenti non-flag (conservativo: blocca anche se il path protetto è la * sorgente di una `cp`, per stare sul sicuro). */ export const WRITE_COMMANDS: ReadonlySet = new Set([ "cp", "mv", "install", "tee", "truncate", "dd", "chmod", "chown", "chgrp", "ln", ]); /** * Operatori di redirect che scrivono su file: il token immediatamente * successivo è il path di destinazione e va protetto. */ export const WRITE_REDIRECT_OPERATORS: ReadonlySet = new Set([ ">", ">>", "2>", "2>>", "&>", "&>>", ]);