"""Safety rules: Plan Mode, permissions, dangerous actions.""" import re # Patterns for potentially dangerous terminal commands DANGEROUS_PATTERNS = [ r"rm\s+-rf\s+/.*", r"sudo\s+rm", r"mkfs\.", r"dd\s+if=", r">\s*/dev/sd", r"chmod\s+777", r"git\s+push\s+.*\s+main", r"git\s+push\s+.*\s+master", r"docker\s+rm\s+-f", r"docker\s+volume\s+rm", ] # Pattern to detect Base64-like values that may be secrets # Matches: api_key=XXXX, token:XXXX, secret="XXXX", etc. _SECRET_VALUE = re.compile( r'(?:api|access|secret|token|key|password|auth)' r'[-_]?' r'(?:key|token|secret)?' r'\s*[=:]\s*' r'[\'"]?' r'[A-Za-z0-9+/=_-]{20,}' r'[\'"]?' ) def is_dangerous_command(command: str) -> bool: """Check if a terminal command matches known dangerous patterns.""" for pattern in DANGEROUS_PATTERNS: if re.search(pattern, command, re.IGNORECASE): return True return False def contains_secret(text: str) -> bool: """Check if text likely contains a hardcoded secret.""" return bool(_SECRET_VALUE.search(text)) def redact_secrets(text: str) -> str: """Return text with obvious credential-looking assignments redacted. This is defensive output hygiene, not a credential scanner. It must only be applied to data already produced by approved checks. """ return _SECRET_VALUE.sub(lambda m: m.group(0).split('=')[0] + '=' if '=' in m.group(0) else '', text) # Credential-discovery commands are never legitimate for this plugin. # This is not a scanner for collecting credentials; it is a pre-execution guard # for commands/plans that attempt credential discovery. CREDENTIAL_DISCOVERY_PATTERNS = [ r"\b(grep|rg|ripgrep|find|cat|sed|awk|python|python3|node|perl)\b.*\b(password|passwd|pwd|token|secret|api[_-]?key|access[_-]?key|private[_-]?key|credential|auth|cookie|session)\b", r"\b(password|passwd|pwd|token|secret|api[_-]?key|access[_-]?key|private[_-]?key|credential|auth|cookie|session)\b.*\b(grep|rg|ripgrep|find|cat|sed|awk|python|python3|node|perl)\b", r"\b(env|printenv|set)\b.*\b(password|token|secret|key|credential|auth)\b", r"\b\.env(\.|\b|$)", r"\b(config|settings|application|appsettings).*\b(password|token|secret|credential|auth)\b", r"\b(browser|chrome|firefox|localstorage|sessionstorage|cookie|cookies)\b.*\b(password|token|secret|credential|auth|session)\b", r"\bfind\b.*\b(login|credential|credentials|password|token|secret)\b", r"\b(read|open|dump|extract|list|locate|recover|discover|search)\b.*\b(login|credential|credentials|password|token|secret|cookie|session)\b", ] def is_credential_discovery_command(command: str) -> bool: """Return True if a command/plan appears to look for credential material.""" c = str(command or "").lower() return any(re.search(pattern, c, re.IGNORECASE) for pattern in CREDENTIAL_DISCOVERY_PATTERNS)