+
    jHàjõ  ã                  óZ  a € 0 t $ R t^ RIHt ^ RIHt ^ RIHtHtH	t	H
t
Ht ]! RR04      tR]R&   ]! 0 Rm4      tRRR	R/t]! R
R7       ! R R4      4       t]! R]! 4       ]! 4       R7      t]! R
]! 4       ]! 4       R7      t]3R R lltR R ltR R ltR R ltR R lt. R OtR R ltR# )!a¬  Per-platform slash command access control.

A second axis beside ``allow_from``: of the users allowed to talk to the gateway, which may run
which slash commands. Two lists per scope (DM vs group, mirroring ``allow_from`` /
``group_allow_from``): ``allow_admin_from`` (user IDs that get every registered command, built-in
and plugin) and ``user_allowed_commands`` (names non-admins may run; empty/unset -> only the
``_ALWAYS_ALLOWED_FOR_USERS`` floor). No ``allow_admin_from`` for a scope => gating disabled there,
so existing installs are unaffected until an operator lists an admin. Applied at the dispatch
site in ``gateway/run.py`` via the live registry; never affects plain chat.
)Úannotations)Ú	dataclass)ÚAnyÚCallableÚ	FrozenSetÚIterableÚOptionalÚhelpÚwhoamiúfrozenset[str]Ú_ALWAYS_ALLOWED_FOR_USERSÚdmÚgroupT)Úfrozenc                  óR   € ] tR t^t$ RtR]R&   R]R&   R]R&   R R ltR	 R
 ltRtR# )ÚSlashAccessPolicyzXResolved access policy for one (platform, scope) pair; scope is ``"dm"`` or ``"group"``.ÚboolÚenabledr   Úadmin_user_idsÚuser_allowed_commandsc               ó    € V ^8„  d   QhRRRR/# )é   Úuser_idúOptional[str]Úreturnr   © )Úformats   "Ú9/home/ubuntu/.hermes/hermes-agent/gateway/slash_access.pyÚ__annotate__ÚSlashAccessPolicy.__annotate__&   s   € ÷ Eñ E ð E°$ñ Eó    c                	ó€   € V P                   '       g   R # \        V4      ;'       d    \        V4      V P                  9   # ©T)r   r   Ústrr   )Úselfr   s   &&r   Úis_adminÚSlashAccessPolicy.is_admin&   s/   € à�|�|ˆ|ÙÜ�G‹}×DÐD¤ W£°×1DÑ1DÑ!DÐDr    c               ó$   € V ^8„  d   QhRRRRRR/# )r   r   r   Úcanonical_cmdr#   r   r   r   )r   s   "r   r   r   ,   s!   € ÷ 
ñ 
˜}ð 
¸Sð 
ÀTñ 
r    c                	ó˜   € V P                  V4      '       d   R # \        V4      ;'       d     V\        9   ;'       g    W P                  9   # r"   )r%   r   r   r   )r$   r   r(   s   &&&r   Úcan_runÚSlashAccessPolicy.can_run,   sE   € Ø�=‰=˜×!Ò!ÙÜ�MÓ"÷ 
ð 
ØÔ6Ñ6×eÐe¸-×KeÑKeÑ:eð	
r    r   N)	Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__annotations__r%   r*   Ú__static_attributes__r   r    r   r   r      s&   ‡ ábàƒMØ"Ó"Ø)Ó)õE÷
ñ 
r    r   F©r   r   r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úrawr   Ú	normalizezCallable[[str], str]r   r   r   )r   s   "r   r   r   =   s'   € ÷ Sñ S�cð SÐ&:ð SÀ^ñ Sr    c                ó  a€ V f   \        4       # \        V \        \        \        \         34      '       d   T pM2\        V \
        4      '       d   R V P                  R4       4       pMV 3p\        R V3R lV 4        4       4      # )zžNormalize a YAML-loaded value (None, list/tuple/set, comma string, or scalar) into a
