Ë
    ãß²jkß  ã                   óR  — 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ZddlZddl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 ddlmZ ddlmZmZmZ ddlmZ ddlmZmZmZmZmZmZmZm Z m!Z! ddl"m#Z# dd	l$m%Z%m&Z&m'Z'm(Z(m)Z)m*Z*  ejV                  e,«      Z-g d
¢Z.da/ee0   e1d<   eZ2de3e0   dz  de3e0   fd„Z4de5dz  de5e0e0f   fd„Z6e'Z7 ejp                  d«      Z9de0de0fd„Z:e#Z;de0fd„Z<dTde0de0fd„Z=ddddœde>de0dz  de0dz  de>fd„Z?de0de0fd„Z@de0deAfd „ZBd!de	j†                  eDfd"œd#e3e0   d$eEd%e0d&eFd'e0dz  d(eFfd)„ZGdee0   fd*„ZHd+e0de0fd,„ZId+e0de0fd-„ZJg d.¢ZKd/ZLd0ZMd1e3deAfd2„ZNd3ZOd1e3dee0   fd4„ZPd5ZQd6ZRg d7¢ZS eT«       ZUeTej¬                     e1d8<    ej®                  «       ZXd9ZYd:d;gZZdUd=eAd>eAd?eAde3e0   fd@„Z[de0dAe0deAfdB„Z\dee0   fdC„Z]da^eeA   e1dD<   da_eeA   e1dE<   dAe0deAfdF„Z`d<dGœdHe0dIe0dJe0dKeAfdL„ZadVdM„Zbde3e0   fdN„ZcdOZdde3e0   fdP„Zed=eAde3e0   fdQ„Zf G dR„ dSe«      Zgy)WzçDocker execution environment for sandboxed command execution.

Security hardened (cap-drop ALL, no-new-privileges, PID limits), configurable
resource limits (CPU, memory, disk), and optional filesystem persistence via
bind mounts.
é    N)ÚPath)ÚOptional)ÚBaseEnvironmentÚEnvironmentConnectionErrorÚ_SHELL_ENV_NAME_RE)Ú_popen_bash)	Ú_EGRESS_LABEL_KEYÚ_critical_egress_env_namesÚ_egress_enforce_on_dockerÚ_egress_proxy_args_for_dockerÚ_egress_reuse_fingerprintÚcheck_docker_env_collisionsÚcheck_extra_args_collisionsÚcheck_forward_env_collisionsÚmerge_egress_env)Úsanitize_task_id_for_path)Ú	bash_argvÚclient_env_withÚload_hermes_env_varsÚprepend_unsetÚresolve_passthrough_envÚrun_capture)z/usr/local/bin/dockerz/opt/homebrew/bin/dockerz6/Applications/Docker.app/Contents/Resources/bin/dockerÚ_docker_executableÚforward_envÚreturnc                 ó  — g }| xs g D ]~  }t        |t        «      st        j                  d|«       Œ*|j	                  «       }|sŒ=t
        j                  |«      st        j                  d|«       Œi||vsŒn|j                  |«       Œ€ |S )z?Return a deduplicated list of valid environment variable names.z0Ignoring non-string docker_forward_env entry: %rz-Ignoring invalid docker_forward_env entry: %r)Ú
isinstanceÚstrÚloggerÚwarningÚstripÚ_ENV_VAR_NAME_REÚmatchÚappend)r   Ú
normalizedÚitemÚkeys       ú>/home/ubuntu/.hermes/hermes-agent/tools/environments/docker.pyÚ_normalize_forward_env_namesr)   /   sƒ   € à€JØÒ!˜rò 
#ˆÜ˜$¤Ô$Ü�N‰NÐMÈtÔTØØ�j‰j‹lˆÙØÜ×%Ñ% cÔ*Ü�N‰NÐJÈDÕQØ˜
Ò"Ø×Ñ˜cÕ"ð
#ð Ðó    Úenvc                 óZ  — | si S t        | t        «      s+t        j                  dt	        | «      j
                  «       i S i }| j                  «       D ]Ö  \  }}t        |t        «      r#t        j                  |j                  «       «      st        j                  d|«       ŒPt        |t        t        t        t        f«      s9t        j                  d|j                  «       t	        |«      j
                  «       Œ©t        |t        «      r|n
t        |«      ||j                  «       <   ŒØ |S )zTValidate a docker_env dict to {str: str}; scalars are coerced, other values dropped.zdocker_env is not a dict: %sz#Ignoring invalid docker_env key: %rz/Ignoring non-string docker_env value for %r: %s)r   Údictr   r    ÚtypeÚ__name__Úitemsr   r"   r#   r!   ÚintÚfloatÚbool)r+   r%   r'   Úvalues       r(   Ú_normalize_env_dictr5   @   sã   € áØˆ	Ü�cœ4Ô Ü�‰Ð5´t¸C³y×7IÑ7IÔJØˆ	Ø!#€JØ—i‘i“kò R‰
ˆˆUÜ˜#œsÔ#Ô+;×+AÑ+AÀ#Ç)Á)Ã+Ô+NÜ�N‰NÐ@À#ÔFØÜ˜%¤#¤s¬E´4Ð!8Ô9Ü�N‰NÐLÈcÏiÉiËkÔ[_Ð`eÓ[f×[oÑ[oÔpØÜ+5°e¼SÔ+A¡%ÄsÈ5Ãzˆ
�3—9‘9“;ÒðRð Ðr*   z[^A-Za-z0-9_.-]r4   c                 ób   — t        | t        «      r| syt        j                  d| «      dd xs dS )zXLossy coercion into a Docker label-safe form; empty/invalid input becomes ``"unknown"``.ÚunknownÚ_Né?   )r   r   Ú_LABEL_VALUE_OK_REÚsub)r4   s    r(   Ú_sanitize_label_valuer<   \   s0   € ä�eœSÔ!©ØÜ×!Ñ! # uÓ-¨c¨rÐ2Ò?°iÐ?r*   c                  óD   — 	 ddl m}   | «       xs dS # t        $ r Y yw xY w)z´Active Hermes profile name, or ``"default"`` on any error. Resolved at container-create
    time so a container stays tagged with its creator even if the process switches profiles.r   ©Úget_active_profile_nameÚdefault)Úhermes_cli.profilesr?   Ú	Exceptionr>   s    r(   Ú_get_active_profile_namerC   h   s*   € ðÝ?Ù&Ó(Ò5¨IÐ5øÜò Ùðús   ‚ “	žÚ
shared_keyc                 ó¼   — | st        t        «       «      S t        j                  | j	                  d«      «      j                  «       dd }t        | «      dd › d|› �S )a]  Profile label used for container reuse and orphan reaping. Profiles are isolated by default; an
    explicit shared key lets trusted profiles share one Docker identity. Label sanitization is lossy
    and reuse is label-keyed, so a digest of the raw key disambiguates colliding keys. Plain profile
    names keep their historical un-suffixed labels.zutf-8Né   é2   Ú-)r<   rC   ÚhashlibÚsha256ÚencodeÚ	hexdigest)rD   Údigests     r(   Ú_container_identityrN   r   s]   € ñ
 Ü$Ô%=Ó%?Ó@Ð@Ü�^‰^˜J×-Ñ-¨gÓ6Ó7×AÑAÓCÀCÀRÐH€FÜ# JÓ/°°Ð4Ð5°Q°v°hÐ?Ð?r*   iX  )Úmax_age_secondsÚprofile_filterÚ
docker_exerO   rP   rQ   c           	      ó¾  — |xs t        «       xs d}g d¢}|r|j                  ddt        |«      › �g«       t        |ddg|¢d‘d‘d	d
d¬«      }|€yt        j                  j                  t        j                  j                  «      }d}d„ |j                  j                  «       D «       D ]­  }t        ||«      }	|	€Œ||	z
  j                  «       }
|
| k  rŒ+t        |d|gdd|dd f¬«      }|€ŒD|j                  dk(  r)|dz  }t        j                  d|dd t        |
«      «       Œ|t        j!                  d|dd |j"                  j%                  «       «       Œ¯ |S )aÂ  Remove stale hermes-tagged containers left behind by prior processes (SIGKILL/OOM
    exits that bypass atexit). Only ``status=exited`` containers (running ones may belong
    to a sibling process), only the caller's profile, and only if ``FinishedAt`` is older
    than *max_age_seconds* (a just-exited sibling may be about to reuse its container).
    Best-effort and idempotent: failures log at debug and the count removed so far is returned.
    Údocker)ú--filterúlabel=hermes-agent=1rT   zstatus=exitedrT   úlabel=hermes-profile=Úpsú-aú--formatz{{.ID}}é   z"orphan reaper docker ps failed: %sz'orphan reaper docker ps returned %d: %s©ÚtimeoutÚfailÚnonzeroNr   c              3   ó^   K  — | ]%  }|j                  «       sŒ|j                  «       –— Œ' y ­w©N©r!   ©Ú.0Úlns     r(   ú	<genexpr>z)reap_orphan_containers.<locals>.<genexpr>”   s   è ø€ ÒO˜rÀBÇHÁHÅJ�—‘—
