+
    jHàj ã                  óŠ  € R t ^ RIHt ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIt^ RI	H
t
 ^ RIHtHtHt ]P                  ! ]4      t ! R R]4      t]P(                  ! R4      t]P(                  ! R4      t]P.                  '       d+   ]
! ]P.                  4      P0                  P3                  4       MR	tR
]! 0 Rœm4      R]! 0 R�m4      /t]R
,          ]R&   ]! 0 Ržm4      ]R&   ]P(                  ! R4      t]P(                  ! R4      t]! 0 RŸm4      t]! 0 R m4      t ]P(                  ! R4      t!]P(                  ! R4      t"Rt#RR/R R llt$R R lt%R R lt&R R lt'R  R! lt(]P(                  ! R"4      t)]P(                  ! R#4      t*]P(                  ! R$4      t+]P(                  ! R%4      t,]P(                  ! R&4      t-]! 0 R¡m4      t.]! 0 R¢m4      t/R'R(0t0R£t1^t2]! R*4      t3]! R+R,04      t4]! 0 R¤m4      t5R¥t6]P(                  ! R-4      t7]P(                  ! R.4      t8R/t9]]:.]]:,          3,          t;]! 0 R¦m4      t<R00 R§mR1RR>0R20 R¨mR3RR?0R40 R©mR50 RªmR60 R«mR7R0R80 R¬mR90 R­mR:0 R®mR;0 R¯mR<0 R°mR=0 R±m/t=R2R²R8R³R9R³/t>R6^/t?]P(                  ! R@4      t@^tAR´tBRA RB ltCRC RD ltDRE RF ltERG RH ltF]1tGRItHRµtIR)tJ^@tK ! RJ RK4      tLRL RM ltMRN RO ltNRP RQ ltORR RS ltPRT RU ltQRV RW ltRRX RY ltSRZR/R[ R\ lltTR] R^ ltUR_ R` ltVRa Rb ltWRc Rd ltXRe Rf ltYRg Rh ltZRi Rj lt[Rk Rl lt\Rm Rn lt]Ro Rp lt^Rq Rr lt_Rs Rt lt`Ru Rv ltaRw Rx ltbRy Rz ltcR{ R| ltdR} R~ lteR R€ ltfR�R/R‚ Rƒ lltgR„ R… lthR† R‡ ltiRˆR/R‰ RŠ lltjRˆR/R‹ RŒ lltkRˆR/R� RŽ lltlR� R� ltmR‘RR’R“/R” R• lltnR�RR‘R/R– R— lltoR�RR‘R/R˜ R™ lltpR¶Rš R› lltqR# )·u  Gateway lifecycle guard for cron job creation.

A cron job that restarts/stops the gateway from inside the gateway (``hermes gateway restart``,
``launchctl kickstart ai.hermes.gateway``, ``systemctl restart hermes-gateway``) kills the process,
the supervisor revives it, auto-resume re-runs the turn: a SIGTERM-respawn loop.
``cron.jobs.create_job`` rejects such specs on every creation path. Patterns are command-shaped â€”
anchored on concrete command identifiers â€” so they cannot fire on prose. Defence-in-depth layer.
)ÚannotationsN)ÚPath)ÚCallableÚIteratorÚOptionalc                  ó   € ] tR t^tRtRtR# )ÚGatewayLifecycleBlockedzARaised when a cron job spec contains a gateway-lifecycle command.© N)Ú__name__Ú
__module__Ú__qualname__Ú__firstlineno__Ú__doc__Ú__static_attributes__r	   ó    Ú9/home/ubuntu/.hermes/hermes-agent/cron/lifecycle_guard.pyr   r      s   † ÝKr   r   a¾  (?i)(?:(?<![/\w.\-])hermes(?:\.(?:exe|cmd|bat|com|ps1))?\s+gateway\s+(?:restart|stop|uninstall)\b)|(?:launchctl\s+(?:kickstart|unload|load|stop|restart|submit|bootstrap|bootout|remove|disable)\b[^\n]*\bhermes[.\-]?gateway)|(?:systemctl\s+(?:-\S+\s+)*(?:restart|stop|start)\b[^\n]*\bhermes[.\-]?gateway)|(?:\b(?:p?kill|taskkill|stop-process)\b[^\n]*\bhermes\b[^\n]*\bgateway)|(?:\b(?:p?kill|taskkill|stop-process)\b[^\n]*\bgateway\b[^\n]*\bhermes)z&^pythonw?(?:\d+(?:\.\d+)*)?(?:\.exe)?$Ú Úpkillú-uÚkillallú--userú-nÚpgrepÚpidofz[.*+?\\\[\](){}|].*$z^[.*+?$\s]*$z&(?i)\b(?:kill|taskkill|stop-process)\bzF(?i)hermes_cli|\bhermes\b[^\n]*\bgateway\b|\bgateway\b[^\n]*\bhermes\bu8  Blocked: this command kills every process whose image/name matches the Python interpreter, which is the process hosting this gateway (and this command). Stop only the process you own instead: process(action="kill", session_id="proc_â€¦") for a background job Hermes started, or kill/taskkill by its explicit PID.Ú	substringFc               ó$   € V ^8„  d   QhRRRRRR/# )é   ÚvalueÚstrr   ÚboolÚreturnr	   )Úformats   "r   Ú__annotate__r"   o   s&   € ÷ Fñ F ð F°Dð FÀTñ Fr   c               ó
  € V P                  4       P                  R4      P                  4       P                  R4      pV'       g   R# VP                  R4      '       d@   VP	                  R4      pRP                  V4      ;'       g    \        P                  V4      # \        P                  V4      '       g   V\        P                  R4      8X  d   R# T;'       d(    \        V4      ^8¬  ;'       d    RP                  V4      # )zÐTrue when *value* (a process/image name, `*`-wildcard allowed) denotes the Python interpreter
