+
    iHàjW  ã                  ó,  € R t ^ RIHt ^ RIt^ RIt^ RIt^ RIHt ^ RIH	t	 ^ RI
HtHtHtHtHt ^ RIHt ^ RIHt . ROtR R lt] ! R R4      4       tRR R lltR R ltR R lt]! R4      t ! R R	]],          4      t ! R R
]],          4      tR# )a©  Shared cache substrate for external secret-source backends.

Two-layer fetch cache (in-process + on-disk); the disk half writes atomically
with ``0600`` permissions and honours a TTL, so that logic is audited in exactly
one place. Each backend supplies only its cache-key shape and a serializer.
The disk layer is strictly best-effort: a miss just triggers a refetch, because
a cache problem must never block Hermes startup.
)ÚannotationsN)Ú	dataclass)ÚPath)ÚCallableÚDictÚGenericÚOptionalÚTypeVar)Úsecure_parent_dir)Úatomic_json_writeÚCachedFetchÚ	DiskCacheÚSecretCachec               ó    € V ^8„  d   QhRRRR/# )é   ÚmaterialÚstrÚreturn© )Úformats   "Ú@/home/ubuntu/.hermes/hermes-agent/agent/secret_sources/_cache.pyÚ__annotate__r   !   s   € ÷ Eñ E˜#ð E #ñ Eó    c                óv   € \         P                  ! V P                  R4      4      P                  4       R,          # )uE   SHA-256 prefix used as a cache key â€” never logged, never displayed.zutf-8:Né   N)ÚhashlibÚsha256ÚencodeÚ	hexdigest)r   s   &r   Úfingerprintr   !   s(   € ä�>Š>˜(Ÿ/™/¨'Ó2Ó3×=Ñ=Ó?ÀÕDÐDr   c                  ó<   € ] tR t^&t$ RtR]R&   R]R&   R R ltRtR	# )
r   z;A set of fetched secret values plus when they were fetched.zdict[str, str]ÚsecretsÚfloatÚ
fetched_atc               ó    € V ^8„  d   QhRRRR/# )r   Úttl_secondsr"   r   Úboolr   )r   s   "r   r   ÚCachedFetch.__annotate__-   s   € ÷ Qñ Q Eð Q¨dñ Qr   c                	ón   € V^ 8„  ;'       d*    \         P                   ! 4       V P                  ,
          V8  # )é    )Útimer#   )Úselfr%   s   &&r   Úis_freshÚCachedFetch.is_fresh-   s(   € Ø˜Q‰×PÐP¤D§I¢I£K°$·/±/Õ$AÀ[Ñ#PÐPr   r   N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__annotations__r,   Ú__static_attributes__r   r   r   r   r   &   s   ‡ áEàÓØÓ÷Qñ Qr   c               ó    € V ^8„  d   QhRRRR/# ©r   Ú	home_pathúOptional[Path]r   r   r   )r   s   "r   r   r   1   s   € ÷ ñ  .ð ¸Dñ r   c                ó(   € V f   ^ RI Hp V! 4       p V # )z[``home_path`` as resolved by ``load_hermes_dotenv()``, else ``$HERMES_HOME``/``~/.hermes``.)Úget_hermes_home)Úhermes_constantsr:   )r7   r:   s   & r   Úresolve_cache_homer<   1   s   € àÒÝ4á#Ó%ˆ	ØÐr   c               ó    € V ^8„  d   QhRRRR/# )r   ÚpayloadÚobjectr   úOptional[CachedFetch]r   )r   s   "r   r   r   :   s   € ÷ Dñ D ð DÐ+@ñ Dr   c                óº  € \        V \        4      '       g   R# V P                  R4      V P                  R4      r!\        V\        4      '       d   \        V\        \        34      '       g   R# VP                  4        UUu/ uF7  w  r4\        V\        4      '       g   K  \        V\        4      '       g   K5  W4bK9  	  ppp\        V\	        V4      R7      # u uppi )u©   ``{"secrets": {...}, "fetched_at": n}`` â†’ :class:`CachedFetch`, or None if malformed.

Only strâ†’str pairs survive (JSON permits other types; env vars need strings).
Nr!   r#   )r!   r#   )Ú
isinstanceÚdictÚgetÚintr"   Úitemsr   r   )r>   r!   r#   ÚkÚvÚtypeds   &     r   Úentry_from_payloadrJ   :   s›   € ô
 �gœt×$Ò$ÙØ!Ÿ+™+ iÓ0°'·+±+¸lÓ2KˆZÜ�gœt×$Ò$¬J°zÄCÌÀ<×,PÒ,PÙØ%Ÿm™mœoÔ[™o‘d�a´¸A¼s×1CŒTÌ
