+
    iHàjoa  ã            
      ón  a € 0 t $ R t^ RIHt ^ RIt^ RIHt ^ RIHt ^ RI	H
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RRR R lltR R ltR R ltRR/R R lltR R ltRStR  R! ltR" R# ltR$ R% ltRTtR&R'/R( R) lltR* R+ ltR, R- ltRR.R&R'/R/ R0 lltR1 R2 lt 0 RUmt!R4]"R5&   R6t#R7R8R9R3R:]PH                  PK                  R;R<4      ]PH                  PK                  R=R>4      3t&RVt'R? R@ lt(RA RB lt)RC RD lt*REt+RF RG lt,RH RI lt-RJ RK lt.RL RM lt/RWRN RO llt0RWRP RQ llt1R# )Xa  Shared file safety rules used by both tools and ACP shims.

Every guard here is defense-in-depth, NOT a security boundary: the terminal
tool runs as the same OS user and can read/write anything. The value is a
clear denial for models that respect tool errors plus a visible audit trail.
)ÚannotationsN)ÚPath)Úsuppress)ÚOptionalc               ó    € V ^8„  d   QhRRRR/# )é   Úgetter_nameÚstrÚreturnr   © )Úformats   "Ú6/home/ubuntu/.hermes/hermes-agent/agent/file_safety.pyÚ__annotate__r      s   € ÷ 5ñ 5 ð 5¨ñ 5ó    c                óž   €  ^ RI p\        W4      ! 4       #   \         d,    \        \        P
                  P                  R4      4      u # i ; i)zeCall ``hermes_constants.<getter_name>()`` (local import avoids cycles); ``~/.hermes`` on any failure.Nz	~/.hermes)Úhermes_constantsÚgetattrÚ	Exceptionr   ÚosÚpathÚ
expanduser)r   r   s   & r   Ú_constants_pathr      sB   € ð5ÛäÐ'Ô5Ó7Ð7øÜô 5Ü”B—G‘G×&Ñ& {Ó3Ó4Ò4ð5ús   ‚ –3AÁAc               ó   € V ^8„  d   QhRR/# ©r   r
   r   r   )r   s   "r   r   r      s   € ÷ .ñ .˜4ñ .r   c                 ó   € \        R4      # )z@Active HERMES_HOME (profile-aware). Tests monkeypatch this name.Úget_hermes_home©r   r   r   r   Ú_hermes_home_pathr      s   € äÐ,Ó-Ð-r   c               ó   € V ^8„  d   QhRR/# r   r   )r   s   "r   r   r      s   € ÷ 6ñ 6˜4ñ 6r   c                 ó   € \        R4      # )z;Hermes root dir (parent of any profile, never per-profile).Úget_default_hermes_rootr   r   r   r   Ú_hermes_root_pathr!      s   € äÐ4Ó5Ð5r   c               ó   € V ^8„  d   QhRR/# ©r   r
   z
list[Path]r   )r   s   "r   r   r   $   s   € ÷ Zñ Z�jñ Zr   c            	     ót   € \        \        P                  \        \	        4       \        4       34      4      4      # )zÂResolved active HERMES_HOME and global root, deduplicated.

Both are checked so credential stores at <root>/... stay guarded when
running under a profile (HERMES_HOME = <root>/profiles/<name>).
)ÚlistÚdictÚfromkeysÚ_resolve_eachr   r!   r   r   r   Ú_hermes_dirsr)   $   s*   € ô ”—‘œmÔ->Ó-@ÔBSÓBUÐ,VÓWÓXÓYÐYr   c               ó   € V ^8„  d   QhRR/# r#   r   )r   s   "r   r   r   -   s   € ÷ ñ ˜Jñ r   c                óÂ   € . pV  FB  p\        \        4      ;_uu_ 4        VP                  VP                  4       4       RRR4       KD  	  V#   + '       g   i     KY  ; i)zB``p.resolve()`` for each path, skipping ones that fail to resolve.N)r   r   ÚappendÚresolve)ÚpathsÚoutÚps   &  r   r(   r(   -   sI   € à€CÛˆÜ”i× Õ Ø�J‰J�q—y‘y“{Ô#÷ !Ñ ñ ð €J÷ !× Ð ús   Ÿ AÁAc               ó$   € V ^8„  d   QhRRRRRR/# )r   Úresolvedz
str | PathÚbaser
   Úboolr   )r   s   "r   r   r   6   s&   € ÷ Gñ G˜
ð G¨*ð G¸ñ Gr   c                óð   € \        V \        4      '       d    V P                  V4      RJ# W8H  ;'       g0    V P	                  \        V4      \        P                  ,           4      #   \         d     R# i ; i)zªTrue when ``resolved`` equals ``base`` or lies below it (both already resolved);
``Path`` inputs use ``relative_to`` (platform semantics), ``str`` a realpath prefix test.NF)Ú
isinstancer   Úrelative_toÚ
ValueErrorÚ
startswithr	   r   Úsep)r2   r3   s   &&r   Ú	_is_underr;   6   sk   € ô �(œD×!Ò!ð	Ø×'Ñ'¨Ó-°TÐ9Ð9ð Ñ×FÐF˜x×2Ñ2´3°t³9¼r¿v¹vÕ3EÓFÐFøô ô 	Úð	ús   ˜A& Á&A5Á4A5c               ó    € V ^8„  d   QhRRRR/# )r   r   r	   r
   zOptional[Path]r   )r   s   "r   r   r   A   s   € ÷ ñ ˜#ð  .ñ r   c           	     óö   € \        \        \        4      ;_uu_ 4        \        \        P
                  P                  \        V 4      4      4      P                  4       uuRRR4       #   + '       g   i     R# ; i)zD``Path(expanduser(path)).resolve()``, or None when resolution fails.N)	r   ÚOSErrorÚRuntimeErrorr   r   r   r   r	   r-   ©r   s   &r   Ú_resolve_targetrA   A   sE   € ä	”'œ<×	(Õ	(Ü”B—G‘G×&Ñ&¤s¨4£yÓ1Ó2×:Ñ:Ó<÷ 
)×	(×	(Ñ	(áús   �?A'Á'A8	c               ó    € V ^8„  d   QhRRRR/# )r   r   r	   r
   úset[str]r   )r   s   "r   r   r   H   s   € ÷ 0ñ 0�sð 0 Hñ 0r   c                ó&  € \         P                  P                  R4      0p\        \        4      ;_uu_ 4        ^ RIHpHpHp V! 4       V! 4       V! 4       3 F'  pV'       g   K  VP                  \        V4      4       K)  	  RRR4       \        V 4      p\        V4      ^8”  d§   VP                  R4      '       d�   V^,          R9  d‚   VR,          P                  R^4      ^ ,          P                  R^4      ^ ,          p\         P                  P                  RV 24      pVP                  R4      '       g   VP                  V4       V U	u0 uF"  p	\         P                  P                  V	4      kK$  	  up	#   + '       g   i     EL; iu up	i )uŒ  Every home the write guards must cover. Process ``~`` alone is wrong whenever the
process HOME is not the OS user's real home â€” ``TERMINAL_HOME_MODE=profile``,
containers, and spawned workers pin ``HOME`` to ``{HERMES_HOME}/home``, which leaves
the real home's credential paths unguarded against absolute-path writes while file
tools happily write there (and ``_expand_tilde`` may route ``~`` to yet another
home). Deny/approval lists are built over the union: process home, real home,
subprocess home, and the profile home. A ``~name/...`` input resolves to a named
account's home, which joins the set so ``~root/.ssh/authorized_keys`` stays denied.Ú~)Úget_real_homeÚget_subprocess_homeÚ_profile_home_pathNz/\:é   NNÚ/Ú\)r   r   r   r   r   r   rF   rG   rH   Úaddr	   Úlenr9   ÚsplitÚrealpath)
r   ÚhomesrF   rG   rH   Ú	candidateÚrawÚnameÚexpandedÚhs
   &         r   Ú_guard_homesrV   H   s'  € ô �W‰W×Ñ Ó$Ð%€EÜ	”)×	Õ	ß[Ñ[á'›/Ñ+>Ó+@ÑBTÓBVÓWˆIß‰yØ—	‘	œ#˜i›.Ö)ñ X÷ 
ô ˆd‹)€CÜ
ˆ3ƒx�!„|˜Ÿ™ s×+Ò+°°Aµ¸eÔ0CØ�2�w�}‰}˜S !Ó$ QÕ'×-Ñ-¨d°AÓ6°qÕ9ˆÜ—7‘7×%Ñ%¨¨$¨ jÓ1ˆØ×"Ñ" 3×'Ò'Ø�I‰I�hÔÙ).Ó/© AŒB�G‰G×Ñ˜QÖ©Ñ/Ð/÷ 
×	Ð	üò 0s   ¸'E:Á$E:Å(FÅ:F	c               ó    € V ^8„  d   QhRRRR/# )r   r   r	   r
   ztuple[set[str], str]r   )r   s   "r   r   r   a   s   € ÷ Oñ O˜cð OÐ&:ñ Or   c                ó¢   € \        V 4      \        P                  P                  \        P                  P	                  \        V 4      4      4      3# )uR   ``(guard homes, realpath(expanduser(path)))`` â€” the write-guard coordinate pair.)rV   r   r   rO   r   r	   r@   s   &r   Ú_homes_and_resolvedrY   a   s4   € ä˜ÓœrŸw™w×/Ñ/´·±×0BÑ0BÄ3ÀtÃ9Ó0MÓNÐNÐNr   c               ó    € V ^8„  d   QhRRRR/# ©r   r   r	   r
   r4   r   )r   s   "r   r   r   �   s   € ÷ ñ ˜sð  tñ r   c                ó`  € \        V 4      P                  RR4      pVP                  R4      '       d   R# VP                  R4      '       d   R# VP                  R4      '       dJ   VR,          pVP                  4       pVP                  R4      '       g   VP                  R	4      '       d   R# R
# )uÁ   Return True if ``path`` is a Windows NT-/device-namespace path.

