Ë
    ãß²jµ  ã                   ó&  — d Z ddlZddlZddlmZ  ej                  d«      Zg d¢Zedd Z	dZ
de
› �d	fd
e
› �dfde
› �dfde
› �dfde
› d�dfgZdZdZdededefd„Zdedefd„Zdedeeee   f   fd„Zdedefd„Zdedefd„Zdedeeef   fd„Zy) z£Cron prompt threat scanning: the small user-authored prompt gets the strict pattern set;
the assembled prompt (with skill bodies) gets only prose-proof directives.é    N)ÚINVISIBLE_CHARSztools.cronjob_tools))zJignore\s+(?:\w+\s+)*(?:previous|all|above|prior)\s+(?:\w+\s+)*instructionsÚprompt_injection)zdo\s+not\s+tell\s+the\s+userÚdeception_hide)zsystem\s+prompt\s+overrideÚsys_prompt_override)z<disregard\s+(your|all|any)\s+(instructions|rules|guidelines)Údisregard_rules)zKcat\s+[^\n]*(\.env|credentials|\.netrc|\.pgpass|id_rsa|id_ed25519|id_ecdsa)Úread_secrets)Úauthorized_keysÚssh_backdoor)z/etc/sudoers|visudoÚsudoers_mod)zrm\s+-rf\s+/Údestructive_root_rmé   z:\$\{?\w*(?:KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)\w*\}?z curl\s+[^\n]*https?://[^\s"\'`]*Úexfil_curl_urlz wget\s+[^\n]*https?://[^\s"\'`]*Úexfil_wget_urlzIcurl\s+[^\n]*(?:--data(?:-raw|-binary|-urlencode)?|-d|--form|-F)\s+[^\n]*Úexfil_curl_dataz(wget\s+[^\n]*--post-(?:data|file)=[^\n]*Úexfil_wget_postzHcurl\s+[^\n]*(?:-H|--header)\s+["\']Authorization:\s*(?:Bearer|token)\s+z["\']Úexfil_curl_auth_header))i ð iÿÿ )i &  i¿'  )i #  iÿ#  )iæñ iÿñ )éã   r   iþ  ÚtextÚidxÚreturnc                 óx  ‡ — |dz
  }|dk\  r5t        ‰ |   «      t        k(  r |dz  }|dk\  rt        ‰ |   «      t        k(  rŒ |dz   }|t        ‰ «      k  r>t        ‰ |   «      t        k(  r)|dz  }|t        ‰ «      k  rt        ‰ |   «      t        k(  rŒ)|dk  s|t        ‰ «      k\  ryt        ˆ fd„||fD «       «      S )zMTrue when the ZWJ at text[idx] sits between emoji codepoints (skipping VS16).é   r   Fc              3   óR   •‡K  — | ]  Št        ˆˆfd „t        D «       «      –— Œ y­w)c              3   ó\   •K  — | ]#  \  }}|t        ‰‰   «      cxk  xr |k  nc –— Œ% y ­w)N)Úord)Ú.0ÚloÚhiÚposr   s      €€ú>/home/ubuntu/.hermes/hermes-agent/tools/cronjob_prompt_scan.pyú	<genexpr>z5_zwj_has_emoji_neighbour.<locals>.<genexpr>.<genexpr>F   s*   øè ø€ ÒP©6¨2¨rˆB”#�d˜3‘i“.Ö& B×&Ð&ÑPùs   ƒ),N)ÚanyÚ_EMOJI_NEIGHBOUR_CP_RANGES)r   r   r   s    @€r    r!   z+_zwj_has_emoji_neighbour.<locals>.<genexpr>E   s"   ùè ø€ ò ØUXŒÔPÔ5OÔP×Pñùs   „#')r   Ú_VARIATION_SELECTOR_CPÚlenÚall)r   r   ÚleftÚrights   `   r    Ú_zwj_has_emoji_neighbourr)   ;   sÈ   ø€ à�‰7€DØ
�!Š)œ˜D ™J›Ô+AÒAØ�‰	ˆð �!Š)œ˜D ™J›Ô+AÓAà�!‰G€EØ
”#�d“)Ò
¤ D¨¡KÓ 0Ô4JÒ JØ�‰
ˆð ”#�d“)Ò
¤ D¨¡KÓ 0Ô4JÓ Jàˆa‚x�5œC ›IÒ%ØÜó Ø]aÐchÐ\iôó ð ó    Úpromptc                 ó`   — t        j                  dt        › d�d| t         j                  ¬«      S )u  Scrub the bundled GitHub skill's `Authorization: token $GITHUB_TOKEN` + api.github.com
    curl so it doesn't trip the auth-header exfil rule.

    re.sub scrubs EVERY occurrence. The trailing ``[^\s;&|$`]*`` consumes only the URL path â€”
    never separators or subshell openers â€” so a payload smuggled onto the same line still gets
    scanned. Host must be exactly api.github.com followed by ``/``, whitespace, quote, or end:
    lookalike authorities (api.github.com.evil.com, api.github.com@evil.com) fall through.
    zBcurl\s+[^\n;&|$`]*(?:-H|--header)\s+["\']Authorization:\s*token\s+zJ["\']\s+["\']?https://api\.github\.com(?::\d+)?(?:/|\s|$|["\'])[^\s;&|$`]*z curl https://api.github.com/user)Úflags)ÚreÚsubÚ_CRON_SECRET_VAR_REÚ
