Ë
    ÛJêj›2  ã                  ó  — d Z ddlmZ ddlmZmZ ddlmZ ddlm	Z	m
Z
 ddlmZmZmZmZ ddlmZmZ ddlmZmZ dd	lmZmZmZ  G d
„ dee«      Z G d„ de«      Ze G d„ d«      «       Ze G d„ d«      «       Z G d„ d«      Z g d¢Z!y)uý  Permission Gateway â€” security boundary between agents and tools.

The Permission Gateway is the single point through which all agent tool
calls must pass. It combines:

1. Agent identity scope checks (does the agent have the required permission?)
2. Policy engine evaluation (does the system policy allow this action?)
3. Approval routing (does this action require human approval?)

Core principle: DEFAULT DENY. No tool call is permitted unless explicitly
allowed by both identity scope AND policy engine.
é    )Úannotations)Ú	dataclassÚfield)ÚEnum)ÚAnyÚClassVar)ÚACTION_SCOPE_REQUIREMENTSÚKNOWN_SAFE_ACTIONSÚSENSITIVE_ACTIONSÚnormalize_action)ÚAuditEventTypeÚAuditLog)ÚAgentIdentityÚ
TrustLevel)ÚPolicyContextÚPolicyDecisionÚPolicyEnginec                  ó   — e Zd ZdZdZdZdZy)ÚPermissionDecisionz#Outcome of a permission evaluation.ÚallowÚdenyÚrequire_approvalN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__ÚALLOWÚDENYÚREQUIRE_APPROVAL© ó    úU/home/oem/CyberBrain26-unified/src/cyberbrain26/security_plane/permission/__init__.pyr   r   #   s   „ Ù-à€EØ€DØ)Ñr!   r   c                  ó   — e Zd ZdZy)ÚSecurityErrorzžRaised when a security boundary check fails.

    Distinguishes deliberate security denials and approval
    requirements from operational/system errors.
    N)r   r   r   r   r    r!   r"   r$   r$   +   s   „ òr!   r$   c                  ó^   — e Zd ZU dZded<   ded<   dZded<    ee¬	«      Zd
ed<   dZ	ded<   y)ÚPermissionRequestz.A request for permission to perform an action.r   ÚagentÚstrÚactionNú
str | NoneÚresource)Údefault_factoryzdict[str, Any]Úcontextç        ÚfloatÚ
risk_score)
r   r   r   r   Ú__annotations__r+   r   Údictr-   r0   r    r!   r"   r&   r&   3   s3   … á8àÓØƒKØ€HˆjÓÙ#°DÔ9€Gˆ^Ó9Ø€J�Ôr!   r&   c                  ó^   — e Zd ZU dZded<   ded<   dZded<   dZd	ed
<   dZded<   dZded<   y)ÚPermissionResultz"Result of a permission evaluation.r   Údecisionr(   ÚreasonNzPolicyDecision | NoneÚpolicy_decisionr*   Úscope_requiredFÚboolÚapproval_requiredzPermissionRequest | NoneÚrequest)	r   r   r   r   r1   r7   r8   r:   r;   r    r!   r"   r4   r4   >   s;   … á,à Ó ØƒKØ-1€OÐ*Ó1Ø!%€N�JÓ%Ø#Ð�tÓ#Ø(,€GÐ%Ô,r!   r4   c                  ól   — e Zd ZU dZ ee«      Zded<   d	d
d„Z	 	 	 d	 	 	 	 	 	 	 	 	 	 	 dd„Z	dd„Z
dd„Zy)ÚPermissionGatewayaš  Security boundary that gates all agent tool calls.

    Evaluates whether an agent identity is permitted to perform an action
    by checking both identity scopes and system policy.

    Usage:
        gateway = PermissionGateway()
        result = gateway.evaluate(identity, "execute_shell", "/bin/ls")
        if result.decision == PermissionDecision.DENY:
            raise SecurityError(result.reason)
    zClassVar[dict[str, str]]ÚACTION_SCOPE_MAPNc                ó8   — |xs
 t        «       | _        || _        y )N)r   Úpolicy_engineÚ	audit_log)Úselfr@   rA   s      r"   Ú__init__zPermissionGateway.__init__]   s   € Ø*Ò<¬l«nˆÔØ"ˆ�r!   c                ó�
  — t        |«      }t        ||||xs i |¬«      }|j                  t        j                  k(  r~| j
                  rH| j
                  j                  t        j                  |j                  |j                  ||xs ddd¬«       t        t        j                  d|j                  › d�|¬«      S | j                  j                  |«      }|€‹|t        v rƒ| j
                  rK| j
                  j                  t        j                   |j                  |j                  ||xs dd	d
