Skip to content

Commit 649be88

Browse files
committed
Add live integration tests, Render deployment, proxy rate limit fix
Integration tests (test_integration.py): - Added 10 new live-network tests covering Sprint 2 and Sprint 3 features (tests 15-24): DNS resolve, enumerate, DNSSEC, DNSBL, email security, propagation, TLS inspect, CT logs, Shodan threat intel, RIPE PDNS - Tests use real external APIs with no mocks; assertions are plausible-value checks (not fragile exact-value checks) with SKIP fallback for transient network issues - Total: 24 live integration tests covering all 27 tools api.py — proxy rate limit fix: - Replaced get_remote_address (returns proxy IP behind Render/nginx) with _real_ip() which checks X-Forwarded-For → X-Real-IP → direct connection - Prevents all users sharing one rate limit bucket when deployed behind a reverse proxy (Render, Cloudflare, nginx, etc.) render.yaml — Render.com Blueprint deployment config: - Web Service: uvicorn api:app, free plan, auto-deploy on git push - Health check: /v1/meta/status - Env vars: PEERGLASS_ALLOWED_ORIGINS (CORS), GREYNOISE_API_KEY (optional) - Static Site section pre-written for Sprint 7 Web UI (commented out) - Documents free tier limitations (sleep, cache wipe, no persistent storage) requirements.txt: - Added for pip-based deployment environments (Render, Railway, Heroku) - Mirrors pyproject.toml dependencies https://claude.ai/code/session_01HbqpFDHjFtjBm3Kf6e6YAp
1 parent 9fea657 commit 649be88

4 files changed

Lines changed: 397 additions & 1 deletion

File tree

api.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,23 @@
4949
from slowapi.util import get_remote_address
5050
from slowapi.errors import RateLimitExceeded
5151

52-
limiter = Limiter(key_func=get_remote_address)
52+
53+
def _real_ip(request: Request) -> str:
54+
"""
55+
Extract the real client IP, respecting X-Forwarded-For and X-Real-IP
56+
headers set by reverse proxies (Render, nginx, Cloudflare, etc.).
57+
Falls back to direct connection address if no proxy headers are present.
58+
"""
59+
forwarded_for = request.headers.get("X-Forwarded-For")
60+
if forwarded_for:
61+
return forwarded_for.split(",")[0].strip()
62+
real_ip = request.headers.get("X-Real-IP")
63+
if real_ip:
64+
return real_ip.strip()
65+
return get_remote_address(request)
66+
67+
68+
limiter = Limiter(key_func=_real_ip)
5369

5470
import rir_client
5571
import cache as cache_module

render.yaml

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# render.yaml — PeerGlass deployment on Render.com
2+
# Docs: https://render.com/docs/blueprint-spec
3+
#
4+
# Deploy instructions:
5+
# 1. Push this repo to GitHub
6+
# 2. Go to https://dashboard.render.com → New → Blueprint
7+
# 3. Connect your GitHub repo — Render auto-reads this file
8+
# 4. Set GREYNOISE_API_KEY in the dashboard (optional, for threat intel)
9+
# 5. Done — API is live at https://peerglass-api.onrender.com
10+
#
11+
# Architecture on Render:
12+
# ┌─────────────────────────────────────────────┐
13+
# │ peerglass-api (Web Service — Python) │
14+
# │ uvicorn api:app → /v1/ip, /v1/dns, … │
15+
# │ Auto-deploys on every git push to main │
16+
# └─────────────────────────────────────────────┘
17+
# ┌─────────────────────────────────────────────┐
18+
# │ peerglass-ui (Static Site — Sprint 7) │
19+
# │ React + Vite build → dist/ │
20+
# │ Note: uncomment when Web UI is built │
21+
# └─────────────────────────────────────────────┘
22+
#
23+
# IMPORTANT LIMITATIONS on free tier:
24+
# - Service SLEEPS after 15 min of inactivity → ~30s cold start
25+
# - In-memory cache (cache.py) is wiped on sleep/redeploy
26+
# - Change monitor baselines are lost on sleep
27+
# - Upgrade to Starter ($7/mo) for always-on with persistent cache
28+
#
29+
# MCP stdio server (server.py) is NOT deployable here —
30+
# it runs locally inside Claude Desktop as a stdio subprocess.
31+
32+
services:
33+
# ── REST API ─────────────────────────────────────────────────
34+
- type: web
35+
name: peerglass-api
36+
runtime: python
37+
plan: free # upgrade to starter for always-on
38+
region: oregon # closest to RIR servers (ARIN/APNIC)
39+
branch: main
40+
buildCommand: pip install -r requirements.txt
41+
startCommand: uvicorn api:app --host 0.0.0.0 --port $PORT
42+
healthCheckPath: /v1/meta/status
43+
44+
envVars:
45+
# CORS — set to your frontend domain in production
46+
# e.g. "https://your-username.github.io" or "*" for open access
47+
- key: PEERGLASS_ALLOWED_ORIGINS
48+
value: "*"
49+
50+
# Optional — enables GreyNoise threat classification
51+
# Free API key: https://www.greynoise.io/plans/community
52+
- key: GREYNOISE_API_KEY
53+
sync: false # set manually in Render dashboard
54+
55+
autoDeploy: true # redeploy on every push to branch
56+
57+
# ── Web UI (uncomment after Sprint 7 builds the React UI) ────
58+
# - type: web
59+
# name: peerglass-ui
60+
# runtime: static
61+
# plan: free # static sites never sleep
62+
# branch: main
63+
# buildCommand: cd ui && npm ci && npm run build
64+
# staticPublishPath: ui/dist
65+
# pullRequestPreviewsEnabled: true
66+
# headers:
67+
# - path: /*
68+
# name: X-Frame-Options
69+
# value: DENY
70+
# - path: /*
71+
# name: X-Content-Type-Options
72+
# value: nosniff
73+
# routes:
74+
# - type: rewrite
75+
# source: /*
76+
# destination: /index.html # SPA fallback for client-side routing

requirements.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# PeerGlass — Python dependencies
2+
# Generated from pyproject.toml for Render.com and other pip-based deployments.
3+
#
4+
# Install: pip install -r requirements.txt
5+
# Dev install (editable): pip install -e .
6+
7+
mcp[cli]>=1.0.0
8+
httpx>=0.27.0
9+
pydantic>=2.0.0
10+
fastapi>=0.110.0
11+
uvicorn[standard]>=0.27.0
12+
slowapi>=0.1.9
13+
dnspython>=2.4.0

0 commit comments

Comments
 (0)