test: adversarial robustness suite for the crawl pipeline - #1198
Draft
vringar wants to merge 1 commit into
Draft
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1198 +/- ##
==========================================
- Coverage 62.36% 60.09% -2.27%
==========================================
Files 40 41 +1
Lines 3930 4095 +165
==========================================
+ Hits 2451 2461 +10
- Misses 1479 1634 +155 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Generate adversarial circumstances for the crawl pipeline and assert it
degrades gracefully: forward progress (every started visit reaches a
terminal state), no silent data loss, no hang, proper incomplete-visit
recording, and the crawl continues via watchdog/BrowserManager recovery.
Browser-free tests drive the real StorageController subprocess in-process
(via DataSocket) and the asyncio server via raw sockets, injecting provider
faults, wire-protocol hostility, and malformed records. Browser-required
tests exercise the full TaskManager -> BrowserManager -> Firefox recovery
path for crashing/hanging custom commands and a mid-visit browser kill;
they skip cleanly where no launchable Firefox is present and run for real
in CI.
The pipeline survives socket hostility (server stays up after every hostile
frame incl. a 2 GiB length prefix; no hang), transient store failures (the
controller recovers on a fresh connection), and malformed records (huge
values + injection-y strings against the real SQLite path).
The suite captures confirmed defects as xfail(strict) tests (the failing
assertion is the finding; CI flags an XPASS once fixed):
- a raising store_record task strands the visit: it is never enqueued to
the completion queue, on finalize or shutdown -> data loss + a
callback-bearing CommandSequence hangs forever
- the same raise tears down the whole shared connection (BrokenPipe for
subsequent records); the TaskManager's single long-lived socket means
one bad record can break the crawl
- a permanent write_table fault crashes the controller mid-drain ->
completed visits lost
These fixes are design calls (count-and-continue vs fail-loud, and whether a
per-record failure should ever close the connection) and are left for a
maintainer; this change delivers the adversarial tests + findings and a docs
catalogue under docs/developers/Adversarial-Robustness.md.
vringar
force-pushed
the
test/adversarial-robustness
branch
from
July 20, 2026 22:54
81d684a to
b1a2e03
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adversarial robustness suite for the crawl pipeline
Generates adversarial circumstances for the crawl pipeline and asserts it
degrades gracefully: forward progress (every started visit reaches a terminal
state), no silent data loss, no hang, proper incomplete-visit recording, and
the crawl continues via the watchdog / BrowserManager recovery path.
What's added
test/storage/test_adversarial_storage_controller.py— drives the realStorageControllersubprocess in-process (real socket viaDataSocket),injecting provider faults. Covers write/flush faults (transient + permanent),
a raising
store_recordtask, and malformed/hostile records (the latteragainst the real SQLite provider).
test/storage/test_adversarial_socket.py— raw-socket wire-protocolhostility against the controller's asyncio server (truncated / garbage /
oversized / wrong-arity frames, non-sequence body, mid-message disconnect).
test/test_adversarial_pipeline.py— fullTaskManager→BrowserManager→ Firefox recovery for a crashing custom command, a hanging custom command,
and a browser killed mid-visit. Browser-required; skips cleanly where no
launchable Firefox is present, runs for real in CI.
test/storage/conftest.py—adversarial_mp_loggerfixture (captures logslike
mp_loggerbut does not assert log-cleanliness, since these testsintentionally provoke ERROR logging).
docs/developers/Adversarial-Robustness.md— catalogue of scenarios,survival vs. defect status, and the prioritized gap list.
What the pipeline survives (passing tests)
(including a 2 GiB length-prefix), a subsequent good visit still completes,
and shutdown never hangs.
fresh connection completes.
visit_id)against the real SQLite path.
Confirmed defects (captured as
xfail(strict=True)— the failing assertion is the finding; CI flags an XPASS once fixed)store_recordtask strands the visit. The controllerfires un-awaited asyncio store tasks; the exception only surfaces when
finalize_visit_idawaits them, after popping them and before recording thecompletion token — so the visit is never enqueued to the completion queue, on
finalize or on shutdown (browser-crash case). A callback-bearing
CommandSequencewould hang forever and the visit is silently lost.for subsequent records). The
TaskManagerkeeps one long-livedDataSocketfor
site_visits/crawl_history/finalizeacross all visits, so one badrecord can break the socket for the rest of the crawl. (The controller itself
recovers on a fresh connection — proven by the transient-recovery test.)
write_tablefault raises out offlush_cacheduringshutdown, crashing the controller before the completion queue is drained —
completed visits lost.
Pre-existing and related: G3 — SQLite silently drops unknown-table/column
records (and PRIMARY-KEY conflicts), logged only as "Unsupported record"
(crosslink #28/#30). A crashing extension modification (S2) is documented as a
design item; its recovery shape is covered by the mid-visit browser-kill test.
The G1/G1b/G2 fixes are design calls (count-and-continue vs. fail-loud when the
provider itself fails, and whether a per-record failure should ever close the
connection) and are left for a maintainer; the deliverable here is the
adversarial tests + findings.
Relates to #28 / #30 (silent drop) and the socket-reliability thread.
🤖 Generated with Claude Code