47 lines
1.4 KiB
Python
47 lines
1.4 KiB
Python
"""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)
|