
    `gjr              	       V   d Z ddlZddlZddlZddlZddlZddlmZm	Z	  ej                  e      Z ej                  dd      ZdZdeded	ee   fd
Zded	ee   fdZdeded	e	ee   ee   f   fdZded	e	ee   ee   f   fdZded	e	ee   ee   f   fdZ	 ddededee   d	efdZy)u  OSV malware check for MCP extension packages.

Before launching an MCP server via npx/uvx, queries the OSV (Open Source
Vulnerabilities) API to check if the package has any known malware advisories
(MAL-* IDs).  Regular CVEs are ignored — only confirmed malware is blocked.

The API is free, public, and maintained by Google.  Typical latency is ~300ms.
Fail-open: network errors allow the package to proceed.

Inspired by Block/goose's extension malware check.
    N)OptionalTupleOSV_ENDPOINTzhttps://api.osv.dev/v1/query
   commandargsreturnc                 H   t        |       }|syt        ||      \  }}|sy	 t        |||      }|rDdj                  d |dd D              }dj                  d |dd D              }d| d	| d
| d| S y# t        $ r"}t        j                  d|||       Y d}~yd}~ww xY w)a~  Check if an MCP server package has known malware advisories.

    Inspects the *command* (e.g. ``npx``, ``uvx``) and *args* to infer the
    package name and ecosystem.  Queries the OSV API for MAL-* advisories.

    Returns:
        An error message string if malware is found, or None if clean/unknown.
        Returns None (allow) on network errors or unrecognized commands.
    Nz)OSV check failed for %s/%s (allowing): %sz, c              3   &   K   | ]	  }|d      yw)idN .0ms     B/root/.hermes/venv/lib/python3.12/site-packages/tools/osv_check.py	<genexpr>z,check_package_for_malware.<locals>.<genexpr>6   s     5A$5s      z; c              3   L   K   | ]  }|j                  d |d         dd   yw)summaryr   Nd   )getr   s     r   r   z,check_package_for_malware.<locals>.<genexpr>7   s+      
01AEE)QtW%ds+
s   "$zBLOCKED: Package 'z' (z ) has known malware advisories: z. Details: )_infer_ecosystem_parse_package_from_args
_query_osv	Exceptionloggerdebugjoin)	r   r   	ecosystempackageversionmalwareexcids	summariess	            r   check_package_for_malwarer&      s     !)I/i@GWWi9 ii5!55II 
5<Ra[
 
	 !	YK 8%{9+7	
   @)WVYZs   A6 6	B!?BB!c                 r    t         j                  j                  |       j                         }|dv ry|dv ryy)z.Infer package ecosystem from the command name.>   npx.cmdnpxnpm>   uvx.cmduvxpipxPyPIN)ospathbasenamelower)r   bases     r   r   r   A   s:    77G$**,D!!))    r   c                    | syd}d}| D ]V  }t        |t              s|r|} n?|dv rd}!|j                  d      r|t        d      d } n|j                  d      rT|} n |sy|dk(  rt	        |      S |d	k(  rt        |      S |dfS )
zExtract package name and optional version from command args.

    Returns (package_name, version) or (None, None) if not parseable.
    )NNNF)z	--packagez-pTz
--package=-r*   r.   )
isinstancestr
startswithlen_parse_npm_package_parse_pypi_package)r   r   package_token	take_nextargs        r   r   r   K   s      MI #s#M%%I>>,'L 1 23M>>#" E!-00	f	"=11$r4   tokenc                     | j                  d      r>t        j                  d|       }|r"|j                  d      |j                  d      fS | dfS d| v r8| j	                  dd      }|d   }t        |      dkD  r|d   dk7  r|d   nd}||fS | dfS )z7Parse npm package: @scope/name@version or name@version.@z^(@[^/]+/[^@]+)(?:@(.+))?$      Nr   latest)r9   rematchgrouprsplitr:   )r@   rG   partsnamer!   s        r   r;   r;   w   s    6>;;q>5;;q>11d{
e|S!$Qx!%j1nqX1E%(4W}$;r4   c                 ~    t        j                  d|       }|r"|j                  d      |j                  d      fS | dfS )z;Parse PyPI package: name==version or name[extras]==version.z-^([a-zA-Z0-9._-]+)(?:\[[^\]]*\])?(?:==(.+))?$rC   rD   N)rF   rG   rH   )r@   rG   s     r   r<   r<      s=     HHEuME{{1~u{{1~--$;r4   r    r!   c                    d| |di}|r||d<   t        j                  |      j                  d      }t        j                  j                  t        |dddd	      }t        j                  j                  |t        
      5 }t        j                  |j                               }ddd       j                  dg       }|D 	cg c]&  }	|	j                  dd      j                  d      s%|	( c}	S # 1 sw Y   MxY wc c}	w )zFQuery the OSV API for MAL-* advisories. Returns list of malware vulns.r    )rK   r   r!   zutf-8zapplication/jsonzhermes-agent-osv-check/1.0)zContent-Typez
User-AgentPOST)dataheadersmethod)timeoutNvulnsr    zMAL-)jsondumpsencodeurllibrequestRequest_OSV_ENDPOINTurlopen_TIMEOUTloadsreadr   r9   )
r    r   r!   payloadrO   reqrespresultrS   vs
             r   r   r      s     7CDG$	::g%%g.D
..
 
 .6
  ! C 
		X		6 )$DIIK() JJw#EC!dB : :6 BACC) )
 Ds   $C2&C>+C>2C;)N)__doc__rU   loggingr/   rF   urllib.requestrX   typingr   r   	getLogger__name__r   getenvr[   r]   r8   listr&   r   r   r;   r<   r   r   r4   r   <module>rm      s/  
   	 	  "			8	$		.*HI$$$c]$Nc hsm )
))
8C=(3-'()Xc eHSM8C=,H&I "s uXc]HSM-I'J  <@DD D+3C=D	Dr4   