"""Permission gating for tool execution.""" import logging from rich.prompt import Confirm from app.models.config import PermissionsConfig logger = logging.getLogger(__name__) class PermissionDenied(Exception): """Raised when a tool is denied execution by permissions policy.""" class PermissionsService: """Check whether a tool is allowed to execute based on config tiers.""" def __init__(self, config: PermissionsConfig) -> None: self.config = config def check(self, tool_name: str, description: str = "") -> bool: """Check if a tool is permitted to run. Returns: True if permitted, False if denied. """ if tool_name in self.config.deny: logger.info("Tool '%s' is in deny list — blocked", tool_name) return False if tool_name in self.config.auto_approve: logger.debug("Tool '%s' is auto-approved", tool_name) return True # Explicit prompt_user list or unlisted tools both trigger a prompt return self._prompt_user(tool_name, description) def _prompt_user(self, tool_name: str, description: str) -> bool: """Prompt the user for approval via the terminal.""" prompt_text = f"Allow tool [bold]{tool_name}[/bold]" if description: prompt_text += f" — {description}" prompt_text += "?" return Confirm.ask(prompt_text, default=False)