ÑOùs   ‚-˜-Úrmé   z%orphan reaper docker rm %s failed: %srF   ©r\   r]   Ú	fail_argsé   z2Reaped orphan container %s (exited %d seconds ago)zdocker rm %s failed: %s)Úfind_dockerÚextendr<   Ú_docker_queryÚdatetimeÚnowÚtimezoneÚutcÚstdoutÚ
splitlinesÚ_container_finished_atÚtotal_secondsÚ
returncoder   Úinfor1   ÚdebugÚstderrr!   )rO   rP   rQ   rS   ÚfiltersÚlistingro   ÚremovedÚcidÚfinished_atÚageÚresults               r(   Úreap_orphan_containersr�   }   sˆ  € ð Ò4œ;›=Ò4¨H€FÚO€GÙØ�‰˜
Ð&;Ô<QÐR`Ó<aÐ;bÐ$cÐdÔeäØ	��tÐ=˜gÐ= zÐ=°9Ð=ÀrØ1Ð;dôf€Gð €Øô ×
Ñ
×
Ñ
¤× 1Ñ 1× 5Ñ 5Ó
6€CØ€GÙO W§^¡^×%>Ñ%>Ó%@ÔOò UˆÜ,¨V°SÓ9ˆØÐØØ�[Ñ ×/Ñ/Ó1ˆØ�Ò Øô Ø�T˜3Ð¨Ð2YÐfiÐjmÐkmÐfnÐepôrˆàˆ>ØØ×Ñ Ò!Ø�q‰LˆGÜ�K‰KÐLÈcÐRUÐSUÈhÔX[Ð\_ÓX`Õaä�L‰LÐ2°C¸¸°H¸f¿m¹m×>QÑ>QÓ>SÕTð%Uð& €Nr*   Úcontainer_idc                 ó¢  — t        | ddd|gdd|dd f¬«      }|�|j                  d	k7  ry|j                  j                  «       }|r|j	                  d
«      ryt        j                  dd|«      j                  dd«      }	 t        j                  j                  |«      S # t        $ r%}t        j                  d||dd |«       Y d}~yd}~ww xY w)z¨``docker inspect`` FinishedAt as an aware datetime; ``None`` (= don't reap) when
    missing/unparseable or Docker's never-finished zero value ``0001-01-01T00:00:00Z``.ÚinspectrY   z{{.State.FinishedAt}}é
   z*orphan reaper docker inspect %s failed: %sNrF   rh   r   z
0001-01-01z(\.\d{6})\d+z\1ÚZz+00:00z(could not parse FinishedAt %r for %s: %s)rm   rv   rr   r!   Ú
startswithÚrer;   Úreplacern   ÚfromisoformatÚ
ValueErrorr   rx   )rQ   r‚   r€   ÚrawÚes        r(   rt   rt   ª   s×   € ô Ø	�Y 
Ð,CÀ\ÐRÐ\^Ø9ÀlÐSVÐTVÐFWÐEYô[€Fð €~˜×*Ñ*¨aÒ/ØØ
�-‰-×
Ñ
Ó
€CÙ�#—.‘. Ô.Øä
�&‰&� %¨Ó
-×
5Ñ
5°c¸8Ó
D€CðÜ× Ñ ×.Ñ.¨sÓ3Ð3øÜò Ü�‰Ð?ÀÀlÐSVÐTVÐFWÐYZÔ[Üûðús   ÂB  Â 	CÂ)C	Ã	CÚpathc                 óŒ   — t         j                  j                  | «      xr$ t        j                  | t         j                  «      S r`   )ÚosrŽ   ÚisfileÚaccessÚX_OK)rŽ   s    r(   Ú_is_executabler”   ¾   s)   € Ü�7‰7�>‰>˜$ÓÒ<¤B§I¡I¨d´B·G±GÓ$<Ð<r*   © )ri   r^   Ú	exc_typesÚargvr\   r]   ri   r^   r–   c                ó  — 	 t        | |¬«      }|�L|j                  dk7  r=t        j                  |g|¢|j                  ‘|j                  j                  «       ‘­Ž  y|S # |$ r"}t        j                  |g|¢|‘­Ž  Y d}~yd}~ww xY w)zìBest-effort ``run_capture`` for probes: logs *fail* (``*fail_args, exc``) at debug and
    returns ``None`` when the CLI raises; with *nonzero* set, a nonzero exit also logs
    (``*fail_args, returncode, stderr``) and returns ``None``.©r\   Nr   )r   r   rx   rv   ry   r!   )r—   r\   r]   ri   r^   r–   r€   r�   s           r(   rm   rm   Â   s‰   € ðÜ˜T¨7Ô3ˆð Ð˜v×0Ñ0°AÒ5Ü�‰�WÐS˜yÐS¨&×*;Ñ*;ÐS¸V¿]¹]×=PÑ=PÓ=RÓSØØ€Møð ò Ü�‰�TÐ)˜IÐ) qÓ)Üûðús   ‚A ÁBÁ$BÂBc                  ó†  — t         �t         S t        j                  d«      } | r$t        | «      rt        j                  d| «       | }nut        j                  d«      x}rn]t        j                  d«      x}rt        j                  d|«       n/t        d„ t        D «       d«      x}rt        j                  d|«       |r|a |S )	z®Locate the docker/podman CLI (cached): ``HERMES_DOCKER_BINARY`` override, ``docker``
    on PATH, ``podman`` on PATH, then macOS Docker Desktop locations; ``None`` if absent.NÚHERMES_DOCKER_BINARYz'Using HERMES_DOCKER_BINARY override: %srS   Úpodmanz%Using podman as container runtime: %sc              3   ó8   K  — | ]  }t        |«      sŒ|–— Œ y ­wr`   )r”   )rc   Úps     r(   re   zfind_docker.<locals>.<genexpr>ã   s   è ø€ ÒM˜a¼>È!Õ;LœÑMùs   ‚“z%Found docker at non-PATH location: %s)
r   r�   Úgetenvr”   r   rw   ÚshutilÚwhichÚnextÚ_DOCKER_SEARCH_PATHS)ÚoverrideÚfounds     r(   rk   rk   Ô   s­   € ô Ð%Ü!Ð!ä�y‰yÐ/Ó0€HÙ”N 8Ô,Ü�‰Ð=¸xÔHØ‰Ü—,‘,˜xÓ(Ð	(ˆÐ	(ØÜ—,‘,˜xÓ(Ð	(ˆÐ	(Ü�‰Ð;¸UÕCÜÑMÔ#7ÔMÈtÓTÐ	TˆÐ	TÜ�‰Ð;¸UÔCÙØ"ÐØ€Lr*   Ú
executablec                 óh   — dt         j                  j                  | «      j                  «       v rdS dS )z”User-facing runtime name (``"Podman"`` / ``"Docker"``) for the CLI at *executable*, so
    diagnostics and pickers name the runtime actually in use.rœ   ÚPodmanÚDocker)r�   rŽ   ÚbasenameÚlower©r¦   s    r(   Údocker_runtime_namer­   ê   s.   € ð  ¤2§7¡7×#3Ñ#3°JÓ#?×#EÑ#EÓ#GÑGˆ8ÐUÈXÐUr*   c                 ó"   — t        | «      dk7  ryy)z¬How to bring the runtime at *executable* back up, for a "not reachable" message. Docker has
    a daemon to start; Podman is daemonless (outside Linux it runs inside a VM).r¨   zstart Docker and retryz$run `podman machine start` and retry)r­   r¬   s    r(   Údocker_runtime_start_hintr¯   ð   s   € ô ˜:Ó&¨(Ò2Ø'Ø1r*   )z
--cap-dropÚALLú	--cap-addÚDAC_OVERRIDEr±   ÚCHOWNr±   ÚFOWNERú--tmpfsz/tmp:rw,nosuid,size=512mrµ   z#/var/tmp:rw,noexec,nosuid,size=256mÚ256Ú1gÚ
extra_argsc                 ó.   — t        d„ | xs g D «       «      S )zUTrue when docker_extra_args already set ``--shm-size`` (then our default is skipped).c              3   óp   K  — | ].  }t        |t        «      xr |d k(  xs |j                  d«      –— Œ0 y­w)ú
--shm-sizez--shm-size=N)r   r   r‡   )rc   Úas     r(   re   z+_extra_args_set_shm_size.<locals>.<genexpr>  s:   è ø€ ò %àô 	�1”cÓÒQ  \Ñ 1Ò P°Q·\±\À-Ó5PÓQñ%ùs   ‚46)Úany)r¸   s    r(   Ú_extra_args_set_shm_sizer¾     s!   € äñ %àÒ" ô%ó %ð %r*   )z	--networkz--netc                 ó4  — | xs g D �cg c]  }t        |t        «      sŒ|‘Œ }}t        |«      D ]a  \  }}t        D ]S  }||k(  r|dz   t	        |«      k  r||dz      ndc c S |j                  |› d�«      sŒ<|j                  dd«      d   c c S  Œc yc c}w )a_  Network mode requested by ``docker_extra_args`` (``--network none`` / ``--network=none`` /
    ``--net``), or None when the operator set no network flag. Docker rejects a repeated
    ``--network`` outright (exit 125), so the implicit ``docker_network: false`` flag and an
    operator-supplied one must be reconciled before the command line is built.rj   Ú Ú=N)r   r   Ú	enumerateÚ_NETWORK_FLAGSÚlenr‡   Úsplit)r¸   r¼   ÚargsÚiÚargÚflags         r(   Ú_extra_args_network_moderÊ     s¤   € ð
 #Ò( bÖ@�!¬Z¸¼3Õ-?ŠAÐ@€DÐ@Ü˜D“/ò ,‰ˆˆ3Ü"ò 	,ˆDØ�dŠ{Ø&'¨!¡e¬c°$«iÒ&7�t˜A ™E’{¸RÔ?Ø�~‰~   a˜jÕ)Ø—y‘y  aÓ(¨Ñ+Ô+ñ		,ð,ð ùò As
   ‰BŸB)rµ   z/run:rw,noexec,nosuid,size=64m)rµ   z/run:rw,exec,nosuid,size=64m)r±   ÚSETUIDr±   ÚSETGIDÚ_TEARDOWN_THREADS)z/initz&/package/admin/s6-overlay/command/initz--security-optzno-new-privilegesFÚrun_as_host_userÚrun_execÚsnap_compatc                 ó¨   — t        t        «      |rg nt        t        «      z   }|t        |rt        nt        «      z  }| r|S |t        t
        «      z   S )a  Security/cap/tmpfs args for the privilege mode; ``run_exec`` mounts /run exec for s6 images.
    ``snap_compat`` drops no-new-privileges: snap-packaged Docker's AppArmor profile turns it into
    "exec: operation not permitted" for every process in the container (#9730, LP#1908448).)ÚlistÚ_BASE_SECURITY_ARGSÚ_NO_NEW_PRIVILEGES_ARGSÚ_RUN_TMPFS_EXECÚ_RUN_TMPFS_NOEXECÚ_PRIVDROP_CAP_ARGS)rÎ   rÏ   rÐ   rÆ   s       r(   Ú_build_security_argsrØ   C  sJ   € ô Ô#Ó$©k©¼tÔD[Ó?\Ñ]€DØŒD¡H•Ô2CÓDÑD€DÙ#ˆ4ÐH¨´Ô5GÓ0HÑ)HÐHr*   Úimagec           	      ó”  — t        | dd|ddgdd|fdt        j                  t        f¬«      }|�|j                  xs d	j                  «       nd	}|r|d
k(  ry	 t        j                  |«      }t        |t        «      r|g}t        |t        «      r|syt        |d   «      j                  «       t        v S # t        t        f$ r Y yw xY w)zéTrue if ``image``'s entrypoint is the s6-overlay ``/init`` (own PID 1: incompatible
    with ``--init`` and a noexec /run). Any inspection failure, including an image not yet
    pulled, returns False and keeps the hardened defaults.rÙ   r„   rY   z{{json .Config.Entrypoint}}rZ   z/Docker: could not inspect entrypoint for %s: %sz4Docker: image inspect for %s returned %d (stderr=%s))r\   r]   ri   r^   r–   rÀ   ÚnullFr   )rm   Ú
