Skip to content

Add GraphQL fault-injection proxy (node + Python)#2

Open
jmbrunskill wants to merge 2 commits into
mainfrom
graphql-error-injection-proxy
Open

Add GraphQL fault-injection proxy (node + Python)#2
jmbrunskill wants to merge 2 commits into
mainfrom
graphql-error-injection-proxy

Conversation

@jmbrunskill

Copy link
Copy Markdown

A reverse proxy for manual testing of typed GraphQL errors and the
connection-lost banner — companion to open-msupply
PR #11444.
It sits between the client and the real omSupply server, proxies normally,
and lets you swap individual operations for typed GraphQL errors
(Unauthenticated, Forbidden, Bad user input, Internal error) or
simulate transport failures (offline, HTTP 500 no body, truncated body) via
a small web UI (/__mock) and a POST /__mock/control JSON API.

Two interchangeable implementations:

  • node/ — zero-dependency Node 18+ proxy (the default pick).
  • python/ — mitmproxy reverse proxy, using a newer two-stage rule
    schema (active master switch + composable delay_ms / response.kind).

This lands the directory across two commits: the initial node/python split

  • Python schema redesign, and this pass removing slow_stream and making
    the docs consistent.

Most recent change (this pass)

  • Removed the Python slow_stream / slow-trickle mode (code, UI, docs).
    Real chunked trickling via mitmproxy's flow.response.stream was
    unreliable — HTTP 200, empty body, then a client timeout — so it's removed
    rather than shipped broken. A fixed delay is still available via delay_ms
    / the Slow preset.
  • Rewrote python/README.md for the two-stage schema (it was stale and
    still documented the old mode-based schema).
  • Scrubbed inaccurate "slow trickle" mentions from the top-level and
    Node docs (the Node version never had it) and added a Future work
    section.

⚠️ Outstanding code-review items (carried, not addressed here)

All tracked in graphql-error-injection-proxy/WIP.md. The Node version
is still on the original mode-based schema and was not touched beyond doc
accuracy:

  1. Slow preset is a no-op bugmode:passthrough + delay_ms:5000, but
    ruleAppliesTo returns false for passthrough so the delay never fires
    (same root cause the Python rewrite fixed).
  2. Three near-identical upstream-forward blocks in handleGraphql should be
    deduped.
  3. Bare catch in truncate mode silently destroys the socket — add a
    console.error.
  4. respondHttpStatus writes a 26-byte body despite its "no body" comment.
  5. Stops logging errorType for non-error modes is still TODO.

Python (minor): verify the error body omits extensions when detail
is empty (Node omits the key; looks handled in the rewrite — worth a glance).

🔭 Follow-up work

  • Port the Node version to the two-stage rule schema so the two
    implementations match again (this also fixes the Node Slow-preset no-op).
  • Implement real slow-trickle streaming in Python — needs the mitmproxy
    Response.stream callable signature confirmed (single-chunk fn(bytes) -> bytes vs iterator fn(chunks) -> Iterator[bytes]); see python/README.md.
  • Once both are on the new schema, factor the shared presets / control HTML /
    rule shape into one place, or accept the divergence in writing.

Test steps

Manual-test helpers (no automated tests). Smoke-tested:

Python

  1. brew install mitmproxy
  2. Start a server on :8001, then
    mitmdump -s ./fault_injection_proxy.py --mode reverse:http://localhost:8001 --listen-port 8000
  3. Open http://localhost:8000/__mock.
  4. Verify: Off → transparent passthrough; Forbidden → typed error;
    delay_ms=2000 + kind=error takes ~2s then errors; Fail next 3 fires
    then auto-deactivates. (Confirmed passing.)
  5. Confirm no slow_stream preset/option remains in the UI.

Node: node server.js (forwards :8000:8001), open /__mock,
exercise presets.

Notes for reviewers

  • Intentionally a dev/manual-test tool — no auth on the control plane, which
    shares the data-plane port. Localhost-only.
  • No linked issue in this repo; the work supports open-msupply PR #11444.
    Labelled enhancement.

jmbrunskill and others added 2 commits June 8, 2026 12:43
…on schema

Mid-flight commit; see WIP.md in the directory for context on what's
done, what's broken (slow_stream trickling), and next steps.

- Split monorepo'd directory into node/ and python/ subdirs with a
  top-level README that compares the two.
- Extracted control-UI HTML out of both server.js and
  fault_injection_proxy.py into sibling control.html files.
- Python only: rewrote against a two-stage rule schema (active +
  composable delay_ms / response.kind), deleted dead helpers, fixed
  OPTIONS-preflight-to-/graphql bug, rewrote control.html to match.
  slow_stream chunked trickling is broken; everything else verified.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Real chunked trickling via mitmproxy's flow.response.stream was
unreliable (HTTP 200, empty body, then a client timeout), so the
slow_stream / slow-trickle mode is removed rather than shipped broken.
It's deferred to a future dev; python/README.md documents what an
implementation needs to check (the Response.stream callable signature).

- python: drop slow_stream from fault_injection_proxy.py + control.html
  (a fixed delay is still available via delay_ms / the Slow preset)
- python: rewrite README for the two-stage rule schema; it was stale and
  still documented the old mode-based schema
- scrub inaccurate "slow trickle" mentions from the top-level and node
  docs (the Node version never had it) and add a Future work section
- record the outstanding code-review items and follow-up in WIP.md

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant