Skip to content

feat: add the proxy command with a transparent TCP relay - #1

Merged
mickamy merged 5 commits into
mainfrom
feat/proxy-command
Aug 26, 2026
Merged

feat: add the proxy command with a transparent TCP relay#1
mickamy merged 5 commits into
mainfrom
feat/proxy-command

Conversation

@mickamy

@mickamy mickamy commented Aug 26, 2026

Copy link
Copy Markdown
Owner

Summary

Adds the proxy subcommand: a transparent TCP relay that sits between a client and a PostgreSQL server and forwards bytes unchanged. This is the outer shell that the wire parser, policy evaluation, and ledger will be layered into; today it enforces nothing and records nothing.

What is in here

  • internal/proxy: Server{Upstream, Logger}.Serve(ctx, ln) accepts connections, dials the upstream with a 10s timeout, and relays both directions. A half-close on one side is passed on as CloseWrite so the other direction can drain. Transient Accept errors are retried with exponential backoff (5ms to 1s); only a closed listener is fatal. Canceling the context closes the listener and every live session and returns nil, so SIGINT/SIGTERM exit 0.
  • internal/cli: rollcall proxy -upstream ADDR [-listen ADDR] (default listen 127.0.0.1:6432). Both addresses are validated as host:port before binding. -h is only treated as a help request when it is the first argument; elsewhere the flag package handles it. The template's hello command is removed.
  • Logging goes to stderr through log/slog: one listening line at startup, session open/close at debug level, and a warning for relay errors other than EOF or a closed connection.
  • README gains a Status section stating that policy enforcement and the ledger are still being built.

Testing

  • make test and make lint (custom-gcl with deadmut and pointless) pass.
  • internal/proxy: relays both directions through an echo server, propagates half-close, closes the client when the upstream is unreachable, and returns an accept: error when the listener is closed externally.
  • internal/cli: flag and address validation cases, help handling before and after flags, and a live-listener test that starts the proxy, waits for the listening log line, cancels, and asserts exit 0.

Not in this PR

PostgreSQL message framing, statement classification, policy, and the ledger. The next step replaces the client-to-upstream io.Copy with a message-framed loop.

@mickamy
mickamy merged commit 258226b into main Aug 26, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant