Ë
    ãß²j÷9  ã                   ó¤  — U d Z ddlZddlZddlZddlZddlZddlmZ  ej                  d«      Z	 ej                  «       dk(  ZdZdZ eh d£«      Z eh d	£«      Zd&d
„Zdededededeeef   f
d„ZdZi Zeed<   i Zeed<    e«       Zeed<   dedefd„Zddœdededefd„Zdedefd„Zdedefd„Zdedefd „Z d!edefd"„Z!d'd!ed#ed$edefd%„Z"y)(a5  Child-process environment for execute_code: env scrubbing, interpreter and cwd resolution.

Both the per-call remote path and the local session kernel build their child
env through ``_build_child_env`` so the security rules (secret scrubbing,
PYTHONPATH hygiene, UTF-8 forcing, TZ) cannot drift between them.
é    N)ÚDictztools.code_execution_toolÚWindows)ÚPATHÚHOMEÚUSERÚLANGÚLC_ÚTERMÚTMPDIRÚTMPÚTEMPÚSHELLÚLOGNAMEÚXDG_Ú
PYTHONPATHÚVIRTUAL_ENVÚCONDA)ÚKEYÚTOKENÚSECRETÚPASSWORDÚ
CREDENTIALÚPASSWDÚAUTHÚDSNÚWEBHOOKÚCREDSÚBEARERÚAPIKEY>   Ú
HERMES_ENVÚHERMES_HOMEÚHERMES_CONFIGÚHERMES_PROFILEÚHERMES_DELEGATED_CHILD_CONTEXT>   úPROGRAMFILES(X86)ÚOSÚPUBLICÚWINDIRÚAPPDATAÚCOMSPECÚPATHEXTÚHOMEPATHÚUSERNAMEÚ	HOMEDRIVEÚ
SYSTEMROOTÚ
USERDOMAINÚPROGRAMDATAÚSYSTEMDRIVEÚUSERPROFILEÚCOMPUTERNAMEÚLOCALAPPDATAÚPROGRAMFILESÚPROGRAMW6432ÚALLUSERSPROFILEÚNUMBER_OF_PROCESSORSÚPROCESSOR_ARCHITECTUREc           	      ó  ‡‡— 	 ddl m}m}m} ‰€|Š|€t
        }i }g }| j                  «       D ]˜  \  Š} ‰‰«      r |‰|«      }	|	�|	|‰<   Œt        ˆfd„t        D «       «      rŒ8t        ˆfd„t        D «       «      s ‰t        v s|r‰j                  «       t        v r||‰<   Œv‰j                  d«      sŒˆ|j                  ‰«       Œš |j                  ˆfd	„ ||«      j                  «       D «       «       |r8t         j#                  d
t%        |«      dj'                  t)        |«      «      «       ddlm}
m}  || «      }|j1                  |
«      r|
ddfD ]  }||v sŒ||   ||<   Œ  ||«      S # t        $ r d„ }d„ }d„ }Y �Œxw xY w)u”  Produce the scrubbed child-process env for execute_code.

    Rules, in order: (1) passthrough vars (skill/config-declared) resolve
    through the active profile secret scope â€” an absent scoped value is
    omitted; (2) secret-substring names are blocked; (3) safe prefixes pass;
    (4) operational HERMES_* pass by exact name; (5) on Windows the
    OS-essential allowlist passes by exact name.
    r   )Úis_env_passthroughÚresolve_passthrough_valueÚscoped_passthrough_additionsc                  ó   — y)NF© )Ú_s    ú=/home/ubuntu/.hermes/hermes-agent/tools/code_execution_env.pyú<lambda>z"_scrub_child_env.<locals>.<lambda>@   ó   � ó    c                  ó   — y ©Nr@   )Ú_nameÚ	_fallbacks     rB   rC   z"_scrub_child_env.<locals>.<lambda>A   rD   rE   c                 ó   — i S rG   r@   )Ú_presents    rB   rC   z"_scrub_child_env.<locals>.<lambda>B   s   € ¸€ rE   c              3   óB   •K  — | ]  }|‰j                  «       v –— Œ y ­wrG   )Úupper)Ú.0ÚsÚks     €rB   ú	<genexpr>z#_scrub_child_env.<locals>.<genexpr>Q   s   øè ø€ Ò: !ˆq�A—G‘G“IŒ~Ñ:ùs   ƒc              3   ó@   •K  — | ]  }‰j                  |«      –— Œ y ­wrG   )Ú
