
    KiO                        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
mZ ddl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eef         fdZd
ee         fdZg 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)is_interrupted)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        6/home/ubuntu/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$;;#    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                  (   t           t           S t          j        d          } | r| a | S t          D ]a}t          j                            |          r@t	          j        |t          j                  r!|a t          
                    d|           |c S bdS )a5  Locate the docker CLI binary.

    Checks ``shutil.which`` first (respects PATH), then probes well-known
    install locations on macOS where Docker Desktop may not be in PATH
    (e.g. when running as a gateway service via launchd).

    Returns the absolute path, or ``None`` if docker cannot be found.
    Ndockerz%Found docker at non-PATH location: %s)r   shutilwhich_DOCKER_SEARCH_PATHSospathisfileaccessX_OKr   info)foundr'   s     r   find_dockerr-   I   s     %!!L""E "$  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=512mr4   z#/var/tmp:rw,noexec,nosuid,size=256mr4   z/run:rw,noexec,nosuid,size=64m_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_availablerH   {   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edef fdZ	e
defd            Zd dddded
ededz  dedz  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cwdr<   cpumemorydiskpersistent_filesystemtask_idvolumesr   networkhost_cwdauto_mount_cwdc                    |dk    rd}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<t.          j                            t.          j                            |                    nd}|o0t7          |          o!t.          j                            |          o| }|r>|r<t.          j                            |          st                              d|            d | _        d | _        g }| j        r |            dz  |z  }t          |dz            | _        t/          j         | j        d           |                    d| j         dg           |sS|sQt          |dz            | _        t/          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#}  |            D ]S}|                    d|d%          d|d&          d'g           t          	                    d(|d%         |d&                    T |            }|rQ|                    d|d%          d|d&          d'g           t          	                    d)|d%         |d&                    n2# tH          $ r%}t                              d*|           Y d }~nd }~ww xY wt          	                    d+|            t          tJ                    |z   |z   |z   }t          	                    d,|            tM                      pd| _'        d-tQ          j)                    j*        d d.          }| j'        d/d0d1|d2|g||d3d4}t                              d5d6+                    |                      tY          j-        |ddd7d8          }|j.                                        | _        t          	                    d9| d:| j        d d;          d<           d S )=N~rK   )rO   r<   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: :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	workspacer4   z/workspace:rw,exec,size=10g)r4   z/home:rw,exec,size=1gr4   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	host_pathcontainer_pathz:roz$Docker: mounting credential %s -> %sz$Docker: mounting skills dir %s -> %sz1Docker: could not load credential file mounts: %szDocker volume_args: zDocker run_args: zhermes-   rA   z-dz--name-wsleep2hzStarting container:  x   )r:   r;   r<   checkzStarted container z (   ))/super__init___base_image_persistent_task_idr   _forward_env_container_idr   r+   r   listr   rH   extendr   sysplatform_storage_opt_supportedr   tools.environments.baser^   r   r&   r'   abspath
expanduserboolisdirdebug_workspace_dir	_home_dirmakedirstools.credential_filesrd   re   r   _SECURITY_ARGSr-   _docker_exeuuiduuid4hexjoinr@   rA   stdout)!selfrN   rO   r<   rP   rQ   rR   rS   rT   rU   r   rV   rW   rX   resource_argsr^   volume_argsworkspace_explicitly_mountedvolhost_cwd_absbind_host_cwdwritable_argssandboxrd   re   mount_entryskills_mounteall_run_argscontainer_namerun_cmdrG   	__class__s!                                   r   rr   zDockerEnvironment.__init__   s     #::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eeeeeeee99;; 	 	""";/TT+>N2OTTT$    :, 01    6577L 	""#K0VV<@P3QVVV$    : - !12  
  	Q 	Q 	QLLLaPPPPPPPP	Q 	8;88999N++m;mKkY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VVs   CS 
T#TT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"   r+   z--formatz{{.Driver}}T
   r9   overlay2Fcreater]   zsize=1mzhello-world   r   rmr8   )r:   r<   z Docker --storage-opt support: %s)r5   r-   r@   rA   r   r   lowerrB   r   r   r   )r"   rG   driverprobecontainer_ids        r   r|   z(DockerEnvironment._storage_opt_supportedx  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#r`   )r<   