ÐSTÔVY×HZŒTˆQŠT™o€EÑ[Ü˜u´°zÓ1BÔCÐCùó \s   ÂCÂ CÂ8Cc               ó$   € V ^8„  d   QhRRRRRR/# )r   Úpathr   r>   rC   r   ÚNoner   )r   s   "r   r   r   H   s!   € ÷ >ñ >˜Dð >¨4ð >°Dñ >r   c                óh   € ^ RI Hp V! V P                  4       \        V 4       \	        WRRR7       R# )zèSecret cache entry at 0600 from creation; the containing dir is tightened to 0700
(``secure_parent_dir`` refuses ``/``, top-level dirs and the install tree). Raises ``OSError``
on failure; callers decide whether that is best-effort.)Úmkdir_under_hermes_homeNi€  )ÚindentÚmode)r;   rO   Úparentr
   r   )rL   r>   rO   s   && r   Úatomic_write_jsonrS   H   s'   € õ 9á˜DŸK™KÔ(Ü�dÔÜ�d¨D°u×=r   ÚKc                  óf   € ] tR t^VtRtR R ltRR R lltRR R lltRR	 R
 lltRR R llt	Rt
R# )r   u  Best-effort, profile-aware on-disk cache for fetched secret values.

One JSON object per backend at ``<hermes_home>/cache/<basename>``::

    {"key": "<serialized cache key>", "secrets": {...}, "fetched_at": 1.0}

The file holds only secret *values*, never raw auth material â€” backends
fingerprint tokens/sessions before they reach ``key_serializer``. Both
``read`` and ``write`` short-circuit when ``ttl_seconds <= 0``, so a TTL of
zero disables both layers symmetrically: an opted-out user never gets
secret values written to disk at all.
c               ó$   € V ^8„  d   QhRRRRRR/# ©r   Úbasenamer   Úkey_serializerzCallable[[K], str]r   rM   r   )r   s   "r   r   ÚDiskCache.__annotate__d   s#   € ÷ .ñ . ð .Ð9Kð .ÐPTñ .r   c               	ó   € Wn         W n        R # ©N©Ú	_basenameÚ_key_serializer©r+   rX   rY   s   &&$r   Ú__init__ÚDiskCache.__init__d   s   € Ø!ŒØ-Ör   Nc               ó    € V ^8„  d   QhRRRR/# r6   r   )r   s   "r   r   rZ   h   s   € ÷ Hñ H˜nð H¸ñ Hr   c                	óH   € \        V4      R ,          V P                  ,          # )Úcache)r<   r^   ©r+   r7   s   &&r   rL   ÚDiskCache.pathh   s   € Ü! )Ó,¨wÕ6¸¿¹ÕGÐGr   c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r   ÚkeyrT   r%   r"   r7   r8   r   r@   r   )r   s   "r   r   rZ   k   s/   € ÷ Tñ T˜ð T¨ð T¸.ð TÐTiñ Tr   c                óÖ  € V^ 8:  d   R#  \        V P                  V4      RRR7      ;_uu_ 4       p\        P                  ! V4      pRRR4       \        X\        4      '       d&   TP                  R4      T P                  T4      8w  d   R# \        T4      pTe   TP                  T4      '       d   T# R#   + '       g   i     Lw; i  \        \        P
                  3 d     R# i ; i)zEFresh cached entry for ``key``, or None (I/O error, mismatch, stale).NÚrz	utf-8-sig)Úencodingri   )ÚopenrL   ÚjsonÚloadÚOSErrorÚJSONDecodeErrorrB   rC   rD   r_   rJ   r,   )r+   ri   r%   r7   Úfr>   Úentrys   &&&&   r   ÚreadÚDiskCache.readk   s»   € à˜!ÔÙð	Ü�d—i‘i 	Ó*¨C¸+×FÕFÈ!ÜŸ)š) A›,�÷ Gô ˜'¤4×(Ò(¨G¯K©K¸Ó,>À$×BVÑBVÐWZÓB[Ô,[ÙÜ" 7Ó+ˆØÒ)¨e¯n©n¸[×.IÒ.IˆuÐSÈtÐS÷ G×Fûäœ×-Ñ-Ð.ô 	Úð	ús.   ‹%C	 °B6ÁC	 Â6C	ÃC	 ÃC	 Ã	C(Ã'C(c          
     ó,   € V ^8„  d   QhRRRRRRRRR	R
