Skip to content

Quick Scan feature (v1.1.0 candidate)#2

Merged
osintph merged 8 commits into
mainfrom
feature/quick-scan
Jul 4, 2026
Merged

Quick Scan feature (v1.1.0 candidate)#2
osintph merged 8 commits into
mainfrom
feature/quick-scan

Conversation

@osintph

@osintph osintph commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Adds an ad-hoc Quick Scan feature for target investigation, independent of the existing project/keyword/IOC pipeline. Delivered as six layered, reviewable commits. Full suite green: 133 passed, 2 skipped (71/2 baseline + 62 new, zero regressions). New files pass ruff with no new lint errors.

Files changed, grouped by commit

Commit 1 — storage models and Storage methods

  • src/darkweb_scanner/storage.py (+146): QuickScanSession + QuickScanFinding models and 7 Storage methods.

Commit 2 — source config module and normalization logic

  • src/darkweb_scanner/quick_scan_sources.py (+180, new): typed QuickScanSource registry.
  • src/darkweb_scanner/quick_scan.py (+164, new): pure detection / normalization / high-signal / context logic.

Commit 3 — orchestrator run_quick_scan

  • src/darkweb_scanner/quick_scan.py (+229): async orchestrator with Tor + safe_fetch dispatch, depth/URL/timeout caps.

Commit 4 — /api/quick-scan/ routes*

  • src/darkweb_scanner/dashboard/dashboard_routes.py (+169): start/status/sessions/findings + /quick-scan page.
  • src/darkweb_scanner/dashboard/http_client.py (+4): allowlist entry.

Commit 5 — Quick Scan tab UI

  • src/darkweb_scanner/dashboard/templates/quick_scan.html (+357, new): standalone page + vanilla-JS polling.
  • src/darkweb_scanner/dashboard/templates/index.html (+1): sidebar nav link.

Commit 6 — unit and integration test suite

  • tests/unit/test_quick_scan_target_detection.py (+80)
  • tests/unit/test_quick_scan_high_signal.py (+76)
  • tests/integration/test_quick_scan_orchestration.py (+155)
  • tests/integration/test_quick_scan_routes.py (+179)

Deviations from spec, with justification

  1. UI is a standalone page, not an in-SPA panel. The dashboard is a single index.html with no static/ dir. This honors the spec's literal GET /quick-scanquick_scan.html requirement; the sidebar entry navigates there.
  2. dpaste.org and rentry.co ship disabled. Neither exposes a documented public search endpoint, so per the spec's own "otherwise skip cleanly" clause both are registered with empty url_templates. The clearnet safe_fetch path is fully implemented and tested (test_clearnet_path_uses_safe_fetch); enabling a paste source is a one-line change once an endpoint exists.
  3. Unauthenticated requests return 302, not 401. The platform-wide @require_login decorator redirects to the login page; shared auth behavior was not altered. Cross-user (403) and double-start (409) match the spec exactly.
  4. Single-active-scan guard is DB-backed (has_active_quick_scan over pending/running) rather than an in-process global like the existing crawler. Correct across gunicorn workers — addresses SECURITY_REVIEW_FABLE finding #5 rather than replicating that flaw.
  5. 10-minute total cap is enforced cooperatively at fetch granularity (deadline checked before each batch and each fetch), so worst-case overshoot is one 30s per-source timeout rather than a hard mid-fetch kill that would lose accumulated findings. Verified by test_total_timeout_marks_session_completed_with_warning (marks completed + warning).

Allowlist additions to http_client.py

Exactly one host added to ALLOWED_EXTERNAL_HOSTS:

  • dpaste.org — clearnet paste source, fetched via safe_fetch (HTTPS-only, IP-blocklisted). Added with a comment noting the source ships disabled pending a search endpoint.

rentry.co was not added (disabled source, no outbound calls). Onion sources (Ahmia, Torch, Haystak, ransomware seeds) need no allowlist entry — they route through Tor.

Smoke test pending

Manual smoke test against a benign domain (e.g. example.com) on a deployed instance with a live Tor daemon is not yet run — it requires the running stack. Expected: UI updates live, findings are stored, and the session completes cleanly.

🤖 Generated with Claude Code

osintph and others added 8 commits July 4, 2026 15:11
…sions and quick_scan_findings

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…_scan.py

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ntegration

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds start/status/sessions/findings endpoints plus the /quick-scan page route,
all @require_login. Ownership checks return 403; a DB-backed active-scan guard
returns 409. Adds dpaste.org to ALLOWED_EXTERNAL_HOSTS for the clearnet paste path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two concurrent first requests could both instantiate Storage and race
Base.metadata.create_all in Postgres (UniqueViolation on
pg_type_typname_nsp_index). Guard the storage_helper singleton with
double-checked locking; the CLI path keeps _create_tables in
Storage.__init__ unchanged. Also make checkfirst=True explicit on
create_all.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011pZtyQhe6HVvB6Pq3UQzvP
…nd progress logging

- POST /api/quick-scan/cancel/<session_id>: owner-only (404/403/400 guards),
  flips status to cancelled and stamps completed_at.
- run_quick_scan honors cancellation at every source and fetch boundary via
  _is_cancelled; on cancel it stops early, syncs counters, and never stamps
  completed. Also refuses to start a session already cancelled while pending.
- INFO logging at each stage: source query start/complete with URL count,
  fetch start/complete/timeout, finding created, cancellation detected.
- Cancel button in the Activity panel, visible only while pending/running.
- Integration tests: mid-run cancel with a real worker thread (event-gated
  fetch stub), plus 404/403 cancel guards.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011pZtyQhe6HVvB6Pq3UQzvP
@osintph

osintph commented Jul 4, 2026

Copy link
Copy Markdown
Owner Author

Smoke tested on the VPS against the feature branch. Verified:

  • Fresh scan starts and completes (example.com, 88 URLs, 0 findings, ~4 min)
  • Cancel button interrupts a running scan (bpi.com.ph, status transitioned to cancelled cleanly)
  • Previous sessions table renders both completed and cancelled correctly
  • Three-restart race check on the singleton lock passed with no create_tables errors

Merging as v1.1.0 candidate. Documentation and release commit to follow in a separate PR.

@osintph
osintph merged commit fcf47b5 into main Jul 4, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant