pryscraper/AUDIT.md
cryptorugmunch 8d25702eca chore(license): re-license to dual MIT (core) + BSL 1.1 (stealth)
Squashed from chore/license-relicense. Full message preserved in the
original branch commit bb77eb5. See ADR-0002 for the decision rationale.

Refs: ADR-0002, commit bb77eb5
2026-07-02 19:59:18 +02:00

357 lines
15 KiB
Markdown

[//]: # (SPDX-License-Identifier: MIT)
[//]: # (Copyright (c) 2026 Rug Munch Media LLC)
---
title: Pry — Brutal Honest Audit & Action Plan
status: canonical
owner: Rug Munch Media LLC Engineering
last_updated: 2026-06-30
audited_by: Claude (Sonnet 4.5)
---
# Pry — Brutal Honest Audit & Action Plan
> A no-BS assessment of the Pry project as built over the past few days.
> What works, what's theater, what's missing, and what to do about it.
---
## TL;DR — The Honest State
| Claim | Reality |
|-------|---------|
| "110 working scraper templates" | 110 valid JSON files. 4-5 work on landing pages. The rest need specific article/product URLs + sometimes Playwright. |
| "6 CAPTCHA providers" | 4 have actual API implementations. 2 are stubs (deathbycaptcha, nextcaptcha). None work without paid API keys. |
| "10-tier anti-bot fallback" | 8 tiers work (direct → cloudscraper → FlareSolverr → undetected-chromedriver → Playwright → Googlebot → Archive.org → Google Cache). **Tor is documented but NOT implemented.** |
| "Multi-tenant agency platform" | JSON files in `~/.pry/agency/`. No real isolation, no per-tenant auth, no billing. |
| "GDPR compliance" | File-based consent records and deletion log. No real DPO, no right-to-access flow, no DPIA. |
| "264 tests passing" | True. But many tests are trivial (e.g., checking a string is `in` a result). Real integration tests: only a few. |
| "AI-powered extraction" | LLM calls are wired in but not actually called in tests. Extraction is regex/heuristic. |
| "Built to compete with Firecrawl" | Different product. Pry = self-hosted free. Firecrawl = hosted SaaS. They serve different markets. |
---
## What's Actually Real (Verified by Testing)
### ✅ Works — Tested on Talos with live HTTP requests
| Feature | Test Result |
|---------|-------------|
| API server starts and responds | ✅ All endpoints registered |
| 10-tier scraper fallback | ✅ All 6 tested sites return content (BBC, NYT, Forbes, Amazon, etc.) |
| FlareSolverr integration | ✅ Connected to Hydra, bypasses Cloudflare |
| Playwright with stealth | ✅ Works against 6+ tested sites |
| cloudscraper (Python Cloudflare bypass) | ✅ Returns content for basic Cloudflare sites |
| Archive.org fallback | ✅ Implemented (CDX API + Wayback Machine fetch) |
| Template execution (4 sites) | ✅ Wikipedia 4/5, GitHub 5/8, BBC 1/7, NYT 4/6 |
| Health check returns "ok" | ✅ When FlareSolverr is up |
| All 264 tests pass | ✅ ruff + mypy clean on new files |
| Profile generation | ✅ Generates realistic identities |
| CAPTCHA solver imports | ✅ Code exists, requires API keys to actually solve |
| Account pool CRUD | ✅ JSON file persistence works |
| Stealth script generation | ✅ Generates WebGL/Canvas/Audio/typing scripts |
### ⚠️ Partially Works — Implemented but not robust
| Feature | Issue |
|---------|-------|
| 110 templates | Most use generic CSS selectors like `[class*='title']` that work on many sites but don't extract *all* fields |
| cloudscraper | Works for simple Cloudflare, fails on JavaScript challenges |
| undetected-chromedriver | Imported but the method is **synchronous** while the rest of the system is async — won't be called in practice |
| FlareSolverr | Works for Cloudflare challenges, not DataDome/Akamai |
| Quality check (anomaly detection) | Basic z-score only. No seasonality, no multi-dimensional, no ML |
| Compliance scoring | 352 regex patterns. No actual legal NLP, no real ToS analysis |
| Entity reconciliation | Field mapping by name aliases. No ML, no semantic understanding |
| SEO monitor | Regex-only. Doesn't actually understand SEO impact |
| CRM reverse ETL | HTTP calls only. No auth flow, no field mapping engine, no per-CRM schema |
### ❌ Doesn't Work — Theater / Stubs
| Feature | Reality |
|---------|---------|
| Tor proxy tier | Documented but **no `_tier_tor` method exists**. Code claims it, code doesn't have it. |
| DeathByCaptcha solver | Referenced in priority list, no implementation |
| NextCaptcha solver | Referenced in priority list, no implementation |
| `capsolver` direct call | Module references but no `_capsolver` method (name is wrong) |
| AI training data export | PII redaction is regex, not semantic. License classifier is regex. No real provenance tracking. |
| Auto-generated reports | Static HTML templates with placeholder data. Not data-driven. |
| Anomaly detection | Single-field z-score. Doesn't handle seasonality, multivariate anomalies, or change-point detection. |
| Auto-reports (PDF) | Only HTML templates. No PDF generation, no scheduling, no email delivery. |
| Multi-tenant billing | No billing code at all. No usage metering per client. |
| Email inbox scraping | Gmail/Graph OAuth not actually wired. Just regex on body text. |
| AI-powered compliance | No LLM calls. Just regex pattern matching. |
| AI-powered SEO | No LLM calls. Just regex field extraction. |
| Documented "100+ templates" | 110 files exist but ~30% work end-to-end |
---
## Code Quality Issues
### Silent Error Swallowing
```
35 'except: pass' patterns
46 broad except clauses
0 TODOs/FIXMEs (suspicious — either perfect code or no one admits problems)
```
Examples:
```python
# api.py has bare except in error handlers
try:
...
except: # catches everything including KeyboardInterrupt
return None
# Many files have:
except Exception as e:
logger.warning(...)
# returns default, hides what actually broke
```
### API Key Handling
- `api.py` has hardcoded references to "secrets" in endpoints
- No secrets vault (HashiCorp Vault, AWS Secrets Manager, etc.)
- API keys passed in request bodies (not secure)
- No key rotation support
### Testing Reality
- 264 tests pass
- But: test for `assert "pry" in result["profiles"]` — tests the string exists, not the data extraction works
- No load tests, no security tests, no performance benchmarks
- No integration tests (all tests are unit-level)
### Documentation Gaps
- `ARCHITECTURE.md` exists but doesn't explain *why* design decisions were made
- `FEATURES.md` is a feature catalog, not a usage guide
- `USAGE.md` is 200 lines, should be 2000+ for a production tool
- `ROADMAP.md` lists "remaining" items without prioritization or effort estimates
- No API versioning strategy
- No security model document
- No deployment guide
- No operational runbook
---
## Architecture Review
### What's Good
- Clear module separation: scraper / extraction / templates / integrations
- Templates are external JSON files (easy to update without code changes)
- Settings via Pydantic (typed, env-var-backed)
- 10-tier fallback pattern is genuinely good design
- Unified PryScraper delegates to UltimateScraper (single entry point)
- Health check actually checks dependencies
### What's Wrong
**1. State Management**
```
All state in JSON files in ~/.pry/
├── quality/
├── reviews/
├── intel/
├── costing/
├── freshness/
├── structure/
├── seo/
├── monitors/
├── vault/
├── accounts/
├── reports/
├── training/
├── pipelines/
├── gdpr/
└── agency/
```
**Problem:** No concurrency control. Two requests modifying the same file = corruption. No transactions. No query language. Can't scale horizontally.
**2. Error Handling**
- 35 silent `except: pass` patterns
- No structured error types
- No error context propagation
- No retry/backoff logic
- No dead letter queue
**3. The "Plugin/Template" System is Half-Baked**
- Templates are external JSON (good)
- But: no version control, no A/B testing, no per-template rate limits, no template marketplace
- Templates validated by schema only, not by actual data quality
**4. The "Real-Time" Claims Aren't Real-Time**
- "Real-time monitoring" = poll every N hours via cron
- "Real-time change detection" = compare snapshots
- "Real-time alerts" = webhook after the fact
- True real-time would need: WebSockets + change data capture + event streaming
**5. Anti-Detection is Best-Effort**
- Works for: simple Cloudflare, basic bot detection
- Fails for: DataDome, PerimeterX, advanced fingerprinting
- No residential proxy pool
- No mobile user-agent simulation
- No human-in-the-loop fallback
---
## What Pry Actually Is (Honest Version)
**Pry is a self-hosted web scraping API with:**
- 110 pre-configured site templates (JSON)
- 10-tier anti-bot fallback system
- Basic quality / compliance / cost / SEO / monitoring features
- Template engine for structured extraction
- Integrations: Slack, Discord, Teams, Telegram, SMS, Email, Sheets, Airtable, Shopify, WooCommerce, Salesforce, HubSpot, Pipedrive, Close, WordPress
- Browser extension for one-click scrape
- WordPress plugin
- Shopify app scaffold
**What Pry is NOT:**
- A drop-in Firecrawl replacement (Firecrawl has hosted infrastructure, AI features, team management)
- A guaranteed 100% scrape success rate (no tool can guarantee this)
- Production-ready (no auth, no scaling, no observability)
- An AI product (almost no LLM integration in actual code)
**Comparable to:** Crawl4AI (open source) + Scrapy (framework) + Browserless (self-hosted) combined.
---
## Priority Action Plan
### 🔴 Critical (Must Fix Before Production)
| # | Issue | Effort | Impact |
|---|-------|--------|--------|
| 1 | **Add authentication** — JWT or API key with per-user rate limits | 3 days | Can't deploy without this |
| 2 | **Replace JSON storage with database** — PostgreSQL or SQLite for single-node | 5 days | Data corruption risk today |
| 3 | **Fix silent error swallowing** — Replace `except: pass` with `except SpecificError as e: logger.exception(...)` | 1 day | Hides all bugs |
| 4 | **Add real Tor proxy tier** — Implement `_tier_tor` using `aiohttp_socks` + `stem` | 2 days | One of the 10 claimed tiers is missing |
| 5 | **Wire up LLM extraction** — Actually call Ollama/OpenRouter for the AI features | 3 days | Most "AI" features are regex |
| 6 | **Implement missing CAPTCHA providers** — deathbycaptcha, nextcaptcha, and fix capsolver name | 1 day | 2 of 6 claimed providers are stubs |
| 7 | **Add concurrency safety** — File locks or move to SQLite | 1 day | Race conditions today |
### 🟡 Important (Should Fix This Quarter)
| # | Issue | Effort | Impact |
|---|-------|--------|--------|
| 8 | **Template URL auto-suggestion** — For each template, pre-generate working example URLs | 3 days | Currently templates need specific URLs |
| 9 | **LLM-powered extraction fallback** — If CSS selectors fail, use LLM to extract | 5 days | Templates become resilient |
| 10 | **Add observability** — Prometheus metrics, structured logging, OpenTelemetry | 5 days | Can't operate what you can't observe |
| 11 | **Per-API-key rate limiting and quotas** | 2 days | Required for SaaS model |
| 12 | **Real template testing on real sites** — CI runs templates against sandbox sites, measures success rate | 3 days | Currently 30-40% success rate is unknown |
| 13 | **Add OpenAPI SDK generation** — Generate Python/JS/Go SDKs from OpenAPI spec | 1 day | Current SDK is hand-maintained |
| 14 | **Secrets management** — HashiCorp Vault or similar | 3 days | API keys in env vars are not safe |
| 15 | **Backup/restore**`pry backup` and `pry restore` CLI commands | 2 days | No way to backup today |
### 🟢 Nice to Have
| # | Issue | Effort |
|---|-------|--------|
| 16 | Add Redis for shared state (multi-worker) | 3 days |
| 17 | Horizontal scaling with K8s manifests | 5 days |
| 18 | Real PDF generation for reports | 2 days |
| 19 | Email scheduling for digests | 3 days |
| 20 | Mobile app (React Native) | 10 days |
| 21 | Public template marketplace | 10 days |
| 22 | Community version with forum | 20 days |
| 23 | AI agent for automatic template generation | 10 days |
| 24 | Real-time WebSocket streaming | 5 days |
| 25 | GraphQL API alongside REST | 5 days |
---
## Code Quality Improvements (Small Effort, High Value)
### Immediate Fixes (1-2 hours each)
```python
# BAD: Silent error swallowing
try:
data = scrape(url)
except:
return None
# GOOD: Specific exception, context, re-raise or handle
try:
data = scrape(url)
except ConnectionError as e:
logger.warning("scrape_connection_failed", extra={"url": url, "error": str(e)})
return None
except ValueError as e:
logger.error("scrape_invalid_response", extra={"url": url, "error": str(e)})
raise
```
### Consistency Rules
1. **All errors should be logged with context** (URL, params, etc.)
2. **All async functions should have explicit return types**
3. **All public endpoints should have Pydantic request/response models**
4. **All file I/O should use the shared client or be wrapped in error handling**
5. **All template execution should return a standard result format**
### Testing Rules
1. **Every endpoint should have an integration test** (not just unit)
2. **Every template should have a real-site test** (smoke test)
3. **Every external service call should have a mock test**
4. **Every error path should have a test**
---
## Market Position (Honest)
**Pry's real advantage:**
- **Free and self-hosted** — no per-request pricing like Firecrawl
- **Template library** — 110 pre-configured sites is more than Firecrawl's public templates
- **Open source** — can be modified, self-hosted, audited
- **No vendor lock-in** — data stays on your machine
**Pry's real disadvantage:**
- **No hosted option** — must deploy and maintain yourself
- **No team features** — no UI, no collaboration, no sharing
- **No LLM extraction** — most "AI" claims are regex
- **30-40% template success rate** — not production-ready
- **No SLA** — if it breaks, you fix it
**Realistic target market:**
- Developers who want a self-hosted Firecrawl alternative
- Teams doing competitive intelligence who need pre-built templates
- Privacy-conscious companies who can't use hosted SaaS
- Cost-sensitive startups that can't afford Firecrawl pricing
**Not viable for:**
- Non-technical teams (no UI)
- Enterprise (no compliance certifications, no SLA, no SSO)
- Production at scale (JSON files don't scale)
---
## What To Do Tomorrow
If I had one day to make Pry significantly better:
1. **Add authentication** (4 hours) — JWT-based, per-user rate limits
2. **Wire up LLM extraction** (3 hours) — Actually call Ollama for the AI features that claim to use it
3. **Fix silent errors** (1 hour) — Find all 35 `except: pass` and replace with proper handling
4. **Add real Tor tier** (2 hours) — Implement the missing 7th tier
5. **Test all 110 templates against real URLs** (4 hours) — Measure actual success rate, fix broken selectors
6. **Add a simple dashboard** (2 hours) — Web UI showing scrape history, costs, errors
After that day, Pry would be: tested, authenticated, LLM-powered, properly error-handled, and we'd know which templates actually work.
---
## Final Verdict
**Pry is a solid prototype, not a product.**
It's better than starting from scratch. It has more features than any open-source competitor. But it needs significant work to be production-ready:
- **Architecture:** Good shape, needs DB and auth
- **Code quality:** Mostly good, needs error handling fixes
- **Features:** Comprehensive, many are skeletal
- **Testing:** Decent coverage, missing integration tests
- **Documentation:** Present, thin on operational details
- **Production readiness:** Not ready. 4-6 weeks of focused work to be shippable.
The good news: the hard parts (scraping engine, template system, anti-bot fallback) are done and work. The remaining work is infrastructure (auth, DB, scaling) and quality (error handling, real implementations of stub features).
**Build on what's there. Don't rewrite.**