
자동화된 공급망 보안 모니터로, PyPI 및 npm 레지스트리를 폴링하고 새 릴리스를 이전 버전과 비교(diff)하며, LLM 분석을 사용하여 악성 코드 변경을 탐지하고 Slack 알림을 보냅니다.
상위 PyPI 및 npm 패키지의 공급망 손상을 자동으로 모니터링합니다. 두 레지스트리를 폴링하여 새 릴리스를 찾고, 각 릴리스를 이전 버전과 비교(diff)한 후, LLM(Cursor Agent CLI 경유)을 사용하여 차이점을 양성 또는 악성으로 분류합니다. 악성 발견 시 Slack 알림이 전송됩니다.
기본적으로 두 생태계가 모두 모니터링됩니다. --no-pypi 또는 --no-npm을 사용하여 하나를 비활성화할 수 있습니다.
각 생태계는 자체 폴링 스레드를 실행하지만 분석 및 알림 파이프라인은 공유합니다.
┌─── PyPI ──────────────────────┐ ┌─── npm ───────────────────────┐
│ │ │ │
│ changelog_since_serial() │ │ CouchDB _changes feed │
│ │ │ │ │ │
│ ▼ │ │ ▼ │
│ ┌────────────┐ │ │ ┌────────────┐ │
│ │ All PyPI │─┐ │ │ │ All npm │─┐ │
│ │ events │ │ │ │ │ changes │ │ │
│ └────────────┘ ▼ │ │ └────────────┘ ▼ │
│ hugovk ──► Watchlist │ │ download-counts ─► Watchlist │
│ │ │ │ │ │
│ "new release" events only │ │ new versions since last epoch │
└───────────────┬───────────────┘ └───────────────┬───────────────┘
│ │
▼ ▼
┌───────────────────┐ ┌───────────────────┐
│ Download old + new│ │ Download old + new│
│ (sdist + wheel) │ │ (tarball) │
└───────────────────┘ └───────────────────┘
│ │
└─────────────────┬─────────────────┘
▼
┌───────────────┐
│ Unified diff │
│ report (.md) │
└───────┬───────┘
▼
┌───────────────┐ ◄── LLM analysis
│ Cursor Agent │ (read-only)
│ CLI (ask mode)│
└───────┬───────┘
│
verdict?
│
malicious │
▼
┌───────────────┐
│ Slack alert │
└───────────────┘
LLM 분석은 다음을 찾도록 프롬프트됩니다:
pip install -r requirements.txt로 런타임 종속성을 설치하세요 (표준 라이브러리로 대부분 커버됨; requests는 Slack 업로드에 사용됨)agent 바이너리Windows (PowerShell):
irm 'https://cursor.com/install?win32=true' | iex
macOS / Linux:
curl https://cursor.com/install -fsS | bash
다음 명령으로 확인하세요:
agent --version
Cursor에 인증되어 있어야 합니다 (agent login 또는 CURSOR_API_KEY 설정).
Slack 봇 토큰을 etc/slack.json에 배치하세요:
{
"url": "https://hooks.slack.com/services/...",
"bot_token": "xoxb-...",
"channel": "C01XXXXXXXX"
}
봇은 대상 채널에 chat:write 범위가 필요합니다. channel 필드는 알림이 게시되는 Slack 채널 ID입니다.
# One-shot: analyze releases from the last ~10 minutes
python monitor.py --once
# Continuous: monitor top 1000 packages (both ecosystems), poll every 5 min
python monitor.py --top 1000 --interval 300
# Production: monitor top 15000, alert to Slack
python monitor.py --top 15000 --interval 300 --slack
# npm only, top 5000
python monitor.py --no-pypi --npm-top 5000
# PyPI only
python monitor.py --no-npm
| 파일 | 목적 |
|---|---|
monitor.py | 메인 오케스트레이터 — PyPI + npm 폴링, 차이점 비교, 분석, 알림 (병렬 스레드) |
pypi_monitor.py | 독립 실행형 PyPI 변경 로그 폴러 (탐색용) |
package_diff.py | 모든 PyPI 또는 npm 패키지의 두 버전 다운로드 및 차이점 비교 |
analyze_diff.py | Cursor Agent CLI에 차이점 전송, 판정 분석 |
top_pypi_packages.py | 다운로드 수 기준 상위 N개 PyPI 패키지 가져오기 및 목록 출력 |
slack.py | Slack API 클라이언트 (SendMessage, PostFile) |
etc/slack.json | Slack 봇 자격 증명 |
last_serial.yaml | 지속형 폴링 상태 (PyPI 시리얼 + npm 시퀀스/에포크) |
logs/ | 일일 로그 파일 (monitor_YYYYMMDD.log) |
python monitor.py [OPTIONS]
Options:
--top N Number of top packages to watch per ecosystem (default: 15000)
--interval SECS Poll interval in seconds (default: 300)
--once Single pass over recent events, then exit
--slack Enable Slack alerts for malicious findings
--model MODEL Override LLM model (default: composer-2-fast)
--debug Enable DEBUG logging (includes agent raw output)
PyPI options:
--no-pypi Disable PyPI monitoring
--serial N PyPI changelog serial to start from
npm options:
--no-npm Disable npm monitoring
--npm-top N Top N npm packages to watch (default: same as --top)
--npm-seq N npm replication sequence to start from
PyPI와 npm은 각각 자체 폴링 스레드에서 실행됩니다. 폴링 상태(PyPI 시리얼, npm 시퀀스 + 에포크)는 last_serial.yaml에 저장되어 재시작 후에도 중단된 지점에서 재개됩니다.
PyPI 파이프라인:
--interval초마다 changelog_since_serial() 호출 — 마지막 확인 이후의 모든 이벤트를 반환하는 단일 API 호출"new release" 이벤트만 필터링npm 파이프라인:
replicate.npmjs.com에서 현재 CouchDB 복제 시퀀스 읽기--interval초마다 마지막 시퀀스 이후의 모든 레지스트리 변경 사항에 대해 _changes 피드 가져오기모든 출력은 콘솔과 logs/monitor_YYYYMMDD.log 모두에 기록됩니다.
# Compare two versions from PyPI
python package_diff.py requests 2.31.0 2.32.0
# Compare two versions from npm
python package_diff.py --npm express 4.18.2 4.19.0
# Save to file
python package_diff.py telnyx 2.0.0 2.1.0 -o telnyx_diff.md
# Compare local archives
python package_diff.py --local old.tar.gz new.tar.gz -n mypackage
다운로드는 pip 또는 npm이 아닌 레지스트리 API(PyPI JSON API / npm 레지스트리)를 통해 직접 수행됩니다. 이는 다음을 의미합니다:
# Analyze a diff file
python analyze_diff.py telnyx_diff.md
# JSON output
python analyze_diff.py telnyx_diff.md --json
# Use a specific model
python analyze_diff.py telnyx_diff.md --model claude-4-opus
Cursor Agent CLI를 --mode ask(읽기 전용) 및 --trust로 실행합니다. 에이전트가 차이점 파일을 읽고 구조화된 판정을 반환합니다.
종료 코드: 0 = 양성, 1 = 악성, 2 = 알 수 없음/오류.
# See what's being released right now (last ~10 min)
python pypi_monitor.py --once --top 15000
# Continuous monitoring (console output only, no analysis)
python pypi_monitor.py --top 1000 --interval 120
전체 분석 파이프라인을 실행하지 않고 PyPI 릴리스 속도를 탐색하거나 changelog API를 디버깅하는 데 유용합니다.