frozenset of stripped, non-empty strings, applying ``normalize`` to each.c              3  óT   "  € T F  qP                  4       '       g   K  Vx € K   	  R # 5i©N)Ústrip©Ú.0Úss   & r   Ú	<genexpr>Ú_coerce_list.<locals>.<genexpr>E   s   é € Ð8™N�q¯g©g¯i—’›Nùs   ‚(ž
(Ú,c              3  ó8   "  € T F  q'       g   K  Vx € K  	  R # 5ir9   r   r;   s   & r   r>   r?   H   s   é € ÐRÑ L˜1ÓPQ—Q’QÓ Lùs   ‚	�
c              3  ób   <"  € T F$  pS! \        V4      P                  4       4      x € K&  	  R # 5ir9   )r#   r:   )r<   Úitr6   s   & €r   r>   r?   H   s#   øé € Ð LÁeÀ¡¬3¨r«7¯=©=«?×!;Ð!;Ãeùs   ƒ,/)Ú	frozensetÚ
isinstanceÚlistÚtupleÚsetr#   Úsplit)r5   r6   Úitemss   &f r   Ú_coerce_listrK   =   sj   ø€ ð ‚{Ü‹{ÐÜ�#œœe¤S¬)Ð4×5Ò5Ø"‰Ü	�Cœ×	Ò	Ù8˜CŸI™I cœNÓ8‰à�ˆÜÑRÔ LÁeÔ LÓRÓRÐRr    c               ó    € V ^8„  d   QhRRRR/# ©r   r5   r   r   r   r   )r   s   "r   r   r   K   s   € ÷ ñ ˜ð  ñ r    c                ó   € \        V 4      # )z<Normalize an admin/user id list into a frozenset of strings.©rK   ©r5   s   &r   Ú_coerce_id_listrQ   K   s   € ä˜ÓÐr    c               ó    € V ^8„  d   QhRRRR/# rM   r   )r   s   "r   r   r   P   s   € ÷ >ñ >˜cð > nñ >r    c                ó   € \        V R 4      # )zCommand allowlist: strip leading slashes (``/help`` or ``help``) and lowercase to match
how ``resolve_command()`` stores names.c                ó@   € V P                  R 4      P                  4       # )Ú/)ÚlstripÚlower)r=   s   &r   Ú<lambda>Ú&_coerce_command_list.<locals>.<lambda>S   s   €  q§x¡x°£}×':Ñ':Ô'<r    rO   rP   s   &r   Ú_coerce_command_listrZ   P   s   € ô ˜Ñ<Ó=Ð=r    c               ó$   € V ^8„  d   QhRRRRRR/# )r   ÚextraÚdictÚscoper#   r   r   r   )r   s   "r   r   r   V   s'   € ÷ lñ l˜Tð l¨#ð lÐ2Cñ lr    c                ó.  € \         P                  V\         R,          4      w  r#\        V P                  V4      4      p\        V P                  V4      4      pVR8X  d#   V'       g   \        V P                  R4      4      p\	        \        V4      WER7      # )zùBuild a policy from a platform's ``extra`` dict for one scope.

DM scope falls back to ``group_user_allowed_commands`` ONLY for the command list, and only
when DM didn't set its own. Admin lists are NOT cross-scope: a DM admin is not a group admin.
r   Úgroup_user_allowed_commandsr3   )Ú_SCOPE_KEYSÚgetrQ   rZ   r   r   )r\   r^   Ú	admin_keyÚcmd_keyÚ	admin_idsÚcmdss   &&    r   Úpolicy_from_extrarg   V   sp   € ô %Ÿ™¨´¸DÕ0AÓBÑ€IÜ §	¡	¨)Ó 4Ó5€IÜ §	¡	¨'Ó 2Ó3€DØ�„}ŸTÜ# E§I¡IÐ.KÓ$LÓMˆÜ¤T¨)£_ÀYÔkÐkr    c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úgateway_configr   Úsourcer   r   r   )r   s   "r   r   r   d   s'   € ÷ Yñ Y cð Y°3ð YÐ;Lñ Yr    c                óT  € V e   Vf   \         # \        V RR4      pRpVe    VP                  VP                  4      p\        VRR4      p\        V\        4      '       g   \        V\        4      '       d   TM/ p\        VRR4      pVe(   \        V4      P                  4       P                  4       MRpV'       d   V\        9   d   RMRp\        WG4      # \        VR4      p\        VR4      p	VP                  '       d   V	P                  '       g   V# T	#   \         d    Rp Lèi ; i)zèResolve the slash-gating policy for a SessionSource.

Disabled (allow-everything) when gateway_config/source is None, the platform has no
PlatformConfig, or no admin list is set for the scope. Gates slash commands only, never chat.
NÚ	platformsr\   Ú	chat_typeÚ r   r   )Ú_DISABLED_POLICYÚgetattrrb   ÚplatformÚ	ExceptionrE   r]   r#   r:   rW   Ú_DM_CHAT_TYPESrg   r   )
ri   rj   rl   Úplatform_configr\   rm   Ú
normalizedr^   Ú	dm_policyÚgroup_policys
   &&        r   Úpolicy_for_sourcerx   d   s  € ð Ò ¢ÜÐÜ˜¨°TÓ:€IØ€OØÒð	#Ø'Ÿm™m¨F¯O©OÓ<ˆOô �O W¨dÓ3€EÜ�eœT×"Ò"Ü#-¨o¼t×#DÒ#D‘È"ˆÜ˜ ¨TÓ2€IØ3<Ò3H”�Y“×%Ñ%Ó'×-Ñ-Ô/Èb€JßØ"¤nÔ4‘¸'ˆÜ  Ó.Ð.ô
 " %¨Ó.€IÜ$ U¨GÓ4€LØ!×)×)Ð)°,×2F×2FÐ2Fˆ9ÐXÈLÐXøô# ô 	#Ø"ŠOð	#ús   £D ÄD'Ä&D'c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úrunnerr   rj   r   r   r   )r   s   "r   r   r   ‰   s"   € ÷ -ñ - Sð -°#ð -Ð:Kñ -r    c                óv  € \        V RR4      p\        VRR4      '       d   Vf   \        W!4      # ^ RIHp V! V4      pVe   VP                  M\        VRR4      p\        V RR4      ;'       g    RpV'       d7   WV8w  d1   \        V R	R4      ;'       g    / P                  V4      pVf   \        # \        W!4      # )
a  Slash-gating policy from the profile whose bot received ``source``.

Under ``multiplex_profiles`` the runner's ``config`` is the launch profile's alone, so a platform
configured only in a secondary profile had no PlatformConfig there and every caller came back
unrestricted (#121705). Authorization follows the transport (bot-owning) profile, the owner
``RoutingIdentity.authorization_home`` already names; a served profile whose config is not cached
fails closed instead of inheriting the launch profile's open policy.
ÚconfigNÚmultiplex_profilesF)Úidentity_ofÚprofileÚ_primary_profile_nameÚdefaultÚ_profile_configs)rp   rx   Úgateway.session_identityr~   Útransport_profilerb   Ú_FAIL_CLOSED_POLICY)rz   rj   r|   r~   ÚidentityÚownerÚprimarys   &&     r   Úpolicy_for_runner_sourcer‰   ‰   s²   € ô �V˜X tÓ,€FÜ�6Ð/°×7Ò7¸6º>Ü  Ó0Ð0Ý4á˜6Ó"€HØ*2Ò*>ˆH×&Ò&ÄGÈFÐT]Ð_cÓDd€EÜ�fÐ5°tÓ<×IÐIÀ	€Gß�Ô!Ü˜&Ð"4°dÓ;×AÐA¸r×FÑFÀuÓMˆØŠ>Ü&Ð&Ü˜VÓ,Ð,r    N>   rn   r   ÚdirectÚprivate)Úallow_admin_fromr   )Úgroup_allow_admin_fromr`   )r   rx   rg   )Ú__conditional_annotations__r0   Ú
__future__r   Údataclassesr   Útypingr   r   r   r   r   rD   r   r1   rs   ra   r   ro   r…   r#   rK   rQ   rZ   rg   rx   Ú__all__r‰   )rŽ   s   @r   Ú<module>r“      sÎ   øðô	õ #å !ß ?Õ ?ñ -6°v¸xÐ6HÓ,IÐ ˜>Ó IáÒ:Ó;€ð 	Ð
7ØÐFð€ñ �$Ô÷
ð 
ó ð
ñ* %Ø¡)£+ÁYÃ[ôÐ ñ (Ø¡£ÁIÃKôÐ ð
 >A÷ Sõõ
>õlõYòB J€÷-r    