startswith)rN   ÚprP   s     €rB   rQ   z#_scrub_child_env.<locals>.<genexpr>S   s   øè ø€ Ò< A�—‘˜Q—Ñ<ùs   ƒÚHERMES_c              3   ó>   •K  — | ]  \  }} ‰|«      sŒ||f–— Œ y ­wrG   r@   )rN   rP   ÚvÚis_passthroughs      €rB   rQ   z#_scrub_child_env.<locals>.<genexpr>[   s"   øè ø€ Òk™t˜q !ÑYgÐhiÕYj�Q˜”FÑkùs   ƒ”	a  execute_code: dropped %d non-allowlisted HERMES_* var(s) from the sandbox child env (%s). This is intentional hardening (#27303); if a sandbox script legitimately needs one, declare it via env_passthrough in the skill/config so it passes by explicit opt-in.z, )ÚDELEGATED_CHILD_ENV_MARKERÚdelegated_child_subprocess_envÚHERMES_KANBAN_DBÚHERMES_KANBAN_BOARD)Útools.env_passthroughr<   r=   r>   Ú	ExceptionÚ_IS_WINDOWSÚitemsÚanyÚ_SECRET_SUBSTRINGSÚ_SAFE_ENV_PREFIXESÚ_HERMES_CHILD_ALLOWEDrM   Ú_WINDOWS_ESSENTIAL_ENV_VARSrS   ÚappendÚupdateÚloggerÚdebugÚlenÚjoinÚsortedÚagent.delegation_contextrY   rZ   Úget)Ú
source_envrX   Ú
is_windowsr<   r=   r>   ÚscrubbedÚ_dropped_hermesrW   ÚresolvedrY   rZ   ÚscopedÚkeyrP   s    `            @rB   Ú_scrub_child_envrv   4   s¡  ù€ ð;ßuÑuð
 ÐØ+ˆØÐÜ ˆ
Ø€Hð €OØ× Ñ Ó"ò &‰ˆˆ1Ù˜!ÔÙ0°°AÓ6ˆHØÐ#Ø&�˜‘ØÜÓ:Ô'9Ô:Ô:ØÜÓ<Ô);Ô<Ô<ØÔ-Ñ-Ù 1§7¡7£9Ô0KÑ#KØˆH�QŠKØ�\‰\˜)Õ$Ø×"Ñ" 1Õ%ð&ð  ‡O�OÓkÑ'CÀHÓ'M×'SÑ'SÓ'UÔkÔkÙÜ�‰ðSô �Ó  $§)¡)¬F°?Ó,CÓ"Dô	
÷ñ ,¨JÓ7€Fð ‡z�zÐ,Ô-Ø.Ð0BÐDYÐZò 	,ˆCØ�fŠ}Ø & s¡�˜’ð	,ñ *¨(Ó3Ð3øôe ò ;Ù,ÐÙ$AÐ!Ù':Ó$ð;ús   „
E1 Å1FÆFÚrpc_endpointÚ	rpc_tokenÚtmpdirÚchild_pythonÚreturnc           	      ó  — ddl m}m}m} t	        t
        j                  «      }| |d<   ||d<   d|d<   d|d<   d|d	<   dd
lm}  |«       }	|	rt        s|	|d<   |j                  dd«        ||«        |«       }
|
r|
|d<    ||«       ddlm}  ||«       |j                  dd«      }|g}t        |«      rm|j                  t
        j                   j#                  t
        j                   j#                  t
        j                   j%                  t&        «      «      «      «       n3|t(        vr+t(        j+                  |«       t,        j/                  d|«       |r|j                  |«       t
        j0                  j3                  |«      |d<   |S )z@Build the scrubbed child environment both execution paths share.r   )Úapply_scratch_tmp_envÚapply_subprocess_home_envÚget_hermes_home_overrideÚHERMES_RPC_SOCKETÚHERMES_RPC_TOKENÚ1ÚPYTHONDONTWRITEBYTECODEzutf-8ÚPYTHONIOENCODINGÚ
PYTHONUTF8)Úget_timezone_nameÚTZÚHERMES_TIMEZONENr!   )Ú_strip_hermes_owned_pythonpathr   Ú ziexecute_code: child interpreter %s is outside the Hermes environment; hermes root omitted from PYTHONPATH)Úhermes_constantsr}   r~   r   rv   ÚosÚenvironÚhermes_timer†   r_   ÚpopÚ#tools.environments.local_pythonpathr‰   rn   Ú_uses_hermes_python_environmentrf   ÚpathÚdirnameÚabspathÚ__file__Ú_external_env_loggedÚaddrh   ÚinfoÚpathseprk   )rw   rx   ry   rz   r}   r~   r   Ú	child_envr†   Ú_tz_nameÚ_home_overrider‰   Ú_existing_ppÚ	_pp_partss                 rB   Ú_build_child_envrŸ   t   sa  € ÷ lÑkÜ ¤§¡Ó,€IØ%1€IÐ!Ñ"Ø$-€IÐ Ñ!Ø+.€IÐ'Ñ(ð %,€IÐ Ñ!Ø!€IˆlÑõ .á Ó"€Hñ �Ø"ˆ	�$‰Ø‡M�MÐ# TÔ*Ù˜iÔ(ñ .Ó/€NÙØ#1ˆ	�-Ñ Ù˜iÔ(õ SÙ" 9Ô-Ø—=‘= ¨rÓ2€LØ�€IÜ& |Ô4Ø×ÑœŸ™Ÿ™¬¯©¯©¼¿¹¿¹ÌÓ9RÓ)SÓTÕUØ	Ô1Ñ	1ä× Ñ  Ô.Ü�‰ð GØHTô	VáØ×Ñ˜Ô&Ü Ÿj™jŸo™o¨iÓ8€IˆlÑØÐrE   é    Ú_usable_python_cacheÚ_python_prefix_cacher–   Úcacheru   c                 óx   — t        | «      t        k\  r#| j                  t        t	        | «      «      «       || |<   y)z<Insert into a bounded probe cache, FIFO-evicting at the cap.N)rj   Ú_PROBE_CACHE_MAXr�   ÚnextÚiter)r£   ru   Úvalues      rB   Ú_cache_probe_resultr©   ·   s-   € ä
ˆ5ƒzÔ%Ò%Ø�	‰	”$”t˜E“{Ó#Ô$Ø€Eˆ#‚JrE   F©ÚtextÚpython_pathÚcoder«   c          
      óü   — 	 ddl m} t        j                  | d|gdd|t        rt        j
                  ndt        j                   |«       ¬«      S # t        t        j                  t        j                  f$ r Y yw xY w)zRRun ``python_path -c code``; None if missing, unspawnable, or past the 5s timeout.r   )rZ   z-cé   T)ÚtimeoutÚcapture_outputr«   ÚcreationflagsÚstdinÚenvN)
rm   rZ   Ú
subprocessÚrunr_   ÚCREATE_NO_WINDOWÚDEVNULLÚOSErrorÚTimeoutExpiredÚSubprocessError)r¬   r­   r«   rZ   s       rB   Ú_probe_pythonr¼   ¾   sn   € ðÝKÜ�~‰~Ø˜$ Ð%¨qÀÈDÝ9Dœ*×5Ò5È!Ü×$Ñ$Ñ*HÓ*Jô
ð 	
øô
 ”Z×.Ñ.´
×0JÑ0JÐKò Ùðús   ‚AA Á(A;Á:A;c                 ó–   — t         j                  | «      }|�|S t        | d«      }|€y|j                  dk(  }t	        t         | |«       |S )zbWhether the interpreter is Python 3.8+ (what the RPC stubs need); success cached, failure retried.z<import sys; sys.exit(0 if sys.version_info >= (3, 8) else 1)Fr   )r¡   rn   r¼   Ú
returncoder©   )r¬   ÚcachedÚresultÚusables       rB   Ú_is_usable_pythonrÂ   Ë   sT   € ä!×%Ñ% kÓ2€FØÐØˆÜ˜;Ð(fÓg€FØ€~ØØ×Ñ !Ñ#€FÜÔ,¨k¸6ÔBØ€MrE   c                 ó<  — t         j                  | «      }|�|S t        | dd¬«      }|�s|j                  dk(  rd|j                  j                  «       rJt        j                  j                  |j                  j                  «       «      }t        t         | |«       |S y)z[Resolved ``sys.prefix`` reported by *python_path* ("" on failure; failures are not cached).zimport sys; print(sys.prefix)Trª   r   rŠ   )
r¢   rn   r¼   r¾   ÚstdoutÚstriprŒ   r’   Úrealpathr©   )r¬   r¿   rÀ   Úprefixs       rB   Ú_python_environment_prefixrÈ   Ø   s„   € ä!×%Ñ% kÓ2€FØÐØˆÜ˜;Ð(GÈdÔS€FØÐ˜f×/Ñ/°1Ò4¸¿¹×9LÑ9LÔ9NÜ—‘×!Ñ! &§-¡-×"5Ñ"5Ó"7Ó8ˆÜÔ0°+¸vÔFØˆØrE   c                 ó6  — | t         j                  k(  sMt        j                  j	                  | «      t        j                  j	                  t         j                  «      k(  ryt        | «      t        j                  j	                  t         j                  «      k(  S )u  Whether *python_path* belongs to Hermes's active Python environment. Short-circuits when
    it IS the running interpreter (by path or realpath â€” covers ``uv run`` venvs) so no probe
    runs on the default strict path and a flaky probe can never drop the hermes root.T)ÚsysÚ
executablerŒ   r’   rÆ   rÈ   rÇ   )r¬   s    rB   r‘   r‘   å   sb   € ð ”c—n‘nÒ$¬¯©×(8Ñ(8¸Ó(EÌÏÉ×IYÑIYÔZ]×ZhÑZhÓIiÒ(iØÜ% kÓ2´b·g±g×6FÑ6FÄsÇzÁzÓ6RÑRÐRrE   Úmodec                 ó&  — | dk7  rt         j                  S t        rdnd\  }}dD ]Û  }t        j                  j                  |d«      j                  «       }|r|ndD ]¢  }t        j                  j                  |||«      }t        j                  j                  |«      r$t        j                  |t        j                  «      sŒht        |«      r|c c S t        j                  d||«       t         j                  c c S  ŒÝ t         j                  S )zµChild interpreter: ``sys.executable`` in strict mode; in project mode the active
    VIRTUAL_ENV/CONDA_PREFIX python if it exists and passes the 3.8+ probe, else ``sys.executable``.Úproject)ÚScripts)z
python.exezpython3.exe)Úbin)ÚpythonÚpython3)r   ÚCONDA_PREFIXrŠ   r@   z\execute_code: skipping %s=%s (Python version < 3.8 or broken). Using sys.executable instead.)rÊ   rË   r_   rŒ   r�   rn   rÅ   r’   rk   ÚisfileÚaccessÚX_OKrÂ   rh   r˜   )rÌ   ÚsubdirÚ	exe_namesÚvarÚrootÚexeÚ	candidates          rB   Ú_resolve_child_pythonrÝ   î   sÚ   € ð ˆyÒÜ�~‰~ÐÝFQÑBÐWuÑ€FˆIØ.ò 
"ˆÜ�z‰z�~‰~˜c 2Ó&×,Ñ,Ó.ˆÙ $‘9¨"ò 	"ˆCÜŸ™Ÿ™ T¨6°3Ó7ˆIÜ—G‘G—N‘N 9Ô-´"·)±)¸IÄrÇwÁwÔ2OØÜ  Ô+Ø Ô Ü�K‰Kð 8Ø9<¸iôIä—>‘>Ô!ñ	"ð
"ô �>‰>ÐrE   Ústaging_dirÚtask_idc                 ó  — | dk7  r|S |rd	 ddl m}  ||«      }|r!t        j                  j                  |«      r|S 	 ddlm}  ||«      }|r!t        j                  j                  |«      r|S ddlm	}  |«       j                  «       }|rt        j                  j                  |«      ndt        j                  «       fD ](  }	|	sŒt        j                  j                  |	«      sŒ&|	c S  |S # t        $ r d}Y Œáw xY w# t        $ r d}Y ŒÀw xY w)u,  Child cwd. Strict: the staging dir. Project mirrors the terminal/file-tool ladder so every
    file-writing path agrees: session cwd record (`cd` state) â†’ registered ``session.cwd.set``
    override â†’ TERMINAL_CWD â†’ os.getcwd() â†’ staging dir (never Popen on a missing cwd).

    (#56047)
    rÎ   r   )Úget_session_cwdN)Ú_registered_task_cwd_override)Úscope_terminal_cwdrŠ   )Útools.terminal_toolrá   r^   rŒ   r’   ÚisdirÚtools.file_tools_pathsrâ   Úagent.runtime_cwdrã   rÅ   Ú
expanduserÚgetcwd)
rÌ   rÞ   rß   rá   Úrecordedrâ   Úsession_cwdrã   ÚrawrÜ   s
             rB   Ú_resolve_child_cwdrí     sø   € ð ˆyÒØÐÙð	Ý;Ù& wÓ/ˆHñ œŸ™Ÿ™ hÔ/ØˆOð	ÝLÙ7¸Ó@ˆKñ œ2Ÿ7™7Ÿ=™=¨Ô5ØÐÝ4Ù
Ó
×
$Ñ
$Ó
&€CÙ14”b—g‘g×(Ñ(¨Ô-¸"¼b¿i¹i»kÐJò ˆ	ÚœŸ™Ÿ™ yÕ1ØÒðð Ðøô! ò 	ØŠHð	ûô ò 	ØŠKð	ús"   ‹C- ½C> Ã-C;Ã:C;Ã>DÄD)NN)rŠ   )#Ú__doc__ÚloggingrŒ   Úplatformrµ   rÊ   Útypingr   Ú	getLoggerrh   Úsystemr_   rc   rb   Ú	frozensetrd   re   rv   ÚstrrŸ   r¥   r¡   ÚdictÚ__annotations__r¢   Úsetr–   r©   Úboolr¼   rÂ   rÈ   r‘   rÝ   rí   r@   rE   rB   ú<module>rú      s…  ðòó Û 	Û Û Û 
Ý ð 
ˆ×	Ñ	Ð6Ó	7€àˆh�o‰oÓ 9Ñ,€ðOÐ ð>Ð ñ "ò #ó Ð ñ (ò )ó Ð ó=4ð@6 cð 6°cð 6À3ð 6Ø#&ð6Ø+/°°S°©>ó6ðv Ð ØÐ �dÓ ØÐ �dÓ ñ  ›EÐ �cÓ !ð˜tð ¨#ó ð @Eò 
˜sð 
¨#ð 
¸ó 
ð
 3ð 
¨4ó 
ð
¨Cð 
°Có 
ðS°ð S¸ó Sð ð ¨ó ñ(˜Sð ¨sð ¸Sð È#ô rE   