
    PL
j=              	          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dS )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                    t          |           }|sdS t          ||          \  }}|sdS 	 t          |||          }n5# t          $ r(}t                              d|||           Y d}~dS d}~ww xY w|r\d                    d |dd         D                       }d                    d |dd         D                       }d| d	| d
| d| S dS )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          V  dS )idN .0ms     3/home/kuhnn/.hermes/hermes-agent/tools/osv_check.py	<genexpr>z,check_package_for_malware.<locals>.<genexpr>6   s&      55A$555555       z; c              3   ^   K   | ](}|                     d |d                   dd         V  )dS )summaryr   Nd   )getr   s     r   r   z,check_package_for_malware.<locals>.<genexpr>7   sN       
 
01AEE)QtW%%dsd+
 
 
 
 
 
r   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'      sI    !))I t/i@@GW tWi99   @)WVYZZZttttt
  
ii55!55555II 
 
5<RaR[
 
 
 
 
	7 7 7Y 7 77 7+47 7	
 4s   > 
A0A++A0c                     t           j                            |                                           }|dv rdS |dv rdS dS )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   sJ    7G$$**,,D!!!u)))v4r   r    c                     | sdS d}| D ]0}t          |t                    s|                    d          r.|} |sdS |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.
    )NNN-r+   r/   )
isinstancestr
startswith_parse_npm_package_parse_pypi_package)r   r    package_tokenargs       r   r   r   K   s      z M  #s## 	>># 	 zE!-000	f		"=111$r   tokenc                 \   |                      d          rEt          j        d|           }|r*|                    d          |                    d          fS | dfS d| v rK|                     dd          }|d         }t          |          dk    r|d         dk    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rsplitlen)r>   rE   partsnamer"   s        r   r:   r:   i   s     6>> 	2;;q>>5;;q>>11d{
e||S!$$Qx!%jj1nnqX1E1E%((4W}$;r   c                     t          j        d|           }|r*|                    d          |                    d          fS | dfS )z;Parse PyPI package: name==version or name[extras]==version.z-^([a-zA-Z0-9._-]+)(?:\[[^\]]*\])?(?:==(.+))?$rA   rB   N)rD   rE   rF   )r>   rE   s     r   r;   r;   z   sG     HEuMME .{{1~~u{{1~~--$;r   r!   r"   c                    d| |di}|r||d<   t          j        |                              d          }t          j                            t          |dddd	          }t          j                            |t          
          5 }t          j	        |
                                          }ddd           n# 1 swxY w Y   |                    dg           }d |D             S )zFQuery the OSV API for MAL-* advisories. Returns list of malware vulns.r!   )rJ   r    r"   zutf-8zapplication/jsonzhermes-agent-osv-check/1.0)zContent-Typez
User-AgentPOST)dataheadersmethod)timeoutNvulnsc                 d    g | ]-}|                     d d                              d          +|.S )r    zMAL-)r   r9   )r   vs     r   
<listcomp>z_query_osv.<locals>.<listcomp>   s7    CCC!dB : :6 B BCACCCr   )jsondumpsencodeurllibrequestRequest_OSV_ENDPOINTurlopen_TIMEOUTloadsreadr   )	r!   r    r"   payloadrN   reqrespresultrR   s	            r   r   r      s+    7CCDG %$	:g%%g..D
.
 
 .6
 
  !  C 
		X		6	6 )$DIIKK(() ) ) ) ) ) ) ) ) ) ) ) ) ) ) JJw##ECCuCCCCs   'B::B>B>)N)__doc__rW   loggingr0   rD   urllib.requestrZ   typingr   r   	getLogger__name__r   getenvr]   r_   r8   listr'   r   r   r:   r;   r   r   r   r   <module>rn      s  
 
   				 				     " " " " " " " "		8	$	$	.*HII$$$c]$ $ $ $Nc hsm    

8C=(3-'(   <c eHSM8C=,H&I    "s uXc]HSM-I'J     <@D DD D+3C=D	D D D D D Dr   