Ë
    ãß²j;7  ã                  óò   — d Z ddlmZ ddlZddlZddlZ ej                  d«      ZdZdZ	dZ
dd	hZ eh d
£«      Zdd„Z	 	 	 	 	 	 	 	 dd„Zddd„Zdd„Z ed«      Zdd„Zdd„Zdd„Zdd„Zd d„Zd!d„Zd"d„Zy)#a  Egress-proxy (iron-proxy) plumbing for the Docker backend.

Builds the mount/env/host args that route a sandbox through the host-side
credential firewall, and guards the three config surfaces (docker_forward_env,
docker_env, docker_extra_args) that could otherwise weaken or bypass it.
é    )ÚannotationsNztools.environments.dockerzhermes-egressz#/etc/ssl/certs/hermes-egress-ca.crtÚ"_HERMES_EGRESS_NODE_OPTIONS_APPENDú--use-openssl-caz--use-bundled-ca>
   ÚNO_PROXYÚno_proxyÚ
HTTP_PROXYÚ
http_proxyÚHTTPS_PROXYÚhttps_proxyÚSSL_CERT_FILEÚCURL_CA_BUNDLEÚREQUESTS_CA_BUNDLEÚNODE_EXTRA_CA_CERTSc                 ó  ‡— 	 ddl m}  ddlm}  | «       j                  d«      xs i }|j                  d«      sg i g fS |j                  «       }t        |j                  dd	«      «      Šd)ˆfd
„}|j                  s |d«      S |j                  r|j                  s |d|j                  › d�«      S |j                  �|j                  j                  «       s |d|j                  › d�«      S |j!                  «       }|s |d«      S d|j                  › dt"        › d�g}d|j                  › �}d|j                  dz   › �}	d|d|d|	d|	dddddt"        dt"        dt"        d t"        d!d"t$        d#i}
|D ]\  }|j&                  |
|j(                  <   |j&                  |
d$|j(                  › �<   t+        |d%d&«      xs d&D ]  }|j&                  |
|<   Œ Œ^ d'd(g}||
|fS # t        $ r%}t
        j                  d|«       g i g fcY d}~S d}~ww xY w)*u¤  ``(volume_args, env_overrides, host_args)`` for routing through iron-proxy; all empty
    when the proxy is disabled/unconfigured/not running. Under ``proxy.enforce_on_docker``
    (default) any half-configured state raises so the sandbox refuses to start unprotected;
    otherwise it warns and continues. Only ImportError is swallowed â€” a broken config must
    fail visibly rather than silently disable enforcement.r   ©Úload_config©Ú
iron_proxyz%Egress proxy plumbing unavailable: %sNÚproxyÚenabledÚenforce_on_dockerTc                óT   •— ‰rt        | «      ‚t        j                  d| «       g i g fS )Nu:   %s â€” continuing without proxy (enforce_on_docker=false).©ÚRuntimeErrorÚloggerÚwarning)ÚmsgÚenforces    €úE/home/ubuntu/.hermes/hermes-agent/tools/environments/docker_egress.pyÚ	_degradedz0_egress_proxy_args_for_docker.<locals>._degraded1   s-   ø€ ÙÜ˜sÓ#Ð#Ü�‰ÐSÐUXÔYØ�B˜ˆ|Ðó    zvproxy.enabled is true but iron-proxy is not configured. Run `hermes egress setup` to mint tokens and write proxy.yaml.z.iron-proxy is enabled but not running on port z&. Start it with `hermes egress start`.z!iron-proxy CA cert vanished from z0. Re-run `hermes egress setup` to regenerate it.z�iron-proxy is configured but mappings.json is empty or corrupt.  Re-run `hermes egress setup` to mint provider tokens before starting a sandbox.z-vú:z:rozhttp://host.docker.internal:é   r
   r   r   r	   r   z127.0.0.1,localhost,::1r   r   r   r   r   ÚHERMES_EGRESS_PROXYÚ1r   ÚHERMES_PROXY_TOKEN_Úalias_env_names© z