Checks the raw string only â€” never resolves the path (resolving is the
credential-leak trigger this guard exists to prevent).
rJ   rK   z\??\Tz\\.\z\\?\:é   NNzUNC\zGLOBALROOT\F)r	   Úreplacer9   Úupper)r   ÚsÚrestr_   s   &   r   Úis_nt_namespace_pathrb   �   sˆ   € ô 	ˆD‹	×Ñ˜#˜tÓ$€AØ‡|�|�H×ÒÙØ‡|�|�I×ÒÙØ‡|�|�I×ÒØ��uˆØ—
‘
“ˆØ×Ñ˜G×$Ò$¨×(8Ñ(8¸×(HÒ(HÙÙr   ÚverbÚAccessc               ó$   € V ^8„  d   QhRRRRRR/# )r   r   r	   rc   r
   úOptional[str]r   )r   s   "r   r   r   £   s!   € ÷ 
ñ 
 ð 
¨sð 
À-ñ 
r   c               ó8   € \        V 4      '       g   R# V RV  R2# )zCReturn an error message when ``path`` uses the NT/device namespace.Nú
 denied: 'a   ' uses a Windows NT/device namespace prefix (\??\, \\.\, \\?\UNC\, or GLOBALROOT). These paths bypass normal path normalization and can trigger outbound SMB authentication (NTLM credential leak) merely by being resolved. Use a normal absolute path instead.)rb   )r   rc   s   &$r   Úget_nt_namespace_errorri   £   s*   € ä ×%Ò%Ùàˆ&�
˜4˜&ð !.ð 	.ðr   c               ó    € V ^8„  d   QhRRRR/# ©r   Úhomer	   r
   rC   r   )r   s   "r   r   r   °   s   € ÷ 0ñ 0 3ð 0¨8ñ 0r   c                ól  a € RpRR\         P                  P                  RR4      \         P                  P                  RR4      \         P                  P                  RR4      3p. V 3R lV 4       OR	 V 4       OR
NRNRNpV Uu0 uF"  p\         P                  P                  V4      kK$  	  up# u upi )z8Return exact sensitive paths that must never be written.ú.envú.anthropic_oauth.jsonÚauthúgoogle_oauth.jsonÚcacheúbws_cache.jsonzbws_cache.enc.jsonc              3  óh   <"  € T F'  p\         P                  P                  ! S.VO5!  x € K)  	  R # 5i©N)r   r   Újoin)Ú.0Úfrl   s   & €r   Ú	<genexpr>Ú+build_write_denied_paths.<locals>.<genexpr>Ê   s&   øé € Ð	5©* QŒ"�'‰'�,Š,�tÐ
 ˜a×
 Ð
 «*ùs   ƒ/2c              3  óz   "  € T F1  p\        4       \        4       3 F  p\        W!,          4      x € K  	  K3  	  R # 5iru   )r   r!   r	   )rw   rx   r3   s   &  r   ry   rz   Ë   s.   é € Ð	e¡˜AÔ;LÓ;NÔPaÓPcÓ:d°$Œ#ˆd�h�-ˆ-Ñ:d‰-£ùs   ‚9;z/etc/sudoersz/etc/passwdz/etc/shadow))ú.sshÚauthorized_keys)r|   Úid_rsa)r|   Ú
id_ed25519)z.netrc)z.pgpass)z.npmrc)z.pypirc)z.git-credentials)r   r   rv   rO   )rl   Ú
home_filesÚhermes_filesr.   r0   s   f    r   Úbuild_write_denied_pathsr‚   °   sº   ø€ ð
€Jð 	Ð'Ü
�‰�‰�VÐ0Ó1Ü
�‰�‰�WÐ.Ó/Ü
�‰�‰�WÐ2Ó3ð	€LðÜ	5©*Ó	5ðá	e¡Ó	eðð 	ðð &ðð (5ð€Eñ
 */Ó/© AŒB�G‰G×Ñ˜QÖ©Ñ/Ð/ùÒ/s   Â(B1c               ó    € V ^8„  d   QhRRRR/# )r   rl   r	   r
   z	list[str]r   )r   s   "r   r   r   Õ   s   € ÷ 9ñ 9 cð 9¨iñ 9r   c                óÂ   a € . V 3R l\          4       ORNRNpV Uu. uF7  p\        P                  P                  V4      \        P                  ,           NK9  	  up# u upi )z?Return sensitive directory prefixes that must never be written.c              3  ó†   <"  € T F6  p\         P                  P                  ! S.VP                  R 4      O5!  x € K8  	  R# 5i)rJ   N)r   r   rv   rN   )rw   Údrl   s   & €r   ry   Ú.build_write_denied_prefixes.<locals>.<genexpr>Ø   s0   øé € Ð	JÑ5I°Œ"�'‰'�,Š,�tÐ
+˜aŸg™g c›l×
+Ð
+Ó5Iùs   ƒ>Az/etc/sudoers.dz/etc/systemd)ÚHOME_CREDENTIAL_DIRSr   r   rO   r:   )rl   r.   r0   s   f  r   Úbuild_write_denied_prefixesr‰   Õ   s]   ø€ ðÜ	JÕ5IÓ	Jðàðà(ð€Eñ 38Ó8±%¨QŒB�G‰G×Ñ˜QÓ¤"§&¡&×(Ð(±%Ñ8Ð8ùÒ8s   œ=Ac               ó   € V ^8„  d   QhRR/# )r   r
   rC   r   )r   s   "r   r   r   Þ   s   € ÷ ñ ˜hñ r   c            
     ó¬  € \        4       p \        R\        P                  ! RR4      P	                  \        P
                  4      4       Fs  p\        \        \        4      ;_uu_ 4        V P                  \        P                  P                  \        P                  P                  V4      4      4       RRR4       Ku  	  V #   + '       g   i     KŠ  ; i)zFResolved HERMES_WRITE_SAFE_ROOT paths (``os.pathsep``-separated list).NÚHERMES_WRITE_SAFE_ROOTÚ )ÚsetÚfilterr   ÚgetenvrN   Úpathsepr   r>   r8   rL   r   rO   r   )Úrootsr   s     r   Úget_safe_write_rootsr“   Þ   sˆ   € ä“e€EÜ�tœRŸYšYÐ'?ÀÓD×JÑJÌ2Ï:É:ÓVÖWˆÜ”gœz×*Õ*Ø�I‰I”b—g‘g×&Ñ&¤r§w¡w×'9Ñ'9¸$Ó'?Ó@ÔA÷ +Ñ*ñ Xð €L÷ +×*Ð*ús   Á(ACÃCc               ó    € V ^8„  d   QhRRRR/# rk   r   )r   s   "r   r   r   ç   s   € ÷ Dñ D Sð D¨Xñ Dr   c                ó€   € \         P                  P                  \         P                  P                  V RR4      4      0# )ae  Paths that need human APPROVAL to write but are not hard-denied credentials.

``~/.ssh/config`` is routine to edit and holds no key bytes, but can carry
``ProxyCommand`` / ``Match exec``. Interactive file tools prompt
(approve-once/session/always, like the terminal tool's ``~/.ssh`` gate);
non-interactive callers (ACP shims, background jobs) fail closed.
r|   Úconfig)r   r   rO   rv   )rl   s   &r   Úbuild_write_approval_pathsr—   ç   s-   € ô �G‰G×ÑœRŸW™WŸ\™\¨$°¸ÓAÓBÐCÐCr   ÚentryFc               ó$   € V ^8„  d   QhRRRRRR/# )r   r   r	   r˜   r4   r
   rf   r   )r   s   "r   r   r   ü   s!   € ÷ >ñ > ð >°ð >Àñ >r   c               óà  € \        V 4      '       d   R# \        V 4      w  r#^ RIHpHp V! V 4      '       g   V'       d   V! V RR7      '       d   R# \        W#4      pV'       g	   V'       g   V# V! \        P                  P                  \        V 4      4      4      w  rx\        P                  P                  \        P                  P                  T;'       g    R4      V4      p	\        W)4      # )u0  Return ``'credential'``, ``'safe_root'``, ``'nt_namespace'``, or ``None`` if writes are allowed.

``entry=True`` is for ops that unlink/rename the directory entry itself (a
symlink, not its target): the entry â€” parent realpath'd, final component
kept â€” is vetted as well as the target it resolves to.Únt_namespace)Úis_protected_pathÚsplit_entryF)ÚfollowÚ
credentialÚ.)rb   rY   Úagent.runtime_self_protectionrœ   r�   Ú_classify_resolved_write_denialr   r   r   r	   rv   rO   )
r   r˜   rP   r2   rœ   r�   ÚdenialÚparentÚleafÚ
entry_paths
   &$        r   Ú_classify_write_denialr§   ü   s¨   € ô ˜D×!Ò!ÙÜ)¨$Ó/�O€E÷
 Má˜×Ò§5Ñ->¸tÈE×-RÓ-RÙÜ,¨UÓ=€Fß—UØˆÙœrŸw™w×1Ñ1´#°d³)Ó<Ó=�L€FÜ—‘—‘œbŸg™g×.Ñ.¨v¯}¨}¸Ó=¸tÓD€JÜ*¨5Ó=Ð=r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   rP   rC   r2   r	   r
   rf   r   )r   s   "r   r   r     s!   € ÷ ñ ¨8ð ¸sð À}ñ r   c                ó$  a€ \         ;QJ d    V3R lV  4       F  '       g   K   RM	  RM! V3R lV  4       4      '       d   R# \         ;QJ d    V3R lV  4       F  '       g   K   RM	  RM! V3R lV  4       4      '       d   R# \        4        F”  p\         F‡  p\        \        4      ;_uu_ 4        \        S\        P                  P                  \        P                  P                  \        V4      V4      4      4      '       d    RRR4         R#  RRR4       K‰  	  K–  	  \        4       pV'       dC   \         ;QJ d    V3R lV 4       F  '       g   K   RM	  RM! V3R lV 4       4      '       g   R# R#   + '       g   i     Kö  ; i)	zPCredential / protected-subpath / safe-root verdict for an already-resolved path.c              3  ó@   <"  € T F  pS\        V4      9   x € K  	  R # 5iru   ©r—   ©rw   rl   r2   s   & €r   ry   Ú2_classify_resolved_write_denial.<locals>.<genexpr>  s   øé € Ð