/# ©r   ri   rT   rs   r   r%   r"   r7   r8   r   rM   r   )r   s   "r   r   rZ   y   s0   € ÷ ñ ˜ð  ;ð ¸Uð È~ð Ðimñ r   c                óÊ   € V^ 8:  d   R# RV P                  V4      RVP                  RVP                  /p \        V P	                  V4      V4       R#   \
         d     R# i ; i)z[Persist ``entry`` atomically at mode 0600; no-op when ``ttl_seconds <= 0`` or on I/O error.Nri   r!   r#   )r_   r!   r#   rS   rL   rp   )r+   ri   rs   r%   r7   r>   s   &&&&& r   ÚwriteÚDiskCache.writey   s_   € à˜!ÔÙØ˜$×.Ñ.¨sÓ3°YÀÇÁÈ|Ð]b×]mÑ]mÐnˆð	Ü˜dŸi™i¨	Ó2°GÖ<øÜô 	Úð	ús   ¶A ÁA"Á!A"c               ó    € V ^8„  d   QhRRRR/# ©r   r7   r8   r   rM   r   )r   s   "r   r   rZ   ƒ   s   € ÷ ñ ˜~ð ¸ñ r   c                óv   €  V P                  V4      P                  4        R#   \        \        3 d     R# i ; i)z6Delete the on-disk cache file if present (idempotent).N)rL   ÚunlinkÚFileNotFoundErrorrp   rf   s   &&r   ÚclearÚDiskCache.clearƒ   s3   € ð	Ø�I‰I�iÓ ×'Ñ'Ö)øÜ!¤7Ð+ô 	Úð	ús   ‚# £8·8r]   r\   )r.   r/   r0   r1   r2   ra   rL   rt   ry   r€   r4   r   r   r   r   r   V   s'   † ñõ.÷H÷T÷÷ó r   c                  óV   € ] tR t^‹tRtR R ltRR R lltRR R lltRR	 R
 lltRt	R# )r   zÐTwo-layer cache: in-process dict (L1) over a :class:`DiskCache` (L2).

L1 saves repeated fetches WITHIN one process (CLI startup, gateway
hot-reload); L2 saves them ACROSS back-to-back short-lived processes.
c               ó$   € V ^8„  d   QhRRRRRR/# rW   r   )r   s   "r   r   ÚSecretCache.__annotate__’   s(   € ÷ Uñ U ð UÐ9Kð UÐPTñ Ur   c               	ó6   € / V n         \        WR 7      V n        R# ))rY   N)Úmemoryr   Údiskr`   s   &&$r   ra   ÚSecretCache.__init__’   s   € Ø,.ˆŒÜ"+¨HÔ"TˆŽ	r   Nc          
     ó,   € V ^8„  d   QhRRRRRRRRR	R
/# )r   ri   rT   r%   r"   r7   r8   Ú	read_diskz-Optional[Callable[[], Optional[CachedFetch]]]r   r@   r   )r   s   "r   r   r„   –   s1   € ÷ ñ ˜!ð ¨%ð ¸Nð ØGðØShñr   c                óø   € V P                   P                  V4      pV'       d   VP                  V4      '       d   V# V'       d   V! 4       MV P                  P	                  WV4      pVe   W`P                   V&   V# )zŒFresh entry from L1, else from L2 (promoted into L1), else None.

``read_disk`` swaps in an alternative L2 reader (e.g. an encrypted file).
)r†   rD   r,   r‡   rt   )r+   ri   r%   r7   rŠ   ÚcachedÚdisk_cacheds   &&&&&  r   ÚlookupÚSecretCache.lookup–   s_   € ð —‘—‘ Ó%ˆß�f—o‘o k×2Ò2ØˆMß%.‘i”k°D·I±I·N±NÀ3ÐU^Ó4_ˆØÒ"Ø*�K‰K˜ÑØÐr   c          
     ó,   € V ^8„  d   QhRRRRRRRRR	R
/# rw   r   )r   s   "r   r   r„   ¤   s0   € ÷ <ñ <˜ð < ;ð <¸Uð <È~ð <Ðimñ <r   c                	óZ   € W P                   V&   V P                  P                  WW44       R # r\   )r†   r‡   ry   )r+   ri   rs   r%   r7   s   &&&&&r   ÚstoreÚSecretCache.store¤   s    € Ø �‰�CÑØ�	‰	�‰˜ KÖ;r   c               ó    € V ^8„  d   QhRRRR/# r|   r   )r   s   "r   r   r„   ¨   s   € ÷ #ñ #˜~ð #¸ñ #r   c                	óp   € V P                   P                  4        V P                  P                  V4       R # r\   )r†   r€   r‡   rf   s   &&r   r€   ÚSecretCache.clear¨   s"   € Ø�‰×ÑÔØ�	‰	�‰˜	Ö"r   )r‡   r†   )NNr\   )
r.   r/   r0   r1   r2   ra   rŽ   r’   r€   r4   r   r   r   r   r   ‹   s!   † ñõU÷÷<÷#ó #r   )r   r   r   rS   rJ   r   r<   r\   )r2   Ú
__future__r   r   rn   r*   Údataclassesr   Úpathlibr   Útypingr   r   r   r   r	   r;   r
   Úutilsr   Ú__all__r   r   r<   rJ   rS   rT   r   r   r   r   r   Ú<module>r�      s�   ðñõ #ã Û Û Ý !Ý ß =Õ =å .Ý #ò€õEð
 ÷Qð Qó ðQ÷õDõ>ñ ˆCƒL€ô2�˜•
ô 2ôj#�'˜!•*ö #r   