subprocessÚSubprocessErrorÚOSErrorrr   r!   ÚjsonÚloadsr‹   Ú	TypeErrorr   r   rÒ   Ú_S6_INIT_ENTRYPOINTS)rQ   rÙ   r€   rŒ   Ú
entrypoints        r(   Ú_image_uses_init_entrypointrä   L  sÑ   € ô Ø	�W˜i¨°
Ð<YÐZÐdfØ>È5È(ØFÜ×-Ñ-¬wÐ7ô	9€Fð
 ,2Ð+=ˆ6�=‰=Ò˜B×
%Ñ
%Ô
'À2€CÙ�#˜’-ØðÜ—Z‘Z “_ˆ
ô �*œcÔ"Ø �\ˆ
Ü�j¤$Ô'©zØÜˆz˜!‰}Ó×#Ñ#Ó%Ô)=Ð=Ð=øô œ	Ð"ò Ùðús   ÁB5 Â5CÃCc                  ó’   — t        t        dd«      } t        t        dd«      }| �|€y	  | «       › d |«       › �S # t        $ r Y yw xY w)z®``<uid>:<gid>`` of the host user, or ``None`` without POSIX ids. Uses os.getuid/getgid
    directly (not pwd/getpass) so nameless UIDs inside sandboxed launchers never raise.ÚgetuidNÚgetgidú:)Úgetattrr�   rB   )Úget_uidÚget_gids     r(   Ú_resolve_host_user_specrì   c  sX   € ô ”b˜( DÓ)€GÜ”b˜( DÓ)€GØ€˜'˜/ØðÙ“)�˜A™g›i˜[Ð)Ð)øÜò Ùðús   ©: º	AÁAÚ_storage_opt_okÚ_cgroup_limits_okc                 óÊ  — t         �t         S t        «       }|r| sy	 t        |ddddddd	d
| ddgd¬«      }|j                  dk(  rda y|j                  xs dj                  «       }d|j                  «       vr%t        j                  d|j                  |dd «       yda t        j                  d|dd «       y# t        $ r }t        j                  d|«       Y d}~yd}~ww xY w)a   Probe once per process whether ``--cpus``/``--memory``/``--pids-limit`` work here, via a
    throwaway ``sleep 0`` container from *image* (no extra pull). Without delegated cgroup
    controllers (unprivileged LXCs, rootless) these flags fail every start with exit 126;
    the result is host-wide, so it is cached. Only DEFINITIVE answers are cached: a probe
    that could not run (auto-pull past the timeout, daemon cold-start, manifest/pull error)
    says nothing about cgroup support, so it degrades this spawn and is retried on the next.NFÚrunz--rmú--cpusz0.5ú--memoryÚ64mú--pids-limitÚ32ÚsleepÚ0é<   r™   zbCgroup limit probe failed; containers run without CPU/memory/PID limits until a probe succeeds: %sr   TrÀ   Úcgroupz‹Cgroup limit probe could not determine support (docker exited %d: %s). Containers run without CPU/memory/PID limits until a probe succeeds.iô  zóCgroup resource limits (--cpus/--memory/--pids-limit) not available in this environment. Containers will run without CPU, memory or PID limits. To enable, delegate the cpu, memory and pids cgroup controllers to this container. Probe stderr: %s)
rî   rk   r   rB   r   r    rv   ry   r!   r«   )rÙ   rQ   r€   r�   ry   s        r(   Ú_cgroup_limits_availablerú   t  s
  € ô Ð$Ü Ð ä“€JÙ™UØðÜØ˜ ¨°%¸ÀUÈNÐ\`Ø�G˜Sð"àôˆð ×Ñ˜AÒØ ÐØØ�m‰mÒ!˜r×(Ñ(Ó*€FØ�v—|‘|“~Ñ%ä�‰ðSà×Ñ˜v d s˜|ô	-ð ØÐÜ
‡N�Nð	Qð 	ˆt�ˆôð øô- ò Ü�‰ð JØKLô	Näûðús   �B9 Â9	C"ÃCÃC"©Úexc_infoÚlog_msgÚerrorÚhintrü   c                óN   — t        j                  | g|¢­d|iŽ t        ||¬«      S )Nrü   )Ú
retry_hint)r   rþ   r   )rý   rþ   rÿ   rü   Úlog_argss        r(   Ú_docker_unavailabler  ¡  s%   € Ü
‡L�L�Ð7˜8Ò7¨hÒ7Ü% e¸Ô=Ð=r*   c                  óš  — t        «       } | st        ddd¬«      ‚	 t        | dgd¬«      }|j                  dk7  r3t        d| |j                  |j                  j                  «       dd¬«      ‚y# t        $ r t        d| d	d
d¬«      ‚t        j
                  $ r t        d| d	dd¬«      ‚t        $ r t        j                  dd	¬«       ‚ w xY w)zXFail fast with an ``EnvironmentConnectionError`` when the docker CLI/daemon is unusable.z–Docker backend selected but no docker executable was found in PATH or known install locations. Install Docker Desktop and ensure the CLI is available.z|Docker executable not found in PATH or known install locations. Install Docker and ensure the 'docker' command is available.zZInstall Docker (or fix PATH) and retry, or run `hermes setup terminal` to switch to Local.)rþ   rÿ   Úversioné   r™   zVDocker backend selected but the resolved docker executable '%s' could not be executed.TzHDocker executable could not be executed. Check your Docker installation.z)Repair the Docker installation and retry.)rü   rþ   rÿ   zYDocker backend selected but '%s version' timed out. The Docker daemon may not be running.zHDocker daemon is not responding. Ensure Docker is running and try again.uˆ   Start Docker (e.g. `systemctl start docker` or launch Docker Desktop), then retry â€” or run `hermes setup terminal` to switch to Local.z4Unexpected error while checking Docker availability.rû   r   zIDocker backend selected but '%s version' failed (exit code %d, stderr=%s)zXDocker command is available but 'docker version' failed. Check your Docker installation.uu   Start Docker, or add your user to the docker group, then retry â€” or run `hermes setup terminal` to switch to Local.N)rk   r  r   ÚFileNotFoundErrorrÜ   ÚTimeoutExpiredrB   r   rþ   rv   ry   r!   )rQ   r€   s     r(   Ú_ensure_docker_availabler	  ¦  s  € ä“€JÙÜ!ðbðQàmôoð 	oðÜ˜j¨)Ð4¸aÔ@ˆð" ×Ñ˜AÒÜ!ØWØ˜×)Ñ)¨6¯=©=×+>Ñ+>Ó+@ØlðFô	Gð 	Gð øô! ò >Ü!ØdØ Ø\Ø<ô	>ð 	>ô
 ×$Ñ$ò GÜ!ØgØ Ø\ðFô	Gð 	Gô ò Ü�‰ÐKÐVZˆÔ[Øðús   œA. Á.AC
c                 óV   — t        | «      D ��cg c]  }d|fD ]  }|‘Œ Œ c}}S c c}}w )z§``-e KEY`` flags (no values): the docker CLI resolves values from its own env,
    so secrets live in owner-readable /proc/*/environ instead of world-readable cmdline.z-e)Úsorted)Únamesr'   rÈ   s      r(   Ú_name_only_env_argsr  Ë  s,   € ô " %›=×@�C°T¸3°KÒ@¨SŠCÐ@ˆCÓ@Ð@ùÓ@s   �%))Úget_credential_file_mountsTÚ
credential)Úget_skills_directory_mountFz
skills dir)Úget_cache_directory_mountsFz	cache dirc            	      ó&  — g } 	 ddl m} t        D ]Ð  \  }}} t        ||«      «       D ]¶  }t	        |d   «      }|r'|j                  «       rdn|j                  «       rdnd}n|j                  «       rdnd}|r*t        j                  d|j                  «       d   ||«       Œz| j                  d|d   › d	|d
   › d�g«       t        j                  d||d   |d
   «       Œ¸ ŒÒ 	 | S # t        $ r!}t        j                  d|«       Y d}~| S d}~ww xY w)a=  ``-v host:container:ro`` args for credential files, skill dirs and cache dirs. Read-only so the
    container can authenticate/read but never modify host state. Missing or wrong-kind sources are
    skipped with a warning (Docker-in-Docker auto-creates a missing file source as a directory,
    which would exit 125).r   NÚ	host_pathz=source is a directory (likely Docker-in-Docker auto-creation)zsource not foundzsource is not a directoryu$   Docker: skipping %s mount â€” %s: %sú-vrè   Úcontainer_pathz:rozDocker: mounting %s %s -> %sz1Docker: could not load credential file mounts: %s)Útools.credential_filesÚcredential_filesÚ_RO_MOUNT_SOURCESré   r   Úis_dirÚis_filer   r    rÅ   rl   rw   rB   rx   )	rÆ   ÚcfÚgetterÚexpects_fileÚnounÚentryÚsrcÚproblemr�   s	            r(   Ú_readonly_skill_mount_argsr"  Ø  s0  € ð
 €DðMÝ+Ü*;ò 	oÑ&ˆF�L $Ø,œ  VÓ,Ó.ò o�Ü˜5 Ñ-Ó.�ÙØbe×blÑblÔbnÑ^Ø,/¯K©K¬M¡DÐ?Qñ ð '*§j¡j¤l™dÐ8S�GÙÜ—N‘NÐ#IÈ4Ï:É:Ë<ÐXYÉ?Ð\cÐehÔiØØ—‘˜T e¨KÑ&8Ð%9¸¸5ÐAQÑ;RÐ:SÐSVÐ#WÐXÔYÜ—‘Ð:¸DÀ%ÈÑBTÐV[Ð\lÑVmÕnñoñ	oð €Køô ò MÜ�‰ÐHÈ!×LÐLØ€KûðMús   „CC& Ã&	DÃ/DÄDc                 ó„   — | sg S t        «       }|�t        j                  d|«       d|gS t        j                  d«       g S )u¹   ``--user uid:gid`` so bind-mount writes are owned by the host user, not root. Without
    POSIX ids fall back to the full cap set â€” the image's init may still need to drop privileges.z)Docker: running container as host user %sz--userzƒdocker_run_as_host_user is enabled but this platform does not expose POSIX uid/gid; container will start as its image default user.)rì   r   rw   r    )rÎ   Ú	user_specs     r(   Ú_host_user_argsr%  ò  sN   € ñ Øˆ	Ü'Ó)€IØÐÜ�‰Ð?ÀÔKØ˜)Ð$Ð$Ü
‡N�Nð	TôUð €Ir*   c            )       ó4  ‡ — e Zd ZdZdZdZdeedf   fd„Zdddddd	d
dddddd	d	dde	dd	fdedede
dede
de
dedededee   dz  dedz  dedee   dedededededed ef(ˆ fd!„Zdeeee   ee   ee   ee   f   fd"„Zdee   fd#„Zdeee   ee   f   fd$„Zdedefd%„Zd&ededz  fd'„Zd(ed)edee   fd*„Zdedefd+„Zd,eeef   deeef   dz  fd-„Zdee   fd.„Zdeeeef   ee   f   fd/„Zdeee   eedf   eeef   f   fd0„Zd	d1dd2œd3ed4ede
d5edz  dej>                  f
d6„Z d7Z!d8edefd9„Z"defd:„Z#dId;ededefˆ fd<„Z$e%defd=„«       Z&d&edee   fd>„Z'd?ed@edAedeeeef      fdB„Z(dJdC„Z)d	dDœdEefdF„Z*e%dKdedefdG„«       Z+dLdedefdH„Z,ˆ xZ-S )MÚDockerEnvironmentu  Hardened Docker container execution (caps dropped, no-new-privileges, PID limits,
    size-limited tmpfs). The container is the security boundary â€” its filesystem stays
    writable so agents can install packages. Persistence bind-mounts /workspace and /root.Tr   .c                 ó,   — t        | j                  «      S )z@Keep explicit docker_forward_env values out of shared snapshots.)ÚtupleÚ_forward_env©Úselfs    r(   Ú,_additional_profile_scoped_passthrough_namesz>DockerEnvironment._additional_profile_scoped_passthrough_names	  s   € ä�T×&Ñ&Ó'Ð'r*   ú/rootrø   r   Fr@   NrÀ   rÙ   Úcwdr\   ÚcpuÚmemoryÚdiskÚpersistent_filesystemÚtask_idÚvolumesr   r+   ÚnetworkÚhost_cwdÚauto_mount_cwdrÎ   r¸   Úpersist_across_processesÚshm_sizeÚshared_container_keyrÐ   c           	      ó  •— |dk(  rd}t         ‰$| �  ||¬«       || _        || _        d| _        || _        t        |
«      | _        t        |«      | _	        d| _
        d | _        i | _        d | _        d | _        t        j!                  d|	«       |	�(t#        |	t$        «      st        j'                  d|	«       g }	t)        «        | j+                  |||||||«      }| j-                  |	|||«      \  }}|j/                  t1        «       «       | j3                  |«      \  }}}}}|j/                  |«       t5        |«      }t7        «       xs d| _        t;        | j8                  |«      }|rt        j!                  d	|«       t=        |xr t?        |«      ||¬
«      }|| _         |rt        j'                  d«       t        j!                  d|«       ||z   |z   |z   |z   |z   |z   |z   } t        j!                  d| «       tC        |«      }!tE        |«      }"ddd|"d|!tF        |i| _$        || _%        || _&        | | _'        |xr | jQ                  |"|!||«      }#|#s| jS                  |«      | _        | jU                  «       | _+        | jY                  «        y )NÚ~r.  )r/  r\   Fr•   zDockerEnvironment volumes: %sz'docker_volumes config is not a list: %rrS   ug   Docker: image %s uses /init (s6-overlay) as entrypoint â€” skipping --init and mounting /run with exec.)rÏ   rÐ   z]docker_snap_compat: running without --init and no-new-privileges (snap Docker under AppArmor)zDocker volume_args: %szDocker run_args: %szhermes-agentÚ1úhermes-task-idúhermes-profile)-ÚsuperÚ__init__Ú_persistentÚ_persist_across_processesÚ_session_scopedÚ_task_idr)   r*  r5   Ú_envÚ_init_unset_passthrough_namesÚ_container_idÚ_init_env_valuesÚ_workspace_dirÚ	_home_dirr   rw   r   rÒ   r    r	  Ú_resource_argsÚ_mount_argsrl   r"  Ú_egress_and_env_argsr%  rk   Ú_docker_exerä   rØ   r3   Ú_snap_compatrN   r<   r	   Ú_labelsÚ_imageÚ_image_uses_s6_initÚ_all_run_argsÚ_attach_existing_containerÚ_docker_runÚ_build_init_env_argsÚ_init_env_argsÚinit_session)%r,  rÙ   r/  r\   r0  r1  r2  r3  r4  r5  r   r+   r6  r7  r8  rÎ   r¸   r9  r:  r;  rÐ   Úresource_argsÚvolume_argsÚwritable_argsÚegress_labelÚegress_volume_argsÚegress_host_argsÚenv_argsÚvalidated_extraÚ	user_argsÚimage_uses_s6_initÚsecurity_argsÚall_run_argsÚprofile_nameÚ
task_labelÚreusedÚ	__class__s%                                       €r(   rB  zDockerEnvironment.__init__  s¶  ø€ ð, �#Š:ØˆCÜ‰Ñ˜S¨'ÐÔ2Ø0ˆÔØ)AˆÔ&ð  %ˆÔØˆŒÜ8¸ÓEˆÔÜ'¨Ó,ˆŒ	Ø>@ˆÔ*Ø,0ˆÔØ02ˆÔØ-1ˆÔØ(,ˆŒÜ�‰Ð3°WÔ=ØÐ¤z°'¼4Ô'@Ü�N‰NÐDÀgÔNØˆGä Ô"à×+Ñ+¨E°3¸ÀÀgÈxÐYcÓdˆØ%)×%5Ñ%5°g¸xÈÐY`Ó%aÑ"ˆ�]Ø×ÑÔ5Ó7Ô8à×%Ñ% jÓ1ñ 	VˆÐ(Ð*:¸HÀoà×ÑÐ-Ô.Ü#Ð$4Ó5ˆ	ô '›=Ò4¨HˆÔô 9¸×9IÑ9IÈ5ÓQÐÙÜ�K‰Kð?àôô -ØÒ0¤ i£Ð;MÐ[fôhˆà'ˆÔÙÜ�N‰NØoôqô 	�‰Ð,¨kÔ:ð ˜IÑ%¨Ñ5¸ÑEØñØ!,ñ-Ø/7ñ8Ø:IñJð 	ô 	�‰Ð)¨<Ô8ô +Ð+?Ó@ˆÜ*¨7Ó3ˆ
à˜CØ˜jØ˜lÜ˜|ð	-ˆŒð ˆŒØ#5ˆÔ Ø)ˆÔà)ò =¨d×.MÑ.MØ˜ l°Gó/=ˆáØ!%×!1Ñ!1°#Ó!6ˆDÔð #×7Ñ7Ó9ˆÔØ×ÑÕr*   c                 óà  — t        «       \  }}}t        |||«      }|r
t        «       nd}t        |«      }|r.t	        | j
                  ||«       t        | j                  ||«       t        | j                  ||«      }t        |«      | _
        g }	|xs g D ]:  }
t        |
t        «      st        j                  d|
«       Œ*|	j                  |
«       Œ< |rt!        |	||«       |||t#        |«      |	fS )a)  Egress credential-injection proxy plumbing (CA mount + HTTPS_PROXY/CA-bundle env so
        outbound traffic routes through the host-side proxy and the sandbox receives proxy tokens
        instead of real API keys), merged with docker_env into name-only ``-e`` args, plus the
        validated docker_extra_args. Returns ``(egress_label, volume_args, host_args, env_args,
        validated_extra)``; sets ``self._run_env_values`` (injected into the docker-client
        subprocess env at run time and reused verbatim by container-recreation recovery).Tz/Ignoring non-string docker_extra_args entry: %r)r   r   r   r
   r   r*  r   rG  r   r-   Ú_run_env_valuesr   r   r   r    r$   r   r  )r,  r¸   r_  Úegress_env_overridesr`  r^  Úenforce_egressÚcritical_egress_namesÚ
merged_envrb  rÈ   s              r(   rO  z&DockerEnvironment._egress_and_env_argsy  sý   € ô FcÓEdÑBÐÐ0Ð2BÜ0Ð1CÐEYÐ[kÓlˆÙ8LÔ2Ô4ÐRVˆÜ :Ð;OÓ PÐÙÜ(¨×):Ñ):Ð<QÐSaÔbÜ'¨¯	©	Ð3GÈÔXä% d§i¡iÐ1EÀ~ÓVˆ
Ü# JÓ/ˆÔàˆØÒ$ "ò 	(ˆCÜ˜c¤3Ô'Ü—‘ÐPÐRUÔVØØ×"Ñ" 3Õ'ð		(ñ
  Ü'¨Ð9NÐP^Ô_ØÐ/Ð1AÔCVÐWaÓCbÐdsÐsÐsr*   c                 ó`  — g }t        |«      rS|dkD  r|j                  dt        |«      g«       |dkD  r|j                  d|› d�g«       |j                  dt        g«       t        |xs d«      j	                  «       }	|	r#|	dk7  rt        |«      s|j                  d|	g«       |dkD  rPt        j                  d	k7  r=| j                  «       r|j                  d
d|› d�g«       nt        j                  d«       |s4t        |«      }
|
€|j                  d«       |S |
dk7  rt        d|
›d�«      ‚|S )zKcgroup-gated CPU/memory/pids limits, shm size, disk quota and network mode.r   rñ   rò   Úmrô   rÀ   r÷   r»   Údarwinú--storage-optzsize=z�Docker storage driver does not support per-container disk limits (requires overlay2 on XFS with pquota). Container will run without disk quota.z--network=noneÚnonez`terminal.docker_network is false (air-gapped) but terminal.docker_extra_args requests --network=zj. Remove the --network entry from docker_extra_args, or set docker_network: true to opt into that network.)rú   rl   r   Ú_DEFAULT_PIDS_LIMITr!   r¾   ÚsysÚplatformÚ_storage_opt_supportedr   r    rÊ   r$   ÚRuntimeError)r,  rÙ   r0  r1  r2  r6  r:  r¸   rÆ   ÚshmÚextra_networks              r(   rM  z DockerEnvironment._resource_args•  sB  € àˆÜ# EÔ*Ø�QŠwØ—‘˜X¤s¨3£xÐ0Ô1Ø˜ŠzØ—‘˜Z¨F¨8°1¨Ð6Ô7Ø�K‰K˜Ô)<Ð=Ô>ô �(’.˜bÓ!×'Ñ'Ó)ˆÙ�3˜#’:Ô&>¸zÔ&JØ�K‰K˜ sÐ+Ô,Ø�!Š8œŸ™¨Ò0Ø×*Ñ*Ô,Ø—‘˜_°°d°V¸1¨oÐ>Õ?ä—‘ðeôfñ Ü4°ZÓ@ˆMØÐ$Ø—‘Ð,Ô-ð ˆð  &Ò(ô #ð*Ø*7Ð):ð ;_ð`óað að
 ˆr*   c                 ó°  — g }|xs g D ]j  }t        |t        «      st        j                  d|«       Œ*|j	                  «       }|sŒ=d|vrt        j                  d|«       ŒX|j                  d|g«       Œl t        d„ |D «       «      }|r<t        j                  j                  t        j                  j                  |«      «      nd}|xr1 t        |«      xr$ t        j                  j                  |«      xr | }	|r7|r5t        j                  j                  |«      st        j                  d|«       |	r|nd| _        |	 xr | }
g }| j                  r¯d	d
lm}  |«       dz  t%        |«      z  }t        |dz  «      | _        t        j(                  | j&                  d¬«       |d| j&                  › d�gz  }|
r[t        |dz  «      | _        t        j(                  | j*                  d¬«       |d| j*                  › d�gz  }n||
rddgng z  }|g d¢z  }|	r#t        j-                  d|«       d|› d�g|¢}||fS |rt        j                  d«       ||fS )z¯``(volume_args, writable_args)`` for user volumes, host cwd and /workspace,/root.
        Persistent mode bind-mounts from TERMINAL_SANDBOX_DIR (default ~/.hermes/sandboxes/).z'Docker volume entry is not a string: %rrè   z*Docker volume '%s' missing colon, skippingr  c              3   ó$   K  — | ]  }d |v –— Œ
 y­w)ú:/workspaceNr•   )rc   Úvs     r(   re   z0DockerEnvironment._mount_args.<locals>.<genexpr>È  s   è ø€ Ò*SÀ!¨=¸AÔ+=Ñ*Sùs   ‚rÀ   z@Skipping docker cwd mount: host_cwd is not a valid directory: %sNr   )Úget_sandbox_dirrS   ÚhomeT)Úexist_okz:/rootÚ	workspacer  rµ   z/workspace:rw,exec,size=10g)rµ   z/home:rw,exec,size=1grµ   z/root:rw,exec,size=1gz.Mounting configured host cwd to /workspace: %szDSkipping docker cwd mount: /workspace already mounted by user config)r   r   r   r    r!   rl   r½   r�   rŽ   ÚabspathÚ
expanduserr3   Úisdirrx   r7  rC  Útools.environments.baser�  Ú_sandbox_dir_namerL  ÚmakedirsrK  rw   )r,  r5  r7  r8  r4  r\  ÚvolÚworkspace_explicitly_mountedÚhost_cwd_absÚbind_host_cwdÚmount_workspacer]  r�  Úsandboxs                 r(   rN  zDockerEnvironment._mount_args¹  sE  € ð "$ˆØ’M˜rò 
	,ˆCÜ˜c¤3Ô'Ü—‘ÐHÈ#ÔNØØ—)‘)“+ˆCÙØØ˜#‰~Ü—‘ÐKÈSÔQØØ×Ñ  c˜{Õ+ð
	,ô (+Ñ*SÀ{Ô*SÓ'SÐ$áHP”r—w‘w—‘¤r§w¡w×'9Ñ'9¸(Ó'CÔDÐVXˆàò 1œt LÓ1ò 1´b·g±g·m±mÀLÓ6Qò 1Ø0Ð0ð 	ñ ™h¬r¯w©w¯}©}¸\Ô/JÜ�L‰LÐ[Ð]eÔfñ )6™¸4ˆŒØ+Ð+ÒPÐ4PÐ0Pˆà#%ˆØ×ÒÝ?ñ &Ó'¨(Ñ2Ô5FÀwÓ5OÑOˆGÜ  ¨6Ñ!1Ó2ˆDŒNÜ�K‰K˜Ÿ™°Õ6Ø˜d t§~¡~Ð&6°fÐ$=Ð>Ñ>ˆMÙÜ&)¨'°KÑ*?Ó&@�Ô#Ü—‘˜D×/Ñ/¸$Õ?Ø $¨4×+>Ñ+>Ð*?¸{Ð(KÐ!LÑL‘àÉ?˜iÐ)FÑGÐ`bÑbˆMØÒeÑeˆMáÜ�K‰KÐHÈ,ÔWØ L >°Ð!=ÐLÀÐLˆKð ˜MÐ)Ð)ñ *Ü�L‰LÐ_Ô`Ø˜MÐ)Ð)r*   c                 ó  — | j                  |||«      }|€y|\  }}|sS| j                  |«      }|dk7  r=t        j                  d|dd |xs d||«       	 t	        | j
                  dd|gd	¬
«       y|dk7  r/| j                  |«      }
|
�t        j                  d|dd ||
«       y|| _
        t        j                  d|dd |||«       y# t        j                  t        f$ r$}	t        j                  d|dd |	«       Y d}	~	yd}	~	ww xY w)a©  Attach to a prior process's labeled container ("ONE long-lived container shared
        across sessions"; opt out via ``docker_persist_across_processes: false``).
        Network guard is lockdown-only: a bridge container under ``docker_network: false``
        is removed and recreated, but a ``none`` container under default config is kept so
        ``--network=none`` in extra args doesn't churn containers every startup.NFru  uœ   Existing container %s has NetworkMode=%s but docker_network=false requests an air-gapped container â€” removing it and starting fresh (task=%s, profile=%s).rF   r7   rf   ú-frg   r™   z,Failed to remove mismatched container %s: %sÚrunningu[   Failed to start existing container %s (state=%s): %s â€” falling back to a fresh container.z:Reusing container %s (task=%s, profile=%s, prior state=%s)T)Ú_find_reusable_containerÚ_container_network_moder   r    r   rP  rÜ   r  rÞ   Ú_start_containerrI  rw   )r,  rh  rg  r^  r6  Úexistingr‚   ÚstateÚactual_moder�   Úerrs              r(   rV  z,DockerEnvironment._attach_existing_containerî  sE  € ð ×0Ñ0°¸\È<ÓXˆØÐØØ&Ñˆ�eÙØ×6Ñ6°|ÓDˆKØ˜fÒ$Ü—‘ðZð !  "Ð% {Ò'?°iÀÈ\ô	[ð
iÜ ×!1Ñ!1°4¸¸|Ð LÐVXÕYð à�IÒØ×'Ñ'¨Ó5ˆCØˆÜ—‘ð@à   "Ð% u¨cô3ð Ø)ˆÔÜ�‰ØHØ˜˜"Ð˜z¨<¸ô	@ð øô! #×1Ñ1´7Ð;ò iÜ—N‘NÐ#QÐS_Ð`cÐacÐSdÐfg×hÐhØûðiús   ÁC	 Ã	DÃ"DÄDr‚   c                 ó    — 	 t        | j                  d|gdd¬«       y# t        j                  t        j                  f$ r}|cY d}~S d}~ww xY w)zM``docker start`` a stopped container; returns the failure instead of raising.Ústartrg   T)r\   ÚcheckN)r   rP  rÜ   ÚCalledProcessErrorr  )r,  r‚   r�   s      r(   r–  z"DockerEnvironment._start_container  sJ   € ð	Ü˜×)Ñ)¨7°LÐAÈ2ÐUYÕZØøÜ×-Ñ-¬z×/HÑ/HÐIò 	Ø�Hûð	ús   ‚ ž#AÁAÁAÁAÚnameÚworkdirc           	      ó,  — | j                   j                  «       D ���cg c]  \  }}d|› d|› �fD ]  }|‘Œ Œ }}}}| j                  ddg| j                  s| j                  rg ndg¢d‘|‘|¢d‘|‘| j
                  ¢| j                  ‘d‘d	‘S c c}}}w )