JÁE¸Dˆ8Ô1°$Ó7Ö7ÃEùó   ƒTFNc              3  óè   <"  € T Fg  pS\        V4      9   ;'       gM    \        ;QJ d(    V3R  l\        V4       4       F  '       g   K   RM	  RM! V3R  l\        V4       4       4      x € Ki  	  R# 5i)c              3  óF   <"  € T F  pSP                  V4      x € K  	  R # 5iru   )r9   )rw   Úprefixr2   s   & €r   ry   Ú<_classify_resolved_write_denial.<locals>.<genexpr>.<genexpr>!  s!   øé € Ð[Ñ9Z¨vˆx×"Ñ" 6×*Ð*Ó9Zùs   ƒ!TFN)r‚   Úanyr‰   r¬   s   & €r   ry   r­     sc   øé € ð ñ ˆDð 	Ô,¨TÓ2Ñ2÷ 	\ð 	\ß‹3Ô[Ô9TÐUYÔ9ZÓ[�3�3Š3Ô[Ô9TÐUYÔ9ZÓ[Ó[ô	\ãùs   ƒA2�A2©A2Á	)A2rŸ   c              3  ó<   <"  € T F  p\        SV4      x € K  	  R # 5iru   ©r;   )rw   Úrootr2   s   & €r   ry   r­   -  s   øé € ÐOÁJ¸Dœi¨°$×7Ð7ÃJùs   ƒÚ	safe_root)r³   r)   Ú_HERMES_PROTECTED_SUBPATHSr   r   r;   r   r   rO   rv   r	   r“   )rP   r2   r3   ÚsubÚ
safe_rootss   &f   r   r¢   r¢     s  ø€ ÷ ƒsÔ
JÁEÓ
J‡s‡s‚sÔ
JÁEÓ
J×JÒJÙç
ƒsô ñ ó‡s‡s‚sô ñ ó÷ ò ñ
 ä–ˆß-ˆCÜœ)×$Õ$Ü˜X¤r§w¡w×'7Ñ'7¼¿¹¿¹ÄSÈÃYÐPSÓ8TÓ'U×VÒVØ'÷ %Ó$ØV÷ %Ñ$ó .ñ ô &Ó'€JßŸ#›#ÔOÁJÓOŸ#Ÿ#š#ÔOÁJÓO×OÒOÙá÷ %×$Ð$ús   Â3AE>	Å>Fc               ó    € V ^8„  d   QhRRRR/# r[   r   )r   s   "r   r   r   3  s   € ÷ 4ñ 4˜#ð 4 $ñ 4r   c                ó   € \        V 4      RJ# )zBReturn True if path is blocked by the write denylist or safe root.N)r§   r@   s   &r   Úis_write_deniedr½   3  s   € ä! $Ó'¨tÐ3Ð3r   ÚWritec               ó(   € V ^8„  d   QhRRRRRRRR/# )r   r   r	   rc   r˜   r4   r
   rf   r   )r   s   "r   r   r   8  s/   € ÷ añ a ð a¨sð aÀTð aÐVcñ ar   c               óè   € \        WR7      pVR8X  d<   \        P                  P                  \	        \        4       4      4      pV RV  RV R2# VR8X  d   \        WR7      # V'       d	   V RV  R2# R	# )
