mz-deploy: stop rotating SSH tunnel keys on every apply (DEX-53) - #37374
mz-deploy: stop rotating SSH tunnel keys on every apply (DEX-53)#37374sjwiesman wants to merge 2 commits into
Conversation
The connection-options diff is purely structural, so the server-generated `PUBLIC KEY 1`/`PUBLIC KEY 2` that `SHOW CREATE` reports for an SSH tunnel connection (and that a user cannot write in project SQL) always looked like drift. Every re-apply emitted `ALTER CONNECTION ... DROP (PUBLIC KEY 1/2)`, which rotates the keypair and breaks bastions authorized against the old keys. Exclude these server-managed options from both sides of the diff so apply is idempotent. Ticket: DEX-53 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Confirmed the core assumption holds:
So this can't ever swallow a legitimate user change. 👍 One thing worth tightening before this becomes the durable answer: Cheap guard, and it matches existing code on this enum (there's already an exhaustive match over fn is_server_managed(name: ConnectionOptionName) -> bool {
use ConnectionOptionName::*;
match name {
// Server-generated for SSH connections and overwritten by the planner on
// every plan (plan_create_connection); never written by the user.
PublicKey1 | PublicKey2 => true,
// Everything else is user-authored. Enumerated explicitly (no `_`) so a
// new ConnectionOptionName variant won't compile until it's classified —
// otherwise a future server-generated option silently reintroduces the
// rotate-on-every-apply bug this PR fixes.
Host | Port | User | Broker | Brokers | /* …rest of the variants… */ => false,
}
}(The full variant list can be lifted straight from the exhaustive match at It doesn't guarantee the next person classifies a new option correctly, but it turns a silent bug into a reviewed decision. Longer term the sturdier version is a single Not blocking, the fix is correct as-is. |
|
Follow-up on the longer-term direction I mentioned above (a separate PR or this one, your choice). The exhaustive-match tweak is the cheap stopgap. The durable fix is to stop keeping "which options are server-generated" in two places: right now it lives both in the planner's SSH overwrite ( Move it onto the enum in impl ConnectionOptionName {
/// Options whose values are generated and owned by the server (surfaced in
/// SHOW CREATE) rather than written by the user. Today: the SSH tunnel
/// public keys.
pub fn is_server_generated(&self) -> bool {
use ConnectionOptionName::*;
match self {
PublicKey1 | PublicKey2 => true,
Host | Port | User | Broker | Brokers | /* …rest, no wildcard… */ => false,
}
}
}Then The point is that the predicate becomes load-bearing for the planner's own strip, not just a list mz-deploy has to remember to mirror. Adding a new server-generated option then has to flip |
The server-managed classification was a `matches!` with an implicit `_ => false`, so a newly added `ConnectionOptionName` variant would silently default to user-authored. If a future connection type surfaces a server-generated value in `SHOW CREATE`, that would reintroduce the rotate-on-every-apply bug this branch fixes, with nothing to flag it. Enumerate every variant explicitly with no wildcard so a new variant fails to compile here until it is classified, turning a silent bug into a reviewed decision. The durable fix (a single `ConnectionOptionName::is_server_generated()` in mz-sql-parser that both this and the planner's SSH overwrite consult) is a follow-up. Reported-by: tonydu-mz Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@tonydu-mz took your suggestion in the mz-deploy crate. I will leave it to the SQL team if they want to push into the parser crate. |
The connection-options diff is purely structural, so the server-generated
PUBLIC KEY 1/PUBLIC KEY 2thatSHOW CREATEreports for an SSH tunnelconnection (and that a user cannot write in project SQL) always looked
like drift. Every re-apply emitted
ALTER CONNECTION ... DROP (PUBLIC KEY 1/2), which rotates the keypair and breaks bastions authorized againstthe old keys. Exclude these server-managed options from both sides of the
diff so apply is idempotent.
Ticket: DEX-53
Co-Authored-By: Claude Opus 4.8 (1M context) noreply@anthropic.com
🤖 Generated with Claude Code
https://claude.ai/code/session_01VAcnVpSQi8ZgF5LekQRwvw