--add-hostz!host.docker.internal:host-gateway)r   Ústr)Úhermes_cli.configr   Úagent.proxy_sourcesr   ÚImportErrorr   ÚdebugÚgetÚ
get_statusÚboolÚ
configuredÚpidÚ	listeningÚtunnel_portÚca_cert_pathÚexistsÚload_mappingsÚ_CONTAINER_CAÚ_NODE_OPTIONS_SENTINELÚproxy_tokenÚreal_env_nameÚgetattr)r   ÚipÚexcÚ	proxy_cfgÚstatusr    ÚmappingsÚvolume_argsÚ	proxy_urlÚplain_http_urlÚenv_overridesÚmÚaliasÚ	host_argsr   s                 @r   Ú_egress_proxy_args_for_dockerrI      sq  ø€ ðÝ1Ý8ñ
 “×!Ñ! 'Ó*Ò0¨b€IØ�=‰=˜Ô#Ø�B˜ˆ|Ðà�]‰]‹_€FÜ�9—=‘=Ð!4°dÓ;Ó<€Gõð ×ÒÙðMóNð 	Nð �JŠJ˜6×+Ò+ÙØ<¸V×=OÑ=OÐ<Pð Q3ð 3ó4ð 	4ð ×ÑÐ"¨&×*=Ñ*=×*DÑ*DÔ*Fñ Ø/°×0CÑ0CÐ/Dð E=ð =ó>ð 	>ð
 ×ÑÓ!€HÙÙð0ó1ð 	1ð
 ˜F×/Ñ/Ð0°´-°ÀÐDÐE€Kð /¨v×/AÑ/AÐ.BÐC€IØ3°F×4FÑ4FÈÑ4JÐ3KÐL€Nð 	�yØ�yØ�nØ�nàÐ-ØÐ-ð
 	œmØœØœ-Øœ}Ø˜sÜÐ 2ð%%4€Mð, ò 1ˆØ)*¯©ˆ�a—o‘oÑ&ØABÇÁˆÐ+¨A¯O©OÐ+<Ð=Ñ>Ü˜QÐ 1°2Ó6Ò<¸"ò 	1ˆEØ#$§=¡=ˆM˜%Ò ñ	1ð1ð ÐBÐC€IØ˜¨	Ð2Ð2øôW ò Ü�‰Ð<¸cÔBØ�B˜ˆ|Õûðús   ƒG Ç	HÇ"HÇ<HÈHc                ó²   — | s|s|syt        j                  | ||dœdd¬«      }t        j                  |j	                  d«      «      j                  «       dd S )	z@Stable Docker-label value for the egress posture of a container.Úoff)rB   rE   rH   T)ú,r"   )Ú	sort_keysÚ
separatorszutf-8Né   )ÚjsonÚdumpsÚhashlibÚsha256ÚencodeÚ	hexdigest)rB   rE   rH   Úpayloads       r   Ú_egress_reuse_fingerprintrW   t   sV   € ñ ™=©IØÜ�j‰jØ#°mÐR[Ñ\Ø :ô/€Gô �>‰>˜'Ÿ.™.¨Ó1Ó2×<Ñ<Ó>¸sÀÐCÐCr!   c                óö   — 	 ddl m} t         |«       j                  d«      xs i j                  d| «      «      S # t        t
        f$ r | cY S t        $ r"}t        j                  d|«       | cY d}~S d}~ww xY w)zIRead proxy.enforce_on_docker; any config failure fails safe to *default*.r   r   r   r   z:Could not read proxy config for egress collision check: %sN)	r*   r   r0   r.   r,   ÚOSErrorÚ	Exceptionr   r   )Údefaultr   r>   s      r   Ú_egress_enforce_on_dockerr\      sm   € ðÝ1Ü‘[“]×&Ñ& wÓ/Ò5°2×:Ñ:Ð;NÐPWÓXÓYÐYøÜœÐ!ò ØŠÜò Ü�‰ÐSÐUXÔYØ�ûðús!   ‚8; »A8ÁA8ÁA3Á-A8Á3A8c                ó@   — t        t        «      dhz  t        | «      z  S )aw  Env names that would weaken or bypass enforced egress if overridden.

    Every name the egress layer writes is critical: mapped tokens land under arbitrary
    ``real_env_name``/``alias_env_names`` entries from mappings.json, so a suffix
    heuristic would silently unprotect any mapped credential not ending in
    ``_API_KEY``/``_TOKEN`` (e.g. ``AWS_SECRET_ACCESS_KEY``).ÚNODE_OPTIONS)ÚsetÚ_PROXY_CONTROL_ENV)rE   s    r   Ú_critical_egress_env_namesra   ‹   s"   € ô Ô!Ó" nÐ%5Ñ5¼¸MÓ8JÑJÐJr!   ÚditPqc                ó0  — | j                  d«      r&| j                  d«      \  }}}|dv r|dd |r|fS dfS y| j                  d«      syt        | dd «      D ]<  \  }}|t        v rŒ|dk(  r(| |dz   d }|j                  d«      r|dd }d	|xs dfc S  y y)
