Ë
    áß²jŸ<  ã                  ón  — d Z ddlm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mZmZmZmZ ddgZd	Zd
Z ej0                  d«      Zdd„Zdd„Zdd„Zd d„Zd!d„Z G d„ de«      Zdeeddœ	 	 	 	 	 	 	 	 	 	 	 d"d„Z d#d„Z!eedœ	 	 	 	 	 	 	 	 	 d$d„Z"eedœ	 	 	 	 	 	 	 d%d„Z#ddiZ$d„ Z%y)&uz  ``command`` secret source â€” resolve secrets via a user-configured helper.

Ports the desktop app's TypeScript ``CommandSecretsProvider`` semantics. The
helper (``keepassxc-cli``, ``secret-tool``, a script that cats a tmpfs env
file, ...) comes from ``secrets.command`` in ``config.yaml`` â€” NEVER from
``.env``, which holds only secret values.

Security model: the command string is the USER'S OWN configuration, so it runs
via ``/bin/sh -c``; the requested key reaches the child ONLY via
``HERMES_SECRET_KEY`` (never interpolated, so a hostile key name is inert); hard
timeout (default 3s) + 1 MiB output cap, every failure degrades to "no value";
failure logs carry ONLY structured fields (exit code / signal / errno), never
the command, the helper's stderr (captured and DISCARDED) or any value; startup
runs the helper exactly ONCE with an empty key; POSIX-only (needs ``/bin/sh``).
é    )ÚannotationsN)ÚPath)ÚDictÚOptional)Ú	ErrorKindÚFetchResultÚSecretSourceÚcoerce_floatÚsource_child_envr   Úunquote_dotenv_valueg      @i   z^([A-Za-z_][A-Za-z0-9_]*)=(.*)$c                 óZ   — t         j                  dk(  xs t        j                  «       dk(  S )NÚntÚWindows)ÚosÚnameÚplatformÚsystem© ó    úA/home/ubuntu/.hermes/hermes-agent/agent/secret_sources/command.pyÚ_is_windowsr   )   s!   € Ü�7‰7�d‰?Ò<œhŸo™oÓ/°9Ñ<Ð<r   c                ó@   — t        d| › �t        j                  ¬«       y )Nz[secrets:command] )Úfile)ÚprintÚsysÚstderr)Úmessages    r   Ú_logr   -   s   € Ü	Ð˜w˜iÐ
(¬s¯z©zÖ:r   c                óp   — | j                  «       }t        |«      dk\  r|d   |d   k(  r|d   dv r|dd S |S )z¸Strip one layer of matching surrounding quotes from a dotenv value.

    Requires length >= 2 so a lone ``"`` stays intact while ``""``/``''``
    correctly yield an empty string.
    é   r   éÿÿÿÿz"'é   )ÚstripÚlen)ÚrawÚts     r   r   r   1   sB   € ð 	�	‰	‹€AÜ
ˆ1ƒv�‚{�q˜‘t˜q ™u’}¨¨1©°©Ø��2ˆwˆØ€Hr   c                ó˜  — t        «       rt        d«       yt        «       }||d<   	 t        j                  dd| g|t        j
                  t        j                  t        j                  d¬«      }	 |j                  |¬	«      \  }}|j*                  dk7  ret-        |j*                  «      d}
}	|j*                  dk  r-	 t        j.                  |j*                   «      j0                  }
d}	t        d|	› d|
› �«       yt3        |«      |kD  rt        d|› d�«       y|j5                  dd¬«      S # t        $ r"}t        d|j                  › �«       Y d}~yd}~ww xY w# t        j                  $ r¸ 	 t        j                  t        j                  |j                  «      t        j                   «       n*# t"        t$        t        f$ r |j'                  «        Y nw xY w	 |j                  d
¬	«       n$# t        j                  t(        t        f$ r Y nw xY wt        d|d›d�«       Y yw xY w# t(        $ r t-        |j*                   «      }
Y �Œcw xY w)u  Run the helper via ``/bin/sh -c`` and return its stdout, or None.

    The key travels as DATA in ``HERMES_SECRET_KEY``. stdout/stderr are piped
    (never inherited); stderr is discarded. Any failure logs structured fields
    only and returns None â€” never raises.
    zSthe 'command' provider is POSIX-only (needs /bin/sh); resolving no value on WindowsNÚHERMES_SECRET_KEYz/bin/shz-cT)ÚenvÚstdinÚstdoutr   Ústart_new_sessionz2helper failed to spawn; resolving no value: errno=)Útimeoutg      ð?zhelper timed out after Úgzs; resolving no valuer   Únoneú?z(helper failed; resolving no value: code=z signal=zhelper output exceeded the z-byte cap; resolving no valuezutf-8Úreplace)Úerrors)r   r   r   Ú
