fix: Harden instance rename against interleaving and lost unwinds

This commit is contained in:
2026-08-12 11:08:36 +00:00
parent f534b74066
commit cdc50b7aaf
10 changed files with 220 additions and 64 deletions
@@ -39,10 +39,13 @@ that tempts someone to touch the licence from this path.
are unaffected — they dial `GRPC_HOST`, which is not per-tenant.
- **The old host keeps working for up to 60 seconds.** `server/internal/auth/instancehost.go`
caches slug-to-instance lookups for 60s, and admin has no path to invalidate
another process's memory. This is a lag, not a leak: the stale entry maps the
old slug to the same instance, so nothing is exposed that was not exposed a
minute earlier. Adding a cross-service invalidation channel for a 60-second
window is not worth the coupling.
another process's memory. The released slug can be claimed by another account
inside that window, so for up to a minute a replica still maps that host to the
previous tenant. No data is exposed — the host/session guard rejects a session
belonging to a different instance — but the new owner's users can briefly reach
the old tenant's instance on their own host, and see its login page rather than
theirs. Adding a cross-service invalidation channel for a 60-second window is
not worth the coupling.
- **The customer must sign in again.** `km_session` is set with no `Domain`
attribute, so it is host-only and does not follow the instance to its new
subdomain. The UI says so rather than letting the customer discover it.
@@ -52,7 +55,7 @@ that tempts someone to touch the licence from this path.
| | Customer (owner or admin) | Staff |
|---|---|---|
| Cloud instance | rename, 24h cooldown | rename, no cooldown |
| Self-hosted instance | refused, 409 | name only; there is no slug |
| Self-hosted instance | refused, 400 | name only; there is no slug |
| Cloud placeholder | refused, 409 | refused, 409 |
Self-hosted is refused on the customer side for the same reason the member
@@ -219,7 +222,7 @@ exercise, matching existing practice:
- A second rename within 24 hours answers 429.
- A rename onto an occupied slug answers 409 and changes nothing.
- A rename attempt on a self-hosted instance from the customer portal answers
409.
400, the same status and constant the member endpoints already answer with.
- The audit log carries `instance.renamed` with both slugs.
## Out of scope