
    ib                        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m	Z	 ddl
mZmZ ddlmZ  ej        e          Zg dZdae	e         ed<    ej        d          Zd	ee         dz  d
ee         fdZdedz  d
eeef         fdZd
eeef         fdZd
e	e         fdZg dZg dZde d
ee         fdZ!d
e	e         fdZ"da#e	e          ed<   ddZ$ G d de          Z%dS )zDocker 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)Optional)BaseEnvironment_popen_bash)_HERMES_PROVIDER_ENV_BLOCKLIST)z/usr/local/bin/dockerz/opt/homebrew/bin/dockerz6/Applications/Docker.app/Contents/Resources/bin/docker_docker_executablez^[A-Za-z_][A-Za-z0-9_]*$forward_envreturnc                    g }t                      }| pg D ]}t          |t                    st                              d|           3|                                }|sJt                              |          st                              d|           ||v r|                    |           |	                    |           |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)
set
isinstancestrloggerwarningstrip_ENV_VAR_NAME_REmatchaddappend)r   
normalizedseenitemkeys        >/home/ubuntu/.hermes/hermes-agent/tools/environments/docker.py_normalize_forward_env_namesr   $   s    JUUD!r  $$$ 	NNMtTTTjjll 	%%c** 	NNJDQQQ$;;#    envc                 ^   | si S t          | t                    st                              d|            i S i }|                                 D ]\  }}t          |t
                    r,t                              |                                          st                              d|           b|                                }t          |t
                    sOt          |t          t          t          f          rt          |          }nt                              d||           |||<   |S )zValidate and normalize a docker_env dict to {str: str}.

    Filters out entries with invalid variable names or non-string values.
    zdocker_env is not a dict: %rz#Ignoring invalid docker_env key: %rz/Ignoring non-string docker_env value for %r: %r)r   dictr   r   itemsr   r   r   r   intfloatbool)r   r   r   values       r   _normalize_env_dictr$   =   s   
  	c4   5s;;;	!#Jiikk    
U#s## 	+;+A+A#))+++N+N 	NN@#FFFiikk%%% 	 %#ud!344 E

PRUW\]]]
3r   c                  L    	 ddl m}   |             pi S # t          $ r i cY S w xY w)zDLoad ~/.hermes/.env values without failing Docker command execution.r   load_env)hermes_cli.configr'   	Exceptionr&   s    r   _load_hermes_env_varsr*   [   sN    ......xzzR   			s    ##c                  x   t           t           S t          j        d          } | r]t          j                            |           r>t          j        | t          j                  r| a t                              d|            | S t          j
        d          }|r|a |S t          j
        d          }|r|a t                              d|           |S t          D ]a}t          j                            |          r@t          j        |t          j                  r!|a t                              d|           |c S bdS )u  Locate the docker (or podman) CLI binary.

    Resolution order:
    1. ``HERMES_DOCKER_BINARY`` env var — explicit override (e.g. ``/usr/bin/podman``)
    2. ``docker`` on PATH via ``shutil.which``
    3. ``podman`` on PATH via ``shutil.which``
    4. Well-known macOS Docker Desktop install locations

    Returns the absolute path, or ``None`` if neither runtime can be found.
    NHERMES_DOCKER_BINARYz'Using HERMES_DOCKER_BINARY override: %sdockerpodmanz%Using podman as container runtime: %sz%Found docker at non-PATH location: %s)r   osgetenvpathisfileaccessX_OKr   infoshutilwhich_DOCKER_SEARCH_PATHS)overridefoundr1   s      r   find_dockerr;   e   s7    %!! y/00H BGNN8,, 8RW1M1M %=xHHH L""E " L""E ";UCCC %  7>>$ 	BIdBG$<$< 	!%KK?FFFKKK4r   )z
--cap-dropALL	--cap-addDAC_OVERRIDEr=   CHOWNr=   FOWNERz--security-optzno-new-privilegesz--pids-limit256--tmpfsz/tmp:rw,nosuid,size=512mrB   z#/var/tmp:rw,noexec,nosuid,size=256mrB   z/run:rw,noexec,nosuid,size=64m)r=   SETUIDr=   SETGIDrun_as_host_userc                     | rt          t                    S t          t                    t          t                    z   S )zBReturn the security/cap/tmpfs args tailored to the privilege mode.)list_BASE_SECURITY_ARGS_GOSU_CAP_ARGS)rE   s    r   _build_security_argsrJ      s5     )'(((#$$tN';';;;r   c                      t          t          dd          } t          t          dd          }| |dS 	  |              d |             S # t          $ r Y dS w xY w)au  Return ``<uid>:<gid>`` for the current host user, or ``None`` on platforms
    where this is not meaningful (e.g. Windows without posix ids).

    We intentionally read ``os.getuid()``/``os.getgid()`` directly rather than
    going through ``getpass``/``pwd`` so this stays cheap and never raises on
    nameless UIDs (nss lookups can fail inside sandboxed launchers).
    getuidNgetgid:)getattrr/   r)   )get_uidget_gids     r   _resolve_host_user_specrR      s{     b(D))Gb(D))G'/t'))))ggii)))   tts   A 