that hosts the gateway. *substring*: pkill/pgrep match an ERE anywhere in the name, so `py`
reaches `python3` too.ú"'ú.exeFÚ*ÚpythonT)
ÚstripÚlowerÚremovesuffixÚendswithÚrstripÚ
startswithÚ_HOST_INTERPRETER_NAMEÚ_INTERPRETER_IMAGE_REÚmatchÚlen)r   r   ÚnameÚprefixs   &$  r   Ú_is_interpreter_imager4   o   sÈ   € ð �;‰;‹=×Ñ˜uÓ%×+Ñ+Ó-×:Ñ:¸6ÓB€DßÙØ‡}�}�S×ÒØ—‘˜SÓ!ˆØ×"Ñ" 6Ó*×WÐWÔ.D×.OÑ.OÐPVÓ.WÐWÜ×"Ñ" 4×(Ò(¨DÔ4J×4WÑ4WÐX^Ó4_Ô,_ÙØ×EÐEœ˜T› a™×EÐE¨H×,?Ñ,?ÀÓ,EÐEr   c               ó(   € V ^8„  d   QhRRRRRRRR/# )r   Úpatternr   Úfull_cmdliner   Úexactr    r	   )r!   s   "r   r"   r"   ~   s0   € ÷ `ñ `¨sð `ÀTð `ÐRVð `Ð[_ñ `r   c               ó¾  € V P                  4       P                  R4      P                  R4      pVP                  R4      pV'       d   VP                  R4      MVRR3w  rEp\	        WB'       * R7      '       d   RM\
        P                  V4      pV'       d4   WGP                  4       R R,           V,           pVRVP                  4        p\	        WB'       * R7      '       g)   T;'       d    \        \        P                  V4      4      # VP                  4       '       * ;'       g:    \        \        P                  V4      4      ;'       g    RVP                  4       9   # )	uH  pkill/pgrep/killall operand semantics: an ERE against the process NAME (or, with `-f`, the full
command line). `python -m hermes_cli.main â€¦` is the gateway's own cmdline, so a `-f` pattern
that names the interpreter and then only wildcards or a `hermes` token reaches it, while
`python mt_add.py` (a specific script) does not.r$   Ú^Ú$Ú r   )r   NÚhermes)r(   Úlstripr*   Ú	partitionr4   Ú	_ERE_TAILÚsearchÚstartr   Ú_GATEWAY_CMDLINE_TOKEN_REÚ_ERE_WILDCARD_ONLYr0   r)   )r6   r7   r8   ÚcoreÚheadÚ_Úrestr0   s   &$$     r   Ú!_pattern_reaches_host_interpreterrI   ~   s  € ð
 �=‰=‹?× Ñ  Ó'×.Ñ.¨sÓ3€DØ×Ñ˜SÓ!€Dß+7�D—N‘N 3Ô'¸dÀBÈ¸^�M€DˆTô *¨$¼)×DÓD‰DÌ)×JZÑJZÐ[_ÓJ`€EßØ—K‘K“M�NÐ# cÕ)¨DÕ0ˆØ�O�e—k‘k“mÐ$ˆÜ  ´×;Ó;Ø×LÐL¤Ô%>×%EÑ%EÀdÓ%KÓ LÐLØ�z‰z‹|Ô×_Ð_œtÔ$6×$<Ñ$<¸TÓ$BÓC×_Ð_ÀxÐSW×S]ÑS]ÓS_ÑG_Ð_r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   r2   r   Úargsú	list[str]r    r   r	   )r!   s   "r   r"   r"   ‘   s&   € ÷ (]ñ (]¨3ð (]°ið (]ÀDñ (]r   c                óB  aa€ V R9   EdK   V R8H  ;'       g;    V R8H  \         ;QJ d    R V 4       F  '       g   K   RM	  RM! R V 4       4      8g  oV R9   ;'       d5    \         ;QJ d    R V 4       F  '       g   K   RM	  RM! R V 4       4      o. p^ pV\        V4      8  ds   W,          pVR8X  d   W!V^,           R ,          pMPV\        V ,          9   d   V^,          pKO  VP                  R	4      '       g   VP	                  V4       V^,          pK‚  \         ;QJ d     VV3R
 lV 4       F  '       g   K   R# 	  R# ! VV3R
 lV 4       4      # V R8X  d°   \        VRR 4       F›  w  r4VP                  4       P                  R4      pW^,           ,          pVR8X  d   \        V4      '       d    R# VR8X  g   KW  \        P                  ! RV4      pV'       g   Kx  \        VP                  ^4      4      '       g   Kš   R# 	  R# . p\        V4       FÑ  w  r4VP                  R4      w  rYp
VP                  4       R9   dD   TP	                  V
'       d   T
M'V^,           \        V4      8  d   W^,           ,          MR4       Kq  V R8X  g   Kz  VP                  R	4      '       d   K“  V^ 8X  g'   W^,
          ,          P                  R	4      '       d   KÀ  VP	                  V4       KÓ  	  \         ;QJ d    R V 4       F  '       g   K   R# 	  R# ! R V 4       4      # )zTWhether killer/enumerator *name* with argv *args* would select the host interpreter.r   r   c              3  ó*   "  € T F	  qR9   x € K  	  R# 5i)ú-rN)rO   z--regexpz-xz--exactr	   ©Ú.0Úts   & r   Ú	<genexpr>Ú3_killer_targets_host_interpreter.<locals>.<genexpr>•   s   é € Ð=uÑptÐklÐCfÖ>fÓptùó   ‚TFc              3  ó*   "  € T F	  qR9   x € K  	  R# 5i)ú-fN)rW   z--fullr	   rP   s   & r   rS   rT   –   s   é € Ð9^ÑY]ÐTUÐ?OÖ:OÓY]ùrU   ú--NÚ-c              3  ó@   <"  € T F  p\        VSSR 7      x € K  	  R# 5i))r7   r8   N)rI   )rQ   Úopr8   r7   s   & €€r   rS   rT   ¤   s"   øé € ÐtÑksÐegÔ4°RÀlÐZ_×`Ñ`Óksùs   ƒÚtaskkillz/-ÚimÚfiz#(?i)\s*['\"]?imagename\s+eq\s+(\S+)Ú:r   úget-processc              3  óf   "  € T F'  qP                  R 4       F  p\        V4      x € K  	  K)  	  R# 5i)Ú,N)Úsplitr4   )rQ   r   Úparts   &  r   rS   rT   ¹   s+   é € Ð\¹¨uÏ;É;ÐWZÖK[À4Ô$ T×*Ð*ÑK[Ñ*»ùs   ‚/1)r   r   r   r   )r   r   éÿÿÿÿ)z-namez-processnamer   )Úanyr1   Ú_KILLER_VALUE_OPTIONSr-   ÚappendÚ	enumerater)   r>   r4   Úrer0   Úgroupr?   )r2   rK   ÚoperandsÚpositionÚtokenÚoptionr   Úfilter_matchÚvaluesrG   Úinline_valuer8   r7   s   &&         @@r   Ú _killer_targets_host_interpreterrs   ‘   s„  ù€ àÐ5Õ5à˜‘×uÐu D¨IÑ$5¿#»#Ñ=uÑptÓ=u¿#¿#º#Ñ=uÑptÓ=uÓ:uÑ#uˆØÐ1Ñ1×^Ð^·c³cÑ9^ÑY]Ó9^·c·c²cÑ9^ÑY]Ó9^Ó6^ˆØ ˆØˆØœ˜T›Ô"Ø•NˆEØ˜Œ}Ø ¨A¥ Ð/Õ/�ØØÔ-¨dÕ3Ô3Ø˜A•�ÙØ×#Ñ# C×(Ò(Ø—‘ Ô&Ø˜�MŠHß‹sÕtÑksÓt�sŒsÐtŠsÐtˆsÕtÑksÓtÓtÐtØˆzÔÜ(¨¨c¨r¨Ö3‰OˆHØ—[‘[“]×)Ñ)¨$Ó/ˆFØ A�Õ&ˆEØ˜Œ~Ô"7¸×">Ò">ÚØ˜Ž~Ü!ŸxšxÐ(NÐPUÓV�ß‘<Ô$9¸,×:LÑ:LÈQÓ:O×$PÔ$PÚñ  4ñ ð €FÜ$ Tž?‰ˆØ"'§/¡/°#Ó"6Ñˆ�<Ø�<‰<‹>Ð<Ô<Ø�M‰M¯,™,ÐS[Ð^_ÕS_ÔbeÐfjÓbkÔSk¸TÈQÅ,Ö=OÐqsÖuØ�]Ö"¨5×+;Ñ+;¸C×+@Ô+@ÀhÐRSÄmÐ[_ÐklÕ`lÕ[m×[xÑ[xÐy|×[}Ô[}Ø�M‰M˜%Ö ñ +÷ ‹3Ñ\¹Ó\�3Œ3Ð\Š3Ð\ˆ3Ñ\¹Ó\Ó\Ð\r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   ÚtokensrL   Úkillerszfrozenset[str]r    r   r	   )r!   s   "r   r"   r"   ¼   s"   € ÷ ñ ¨Ið Àð ÐSWñ r   c                óž  € \        V 4      pVe   V.M. pT\        V 4       UUu. uF6  w  rE\        V4      P                  4       P	                  R4      V9   g   K4  VNK8  	  upp,          pV FW  p\        W,          4      P                  4       P	                  R4      pWq9   g   K9  \        WpV^,           R 4      '       g   KV   R# 	  R# u uppi )zæWhether a tokenized segment runs one of *killers* against the host interpreter. The
executable is read at the wrapper-peeled position first, then at the first killer token anywhere
in the segment (`xargs kill`, Python argv lists).Nr%   TF)Ú_executed_command_indexri   Ú_executable_namer)   r*   rs   )ru   rv   ÚindexÚ
candidatesÚirn   rm   r2   s   &&      r   Ú_segment_names_host_interpreterr}   ¼   s¸   € ô $ FÓ+€EØ!Ò-�%‘°2€JØ¤Y¨vÔ%6ÔzÑ%6™˜Ô:JÈ5Ó:Q×:WÑ:WÓ:Y×:fÑ:fÐgmÓ:nÐryÑ:y—1�1Ñ%6ÒzÕz€JÛˆÜ Õ 0Ó1×7Ñ7Ó9×FÑFÀvÓNˆØŽ?Ô?ÀÈXÐXYÍ\È]ÐF[×\Ô\Úñ ñ ùó {s   ¤1C	ÁC	c               ó    € V ^8„  d   QhRRRR/# ©r   Útextr   r    r   r	   )r!   s   "r   r"   r"   Ê   s   € ÷ ñ ¨ð °ñ r   c                óž  € \         P                  RV 4      p\        \        P	                  V4      4      p\        V4       F‰  pRP                  V4      p\        P                  RV4      pWT8w  d   W5P                  4       .MV. FA  p\        V\        4      '       d     R# V'       g   K'  \        V\        4      '       g   K?    R# 	  K‹  	  R# )aM  Branch E entrypoint: a process killer aimed at the interpreter image hosting the gateway, or a
name-derived PID feed into one (`pgrep python | xargs kill`, `kill $(pidof python3)`,
`Get-Process python | Stop-Process`). Segment-tokenized, so quoted/spliced spellings and Python
argv lists resolve the same way the shell resolves them.r<   TF)Ú_SHELL_LINE_CONTINUATIONÚsubr   Ú_KILL_VERB_RErA   Ú_iter_command_segmentsÚjoinÚ_ARGV_LIST_PUNCTUATIONrc   r}   Ú_NAME_KILLERSÚ_NAME_ENUMERATORS)r€   Ú
normalizedÚkill_verb_presentÚsegmentÚjoinedÚstrippedru   s   &      r   Úcontains_host_interpreter_killr�   Ê   sª   € ô
 *×-Ñ-¨c°4Ó8€JÜœ]×1Ñ1°*Ó=Ó>ÐÜ)¨*Ö5ˆØ—‘˜'Ó"ˆÜ)×-Ñ-¨c°6Ó:ˆð 7?Ô6H˜§¡Ó!1Ñ2ÈwÈiÒWˆFÜ.¨v´}×EÒEÛß Ñ Ô%DÀVÔM^×%_Ô%_Ûó	 Xñ 6ñ r   z\\\r?\n[ \t]*z[\[\],]+z (?i)hermes\s+(?:-\S++(?:\s++(?!-\S)\S++)?\s++)*(?:--profile=([^\s]+)|(?:-p|--profile)\s+([^\s]+))(?:\s++-\S++(?:\s++(?!-\S)\S++)?)*\s+gateway\s+(?:restart|stop)zV(?i)\blaunchctl\s+(?:kickstart|unload|load|stop|restart|bootout|kill|disable|remove)\bz(?i)\bhermes[.\-]?gateway\bú-cú	--commandi   ú;&|()zMobile DocumentsÚCloudStoragez^\.[A-Za-z]zB\|\s*&?\s*(?:sudo\s+)?(?:sh|bash|dash|ksh|zsh|xargs|eval|source)\bi   ÚsudoÚdoasÚenvÚniceÚioniceÚstdbufÚtimeoutÚpkexecÚsuÚrunuserÚsetprivúsystemd-runÚnsenterÚunshareú-Cz--adjustmentz^[A-Za-z_][A-Za-z0-9_]*=c               ó   € V ^8„  d   QhRR/# )r   r    úOptional[str]r	   )r!   s   "r   r"   r"   s  s   € ÷ "ñ "˜}ñ "r   c                 ó   € ^ RI Hp  V ! 4       # )z[Profile running the guard (``hermes_cli.profiles.current_profile_name``); ``None`` if none.©Úcurrent_profile_name)Úhermes_cli.profilesr§   r¦   s    r   Ú_current_profile_namer©   s  s   € å8áÓ!Ð!r   c               ó    € V ^8„  d   QhRRRR/# )r   Únamedr   r    r   r	   )r!   s   "r   r"   r"   z  s   € ÷ Tñ T Sð T¨Tñ Tr   c                ó¶   € \        4       p\        V4      ;'       d>    V P                  4       P                  4       VP                  4       P                  4       8H  # )z¨True when *named* is the profile executing the guard. Without a profile identity
