§
    øžyjH&  ã                  óÔ   — d Z ddlmZ ddlZddlZddlZddlmZ ddlm	Z	  ej
        d¦  «        Zdad!d
„Zd"d„ZdZdZd#d„Zd"d„Zd!d„Zd$d„Zd%d„Zd&d„Zdddœd'd„Zddddœd(d „ZdS ))u9  Startup security posture audit (warn-on-load, never blocks).

Surfaces dangerous host / deployment posture at process start so operators
get an at-a-glance "you're exposed" signal. Motivated by the June 2026
MCP-config persistence campaign, where compromised boxes ran as root with an
exposed dashboard / API server and no firewall â€” and nothing ever told the
operator. These checks are advisory: they emit ``logger.warning`` records
and return human-readable strings; they never raise or block startup.

Checks (each is independent and fail-safe â€” any internal error is swallowed
and simply yields no finding):

1. Running as root (POSIX uid 0).
2. SSH daemon present with password authentication enabled.
3. Running inside a container with no persistent volume mount over the
   HERMES_HOME data dir (state is ephemeral â€” lost on container restart).
4. A network-accessible gateway listener (dashboard / API server) with no
   authentication configured.

Cross-platform: the root and SSH checks are POSIX-only and no-op on Windows.
Everything is best-effort and read-only.
é    )ÚannotationsN©ÚPath)ÚOptionalzhermes.security_auditFÚreturnÚboolc                 ó¢   — t          t          dd¦  «        pt          t          dd¦  «        } | €dS 	  | ¦   «         dk    S # t          $ r Y dS w xY w)zCTrue when the process runs as POSIX uid 0. Always False on Windows.ÚgeteuidNÚgetuidFr   )ÚgetattrÚosÚ	Exception)r   s    úG/home/ragecks/.hermes/hermes-agent/hermes_cli/security_audit_startup.pyÚ_is_rootr   &   se   € å•R˜ DÑ)Ô)ÐH­WµR¸À4Ñ-HÔ-H€FØ€~ØˆuðØˆv‰xŒx˜1Š}ÐøÝð ð ð Øˆuˆuðøøøs   ²A  Á 
AÁAúOptional[str]c                 ó(   — t          ¦   «         sd S 	 dS )Nu	  Running as ROOT. The agent's terminal/file tools execute with full root privileges â€” a single prompt-injection or exposed endpoint is a full host compromise. Run Hermes as an unprivileged user (or in a sandboxed terminal backend / container with a non-root user).)r   © ó    r   Ú_running_as_rootr   1   s#   € Ý‰:Œ:ð Øˆtð	Hðð r   )z/etc/ssh/sshd_configz/etc/ssh/sshd_config.dú	list[str]c                 ó  — g } d„ t           D ¦   «         }	 t          t          ¦  «        }|                     ¦   «         r5|                     t          |                     d¦  «        ¦  «        ¦  «         n# t          $ r Y nw xY w|D ]}	 |                     dd¬¦  «         	                    ¦   «         D ]B}| 
                    ¦   «         }|r*|                     d¦  «        s|                      |¦  «         ŒCŒp# t          $ r Y Œ|w xY w| S )zAYield non-comment lines from sshd_config + its drop-in directory.c                ó,   — g | ]}t          |¦  «        ‘ŒS r   r   )Ú.0Úps     r   ú
