Ë
    ÛJêjÍB  ã                  ó   — U d Z ddlmZ ddlZddlmZ ddlmZ ddlm	Z	 ddl
mZ ddlmZ dd	lmZ g d
¢ZdZded<   d8d„Zd9d„Zd:d„Zedœ	 	 	 	 	 	 	 	 	 d;d„Z ed¬«       G d„ d«      «       Z e	dd¬«      Zded<   d<d„Ze	 	 	 	 d=d„«       Zi dej6                  j8                  “dej:                  j8                  “dej<                  j8                  “d ej>                  j8                  “d!ej@                  j8                  “d"ejB                  j8                  “d#ejD                  j8                  “d$ejF                  j8                  “d%ejH                  j8                  “d&ejJ                  j8                  “d'ejL                  j8                  “d(ejN                  j8                  “d)ejB                  j8                  “d*ejB                  j8                  “d+ejB                  j8                  “d,ejB                  j8                  “d-ejB                  j8                  “ejB                  j8                  ejJ                  j8                  d.œ¥Z(d/ed0<    e)h d1£«      Z*d2ed3<    e)h d4£«      Z+d2ed5<    e)e(«      e*z  e+z  Z,d2ed6<   d>d7„Z-y)?a4
  Canonical action vocabulary shared by the policy and permission layers.

Every authorization decision is a comparison of a caller-supplied string
against a fixed vocabulary of action names. Two gates used to consult that
vocabulary with the raw string, so a value such as ``"execute_shell "``
(trailing space) or ``"RUN_SHELL"`` matched no entry at all: the scope gate
was skipped and the action was not classified as sensitive. This module is the
single normalization point both gates call before they look anything up, so
the very same canonical string decides the scope check, the sensitivity
classification and the policy rule match.

The vocabulary is also explicit. An action the system does not know is
unregistered and is denied by default; it becomes usable only when it is
registered here (scope-mapped, classified as sensitive, or listed as a known
safe non-mutating action). Opting in is a code change, not a runtime string,
which is what keeps an invented action name from being treated as harmless.

It also owns the format of an *already granted* authorization, because the
second gate in front of the sandbox needs the same vocabulary as the first one.
A ``cyberbrain run`` step declares its action once; the dispatcher's
authorization chain requests the human approval and then hands control to the
agent, whose own gateway re-checks that very action immediately before the
provider runs. Those two checks are one decision, not two, so the outer one
mints an ``ExecutionAuthorization`` naming the agent, the action and a digest of
the exact payload a human approved, and binds it to the single in-flight agent
call. The inner gateway re-verifies identity, action and payload digest against
that grant instead of raising a second, independent approval request: defence in
depth is preserved (every gate still runs, and a payload that changed after the
operator approved it is refused) while one human decision stays one human
decision.

The grant is deliberately not a bearer token that can be passed around. It lives
in a context variable scoped to the dispatcher's own ``await``, so it cannot be
read out of a payload, cannot be stored, cannot survive a process restart, and
is gone before the next task is dispatched. A durable task retried after a
restart therefore reruns the whole chain and asks a human again.

This module imports nothing from the rest of the security plane except
``identity`` (which has no security-plane imports of its own), so ``policy``,
``permission``, the extension layer's dispatcher and the execution plane's
gateway can all depend on it without an import cycle.
é    )ÚannotationsN)ÚIterator)Úcontextmanager)Ú
ContextVar)Ú	dataclass)ÚFinal)ÚPermissionScope)ÚACTION_SCOPE_REQUIREMENTSÚ!DEFAULT_EXECUTION_TIMEOUT_SECONDSÚKNOWN_ACTIONSÚKNOWN_SAFE_ACTIONSÚSENSITIVE_ACTIONSÚExecutionAuthorizationÚbound_execution_authorizationÚcurrent_execution_authorizationÚexecution_payload_digestÚis_registered_actionÚnormalize_actioné   z
Final[int]r   c                ó`   — t        | t        «      sy| j                  «       j                  «       S )uÊ  Return the canonical form of an action name.

    Both sides of every decision â€” the scope lookup and the policy
    classification â€” must call this first, otherwise a cosmetic difference in
    the caller's string silently selects a different (weaker) authorization
    path. Surrounding whitespace and letter case are not part of an action's
    identity, so they are removed rather than trusted.

    Args:
        action: The raw action value. Anything that is not a string carries no
            action name at all and normalizes to the empty string, which is
            unregistered and therefore denied.

    Returns:
        The stripped, lower-cased action name, or ``""`` when none can be read.
    Ú )Ú
isinstanceÚstrÚstripÚlower©Úactions    úI/home/oem/CyberBrain26-unified/src/cyberbrain26/security_plane/actions.pyr   r   L   s&   € ô" �fœcÔ"ØØ�<‰<‹>×ÑÓ!Ð!ó    c                ót   — t        | t        «      r| j                  «       j                  «       S t	        | «      S )a  Return the language token the execution layer will actually act on.

    The execution gateway maps ``"py"``/``"python"`` and ``"sh"``/``"shell"`` onto
    one action each, so a digest taken from the raw payload value and a digest
    taken from the gateway's normalized value must agree; that is why the same
    strip/lower-case rule is applied on both sides. A non-string is rendered with
    ``repr`` rather than folded into the empty string, so a malformed value can
    never collide with an absent one in a digest.
    )r   r   r   r   Úrepr)Úlanguages    r   Ú_canonical_languager#   b   s.   € ô �(œCÔ Ø�~‰~Ó×%Ñ%Ó'Ð'Ü�‹>Ðr   c                ó<   — t        | t        «      r| S t        | «      S )zBRender one payload field into the material a digest is taken over.)r   r   r!   )Úvalues    r   Ú_digest_fieldr&   q   s   € ä˜u¤cÔ*ˆ5Ð;´°U³Ð;r   )Útimeout_secondsc                óØ   — dj                  t        | «      t        |«      t        |«      t        |«      f«      }t        j                  |j                  d«      «      j                  «       S )a  Return a stable fingerprint of everything that decides what will run.

    The digest covers the four inputs the execution gateway hands to the
    provider - the code, the normalized language, the workspace it runs in and
    the timeout - and nothing else. It is the security-critical half of the
    single-approval flow: the outer gate approves this fingerprint, so the inner
    gate may only skip asking again while the payload in front of it still
    hashes to it. Any difference in any of the four fields (including whitespace
    in the workspace path) produces a different digest, which the inner gate
    refuses instead of executing.

    Fields are joined with a NUL separator, which cannot occur in the payload, so
    no two different field tuples can produce the same material.
    ú zutf-8)Újoinr&   r#   ÚhashlibÚsha256ÚencodeÚ	hexdigest)Úcoder"   Ú	workspacer'   Úmaterials        r   r   r   v   sZ   € ð* �{‰{ä˜$ÓÜ Ó)Ü˜)Ó$Ü˜/Ó*ð		
ó€Hô �>‰>˜(Ÿ/™/¨'Ó2Ó3×=Ñ=Ó?Ð?r   T)Úfrozenc                  ó^   — e Zd ZU dZded<   ded<   ded<   ded<   dZded	<   dZded
<   dd„Zy)r   aÎ  One already-granted authorization for exactly one execution payload.

    Minted by the dispatcher's authorization chain *after* a human approved the
    declared action, and consumed by the execution gateway for the very payload
    the digest was taken over. Immutable and unforgeable from outside: the only
    producer is the dispatcher, it never travels in a payload or a database, and
    its lifetime is one in-flight agent call (see
    :func:`bound_execution_authorization`).

    Attributes:
        agent_id: Identity the approval was granted to. A grant is never usable
            by another identity, so one agent's approval cannot be spent by a
            second one.
        task_id: Dispatch task the approval belongs to, recorded for the audit
            trail. The binding that actually scopes the grant to one task is the
            context-variable lifetime, not this field.
        action: Canonical action a human approved. The gateway ignores the grant
            entirely when the action it is about to perform differs, which is
            what keeps an approval for one action from authorizing another (a
            step declaring the non-mutating label ``"code"``, for instance, still
            raises its own approval for ``execute_python``).
        resource: The declared resource of the dispatch, carried for the audit
            trail only. It is deliberately *not* compared at consumption time:
            the dispatcher's declared resource and the gateway's execution
            workspace are different attributes of a step, and the workspace is
            already covered by the payload digest.
        payload_digest: Fingerprint from :func:`execution_payload_digest`.
        approval_request_id: The approval request a human decided, or ``None``
            when the outer chain allowed the action outright. A grant without a
            request id carries no human decision, so the gateway never treats it
            as a substitute for one.
    r   Úagent_idÚtask_idr   Úpayload_digestNz
str | NoneÚapproval_request_idÚresourcec               ód   — | j                   |k(  xr  | j                  |k(  xr | j                  |k(  S )ax  Report whether this grant authorizes the execution being attempted.

        Callers must have already decided that the grant's action is the action
        being performed; a differing action is not answered here, because the
        right response to "approved something else" is to run the full
        authorization chain for the real action, not to fail a match.
        )r4   r   r6   )Úselfr4   r   r6   s       r   ÚcoverszExecutionAuthorization.coversÀ   s9   € ð �M‰M˜XÑ%ò 6Ø—‘˜vÑ%ò6à×#Ñ# ~Ñ5ð	
r   )r4   r   r   r   r6   r   ÚreturnÚbool)Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú__annotations__r7   r8   r;   © r   r   r   r   –   s9   … ñðB ƒMØƒLØƒKØÓØ&*Ð˜Ó*Ø€HˆjÓô
r   r   Ú$cyberbrain26_execution_authorization)Údefaultz)ContextVar[ExecutionAuthorization | None]Ú _CURRENT_EXECUTION_AUTHORIZATIONc                 ó*   — t         j                  «       S )zCReturn the grant bound to the dispatch currently in flight, if any.)rF   ÚgetrC   r   r   r   r   Ô   s   € ä+×/Ñ/Ó1Ð1r   c              #  óž   K  — t         j                  | «      }	 d–— t         j                  |«       y# t         j                  |«       w xY w­w)aŠ  Bind ``authorization`` for the duration of one agent call.

    Security rationale: the binding is both the propagation mechanism and the
    security boundary. Because the context variable is set and reset around the
    dispatcher's own ``await agent.execute(...)``, a grant is readable by the
    gates of exactly that one call and by nothing else - it cannot be read from
    the payload, forged by a caller, smuggled in through the event bus, reused
    by a later step or persisted for a later process. Binding ``None`` clears
    any grant inherited from an enclosing scope, so a nested dispatch cannot
    spend an outer task's approval.
    N)rF   ÚsetÚreset)ÚauthorizationÚtokens     r   r   r   Ù   s=   è ø€ ô -×0Ñ0°Ó?€Eð6Ûä(×.Ñ.¨uÕ5øÔ(×.Ñ.¨uÕ5üs   ‚A™3 �A³A
Á
AÚ	read_fileÚ
write_fileÚdelete_fileÚexecute_shellÚexecute_pythonÚaccess_networkÚaccess_browserÚexecute_gitÚexecute_dockerÚaccess_secretsÚ
access_mcpÚ	audit_logÚpublish_contentÚsend_external_messageÚdata_uploadÚscan_networkÚ	vuln_scan)Úexploit_targetÚcredential_accesszFinal[dict[str, str]]r
   >   r^   rO   r\   rP   r]   rQ   rS   rW   rV   rR   r_   rZ   r`   r[   zFinal[frozenset[str]]r   >   r/   ÚplanÚevaluater   r   c                ó$   — t        | «      t        v S )záCheck whether an action name is part of the canonical vocabulary.

    The name is normalized first, so a whitespace or case variant of a known
    action is recognised rather than treated as a different, unknown action.
    )r   r   r   s    r   r   r   ^  s   € ô ˜FÓ#¤}Ð4Ð4r   )r   Úobjectr<   r   )r"   rd   r<   r   )r%   rd   r<   r   )
