+
    „WÝjæ  ã                  ó–  a € 0 t $ R t^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIH	t	 ^ RI
HtHt ^ RIHt ]! 4        ^ RIHtHt ]P$                  ! ]4      t]	! R4      t]P,                  ! 4       t/ tR]R	&   / tR]R
&   R R ltR R ltR R ltR R ltR R ltR R lt R R lt!R R lt"R R lt#R%R R llt$R R  lt%R! R" lt&R# R$ lt'R# )&uÔ  Managed scope â€” IT-pushed, user-immutable config & env layer.

DISTINCT from ``hermes_cli.config.is_managed()`` / ``HERMES_MANAGED`` (a coarse package-manager
write-lock that blocks all mutation); this layer injects specific immutable values. The two are
independent and may coexist. v1 enforcement is filesystem permissions only (see
``docs/design/managed-scope.md`` Â§7); ``get_managed_dir()`` is the single seam for adding
macOS / Windows native locations later.
)ÚannotationsN)ÚPath)ÚDictÚOptional)Údrop_stale_root_modules)Úfast_safe_loadÚfile_signaturez/etc/hermesúdict[str, tuple]Ú_CONFIG_CACHEÚ
_ENV_CACHEc               ó   € V ^8„  d   QhRR/# )é   ÚreturnÚbool© )Úformats   "ÚLC:\Users\johnn\AppData\Local\hermes\hermes-agent\hermes_cli\managed_scope.pyÚ__annotate__r   '   s   € ÷ /ñ /�tñ /ó    c                 ó(   € R\         P                  9   # )z¶True inside the test suite: ignore the system ``/etc/hermes`` so a real managed scope on a
dev/CI box can't leak policy into the suite. An explicit ``HERMES_MANAGED_DIR`` still wins.ÚPYTEST_CURRENT_TEST)ÚosÚenvironr   r   r   Ú_under_pytestr   '   s   € ð !¤B§J¡JÑ.Ð.r   c               ó   € V ^8„  d   QhRR/# )r   r   zOptional[Path]r   )r   s   "r   r   r   -   s   € ÷ %ñ %˜ñ %r   c                 óê   € \         P                  P                  RR4      P                  4       p V '       d   \	        V 4      pM\        4       '       d   R# \        pVP                  4       '       d   V# R# )ub  Resolve the managed-scope directory, or None when no scope is present.

Priority: ``$HERMES_MANAGED_DIR`` (IT-only bootstrap override; never persisted to any .env;
honored only when non-empty AND the directory exists), then ``/etc/hermes`` when it exists.
A missing directory resolves to None â€” the common case, so it must be cheap + side-effect-free.
ÚHERMES_MANAGED_DIRÚ N)r   r   ÚgetÚstripr   r   Ú_DEFAULT_MANAGED_DIRÚis_dir)ÚoverrideÚps     r   Úget_managed_dirr$   -   sR   € ô �z‰z�~‰~Ð2°BÓ7×=Ñ=Ó?€HßÜ�‹N‰Ü	�ŠÙä ˆØ—‘—
’
ˆ1Ð$ Ð$r   c               ó   € V ^8„  d   QhRR/# )r   r   ÚNoner   )r   s   "r   r   r   >   s   € ÷ ñ  $ñ r   c                 ó¬   € \         ;_uu_ 4        \        P                  4        \        P                  4        RRR4       R#   + '       g   i     R# ; i)z@Drop cached managed config/env. For tests and post-edit reloads.N)Ú_CACHE_LOCKr
   Úclearr   r   r   r   Úinvalidate_managed_cacher*   >   s+   € ç	ŽÜ×ÑÔÜ×ÑÔ÷ 
��Šús   �)AÁA	c               ó    € V ^8„  d   QhRRRR/# )r   Úpathr   Úcacher	   r   )r   s   "r   r   r   E   s   € ÷ ñ �tð Ð$4ñ r   c                ó|  €  V P                  4       p\        T4      p\        T 4      p\        ;_uu_ 4        TP                  T4      pTeD   TR\        T4       T8X  d1   \        P                  ! T\        T4      ,          4      uuRRR4       # RRR4        T! T 4      p\        ;_uu_ 4        . TO\        P                  ! T4      N5Y&   RRR4       T#   \         d     R# i ; i  + '       g   i     La; i  \         d"   p\        P                  RY4        Rp?R# Rp?ii ; i  + '       g   i     T# ; i)u*  Shared stat-signature-keyed read; returns a deepcopy of the parsed value.

