agents, deploy: the subsystem's door is the router it was handed, not a node inside it

Two more of the shape the previous commit fixed in nineteen places, found by the
gate rather than by reading: apps/deploy panicked the fleet's own surface-check
(`the group "/v1/deploy" declares middleware at deploy.go:316 and no routes
anywhere beneath it`), and apps/agents failed 54 of its own tests.

deploy is the clearer one. deploy.go built app.Group(dashPrefix) to hold
cloud.Bridge + bounce, and dashboard.go builds ANOTHER app.Group(dashPrefix) to
hold the routes. Group returns a new definition per call, so those are two nodes
at one path: the middleware sat on the empty one and NEITHER the bridge NOR the
sign-in bounce ever ran for a single route of that surface.

agents is the same mistake with a subtler tell, because its group is not empty —
/metrics, /activity and the :ref leaves ARE beneath it, so nothing panicked. The
rest of the surface is not: the collection root, mountSessions and mountTargets
all register on the Router by absolute path. So Bridge parked no org for
/v1/agents/targets or /v1/agents/sessions, and every op under them answered 403
"X-Org-Id required" to a request that carried one.

It only ever showed up in tests, and that is the part worth keeping in mind:
Serve installs a Bridge app-wide, so serving was unaffected and only a bare Mount
could see the hole. TestHTTPTargetRejectsOversizeGPUList is the example — it
asserts 400 for an oversize GPU list, got the 403 first, and so had never once
exercised the bound it is named after. It passes now for its stated reason.

No bound widens. Every prefix either subsystem declares is under its own group's
path (manifest/apps.go), so a scope confines this to exactly what the group named
and the plugin binaries serve nothing else.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
This commit is contained in:
2026-08-04 13:40:46 -07:00
parent 82f3b7af3e
commit bd2c284e4a
2 changed files with 35 additions and 13 deletions
+23 -12
View File
@@ -334,19 +334,30 @@ func Mount(app cloud.Router, deps cloud.Deps) error {
mounted = s
o := agentOps{s: s}
// Bridge FIRST, and at the door this SUBSYSTEM is, not on one node inside it: a
// typed op receives only a context, so the validated org reaches it by being
// parked there — never as an In field, which is caller-supplied and would be a
// cross-tenant read the caller asserted for itself.
//
// IT IS INSTALLED ON THE ROUTER, NOT ON THE /v1/agents GROUP, because this
// surface is not composed under that group. A group's middleware wraps the
// routes in its OWN subtree, and three quarters of this surface is registered
// somewhere else: the collection root and the two sub-planes go on the Router by
// absolute path (zip.Get(zapp, "/v1/agents"), mountSessions(s, app),
// mountTargets(s, app)) and only /metrics, /activity and the :ref leaves are
// composed beneath g. So a Bridge on g parked no org for /v1/agents/targets or
// /v1/agents/sessions, and every op there answered 403 "X-Org-Id required" to a
// request that carried one. Serve installs one app-wide, which is why serving
// was unaffected and only the tests — which Mount onto a bare app — could see
// it; a gate whose absence just one door down is invisible in production is the
// kind that stays broken. Under Serve a scope bounds this to the prefixes the
// manifest declares, and under a bare Mount it is app-wide, which is what the
// subsystem's own door honestly is.
//
// fiber runs middleware in registration order, so it goes above every route
// below, group included.
app.Use(cloud.Bridge())
g := app.Group("/v1/agents")
// Bridge FIRST, and at the TOP of the whole surface: a typed op receives only
// a context, so the validated org reaches it by being parked there — never as
// an In field, which is caller-supplied and would be a cross-tenant read the
// caller asserted for itself. fiber runs middleware in registration order, so
// one installed further down never runs for the leaves above it: this used to
// sit inside mountTargets, below, which left every leaf registered before that
// call — this file's, mountSessions' — with no org on the context the moment
// they became typed ops. Serve installs one app-wide too; nesting is harmless
// (the inner one is what the handler sees) and the tests mount this subsystem
// on a bare app with no Serve, so the subsystem's own install is what makes
// them pass.
g.Use(cloud.Bridge())
// The root of the surface. Declared on the App with its WHOLE path, not on the
// group with an empty leaf: joining "/v1/agents" with "" yields "/v1/agents/",
// a different path from the one these two have always served.
+12 -1
View File
@@ -313,7 +313,18 @@ func init() {
// It is installed FIRST: fiber runs middleware in registration order, so one
// installed after its leaves never runs.
func routes(app cloud.Router, s *cloud.Service[state]) {
app.Group(dashPrefix).Use(cloud.Bridge(), zip.H(bounce))
// ON THE ROUTER, not on a Group(dashPrefix) of its own. This read
// `app.Group(dashPrefix).Use(...)`, and the routes it meant to wrap are
// composed under a DIFFERENT app.Group(dashPrefix) — the one dashboard.go
// builds. Group returns a NEW definition on every call, so those are two nodes
// at the same path: the middleware sat on the empty one, and NEITHER
// cloud.Bridge NOR bounce ever ran for a single route of this surface. Every
// prefix this subsystem declares is under dashPrefix (manifest/apps.go), so a
// scope bounds this to exactly what the group named, and the plugin binary
// serves nothing else — the bound is unchanged, it is now a predicate over the
// request rather than a place in the tree that the routes turned out not to be
// in.
app.Use(cloud.Bridge(), zip.H(bounce))
// Liveness — public (probe-able without a JWT). It stays a RAW handler because
// it answers 503 carrying the SAME domain body as its 200 (status + the k8s and