z³``docker run -d`` argv for a fresh ``sleep infinity`` container (idle reaper handles
        lifetime). s6-overlay images already provide PID 1, so ``--init`` is skipped for them.z--labelrÁ   rð   z-dz--initz--namez-wrö   Úinfinity)rR  r0   rP  rT  rQ  rU  rS  )r,  rŸ  r   Úkr€  rÈ   Ú
label_argss          r(   Ú_run_commandzDockerEnvironment._run_command  sí   € ð '+§l¡l×&8Ñ&8Ó&:×^Ð^™d˜a ÀyÐUVÐTWÐWXÐYZÐX[ÐR\ÐF]Ò^¸s’cÐ^�cÐ^ˆ
Ò^ð
 ×Ñ˜e Tð	!ð
 ×,Ò,°×0AÒ0A‰bÈÀzð!ð ð!ð ð!ð ð!ð ð!ð ð!ð ×Ñð!ð �K‰Kð!ð ð!ð  ð!ð 	!ùô _s   ŸBc                 óf  — dt        j                  «       j                  dd › �}| j                  ||«      }t        j                  ddj                  |«      «       	 t        |dd| j                  | j                  «      ¬«      }|j"                  j%                  «       }t        j'                  d||dd «       |S # t        j                  t        j                  f$ rR}t        j                  d	||«       t        j                  | j                  d
d|gddt        j                   ¬«       ‚ d}~ww xY w)zÞStart a fresh container and return its id. A failed ``docker run`` (exit 125, timeout
        mid-pull) can leave a "Created" orphan the exited-only reaper never catches, so it is
        removed by name before re-raising.úhermes-Né   zStarting container: %sÚ éx   T©r\   r�  r+   z<docker run failed for %s, cleaning up orphaned container: %srf   r’  r…   ©Úcapture_outputr\   ÚstdinzStarted container %s (%s)rF   )ÚuuidÚuuid4Úhexr¥  r   rx   Újoinr   Ú_docker_client_envrl  rÜ   rž  r  r    rð   rP  ÚDEVNULLrr   r!   rw   )r,  r/  Úcontainer_nameÚrun_cmdr€   r�   r‚   s          r(   rW  zDockerEnvironment._docker_run-  s  € ð #¤4§:¡:£<×#3Ñ#3°B°QÐ#7Ð"8Ð9ˆØ×#Ñ# N°CÓ8ˆÜ�‰Ð-¨s¯x©x¸Ó/@ÔAð		Ü Ø ¨DØ×+Ñ+¨D×,@Ñ,@ÓAôCˆFð —}‘}×*Ñ*Ó,ˆÜ�‰Ð/°ÀÈcÈrÐARÔSØÐøô ×-Ñ-¬z×/HÑ/HÐIò 	Ü�N‰NÐYÐ[iÐklÔmÜ�N‰NØ×!Ñ! 4¨¨~Ð>Ø#¨R´z×7IÑ7IõKð ûð	ús   Á(B; Â;#D0ÃAD+Ä+D0Úvaluesc                 ó   — t        |«      S )a   Env for the docker-client subprocess carrying forwarded values (pairs with name-only
        ``-e KEY`` flags to keep secrets out of cmdline); ``None`` = inherit when empty.

        Name-only ``-e KEY`` flags make the docker CLI read each value from its own process environment,
        keeping secrets out of the client's world-readable ``/proc/<pid>/cmdline`` (issue #96268). Values
        live in ``/proc/<pid>/environ`` instead, which is owner/root-only. Returns ``None`` (inherit as
        before) when there is nothing to add.
        )r   )r,  r·  s     r(   r³  z$DockerEnvironment._docker_client_envC  s   € ô ˜vÓ&Ð&r*   c                 óâ   — | j                  «       \  }}i | j                  ¥|¥}|D ]  }|j                  |d«       Œ t        t	        |«      «      | _        t        |«      | _        t        |«      S )u}  Name-only ``-e`` args for init_session so ``export -p`` captures docker_env
        plus the current profile's forwarded values (values travel via the client env).

        The VALUES intentionally do not appear in the argv â€” they are passed via the docker client
        subprocess env (see _docker_client_env and issue #96268); the flags here are name-only ``-e KEY``.
        N)	Ú_resolve_passthrough_envrG  Úpopr)  r  rH  r-   rJ  r  )r,  Úpassthrough_envÚunset_namesÚexec_envrŸ  s        r(   rX  z&DockerEnvironment._build_init_env_argsN  sp   € ð (,×'DÑ'DÓ'FÑ$ˆ˜Ø3�d—i‘iÐ3 ?Ð3ˆØò 	%ˆDØ�L‰L˜˜tÕ$ð	%ä-2´6¸+Ó3FÓ-GˆÔ*Ü $ X£ˆÔÜ" 8Ó,Ð,r*   c                 ó8   — t        | j                  t        ¬«      S )zbSee ``remote_common.resolve_passthrough_env``; explicit docker_forward_env bypasses the blocklist.)Úhermes_env_loader)r   r*  Ú_load_hermes_env_varsr+  s    r(   rº  z*DockerEnvironment._resolve_passthrough_env]  s   € ä& t×'8Ñ'8ÔLaÔbÐbr*   c                 óz   — | j                  «       \  }}t        |«      t        t        |«      «      t	        |«      fS )z¡Runtime name-only forwarding args, names absent from scope, and the values
        to inject into the docker client subprocess env.

        See #96268.
        )rº  r  r)  r  r-   )r,  r¼  r½  s      r(   Ú#_build_runtime_env_args_with_unsetsz5DockerEnvironment._build_runtime_env_args_with_unsetsa  s:   € ð (,×'DÑ'DÓ'FÑ$ˆ˜Ü" ?Ó3´U¼6À+Ó;NÓ5OÔQUÐVeÓQfÐfÐfr*   rª  )Úloginr\   Ú
stdin_dataÚ
cmd_stringrÄ  rÅ  c                óü  — | j                   sJ d«       ‚| j                  dg}|�|j                  d«       d}i }|r?|j                  | j                  «       t        t        | di «      «      }t        | dd«      }n1| j                  r%| j                  «       \  }}}|j                  |«       || j                   gt        t        ||«      |«      ¢z  }| j                  |«      }	|	�t        |||	¬«      S t        ||«      S )zâSpawn bash inside the container. Init seeds the snapshot; profile-scoped passthrough
        values are re-injected on every command because one container can be shared by
        multiple routed profiles in a gateway process.zContainer not startedÚexecz-ir•   rJ  rH  )r+   )rI  rP  r$   rl   rY  r-   ré   Ú_profile_scoped_passthroughrÃ  r   r   r³  r   )
r,  rÆ  rÄ  r\   rÅ  Úcmdr½  Ú
env_valuesÚruntime_argsÚ
client_envs
             r(   Ú	_run_bashzDockerEnvironment._run_bashj  s  € ð ×!Ò!Ð:Ð#:Ó:Ð!Ø×Ñ Ð(ˆØÐ!Ø�J‰J�tÔð (*ˆØ%'ˆ
ÙØ�J‰J�t×*Ñ*Ô+Üœg dÐ,>ÀÓCÓDˆJÜ! $Ð(GÈÓL‰KØ×-Ò-Ø48×4\Ñ4\Ó4^Ñ1ˆL˜+ zØ�J‰J�|Ô$Ø�×"Ñ"Ð^¤Y¬}¸ZÈÓ/UÐW\Ó%]Ð^Ñ^ˆà×,Ñ,¨ZÓ8ˆ
Ø?IÐ?UŒ{˜3 
°
Ô;ÐwÔ[fÐgjÐlvÓ[wÐwr*   )zNo such containerzis not runningzno such containerÚoutputc                 ó@   ‡— t        ˆfd„| j                  D «       «      S )Nc              3   ó&   •K  — | ]  }|‰v –— Œ
 y ­wr`   r•   )rc   rž   rÏ  s     €r(   re   z7DockerEnvironment._is_container_gone.<locals>.<genexpr>‹  s   øè ø€ ÒD 1�1˜”;ÑDùs   ƒ)r½   Ú_NO_CONTAINER_PATTERNS)r,  rÏ  s    `r(   Ú_is_container_gonez$DockerEnvironment._is_container_goneŠ  s   ø€ ÜÓD¨×(CÑ(CÔDÓDÐDr*   c                 ó\  — t         j                  d| j                  xs ddd «       d| _        | j                  | j                  j                  dd«      | j                  j                  dd«      | j                  j                  t        d«      «      }|�y|\  }}|dk(  r!|| _        t         j                  d	|dd «       nN| j                  |«      x}€!|| _        t         j                  d