AA_storage_opt_okc                     t                      } | s)t                              d           t          d          	 t	          j        | dgddd          }|j        dk    rHt                              d| |j        |j                                                   t          d	          dS # t          $ r- t                              d
| d           t          d          t          j
        $ r- t                              d| d           t          d          t          $ r t                              dd            w xY w)zBest-effort check that the docker CLI is available before use.

    Reuses ``find_docker()`` so this preflight stays consistent with the rest of
    the Docker backend, including known non-PATH Docker Desktop locations.
    zDocker 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.versionT   capture_outputtexttimeoutr   zIDocker backend selected but '%s version' failed (exit code %d, stderr=%s)zXDocker command is available but 'docker version' failed. Check your Docker installation.zVDocker backend selected but the resolved docker executable '%s' could not be executed.)exc_infozHDocker executable could not be executed. Check your Docker installation.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.z4Unexpected error while checking Docker availability.N)r;   r   errorRuntimeError
subprocessrun
returncodestderrr   FileNotFoundErrorTimeoutExpiredr)   )
docker_exeresults     r   _ensure_docker_availablerf      s    J 	
 	
 	
 	

 K
 
 	

-#	
 
 
B !!LL,!##%%   2   "!7  	
 	
 	
	 	 	
 	
 	
 V
 
 	
 $ 	
 	
 	
4	 	 	
 	
 	
 V
 
 	
    B 	 	
 	
 	
 	s   B* *BEc                       e Zd ZdZ	 	 	 	 	 	 	 	 	 	 	 	 	 	 d#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dedef fdZ
dee         fdZdddddededededz  dej        f
d Zedefd!            Zd" Z xZS )$DockerEnvironmentu  Hardened Docker container execution with resource limits and persistence.

    Security: all capabilities dropped, no privilege escalation, PID limits,
    size-limited tmpfs for scratch dirs. The container itself is the security
    boundary — the filesystem inside is writable so agents can install packages
    (pip, npm, apt) as needed. Writable workspace via tmpfs or bind mounts.

    Persistence: when enabled, bind mounts preserve /workspace and /root
    across container restarts.
    /root<   r   FdefaultNTimagecwdrZ   cpumemorydiskpersistent_filesystemtask_idvolumesr   r   networkhost_cwdauto_mount_cwdrE   c                    |dk    rd}t                                          ||           || _        || _        t	          |
          | _        t          |          | _        d | _        t          
                    d|	            |	4t          |	t                    st                              d|	           g }	t                       g }|dk    r$|                    dt!          |          g           |dk    r|                    d| d	g           |dk    rZt"          j        d