zuReturn a user/model-facing error when writes to ``path`` are blocked
(``entry``: see :func:`_classify_write_denial`).)r˜   r·   rh   z%' is outside HERMES_WRITE_SAFE_ROOT (z:). Unset the variable or add this path's directory prefix.r›   ©rc   z(' is a protected system/credential file.N)r§   r   r‘   rv   Úsortedr“   ri   )r   rc   r˜   r£   Úroots_displays   &$$  r   Úget_write_denied_errorrÄ   8  s…   € ô $ DÔ6€FØ�ÔÜŸ
™
Ÿ™¬Ô/CÓ/EÓ(FÓGˆàˆf�J˜t˜fð %ØˆÐXðZð	
ð �ÔÜ% dÔ6Ð6ßPVˆdˆV�:˜d˜VÐ#KÐLÐ`Ð\`Ð`r   c               ó    € V ^8„  d   QhRRRR/# r[   r   )r   s   "r   r   r   G  s   € ÷ Oñ O Sð O¨Tñ Or   c                ó”   a€ \        V 4      w  po\        ;QJ d    V3R lV 4       F  '       g   K   R# 	  R# ! V3R lV 4       4      # )z�True if ``path`` is approval-gated (``~/.ssh/config``): interactive callers
prompt, callers without a channel treat it as a block (fail closed).c              3  ó@   <"  € T F  pS\        V4      9   x € K  	  R # 5iru   r«   r¬   s   & €r   ry   Ú-is_write_approval_required.<locals>.<genexpr>K  s   øé € ÐNÉÀˆxÔ5°dÓ;Ö;Ëùr®   TF)rY   r³   )r   rP   r2   s   & @r   Úis_write_approval_requiredrÉ   G  s<   ø€ ô *¨$Ó/�O€Eˆ8ß‹3ÔNÉÓN�3Œ3ÐNŠ3ÐNˆ3ÔNÉÓNÓNÐNr   rn   rC   Ú_BLOCKED_PROJECT_ENV_BASENAMESuT    (Defense-in-depth â€” not a security boundary; the terminal tool can still bypass.)z	auth.jsonz	auth.lockro   zwebhook_subscriptions.jsonrp   rq   rr   rs   c               ó    € V ^8„  d   QhRRRR/# ©r   r   r	   r
   rf   r   )r   s   "r   r   r   p  s   € ÷ .Añ .A˜sð .A }ñ .Ar   c                ó  aaa€ \        V RR7      pV'       d   V# \        V 4      P                  4       P                  4       o\	        4       oRp\
        ;QJ d    V3R lS 4       F  '       g   K   RM	  RM! V3R lS 4       4      '       d   RpMì\
        ;QJ d$    VV3R l\         4       F  '       g   K   RM	  RM! VV3R l\         4       4      '       d   R	\        ,           pM”\         FV  w  or4\        V3R
 lS 4       4       F-  p\        SV4      '       g   K  SV8X  d   TMT\        ,           p M	  V'       g   KV   M	  Vf1   SP                  P                  4       \        9   d   R\        ,           pV'       d	   RV  RV 2# R# )aJ  Return an error message when a read targets a denied Hermes path.

Blocked: internal skill-hub caches (prompt-injection carriers), credential
stores under HERMES_HOME and the global root (exact files, plus anything
under ``mcp-tokens/`` and ``browser-profile/``), and project-local ``.env``
files anywhere on disk (``.env.example`` is the documented-shape substitute).

Callers that resolve relative paths against a non-process cwd (e.g.
``TERMINAL_CWD``) MUST pass an absolute path: ``resolve()`` here anchors at
the process cwd, so a relative ``"auth.json"`` would miss the denylist.
ÚReadrÁ   Nc              3  óX   <"  € T F  p\        SVR ,          R,          4      x € K!  	  R# 5i)Úskillsz.hubNrµ   )rw   Úhdr2   s   & €r   ry   Ú'get_read_block_error.<locals>.<genexpr>‡  s$   øé € Ð
MÁ¸2Œ9�X˜r H�}¨vÕ5×6Ð6Ãùs   ƒ'*TFzŠis an internal Hermes cache file and cannot be read directly to prevent prompt injection. Use the skills_list or skill_view tools instead.c              3  óV   <a"  € T F  oS\        V3R  lS 4       4      9   x € K  	  R# 5i)c              3  ó4   <"  € T F  qS,          x € K  	  R # 5iru   r   )rw   rÑ   rS   s   & €r   ry   Ú1get_read_block_error.<locals>.<genexpr>.<genexpr>Œ  s   øé € Ð&G¹;°R¨D§y¢y»;ùó   ƒN)r(   )rw   rS   Úhermes_dirsr2   s   &@€€r   ry   rÒ   Œ  s#   ùé € ÐkÑTjÈDˆXœÔ&G¹;Ó&GÓGÖGÓTjùs   „%)z}is a Hermes credential store and cannot be read directly. Provider tools consume these credentials through internal channels.c              3  ó4   <"  € T F  qS,          x € K  	  R # 5iru   r   )rw   rÑ   Úsubdirs   & €r   ry   rÒ   “  s   øé € Ð,OÁ;¸R°&¯[ª[Ã;ùrÖ   zšis a secret-bearing environment file and cannot be read to prevent credential leakage. If you need to check the file structure, read .env.example instead.zAccess denied: Ú )ri   r   r   r-   r)   r³   Ú_CREDENTIAL_FILE_NAMESÚ_DID_SUFFIXÚ_READ_DENIED_DIRSr(   r;   rS   ÚlowerrÊ   )	r   Únt_errorÚreasonÚdir_msgÚfile_msgÚblocked_dirr×   r2   rÙ   s	   &     @@@r   Úget_read_block_errorrä   p  sF  ú€ ô" & d°Ô8€HßØˆÜ�D‹z×$Ñ$Ó&×.Ñ.Ó0€HÜ“.€KØ€Fß
ƒsÔ
MÁÓ
M‡s‡s‚sÔ
MÁÓ
M×MÒMðQñ 	÷ 
‹ÕkÕTjÓk��ŠÕkÕTjÓk×	kÒ	kðCÜEPõQñ 	÷
 *;Ñ%ˆF�GÜ,Ô,OÁ;Ó,OÖO�Ü˜X {×3Ô3Ø)1°[Ô)@™gÀhÔR]Õ]�FÙñ  P÷ ‰vÙñ *;ð Š>˜hŸm™m×1Ñ1Ó3Ô7UÔUð_Üalõmð ÷ 17ˆ_˜T˜F ! F 8Ð,Ð@¸DÐ@r   c               ó    € V ^8„  d   QhRRRR/# )r   r   r	   r
   ÚNoner   )r   s   "r   r   r   ¡  s   € ÷ "ñ " ð "¨ñ "r   c                óh   €  \        V 4      pT'       d   \        T4      hR#   \         d     R# i ; i)a  Raise ``ValueError`` if ``path`` is a denied Hermes read (see ``get_read_block_error``).

