80 lines
1.6 KiB
Python
80 lines
1.6 KiB
Python
from dataclasses import dataclass
|
|
|
|
|
|
SAFE_COMMAND_PREFIXES = (
|
|
"pwd",
|
|
"ls",
|
|
"cat",
|
|
"head",
|
|
"tail",
|
|
"find",
|
|
"rg",
|
|
"wc",
|
|
"stat",
|
|
"git status",
|
|
"git diff",
|
|
"git log",
|
|
"git show",
|
|
"date",
|
|
"whoami",
|
|
"uname",
|
|
"ps",
|
|
"python3 -m http.server",
|
|
"python -m http.server",
|
|
"npm run build",
|
|
)
|
|
|
|
APPROVAL_REQUIRED_PREFIXES = (
|
|
"curl",
|
|
"wget",
|
|
"pip",
|
|
"npm",
|
|
"python",
|
|
"python3",
|
|
"node",
|
|
"git commit",
|
|
"git push",
|
|
"pkill",
|
|
"kill",
|
|
"touch",
|
|
"echo ",
|
|
)
|
|
|
|
BLOCKED_PATTERNS = (
|
|
"sudo ",
|
|
"rm -rf",
|
|
"chmod ",
|
|
"chown ",
|
|
";",
|
|
"&&",
|
|
"||",
|
|
"$(",
|
|
)
|
|
|
|
|
|
@dataclass
|
|
class TerminalDecision:
|
|
decision: str
|
|
reason: str
|
|
|
|
|
|
def evaluate_terminal_command(command: str, mode: int) -> TerminalDecision:
|
|
normalized = command.strip()
|
|
|
|
if any(pattern in normalized for pattern in BLOCKED_PATTERNS):
|
|
return TerminalDecision(decision="blocked", reason="Blocked by hard policy.")
|
|
|
|
if mode == 1:
|
|
return TerminalDecision(decision="allow", reason="Terminal mode 1 auto-runs commands.")
|
|
|
|
if mode == 2:
|
|
return TerminalDecision(decision="approval", reason="Terminal mode 2 requires approval.")
|
|
|
|
if normalized.startswith(SAFE_COMMAND_PREFIXES):
|
|
return TerminalDecision(decision="allow", reason="Safe read-only command.")
|
|
|
|
if normalized.startswith(APPROVAL_REQUIRED_PREFIXES):
|
|
return TerminalDecision(decision="approval", reason="Command needs approval.")
|
|
|
|
return TerminalDecision(decision="approval", reason="Unknown command defaults to approval.")
|