mongoproxy prepared target sessions
2026-09-30: anonymous session handshake deadline
Account-free gateway sessions now clear both handshake deadlines when entering the authenticated session state. Previously only the read deadline was cleared; the original 15-second write deadline could expire before a later hello response, closing the socket and producing a monitor-thread EOF in MongoDB clients. Configured read idle limits still apply. SCRAM authentication is unchanged. There is no configuration or data migration; deploy the new binary and reconnect clients to use the fix.
The local protocol fixture regression keeps one anonymous connection open for 16 seconds, then checks hello and ping responses on that socket. It does not use a live MongoDB server or the Java driver. Validation results are recorded in docs/change-rationale.md.
2026-09-28: account-free targets and gateways
MongoDB targets may omit target accounts when the upstream server has authentication disabled. Their handshake does not send SCRAM metadata or a SCRAM exchange. MongoDB gateways may likewise omit gateway accounts; those connections are treated as authenticated at the gateway and commands are forwarded without a synthetic username or password. Configured gateway accounts retain local SCRAM authentication and target-account mapping.
The model, API, startup readiness checks and frontend drafts use an empty account list as the explicit anonymous mode. Adding an account changes the mode back to account selection and authentication.
2026-09-22: protocol-authenticated idle standby
Reason and behavior
Previously target protocol connections were created only after a downstream client needed them. Handler.PrepareSession now eagerly opens and authenticates one real single-node target session without a downstream client. It clears PreparedTarget on the setup snapshot to prevent recursive borrowing. The parent gateway pool owns publishing, periodic heartbeats, replacement, rejection backoff and shutdown.
MongoDB uses ping with $db equal to AuthSource, defaulting to admin only when AuthSource is empty. Custom authentication databases are not restricted to admin. Only authenticate=true can borrow; pre-authentication hello always opens a separate unauthenticated connection. An explicit SCRAM rejection retains its existing mongodb_authentication stage and now wraps a typed authentication_rejected cause for safe standby classification.
Checkout checks current target credential validity before accessing the pool. A prepared value is checked against target identity/account, database/authSource, outbound route, TLS, compression and session options. The request context is used for a fresh heartbeat before handing the session to protocol serving code. A failed heartbeat closes the standby and falls back to the existing new-connection path; a canceled request returns its context error. No business command is replayed. Checked-out connections are never returned to this standby pool: transactions, cursors and subscriptions cannot be shared with another client.
Preparation is bounded by the configured connect timeout (15 seconds by default). Heartbeats have a five-second upper bound and respect earlier context cancellation. Their cancellation callback is stopped, or joined if already running, before returning ownership. Canceling a completed setup or heartbeat context cannot close a successfully handed-off session.
Setup failures preserve only typed authentication, permission and host-identity rejection categories using outbound.FailureKind. Unknown errors use a generic message. Original server-controlled error text is not retained in the returned error chain, and there is no string-based password-error guessing. The parent pool can stop reconnecting explicit rejections instead of repeatedly attempting login.
Scope and compatibility
Only this protocol directory is changed by this adapter task. No schema migration, production data change, new explicit transaction or business write is introduced. Disabled persistence and clustered targets continue through the original open path. Existing protocol serving/audit behavior remains in place. Shared pool wiring and project-wide change-rationale documentation belong to the parent integration task.
Actual validation
Go 1.25.0, GOFLAGS=-p=2, GOTMPDIR=artifacts/portable-validation/build-work and its cache were used for:
- go test ./internal/protocol/mysqlproxy ./internal/protocol/pgproxy ./internal/protocol/mongoproxy ./internal/protocol/redisproxy -count=1 -timeout=120s — passed.
- go vet ./internal/protocol/mysqlproxy ./internal/protocol/pgproxy ./internal/protocol/mongoproxy ./internal/protocol/redisproxy — passed.
- Prepared fixture coverage includes eager authentication, Ping, same-connection checkout with a second heartbeat, failed-heartbeat replacement, cancellation, blocked setup/heartbeat deadlines, credential validation, identity/database mismatches, explicit typed authentication rejection and credential-safe errors.
- MySQL/PostgreSQL also verify database overrides leave the default standby available; MongoDB verifies pre-auth hello isolation and custom AuthSource on authentication, idle Ping and checkout Ping; Redis checks buffering/deadlines.
- The attempted targeted race run was unavailable because this environment has CGO disabled (go: -race requires cgo). No race-pass claim is made.
These are local protocol fixtures, not live database or production-server tests. No frontend build, embedded asset build, deployment or commit was performed here.