self-targeting cannot be proven, so nothing is blocked (sibling restarts stay allowed).)r©   r   r(   Úcasefold)r«   Úcurrents   & r   Ú_named_profile_is_currentr¯   z  sA   € ô $Ó%€GÜ�‹=×SÐS˜UŸ[™[›]×3Ñ3Ó5¸¿¹»×9QÑ9QÓ9SÑSÐSr   c               ó    € V ^8„  d   QhRRRR/# )r   Únormalized_textr   r    r   r	   )r!   s   "r   r"   r"   ƒ  s   € ÷ ñ ¸3ð À4ñ r   c                óŠ   € \        \        P                  V 4      4      ;'       d    \        \        P                  V 4      4      # )uH   Order-independent companion to Branch B â€” see the verbs regex comment.)r   Ú_LAUNCHCTL_LIFECYCLE_VERBS_RErA   Ú_HERMES_GATEWAY_LABEL_RE)r±   s   &r   Ú%_contains_launchctl_gateway_lifecyclerµ   ƒ  s;   € äÔ-×4Ñ4°_ÓEÓF÷ ð Ì4Ü ×'Ñ'¨Ó8óLð r   c               ó    € V ^8„  d   QhRRRR/# r   r	   )r!   s   "r   r"   r"   Š  s   € ÷ ?kñ ?k¨Sð ?k°Tñ ?kr   c                óÜ  € V '       g   R# ^ RI Hp V! V 4      p \        P                  RV 4      p\        P                  V4      '       d   R# \        P                  V4      pV'       dc   VP                  ^4      ;'       g    VP                  ^4      pV'       d1   \        VP                  4       P                  R4      4      '       d   R# \        V4       Fv  pRP                  V4      pV'       d   \        P                  V4      '       d    R# \        P                  RV4      pWv8w  g   KX  \        P                  V4      '       g   Ku   R# 	  \        V4      ;'       g    \        V4      # )u  Return True if *text* contains a gateway lifecycle command pattern.

Passes, in order: raw-text regex (the only pass that fires on inputs shlex cannot tokenize, e.g.
Python source); profile-flag form; the same regex on each shell-tokenized segment with quotes/
escapes resolved (closes splice bypasses like ``kick"start"`` / ``kick\start``);
order-independent launchctl pass. Single choke point for every recursion level of
``_contains_unsafe_gateway_action``.

That second pass exists because a real shell resolves quote-splicing (``kick"start"``) and
backslash-escaping (``kick\start``) into one literal word â€” ``kickstart`` â€” before the command ever
runs. The raw text still has the quote or backslash sitting between the verb's two halves, so the first
pass alone lets a spliced verb reach ``launchctl``/``systemctl`` untouched while still executing as the
blocked lifecycle command (#80269, reported against #80260's bootout parity fix). Tokenizing closes that
gap while keeping the same gateway-label anchoring (``_GATEWAY_LIFECYCLE_PATTERN`` still requires a
``hermes``/``gateway`` token) â€” this function is the single choke point
``_contains_unsafe_gateway_action`` calls at every recursion level, so referenced-script and ``sh -c``
payload scanning inherit the fix automatically.
F©Ústrip_inert_heredoc_bodiesr<   Tr$   )Útools.shell_heredocr¹   r‚   rƒ   Ú_GATEWAY_LIFECYCLE_PATTERNrA   Ú_PROFILE_FLAG_LIFECYCLE_PATTERNrk   r¯   r(   r…   r†   r‡   rµ   r�   )r€   r¹   rŠ   Úprofile_matchr«   rŒ   r�   rŽ   s   &       r   Ú"contains_gateway_lifecycle_commandr¾   Š  s  € ÷& Ùõ ?á% dÓ+€DÜ)×-Ñ-¨c°4Ó8€JÜ!×(Ñ(¨×4Ò4Ùô 4×:Ñ:¸:ÓF€MßØ×#Ñ# AÓ&×@Ð@¨-×*=Ñ*=¸aÓ*@ˆ÷ Ô.¨u¯{©{«}×/BÑ/BÀ5Ó/I×JÒJÙô *¨*Ö5ˆØ—‘˜'Ó"ˆßÔ0×7Ñ7¸×?Ò?ÚÜ)×-Ñ-¨c°6Ó:ˆØÖÔ"<×"CÑ"CÀH×"MÔ"MÚñ 6ô 1°Ó<×jÐjÔ@^Ð_iÓ@jÐjr   i @  c                  óN   € ] tR tRtRtRtR R ltR R ltR R ltR	 R
 lt	Rt
R# )Ú_LifecycleScanBudgetiÛ  a	  Shared work budget for one complete referenced-script walk. ``refusal`` records why the walk
failed closed for a reason other than a lifecycle command (budget, size, device, live SQLite,
cloud placeholder) so the caller can tell the model the real reason (#113944).c               ó   € V ^8„  d   QhRR/# )r   r    ÚNoner	   )r!   s   "r   r"   Ú!_LifecycleScanBudget.__annotate__è  s   € ÷ +ñ +˜$ñ +r   c                	ól   € \         V n        \        V n        \        V n        \        V n        R V n        R # ©N)	Ú_MAX_LIFECYCLE_SCAN_BYTESÚbytes_remainingÚ_MAX_LIFECYCLE_SCAN_LINESÚlines_remainingÚ_MAX_LIFECYCLE_SCAN_PATHSÚpaths_remainingÚ _MAX_LIFECYCLE_SCAN_REMOTE_READSÚremote_reads_remainingÚrefusal©Úselfs   &r   Ú__init__Ú_LifecycleScanBudget.__init__è  s)   € ä8ˆÔÜ8ˆÔÜ8ˆÔÜ&FˆÔ#Ø&*ˆŽr   c               ó    € V ^8„  d   QhRRRR/# r   r	   )r!   s   "r   r"   rÃ   ð  s   € ÷ ñ  ð ¨ñ r   c                ó²  € \        V4      V P                  8”  d   R# \        VP                  RRR7      4      pW P                  8”  d   R# VP                  R4      ^,           pW0P                  8”  d   R# \        R VP                  R4       4       ^ R7      pV\        8”  d   R# V ;P                  V,          un        V ;P                  V,          un        R# )	z>Charge *text* before tokenization; False when it does not fit.Fúutf-8Úreplace©ÚerrorsÚ
c              3  ó8   "  € T F  p\        V4      x € K  	  R # 5irÅ   )r1   )rQ   Úlines   & r   rS   Ú3_LifecycleScanBudget.charge_text.<locals>.<genexpr>ý  s   é € Ð>Ñ-= T”s˜4—y�yÓ-=ùs   ‚)ÚdefaultT)r1   rÇ   ÚencodeÚcountrÉ   Úmaxrc   Ú_MAX_LIFECYCLE_SCAN_LINE_BYTES)rÐ   r€   ÚencodedÚlinesÚlongests   &&   r   Úcharge_textÚ _LifecycleScanBudget.charge_textð  s¯   € ô ˆt‹9�t×+Ñ+Ô+ÙÜ�d—k‘k '°)�kÓ<Ó=ˆØ×)Ñ)Ô)ÙØ—
‘
˜4Ó  1Õ$ˆØ×'Ñ'Ô'Ùô Ñ>¨T¯Z©Z¸Ô-=Ó>ÈÔJˆØÔ3Ô3ÙØ×Ò Õ'ÕØ×Ò Õ%ÕÙr   c               ó   € V ^8„  d   QhRR/# ©r   r    r   r	   )r!   s   "r   r"   rÃ     s   € ÷ ñ ˜Tñ r   c                ó^   € V P                   ^ 8:  d   R# V ;P                   ^,          un         R# )z?Charge one unique referenced path before any local/remote read.FT)rË   rÏ   s   &r   Úcharge_pathÚ _LifecycleScanBudget.charge_path  s'   € à×Ñ 1Ô$ÙØ×Ò Õ!ÕÙr   c               ó   € V ^8„  d   QhRR/# rè   r	   )r!   s   "r   r"   rÃ     s   € ÷ ñ  Dñ r   c                ó^   € V P                   ^ 8:  d   R# V ;P                   ^,          un         R# )z:Charge one remote-backend read (a network roundtrip each).FT)rÍ   rÏ   s   &r   Úcharge_remote_readÚ'_LifecycleScanBudget.charge_remote_read  s'   € à×&Ñ&¨!Ô+ÙØ×#Ò# qÕ(Õ#Ùr   )rÇ   rÉ   rË   rÎ   rÍ   N)r
   r   r   r   r   Ú	__slots__rÑ   rå   rê   rî   r   r	   r   r   rÀ   rÀ   Û  s(   † ñVð€Iõ+õõ(÷ñ r   rÀ   c               ó    € V ^8„  d   QhRRRR/# )r   Ú	max_bytesúOptional[int]r    Úintr	   )r!   s   "r   r"   r"     s   € ÷ Eñ E -ð E°Cñ Er   c           	     ó\   € V f   \         # \        \         \        ^ \        V 4      4      4      # )z�Per-read byte cap: never above the per-file cap, never negative. One definition so local and
remote reads cannot diverge.

See #76762, #77703.
)Ú_MAX_REFERENCED_SCRIPT_BYTESÚminrà   rô   ©rò   s   &r   Ú_capped_read_limitrù     s)   € ð ÒÜ+Ð+ÜÔ+¬S°´C¸	³NÓ-CÓDÐDr   c               ó    € V ^8„  d   QhRRRR/# r   r	   )r!   s   "r   r"   r"     s   € ÷ ñ ¨Cð °Dñ r   c                óZ   €  \        4       P                  V 4      #   \         d     R# i ; i)us  Whether *text* may safely enter an optional tokenizer pass (``tools/terminal_tool.py`` gates
its launchctl pre-scan on this). A FRESH budget, independent of the full guard's walk: the
pre-scan may pass while the walk later exhausts, still fail-closed â€” only the friendlier
launchctl diagnostic is lost. ``False`` is not a verdict: callers must still run the full guard.F)rÀ   rå   Ú	Exception)r€   s   &r   Ú!lifecycle_scan_root_within_budgetrý     s-   € ð
Ü#Ó%×1Ñ1°$Ó7Ð7øÜô Úðús   ‚ ›*©*c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r   ÚbudgetrÀ   Úwhatr   Údepthrô   r    r   r	   )r!   s   "r   r"   r"   )  s)   € ÷ ñ Ð2ð ¸#ð Àcð Èdñ r   c                óN   € \         P                  R W4       RV RV R2V n        R# )u   lifecycle guard scan budget exhausted (%s at depth %d); failing closed â€” see _MAX_LIFECYCLE_SCAN_* in cron/lifecycle_guard.pyzthe scan budget was exhausted (z
 at depth Ú)T©ÚloggerÚwarningrÎ   )rÿ   r   r  s   &&&r   Ú_budget_exhaustedr  )  s2   € Ü
‡N�Nð	Ràôð
 7°t°f¸JÀuÀgÈQÐO€F„NÙr   c               ó    € V ^8„  d   QhRRRR/# )r   Úpathr   r    r   r	   )r!   s   "r   r"   r"   3  s   € ÷ wñ w˜Tð w cñ wr   c                ó  € ^ RI Hp V! V 4      '       d   RV  R2#  \        P                  ! V 4      p\        P
                  ! TP                  4      '       g   RT  R2# RT  R\         R2#   \         d
    RT  R2u # i ; i)z®Name why an *executed* script failed closed without being scanned (live SQLite, device,