``None`` when the file is absent or fails to parse (fail-open). A parse failure is logged
LOUDLY â€” the admin needs to know their policy isn't applied â€” but never raises, so a malformed
managed file can't brick startup.
Nuˆ   managed scope: failed to parse %s: %s â€” IGNORING this managed file. Admin policy from this file is NOT being applied. Fix and restart.)ÚstatÚOSErrorr   Ústrr(   r   ÚlenÚcopyÚdeepcopyÚ	ExceptionÚloggerÚwarning)	r,   r-   ÚparseÚstÚkeyÚpath_keyÚhitÚparsedÚexcs	   &&&      r   Ú_cached_readr?   E   sú   € ðØ�Y‰Y‹[ˆô ˜Ó
€CÜ�4‹y€Hß	ŽØ�i‰i˜Ó!ˆØŠ?˜s 9¤C¨£H˜~°Ô4Ü—=’= ¤S¨£X¥Ó/÷ 
�ŠðÙ�t“ˆ÷ 
ŽØ7˜CÐ7¤§¢¨vÓ!6Ñ7ˆ‰÷ 
à€Møô% ô Úðú÷ 
�ûô ô Ü�‰ðQàô	õ ûðú÷ 
Žà€MúsA   ‚C ¶AC(ÂC; Â.D*ÃC%Ã$C%Ã(C8	Ã;D'ÄD"Ä"D'Ä*D;	c               ó$   € V ^8„  d   QhRRRRRR/# )r   Únamer1   r-   r	   r   Údictr   )r   s   "r   r   r   c   s"   € ÷ 6ñ 6˜Sð 6Ð)9ð 6ÀTñ 6r   c                óz   € \        4       pVf   / # \        W0,          W4      p\        V\        4      '       d   V# / # )N)r$   r?   Ú
isinstancerB   )rA   r-   r8   Úmanaged_dirr=   s   &&&  r   Ú_load_managed_filerF   c   s;   € Ü!Ó#€KØÒØˆ	Ü˜+Õ,¨eÓ;€FÜ ¬×-Ò-ˆ6Ð5°2Ð5r   c               ó   € V ^8„  d   QhRR/# )r   r   rB   r   )r   s   "r   r   r   k   s   € ÷ ñ ˜Tñ r   c                 ó&   € \        R\        R 4      # )zDParsed managed config.yaml, or {} when absent/malformed (fail-open).zconfig.yamlc                óL   € \        V P                  R R7      4      ;'       g    / # )ú	utf-8-sig©Úencoding)r   Ú	read_text)r#   s   &r   Ú<lambda>Ú%load_managed_config.<locals>.<lambda>m   s%   € ÄnÐUV×U`ÑU`ÐjuÐU`ÓUvÓFw×F}ÐF}Ð{}ÐF}r   )rF   r
   r   r   r   Úload_managed_configrP   k   s   € ä˜m¬]Ñ<}Ó~Ð~r   c               ó   € V ^8„  d   QhRR/# )r   r   údict[str, str]r   )r   s   "r   r   r   p   s   € ÷ Fñ F˜.ñ Fr   c                 ó,   € \        R\        \        4      # )z?Parsed managed .env (KEY=VALUE), or {} when absent (fail-open).z.env)rF   r   Ú_parse_managed_envr   r   r   Úload_managed_envrU   p   s   € ä˜f¤jÔ2DÓEÐEr   c               ó    € V ^8„  d   QhRRRR/# )r   r,   r   r   rR   r   )r   s   "r   r   r   u   s   € ÷ ñ ˜Tð  nñ r   c                óB   € ^ RI Hp V P                  RR7       V! V 4      # )é    )Úload_env_filerJ   rK   )Úagent.secret_scoperY   rM   )r,   rY   s   & r   rT   rT   u   s   € Ý0à‡N�N˜K€NÔ(Ù˜ÓÐr   c               ó    € V ^8„  d   QhRRRR/# )r   ÚconfigrB   r   r   )r   s   "r   r   r   |   s   € ÷ ñ  $ð ¨4ñ r   c                ó<  €  \        4       pV'       g   V # ^ RIHpHpHp V! V! V4      4      p\        VP                  R4      \        4      '       d   \        V4      pRVR,          /VR&   V! W4      #   \         d    \        P                  RRR7       T u # i ; i)a  Overlay administrator-pinned config values on top of an already-built dict.