<listcomp>z+_iter_sshd_config_lines.<locals>.<listcomp>E   s   € Ð=Ð=Ð= Q�˜a™œÐ=Ð=Ð=r   z*.confúutf-8Úreplace©ÚencodingÚerrorsú#)Ú_SSHD_CONFIG_PATHSr   Ú_SSHD_CONFIG_DIRÚis_dirÚextendÚsortedÚglobr   Ú	read_textÚ
splitlinesÚstripÚ
startswithÚappend)ÚlinesÚpathsÚdr   ÚrawÚstrippeds         r   Ú_iter_sshd_config_linesr2   B   s-  € à€EØ=Ð=Õ*<Ð=Ñ=Ô=€EðÝÕ!Ñ"Ô"ˆØ�8Š8‰:Œ:ð 	3Ø�LŠL� §¢ xÑ 0Ô 0Ñ1Ô1Ñ2Ô2Ð2øøÝð ð ð Øˆðøøøàð ð ˆð	Ø—{’{¨G¸I�{ÑFÔF×QÒQÑSÔSð +ð +�ØŸ9š9™;œ;�Øð + H×$7Ò$7¸Ñ$<Ô$<ð +Ø—L’L Ñ*Ô*Ð*øð+øõ ð 	ð 	ð 	ØˆHð	øøøà€Ls%   •AA3 Á3
B Á?B ÂA,C5Ã5
DÄDc                 óà   — t          ¦   «         } | sdS d}d}| D ]B}t          j        d|¦  «        }|r)|                     d¦  «                             ¦   «         }d}ŒC|dk    rdS |rdnd	}d
|› d�S )a(  Warn when an SSH daemon has password authentication enabled.

    Password auth on a public SSH daemon is the classic brute-force surface
    and pairs badly with a root-capable agent box. POSIX-only; returns None
    when there's no sshd config to read (e.g. Windows, or SSH not installed).
    NÚyesFz#(?i)^PasswordAuthentication\s+(\w+)é   TÚnoÚ u$    (default â€” no explicit directive)z&SSH password authentication is ENABLEDz’. Password auth is brute-forceable and dangerous on an internet-facing box. Set 'PasswordAuthentication no' in sshd_config and use key-based auth.)r2   ÚreÚmatchÚgroupÚlower)r-   ÚverdictÚsaw_directiveÚlineÚmÚ	qualifiers         r   Ú_ssh_password_auth_enabledrA   W   s¬   € õ $Ñ%Ô%€EØð Øˆtà€GØ€MØð !ð !ˆÝŒHÐ;¸TÑBÔBˆØð 	!Ø—g’g˜a‘j”j×&Ò&Ñ(Ô(ˆGØ ˆMøØ�$‚€ØˆtØ#ÐO��Ð)O€Ið	M°ð 	Mð 	Mð 	Mðr   c                 ó2  ‡ — t           j                             d¦  «        rdS t           j                             d¦  «        rdS 	 t          d¦  «                             dd¬¦  «        Š t          ˆ fd	„d
D ¦   «         ¦  «        rdS n# t          $ r Y nw xY wdS )z@Best-effort container detection (Docker / Podman / generic OCI).z/.dockerenvTÚHERMES_DESKTOP_CHILD_PIDFz/proc/1/cgroupr   r   r   c              3  ó    •K  — | ]}|‰v V — Œ	d S )Nr   )r   ÚtokÚcgroups     €r   ú	<genexpr>z _in_container.<locals>.<genexpr>{   s'   øè è € ÐWÐW ˆs�fˆ}ÐWÐWÐWÐWÐWÐWr   )ÚdockerÚ
containerdÚkubepodsÚlibpod)	r   ÚpathÚexistsÚenvironÚgetr   r(   Úanyr   )rF   s   @r   Ú_in_containerrQ   s   sµ   ø€ å	„w‡~‚~�mÑ$Ô$ð ØˆtÝ	„z‡~‚~Ð0Ñ1Ô1ð ØˆuðÝÐ&Ñ'Ô'×1Ò1¸7È9Ð1ÑUÔUˆÝÐWÐWÐWÐWÐ(VÐWÑWÔWÑWÔWð 	Ø�4ð	øåð ð ð Øˆðøøøàˆ5s   Á?B Â
BÂBrL   r   c                óV  — 	 |                       ¦   «         }n# t          $ r | }Y nw xY w	 t          d¦  «                             dd¬¦  «                             ¦   «         }n# t          $ r Y dS w xY wd}d}|D ]ª}|                     ¦   «         }t          |¦  «        dk     rŒ*|d	         |d
         }}	 t          |¦  «        }	n# t          $ r Y ŒWw xY w|	|k    s	|	|j        v r@|�:t          t          |	¦  «        ¦  «        t          t          |¦  «        ¦  «        k    r|	}|}Œ«|€dS |dvS )a;  True if *path* sits on (or under) a real mount point per /proc/mounts.

    Container overlay/root filesystems are ephemeral; a bind/volume mount over
    the data dir shows up as a distinct mount entry. We treat the path as
    persisted when a mountpoint at or above it is NOT the container root
    overlay.
    z/proc/mountsr   r   r   TNr7   é   r5   é   )ÚoverlayÚtmpfsÚaufs)	Úresolver   r   r(   r)   ÚsplitÚlenÚparentsÚstr)