subprocessÚPopenÚDEVNULLÚPIPEÚOSErrorÚerrnoÚcommunicateÚTimeoutExpiredr   ÚkillpgÚgetpgidÚpidÚ_signalÚSIGKILLÚProcessLookupErrorÚPermissionErrorÚkillÚ
ValueErrorÚ
returncodeÚstrÚSignalsr   r$   Údecode)ÚcommandÚ
secret_keyÚtimeout_secondsÚmax_output_bytesr)   ÚprocÚexcÚstdout_bytesÚ_stderr_discardedÚcodeÚsignames              r   Ú_run_helperrR   =   s  € ô „}ÜÐbÔcØô Ó
€CØ)€CÐÑðÜ×ÑØ˜˜gÐ&¨C´z×7IÑ7IÜ—?‘?¬:¯?©?Ø"ô
ˆðØ*.×*:Ñ*:À?Ð*:Ó*SÑ'ˆÐ'ð ‡�˜!ÒÜ˜DŸO™OÓ,¨fˆgˆØ�?‰?˜QÒð0Ü!Ÿ/™/¨4¯?©?Ð*:Ó;×@Ñ@�ð ˆDÜÐ7¸°v¸XÀgÀYÐOÔPØä
ˆ<ÓÐ+Ò+ÜÐ*Ð+;Ð*<Ð<YÐZÔ[Øà×Ñ˜w¨yÐÓ9Ð9øôG ò ÜÐAÀ#Ç)Á)ÀÐMÔNÜûðûô ×$Ñ$ò ð	Ü�I‰I”b—j‘j §¡Ó*¬G¯O©OÕ<øÜ"¤O´WÐ=ò 	Ø�I‰IŽKð	úð	Ø×Ñ SÐÕ)øÜ×)Ñ)¬:´wÐ?ò 	Ùð	úäÐ& °qÐ&9Ð9NÐOÔPÙðûô& ò 0Ü˜tŸ™Ð.Ó/“ð0ús…   §AD* Á0E Â;*H& Ä*	EÄ3EÅEÅH#Å,AF.Æ-H#Æ.$GÇH#ÇGÇH#ÇG,Ç+H#Ç,HÈ
H#ÈHÈH#È"H#È&I	ÉI	c                ó&  — i }| j                  dd«      j                  d«      D ]j  }|j                  «       }|r|j                  d«      rŒ't        j                  |«      }|sŒ?t        |j                  d«      «      ||j                  d«      <   Œl |S )zFParse a KEY=VALUE blob; comments and non-env-shaped lines are skipped.ú
Ú
ú#r    r"   )r1   Úsplitr#   Ú
startswithÚ	_ENV_LINEÚmatchr   Úgroup)r+   Úoutr%   ÚlineÚms        r   Ú_parse_dotenv_mapr_   y   s~   € à€CØ�~‰~˜f dÓ+×1Ñ1°$Ó7ò ?ˆØ�y‰y‹{ˆÙ�t—‘ sÔ+ØÜ�O‰O˜DÓ!ˆÚÜ2°1·7±7¸1³:Ó>ˆC�—‘˜“
ŠOð?ð €Jr   c                  ó`   — e Zd ZdZdZdZdZej                  dej                  diZ
d
d„Zdd„Zy	)ÚCommandSourceau  User-configured helper command as a registered **bulk** source.

    Composes with the other sources through ``apply_all()``; there is
    deliberately NO single-provider selector. The helper enumerates a
    KEY=VALUE blob in one run. Config::

        secrets:
          command:
            enabled: true
            command: "cat /run/user/1000/hermes-secrets.env"
    rH   zCommand helperÚbulkziSet secrets.command.command in config.yaml to a fast, non-interactive helper that prints KEY=VALUE lines.u…   Run the helper manually in a shell to see its real error â€” Hermes discards helper stderr so diagnostics can't leak secret material.c                ó0   — dddœdddœdt         dœdddœdœS )	NzMaster switchF)ÚdescriptionÚdefaultz@Helper run via /bin/sh -c; must print a KEY=VALUE blob on stdoutÚ zHard timeout for one helper runz)Helper values overwrite .env/shell values)ÚenabledrH   Úhelper_timeout_secondsÚoverride_existing)Ú_COMMAND_TIMEOUT_SECONDS)Úselfs    r   Úconfig_schemazCommandSource.config_schemaž   s4   € à'6À5ÑIØ'iØ#%ñ'à6WÜ2Jñ'Là1\ÐinÑ!oñ
ð 	
r   c                óD  — t        |t        «      r|ni }t        «       }t        |j	                  d«      xs d«      j                  «       }|s |j                  dt        j                  «      S t        «       r |j                  dt        j                  «      S t        |j	                  dt        «      t        «      }t        |d|t        «      }|€ |j                  dt        j                  «      S t        |«      }|s|j                   j#                  d«       |S ||_        |S )NrH   rf   úmsecrets.command.enabled is true but secrets.command.command is empty.  Set the helper command in config.yaml.úNthe 'command' secret source is POSIX-only (needs /bin/sh); skipping on Windowsrh   zGhelper command failed (see structured fields above); no secrets appliedz7helper output was not a KEY=VALUE map; nothing to apply)Ú
isinstanceÚdictr   rE   Úgetr#   Úfailr   ÚNOT_CONFIGUREDr   r
   rj   rR   Ú_MAX_OUTPUT_BYTESÚINTERNALr_   ÚwarningsÚappendÚsecrets)rk   ÚcfgÚ	home_pathÚresultrH   r-   r+   ry   s           r   ÚfetchzCommandSource.fetch¨   s  € Ü ¤TÔ*‰c°ˆÜ“ˆä�c—g‘g˜iÓ(Ò.¨BÓ/×5Ñ5Ó7ˆÙØ—;‘;ð  SÜT]×TlÑTlónð näŒ=Ø—;‘;ÐoÜ(×7Ñ7ó9ð 9ô ˜sŸw™wÐ'?ÔAYÓZÜ7ó9ˆä˜W b¨'Ô3DÓEˆØˆ>Ø—;‘;ÐhÜ(×1Ñ1ó3ð 3ô $ FÓ+ˆÙØ�O‰O×"Ñ"Ð#\Ô]ØˆMØ ˆŒØˆr   N)Úreturnrq   )rz   rq   r{   r   r~   r   )Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   ÚlabelÚshaper   rt   rv   Úremediation_hintsrl   r}   r   r   r   ra   ra   †   sG   „ ñ
ð €DØ€EØ€Eà× Ñ ð #Xà×Ñð /ðÐó
ôr   ra   F)ri   rJ   rK   r{   c                óÆ  — t        «       }| xs dj                  «       } | s	d|_        |S t        «       r|j                  j                  d«       |S t        | d||«      }|€|j                  j                  d«       |S t        |«      }||_        |s|j                  j                  d«       |S |j                  «       D ]Ÿ  \  }}	|	j                  «       dk(  r|j                  j                  |«       Œ5|s;t        j                  j                  |«      r|j                  j                  |«       Œr|	t        j                  |<   |j                  j                  |«       Œ¡ |S )a5  Run the helper once at startup and set its KEY=VALUE output on
    ``os.environ``.

    LEGACY shim retained for API symmetry with ``apply_bitwarden_secrets``;
    the startup path goes through :class:`CommandSource` + the registry
    orchestrator instead (which owns precedence and the environ writes).
    rf   rn   ro   zahelper command failed at startup; no secrets applied (process env / .env values remain in effect)z|helper output was not a KEY=VALUE map; nothing applied at startup (a bare-value helper still resolves single keys on demand))r   r#   Úerrorr   rw   rx   rR   r_   ry   ÚitemsÚskippedr   Úenvironrr   Úapplied)
rH   ri   rJ   rK   r{   r|   r+   ry   ÚkeyÚvalues
             r   Úapply_command_secretsrŽ   È   sJ  € ô ‹]€FàŠ}˜"×#Ñ#Ó%€GÙð=ð 	Œð ˆä„}Ø�‰×Ñð"ô	
ð ˆô ˜ " oÐ7GÓH€FØ€~à�‰×Ñð;ô	
ð ˆä Ó'€GØ€F„NÙØ�‰×ÑðQô	
ð ˆà—m‘m“oò #‰
ˆˆUØ�;‰;‹=˜BÒð �N‰N×!Ñ! #Ô&ØÙ ¤R§Z¡Z§^¡^°CÔ%8à�N‰N×!Ñ! #Ô&ØØŒ�
‰
�3‰Ø�‰×Ñ˜cÕ"ð#ð €Mr   c                ó¬  — | j                  dd«      }|j                  d«      }d„ |D «       D �cg c],  }|r(|j                  d«      st        j	                  |«      r|‘Œ. }}|D ]d  }t        j	                  |«      }|€J ‚|j                  d«      |k(  sŒ1t        |j                  d«      «      }|j                  «       dk7  r|c S dc S  t        |«      dkD  ry|j                  «       }|dk(  ryt        j	                  |«      }|rH|j                  d«      |k7  r4t        j                  d	|j                  d«      j                  «       «      €y|S c c}w )
as  Parse a secret-fetch helper's stdout.  Supports BOTH shapes:

    * a bare value (single secret): the whole trimmed stdout is the value.
    * a dotenv blob (KEY=VALUE lines): parse them and return the entry for
      ``wanted_key``.

    Mirrors the TS ``parseSecretOutput`` exactly, including the cross-key
    misroute guard and the base64-padding disambiguation.
    rT   rU   c              3  ó<   K  — | ]  }|j                  «       –— Œ y ­w)N)r#   )Ú.0r%   s     r   ú	<genexpr>z&parse_secret_output.<locals>.<genexpr>  s   è ø€ Ò2 S�S—Y‘Y—[Ñ2ùs   ‚rV   Nr"   r    rf   z=*)r1   rW   rX   rY   rZ   r[   r   r#   r$   ÚreÚ	fullmatch)	r+   Ú
wanted_keyÚtextÚlinesr]   Údotenv_linesr^   r�   Ú
env_shapeds	            r   Úparse_secret_outputrš     sF  € ð �>‰>˜& $Ó'€DØ�J‰J�tÓ€Eñ 3¨EÔ2öàÙ˜Ÿ™¨Ô,´·±ÀÔ1Fò 	ð€Lð ð
 ò :ˆÜ�O‰O˜DÓ!ˆØˆ}Ðˆ}Ø�7‰7�1‹:˜Ó#Ü(¨¯©°«Ó4ˆEð "ŸK™K›M¨RÒ/�5Ò9°TÒ9ð:ô" ˆ<Ó˜1ÒØð
 �J‰J‹L€EØ�‚{Øô —‘ Ó'€JáØ×Ñ˜QÓ :Ò-Ü�L‰L˜ 
× 0Ñ 0°Ó 3× 9Ñ 9Ó ;Ó<ÐDàØ€Lùòcs   ¯1E)rJ   rK   c                ój   — | xs dj                  «       } | syt        | |||«      }|€yt        ||«      S )u‡   Resolve a single secret by running the helper with the key in
    ``HERMES_SECRET_KEY``.  Returns None on any failure â€” never raises.rf   N)r#   rR   rš   )rH   rŒ   rJ   rK   r+   s        r   Úget_command_secretrœ   M  sB   € ð Š}˜"×#Ñ#Ó%€GÙØÜ˜ # Ð8HÓI€FØ€~ØÜ˜v sÓ+Ð+r   c                ól   — | xs dj                  «       } | si S t        | d||«      }|€i S t        |«      S )zÄEnumerate secrets by running the helper ONCE with an empty key.

    Returns the dotenv map ONLY when the helper emits a KEY=VALUE blob;
    a bare-value helper returns ``{}``.  Never raises.
    rf   )r#   rR   r_   )rH   rJ   rK   r+   s       r   Úlist_command_secretsrž   ^  sD   € ð Š}˜"×#Ñ#Ó%€GÙØˆ	Ü˜ " oÐ7GÓH€FØ€~Øˆ	Ü˜VÓ$Ð$r   Úget_source_environment)zagent.secret_sources.baserŸ   c                óÌ   — t         j                  | «      }|€t        dt        ›d| ›�«      ‚dd l}ddlm}  |t        | g|¢­Ž  t        |j                  |d   «      |d   «      S )Nzmodule z has no attribute r   )Ú	warn_oncer"   )	Ú_PLUGIN_COMPAT_LAZYrr   ÚAttributeErrorr   Ú	importlibÚhermes_cli.plugin_compatr¡   ÚgetattrÚimport_module)r   Útargetr¤   r¡   s       r   Ú__getattr__r©   w  se   € Ü ×$Ñ$ TÓ*€FØ€~Ü˜w¤x lÐ2DÀTÀHÐMÓNÐNÛÝ2ÙŒh˜Ð&˜vÓ&Ü�9×*Ñ*¨6°!©9Ó5°v¸a±yÓAÐAr   )r~   Úbool)r   rE   r~   ÚNone)r%   rE   r~   rE   )
rH   rE   rI   rE   rJ   ÚfloatrK   Úintr~   úOptional[str])r+   rE   r~   úDict[str, str])rH   rE   ri   rª   rJ   r¬   rK   r­   r{   zOptional[Path]r~   r   )r+   rE   r•   rE   r~   r®   )
rH   rE   rŒ   rE   rJ   r¬   rK   r­   r~   r®   )rH   rE   rJ   r¬   rK   r­   r~   r¯   )&r‚   Ú
__future__r   r   r   r“   Úsignalr>   r3   r   Úpathlibr   Útypingr   r   Úagent.secret_sources.baser   r   r	   r
   r   Ú__all__rj   ru   ÚcompilerY   r   r   r   rR   r_   ra   rŽ   rš   rœ   rž   r¢   r©   r   r   r   ú<module>r·      sb  ðñõ  #ã 	Û Û 	Û Û Û 
Ý ß !ç jÕ jàÐ0Ð
1€ð Ð ØÐ ð ˆB�J‰JÐ9Ó:€	ó=ó;ó	ó9:óx
ô:�Lô :ðJ $Ø5Ø-Ø $ñAàðAð ðAð ð	Að
 ðAð ðAð óAóF@ðL 6Ø-ñ,àð,ð 
ð,ð ð	,ð
 ð,ð ó,ð( 6Ø-ñ	%àð%ð ð%ð ð	%ð
 ó%ð* ÐUðÐ ó
Br   