``${VAR}`` refs in the managed config expand against the PROCESS env only, so a user cannot
shadow a managed literal via a ref they control; a bare root ``model: x/y`` string is promoted
to ``model.default`` so it can't clobber the dict shape callers expect; managed values
deep-merge ON TOP per leaf while sibling keys stay user-controlled. Fail-open: returns
``config`` unchanged when no scope is present or on any error. Mutates and returns ``config``.
)Ú_deep_mergeÚ_expand_env_varsÚ_normalize_root_model_keysÚmodelÚdefaultz-managed scope: failed to apply config overlayT)Úexc_info)rP   Úhermes_cli.configr^   r_   r`   rD   r   r1   rB   r5   r6   r7   )r\   Úmanagedr^   r_   r`   Úmanaged_expandeds   &     r   Úapply_managed_overlayrg   |   sœ   € ðÜ%Ó'ˆßØˆMç_Ñ_Ù5Ñ6FÀwÓ6OÓPÐô Ð&×*Ñ*¨7Ó3´S×9Ò9Ü#Ð$4Ó5ÐØ)2Ð4DÀWÕ4MÐ(NÐ˜WÑ%Ù˜6Ó4Ð4øÜô Ü�‰ÐFÐQUˆÔVØŠðús   ‚A4 –AA4 Á4$BÂBc               ó$   € V ^8„  d   QhRRRRRR/# )r   ÚdrB   Úprefixr1   r   Úsetr   )r   s   "r   r   r   ˜   s!   € ÷ ñ �Tð  3ð °ñ r   c                ó  € \        4       pV P                  4        Fb  w  r4V'       d   V R V 2M
\        V4      p\        V\        4      '       d   V'       d   V\        WE4      ,          pKQ  VP                  V4       Kd  	  V# )Ú.)rk   Úitemsr1   rD   rB   Ú_flatten_keysÚadd)ri   rj   ÚkeysÚkÚvÚdotteds   &&    r   ro   ro   ˜   sc   € Ü“€DØ—‘–	‰ˆß$*�F�8˜1˜Q˜C‘´°A³ˆÜ�aœ×Ò§1Ø”M !Ó,Õ,ŠDà�H‰H�VÖñ ð €Kr   c               ó   € V ^8„  d   QhRR/# )r   r   rk   r   )r   s   "r   r   r   £   s   € ÷ 0ñ 0˜Sñ 0r   c                 ó(   € \        \        4       4      # )zGDotted leaf keys pinned by the managed config (e.g. {'model.default'}).)ro   rP   r   r   r   Úmanaged_config_keysrw   £   s   € äÔ,Ó.Ó/Ð/r   c               ó    € V ^8„  d   QhRRRR/# )r   Ú
dotted_keyr1   r   r   r   )r   s   "r   r   r   ¨   s   € ÷ /ñ /˜sð / tñ /r   c                ó   € V \        4       9   # )zCTrue if the exact dotted config key is pinned by the managed layer.)rw   )ry   s   &r   Úis_key_managedr{   ¨   s   € àÔ,Ó.Ñ.Ð.r   c               ó    € V ^8„  d   QhRRRR/# )r   rA   r1   r   r   r   )r   s   "r   r   r   ­   s   € ÷ &ñ &˜ð & ñ &r   c                ó   € V \        4       9   # )z=True if the env var name is pinned by the managed .env layer.)rU   )rA   s   &r   Úis_env_managedr~   ­   s   € àÔ#Ó%Ñ%Ð%r   )r   )(Ú__conditional_annotations__Ú__doc__Ú
__future__r   r3   Úloggingr   Ú	threadingÚpathlibr   Útypingr   r   Úhermes_cli.stale_modulesr   Úutilsr   r   Ú	getLoggerÚ__name__r6   r    ÚLockr(   r
   Ú__annotations__r   r   r$   r*   r?   rF   rP   rU   rT   rg   ro   rw   r{   r~   )r   s   @r   Ú<module>rŒ      s²   øðôõ #ã Û Û 	Û Ý ß !õ =á Ô ç 0à	×	Ò	˜8Ó	$€ñ ˜MÓ*Ð à�nŠnÓ€à"$€ÐÓ $Ø!€
ÐÓ !õ/õ%õ"õõ<6õõ
Fõ
õ÷8õ0õ
/÷
&r   