rL   ÚtargetÚmountsÚbestÚbest_fstyper>   ÚpartsÚ
mountpointÚfstypeÚmps
             r   Ú_path_is_mountedre   ‚   si  € ðØ—’‘”ˆˆøÝð ð ð ØˆˆˆðøøøðÝ�nÑ%Ô%×/Ò/¸ÈÐ/ÑSÔS×^Ò^Ñ`Ô`ˆˆøÝð ð ð Øˆtˆtðøøøà€DØ€KØð %ð %ˆØ—
’
‘”ˆÝˆu‰:Œ:˜Š>ˆ>ØØ" 1œX u¨Q¤x�Fˆ
ð	Ý�jÑ!Ô!ˆBˆBøÝð 	ð 	ð 	ØˆHð	øøøà�Š<ˆ<˜2 ¤Ð/Ð/àˆ|�s¥3 r¡7¤7™|œ|­cµ#°d±)´)©n¬nÒ<Ð<Ø�Ø$�øØ€|ØˆtàÐ:Ð:Ð:s/   ‚ —&¥&ª6A! Á!
A/Á.A/Â3CÃ
CÃCÚhermes_homeúOptional[Path]c                ó    — t          ¦   «         sd S | �| }nddlm}  |¦   «         }	 t          |¦  «        rd S n# t          $ r Y d S w xY wd|› d�S )Nr   )Úget_hermes_homez)Running in a container but the data dir (u¶   ) is NOT on a persistent volume mount â€” sessions, memory, skills, and API keys are ephemeral and lost on container restart. Mount a host volume over the HERMES_HOME data directory.)rQ   Úhermes_constantsri   re   r   )rf   Úhomeri   s      r   Ú_container_no_volume_mountrl   ¨   s›   € Ý‰?Œ?ð ØˆtØÐØˆˆà4Ð4Ð4Ð4Ð4Ð4àˆÑ Ô ˆðÝ˜DÑ!Ô!ð 	Ø�4ð	øåð ð ð Øˆtˆtðøøøð	&°Dð 	&ð 	&ð 	&ðs   §9 ¹
AÁAÚconfigúOptional[dict]c                óê  — g }	 ddl m} n# t          $ r |cY S w xY w| pi }	 |                     d¦  «        pi }t	          |t
          ¦  «        r|                     d¦  «        nd}t	          |t
          ¦  «        rè|                     d¦  «        rÓ|                     d¦  «        pi }|                     d¦  «        pt          j                             d	d
¦  «        }|                     d¦  «        pt          j                             dd¦  «        } |t          |¦  «        ¦  «        r:t          |¦  «         	                    ¦   «         s| 
                    d|› d�¦  «         n# t          $ r Y nw xY w|S )a,  Warn about network-accessible gateway listeners with no auth.

    Covers the API server (no API_SERVER_KEY) and the dashboard (non-loopback
    bind with no auth provider). Read-only against config + env; overlaps the
    hard fail-closed guards but surfaces the posture proactively at startup.
    r   )Úis_network_accessibleÚ	platformsÚ
api_serverNÚenabledÚextraÚhostÚAPI_SERVER_HOSTz	127.0.0.1ÚkeyÚAPI_SERVER_KEYr7   z4OpenAI-compatible API server is network-accessible (u¢   ) with NO API_SERVER_KEY. It dispatches terminal-capable agent work â€” an unauthenticated network endpoint is remote code execution. Set a strong API_SERVER_KEY.)Úgateway.platforms.baserp   r   rO   Ú
isinstanceÚdictr   rN   r\   r*   r,   )	rm   Úfindingsrp   ÚcfgÚplatsÚapirt   ru   rw   s	            r   Ú_network_listener_without_authr€   ¾   s¡  € ð €HðØ@Ð@Ð@Ð@Ð@Ð@Ð@øÝð ð ð Øˆˆˆðøøøð ˆ,�B€CðØ—’˜Ñ%Ô%Ð+¨ˆÝ)3°E½4Ñ)@Ô)@ÐJˆe�iŠi˜Ñ%Ô%Ð%ÀdˆÝ�c�4Ñ Ô ð 
	 S§W¢W¨YÑ%7Ô%7ð 
	Ø—G’G˜GÑ$Ô$Ð*¨ˆEØ—9’9˜VÑ$Ô$ÐV­¬
¯ªÐ7HÈ+Ñ(VÔ(VˆDØ—)’)˜EÑ"Ô"ÐJ¥b¤j§n¢nÐ5EÀrÑ&JÔ&JˆCØ$Ð$¥S¨¡Y¤YÑ/Ô/ð ½¸C¹¼¿ºÑ8HÔ8Hð Ø—’ð>È4ð >ð >ð >ñô ð øøõ ð ð ð Øˆðøøøð €Os   „ ‹™¢E E# Å#
E0Å/E0©rf   rm   c                óh  — g }t           t          fD ]4}	  |¦   «         }|r|                     |¦  «         Œ%# t          $ r Y Œ1w xY w	 t	          | ¦  «        }|r|                     |¦  «         n# t          $ r Y nw xY w	 |                     t          |¦  «        ¦  «         n# t          $ r Y nw xY w|S )zõRun all checks and return a list of human-readable warning strings.

    Pure: no logging, no side effects. Each check is independently
    fail-safe. Used directly by tests; the logging wrapper is
    :func:`log_startup_security_warnings`.
    )r   rA   r,   r   rl   r%   r€   )rf   rm   r|   ÚcheckÚrs        r   Úrun_security_auditr…   â   s   € ð €HåÝ"ðð 	ð 	ˆð	Ø�‘”ˆAØð #Ø—’ Ñ"Ô"Ð"øøÝð 	ð 	ð 	ØˆHð	øøøðÝ& {Ñ3Ô3ˆØð 	Ø�OŠO˜AÑÔÐøøÝð ð ð ØˆðøøøðØ�ŠÕ6°vÑ>Ô>Ñ?Ô?Ð?Ð?øÝð ð ð Øˆðøøøà€Os3   ”!6¶
AÁAÁ&A. Á.
A;Á:A;Á?"B" Â"
B/Â.B/)rf   rm   Úforcer†   c                ó>  — t           r|sg S da 	 t          | |¬¦  «        }n# t          $ r g cY S w xY w|rht                               dt          |¦  «        ¦  «         t          |d¦  «        D ]/\  }}t                               d|t          |¦  «        |¦  «         Œ0|S )z½Run the audit once per process and emit each finding via logger.warning.

    Returns the findings (also for tests). Never raises. Idempotent unless
    ``force=True`` (used by tests).
    Tr�   uD   Security posture audit found %d issue(s) â€” review your deployment:r5   z  [security %d/%d] %s)Ú
_AUDIT_RANr…   r   ÚloggerÚwarningrZ   Ú	enumerate)rf   rm   r†   r|   ÚiÚfs         r   Úlog_startup_security_warningsrŽ     sÍ   € õ ð ˜%ð Øˆ	Ø€JðÝ%°+ÀfÐMÑMÔMˆˆøÝð ð ð Øˆ	ˆ	ˆ	ðøøøàð IÝ�ŠØRÝ�‰MŒMñ	
ô 	
ð 	
õ ˜h¨Ñ*Ô*ð 	Ið 	I‰DˆAˆqÝ�NŠNÐ2°Aµs¸8±}´}ÀaÑHÔHÐHÐHØ€Os   �! ¡0¯0)r   r   )r   r   )r   r   )rL   r   r   r   )rf   rg   r   r   )rm   rn   r   r   )rf   rg   rm   rn   r   r   )rf   rg   rm   rn   r†   r   r   r   )Ú__doc__Ú
__future__r   Úloggingr   r8   Úpathlibr   Útypingr   Ú	getLoggerr‰   rˆ   r   r   r"   r#   r2   rA   rQ   re   rl   r€   r…   rŽ   r   r   r   ú<module>r•      s‡  ððð ð, #Ð "Ð "Ð "Ð "Ð "à €€€Ø 	€	€	€	Ø 	€	€	€	Ø Ð Ð Ð Ð Ð Ø Ð Ð Ð Ð Ð à	ˆÔ	Ð2Ñ	3Ô	3€ð €
ðð ð ð ðð ð ð ðÐ ð ,Ð ðð ð ð ð*ð ð ð ð8ð ð ð ð#;ð #;ð #;ð #;ðLð ð ð ð,!ð !ð !ð !ðJ &*ÀDðð ð ð ð ð ðF #'Ø!Øð	ð ð ð ð ð ð ð r   