Repository navigation
Add querypilot proxy: Postgres wire-protocol proxy that enforces QueryPilot policies - #29
Conversation
…eryPilot policies Any Postgres client (psql, psycopg, SQLAlchemy, MCP database servers, BI tools) connects to the proxy unchanged. Each statement is routed through an allowlist: regenerated session commands (BEGIN/SET/SHOW), catalog-only queries for driver and ORM introspection, or SQLValidator, whose rewritten SQL (row filters, LIMIT cap) runs upstream in a READ ONLY transaction. Results are masked by output position, rejections come back as Postgres errors with the validator's message and hint, and every statement is audited. Anything unrecognized is rejected. - pygwire (pure-Python sans-I/O codec) for the wire protocol; libpq results passed through raw so types and text/binary encodings are preserved - simple and extended protocol, named statements, portals with max_rows, transactions and savepoints, cancel requests, ParameterStatus - `querypilot proxy --upstream ... --listen ... --policy querypilot.yaml` - live tests against real Postgres (env URL or Docker, else skip), psql included - docs/proxy.md: protocol coverage, known gaps, why it fails closed - JSONLAuditSink(max_cached=...) bounds its in-memory copy for long-running servers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 38813836 | Triggered | Generic Password | bfcc5c5 | tests/test_proxy_live.py | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
1 similar comment
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 38813836 | Triggered | Generic Password | bfcc5c5 | tests/test_proxy_live.py | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
Summary
querypilot proxyis a Postgres wire-protocol server that puts QueryPilot's validator and access policy in front of a real database. Any client connects to it unchanged: psql, psycopg, SQLAlchemy/LangChain, an existing MCP database server, Cursor/Claude Code, or a BI tool. Each one gets read-only enforcement, row filters, masking, row caps, audit, and errors it can repair, with no SDK integration.pip install "querypilot[proxy]" querypilot proxy --upstream postgresql://readonly@db/prod --listen 127.0.0.1:6543 --policy querypilot.yamlEvery statement takes exactly one route (
proxy/statements.py):BEGIN ... READ ONLY.pg_catalog/information_schemaand call only allowlisted functions pass through. That is what drivers,psql \dand ORM reflection need.pg_stats,pg_stat_*,pg_statistic*, query-string functions (query_to_xml,ts_stat) and non-pg_catalogfunctions are denied.SQLValidator. Only its rewritten SQL (row filters, LIMIT cap) runs upstream, inside a READ ONLY transaction, on a session withdefault_transaction_read_only=onand a statement timeout.SET search_path/role, and SQL that does not parse.Results are masked by output position from
ValidationResult.output_masks. Redacted or hashed columns are described astext. Rejections are PostgresErrorResponses with a SQLSTATE, the validator's agent-safe message, and the repair hint. Every statement goes to the audit sink asproxy_<route>.Implementation
psycopg.pqlevel, so values, type OIDs/typmods and text or binary encodings pass through unchanged. Every upstream call uses the extended protocol, so Postgres itself refuses any second statement smuggled into forwarded text.max_rowswithPortalSuspended.25P02after an error.NegotiateProtocolVersion, SSLRequest answered withN, and an optional password (required off loopback).JSONLAuditSink(max_cached=...)bounds its in-memory copy for long-running servers.docs/proxy.mdcovers protocol coverage, known gaps (no TLS termination, cleartext auth, no server-side cursors/EXPLAIN/COPY,LIMIT $1) and why the proxy fails closed. There is also a new README section.Tests
tests/test_proxy_statements.py: 57 routing tests with no database, which always run.tests/test_proxy_live.py: 25 tests against a real Postgres. The fixture usesQUERYPILOT_TEST_POSTGRES_URLif set, otherwise startspostgres:16-alpinewith Docker, otherwise skips. The tests cover:COMMIT; DROP TABLEandBEGIN READ WRITE, with the upstream row count unchanged.Not tested yet
node-postgres clients (e.g. the MCP reference server), JDBC (DBeaver/Metabase) and asyncpg.
🤖 Generated with Claude Code