oversized). Message-only: the fail-closed verdict itself came from the bounded reader.)Úhas_live_connectionÚ`z3` is a SQLite database open in this gateway processz` could not be readz` is not a regular filez` is larger than the scan cap (ú$ bytes) or the remaining walk budget)Úhermes_cli.sqlite_safe_readr  ÚosÚstatÚOSErrorÚS_ISREGÚst_moderö   )r	  r  Úmetadatas   &  r   Ú_unreadable_reasonr  3  s–   € õ @á˜4× Ò Ø�4�&ÐKÐLÐLð-Ü—7’7˜4“=ˆô �<Š<˜×(Ñ(×)Ò)Ø�4�&Ð/Ð0Ð0ØˆtˆfÐ3Ô4PÐ3QÐQuÐvÐvøô	 ô -Ø�4�&Ð+Ð,Ò,ð-ús   œA+ Á+A?Á>A?c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r   rÿ   rÀ   r	  r   Úreasonr   r    r   r	   )r!   s   "r   r"   r"   C  s*   € ÷ ñ Ð3ð ¸4ð Èð ÐQUñ r   c                ó>   € \         P                  R W4       W n        R# )zDlifecycle guard cannot scan referenced script %s: %s; failing closedTr  )rÿ   r	  r  s   &&&r   Ú_refuse_unreadabler  C  s   € Ü
‡N�NÐYÐ[_ÔhØ„NÙr   c               ó    € V ^8„  d   QhRRRR/# )r   r€   r   r    rL   r	   )r!   s   "r   r"   r"   K  s   € ÷ ñ ˜sð  yñ r   c                ó˜  € . p. pR;p;rEV  F’  pV'       d   RpMsVR8X  d   RpMiVR8X  d   V'       g	   V'       * pMRVR8X  d   V'       g	   V'       * pM;VR8X  d5   V'       g-   V'       g%   VP                  RP                  V4      4       . pK�  VP                  V4       K”  	  V'       d!   VP                  RP                  V4      4       V# )z]Split on newlines outside quotes (a quoted newline is data, not a separator); honors
escapes.FÚ\TÚ'Ú"rÙ   r   )rh   r†   )r€   rã   r®   Ú	in_singleÚ	in_doubleÚescapeÚchs   &      r   Ú_split_logical_linesr#  K  s¬   € ð €EØ€GØ%*Ð*€IÐ*�	ÛˆßØ‰FØ�4ŒZØ‰FØ�3ŒYŸyØ%œ‰IØ�3ŒYŸyØ%œ‰IØ�4ŒZ§	·)Ø�L‰L˜Ÿ™ Ó)Ô*ØˆGÙØ�‰�rÖñ ÷ Ø�‰�R—W‘W˜WÓ%Ô&Ø€Lr   c               ó    € V ^8„  d   QhRRRR/# )r   rÛ   r   r    rL   r	   )r!   s   "r   r"   r"   d  s   € ÷ ñ ˜ð  	ñ r   c                óf   € \         P                   ! V RRR7      pRVn        RVn        \        V4      # )zSPOSIX-tokenize one shell line, honoring quotes and `#` comments; raises ValueError.Tr’   )ÚposixÚpunctuation_charsÚ#)ÚshlexÚwhitespace_splitÚ
commentersÚlist)rÛ   Úlexers   & r   Ú_shlex_tokensr.  d  s.   € ä�KŠK˜ D¸GÔD€EØ!€EÔØ€EÔÜ�‹;Ðr   Úkeep_controlsc               ó$   € V ^8„  d   QhRRRRRR/# )r   ru   rL   r/  r   r    úIterator[list[str]]r	   )r!   s   "r   r"   r"   l  s"   € ÷ ñ ˜Ið ¸ð ÐJ]ñ r   c             #  óÔ   "  € . pV  FM  pV'       d2   \        V4      \        8:  d   V'       d   Vx € . pV'       d   V.x € K<  VP                  V4       KO  	  V'       d   Vx € R# R# 5i)z±Yield non-empty runs of *tokens* between control-operator tokens; with *keep_controls* each
control token is also yielded as its own segment so the line can be rebuilt in order.N)ÚsetÚ_CONTROL_CHARSrh   )ru   r/  rŒ   rn   s   &$  r   Ú_split_segmentsr5  l  sY   é € ð €GÛˆß”S˜“Z¤>Ô1ßØ’Ø�ßØ�g’ÙØ�‰�uÖñ ÷ ØŒñ ùs   ‚+A(®A(¼#A(Á A(c               ó    € V ^8„  d   QhRRRR/# )r   Úcommandr   r    r1  r	   )r!   s   "r   r"   r"   }  s   € ÷ +ñ + Cð +Ð,?ñ +r   c              #  óF  "  € \        V P                  RR4      4       F"  p \        V4      p\        T4       Rj  x€L
  K$  	  R#   \         dL    TP	                  4        F3  p \        \        T4      4       Rj  x€L 
  K#    \         d     K1  i ; i	   K}  i ; i Lc5i)z�Yield shell-tokenized command segments per logical line; a line shlex rejects (unbalanced
quotes) falls back to per-physical-line tokenization.z\
r   N)r#  rÖ   r.  Ú
ValueErrorÚ
splitlinesr5  )r7  rÛ   ru   Úphysical_lines   &   r   r…   r…   }  s—   é € ô % W§_¡_°V¸RÓ%@ÖAˆð	Ü" 4Ó(ˆFô # 6Ó*×*Ò*ó Bøô ô 	Ø!%§¡Ö!2�ðÜ.¬}¸]Ó/KÓL×LÓLøÜ!ô Úðúñ "3ò
 ð	úñ 	+ùsa   ‚B!¢A­B!»B¼
B!ÁBÁ%BÁ<A?
Á=BÂBÂB	ÂBÂB	ÂBÂB!ÂBÂB!c               ó    € V ^8„  d   QhRRRR/# )r   rn   r   r    r	   )r!   s   "r   r"   r"   �  s   € ÷ %ñ %˜Cð % Cñ %r   c                ó@   € \        V 4      P                  ;'       g    T # )zäCommand name of an executable token. ``Path(token).name`` is "" for ``.``, ``..`` and ``/``;
the POSIX dot-source builtin is spelled ``.``, so fall back to the raw token or ``.
./helper.sh`` would escape the sourced-script scan.)r   r2   )rn   s   &r   ry   ry   �  s   € ô �‹;×Ñ×$Ð$˜uÐ$r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   rŒ   rL   rz   rô   r    r	   )r!   s   "r   r"   r"   ”  s!   € ÷ ñ ¨	ð ¸#ð À#ñ r   c                óœ  € \        \        4       EF7  pV\        V 4      8¼  d   Vu # \        W,          4      pV\        9  d   Vu # \
        P                  V\        4       4      pV^,          pV\        V 4      8  di   W,          pVR8X  d   V^,          pMOWT9   d   V^,          pK:  VP                  R4      '       g   \        P                  V4      '       d   V^,          pKw   \        \        P                  V^ 4      4       F=  pV\        V 4      8  g   K  W,          P                  R4      '       d   K4  V^,          pK?  	  EK:  	  V# )u¨   Index of the command a wrapper chain actually executes. Unchanged if not a wrapper; may be
``len(segment)`` when a wrapper has no operand â€” callers must bounds-check.rX   rY   )ÚrangeÚ_MAX_PREFIX_PEELSr1   ry   Ú_TRANSPARENT_COMMAND_PREFIXESÚ!_TRANSPARENT_PREFIX_VALUE_OPTIONSÚgetÚ	frozensetr-   Ú_ENV_ASSIGNMENTr0   Ú_TRANSPARENT_PREFIX_OPERANDS)rŒ   rz   rG   r2   Úvalue_optionsrn   s   &&    r   Ú_peel_transparent_prefixesrI  ”  s  € ô Ô$×%ˆØ”C˜“LÔ ØŠLÜ ¥Ó/ˆØÔ4Ô4ØŠLÜ9×=Ñ=¸dÄIÃKÓPˆØ��
ˆØ”c˜'“lÔ"Ø•NˆEØ˜Œ}à˜•
�ØØÔ%Ø˜•
�ÙØ×Ñ ×$Ò$¬×(=Ñ(=¸e×(DÒ(DØ˜•
�ÙØÜÔ3×7Ñ7¸¸aÓ@ÖAˆAØ”s˜7“|Ö#¨G­N×,EÑ,EÀc×,JÔ,JØ˜•
’ô Bñ+ &ð0 €Lr   c               ó    € V ^8„  d   QhRRRR/# ©r   rŒ   rL   r    ró   r	   )r!   s   "r   r"   r"   ²  s   € ÷ bñ b )ð b°ñ br   c                ó:   € \        R \        V 4       4       R4      # )z?Return the executable token index after simple env assignments.c              3  ód   "  € T F&  w  r\         P                  V4      '       d   K"  Vx € K(  	  R # 5irÅ   )rF  r0   )rQ   r|   rn   s   &  r   rS   Ú'_command_token_index.<locals>.<genexpr>´  s$   é € ÐZÑ#5‘x�q¼_×=RÑ=RÐSX×=Y—’Ó#5ùs   ‚0¦
0N)Únextri   )rŒ   s   &r   Ú_command_token_indexrP  ²  s   € äÑZ¤9¨WÔ#5ÓZÐ\`ÓaÐar   c               ó    € V ^8„  d   QhRRRR/# rK  r	   )r!   s   "r   r"   r"   ·  s   € ÷ 3ñ 3 Yð 3°=ñ 3r   c                ób   € \        V 4      pVf   R# \        W4      pV\        V 4      8  d   V# R# )zWIndex of the command a segment actually executes (env assignments and wrappers peeled).N)rP  rI  r1   )rŒ   rz   s   & r   rx   rx   ·  s4   € ä  Ó)€EØ‚}ÙÜ& wÓ6€EØœC ›LÔ(ˆ5Ð2¨dÐ2r   c               ó    € V ^8„  d   QhRRRR/# ©r   r7  r   r    r   r	   )r!   s   "r   r"   r"   À  s   € ÷ ñ ¨sð °tñ r   c                óä   € \        V 4       F`  p\        V4      pVf   K  \        W,          4      R8X  g   K,  W^,           R pV'       g   KA  V^ ,          P                  4       R9   g   K_   R# 	  R# )u  Detect an executed ``launchctl submit``/``bootstrap``, not quoted text.

Label-independent by design: a NEW job's label is attacker-chosen, so a neutral name defeats any
label-anchored regex. Both verbs register a persistent launchd job â€” never safe in the gateway.

See #62891.
NÚ	launchctlTF>   ÚsubmitÚ	bootstrap)r…   rx   ry   r)   )r7  rŒ   rz   Ú	argumentss   &   r   Ú!contains_launchctl_submit_commandrZ  À  sb   € ô *¨'Ö2ˆÜ'¨Ó0ˆØÔÔ!1°'µ.Ó!AÀ[Ö!PØ¨¥	 Ð,ˆIß‰y˜Y q�\×/Ñ/Ó1Ð5LÖLÚñ 3ñ r   c               ó    € V ^8„  d   QhRRRR/# )r   r€   r   r    r	   )r!   s   "r   r"   r"   Ñ  s   € ÷ %5ñ %5 Cð %5¨Cñ %5r   c                ó0  € . pRpV P                  4       ;'       g    V . EF4  p\        P                  V4      '       d   VP                  V4       K2   \	        V4      p. p\        TRR7       FÃ  p\        T4      pTe¡   \        Yg,          4      P                  \        9   d}   Yg^,           R p\        ;QJ d    R T 4       F  '       g   K   RM	  RM! R T 4       4      '       g8   RpTP                  TRT^,            4       TP                  R T 4       4       K²  TP                  T4       KÅ  	  TP                  RP                  T4      4       EK7  	  V'       d   RP                  V4      # T #   \
         d    TP                  T4        EKt  i ; i)	a  Replace data-sink executables' arguments with a neutral placeholder.