IGNORECASE)r+   s    r    Ú_strip_cron_safe_constructsr2   J   s8   € ô �6‰6ØMÔNaÐMbð cQð 	Qà*ØÜ�m‰môð r*   c                 ó  — | s| g fS t        «       }g }t        | «      D ]N  \  }}|t        v r0|dk(  rt        | |«      s|j	                  dt        |«      d›�«       Œ>|j                  |«       ŒP dj                  |«      t        |«      fS )zÿStrip invisible-unicode chars, keeping ZWJ inside legitimate emoji.

    Returns ``(cleaned, sorted U+XXXX labels removed)``. The skills-attached path sanitizes
    (a stray zero-width space in vetted skill content must not permanently kill the job).
    u   â€�úU+Ú04XÚ )	ÚsetÚ	enumerateÚ_CRON_INVISIBLE_CHARSr)   Úaddr   ÚappendÚjoinÚsorted)r+   ÚremovedÚcleanedr   Úchs        r    Ú_strip_invisible_unicoderA   \   s’   € ñ Ø�rˆzÐÜ›€GØ€GÜ˜VÓ$ò ‰ˆˆRØÔ&Ñ&°°h²ÔC[Ð\bÐdgÔChØ�K‰K˜"œS ›W S˜MÐ*Ô+ØØ�‰�rÕð	ð
 �7‰7�7ÓœV G›_Ð,Ð,r*   c                 ó„   — |D ];  }|D ]4  \  }}t        j                  || t         j                  «      sŒ,d|› d�c c S  Œ= y)Nz(Blocked: prompt matches threat pattern 'zD'. Cron prompts must not contain injection or exfiltration payloads.r6   )r.   Úsearchr1   )r   Úpattern_setsÚpatternsÚpatternÚpids        r    Ú_first_pattern_errorrH   n   sV   € Ø ò ˆØ$ò 	‰LˆG�SÜ�y‰y˜ $¬¯©Õ6à>¸s¸eð DBð Bôñ	ðð r*   c                 óÌ   — t        | «      }t        t        |«      d   «      }t        D ]%  }dt	        |«      d›�|v sŒdt	        |«      d›d�c S  t        |t        t        «      S )zçStrict scan of the USER-SUPPLIED prompt (create/update + runtime defense-in-depth).
    Returns an error string when blocked, else "". Invisible unicode is reported first, in
    ``_CRON_INVISIBLE_CHARS`` order (emoji ZWJ allowed).r   r4   r5   z-Blocked: prompt contains invisible unicode U+z (possible injection).)r2   r7   rA   r9   r   rH   Ú_CRON_THREAT_PATTERNSÚ_CRON_EXFIL_COMMAND_PATTERNS)r+   Úprompt_to_scanr>   Úchars       r    Ú_scan_cron_promptrN   y   sr   € ô 1°Ó8€NÜÔ*¨>Ó:¸1Ñ=Ó>€GÜ%ò iˆØ”�D“	˜#ˆÐ 7Ò*ØBÄ3ÀtÃ9ÈSÀ/ÐQgÐhÒhðiô   Ô0EÔGcÓdÐdr*   Ú	assembledc                 ó¶   — t        | «      \  }}|r/t        j                  dt        |«      dj	                  |«      «       |t        t        |«      t        «      fS )u  Loose scan of the ASSEMBLED prompt (skill content included). Invisible unicode is
    SANITIZED (stripped + logged), not blocked â€” the hard block stays on raw user prompts,
    the actual injection surface. Returns ``(cleaned_prompt, error)``, error "" when passed.zaCron skill-assembled prompt: stripped %d invisible-unicode char(s) (%s) from vetted skill contentz, )rA   ÚloggerÚwarningr%   r<   rH   r2   Ú_CRON_SKILL_ASSEMBLED_PATTERNS)rO   r?   r>   s      r    Ú_scan_cron_skill_assembledrT   …   sU   € ô 0°	Ó:Ñ€GˆWÙÜ�‰ð5ä�‹L˜$Ÿ)™) GÓ,ô	
ð
 Ô(Ô)DÀWÓ)MÔOmÓnÐnÐnr*   )Ú__doc__Úloggingr.   Útools.threat_patternsr   r9   Ú	getLoggerrQ   rJ   rS   r0   rK   r#   r$   ÚstrÚintÚboolr)   r2   ÚtupleÚlistrA   rH   rN   rT   © r*   r    ú<module>r_      s\  ðñNó Û 	õ Kð 
ˆ×	Ñ	Ð0Ó	1€òÐ ð "7°r¸Ð!:Ð àSÐ ð 	)Ð)<Ð(=Ð>Ð@PÐQØ(Ð)<Ð(=Ð>Ð@PÐQØQÐReÐQfÐgÐizÐ{Ø0Ð1DÐ0EÐFÐHYÐZØPÐQdÐPeÐejÐkð  nFð  Gð Ð ð |Ð ØÐ ð 3ð ¨Sð °Tó ð¨ð °ó ð$- Sð -¨U°3¸¸S¹	°>Ñ-Bó -ð$˜sð °có ð	e˜cð 	e có 	eðo¨#ð o°%¸¸S¸±/ô or*   