k    rJ|                                 r|                    dd| d	g           nt                              d           |s|                    d           ddlm} g }d}|	pg D ]}t          |t                     st                              d|           5|                                }|sLd|v r|                    d|g           d|v rd}nt                              d| d           |r<t0          j                            t0          j                            |                    nd}|o0t9          |          o!t0          j                            |          o| }|r>|r<t0          j                            |          st                              d|            d | _        d | _         g }| j        r |            dz  |z  }t!          |dz            | _         t1          j!        | j         d           |                    d| j          dg           |sS|sQt!          |dz            | _        t1          j!        | j        d           |                    d| j         dg           n2|s|s|                    dd g           |                    g d!           |r't          
                    d"|            d| dg|}n|rt                              d#           	 dd$l"m#}m$}m%}  |            D ]S}|                    d|d%          d|d&          d'g           t          
                    d(|d%         |d&                    T |            D ]S}|                    d|d%          d|d&          d'g           t          
                    d)|d%         |d&                    T |            D ]S}|                    d|d%          d|d&          d'g           t          
                    d*|d%         |d&                    Tn2# tL          $ r%}t                              d+|           Y d }~nd }~ww xY wg } tO          | j                  D ])}!|                     d,|! d-| j        |!          g           *g }"|rJtQ                      }#|# d.|#g}"t          
                    d/|#           nt                              d0           tS          |ot9          |"                    }$t          
                    d1|            |$|"z   |z   |z   |z   | z   }%t          
                    d2|%            tU                      pd| _+        d3tY          j-                    j.        d d4          }&| j+        d5d6d7d8|&d9|g|%|d:d;}'t                              d<d=/                    |'                      ta          j1        |'ddd>d?          }(|(j2                                        | _        t          
                    d@|& dA| j        d dB          dC           | 3                                | _4        | 5                                 d S )DN~ri   )rm   rZ   zDockerEnvironment volumes: z%docker_volumes config is not a list: r   z--cpusz--memorymdarwin--storage-optzsize=zDocker storage driver does not support per-container disk limits (requires overlay2 on XFS with pquota). Container will run without disk quota.z--network=none)get_sandbox_dirFz%Docker volume entry is not a string: rN   z-vz:/workspaceTzDocker volume 'z' missing colon, skipping z>Skipping docker cwd mount: host_cwd is not a valid directory: r-   home)exist_okz:/root	workspacerB   z/workspace:rw,exec,size=10g)rB   z/home:rw,exec,size=1grB   z/root:rw,exec,size=1gz,Mounting configured host cwd to /workspace: zDSkipping docker cwd mount: /workspace already mounted by user config)get_credential_file_mountsget_skills_directory_mountget_cache_directory_mounts	host_pathcontainer_pathz:roz$Docker: mounting credential %s -> %sz$Docker: mounting skills dir %s -> %sz#Docker: mounting cache dir %s -> %sz1Docker: could not load credential file mounts: %s-e=z--userz)Docker: running container as host user %szdocker_run_as_host_user is enabled but this platform does not expose POSIX uid/gid; container will start as its image default user.zDocker volume_args: zDocker run_args: zhermes-   r_   z-dz--initz--namez-wsleepinfinityzStarting container:  x   )rX   rY   rZ   checkzStarted container z (   ))6super__init___persistent_task_idr   _forward_envr$   _env_container_idr   r5   r   rG   r   rf   extendr   sysplatform_storage_opt_supportedr   tools.environments.baser|   r   r/   r1   abspath
expanduserr"   isdirdebug_workspace_dir	_home_dirmakedirstools.credential_filesr   r   r   r)   sortedrR   rJ   r;   _docker_exeuuiduuid4hexjoinr^   r_   stdout_build_init_env_args_init_env_argsinit_session)*selfrl   rm   rZ   rn   ro   rp   rq   rr   rs   r   r   rt   ru   rv   rE   resource_argsr|   volume_argsworkspace_explicitly_mountedvolhost_cwd_absbind_host_cwdwritable_argssandboxr   r   r   mount_entryskills_mountcache_mounteenv_argsr   	user_args	user_specsecurity_argsall_run_argscontainer_namerun_cmdre   	__class__s*                                            r   r   zDockerEnvironment.__init__  ss	   $ #::CS'22208EE',,	,0;';;<<<z'4'@'@NNN7NNOOOG 	!""" 77  (CHH!5666A::  *lll!;<<<!8800**,, $$ot%GHHHHe    	3  !1222
 	<;;;;; ',$Mr 	Q 	QCc3'' NsNNOOO))++C czz""D#;/// C''370OOOOPPPPHPXrwrw'9'9('C'CDDDVX 1\""1l++1 10	 	  	fh 	frw}}\/J/J 	fLLdZbddeee-1(, 	%o''(2W<G 6!122DNK6666  ///"    ! )E &)'K*?&@&@#D/$????$$T0===&    ! )E $$<&       " " "   
  	aKKU|UUVVVL!=!=!=LLKK) 	aLL_```.	Q           :9;; 	 	""";/TT+>N2OTTT$    :, 01    !; : < < 	 	""#K0VV<@P3QVVV$    : - !12     :9;; 	 	""";/TT+>N2OTTT$    9, 01   	  	Q 	Q 	QLLLaPPPPPPPP	Q
 $)$$ 	? 	?COOTc#<#<DIcN#<#<=>>>>  "	 
	/11I$%y1	GSSSS*   --=-Q$y//RR8;88999  	
  	 	666777 '==4H :4:<<#3BQB#799eTn#	

 
 
 
  
 	?CHHW,=,=??@@@
 
 
 $]0022UUU4;Mcrc;RUUUVVV
 #7799 	s   "D$U 
U6U11U6r	   c                    t          | j                  }t          | j                  }t                      }	 ddlm} t           |                      }n# t          $ r Y nw xY w||t          z
  z  }|rt                      ni }t          |          D ]4}t          j        |          }||                    |          }||||<   5g }	t          |          D ]$}|	                    d| d||          g           %|	S )zBuild -e KEY=VALUE args for injecting host env vars into init_session.

        These are used once during init_session() so that export -p captures
        them into the snapshot.  Subsequent execute() calls don't need -e flags.
        r   )get_all_passthroughNr   r   )r   r   r   r   tools.env_passthroughr   r)   r   r*   r   r/   r0   getr   )
r   exec_envexplicit_forward_keyspassthrough_keysr   forward_keys
hermes_envr   r#   argss
             r   r   z&DockerEnvironment._build_init_env_args  s>    $(	?? #D$5 6 6%(UU	AAAAAA"#6#6#8#899 	 	 	D	
 -0@Ca0ab0<D*,,,"
,'' 	& 	&CIcNNE}"s++  %(## 	: 	:CKK#777789999s   A 
A#"A#r   )loginrZ   
stdin_data
cmd_stringr   r   c                Z   | j         s
J d            | j        dg}||                    d           |r|                    | j                   |                    | j         g           |r|                    ddd|g           n|                    dd|g           t          ||          S )z1Spawn a bash process inside the Docker container.zContainer not startedexecNz-ibashz-lz-c)r   r   r   r   r   r   )r   r   r   rZ   r   cmds         r   	_run_bashzDockerEnvironment._run_bash+  s     !::#:::!(!JJt  	,JJt*+++

D&'((( 	3JJdJ78888JJj12223
+++r   c                     t           t           S 	 t                      pd} t          j        | dddgddd          }|j                                                                        }|d	k    rd
a d
S t          j        | ddddgddd          }|j        dk    r8|j                                        }|rt          j        | d|gdd           da nd
a n# t          $ r d
a Y nw xY wt          
                    dt                      t           S )zCheck if Docker's storage driver supports --storage-opt size=.
        
        Only overlay2 on XFS with pquota supports per-container disk quotas.
        Ubuntu (and most distros) default to ext4, where this flag errors out.
        Nr-   r5   z--formatz{{.Driver}}T
   rW   overlay2Fcreater{   zsize=1mzhello-world   r   rmrV   )rX   rZ   z Docker --storage-opt support: %s)rS   r;   r^   r_   r   r   lowerr`   r)   r   r   )r-   re   driverprobecontainer_ids        r   r   z(DockerEnvironment._storage_opt_supportedB  sR    &""	$ ]].hF^];#$  F ]((**0022F##"'u N?I}M#$  E 1$$$|1133 CNFD,#?26C C C C"&"' 	$ 	$ 	$#OOO	$7IIIs   AC 1A"C C#"C#c           	         | j         r	 d| j         d| j          d| j         d| j          d	}t          j        |d           n8# t          $ r+}t
                              d| j         |           Y d	}~nd	}~ww xY w| j        s9	 t          j        d