The regex cannot tell an EXECUTED lifecycle command from the same characters as *data* (a grep
pattern, a SQL literal): every argument of a ``_DATA_SINK_EXECUTABLES`` segment becomes ``arg``
and a match that survives is a real command. Strictly fail-closed: masking is skipped when the
line pipes into a shell/interpreter, any argument carries an execution marker, or the line
cannot be tokenized. Masking can only ALLOW what the plain regex would block, never block more.
FT)r/  Nc              3  óâ   a"  € T Fd  o\         P                  S4      ;'       gC    \        ;QJ d#    V3R  l\         4       F  '       g   K   RM	  RM! V3R  l\         4       4      x € Kf  	  R# 5i)c              3  ó,   <"  € T F	  qS9   x € K  	  R # 5irÅ   r	   )rQ   ÚmarkerÚarguments   & €r   rS   Ú6_mask_data_sink_arguments.<locals>.<genexpr>.<genexpr>í  s   øé € ÐUÑ<T°& XÖ-Ó<Tùs   ƒTFN)Ú_DOT_COMMAND_ARGUMENTr0   rf   Ú_UNSAFE_DATA_ARG_MARKERS)rQ   r`  s   &@r   rS   Ú,_mask_data_sink_arguments.<locals>.<genexpr>ë  sW   øé € ð ñ %.˜ô *×/Ñ/°Ó9÷ Vð Vß“sÔUÕ<TÓU—s—s’sÔUÕ<TÓUÓUôVã$-ùs   ƒ A/¤A/°A/Á$A/c              3  ó&   "  € T F  pR x € K	  	  R# 5i)ÚargNr	   )rQ   rG   s   & r   rS   rd  ò  s   é € Ð"<±)¨Q¥5³)ùs   ‚r<   rÙ   )r:  Ú_PIPE_TO_INTERPRETERrA   rh   r.  r9  r5  rP  r   r2   Ú_DATA_SINK_EXECUTABLESrf   Úextendr†   )	r€   Ú	lines_outÚchangedrÛ   ru   ÚrebuiltrŒ   rz   rY  s	   &        r   Ú_mask_data_sink_argumentsrm  Ñ  sn  € ð €IØ€GØ—‘Ó!×+Ð+ d VÓ+ˆÜ×&Ñ& t×,Ò,Ø×Ñ˜TÔ"Ùð	Ü" 4Ó(ˆFð
  ˆÜ& v¸T×BˆGÜ(¨Ó1ˆEØÒ ¤T¨'­.Ó%9×%>Ñ%>ÔBXÔ%XØ#¨A¥I KÐ0�	ß“sñ ñ %.ó—s—s’sñ ñ %.ó÷ ò ð
 #�GØ—N‘N 7¨;¨U°Q­YÐ#7Ô8Ø—N‘NÑ"<±)Ó"<Ô<ÙØ�N‰N˜7Ö#ñ Cð 	×Ñ˜Ÿ™ 'Ó*×+ñ3 ,÷4 $+ˆ4�9‰9�YÓÐ4°Ð4øô) ô 	Ø×Ñ˜TÔ"Ûð	ús   ÁE4Å4FÆFc               ó    € V ^8„  d   QhRRRR/# r   r	   )r!   s   "r   r"   r"   ù  s   € ÷ Uñ U°cð U¸dñ Ur   c                ó|   € \        V 4      '       g   R# \        P                  RV 4      p\        \        V4      4      # )z¯Lifecycle scan exempting matches inside data arguments: cheap regex first (no-match pays
nothing), then re-scan with data-sink arguments masked; only a surviving match blocks.Fr<   )r¾   r‚   rƒ   rm  )r€   rŠ   s   & r   Ú+_lifecycle_command_scan_with_data_exemptionrp  ù  s5   € ô .¨d×3Ò3ÙÜ)×-Ñ-¨c°4Ó8€JÜ-Ô.GÈ
Ó.SÓTÐTr   c               ó    € V ^8„  d   QhRRRR/# rT  r	   )r!   s   "r   r"   r"     s   € ÷ ñ  Cð ¨Dñ r   c                ó>   € \        V 4      ;'       g    \        V 4      # )zCPure-string direct scans: lifecycle regex (data-exempted) + submit.)rp  rZ  )r7  s   &r   Ú_direct_lifecycle_scanrs    s#   € ô 	4°GÓ<÷ 	6ð 	6Ü,¨WÓ5ðr   c               ó    € V ^8„  d   QhRRRR/# )r   r	  r   r    r	   )r!   s   "r   r"   r"     s   € ÷ ñ ˜4ð  Dñ r   c                óZ   €  V P                  RR7      #   \        \        3 d    T u # i ; i)u³   ``path.resolve(strict=False)``, falling back to *path* on OSError (unreadable/long) or
ValueError (embedded NUL from decoded binary tokenized as a path) â€” never crash the guard.F)Ústrict)Úresolver  r9  ©r	  s   &r   Ú_resolve_lenientry    s1   € ðØ�|‰| 5ˆ|Ó)Ð)øÜ”ZÐ ô ØŠðús   ‚ ”*©*c               ó    € V ^8„  d   QhRRRR/# ©r   r	  r   r    r   r	   )r!   s   "r   r"   r"     s   € ÷ 	ñ 	 Tð 	¨dñ 	r   c                ó´   a€ V P                   o\        ;QJ d(    V3R l\        S4       4       F  '       g   K   R# 	  R# ! V3R l\        S4       4       4      # )a  True for paths inside a macOS FileProvider-backed subtree. ``O_NONBLOCK`` does not make
regular-file reads non-blocking, so opening an evicted placeholder can wait indefinitely for
hydration before any command timeout starts: identify the boundary from the path alone.c              3  ó„   <"  € T F5  w  rV'       g   K  SV^,
          ,          R8H  ;'       d
    V\         9   x € K7  	  R# 5i)é   ÚLibraryN)Ú_CLOUD_PLACEHOLDER_MARKERS)rQ   rz   rd   Úpartss   &  €r   rS   Ú-_is_cloud_placeholder_path.<locals>.<genexpr>  s?   øé € ð á+‰KˆEÜô 	Mˆˆe�a�iÕ˜IÑ%×LÐL¨$Ô2LÑ*LÔLÛ+ùs   ƒA ”A ®A TF)r�  rf   ri   )r	  r�  s   &@r   Ú_is_cloud_placeholder_pathrƒ    sS   ø€ ð �J‰J€Eß‹3ô ä$ UÔ+ó�3Œ3ð Š3ð ˆ3ô ä$ UÔ+óó ð r   c               ó    € V ^8„  d   QhRRRR/# r{  r	   )r!   s   "r   r"   r"   !  s   € ÷ bñ b˜ð b $ñ br   c                óP   € \        V 4      ;'       g    \        \        V 4      4      # )zWLexical OR resolved cloud check: covers direct cloud paths and local symlinks into one.)rƒ  ry  rx  s   &r   Ú_on_cloud_pathr†  !  s"   € ä% dÓ+×aÐaÔ/IÔJZÐ[_ÓJ`Ó/aÐar   c               ó    € V ^8„  d   QhRRRR/# )r   Ú	candidater   r    úOptional[Path]r	   )r!   s   "r   r"   r"   &  s   € ÷ ñ  cð ¨nñ r   c                ó’   € V '       d   RV 9   d   R#  \        V 4      P                  4       #   \        \        \        3 d     R# i ; i)u  Sanitize a tokenized path candidate at the ingestion boundary. Tokens from shlex-splitting
arbitrary (possibly binary-decoded) text can carry NUL or junk that each downstream ``Path`` op
rejects differently (ValueError, RuntimeError when HOME is unset under launchd, OSError); reject
once here. ``None`` = not a real path, nothing to scan.

Every OS-facing ``Path`` operation downstream (``expanduser``, ``os.open``, ``resolve``) raises a
*different* exception for the same junk (``ValueError: embedded null byte``, ``RuntimeError: Could not
determine home directory`` when HOME is unset under launchd, OSError for over-long paths). Rejecting
here â€” once, before any OS call â€” is the whole-class fix; catching per-syscall was the whack-a-mole that
produced #76762, #77703, #77780, and #78256.
Ú N)r   Ú
expanduserr9  ÚRuntimeErrorr  )rˆ  s   &r   Ú_expand_candidate_pathrŽ  &  sB   € ÷ ˜ )Ô+ÙðÜ�I‹×)Ñ)Ó+Ð+øÜœ¤gÐ.ô Úðús   “, ¬AÁAc               ó$   € V ^8„  d   QhRRRRRR/# )r   rˆ  r   Úcwdr¤   r    úIterator[Path]r	   )r!   s   "r   r"   r"   :  s!   € ÷ ñ  Cð ¨mð Àñ r   c              #  óè   "  € \        V 4      pVf   R# VP                  4       '       g1    \        T;'       g    \        P                  ! 4       4      V,          pVx € R#   \         d     R# i ; i5i)zPYield *candidate* anchored on *cwd* (or the process cwd) when it is a real path.N)rŽ  Úis_absoluter   r�  r  )rˆ  r�  r	  s   && r   Ú_resolved_or_nothingr”  :  sb   é € ä! )Ó,€DØ‚|ÙØ×Ñ×Òð	Ü˜×)Ð)œtŸxšx›zÓ*¨TÕ1ˆDð „Jøô ô 	âð	üs-   ‚'A2«A  ¹!A  ÁA2Á A/Á+A2Á.A/Á/A2c               ó    € V ^8„  d   QhRRRR/# )r   Úscript_pathr   r    r‰  r	   )r!   s   "r   r"   r"   H  s   € ÷ ñ  cð ¨nñ r   c                ó¼   € ^ RI Hp \        V 4      pVf   R# VP                  4       '       d   V#  V! 4       R,          V,          #   \        \
        3 d     R# i ; i)zªResolve a cron ``script`` value the way ``cron.scheduler`` does (relative paths live under