a	  ``("env"|"env-file", inline_value)`` when ``arg`` spells a docker env flag
    under pflag parsing, else ``None``. ``inline_value`` is the joined value
    (``--env=N=v``, ``-eN=v``) or ``None`` when the flag consumes the next arg
    (``-e``, ``--env``, ``-ite``).ú--Ú=)z--envú
--env-fileé   NÚ-r#   ÚeÚenv)Ú
startswithÚ	partitionÚ	enumerateÚ_DOCKER_RUN_BOOL_SHORTHANDS)ÚargÚflagÚsepÚinlineÚposÚchÚrests          r   Ú_env_flag_valuerv   š   sË   € ð
 ‡~�~�dÔØŸM™M¨#Ó.Ñˆˆc�6ØÐ*Ñ*Ø˜˜�8¡s˜VÐ4Ð4°Ð4Ð4ØØ�>‰>˜#ÔØô ˜S  ˜WÓ%ò ‰ˆˆRØÔ,Ñ,ØØ�Š9Ø�s˜Q‘w�x�=ˆDØ�‰˜sÔ#Ø˜A˜B�x�Ø˜$š, $Ð&Ò&Ùðð r!   c                ó2  — |D �ch c]  }|j                  «       ’Œ }}g }d}|t        | «      k  rÐ| |   }|dk(  rnÅt        |«      }|�}|\  }}	|dk(  r|j                  d«       nW|	�|	n|dz   t        | «      k  r| |dz      nd}
|
j	                  dd«      d   }|j                  «       |v r|j                  |«       ||	�dndz  }Œ£|j                  d«      d   d	v r|j                  |«       |dz  }|t        | «      k  rŒÐt        t        |«      «      S c c}w )
zCReturn docker_extra_args entries that can override egress controls.r   rd   zenv-filerf   r#   Ú re   rg   )z	--networkz--net)ÚupperÚlenrv   ÚappendÚsplitrl   Úsortedr_   )Ú
extra_argsÚcritical_namesÚnÚcritical_foldedÚ
collisionsÚiro   ÚparsedÚkindÚinline_valueÚvalueÚnames               r   Ú_extra_args_egress_collisionsr‰   µ   s9  € ð
 +9Ö9 Q�q—w‘w•yÐ9€OÐ9Ø€JØ	€AØ