|› �¬«       t        t        j                  d|› d|j                  › �|¬«      S |€”|t"        vrŒ| j
                  rO| j
                  j                  t        j                   |j                  |j                  ||xs ddd|xs d› �¬«       t        t        j                  d|xs d› d|j                  › d�|¬«      S |�™|j%                  |«      sˆ| j
                  rK| j
                  j                  t        j                   |j                  |j                  ||xs ddd|› �¬«       t        t        j                  d|j                  › d|› d|› d�||¬«      S | j
                  rG| j
                  j                  t        j                   |j                  |j                  ||xs dd¬«       t'        |||xs i || j(                  j*                  ¬«      }	| j(                  j-                  ||||	«      }
|
j.                  t0        j                  k(  r | j
                  r\| j
                  j                  t        j                   |j                  |j                  ||xs d|
j.                  j2                  d¬«       t        t        j                  d|› d|
j4                  › �|
j.                  ||¬«      S |
j.                  t0        j6                  k(  r¡| j
                  r\| j
                  j                  t        j                   |j                  |j                  ||xs d|
j.                  j2                  d ¬«       t        t        j6                  d|› d!|
j4                  › �|
j.                  |d"|¬#«      S | j
                  r\| j
                  j                  t        j                   |j                  |j                  ||xs d|
j.                  j2                  d$¬«       t        t        j8                  d|› d%|j                  › �|
j.                  ||¬«      S )&uº  Evaluate whether an agent can perform an action.

        Args:
            agent: The agent identity requesting the action.
            action: The action being requested.
            resource: Optional resource being accessed.
            context: Optional additional context (environment, mode, etc.).
            risk_score: Risk score of the request (0.0 to 1.0).

        Returns:
            PermissionResult with decision, reason, and metadata.

        Security rationale: the action is canonicalized with ``normalize_action``
        before *any* lookup, so ``" read_file "``, ``"READ_FILE"`` and
        ``"read_file"`` are one action and reach one verdict. An action that is
        neither scope-mapped nor on the explicitly-named ``KNOWN_SAFE_ACTIONS``
        allowlist is denied here rather than passed on with no scope
        requirement â€” the previous behaviour skipped the scope gate entirely for
        such a name, so any invented string was treated as harmless.

        A sensitive action that is classified but carries no scope requirement
        gets its own denial with its own reason, so "known, risky, and
        unreachable" can never be mistaken for "unknown name".
        )r'   r)   r+   r-   r0   Ú ÚdeniedÚuntrusted_agent)ÚactorÚagent_idr)   r+   ÚresultÚerrorzAgent u(    is UNTRUSTED â€” denied by trust policy)r5   r6   r;   Úunscoped_sensitive_actionzunscoped_sensitive_action:zSensitive action 'uD   ' has no identity scope requirement â€” denied by default for agent Úunknown_actionzunknown_action:z<empty>zAction 'z'' is not a registered action for agent u    â€” denied by defaultÚscope_check_failedzmissing_scope:z lacks required scope 'z' for action 'ú')r5   r6   r8   r;   Úscope_check_passed)rH   rI   r)   r+   rJ   )r)   r+   Úenvironmentr0   Úmode)rH   rI   r)   r+   r7   rJ   zPolicy denied action 'z': )r5   r6   r7   r8   r;   r:   z' requires human approval: T)r5   r6   r7   r8   r:   r;   Úallowedz' permitted for agent )r   r&   Útrust_levelr   Ú	UNTRUSTEDrA   Úrecordr   ÚIDENTITY_CHECKrI   r4   r   r   r>   Úgetr   ÚPERMISSION_CHECKr
   Ú	has_scoper   r@   rR   Úevaluater5   r   Úvaluer6   r   r   )rB   r'   r)   r+   r-   r0   Úcanonical_actionr;   r8   Úpolicy_contextÚpolicy_results              r"   r[   zPermissionGateway.evaluatea   s%  € ô@ ,¨FÓ3ÐÜ#ØØ#ØØ’M˜rØ!ô