r/   rd   r"   rd   r0   rd   r'   rd   r<   r   )r<   úExecutionAuthorization | None)rL   re   r<   zIterator[None])r   rd   r<   r=   ).rA   Ú
__future__r   r+   Úcollections.abcr   Ú
contextlibr   Úcontextvarsr   Údataclassesr   Útypingr   Ú$cyberbrain26.security_plane.identityr	   Ú__all__r   rB   r   r#   r&   r   r   rF   r   r   Ú	READ_FILEr%   Ú
WRITE_FILEÚDELETE_FILEÚSHELLÚPYTHONÚNETWORKÚBROWSERÚGITÚDOCKERÚSECRETSÚMCPÚAUDITr
   Ú	frozensetr   r   r   r   rC   r   r   ú<module>r{      s  ðò)õV #ã Ý $Ý %Ý "Ý !Ý å @ò€ð$ 13Ð ! :Ó 2ó"ó,ó<ð @ñ@à
ð@ð ð@ð ð	@ð
 ð@ð 	ó@ñ@ �$Ô÷5
ð 5
ó ð5
ñp OYØ*°DôOÐ  Ð"Kó ó
2ð
 ð6Ø0ð6àò6ó ð6ð0*4Ø�×*Ñ*×0Ñ0ð*4à�/×,Ñ,×2Ñ2ð*4ð �?×.Ñ.×4Ñ4ð*4ð �_×*Ñ*×0Ñ0ð	*4ð
 �o×,Ñ,×2Ñ2ð*4ð �o×-Ñ-×3Ñ3ð*4ð �o×-Ñ-×3Ñ3ð*4ð �?×&Ñ&×,Ñ,ð*4ð �o×,Ñ,×2Ñ2ð*4ð �o×-Ñ-×3Ñ3ð*4ð �/×%Ñ%×+Ñ+ð*4ð �×&Ñ&×,Ñ,ð*4ð, �×.Ñ.×4Ñ4ð-*4ð. ˜_×4Ñ4×:Ñ:ð/*4ð0 �?×*Ñ*×0Ñ0ð1*4ðD �O×+Ñ+×1Ñ1ðE*4ðF �×(Ñ(×.Ñ.ðG*4ðH &×-Ñ-×3Ñ3ð
 )×0Ñ0×6Ñ6òS*4Ð Ð0ó *ñf ,5òó,Ð Ð(ó ñ^ -6Ò6RÓ,SÐ Ð)Ó Sñ Ð'Ó(Ð+<Ñ<Ð?QÑQð Ð$ó ô
5r   