| j         d| j          dd           n# t          $ r Y nw xY wd	| _         | j        s)| j        | j	        fD ]}|rt          j        |d           d	S d	S )zJStop and remove the container. Bind-mount dirs persist if persistent=True.z(timeout 60 z stop z || z rm -f z) >/dev/null 2>&1 &T)shellzFailed to stop container %s: %sNzsleep 3 && z >/dev/null 2>&1 &)ignore_errors)r   r   r^   Popenr)   r   r   r   r   r   r6   rmtree)r   stop_cmdr   ds       r   cleanupzDockerEnvironment.cleanupj  s    	&YX4#3 X X4;M X X'X X040BX X X   66666 Y Y Y@$BTVWXXXXXXXXY # $ed&6eet?Qeee"     !   D!%D 	9)4>: 9 9 9M!48888	9 	99 9s)   9A 
A8!A33A8'B+ +
B87B8)ri   rj   r   r   r   Frk   NNNTNFF)__name__
__module____qualname____doc__r   r    r!   r"   rG   r   r   r   r^   r   r   staticmethodr   r   __classcell__)r   s   @r   rh   rh     s       	 	 &+ (,$!&!k kk k 	k
 k k k  $k k k #Y%k D[k k k k  !k k k k k kZd3i    @ ;@!$+/, , ,C ,4 ,,!Dj,4>4D, , , ,. %D % % % \%N9 9 9 9 9 9 9r   rh   )r	   N)&r   loggingr/   rer6   r^   r   r   typingr   r   r   r   tools.environments.localr   	getLoggerr   r   r8   r   r   __annotations__compiler   rG   r   r   r$   r*   r;   rH   rI   r"   rJ   rR   rS   rf   rh    r   r   <module>r      sS      				 				      



        @ @ @ @ @ @ @ @ C C C C C C		8	$	$    %) HSM ( ( (2:9:: d3i$.> 49    2TD[ T#s(^    <tCH~    *Xc] * * * *t
 
 
   <4 <DI < < < <#    $ #'$ & & &? ? ? ?Ds9 s9 s9 s9 s9 s9 s9 s9 s9 s9r   