# Shell Safety Module **Package:** `cleveragents.tui.shell_safety` The shell safety module protects users from accidentally executing dangerous commands in the TUI shell mode (`!` prefix). It provides a configurable pattern registry, a danger-level classification system, and an application service that integrates with the TUI warning overlay. --- ## Purpose When a user types `!` in the TUI, the `ShellSafetyService` checks the command against a registry of known-dangerous patterns before the subprocess is spawned. Commands that match a pattern at or above the configured `block_level` are blocked; commands below that level surface a warning overlay that the user must acknowledge before proceeding. --- ## Key Classes ### `ShellDangerLevel` Four-level `IntEnum` severity scale: ``` LOW (1) < MEDIUM (2) < HIGH (3) < CRITICAL (4) ``` Numeric comparisons work naturally: `level >= ShellDangerLevel.HIGH`. ### `DangerousPattern` Immutable frozen dataclass describing a single dangerous pattern: ```python DangerousPattern( name="fork_bomb", pattern=r":\(\)\s*\{", level=ShellDangerLevel.CRITICAL, description="Fork bomb — exhausts process table and crashes the system.", ) ``` ### `DangerousPatternDetector` Maintains the registry of `DangerousPattern` objects and provides `check_first(command) → DangerousCommandWarning | None` to return the highest-severity matching pattern. ### `ShellSafetyService` High-level application service used by the TUI: ```python from cleveragents.tui.shell_safety import ShellSafetyService, ShellDangerLevel # Default: block MEDIUM and above automatically service = ShellSafetyService() # Custom: only block CRITICAL; show overlay for HIGH and below service = ShellSafetyService(block_level=ShellDangerLevel.CRITICAL) # Custom: delegate all decisions to a callback def my_callback(warning): # Return True to allow, False to block return warning.danger_level < ShellDangerLevel.HIGH service = ShellSafetyService(warn_callback=my_callback) result = service.check_command("rm -rf /") if not result.allowed: print(f"Blocked: {result.warning.description}") ``` ### `DangerousCommandWarning` Value object returned when a dangerous pattern is matched: | Attribute | Type | Description | |-----------|------|-------------| | `command` | `str` | The original command text | | `pattern` | `DangerousPattern` | The matched pattern | | `danger_level` | `ShellDangerLevel` | Convenience alias for `pattern.level` | | `message` | `str` | Human-readable warning message | --- ## Built-in Pattern Categories | Category | Example patterns | Default level | |----------|-----------------|---------------| | Recursive deletion | `rm -rf /`, `rm -rf ~` | CRITICAL | | Disk-level writes | `dd if=`, `mkfs`, `shred` | CRITICAL | | Fork bombs | `:(){ :|:& };:` | CRITICAL | | Privilege escalation | `sudo su`, `chmod 777 /` | HIGH | | Network exfiltration | `curl \| sh`, `wget \| bash` | HIGH | | Reverse shells | `nc -e /bin/sh`, `bash -i >& /dev/tcp` | HIGH | | Dangerous redirects | `> /dev/sda`, `> /etc/passwd` | HIGH | | Credential exposure | `env \| curl`, `cat ~/.ssh/id_rsa \| nc` | MEDIUM | --- ## Adding Custom Patterns ```python from cleveragents.tui.shell_safety import ( DangerousPattern, ShellDangerLevel, ShellSafetyService, ) custom = DangerousPattern( name="drop_database", pattern=r"DROP\s+DATABASE", level=ShellDangerLevel.HIGH, description="Drops an entire database — irreversible.", case_sensitive=False, ) service = ShellSafetyService(extra_patterns=[custom]) ``` --- ## Integration with the TUI The TUI wires `ShellSafetyService` into the shell input handler. When `check_command()` returns `allowed=False`, the TUI displays a `DangerousCommandWarningOverlay` widget with the warning message and danger level. The user must explicitly confirm before the command is executed. For commands that are blocked outright (above `block_level` with no callback), the overlay displays a non-dismissable error and the command is never executed. --- ## Testing The shell safety module is fully covered by BDD scenarios in `features/shell_safety.feature`. All pattern matching is deterministic and does not require a running TUI, making it straightforward to test in isolation: ```python from cleveragents.tui.shell_safety import ShellSafetyService service = ShellSafetyService() assert not service.is_safe("rm -rf /") assert service.is_safe("ls -la") ```