Shared chokepoint for provider input-loading sites (e.g. image-gen local
paths). Best-effort: unexpected internal errors no-op rather than break
local-file loading; a real block still propagates.
N)rä   r   r8   )r   Úblockeds   & r   Úraise_if_read_blockedré   ¡  s:   € ðÜ& tÓ,ˆ÷ Ü˜Ó!Ð!ñ øô ô Úðús   ‚" ¢1°1c               ó   € V ^8„  d   QhRR/# )r   r
   r	   r   )r   s   "r   r   r   °  s   € ÷ ,ñ , cñ ,r   c                 ó   €  \        4       P                  4       P                  \        4       P                  4       R,          4      P                  p T '       d
   T ^ ,          # R#   \
        \        \        3 d     R# i ; i)z“Active profile name from HERMES_HOME: ``~/.hermes`` -> ``"default"``,
``~/.hermes/profiles/X`` -> ``"X"``; ``"default"`` on any resolution failure.ÚprofilesÚdefault)r   r-   r7   r!   Úpartsr>   r?   r8   )rî   s    r   Ú_resolve_active_profile_namerï   °  sj   € ðÜ!Ó#×+Ñ+Ó-×9Ñ9Ô:KÓ:M×:UÑ:UÓ:WÐZdÕ:dÓe×kÑkˆ÷ ˆ5��8Ð+ )Ð+øô ”\¤:Ð.ô Úðús   ‚AA# Á#A=Á<A=u[  Sandbox-mirror write blocked by soft guard: {target_path} sits under {mirror_root!r}, which is {body} Use the host-side tool for authoritative state (e.g. ``memory`` for memories), or address the host path directly. To bypass {bypass} with ``cross_profile=True``. (Defense-in-depth â€” not a security boundary; the terminal tool can still bypass.)c               ó(   € V ^8„  d   QhRRRRRRRR/# )r   Útargetr   Úmirror_rootÚ
inner_pathr	   r
   r&   r   )r   s   "r   r   r   Ê  s.   € ÷ cñ c˜ð c¨Dð c¸cð cÀdñ cr   c                ó6   € R\        V 4      R\        V4      RV/# )z1Common ``classify_*_mirror_target`` result shape.Útarget_pathrò   ró   )r	   )rñ   rò   ró   s   &&&r   Ú_mirror_inforö   Ê  s   € àœ3˜v›;¨´s¸;Ó7GÈÐWaÐbÐbr   c               ó    € V ^8„  d   QhRRRR/# )r   r   r	   r
   úOptional[dict]r   )r   s   "r   r   r   Ï  s   € ÷ Fñ F¨ð F°ñ Fr   c           	     ó.  a€ \        V 4      pVe   VP                  MRo\        V3R l\        S4       4       R4      pVf   R# V^,           \	        S4      8  d   \        \        SV^,           R !  4      MRp\        V\        SRV^,            !  V4      # )uó   Classify a write target as a sandbox-mirror of authoritative Hermes state: ``None``
for non-mirror paths, else ``target_path`` (resolved), ``mirror_root`` (the
``â€¦/home/.hermes`` prefix) and ``inner_path`` (what the agent meant on the host).Nc              3  óÚ   <"  € T F`  w  rVR 8X  g   K  V^,           \        S4      8  g   K'  SV^,           ,          R8X  g   K>  SV^,           ,          R8X  g   KU  V^,           x € Kb  	  R# 5i)Ú	sandboxesrl   z.hermesN)rM   )rw   ÚiÚpartrî   s   &  €r   ry   Ú1classify_sandbox_mirror_target.<locals>.<genexpr>×  so   øé € ð 	qÑ.‘7�1Ø�KÑô 
Ø$%¨¥E¬C°«JÑ$6ô 
Ø;@ÀÀQÅ½<È6Ñ;Qô 
ØV[Ð\]Ð`aÕ\aÕVbÐfoÑVoô 
ˆˆQ�ŠÓ.ùs   ƒA+“A+¬A+ÁA+ÁA+r�   r   )rA   rî   ÚnextÚ	enumeraterM   r	   r   rö   )r   rñ   Ú	inner_idxÚinnerrî   s   &   @r   Úclassify_sandbox_mirror_targetr  Ï  s•   ø€ ô ˜TÓ"€FØ"Ò.ˆF�LŠL°B€Eäô	qœi¨Ô.ó 	qàó€Ið
 ÒÙØ1:¸QµÄÀUÃÔ1KŒC”�e˜I¨�M˜NÐ+Ñ,Ô-ÐQS€EÜ˜¤ e¨O¨i¸!­mÐ&<Ñ =¸uÓEÐEr   c               ó(   € V ^8„  d   QhRRRRRRRR/# )r   Úinforø   Úbodyr	   Úbypassr
   rf   r   )r   s   "r   r   r   á  s.   € ÷ rñ r˜.ð r°ð r¸Sð rÀ]ñ rr   c           	     ót   € V f   R# \         P                  ! R/ V BRVP                  V R,          R7      RV/B # )z_Render ``_SANDBOX_MIRROR_WARNING`` for a classify_* result (``body`` may use ``{inner_path}``).Nr  ró   )ró   r  r   )Ú_SANDBOX_MIRROR_WARNINGr   )r  r  r  s   &&&r   Ú_mirror_warningr
  á  s:   € à‚|ÙÜ"×)Ò)Ñq¨DÑq°t·{±{ÈdÐS_ÕN`°{Ó7aÐqÐjpÒqÐqr   c               ó    € V ^8„  d   QhRRRR/# rÌ   r   )r   s   "r   r   r   è  s   € ÷ 	ñ 	 Sð 	¨]ñ 	r   c                ó.   € \        \        V 4      RR4      # )zªModel-facing soft-guard warning when ``path`` lands in a sandbox mirror, else ``None``;
the caller surfaces it as a tool-result error and ``cross_profile=True`` bypasses.uä   a per-task mirror created by a non-local terminal backend (docker/daytona/etc.). Writes here land on a copy that the host Hermes process never reads â€” the authoritative file is likely {inner_path!r} under the real HERMES_HOME.z8this guard after explicit user direction, retry the call)r
  r  r@   s   &r   Úget_sandbox_mirror_warningr  è  s%   € ô Ü& tÓ,ð	Rð 	Cóð r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r   r	   Úmirror_prefixú
str | Noner
   rø   r   )r   s   "r   r   r   ô  s'   € ÷ Oñ O¨3ð O¸zð OÐUcñ Or   c                óÈ   € \        V 4      V'       d   \        V4      MRr2Ve   Ve   \        W#4      '       g   R# \        W#VP                  V4      P	                  4       4      # )ug  Classify a write target as a container-side sandbox mirror. Inside the container
the bind mount strips the ``sandboxes/`` prefix (the agent sees plain ``/root/.hermes/â€¦``),
so the caller supplies ``mirror_prefix`` once it knows file tools run in a docker sandbox.
``None`` without a prefix or outside it, else ``target_path``/``mirror_root``/``inner_path``.N)rA   r;   rö   r7   Úas_posix)r   r  rñ   Úmirrors   &&  r   Ú classify_container_mirror_targetr  ô  sQ   € ô
 % TÓ*Ïm¬O¸MÔ,JÐaeˆFØ‚~˜š¬y¸×/HÒ/HÙÜ˜¨×(:Ñ(:¸6Ó(B×(KÑ(KÓ(MÓNÐNr   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r   r	   r  r  r
   rf   r   )r   s   "r   r   r   ÿ  s"   € ÷ ñ  sð ¸:ð ÐQ^ñ r   c                ó.   € \        \        W4      RR4      # )z]Model-facing soft-guard warning when ``path`` lands in the container's mirror, else ``None``.u¦   the container's bind-mounted home â€” a per-task mirror that the host Hermes process never reads. The authoritative file is {inner_path!r} under the real HERMES_HOME.z$after explicit user direction, retry)r
  r  )r   r  s   &&r   Úget_container_mirror_warningr  ÿ  s!   € äÜ(¨Ó=ð	 ð 	/óð r   )r�   )r|   z.awsz.gnupgz.kubez.dockerz.azurez
.config/ghz.config/gcloud)zstate.dbÚsessionsú
mcp-tokensÚpairingÚvaultúbrowser-profile>   rn   ú.envrcú	.env.testú
.env.localú.env.stagingú.env.productionú.env.development))r  z>is the Hermes MCP token directory and cannot be read directly.z7is a Hermes MCP token file and cannot be read directly.)r  zjis the Hermes real-profile browser snapshot directory (copied cookies/logins) and cannot be read directly.zgis inside the Hermes real-profile browser snapshot (copied cookies/logins) and cannot be read directly.)r  zwis the Hermes credential vault directory and cannot be read directly (secrets are filled server-side by browser_vault).zŒis inside the Hermes credential vault (encrypted secrets + local key) and cannot be read directly (browser_vault resolves them server-side).ru   )2Ú__conditional_annotations__Ú__doc__Ú
__future__r   r   Úpathlibr   Ú
contextlibr   Útypingr   r   r   r!   r)   r(   r;   rA   rV   rY   rb   ri   r‚   rˆ   r‰   r“   r—   r¸   r§   r¢   r½   rÄ   rÉ   rÊ   Ú__annotations__rÜ   r   rv   rÛ   rÝ   rä   ré   rï   r	  rö   r  r
  r  r  r  )r#  s   @r   Ú<module>r*     sY  øðôõ #ã 	Ý Ý Ý õ5õ.õ
6õ
ZõõGõ÷0õ2Oõ^ð&
°X÷ 
õ0ðD pÐ õ9õõDð$ kÐ ð>°u÷ >õ8õ64ð
a°Wð aÈE÷ aõOò,Ð  ó ð
 [ð ð �Ð5°vÐ?[Ø‡G�G‡L�L�Ð,Ó-¨r¯w©w¯|©|¸GÐEUÓ/VðÐ ðÐ õ.Aõb"õ,ð$Zð õcõ
Fõ$rõ	÷O÷ñ r   