stdin_datacommandr   c                |   |                      |          \  }}|p| j        }|p| j        }||||z   }	n||}	n|}	|dk    s|                    d          r
d| d| }d}| j        s
J d            | j        dg}
|	|
                    d           |
                    d	|g           t          | j	                  }	 d
dl
m} | |            z  }n# t          $ r Y nw xY w|rt                      ni }t          |          D ]K}t          j        |          }||                    |          }||
                    d| d| g           L|
                    | j        dd|g           	 g t%          j        |
t$          j        t$          j        |	rt$          j        nt$          j        d          |	rE	 j                            |	           j                                         n# t          $ r Y nw xY wfd}t5          j        |d          }|                                 t;          j                    |z   }                                tA                      r!                                 	 "                    d           n)# t$          j#        $ r $                                 Y nw xY w|%                    d           d%                              dz   ddS t;          j                    |k    r?$                                 |%                    d           | &                    |          S t;          j'        d                                           |%                    d           d%                              j(        dS # t          $ r}d| ddcY d }~S d }~ww xY w)NrZ   z~/zcd z && /zContainer not startedexecz-iri   r   )get_all_passthroughz-e=bashz-lcT)r   rC   stdinr;   c                  j    	 j         D ]}                     |            d S # t          $ r Y d S w xY w)N)r   r   r   )line_output_chunksprocs    r   _drainz)DockerEnvironment.execute.<locals>._drain  s\     $ 4 4&--d33334 4    DDs   $ 
22)targetdaemon   )r<      r`   z
[Command interrupted]   )outputrB   g?r8   zDocker execution error: ))_prepare_commandrO   r<   
startswithrw   r   r   ry   r
   rv   tools.env_passthroughr   r   r    sortedr&   getenvgetr@   PopenPIPESTDOUTDEVNULLr   writeclose	threadingThreadstarttime	monotonicpollr   	terminatewaitrE   killr   _timeout_resultrj   rB   )r   r   rO   r<   r   exec_command
sudo_stdinwork_direffective_timeouteffective_stdincmdforward_keysr   
hermes_envr   valuer   readerdeadliner   r   r   s                       @@r   executezDockerEnvironment.execute  sm    $(#8#8#A#A j?$(#3t| !j&<(:5OO#(OO(O s??h11$77?===|==LH!::#:::!(&JJt

D(#$$$ 4,--	AAAAAA//111LL 	 	 	D	0<D*,,,"
,'' 	5 	5CIcNNE}"s++ 

DS"2"25"2"23444

D&|DEEE/	ON#!z/@)8Pjooj>P	  D  J$$_555J$$&&&&    D      %VDAAAFLLNNN~''*;;H))++%!## 
NN$$$$		!	,,,,%4 $ $ $		$KKK***"$''."9"9<U"U&)   >##h..IIKKKKKK***//0ABBB
3! ))++%$ KKK""" ggn55T_UUU 	O 	O 	O<<<ANNNNNNNN	Os    C 
C! C!0A	N :3G. -N .
G;8N :G;;B N <J N #J96N 8J993N -AN AN 
N;)N60N;6N;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)rw   r   r@   r   r   r   r   rt   r   r   r#   rmtree)r   stop_cmdr   ds       r   cleanupzDockerEnvironment.cleanup  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)rK   rL   r   r   r   FrM   NNTNF)r`   )__name__
__module____qualname____doc__r   intfloatr   rx   rr   staticmethodr|   dictr   r   __classcell__)r   s   @r   rJ   rJ      s       	 	 &+ (,$mW mWmW mW 	mW
 mW mW mW  $mW mW mW #Y%mW mW mW mW mW mW mW mW mW^ %D % % % \%NZO&*)-ZO ZO ZOs ZO ZOtZO$JZO26ZO ZO ZO ZOx9 9 9 9 9 9 9r   rJ   )r   N)#r   loggingr&   rer#   r@   rz   r   r   r   typingr   r}   r   tools.interruptr   	getLoggerr   r   r%   r   r   __annotations__compiler   rx   r   r   r    r-   r   r5   r   rH   rJ    r   r   <module>r      s      				 				      



             3 3 3 3 3 3 * * * * * *		8	$	$    %) HSM ( ( (2:9:: d3i$.> 49    2tCH~    Xc]    D
 
 
 #'$ & & &? ? ? ?DZ9 Z9 Z9 Z9 Z9 Z9 Z9 Z9 Z9 Z9r   