``<HERMES_HOME>/scripts/``) so the guard scans the file that will actually run.)Úget_hermes_homeNÚscripts)Úhermes_constantsr˜  rŽ  r“  r�  r  )r–  r˜  Úraws   &  r   Ú_resolve_script_pathrœ  H  s\   € õ 1ä
  Ó
-€CØ
‚{ÙØ
‡�×ÒØˆ
ðÙÓ  9Õ,¨sÕ2Ð2øÜœ'Ð"ô ò ðús   ±A ÁAÁAc               ó    € V ^8„  d   QhRRRR/# )r   r–  r   r    r¤   r	   )r!   s   "r   r"   r"   Z  s   € ÷ ñ ¨3ð °=ñ r   c                ó    €  \        V 4      pVe,   VP                  4       '       d   \        VP                  4      # R#   \         d     R# i ; i)zHReturn the directory *script_path* resolves to, handling relative names.N)rœ  r“  r   Úparentrü   )r–  r	  s   & r   Ú_resolve_script_directoryr   Z  sP   € ðÜ# KÓ0ˆØÒ × 0Ñ 0× 2Ò 2Ü�t—{‘{Ó#Ð#ñ øô ô ØÙðús   ‚$> §> ¾AÁAc               ó(   € V ^8„  d   QhRRRRRRRR/# )	r   rŒ   rL   rB   rô   ro   r   r    úIterator[str]r	   )r!   s   "r   r"   r"   g  s(   € ÷ &ñ & ð &°3ð &Àð &Èñ &r   c              #  ó(  "  € VR,           p\        V^,           \        V 4      4       Fd  pW,          pWR8X  d+   V^,           \        V 4      8  d   W^,           ,          x € K;  VP                  V4      '       g   KT  V\        V4      R x € Kf  	  R# 5i)zIYield values given to *option*, in both ``--opt v`` and ``--opt=v`` form.Ú=N)r@  r1   r-   )rŒ   rB   ro   r3   rm   rn   s   &&&   r   Ú_iter_option_valuesr¥  g  sr   é € à�c�\€FÜ˜% !�)¤S¨£\Ö2ˆØÕ!ˆØŒ?˜x¨!�|¬c°'«lÔ:Ø Q�,Õ'Ô'Ø×Ñ˜f×%Ô%Øœ˜F›˜Ð%Ô%ó 3ùs   ‚A5BÁ<Bc               ó(   € V ^8„  d   QhRRRRRRRR/# )	r   rŒ   rL   rz   rô   r�  r¤   r    r‘  r	   )r!   s   "r   r"   r"   r  s(   € ÷ $9ñ $9˜Ið $9¨cð $9¸ð $9È.ñ $9r   c              #  ó  "  € V\        V 4      8¼  d   R# W,          p\        V4      pVR9   d;   \        V 4      V^,           8”  d"   \        W^,           ,          V4       Rj  x€L
  R# V\        9   d¹   W^,           R p^ pV\        V4      8  d_   WV,          pVR8X  d   V^,          pMEV\        9   d   M9V\
        9   d   V^,          pKK  VP                  R4      '       d   V^,          pKm   V\        V4      8  d,   WV,          \        9  d   \        WV,          V4       Rj  x€L
  R# VP                  R4      '       d6   RV9   g   VP                  R4      '       d   \        W24       Rj  x€L
  R# R# R#  EL LW L5i)z8Yield the scripts the token at *index* executes, if any.NrX   rY   Ú/>   Ú.Úsource)z.shz.bashz.zsh)	r1   ry   r”  Ú_SHELL_EXECUTABLESÚ_SHELL_COMMAND_FLAGSÚ_SHELL_OPTIONS_WITH_VALUESr-   r(   r+   )rŒ   rz   r�  Ú
executableÚexecutable_namerY  Ú	arg_indexr`  s   &&&     r   Ú_references_atr±  r  s\  é € à”�G“ÔÙØ•€JÜ& zÓ2€Oà˜/Ô)Üˆw‹<˜% !�)Ô#Ü+¨G¸AµIÕ,>ÀÓD×DÐDÙàÔ,Ô,Ø A�I˜KÐ(ˆ	Øˆ	Øœ#˜i›.Ô(Ø Õ+ˆHØ˜4ÔØ˜Q•�	ØØÔ/Ô/ØØÔ5Ô5Ø˜Q•�	ÙØ×"Ñ" 3×'Ò'Ø˜Q•�	ÙØØ”s˜9“~Ô%¨)Õ*>ÔFZÔ*ZÜ+¨IÕ,@À#ÓF×FÐFÙð ×Ñ˜×Ò #¨Ô"3°z×7JÑ7JÐKc×7dÒ7dÜ'¨
Ó8×8Ò8ñ 8eÑò5 Eñ* Gñ 	9ùsD   ‚A FÁ"E:Á#A?FÃ#AFÄ%E=Ä&FÅ,FÅ/E?Å0FÅ=FÅ?Fr�  c               ó$   € V ^8„  d   QhRRRRRR/# )r   r7  r   r�  r¤   r    r‘  r	   )r!   s   "r   r"   r"   ™  s"   € ÷ <ñ <¨Cð <¸ð <ÐR`ñ <r   c             #  óÒ   "  € \        V 4       FO  p\        V4      pVf   K  \        W#V4       Rj  x€L
  \        W#4      pWC8w  g   K;  \        W$V4       Rj  x€L
  KQ  	  R#  L1 L5i)u  Yield scripts executed directly or through a POSIX shell. Each segment is read at the
original token AND at the peeled wrapper target â€” additive on purpose: peeling must never REMOVE
a reference (a local ``./timeout`` is a script, not the coreutils wrapper).N)r…   rP  r±  rI  )r7  r�  rŒ   rz   Úpeeleds   &$   r   Ú_iter_referenced_shell_scriptsrµ  ™  sa   é € ô *¨'Ö2ˆÜ$ WÓ-ˆØŠ=ÙÜ! '°#Ó6×6Ð6Ü+¨GÓ;ˆØŽ?Ü% g°sÓ;×;Ò;ó 3ñ 	7ñ <ùs'   ‚/A'±A#²A'Á	A'ÁA%ÁA'Á%A'c               ó    € V ^8„  d   QhRRRR/# )r   r7  r   r    r¢  r	   )r!   s   "r   r"   r"   §  s   € ÷ ñ ¨#ð °-ñ r   c              #  ó°  "  € \        V 4       FÀ  p\        V4      pVf   K  \        P                  \	        W,          4      R4       F  p\        WV4       Rj  x€L
  K  	  \        V4      pVe   \	        W,          4      \        9  d   K  W^,           R p\        VRR 4       F$  w  rVV\        9   g   K  WE^,           ,          x €  K¾  	  KÂ  	  R#  Lz5i)zaYield code passed through ``sh|bash|... -c`` (and ``su -c`` / ``env -S``) for recursive
scanning.Nr	   re   )
r…   rP  Ú_STRING_COMMAND_OPTIONSrD  ry   r¥  rx   r«  ri   r¬  )r7  rŒ   rz   ro   rY  r°  r`  s   &      r   Ú_iter_shell_command_payloadsr¹  §  sÀ   é € ô *¨'Ö2ˆÜ$ WÓ-ˆØŠ=Ùä-×1Ñ1Ô2BÀ7Å>Ó2RÐTVÖWˆFÜ*¨7¸6ÓB×BÒBñ Xä'¨Ó0ˆØŠ=Ô,¨W­^Ó<ÔDVÔVÙØ A�I˜KÐ(ˆ	Ü#,¨Y°s¸¨^Ö#<ÑˆIØÔ/Ö/Ø¨A¥Õ.Ò.Úó $=ó 3ñ Cùs   ‚ACÁCÁACÂ8Cc               ó    € V ^8„  d   QhRRRR/# )r   ÚdataÚbytesr    r   r	   )r!   s   "r   r"   r"   ½  s   € ÷ +ñ +˜Eð + dñ +r   c                ó^   € V P                  R4      '       d   R# V P                  \        4      # )a`  True when *data* starts with a known compiled-binary signature. Deliberately narrower than
"contains a NUL": ``bash`` still executes a NUL-bearing script, so a padded script must not
bypass the scan. A shebang always wins (interpreted, never binary). Extensions are not
consulted: a suffixless script must still be scanned and fail closed if oversized.s   #!F)r-   Ú_BINARY_MAGICS)r»  s   &r   Ú_has_binary_magicr¿  ½  s%   € ð
 ‡��u×ÒÙØ�?‰?œ>Ó*Ð*r   rò   c               ó$   € V ^8„  d   QhRRRRRR/# ©r   r	  r   rò   ró   r    útuple[Optional[str], bool]r	   )r!   s   "r   r"   r"   Ç  s$   € ÷ ñ Ø
ðØ+ðàñr   c               óÔ   € ^ RI HpHp  V! V RR7      ;_uu_ 4        \        WR7      uuRRR4       #   + '       g   i     R# ; i  T d    Ru # \        \
        3 d    Ru # i ; i)ab  Read a referenced script without racing SQLite connection lifecycle.

The registry check must cover the complete ``open``/``read``/``close``
sequence. A separate ``has_live_connection`` check would leave a race in
which another thread opens SQLite after the check but before this function
closes its descriptor, cancelling that connection's POSIX locks.
)ÚLiveConnectionErrorÚoffline_file_accesszread referenced script)r   rø   N©NT©NF)r  rÄ  rÅ  Ú _read_referenced_script_unlockedr  r9  )r	  rò   rÄ  rÅ  s   &$  r   Ú_read_referenced_scriptrÉ  Ç  sZ   € ÷ UðÙ  Ð,D×EÖEÜ3°DÔN÷ F×E×EÓEûàô ØÒÜ”ZÐ ô àÒðús6   ŠA œ3¨
A ³A	¾A ÁA Á	A'ÁA'Á!A'Á&A'c               ó$   € V ^8„  d   QhRRRRRR/# rÁ  r	   )r!   s   "r   r"   r"   Ý  s$   € ÷ ?9ñ ?9Ø
ð?9Ø+ð?9àñ?9r   c               ó´  € \        V4      p\        V 4      '       d   R	# \        P                  \	        \        R^ 4      ,          p \        P
                  ! W4      p \        P                  ! T4      p\        P                  ! TP                  4      '       g>   R\        P                  ! TP                  4      '       * 3\        P                  ! T4       # \        P                  ! T\        4      p\!        T4      '       d   R
\        P                  ! T4       # TP"                  T8”  d   R	\        P                  ! T4       # \%        T4      T8:  dA   \        P                  ! YB^,           \%        T4      ,
          4      pT'       g   MYg,          pKP   \        P                  ! T4       \!        T4      '       d   R
