ReviewOS

zig-utils/zig-waf

[WAF-52] Implement PostgreSQL repositories and isolated connection pools

#53
Closed chris opened this 9 days ago ·
9 days ago

Objective

Implement libpq binary parameters and results, prepared statements, cancellation, retries, timeouts, and separate bounded pools for API, rollout, and ingestion workloads.

Deliverables

  • Implement the complete scoped behavior described above.
  • Keep request-path work independent from UI, PostgreSQL, and blocking audit I/O.
  • Use Zig 0.17-dev and dependencies pinned through Pantry; do not add Git submodules.
  • Keep public APIs explicit about ownership, resource limits, errors, security policy, and compatibility.
  • Add focused unit, integration, differential, fuzz, benchmark, and documentation coverage as applicable.

Acceptance criteria

  • The scoped implementation and tests are merged on main in small conventional commits.
  • Zig formatting, focused tests, and the relevant CI suite pass.
  • Compatibility claims have executable evidence and no unexplained skips or silent fallbacks.
  • Untrusted inputs have deterministic bounds; hot paths have benchmark evidence.
  • Documentation and the machine-readable compatibility matrix are updated.

Relationships

Blocked by

Blocks

Baselines

  • ModSecurity 3.0.16
  • Coraza 3.7.0
  • OWASP CRS 4.28.0
  • libinjection 4.0.0
  • Zig 0.17-dev resolved and locked through Pantry
9 days ago

Complete.

Prepared statements — prepare/execPrepared/queryPrepared. A prepared name is session-scoped, so it survives a pool checkout and the control plane's handful of hot statement shapes are parsed once rather than per call. Redefining a name is an error rather than a silent replacement of a statement other call sites are using (22a1dc1).

Timeouts — setStatementTimeout; the server cancels an overrunning statement without dropping the session, so one pathological query cannot hold a pooled connection and the pool's whole budget. Verified by bounding a pg_sleep(1) to 50 ms and then using the same connection.

Cancellation — sendQuery/cancel/discardResults. Cancellation only means something for a statement actually in flight, so the API provides one; it is a request rather than a guarantee, since a statement that already finished completes, and the outcome therefore comes from draining the results.

Retries — execRetrying reconnects and retries when the connection turns out to have been severed, which is the failure a long-lived connection actually hits: a restart invalidates it silently and the next statement is how the client finds out. Deliberately narrow — a statement that failed on a connection libpq still considers good is reported rather than retried, and the doc comment states that the first attempt may have committed before the drop, so only statements safe to run twice belong there (623471c).

Separate bounded pools — WorkloadPools budgets API, rollout, and ingestion independently, because a shared pool makes every workload as available as the greediest one and a burst of console traffic should not stop the fleet from receiving a policy. Verified by exhausting ingestion and showing rollout and API unaffected. totalLimit reports what max_connections must accommodate (f048257).

Binary parameters and results — deliberately not used. Text format is used throughout, with bytea via decode(…, 'hex'). Binary moves type encoding onto the client; for timestamptz that means reimplementing PostgreSQL's own encoding, where any drift silently mis-dates security events, and it buys nothing measurable at these value sizes. The same reasoning governs COPY (#55). Recorded in docs/fleet-storage.md rather than left as an omission.

Earlier slices: bbc7f58 (bounded pool), 8204228 (NULL-aware scalars), 3e9a470 (nullable binds), 385f6f0 + 5e6d8b6 (per-test schema isolation and the libpq notice traffic that was intermittently failing the suite).

Sign in to comment on this issue.