Source code for axio.permission

"""Permission system: guards that gate tool execution."""

from __future__ import annotations

import asyncio
from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, Any

from .exceptions import GuardError

if TYPE_CHECKING:
    from .tool import Tool


[docs] class PermissionGuard(ABC): """Gate for tool calls. Return modified kwargs to allow, raise to deny. Tool invokes guards via ``await guard(tool, **kwargs)``. Guards receive the ``Tool`` object and the raw keyword arguments before execution. Return the (possibly modified) dict to allow; raise ``GuardError`` to deny. Because guards see all inputs up front, they are also the right place for **logging and auditing**:: class AuditGuard(PermissionGuard): async def check(self, tool: Tool, **kwargs: Any) -> dict[str, Any]: logger.info("tool=%s args=%s", tool.name, kwargs) return kwargs # always allow See ``examples/agent_swarm/agent_swarm/__main__.py`` (``RoleGuard``) for a production example. """ async def __call__(self, tool: Tool[Any], **kwargs: Any) -> dict[str, Any]: return await self.check(tool, **kwargs)
[docs] @abstractmethod async def check(self, tool: Tool[Any], **kwargs: Any) -> dict[str, Any]: ...
[docs] class ConcurrentGuard(PermissionGuard, ABC): """Guard with concurrency control. Subclass and override ``check()``. ``__call__`` acquires the semaphore then delegates to ``check()``. Set ``concurrency`` to control parallelism (default 1 - one check at a time). """ concurrency: int = 1 def __init__(self) -> None: self._semaphore = asyncio.Semaphore(self.concurrency) async def __call__(self, tool: Tool[Any], **kwargs: Any) -> dict[str, Any]: async with self._semaphore: return await self.check(tool, **kwargs)
[docs] class AllowAllGuard(PermissionGuard):
[docs] async def check(self, tool: Tool[Any], **kwargs: Any) -> dict[str, Any]: return dict(kwargs)
[docs] class DenyAllGuard(PermissionGuard):
[docs] async def check(self, tool: Tool[Any], **kwargs: Any) -> dict[str, Any]: raise GuardError("denied")