Skip to content

feat: tunnel to apps, not just databases - #15

Draft
jeroenrinzema wants to merge 1 commit into
mainfrom
feat/tunnel-app-ports
Draft

jeroenrinzema wants to merge 1 commit into
mainfrom
feat/tunnel-app-ports

Conversation

@jeroenrinzema

Copy link
Copy Markdown
Collaborator

Client half of brainpodnl/brainpod#456, which generalises the tunnel broker from databases to any pod resource that listens on a TCP port.

What changed

OpenSessionRequest.database_id became resource_id — field 1 keeps its number and type, so this is a rename, not a wire break — and gained a port. The response carries target_kind and the resolved remote port.

A Target enum replaces the bare DatabaseEngine that used to thread through the proxy, the banner and the DSN table:

  • Credentials. A database preflights its managed password. An app has none, so the preflight is skipped rather than failing on a missing password, and the banner drops the credential block.
  • Local port. The listener now defaults to the resolved remote port instead of an engine constant. A Postgres tunnel still lands on 127.0.0.1:5432; an app serving 8080 lands on 127.0.0.1:8080.
  • Client hint. An app gets curl http://127.0.0.1:<port>/ where a database gets psql/mariadb/valkey-cli/sqlcmd plus a DSN.
  • NDJSON. listening and closed carry targetKind; engine is null for apps and the credentials event is emitted for database targets only.

--port picks which port to reach. It is required when an app declares more than one; the broker's error enumerates the ports, which is the only discovery mechanism the protocol offers.

Verification

Built the real binary and ran it against a throwaway fake control plane (REST resolve + TunnelBroker + TunnelService + an echo backend), since no live environment was available:

$ brainpod --pod my-pod tunnel web
error: failed to create tunnel session: port is required; available ports: 8080 (http), 9090 (grpc) (InvalidArgument)

$ brainpod --pod my-pod tunnel web --port 5432
error: failed to create tunnel session: port 5432 is not exposed; available ports: 8080 (http), 9090 (grpc) (InvalidArgument)

$ brainpod --pod my-pod tunnel web --port 8080
╭─ ◆ Brainpod tunnel
│
│  App
│  Local      127.0.0.1:8080
│  Remote     App:8080
│
├─ Client
│  curl http://127.0.0.1:8080/
│
╰─ ● Ready · press Ctrl+C to stop
→ 127.0.0.1:55679  connected
✓ 127.0.0.1:55679  closed

$ curl -i http://127.0.0.1:8080/
HTTP/1.1 200 OK
...
hello from the app

Bytes really traverse the tunnel. The fake TunnelService logs a failure line if brainpod-include-credentials ever arrives; it never did for the app target, confirming the preflight is skipped.

--json on the same tunnel emits {"event":"listening",...,"targetKind":"app","engine":null,...} and no credentials event.

cargo test — 95 pass, including new coverage for Target::decode (database with engine, app, database without engine, unknown kind), the credential-less app banner, IPv6 bracketing in the app client command, and --port argument parsing.

Draft until

brainpodnl/brainpod#456 merges. Against today's production control plane this CLI still works for databases, but an app tunnel needs the new broker fields.

The broker now targets any resource that listens on a TCP port, so the
CLI stops assuming a database. OpenSessionRequest.database_id became
resource_id (field 1, same number and type) and gained a port; the
response carries target_kind and the resolved remote port.

A new Target enum replaces the bare DatabaseEngine that used to thread
through the proxy, the banner and the DSN table. An app target has no
managed credentials, so the credential preflight is skipped for it
rather than failing on a missing password, and the banner drops the
credential block and offers a curl command instead.

--port picks which port to reach. It is required when an app declares
more than one; the broker's error lists the ports it exposes, which is
the only discovery mechanism. The local listener now defaults to the
resolved remote port rather than an engine constant, so a database
tunnel still lands on 5432 and an app serving 8080 lands on 8080.
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