|dd «       nt         j                  d|dd |«       | j                  sÌ| j                  st         j                  d«       y	 dt        j                  «       j                  dd › �}t        | j                  || j                   «      dd| j#                  | j$                  «      ¬«      }|j&                  j)                  «       | _        t         j                  d|| j                  dd «       	 d| _        | j5                  «        t         j                  d| j                  xs ddd «       | j9                  «        y# t*        j,                  t*        j.                  t0        f$ r }t         j                  d|«       Y d}~yd}~ww xY w# t6        $ r }t         j                  d|«       Y d}~yd}~ww xY w)zïRecreate a container removed out-of-band: label-based reuse first (another process
        may have recreated it), else a fresh one from the saved image/run-args. False when
        recovery fails so the caller surfaces the original error.u7   Container %s appears to be gone â€” attempting recoveryrÀ   NrF   r?  r@  Úoffr“  z&Recovery: reusing running container %sz Recovery: restarted container %sz*Recovery: failed to start container %s: %sz8Recovery: no saved image name, cannot recreate containerFr§  r¨  rª  Tr«  z)Recovery: created fresh container %s (%s)z,Recovery: failed to create new container: %sz2Recovery: init_session failed in new container: %su(   Recovery successful â€” new container %s)r   r    rI  r”  rR  Úgetr	   rw   r–  rS  rþ   r¯  r°  r±  r   r¥  r/  r³  rl  rr   r!   rÜ   rž  r  rÞ   Ú_snapshot_readyrZ  rB   Ú_mark_recreated)r,  r—  r}   r˜  rš  Únew_namer€   r�   s           r(   Ú_recreate_containerz%DockerEnvironment._recreate_container�  s_  € ô 	�‰ÐPÐSW×SeÑSeÒSkÐikÐmpÐnpÐRqÔrØ!ˆÔà×0Ñ0Ø�L‰L×ÑÐ-¨rÓ2Ø�L‰L×ÑÐ-¨rÓ2Ø�L‰L×ÑÔ.°Ó6ó8ˆð ÐØ!‰JˆC�Ø˜	Ò!Ø%(�Ô"Ü—‘ÐDÀcÈ#È2ÀhÕOØ×.Ñ.¨sÓ3Ð3�#Ð<Ø%(�Ô"Ü—‘Ð>ÀÀCÀRÀÕIä—‘ÐKÈSÐQTÐRTÈXÐWZÔ[à×!Ò!Ø—;’;Ü—‘ÐWÔXØð	Ø$¤T§Z¡Z£\×%5Ñ%5°b°qÐ%9Ð$:Ð;�Ü$Ø×%Ñ% h°·±Ó9À3ÈdØ×/Ñ/°×0DÑ0DÓEôG�ð &,§]¡]×%8Ñ%8Ó%:�Ô"Ü—‘ÐGÈÐSW×SeÑSeÐfiÐgiÐSjÔkð
	Ø#(ˆDÔ Ø×ÑÔô
 	�‰Ð>À×ASÑASÒAYÐWYÐ[^Ð\^Ð@_Ô`Ø×ÑÔØøô ×1Ñ1´:×3LÑ3LÌgÐVò Ü—‘ÐKÈQÔOÜûðûô ò 	Ü�L‰LÐMÈqÔQÜûð	ús1   Ä>B)H7 Ç(J È7(I?ÉI:É:I?Ê	J+ÊJ&Ê&J+Úcommandc                 óð   •— t        ‰| �  ||fi |¤Ž}|j                  dd«      dk7  rN| j                  |j                  dd«      «      r-| j                  r!| j                  «       rt        ‰| �  ||fi |¤Ž}|S )z�Execute a command; if the container was removed out-of-band (idle reaper,
        docker prune, OOM, daemon restart) recreate it and retry once.rv   r   rÏ  rÀ   )rA  ÚexecuterÖ  rÓ  rD  rÚ  )r,  rÛ  r/  Úkwargsr€   rj  s        €r(   rÝ  zDockerEnvironment.execute½  su   ø€ ô ‘‘ ¨#Ñ8°Ñ8ˆà�J‰J�| QÓ'¨1Ò,Ø×'Ñ'¨¯
©
°8¸RÓ(@ÔAØ×.Ò.Ø×(Ñ(Ô*Ü‘W‘_ W¨cÑ<°VÑ<ˆFØˆr*   c                  ó€  — t         �t         S 	 t        «       xs d} t        | dddgd¬«      }|j                  dk7  ry|j                  j                  «       j                  «       d	k7  rda yt        | d
dddgd¬«      }|j                  dk(  r_da |j                  j                  «       ret        j                  | d|j                  j                  «       gddt        j                  ¬«       n"d|j                  xs dj                  «       v rda t        j                  dt         «       t         xs dS # t        $ r Y yw xY w)a  Whether ``--storage-opt size=`` works (only overlay2 on XFS with pquota; ext4 errors out).
        Only definitive answers are cached: a probe that could not run (daemon cold-start,
        hello-world pull timeout) says nothing about pquota support and is retried next spawn.rS   rw   rY   z{{.Driver}}r…   r™   r   FÚoverlay2Úcreatert  zsize=1mzhello-worldrZ   Trf   r  r¬  ÚstoragerÀ   z Docker --storage-opt support: %s)rí   rk   r   rv   rr   r!   r«   rÜ   rð   r´  ry   rB   r   rx   )rS   r€   Úprobes      r(   ry  z(DockerEnvironment._storage_opt_supportedÉ  s(  € ô Ð&Ü"Ð"ð	Ü “]Ò. hˆFÜ  &¨&°*¸mÐ!LÐVXÔYˆFØ× Ñ  AÒ%ØØ�}‰}×"Ñ"Ó$×*Ñ*Ó,°
Ò:Ø"'�Øä ¨°?ÀIÈ}Ð ]ÐgiÔjˆEØ×Ñ 1Ò$Ø"&�Ø—<‘<×%Ñ%Ô'Ü—N‘N F¨D°%·,±,×2DÑ2DÓ2FÐ#GØ26ÀÌ×I[ÑI[ö]à˜uŸ|™|Ò1¨r×8Ñ8Ó:Ñ:Ø"'�ô 	�‰Ð7¼ÔIÜÒ' %Ð'øô ò 	Ùð	ús   Ž.D1 ½-D1 Á+B"D1 Ä1	D=Ä<D=c                 ó‚   — t        | j                  ddd|gddd¬«      }|�|j                  j                  «       xs dS dS )	z­``HostConfig.NetworkMode`` of a container, or ``None`` when inspection fails (callers
        treat ``None`` as a mismatch under lockdown, so a failed inspect fails closed).r„   rY   z{{.HostConfig.NetworkMode}}r…   z%docker inspect NetworkMode failed: %sz*docker inspect NetworkMode returned %d: %sr[   N)rm   rP  rr   r!   )r,  r‚   r€   s      r(   r•  z)DockerEnvironment._container_network_modeè  sR   € ô Ø×Ñ˜y¨*Ð6SÐUaÐbÐlnØ8ÐBnôpˆð 39Ð2D�—‘×#Ñ#Ó%Ò-¨ÐNÈ$ÐNr*   rh  Úprofile_labelr^  c                 ó”  — dddd|› �dd|› �ddt         › d|› �g}t        | j                  ddg|¢d	‘d
‘ddd¬«      }|€ydx}}d„ |j                  j	                  «       D «       D ]\  }|j                  dd«      }	t        |	«      dk7  rŒ$|	d   |	d   j                  «       j                  «       }}
|€|
|f}|dk(  sŒV|�ŒY|
|f}Œ^ |xs |S )u(  ``(container_id, state)`` of an existing container labeled for this task/profile/
        egress posture, or ``None`` on miss or any failure. The egress posture is a label
        FILTER for every posture, "off" included: a container built with egress on must not be
        reused after ``hermes egress disable`` (baked-in proxy env and CA mounts), and every
        container this class creates carries the label. The ``{{.Label "key"}}`` template
        function is Docker-only â€” podman ps exits 125 on it â€” so the probe never uses it (#99213).rT   rU   zlabel=hermes-task-id=rV   zlabel=rÁ   rW   rX   rY   z{{.ID}}	{{.State}}r…   u;   docker ps probe failed: %s â€” will start a fresh containeru@   docker ps probe returned %d: %s â€” will start a fresh containerr[   Nc              3   óB   K  — | ]  }|j                  «       sŒ|–— Œ y ­wr`   ra   rb   s     r(   re   z=DockerEnvironment._find_reusable_container.<locals>.<genexpr>  s   è ø€ ÒI˜"¸b¿h¹h½j”2ÑIùs   ‚˜ú	rj   é   r   r“  )	r	   rm   rP  rr   rs   rÅ   rÄ   r!   r«   )r,  rh  rå  r^  rz   r€   r“  Úfirstrd   Úpartsr}   r˜  s               r(   r”  z*DockerEnvironment._find_reusable_containerð  s  € ð Ð.ØÐ/°
¨|Ð<ØÐ/°¨Ð?Ø˜&Ô!2Ð 3°1°\°NÐCð	Eˆô
 Ø×Ñ˜t TÐW¨GÐW°ZÐWÐAVÐWÐacØNØVôXˆð ˆ>Øð Ðˆ�%ÙI §¡× 8Ñ 8Ó :ÔIò 	'ˆBØ—H‘H˜T 1Ó%ˆEÜ�5‹z˜QŠØØ˜q™ 5¨¡8§>¡>Ó#3×#9Ñ#9Ó#;�ˆCØˆ}Ø˜e˜�Ø˜	Ó! g¡oØ ˜,‘ð	'ð Ò˜%Ðr*   c                 ór   — | j                   | j                  fD ]  }|sŒt        j                  |d¬«       Œ y )NT)Úignore_errors)rK  rL  r    Úrmtree)r,  Úds     r(   Ú_remove_bind_dirsz#DockerEnvironment._remove_bind_dirs  s1   € Ø×%Ñ% t§~¡~Ð6ò 	5ˆAÚÜ—‘˜a¨tÖ4ñ	5r*   )Úforce_removerñ  c                óÊ  ‡‡‡— | j                   Š‰s| j                  s| j                  «        y|s| j                  rd| _         y| j                  Š‰dd Šdˆˆˆfd„}t        j                  |dd‰› �¬«      }t        5  t        j                  |«       ddd«       |j                  «        || _        d| _         | j                  s| j                  «        yy# 1 sw Y   ŒExY w)u‡  Tear down per persist mode. Persist mode (default) leaves the container RUNNING â€”
        stopping it on every exit would kill background processes and add a ``docker start``
        delay per session; reclamation is ``reap_orphan_containers()`` at next startup.
        ``persist_across_processes=False`` or ``force_remove=True`` (explicit-teardown hook,
        unused so far) does ``docker stop`` + ``docker rm -f`` on a daemon thread that the
        atexit hook joins via ``wait_for_cleanup`` so the work completes before exit.

        Cleanup runs on a daemon thread with bounded ``subprocess.run`` calls (not the racy ``Popen(... &)``
        pattern from before PR #33645). The atexit hook in ``tools/terminal_tool.py`` waits up to 15s for
        the thread to finish before the interpreter exits, so ``docker stop`` / ``docker rm`` actually
        completes when we do trigger it.
        NrF   c                  ó  •— g d¢dfddgdffD ]2  \  } }	 t        j                  ‰g| ¢‰‘ddt         j                  ¬«       Œ4 y # t         j                  t        f$ r!}t
        j                  |‰|«       Y d }~Œkd }~ww xY w)	N)Ústopz-tÚ10z%docker stop %s timed out / failed: %srf   r’  zdocker rm -f %s failed: %sTrg   r¬  )rÜ   rð   r´  r  rÞ   r   r    )r—   Úfail_msgr�   r‚   rQ   Úlog_ids      €€€r(   Ú_do_cleanupz.DockerEnvironment.cleanup.<locals>._do_cleanup4  sŽ   ø€ Ú$8Ð:aÐ#bØ%)¨4 LÐ2NÐ#Oð#Qò 8‘��hð8Ü—N‘NØ#Ð9 dÐ9¨LÐ9Ø'+°R¼z×?QÑ?QöSñ8øô #×1Ñ1´7Ð;ò 8Ü—N‘N 8¨V°Q×7Ñ7ûð8ús   •,AÁA>ÁA9Á9A>Tzhermes-cleanup-)ÚtargetÚdaemonrŸ  ©r   N)rI  rC  rð  rD  rP  Ú	threadingÚThreadÚ_TEARDOWN_LOCKrÍ   Úaddrœ  Ú_cleanup_thread)r,  rñ  rø  Útr‚   rQ   r÷  s       @@@r(   ÚcleanupzDockerEnvironment.cleanup  sÛ   ú€ ð ×)Ñ)ˆÙà×#Ò#Ø×&Ñ&Ô(Øá × >Ò >ð "&ˆDÔØð ×%Ñ%ˆ
Ø˜c˜rÐ"ˆ÷	8ô ×Ñ K¸À_ÐU[ÐT\ÐC]Ô^ˆÜñ 	%Ü×!Ñ! !Ô$÷	%à	�‰Œ	Ø ˆÔØ!ˆÔð ×ÒØ×"Ñ"Õ$ð  ÷	%ð 	%ús   Á?CÃC"c                 ól  — t        j                  «       | z   }	 t        5  t        j	                  t        D �ch c]  }|j                  «       rŒ|’Œ c}«       t        t        «      }ddd«       sy|t        j                  «       z
  }|dk  ry|d   j                  |¬«       ŒŒc c}w # 1 sw Y   ŒDxY w)ui  Join every in-flight teardown worker, including those of envs the idle reaper already
        popped out of the active registry (their handles are otherwise unreachable at exit, so
        ``docker rm`` died with the interpreter and left a stopped container behind â€” #86317).
        Re-snapshots each pass: the reaper may start a worker while the drain runs.TNr   Fr™   )ÚtimeÚ	monotonicrþ  rÍ   Údifference_updateÚis_aliverÒ   r²  )r\   Údeadliner  ÚpendingÚ	remainings        r(   Úwait_for_all_teardownsz(DockerEnvironment.wait_for_all_teardownsJ  sž   € ô —>‘>Ó# gÑ-ˆØÜñ 2Ü!×3Ñ3Ô@QÖ4f¸1ÐYZ×YcÑYcÕYe²QÒ4fÔgÜÔ0Ó1�÷2ñ ØØ ¤4§>¡>Ó#3Ñ3ˆIØ˜AŠ~ØØ�A‰J�O‰O IˆOÔ.ð ùâ4f÷2ð 2ús"   ŸB*·B%
ÁB%
ÁB*Â%B*Â*B3c                 óˆ   — t        | dd«      }|�|j                  «       sy|j                  |¬«       |j                  «        S )z†Block up to *timeout* seconds for the cleanup thread (atexit hook). True if it
        finished or none was started, False on timeout.r   NTr™   )ré   r  r²  )r,  r\   Úthreads      r(   Úwait_for_cleanupz"DockerEnvironment.wait_for_cleanup\  sB   € ô ˜Ð0°$Ó7ˆØˆ> §¡Ô!2ØØ�‰˜GˆÔ$Ø—?‘?Ó$Ð$Ð$r*   ©rÀ   rû  )g      .@)g      >@).r/   Ú
__module__Ú__qualname__Ú__doc__Ú_sudo_nopasswd_probe_supportedrÉ  r)  r   r-  Ú_DEFAULT_SHM_SIZEr1   r2   r3   rÒ   r-   r   rB  rO  rM  rN  rV  rB   r–  r¥  rW  r³  rX  Úsetrº  rÃ  rÜ   ÚPopenrÎ  rÒ  rÓ  rÚ  rÝ  Ústaticmethodry  r•  r”  rð  r  r  r  Ú__classcell__)rj  s   @r(   r'  r'    sø  ø„ ñ^ð &*Ð"Ø"&Ðð(¸eÀCÈÀH¹oó (ð ØØØØØ&+Ø ØØ(,ØØØ"&Ø$Ø!&ØØ)-Ø)Ø$&Ø!ñ+iàðið ðið ð	ið
 ðið ðið ðið  $ðið ðið ðið ˜#‘Y Ñ%ðið �D‰[ðið ðið ˜3‘-ðið ðið  ð!ið" ð#ið$ #'ð%ið& ð'ið( "ð)ið* õ+iðXt°%¸¸TÀ#¹YÈÈSÉ	ÐSWÐX[ÑS\Ð^bÐcfÑ^gÐ8gÑ2hó tð8"ÐY]Ð^aÑYbó "ðH3*ÈÈtÐTWÉyÐZ^Ð_bÑZcÐOcÑIdó 3*ðj$ÐZ^ð $Ðcgó $ðL¨Sð °YÀÑ5Eó ð! ð !¨sð !°t¸C±yó !ð"˜sð  só ð,	'¨¨c°3¨h©ð 	'¸DÀÀcÀ¹NÈTÑ<Qó 	'ð- d¨3¡ió -ðc¨%°°S¸#°X±ÀÀCÁÐ0HÑ*Ió cðg°U¸4À¹9ÀeÈCÐQTÈHÁoÐW[Ð\_ÐadÐ\dÑWeÐ;eÑ5fó gð ;@Ø!$Ø+/òx Cð x°4ð xØðxà! D™jðxà4>×4DÑ4Dóxð< ZÐðE¨ð E°ó Eð. Tó .ñ`
˜sð 
¨ð 
Àõ 
ð ð( Dò (ó ð(ð<O°Cð O¸HÀS¹Mó Oð Øð Ø.1ð ØADð ØIQÐRWÐX[Ð]`ÐX`ÑRaÑIbó óB5ð
 /4ò 2% tó 2%ðh ñ/¨ð /¸ò /ó ð/ñ"%¨ð %¸÷ %r*   r'  r  )FFrû  )hr  rn   rI   rß   Úloggingr�   rˆ   Úshlexr    rÜ   rw  rü  r  r¯  Úpathlibr   Útypingr   rˆ  r   r   r   Útools.environments.base_outputr   Ú tools.environments.docker_egressr	   r
   r   r   r   r   r   r   r   Útools.environments.path_utilsr   Ú tools.environments.remote_commonr   r   r   r   r   r   Ú	getLoggerr/   r   r£   r   r   Ú__annotations__r"   rÒ   r)   r-   r5   rÁ  Úcompiler:   r<   r‰  rC   rN   r1   r�   rt   r3   r”   r  rÞ   r2   r)  rm   rk   r­   r¯   rÓ   rv  r  r¾   rÃ   rÊ   rÖ   rÕ   r×   r  rÍ   rý  ÚLockrþ  râ   rÔ   rØ   rä   rì   rí   rî   rú   r  r	  r  r  r"  r%  r'  r•   r*   r(   ú<module>r%     sÇ  ðòó Û Û Û Û 	Û 	Û Û Û Û 
Û Û Û Ý Ý ç cÑ cÝ 6÷÷ õ õ
 D÷k÷ kð 
ˆ×	Ñ	˜8Ó	$€òÐ ð %)Ð �H˜S‘MÓ (Ø%Ð ð¨d°3©i¸$Ñ.>ð À4ÈÁ9ó ð"˜T D™[ð ¨T°#°s°(©^ó ð( -Ð ð
  �R—Z‘ZÐ 2Ó3Ð ð@ ð @¨ó @ð .Ð ð #ó ñ@ Cð @°ó @ð "ÀÐ_cò*Øð*Ø36¸±:ð*ØRUÐX\ÑR\ð*àó*ðZ sð ¸#ó ð(=˜ð = ó =ð
 GIÐ`dØ"×1Ñ1°7Ð;òØ
ˆs‰)ðØ!&ðØ.1ðØ>CðØSVÐY]ÑS]ðàóð$�X˜c‘]ó ð,V Cð V¨Có Vð2¨#ð 2°#ó 2ò6Ð ð Ð ð Ð ð%¨ð %°$ó %ð (€ð¨ð °(¸3±-ó ð" @Ð Ø;€ò
 DÐ ñ ,/«5Ð �3�y×'Ñ'Ñ(Ó 0Ø�—‘Ó!€àJÐ ð ,Ð-@ÐAÐ ñI¨4ð I¸4ð IÐVZð IÐgkÐloÑgpó Ið>¨Cð >¸ð >Àó >ð.
 ¨#¡ó 
ð #'€�˜$‘Ó &Ø$(Ð �8˜D‘>Ó (ð* Cð *¨Dó *ðZ Z_ò > ð >¸ð >À3ð >ÐRVó >ó
"GðJA $ s¡)ó Að8Ð ð D¨¡Ió ð4 dð ¨t°C©yó ôb	%˜õ b	%r*   