
    `gj~5                    b   U d Z ddlmZ ddlZddlZddlmZmZ ddl	m
Z
 ddlmZmZmZ ddlmZmZmZmZmZ  ej*                  e      Zi Zded	<   d
ae G d d             Ze G d d             Ze G d d             Zd
dddZddZddZ ddZ!ddZ"	 	 	 	 	 	 	 	 ddZ#ddZ$	 d 	 	 	 d!dZ%y)"u  Secret-source registry + apply orchestrator.

This module owns everything that must be uniform across secret backends
so no individual source can get it wrong:

* registration (name/scheme uniqueness, API-version gating)
* per-source wall-clock timeout enforcement around ``fetch()``
* precedence: mapped sources beat bulk sources; within a shape,
  ``secrets.sources`` order (or registration order) decides; first
  claim wins — later sources never silently clobber an earlier one
* ``override_existing`` semantics (may beat .env/shell, never another
  secret source, never a protected var)
* cross-source conflict warnings (shadowed claims are always surfaced)
* provenance: which source supplied every applied var

The single entry point for startup is :func:`apply_all`, called from
``hermes_cli.env_loader._apply_external_secret_sources()``.

Plugins register additional sources via
``PluginContext.register_secret_source()`` which lands in
:func:`register_source`.  In-tree sources are registered lazily by
:func:`_ensure_builtin_sources` — the set of bundled sources is
deliberately closed (Bitwarden, and 1Password once it lands); new
third-party backends ship as standalone plugin repos implementing
:class:`agent.secret_sources.base.SecretSource`.
    )annotationsN)	dataclassfield)Path)DictListOptional)SECRET_SOURCE_API_VERSION	ErrorKindFetchResultSecretSourceis_valid_env_namezDict[str, SecretSource]_SOURCESFc                  :    e Zd ZU dZded<   ded<   ded<   ded<   y)	
AppliedVarz7Provenance record for one env var the orchestrator set.strnamesourceshapebooloverrode_envN)__name__
__module____qualname____doc____annotations__     P/root/.hermes/venv/lib/python3.12/site-packages/agent/secret_sources/registry.pyr   r   4   s    A
IKJr   r   c                      e Zd ZU dZded<   ded<   ded<    ee      Zded	<    ee      Zded
<    ee      Z	ded<    ee      Z
ded<    ee      Zded<   y)SourceReportz4One source's outcome within an :class:`ApplyReport`.r   r   labelr   resultdefault_factory	List[str]appliedskipped_existingskipped_claimedskipped_protectedskipped_invalidN)r   r   r   r   r   r   listr'   r(   r)   r*   r+   r   r   r   r!   r!   >   sb    >
IJt4GY4"'"=i=!&t!<OY<#(#>y>!&t!<OY<r   r!   c                  x    e Zd ZU dZ ee      Zded<    ee      Z	ded<    ee      Z
ded<   edd	       Zy
)ApplyReportz.Merged outcome of one orchestrated apply pass.r$   zList[SourceReport]sourceszDict[str, AppliedVar]
provenancer&   	conflictsc                ,    t        | j                        S N)r   r0   )selfs    r   applied_anyzApplyReport.applied_anyT   s    DOO$$r   N)returnr   )r   r   r   r   r   r,   r/   r   dictr0   r1   propertyr5   r   r   r   r.   r.   L   sF    8"'"=G=(-d(CJ%C 6Iy6% %r   r.   )replacec          	        t        | t              st        j                  d|        yt	        | dd      xs d}|r3|j                  dd      j                         r||j                         k7  rt        j                  d|       yt	        | dd      t        k7  r(t        j                  d	|t	        | dd
      t               yt	        | dd      dvr#t        j                  d|t	        | dd             y|t        v r|st        j                  d|       yt	        | dd      }|rLt        j                         D ]5  \  }}||k7  st	        |dd      |k(  st        j                  d|||        y | t        |<   y)ub  Register a secret source.  Returns True on success.

    Rejections are logged, never raised — a bad plugin must not take
    down startup.  ``replace`` allows tests / user plugins to override
    a bundled source of the same name (last-writer-wins like model
    providers), but scheme collisions across *different* names are
    always rejected.
    z=Ignoring secret source %r: does not inherit from SecretSourceFr    _z+Ignoring secret source with invalid name %rapi_versionNzXIgnoring secret source '%s': built against secret-source API v%s, this Hermes speaks v%s?r   )mappedbulkzEIgnoring secret source '%s': shape must be 'mapped' or 'bulk', got %rz9Secret source '%s' already registered; ignoring duplicateschemezKIgnoring secret source '%s': scheme '%s://' is already owned by source '%s'T)
isinstancer   loggerwarninggetattrr9   isalnumlowerr
   r   items)r   r9   r   rA   
other_nameothers         r   register_sourcerK   ^   si    fl+K	
 662&,"Dt||C,446$$**,:NDdKv}d+/HH%'&-57P	

 vw%-??S'&'40	
 xRTXYVXt,F!)!1 	JT!geXt&D&N+&*
 	 HTNr   c                @    t                t        j                  |       S r3   )_ensure_builtin_sourcesr   get)r   s    r   
get_sourcerO      s    <<r   c                 P    t                t        t        j                               S r3   )rM   r,   r   valuesr   r   r   list_sourcesrR      s    !""r   c                 
   t         ryda 	 ddlm}  t         |               	 ddlm} t         |              y# t        $ r t
        j                  dd       Y :w xY w# t        $ r t
        j                  dd       Y yw xY w)	zIdempotently register the bundled sources.

    Lazy so importing this module stays cheap and so a broken bundled
    source can never break registration of the others.
    NTr   )BitwardenSourcez2Failed to register bundled Bitwarden secret sourceexc_info)OnePasswordSourcez2Failed to register bundled 1Password secret source)	_BUILTINS_LOADEDagent.secret_sources.bitwardenrT   rK   	ExceptionrC   rD    agent.secret_sources.onepasswordrW   )rT   rW   s     r   rM   rM      s     &B)*&F)+,  &K $ 	 	&&  &K $ 	 	&&s    9 A  AA BBc                 0    t         j                          day )NF)r   clearrX   r   r   r   _reset_registry_for_testsr^      s    NNr   c                   | j                  |      }t        j                  j                  dd| j                         }	 |j                  | j                  ||      }	 |j                  |      }	 |j                  d	
       t)        |t              s?t               }dt#        |      j$                   d|_        t        j&                  |_        |S |S # t        j                  j                  $ r_ |j                          t               }d|dd| j                   d|_        t        j                  |_        |cY |j                  d	
       S t         $ r]}t               }dt#        |      j$                   d| |_        t        j&                  |_        |cY d}~|j                  d	
       S d}~ww xY w# |j                  d	
       w xY w)u  Run source.fetch() under a wall-clock budget; never raises.

    The budget is enforced with a daemon worker thread: a source that
    blows its budget is reported as ``TIMEOUT`` and its (eventual)
    result is discarded.  The thread itself may linger until process
    exit — acceptable for a startup-only path, and strictly better than
    an unbounded hang on every ``hermes`` invocation.
       zsecret-src-)max_workersthread_name_prefix)timeoutzfetch exceeded z.0fuB   s budget — startup continued without this source (raise secrets.z-.timeout_seconds if the backend is just slow)F)waitzfetch raised z: Nzfetch returned z instead of FetchResult)fetch_timeout_seconds
concurrentfuturesThreadPoolExecutorr   submitfetchr#   TimeoutErrorcancelr   errorr   TIMEOUT
error_kindshutdownrZ   typer   INTERNALrB   )	r   cfg	home_pathrc   executorfuturer#   resexcs	            r   _fetch_with_timeoutry      s    **3/G!!44K}*E 5 H&sI>	]]7]3F" 	u%fk*md6l3344KL 		 #++
M3 !!.. 		MMO-C!'# /6;;-LN I
 '..CNJ 	u%  	-C'S	(:(:';2cUCCI&//CNJu%	 	u%sD   F8 C A'F5<F8 F5A F0F5F8 0F55F8 8Gc                   t                | j                  d      }g }t        |t              r|D ]2  }t        |t              s|t
        v s||vs"|j                  |       4 |D cg c]  }t        |t              r
|t
        vr| }}|r=t        j                  ddj                  |      dj                  t
              xs d       t
        D ]  }||vs|j                  |        g }|D ]S  }t
        |   }| j                  |      }	t        |	t              r|	ni }		 |j                  |	      r|j                  |       U |S c c}w # t        $ r t        j                  d|d       Y w xY w)aE  Resolve which sources run, in which order.

    Order: the optional ``secrets.sources`` list wins; sources not named
    there follow in registration order.  Enabled = the source's own
    ``is_enabled`` says so for its config section.  Mapped-vs-bulk
    precedence is applied on top of this order by :func:`apply_all`.
    r/   z7secrets.sources names unknown source(s): %s (known: %s)z, nonez0Secret source '%s' is_enabled() raised; skippingTrU   )rM   rN   rB   r,   r   r   appendrC   rD   joinr7   
is_enabledrZ   )
secrets_cfgexplicitorderentryeunknownr   enabledr   rs   s
             r   _ordered_enabled_sourcesr      ss    y)HE(D! 	$E%%%8*;U@RU#	$ ' @ C(Qh->  @ @NNI		'"DIIh$7$A6  uLL #%G 	0$ood#T*c	0  %v&	0 N-@&  	0NNM$  0	0s   )!E""E!E10E1c           
     \   ddl }||n|j                  }t               }t        | t              r| ni } t        |       }|s|S |D cg c]  }|j                  dk(  s| c}|D cg c]  }|j                  dk(  s| c}z   }g }	i }
|D ]  }| j                  |j                        }t        |t              r|ni }t        |||      }|	j                  |||f       	 |j                  |      D ]  }|
j                  ||j                            i }|	D ]  \  }}}t        |j                  |j                  xs |j                  |      }|j                   j                  |       |j"                  s`	 |j%                  |      }|j&                  j)                         D ]X  \  }}t        |t*              rt        |t*              s(t-        |      s|j.                  j                  |       O||
v r|j0                  j                  |       o||v rM|j2                  j                  |       |j4                  j                  | d||    d|j                   d	       t7        |j                  |            }|r|s|j8                  j                  |       |||<   |j                  ||<   |j:                  j                  |       t=        ||j                  |j                  |
      |j>                  |<   [  |S c c}w c c}w # t        $ r Y w xY w# t        $ r d}Y w xY w)u]  Fetch from every enabled source and apply the merged result to env.

    ``environ`` defaults to ``os.environ``; injectable for tests.

    Precedence per env var (most-specific intent wins):

    1. Pre-existing env (.env / shell) — unless the winning source has
       ``override_existing: true``.
    2. Mapped sources, in configured order.
    3. Bulk sources, in configured order.

    First claim wins.  A later source that also carries the var gets a
    ``skipped_claimed`` entry and a conflict warning — never a silent
    clobber, and ``override_existing`` never applies across sources.
    r   Nr?   r@   )r   r"   r#   Fz: kept value from z; uW    also supplies it (first source wins — remove one binding or reorder secrets.sources))r   r   r   r   ) osenvironr.   rB   r7   r   r   rN   r   ry   r|   protected_env_vars
setdefaultrZ   r!   r"   r/   okoverride_existingsecretsrH   r   r   r+   r*   r)   r1   r   r(   r'   r   r0   )r   rt   r   _osenvreportr   sorderedfetches	protectedr   rs   r#   varclaimedsroverridevalueexisteds                       r   	apply_allr     s	   " ('ckkC]F!+K!>+BK&{3G #:aagg&9:$:6(9!:;G =?G "I 	oofkk*T*c$VS)<V,-	005 7$$S&++67	 !G& *Vv{{ & ;!') 	b!yy	//4H !....0 	JCc3'z%/E$S)""))#.i$$++C0g~""))#.  ''e-gcl^2{{m $EE
 3773<(Gx##**3/CH!;;GCLJJc"%/{{ll$	&Fc"1	*X M ;:  		  	H	s<   LL%L:L2L6L	LLL+*L+)r   r   r9   r   r6   r   )r   r   r6   zOptional[SecretSource])r6   List[SecretSource])r6   None)r   r   rs   r7   rt   r   r6   r   )r   r7   r6   r   r3   )r   r7   rt   r   r   zOptional[Dict[str, str]]r6   r.   )&r   
__future__r   concurrent.futuresrf   loggingdataclassesr   r   pathlibr   typingr   r   r	   agent.secret_sources.baser
   r   r   r   r   	getLoggerr   rC   r   r   rX   r   r!   r.   rK   rO   rR   rM   r^   ry   r   r   r   r   r   <module>r      s  6 #   (  ' '  
		8	$ %'
! &     
= 
= 
= 	% 	% 	%" >C .b
#
&4,,#,04,,^&T 37\/\;F\r   