Fix a tunnel-hostname race that could publish duplicate rows

tunnels.create() checked for an existing row by hostname and then
inserted/updated in a separate statement, with no lock between the two.
Concurrent publish calls for the same port (e.g. the editor's Ports
extension re-POSTing on every onDidChangeTunnels event) could race past
the check together and each insert their own row for the identical
hostname. Since routers/tunnel.py resolves a tunnel by a plain
find_one(hostname=...) with no ordering, whichever duplicate it happened
to return decided whether a request reached the app or got a generic
"no tunnel is published at this address" 404 - even while a sibling row
for the same hostname was active and serving traffic.

Replaced the check-then-write with a single atomic
INSERT ... ON CONFLICT(hostname) DO UPDATE, which needs hostname to
actually be unique: idx_tunnels_hostname is now a UNIQUE index instead
of a plain one. Since existing databases likely already carry duplicate
rows from this race, init_db() now runs a one-time
_dedupe_tunnel_hostnames() pass (keeps the best row per hostname -
active > provisioning > pending > failed, then newest) before dropping
and recreating the index as unique - CREATE UNIQUE INDEX IF NOT EXISTS
silently no-ops when an index with that name already exists, so the old
non-unique index has to be dropped first or the constraint would never
actually upgrade.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-03 08:16:17 +00:00
co-authored by Claude Sonnet 5
parent dcd90cc907
commit cc969aa187
2 changed files with 94 additions and 46 deletions
+51 -1
View File
@@ -30,6 +30,54 @@ def migrate_bug_tables_to_issue_tables() -> None:
logger.info("Dropped table %s after migration", source_name)
_TUNNEL_STATUS_RANK = {
"active": 4,
"provisioning": 3,
"pending": 2,
"failed": 1,
"suspended": 0,
}
def _dedupe_tunnel_hostnames() -> None:
if "tunnels" not in db.tables:
return
table = get_table("tunnels")
if not table.has_column("hostname") or not table.has_column("uid"):
return
groups = list(
db.query(
"SELECT hostname FROM tunnels "
"WHERE hostname IS NOT NULL AND hostname != '' "
"GROUP BY hostname HAVING COUNT(*) > 1"
)
)
for group in groups:
hostname = group["hostname"]
dupes = list(table.find(hostname=hostname))
dupes.sort(
key=lambda r: (
_TUNNEL_STATUS_RANK.get(r.get("status") or "", -1),
r.get("deleted_at") is None,
r.get("created_at") or "",
r.get("id") or 0,
),
reverse=True,
)
losers = [r["uid"] for r in dupes[1:]]
if not losers:
continue
with db:
for uid in losers:
db.query("DELETE FROM tunnels WHERE uid = :uid", uid=uid)
logger.warning(
"Removed %d duplicate tunnel row(s) for hostname %s, kept %s",
len(losers),
hostname,
dupes[0]["uid"],
)
def init_db():
tables = db.tables
_index(db, "users", "idx_users_username", ["username"])
@@ -785,7 +833,9 @@ def init_db():
_index(db, "instances", "idx_instances_workspace", ["is_workspace", "status"])
_index(db, "instances", "idx_instances_workspace_owner", ["workspace_owner_uid"])
_index(db, "instances", "idx_instances_tunnel_name", ["tunnel_name"])
_index(db, "tunnels", "idx_tunnels_hostname", ["hostname"])
_dedupe_tunnel_hostnames()
_drop_index(db, "idx_tunnels_hostname")
_index(db, "tunnels", "idx_tunnels_hostname", ["hostname"], unique=True)
_index(db, "tunnels", "idx_tunnels_instance", ["instance_uid"])
_index(db, "tunnels", "idx_tunnels_user", ["user_uid"])
_index(db, "tunnels", "idx_tunnels_state", ["desired_state", "status"])