"""Scoped forge wrapper: read-anywhere / write-scoped access control. `ScopedForge` wraps any forge object and restricts write operations to the set of issue/PR numbers the agent is explicitly assigned to. Read operations always pass through unconditionally. """ from __future__ import annotations from typing import Any class ScopedForge: """Delegates all forge calls to an inner forge, raising `PermissionError` on write calls for numbers outside the assigned scope.""" def __init__( self, forge: Any, *, assigned_issue: int, assigned_prs: list[int], ) -> None: self._forge = forge self._allowed_writes: frozenset[int] = frozenset({assigned_issue, *assigned_prs}) def _check_write(self, number: int) -> None: if number not in self._allowed_writes: raise PermissionError( f"write to #{number} is outside the assigned scope " f"(allowed: {sorted(self._allowed_writes)})" ) def is_org_member(self, org: str, username: str) -> bool: return self._forge.is_org_member(org, username) def read_issue(self, number: int) -> dict[str, Any]: return self._forge.read_issue(number) def read_pr(self, number: int) -> dict[str, Any]: return self._forge.read_pr(number) def read_comments(self, number: int) -> list[dict[str, Any]]: return self._forge.read_comments(number) def post_comment(self, number: int, body: str) -> None: self._check_write(number) self._forge.post_comment(number, body) def update_description(self, number: int, body: str) -> None: self._check_write(number) self._forge.update_description(number, body)