fix(topology): remove DMZ gateway auto-attach on LAN create
POST /topologies/{id}/lans previously called _auto_attach_gateway()
whenever a non-DMZ LAN was created, which wired the DMZ gateway decky
to every new subnet. That's why a deployed gateway ended up with
eth0..ethN on every LAN regardless of what the user drew in MazeNET.
Drop the auto-attach helper entirely. The DMZ_ORPHAN deploy-time
validator (decnet/topology/validate.py:65-110) stays strict — users
must explicitly wire the gateway to each subnet they want bridged,
which is the whole point of having a topology editor.
useMazeApi.ts: drop stale auto-bridge reference from comment.
This commit is contained in:
@@ -77,59 +77,9 @@ async def api_create_lan(
|
||||
if row is None: # pragma: no cover — would mean insert vanished
|
||||
raise HTTPException(status_code=500, detail="LAN insert vanished")
|
||||
|
||||
# Auto-bridge: if this is a non-DMZ LAN, attach the topology's
|
||||
# DMZ gateway (the decky with forwards_l3=True that lives on the
|
||||
# DMZ LAN) to it. Satisfies the DMZ_ORPHAN invariant by
|
||||
# construction — every internal LAN always has a bridge path.
|
||||
if not body.is_dmz:
|
||||
try:
|
||||
await _auto_attach_gateway(topology_id, lan_id)
|
||||
except Exception as exc:
|
||||
# Best-effort: if the gateway is missing or the edge can't
|
||||
# be written, the deploy-time validator will surface it.
|
||||
log.warning(
|
||||
"auto-bridge skipped for LAN %s in topology %s: %s",
|
||||
lan_id, topology_id, exc,
|
||||
)
|
||||
|
||||
return LANRow(**row)
|
||||
|
||||
|
||||
async def _auto_attach_gateway(topology_id: str, new_lan_id: str) -> None:
|
||||
"""Attach the topology's DMZ gateway to a newly created non-DMZ LAN."""
|
||||
lans = await repo.list_lans_for_topology(topology_id)
|
||||
dmz = next((lan for lan in lans if lan.get("is_dmz")), None)
|
||||
if dmz is None:
|
||||
return
|
||||
|
||||
edges = await repo.list_topology_edges(topology_id)
|
||||
gateway_uuid: str | None = None
|
||||
for e in edges:
|
||||
if e["lan_id"] != dmz["id"]:
|
||||
continue
|
||||
if e.get("forwards_l3"):
|
||||
gateway_uuid = e["decky_uuid"]
|
||||
break
|
||||
if gateway_uuid is None:
|
||||
return
|
||||
|
||||
if any(
|
||||
e["decky_uuid"] == gateway_uuid and e["lan_id"] == new_lan_id
|
||||
for e in edges
|
||||
):
|
||||
return
|
||||
|
||||
await repo.add_topology_edge(
|
||||
{
|
||||
"topology_id": topology_id,
|
||||
"decky_uuid": gateway_uuid,
|
||||
"lan_id": new_lan_id,
|
||||
"is_bridge": True,
|
||||
"forwards_l3": True,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/{topology_id}/lans/{lan_id}",
|
||||
tags=["MazeNET Topologies"],
|
||||
|
||||
@@ -89,9 +89,8 @@ export function adaptTopology(detail: TopologyDetail): HydratedTopology {
|
||||
|
||||
// Home LAN = first edge; a multi-homed gateway is drawn inside its
|
||||
// home LAN, membership in others is expressed via the edge list.
|
||||
// Gateways (forwards_l3) MUST render inside a DMZ — auto-bridge adds
|
||||
// subnet edges after the original DMZ edge, but edge ordering from the
|
||||
// backend is not guaranteed, so we pick DMZ explicitly for gateways.
|
||||
// Gateways (forwards_l3) MUST render inside a DMZ — edge ordering from
|
||||
// the backend is not guaranteed, so we pick the DMZ edge explicitly.
|
||||
const dmzIds = new Set(detail.lans.filter((l) => l.is_dmz).map((l) => l.id));
|
||||
const gatewayUuids = new Set(
|
||||
detail.edges.filter((e) => e.forwards_l3).map((e) => e.decky_uuid),
|
||||
|
||||
Reference in New Issue
Block a user