ˆð ×Ñ¤
× 4Ñ 4Ò4Ø�~Š~Ø—‘×%Ñ%Ü"×1Ñ1ØŸ.™.Ø"Ÿ^™^Ø+Ø%š^¨Ø#Ø+ð &ô ô $Ü+×0Ñ0Ø §¡Ð/Ð/WÐXØôð ð ×.Ñ.×2Ñ2Ð3CÓDˆð Ð!Ð&6Ô:KÑ&KØ�~Š~Ø—‘×%Ñ%Ü"×3Ñ3ØŸ.™.Ø"Ÿ^™^Ø+Ø%š^¨Ø6Ø6Ð7GÐ6HÐIð &ô ô $Ü+×0Ñ0à(Ð)9Ð(:ð ;7Ø7<·~±~Ð6FðHð  ôð ð Ð!Ð&6Ô>PÑ&PØ�~Š~Ø—‘×%Ñ%Ü"×3Ñ3ØŸ.™.Ø"Ÿ^™^Ø+Ø%š^¨Ø+Ø+Ð,<Ò,IÀ	Ð+JÐKð &ô ô $Ü+×0Ñ0àÐ/Ò<°9Ð=ð >!Ø!&§¡Ð 0Ð0FðHð  ôð ð Ð%¨e¯o©o¸nÔ.MØ�~Š~Ø—‘×%Ñ%Ü"×3Ñ3ØŸ.™.Ø"Ÿ^™^Ø+Ø%š^¨Ø/Ø*¨>Ð*:Ð;ð &ô ô $Ü+×0Ñ0Ø §¡Ð/Ð/FÀ~ÐFVÐVdÐeuÐdvÐvwÐxØ-Øô	ð ð �>Š>Ø�N‰N×!Ñ!Ü×/Ñ/Ø—n‘nØŸ™Ø'Ø!š RØ+ð "ô ô 'Ø#ØØš 2Ø!Ø×#Ñ#×(Ñ(ô
ˆð ×*Ñ*×3Ñ3ØÐ# X¨~ó
ˆð
 ×!Ñ!¤^×%8Ñ%8Ò8Ø�~Š~Ø—‘×%Ñ%Ü"×3Ñ3ØŸ.™.Ø"Ÿ^™^Ø+Ø%š^¨Ø$1×$:Ñ$:×$@Ñ$@Ø#ð &ô ô $Ü+×0Ñ0Ø/Ð0@Ð/AÀÀ]×EYÑEYÐDZÐ[Ø -× 6Ñ 6Ø-Øôð ð ×!Ñ!¤^×%DÑ%DÒDØ�~Š~Ø—‘×%Ñ%Ü"×3Ñ3ØŸ.™.Ø"Ÿ^™^Ø+Ø%š^¨Ø$1×$:Ñ$:×$@Ñ$@Ø.ð &ô ô $Ü+×<Ñ<Ø!Ð"2Ð!3Ð3NÈ}×OcÑOcÐNdÐeØ -× 6Ñ 6Ø-Ø"&Øôð ð �>Š>Ø�N‰N×!Ñ!Ü×/Ñ/Ø—n‘nØŸ™Ø'Ø!š RØ -× 6Ñ 6× <Ñ <Ø ð "ô ô  Ü'×-Ñ-ØÐ.Ð/Ð/EÀeÇnÁnÐEUÐVØ)×2Ñ2Ø)Øô
ð 	
r!   c                óJ   — | j                   j                  t        |«      «      S )zñReturn the required scope for an action, or None if no scope mapping exists.

        The name is canonicalized first, so a cosmetic variant of an action
        resolves to the same scope instead of silently reporting "no mapping".
        )r>   rX   r   ©rB   r)   s     r"   Úrequire_scopezPermissionGateway.require_scope6  s!   € ð ×$Ñ$×(Ñ(Ô)9¸&Ó)AÓBÐBr!   c                ó0   — t        |«      | j                  v S )z,Check whether an action has a scope mapping.)r   r>   ra   s     r"   Úhas_scope_mappingz#PermissionGateway.has_scope_mapping>  s   € ä Ó'¨4×+@Ñ+@Ð@Ð@r!   )NN)r@   zPolicyEngine | NonerA   zAuditLog | NoneÚreturnÚNone)NNr.   )r'   r   r)   r(   r+   r*   r-   zdict[str, Any] | Noner0   r/   re   r4   )r)   r(   re   r*   )r)   r(   re   r9   )r   r   r   r   r2   r	   r>   r1   rC   r[   rb   rd   r    r!   r"   r=   r=   J   s~   … ñ
ñ  26Ð6OÓ1PÐÐ.ÓPô#ð  $Ø)-ØðS
àðS
ð ðS
ð ð	S
ð
 'ðS
ð ðS
ð 
óS
ójCôAr!   r=   )r   r=   r&   r4   r$   N)"r   Ú
__future__r   Údataclassesr   r   Úenumr   Útypingr   r   Ú#cyberbrain26.security_plane.actionsr	   r
   r   r   Ú!cyberbrain26.security_plane.auditr   r   Ú$cyberbrain26.security_plane.identityr   r   Ú"cyberbrain26.security_plane.policyr   r   r   r(   r   Ú	Exceptionr$   r&   r4   r=   Ú__all__r    r!   r"   ú<module>rq      s—   ðñõ #ç (Ý ß  ÷ó ÷ Gß J÷ñ ô*˜˜dô *ô�Iô ð ÷ð ó ðð ÷-ð -ó ð-÷vAñ vAòr�r!   