# \%        T4      T8”  d   R	# RT9   d   TP'                  RR4      pTP)                  RRR7      R3#   \        \        3 d    R
u # i ; i  \         d    R
u \        P                  ! T4       # i ; i  \        P                  ! T4       i ; i)u·  Return ``(text, unsafe)`` using bounded, regular-file-only reads.

Shared choke point for every local script read, so the cloud-placeholder refusal lives here: a
FileProvider path is never opened â€” not even to check hydration â€” because an evicted
placeholder's ``open()`` can hang preflight. Lexical check: direct paths; resolved: symlinks.
``max_bytes`` lowers the per-file cap to what the calling walk can still afford.

See #88052.
NÚ
O_NONBLOCKFó    r   rÕ   rÖ   r×   rÆ  rÇ  )rù   r†  r  ÚO_RDONLYÚgetattrÚopenr  r9  Úfstatr  r  r  ÚS_ISDIRÚcloseÚreadÚ_BINARY_SNIFF_BYTESr¿  Úst_sizer1   rÖ   Údecode)r	  rò   Ú
byte_limitÚflagsÚ
descriptorr  r»  Úchunks   &$      r   rÈ  rÈ  Ý  sÝ  € ô $ IÓ.€JÜ�d×ÒØÐÜ�K‰Kœ'¤" l°AÓ6Õ6€EðÜ—W’W˜TÓ)ˆ
ð
 ô —8’8˜JÓ'ˆô �|Š|˜H×,Ñ,×-Ò-ð œTŸ\š\¨(×*:Ñ*:Ó;Ô;Ð;ô, 	�Š�Õô! �wŠw�zÔ#6Ó7ˆÜ˜T×"Ò"Øô 	�Š�Õð ×Ñ˜jÔ(Øô 	�Š�Õô �$‹i˜:Ô%Ü—G’G˜J°Q­¼¸T»Õ(BÓCˆEßØØ�MŠDð	 &ô 	�Š�ÔÜ˜×ÒØÐô ˆ4ƒy�:ÔØÐØ�$„Ø�|‰|˜G SÓ)ˆØ�;‰;�w yˆ;Ó1°5Ð8Ð8øô[ ”ZÐ ô ð ÒðûôB ô ØÑä
�Š�Õðûô 	�Š�Õús\   ÁG= ÁA"H Ã-H ÄH ÅAH ÆH? Æ	
H ÆH? Ç=HÈHÈH<È#H? È;H<È<H? È?Ic               ó$   € V ^8„  d   QhRRRRRR/# )r   r€   r¤   rò   ró   r    rÂ  r	   )r!   s   "r   r"   r"     s$   € ÷ ñ Ø
ðØ'4ðàñr   c               ó¬   € V '       d   RV 9   d   R# \        V4      p\        V 4      V8”  d   R# \        V P                  RRR7      4      V8”  d   R# V R3# )a©  Apply the local-read contract to text from an untrusted ``read_remote_script`` callback: NUL
means binary (nothing to scan, checked first); oversized fails closed. Size compares re-encoded
*bytes* (matching the ``head -c`` wire bound): a >1 MiB multibyte file truncated at the byte cap
decodes to fewer chars, and a char count would scan instead of failing.

The recursion boundary must not trust its callbacks: any backend (SSH, Modal, Daytona, or a future one)
can hand back raw binary bytes decoded as text, or arbitrarily large output. Enforced here rather than
inside each callback so the guarantee holds for every callback, not just the ones we hardened. See
#76762, #77703.
r‹  FrÕ   rÖ   r×   rÇ  rÆ  )rù   r1   rÞ   )r€   rò   rØ  s   &$ r   Ú_sanitize_remote_script_textrÞ    sY   € ÷ �6˜T”>ØÐÜ# IÓ.€JÜ
ˆ4ƒy�:ÔØÐÜ
ˆ4�;‰;�w yˆ;Ó1Ó2°ZÔ?ØÐØ�ˆ;Ðr   c               ó    € V ^8„  d   QhRRRR/# )r   r–  r   r    ztuple[str, Optional[str]]r	   )r!   s   "r   r"   r"   6  s   € ÷ 
#ñ 
#¨3ð 
#Ð3Lñ 
#r   c                ó„   € \        V 4      pVf   R# \        V4      w  r#V'       d   R\        V4      3# T;'       g    RR3# )zþ``(text, refusal)``: read a cron script with the bounded scanner. Non-regular/oversized/live
SQLite inputs fail closed with a NAMED *refusal* (never a lifecycle-shaped verdict); missing or
unreadable paths stay empty so scheduler validation reports them.Nr   )r   N)rœ  rÉ  r  )r–  ÚresolvedÚscript_textÚunsafes   &   r   Ú_read_script_for_scanningrä  6  sM   € ô $ KÓ0€HØÒØˆÜ1°(Ó;Ñ€KßØÔ% hÓ/Ð/Ð/Ø×Ð˜"˜dÐ"Ð"r   Úread_remote_scriptÚexecutedTc               ó8   € V ^8„  d   QhRRRRRRRRR	R
RRRRRR/# )r   r7  r   r�  r¤   r  rô   Úvisitedz	set[Path]rÿ   rÀ   rå  úOptional[_ReadRemoteScriptFn]ræ  r   r    r	   )r!   s   "r   r"   r"   E  sX   € ÷ Xñ XØðXØ'ðXØ03ðXØ>GðXØQeðXà5ðXàHLðXð 
ñXr   c          
     óþ  aaaa€ SP                  V 4      '       g   V'       d   \        SRS4      # R# \        V 4      '       d   R# S\        8¼  d   V# R VVVV3R llp^ RIHp V! V 4      p	\        V	4       F  p
V! W¡V4      '       g   K   R# 	  \        W‘R7       Uu. uF  q»V3NK  	  ppW�8w  d%   T\        WR7       Uu. uF  q»R3NK  	  up,          pV EF•  w  rÞ\        V4      '       d   V'       d   \        SVRV R	24      u # K4  \        V4      pVS9   d   KH  SP                  4       '       g   V'       d   \        SR
S4      u #  R# SP                  V4       \        VSP                  R7      w  ppV'       d#   V'       d   \        SV\        V4      4      u # KÍ  Vf‹   Se‡   SP!                  4       '       g   V'       d   \        SRS4      u #  R# \#        S! \%        V4      4      SP                  R7      w  ppV'       d&   V'       d   \        SVRV R\&         R24      u # EK[  V'       g   EKf  T! T\)        \%        V4      4      ;'       g    TV4      '       g   EK•   R# 	  R# u upi u upi )a  ``executed=False`` means *command* is the content of a file that is only MENTIONED in inert
(masked) text: it is still scanned for a literal lifecycle command, but "could not scan" (budget,
depth, size, device, live SQLite, cloud) is "nothing to scan" there, never a block (#113944).r€   FTc               ó(   € V ^8„  d   QhRRRRRRRR/# )r   r€   r   r�  r¤   ræ  r   r    r	   )r!   s   "r   r"   Ú5_contains_unsafe_gateway_action.<locals>.__annotate__T  s(   € ÷ 
ñ 
�cð 
 ð 
¸ð 
À$ñ 
r   c           
     ó4   <€ \        WS^,           SSSVR7      # )r~  )r�  r  rè  rÿ   rå  ræ  )Ú_contains_unsafe_gateway_action)r€   r�  ræ  rÿ   r  rå  rè  s   &&&€€€€r   ÚrecurseÚ0_contains_unsafe_gateway_action.<locals>.recurseT  s"   ø€ Ü.Ø ¨¥°GÀFØ1¸Hô
ð 	
r   r¸   ©r�  r  ze` lives on a cloud-synced path (iCloud Drive / ~/Library/CloudStorage) that the guard refuses to openÚpathsrø   zremote readsz.` read from the backend exceeds the scan cap (r  )rå   r  rs  Ú_MAX_REFERENCED_SCRIPT_DEPTHrº   r¹   r¹  rµ  r†  r  ry  rê   ÚaddrÉ  rÇ   r  rî   rÞ  r   rö   r   )r7  r�  r  rè  rÿ   rå  ræ  rï  r¹   Úwalk_commandÚpayloadr	  r{   r–  Úcandidate_executedrá  râ  rã  s   &$dddd$           r   rî  rî  E  si  û€ ð ×Ñ˜g×&Ò&ß;CÔ  ¨°Ó7ÐNÈÐNÜ˜g×&Ò&ÙØÔ,Ô,Øˆ÷
ó 
õ ?á-¨gÓ6€Lä/°Ö=ˆÙ�7 ×*Ô*Úñ >ô 0NÈlÕ/dÓeÑ/d t˜Ó"Ñ/d€JÐeØÔØÔ1OÐPWÕ1aÓbÑ1a¨˜e“}Ñ1aÑbÕbˆ
ä+5Ñ'ˆä˜+×&Ò&ß!Ü)Ø˜KØ˜�}ð %Mð Móò ñ
 Ü# KÓ0ˆØ�wÔÙØ×!Ñ!×#Ò#ß!Ü(¨°¸%Ó@Ò@Øñ@ ð? 	�‰�HÔô 6°kÈV×McÑMcÔdÑˆ�Vßß!Ü)¨&°+Ô?QÐR]Ó?^Ó_Ò_ÙØÒÐ#5Ò#Að ×,Ñ,×.Ò.ß%Ü,¨V°^ÀUÓKÒKØñ" ô! #?Ù"¤3 {Ó#3Ó4À×@VÑ@Vô#ÑˆK˜÷ ß%Ü-Ø Ø˜K˜=ð )Ü8Ð9Ð9]ð_óò ò
 ßÚá�;Ô 9¼#¸h»-Ó H× OÐ OÈCÐQc×dÕdÚñ_ ,6ñ` ùòi fùâbs   ÂI5ÃI:c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r   r7  r   r�  r¤   rå  ré  r    ztuple[bool, Optional[str]]r	   )r!   s   "r   r"   r"      s4   € ÷ #Iñ #IØð#IØ'ð#Ià5ð#Ið  ñ#Ir   c          	     óJ  € \        4       p \        W^ \        4       VVR7      pYD'       d   VP                  3# R3#   \         d\    \
        P                  RRR7        \        T 4      R3u #   \         d&    \        T 4      ;'       g    \        T 4      R3u u # i ; ii ; i)u1  ``(unsafe, refusal)``: *refusal* names a non-lifecycle reason the walk failed closed (budget,
size, device, live SQLite, cloud) so callers can tell the model; ``None`` when the verdict is a
real lifecycle command or the command is allowed.

Total by construction: never raises. Direct scans are pure string ops; the referenced-script
walk (filesystem, remote backends, shlex on decoded bytes) is best-effort defense-in-depth â€” an
unexpected failure is logged and treated as "walk found nothing".

This is the contract #76762 established ("a guarded path must never crash the guard") enforced at the
boundary instead of per-syscall: a guard crash propagates out of ``tools/terminal_tool.py`` and breaks
every terminal command until the gateway restarts (#77780, #78256), which is strictly worse than either
verdict.
)r�  r  rè  rÿ   rå  NzRlifecycle guard referenced-script walk failed; falling back to direct-scan verdictT)Úexc_info)
rÀ   rî  r3  rÎ   rü   r  r  rs  r¾   rZ  )r7  r�  rå  rÿ   rã  s   &$$  r   Úscan_gateway_lifecyclerû     sÀ   € ô" "Ó#€FðIÜ0Ø A¬s«u¸VØ1ô
ˆð ®�v—~‘~Ð9Ð9°TÐ9Ð9øÜô IÜ�‰ð2àð 	ô 	
ð
	IÜ)¨'Ó2°DÐ8Ò8øÜô 	Iä6°wÓ?÷ Bð BÜ8¸ÓAÀDðIô Ið	IúðIús7   Œ,< ¹< ¼"B"ÁA.Á+B"Á.BÂBÂB"ÂBÂB"c               ó(   € V ^8„  d   QhRRRRRRRR/# )	r   r7  r   r�  r¤   rå  ré  r    r   r	   )r!   s   "r   r"   r"   Æ  s4   € ÷ ^ñ ^Øð^Ø'ð^à5ð^ð 