Œc�*‹oÒ
Ø˜‰mˆð �$Š;ØÜ  Ó%ˆØÐØ!'ÑˆD�,Ø�zÒ!Ø×!Ñ! ,Õ/à(4Ð(@™Ø)*¨Q©´°Z³Ò)@�J˜q 1™uÒ%Àbð à—{‘{ 3¨Ó*¨1Ñ-�Ø—:‘:“< ?Ñ2Ø×%Ñ% dÔ+Ø�lÐ.‘°AÑ5ˆAØØ�=‰=˜Ó˜aÑ Ð$:Ñ:Ø×Ñ˜cÔ"Ø	ˆQ‰ˆð- Œc�*‹oÓ
ô. ”#�j“/Ó"Ð"ùò5 :s   …Dc               ón   — | › d|rdnd› d�} |rt        | › d|› �«      ‚t        j                  d| |«       y)zJFail loud under enforcement, otherwise warn and let the user's config win.z; enforce_on_docker is r   Údisabledú.z  z%s  %sNr   )r   r   ÚremedyÚconsequences       r   Ú_collision_guardr�   ×   sC   € àˆEÐ(±g©À:Ð(NÈaÐ
P€CÙÜ˜c˜U " V HÐ-Ó.Ð.Ü
‡N�N�8˜S +Õ.r!   c                óž   ‡— |D �ch c]  }|j                  «       ’Œ c}Št        ˆfd„| D «       «      }|rt        d|› �|dd¬«       y y c c}w )Nc              3  óH   •K  — | ]  }|j                  «       ‰v sŒ|–— Œ y ­w©N)ry   )Ú.0Úkr�   s     €r   ú	<genexpr>z/check_forward_env_collisions.<locals>.<genexpr>ä   s   øè ø€ ÒO˜a°!·'±'³)¸Ò2NœÑOùs   ƒ"›"z@docker_forward_env would inject real egress-protected variables zgRemove these names from docker_forward_env or disable enforce_on_docker to opt out of egress isolation.z?Explicit docker_forward_env values will override egress tokens.©r   r�   rŽ   )ry   r}   r�   )Úforward_envÚcriticalr   r”   r‚   r�   s        @r   Úcheck_forward_env_collisionsr™   ß   sV   ø€ ð +3Ö3 Q�q—w‘w•yÒ3€OÜÓO ;ÔOÓO€JÙÜØNÈzÈlÐ[Øð5àYö	[ð ùò 4s   †A
c                ó  ‡ ‡‡‡— t        «       Š	 ddlm} |j                  «       D �ch c]  }|j                  ’Œ c}Šd
ˆˆˆ fd„Št        ˆfd„t        ‰z  D «       «      }|rt        d|› �|dd¬«       y	y	c c}w # t
        $ r Y ŒIw xY w)z´Reject docker_env overrides of proxy-control vars or real provider keys (read from the
    live token mappings; for those ANY override collides since a real key bypasses the swap).r   r   c                óZ   •— | ‰vry| ‰v r| ‰vxs ‰|    ‰|    k7  S | ‰v xr ‰|    ‰|    k7  S )NFr(   )r”   Ú
egress_envÚprovider_keysÚuser_envs    €€€r   Ú	_collidesz.check_docker_env_collisions.<locals>._collidesø   sO   ø€ Ø�HÑØØ�ÑØ˜JÐ&ÒF¨(°1©+¸ÀA¹Ñ*FÐFØ�JˆÒ? 8¨A¡;°*¸Q±-Ñ#?Ð?r!   c              3  ó4   •K  — | ]  } ‰|«      sŒ|–— Œ y ­wr’   r(   )r“   r”   rŸ   s     €r   r•   z.check_docker_env_collisions.<locals>.<genexpr>ÿ   s   øè ø€ ÒX˜aÉ9ÐUVÍ<œÑXùs   ƒ‘z;docker_env in config.yaml overrides egress-proxy variables z^Remove these keys from docker_env or disable enforce_on_docker to opt out of egress isolation.zTFalling back to docker_env values; sandbox traffic will NOT route through the proxy.r–   N)r”   r)   Úreturnr0   )	r_   r+   r   r7   r;   rZ   r}   r`   r�   )rž   rœ   r   r=   rF   r‚   rŸ   r�   s   ``    @@r   Úcheck_docker_env_collisionsr¢   î   sŽ   û€ ô "›e€MðÝ8Ø24×2BÑ2BÓ2DÖE¨Q˜Ÿ›ÒEˆ÷@ô ÓXÔ$6¸Ñ$FÔXÓX€JÙÜØIÈ*ÈÐVØð*ð-ö	.ð ùò FøÜò Ùðús!   �A< ¨A7»A< Á7A< Á<	BÂBc                óF   — t        | |«      }|rt        d|› �|dd¬«       y y )Nz7docker_extra_args would override egress-proxy controls zNRemove these args or disable enforce_on_docker to opt out of egress isolation.z.Extra Docker args may bypass egress isolation.r–   )r‰   r�   )r~   r˜   r   r‚   s       r   Úcheck_extra_args_collisionsr¤   
  s2   € Ü.¨z¸8ÓD€JÙÜØEÀjÀ\ÐRØØcØHö		Jð r!   c                ó  — |r|ri | ¥|¥ni |¥| ¥}|j                  t        d«      }|rÚ|j                  «       }|j                  dd«      j	                  «       }|t
        v rT|D �cg c]  }|t
        v sŒ||k7  sŒ|‘Œ }}|rt        j                  d||«       |D �cg c]  }|t
        vs||k(  sŒ|‘Œ }}||vr|j                  |«       dj                  |«      j                  «       |d<   |d   s|j                  dd«       |S c c}w c c}w )a  Merge docker_env with egress overrides (egress wins under enforcement, docker_env
    otherwise) and resolve the NODE_OPTIONS sentinel: the flag is APPENDED to the operator's
    NODE_OPTIONS after stripping conflicting CA-mode flags so it wins deterministically.Nr^   rx   zOverriding conflicting NODE_OPTIONS CA-mode flag(s) %s with egress-required %s to keep Node routed through the egress CA store.Ú )
