SurfSense/surfsense_backend/tests/unit
DESKTOP-RTLN3BA\$punk bdacea8b6e feat(crawler): captcha solving + per-attempt billing (Phase 3d)
Wire captchatools as the StealthyFetcher-tier page_action to detect, harvest
(egressing from the crawl's own proxy IP), inject, and submit reCAPTCHA v2/v3
and hCaptcha tokens. Opt-in and off by default (zero attempts, zero cost).

Licensing split:
- Apache-2 app/utils/captcha/ holds the generic, vendor-agnostic config
  (CaptchaConfig + captcha_enabled() = flag AND key present).
- Proprietary app/proprietary/web_crawler/captcha.py holds the bypass logic
  (detect/harvest/inject) plus a process-wide solver latch that halts solving
  on unrecoverable errors (no balance / bad key).

Crawler: CrawlOutcome gains captcha_attempts/captcha_solved, surfaced via a
per-call captcha_state dict threaded crawl_url -> _crawl_with_stealthy(_sync)
and stamped onto every stealth terminal outcome. The stealth tier captures the
proxy once and reuses it for both the fetch and the solver (IP-coherence).

Billing: WebCrawlCreditService gains captcha_billing_enabled,
captcha_solves_to_micros, charge_captcha, and a generic check_balance, sharing
a single _apply_debit path. The indexer accumulates attempts (even on failed
crawls), runs a combined crawl+captcha pre-flight, and posts a per-attempt
owner charge as usage_type="web_crawl_captcha". The captcha worst-case is only
reserved when solving is actually enabled, so a solving-off deployment is never
blocked for captcha that can never run. Both chat scrape tools fold attempts
into the current turn before the success/fail branch.

Fully config-driven prices; no migration. New unit tests cover the config,
factory (detection/latch/timeout/cap), credit service, indexer wiring, and the
chat fold.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 22:58:21 -07:00
..
adapters test: bootstrap pytest environment for backend 2026-02-24 18:19:56 +02:00
agents test: rename SearchSpace -> Workspace across tests + fixtures (Phase 2 Wave F) 2026-06-26 18:36:46 +02:00
automations feat(03a): implement Scrapling-only web crawler and remove Firecrawl integration 2026-06-29 20:37:56 -07:00
connector_indexers feat(crawler): captcha solving + per-attempt billing (Phase 3d) 2026-06-29 22:58:21 -07:00
connectors chore: ran linting 2026-04-07 05:55:39 +05:30
db feat: improved agent streaming 2026-04-29 07:20:31 -07:00
e2e_fakes test(backend): enhance Drive file filtering and add unit tests for _drive_list_files 2026-05-06 17:58:58 +05:30
etl_pipeline test(etl-cache): cover over-budget eviction selection 2026-06-12 11:50:52 +02:00
event_bus test: rename SearchSpace -> Workspace across tests + fixtures (Phase 2 Wave F) 2026-06-26 18:36:46 +02:00
gateway test: rename SearchSpace -> Workspace across tests + fixtures (Phase 2 Wave F) 2026-06-26 18:36:46 +02:00
google_unification chore: ran linting 2026-05-09 05:28:09 +05:30
indexing_pipeline test: rename SearchSpace -> Workspace across tests + fixtures (Phase 2 Wave F) 2026-06-26 18:36:46 +02:00
middleware test: rename SearchSpace -> Workspace across tests + fixtures (Phase 2 Wave F) 2026-06-26 18:36:46 +02:00
notifications test: rename SearchSpace -> Workspace across tests + fixtures (Phase 2 Wave F) 2026-06-26 18:36:46 +02:00
observability test: rename SearchSpace -> Workspace across tests + fixtures (Phase 2 Wave F) 2026-06-26 18:36:46 +02:00
podcasts test: rename SearchSpace -> Workspace across tests + fixtures (Phase 2 Wave F) 2026-06-26 18:36:46 +02:00
proprietary feat(crawler): captcha solving + per-attempt billing (Phase 3d) 2026-06-29 22:58:21 -07:00
routes test: rename SearchSpace -> Workspace across tests + fixtures (Phase 2 Wave F) 2026-06-26 18:36:46 +02:00
services feat(crawler): captcha solving + per-attempt billing (Phase 3d) 2026-06-29 22:58:21 -07:00
tasks test: rename SearchSpace -> Workspace across tests + fixtures (Phase 2 Wave F) 2026-06-26 18:36:46 +02:00
utils feat(crawler): captcha solving + per-attempt billing (Phase 3d) 2026-06-29 22:58:21 -07:00
__init__.py test: bootstrap pytest environment for backend 2026-02-24 18:19:56 +02:00
test_error_contract.py chore: linting 2026-04-22 01:05:31 -07:00
test_obsidian_plugin_indexer.py chore: linting 2026-04-27 14:04:50 -07:00
test_pat_fail_closed_static.py test: rename SearchSpace -> Workspace across tests + fixtures (Phase 2 Wave F) 2026-06-26 18:36:46 +02:00
test_zero_authz_static.py fix(authz):add zero context authorization checks 2026-06-23 12:55:25 +05:30