ñ^r   c               ó*   € \        WVR7      ^ ,          # )zuDetect lifecycle/submit commands, including bounded nested scripts (see
``scan_gateway_lifecycle`` for the contract).)r�  rå  )rû  )r7  r�  rå  s   &$$r   Ú7contains_gateway_lifecycle_command_or_referenced_scriptrþ  Æ  s   € ô " 'ÐGYÔZÐ[\Õ]Ð]r   c               ó$   € V ^8„  d   QhRRRRRR/# )r   Úpromptr¤   Úscriptr    rÂ   r	   )r!   s   "r   r"   r"   Ï  s"   € ÷ >
ñ >
 Mð >
¸=ð >
ÐTXñ >
r   c                óT  € T ;'       g    RpRpRpV'       dc   \        V4      pVe   \        V4      '       d   \        R4      hVRJ;'       d    VP                  R8H  p\	        V4      w  rdV'       d   V RV 2pV'       d   RpMpV'       dH   \        4       pVP                  V4      '       g   \        VR^ 4      pVP                  pM-\        V4      pM!\        Y!'       d   \        V4      MRR	7      w  rtV'       d   V'       d   \        R
V R24      hV'       d   \        R4      hR# )a  Raise ``GatewayLifecycleBlocked`` if *prompt* or *script* contains a gateway-lifecycle
command. The script is read from disk and concatenated with the prompt so a command cannot slip
through by being split across the two. Callers let the ``ValueError``-shaped exception
propagate.r   FNa<  Blocked: the cron script lives on a cloud-synced path (iCloud Drive / ~/Library/CloudStorage). Opening an evicted FileProvider placeholder can hang the guard's preflight scan indefinitely, so it is refused without being read. Move the script to a local, non-cloud path (e.g. ~/.hermes/scripts/) and recreate the job.z.pyrÙ   Tr€   rñ  zPBlocked: the lifecycle guard could not scan this cron job or referenced script: zª. Nothing in the job is known to contain a gateway lifecycle command, but a script the job executes must be scannable (a regular text file under 1 MiB) before it can run.a  Blocked: cron job contains a gateway lifecycle command or persistent launchctl submit operation. This is blocked to prevent agent-driven SIGTERM-respawn loops under launchd/systemd supervision (#30719). Run `hermes gateway restart` from a shell outside the running gateway instead.)rœ  r†  r   Úsuffixrä  rÀ   rå   r  rÎ   rp  rû  r   )	r   r  ÚcombinedÚpython_scriptrÎ   Úresolved_scriptrâ  rã  rÿ   s	   &&       r   Úcheck_gateway_lifecycler  Ï  s1  € ð
 �|ˆ|˜€HØ€MØ!€GßÜ.¨vÓ6ˆàÒ&¬>¸/×+JÒ+JÜ)ðBóð ð (¨tÐ3×WÐW¸×8NÑ8NÐRWÑ8WˆÜ8¸Ó@ÑˆßØ"˜ 2 k ]Ð3ˆHçØ‰ß	ô &Ó'ˆØ×!Ñ! (×+Ò+Ü& v¨v°qÓ9ˆFØ—n‘n‰Gä@ÀÓJ‰Fä0Ø¾vÔ3°FÔ;È4ô
‰ˆ÷ —'Ü%Ø^Ð_fÐ^gð hfð fó
ð 	
÷
 Ü%ð+ó
ð 	
ñ r   >   ú-Aú-Fú-Gú-Oú-Pú-Uú-dú-grO   ú-sú-tr   ú--nsú--uidú--euidú--groupú--olderú--cgroupú--nslistú--parentú--pgroupú--signalú	--pidfileú	--sessionú
--terminalú--delimiterú--runstatesú--ignore-ancestors>   ú-Zr   ú-or  r   ú-yr  r   r  ú	--contextú--older-thanú--younger-than>   ú-Sr#  ú
--omit-pidú--separator>   r   r   r\   ústop-process>   r   r   r`   >   ÚshÚkshÚzshÚbashÚdash>   ú+Oú+or  r#  i   >	   ÚagÚrgÚackÚgrepÚpsqlÚegrepÚfgrepÚsqlite3Ú
journalctl)r  z$(z<(z>(z\!>   rœ   r–   r•   Úexecr—   r”   Únohupr˜   r›   Úsetsidr™   Úbuiltinr7  r    r�   rž   rš   r¡   Ú	eatmydatarŸ   >   r¢   ú-Tr  r  ú-prO   r  r   r   r  ú--prompt>   r¢   r(  r   ú--chdirú--unsetú--split-string>   r�   r   rB  ú--classú--classdata>   ú-eú-ir#  ú--errorú--inputú--output>   ú-kr  r  ú--kill-after>   r
  r  r  r  ú--shellú--supp-group>   r
  r  r  r   r   r  rP  rQ  >   ú--regidú--reuidú--groupsú
--inh-capsú--ambient-capsú--bounding-setú--selinux-labelú--apparmor-profile>   ú-ErB  r   ú--gidr  ú--unitú--sliceú--setenvú
--propertyú--descriptionú--on-calendarú--service-type>
   r
  r(  rO   r  ú-wú--wdú--rootú--setgidú--setuidú--target>   ú-Rrc  rd  re  ú
--map-userú--map-groupú--setgroups)r(  rF  )r�   r‘   )
s   ELFs   þíúÎs   þíúÏs   Îúíþs   Ïúíþs   Êþº¾s   MZs   !<arch>s   ‹s   PKi   rÅ   )rr   Ú
__future__r   Úloggingr  rj   r)  r  ÚsysÚpathlibr   Útypingr   r   r   Ú	getLoggerr
   r  r9  r   Úcompiler»   r/   r®  r2   r)   r.   rE  rg   r@   rD   rˆ   r‰   r„   rC   ÚHOST_INTERPRETER_KILL_REJECTIONr4   rI   rs   r}   r�   r‚   r‡   r¼   r³   r´   r«  r­  r¬  rö   ró  r4  r€  rh  rc  rb  rg  rÕ  r   Ú_ReadRemoteScriptFnrB  rC  r¸  rG  rF  rA  r¾  r©   r¯   rµ   r¾   rÆ   rÈ   rá   rÊ   rÌ   rÀ   rù   rý   r  r  r  r#  r.  r5  r…   ry   rI  rP  rx   rZ  rm  rp  rs  ry  rƒ  r†  rŽ  r”  rœ  r   r¥  r±  rµ  r¹  r¿  rÉ  rÈ  rÞ  rä  rî  rû  rþ  r  r	   r   r   Ú<module>rv     sž  ðñõ #ã Û 	Û 	Û Û Û 
Ý ß /Ñ /à	×	Ò	˜8Ó	$€ôL˜jô Lð  ŸZšZð#Pó%Ð ð\ Ÿ
š
Ð#LÓMÐ Ø>A¿n¿n¸n™˜cŸn™nÓ-×2Ñ2×8Ñ8Ô:ÐRTÐ ð ‰Yò ó ð
 ‰yò ;ó <ð	Ð ð "7°wÕ!?Ð �gÑ Ù!*Ò+TÓ!UÐ �gÑ à�JŠJÐ.Ó/€	Ø—Z’Z Ó0Ð ÙÒJÓK€ÙÒ?Ó@Ð Ø—
’
ÐDÓE€ð
 ŸJšJÐ'pÓqÐ ðQð  ðF¸5÷ Fõ`õ&(]õVõð8 Ÿ:š:Ð&6Ó7Ð ð
 Ÿš KÓ0Ð ð #%§*¢*ð%ó#Ð ð, !#§
¢
Ø]ó!Ð ð Ÿ:š:Ð&DÓEÐ áÒCÓDÐ Ù&Ò'?Ó@Ð Ø˜kÐ*Ð Ø*Ð Ø Ð Ù˜7Ó#€ñ
 'Ð(:¸NÐ'KÓLÐ ñ
 #ÚRóÐ ð
 :Ð ð Ÿ
š
 >Ó2Ð à—z’zØIóÐ ð
 Ð à ˜u h¨s¥mÐ3Õ4Ð ñ !*ò +ó !Ð ð Ò]Ø
ˆT�4ˆLØ	ÒEØ
ˆT�>Ð"ØÒ:ØÒBØÒ7ØˆxˆjØÒ
BØÒWØò 9àò ZàÒcØÒYð!%Ð !ð, 
Ð#ØÐ
ØÐ"ðÐ ð !*¨1˜~Ð à—*’*Ð8Ó9€ð Ð ð€õ "õTõõ?kðT 9Ð Ø!Ð Ø!*Ð Ø Ð Ø#%Ð  ÷5ñ 5õpEõõõwõ õõ2ðÀ÷ õ"+õ %õõ<bõ
3õõ"%5õPUõõõ	õbõ
õ(õõ$õ&õ$9ðN<È÷ <õõ,+ðØ.2÷ð,?9Ø.2÷?9ðDØ7;÷õ.
#ðXà8<ðXàOS÷Xðv#IØ*.ð#Ià8<÷#IðL^Ø*.ð^à8<÷^÷>
ñ >
r   