Úpopr9   Ústripr.   r|   Ú_CA_MODE_FLAGSr   r   r{   Újoin)	rž   rœ   r   ÚmergedÚ
raw_appendÚappend_tokenÚtokensÚtÚdroppeds	            r   Úmerge_egress_envr±     s  € ñ ,3±zÐ'�Ð'˜JÑ'ÐGaÈ*ÐGaÐX`ÐGa€Fà—‘Ô2°DÓ9€JÙØ!×'Ñ'Ó)ˆØ—‘˜N¨BÓ/×5Ñ5Ó7ˆØœ>Ñ)Ø"(ÖV˜Q¨A´Ò,?ÀAÈÓDU’qÐVˆGÐVÙÜ—‘ð'à(/°ô?ð "(ÖX˜A¨1´NÑ+BÀaÈ<ÓFW’aÐXˆFÐXØ˜vÑ%Ø�M‰M˜,Ô'Ø!$§¡¨&Ó!1×!7Ñ!7Ó!9ˆˆ~ÑØ�nÒ%Ø�J‰J�~ tÔ,Ø€Mùò Wùò Ys   Á%DÁ3DÁ9DÂD
Â/D
)r¡   z+tuple[list[str], dict[str, str], list[str]])rB   ú	list[str]rE   údict[str, str]rH   r²   r¡   r)   )T)r[   r0   r¡   r0   )rE   r³   r¡   úset[str])ro   r)   r¡   ztuple[str, str | None] | None)r~   r²   r   r´   r¡   r²   )
r   r)   r   r0   r�   r)   rŽ   r)   r¡   ÚNone)r—   r²   r˜   r´   r   r0   r¡   rµ   )rž   r³   rœ   r³   r   r0   r¡   rµ   )r~   r²   r˜   r´   r   r0   r¡   rµ   )rž   r³   rœ   r³   r   r0   r¡   r³   )Ú__doc__Ú
__future__r   rR   rP   ÚloggingÚ	getLoggerr   Ú_EGRESS_LABEL_KEYr8   r9   r©   Ú	frozensetr`   rI   rW   r\   ra   rn   rv   r‰   r�   r™   r¢   r¤   r±   r(   r!   r   ú<module>r¼      sÈ   ðñõ #ã Û Û à	ˆ×	Ñ	Ð6Ó	7€à#Ð Ø5€Ø=Ð Ø$Ð&8Ð9€ñ ò  ó Ð óT3ðnDØðDØ+9ðDØFOðDØTWóDô	óKñ (¨Ó0Ð óó6#óD/ó[ó.ó8Jôr!   