Skip to content

[FEATURE] Fuzz the pgwire and MCP server interfaces as part of build CI #803

Closed

Description

@jeffreyaven

Feature Description
Add fuzz testing for the two protocol-facing server surfaces of stackql and run it in build.yml:

  • the PostgreSQL wire protocol server (stackql srv, backed by github.com/stackql/psql-wire)
  • the MCP server (stackql mcp, stdio and HTTP transports, backed by github.com/modelcontextprotocol/go-sdk)

Expected behaviour under malformed, truncated, oversized or out-of-sequence input: the server returns a protocol-level error (pgwire ErrorResponse; JSON-RPC -32700 / -32600 / -32601 / -32602) and stays available for subsequent requests. It must not panic, exit, hang, or grow memory without bound.

Proposed CI shape:

  • PRs and pushes: short, time-boxed fuzz run per target (for example 30-60s each), failing the job on any crasher
  • Scheduled (nightly or weekly): longer run with a persisted corpus
  • Crashing inputs uploaded as artifacts, then committed to the seed corpus as regression cases once fixed

Example(s)
Both servers parse input from clients that stackql does not control - SQL drivers and BI tools on pgwire, agents and LLM-generated tool calls on MCP. Current CI exercises both through the robot suites using psql and the MCP client, which only send well-formed traffic, so parser and state-machine edge cases are not covered.

Inputs of interest:

  • pgwire: startup / SSLRequest / CancelRequest packets, message length fields that disagree with the payload, simple query and extended query (Parse / Bind / Describe / Execute / Sync) messages out of order, unknown message types, mid-message disconnects
  • MCP: malformed or partial JSON-RPC frames, invalid UTF-8, requests before initialize, unknown methods, tools/call with missing, mistyped or oversized arguments for each tool, large payloads

A previous defect of this class: a malformed JSON-RPC frame on the stdio transport caused the read loop to exit on the decode error instead of returning -32700.

Possible Approaches or Libraries to Consider

  • Go native fuzzing (testing.F, go test -fuzz=... -fuzztime=...) for in-process targets: pgwire message decoding and session handling, MCP request handling. Seed corpus under testdata/fuzz. go test accepts one -fuzz target per invocation, so CI loops over targets.
  • mcp-server-fuzzer for black-box protocol and tool-argument fuzzing against the built binary over stdio and HTTP, extending the earlier integration work rather than starting again.
  • A pgwire black-box harness against a running stackql srv: build valid frames with github.com/jackc/pgx/v5/pgproto3 (pgx is already a dependency) and mutate them, or use boofuzz for a stateful protocol grammar, which fits alongside the existing Python test tooling.
  • Liveness assertion after each iteration or batch: a known-good query on pgwire and tools/list on MCP must still succeed.
  • ClusterFuzzLite (runs in GitHub Actions) or OSS-Fuzz for continuous fuzzing with corpus management, reusing the same Go fuzz targets.

Additional context

  • Placement: a fuzz job in build.yml that depends on linuxbuild and consumes its binary artifact for the black-box runs, plus the go test -fuzz targets. Linux amd64 only is enough to start.
  • Protocol-level fuzz targets for pgwire may belong in stackql/psql-wire, with this repo covering the integrated server.
  • The fuzz job should run with no provider credentials, against the mock provider setup the robot tests already use, so no fuzzed call reaches a real API.
  • Keep the PR-time budget small (a few minutes total) so it does not materially extend the build.
  • Done when: fuzz targets exist for both surfaces, they run on every PR and on a schedule, crashers fail the build and are retained as artifacts, and the approach is covered in the developer docs.

Activity

  1. self-assigned this
    on Oct 1, 2026
  2. jeffreyaven commented on Oct 12, 2026

    @jeffreyaven
    MemberAuthor

    closed with #835 and stackql/psql-wire#20

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions