Files
cloud/build_registration_test.go
Hanzo AI 4e3d2f55c0
CI/CD / containment (push) Successful in 2m26s
Hanzo CI/CD / cicd (push) Canceled after 2m37s
CI/CD / gate (push) Canceled after 2m37s
mount: a subsystem's middleware reaches its own routes, not the binary
Mounting the embedded IAM took the console down for anyone logged out, and the
mechanism was not IAM: the shared *zip.App was handed to all 107 subsystems, so
any one of them could call app.Use() and gate every route in the process. Blast
radius was a slice position in apps.Wire(). The point fix stopped that one
subsystem; this stops the class.

MountFunc now takes cloud.Router, not *zip.App. Routes register exactly as
before — absolute paths, same specificity — but the two doors to app-wide
middleware, app.Use(mw) and app.Group("/x", mw), are bounded to the prefixes the
subsystem declares. An empty MountSpec.Prefixes means the /v1/<name> convention
every subsystem already follows, so only a subsystem that gates something else
has to name it: IAM exports its two subtrees as iam.Prefixes (the same list that
registers its routes and serves its 503 — one list, three uses), and zen names
/v1 because its model claim genuinely spans it. Middleware outside those
prefixes is not installed and fails the mount, so the binary refuses to boot
half-gated rather than serving with a stranger's gate on.

Global is the one way back to the bare app, and it is spelled out in Wire() and
frozen by TestWireOrderMatchesFrozen, so a new grant cannot arrive as a quiet
field on one line of a 128-entry literal. Seven hold it — ai, agent, authz,
commerce, licensing, metrics, o11y — and every one is a linked module whose own
Mount still takes *zip.App. None of them installs middleware today (measured);
each stops needing Global when its module takes cloud.Router.

Fiber() is promoted onto the scoped Router rather than granting four more
Globals for four read-only uses (in-process dispatch and the route table).
transport.SetApp takes the *fiber.App for the same reason: the package is
imported by cloud, so it cannot name cloud.Router, and the engine was all the
dispatch ever needed.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-26 23:06:36 -07:00

28 lines
1.1 KiB
Go

package cloud_test
import (
"testing"
"github.com/hanzoai/cloud"
)
// TestMountFunc_IsTheSubsystemSignature pins the registry's mount contract: the
// signature every subsystem exports IS a cloud.MountFunc, checked by the compiler.
//
// This file used to test cloud.Typed, the adapter that took a MountFunc's `any`
// app and asserted it back to *zip.App. Both of its tests went with it, and
// neither is a loss:
//
// - "Typed recovers the *zip.App" only ever proved the adapter handed through
// the value it was given. MountFunc now names *zip.App, so there is no
// recovery step left to get wrong.
// - "Typed fails closed on a wrong type" can no longer be written: passing
// "not-a-zip-app" to a MountFunc is a compile error, so the runtime branch it
// exercised does not exist. A test asserting a wrong type is rejected is
// precisely what a type already is.
//
// What remains is the only claim worth making, and the build enforces it.
func TestMountFunc_IsTheSubsystemSignature(t *testing.T) {
var _ cloud.MountFunc = func(cloud.Router, cloud.Deps) error { return nil }
}