flags: move the waitlist mode read /v1/featuregate/mode -> /v1/flags/waitlist (one namespace)
The guard's public waitlist-mode read now lives under /v1/flags (the flags engine owns it) — there is NO /v1/featuregate HTTP endpoint. The route, the Enforce exempt prefix, and the doc/prose comments move; the featuregate Go PACKAGE (native Enforce middleware) is NOT renamed, and the /v1/admin/services board is unchanged. - clients/flags/routes.go GET /v1/featuregate/mode -> GET /v1/flags/waitlist - clients/flags/waitlist.go doc comments repointed - clients/featuregate/middleware.go defaultExemptPrefixes /v1/featuregate/ -> /v1/flags/waitlist - clients/featuregate/middleware_test.go exempt-path assertion updated - apps/apps.go stale prose comment repointed Verified green: go build ./clients/flags/... ./clients/featuregate/... ./apps/..., go vet, and CGO_ENABLED=0 go test ./clients/featuregate/...
This commit is contained in:
+1
-1
@@ -339,7 +339,7 @@ func Wire() []cloud.MountSpec {
|
||||
{Name: "admin", Mount: admin.Mount},
|
||||
// Launch-control (per-service waitlist mode) folded into the flags engine: the
|
||||
// mode IS the switch waitlist.<svc>, the board is the /v1/admin/services lens,
|
||||
// and /v1/featuregate/mode is served by flags. featuregate is no longer a mounted
|
||||
// and /v1/flags/waitlist is served by flags. featuregate is no longer a mounted
|
||||
// subsystem — it exposes only the native Enforce middleware (wired in serve.go),
|
||||
// a consumer of flags.WaitlistModeForHost.
|
||||
// Tasks: the durable workflow/UI surface AND platform cron (durable schedules
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// from IAM). It is a CONSUMER of the ONE policy engine — the per-service waitlist MODE
|
||||
// and the host→service registry live in clients/flags (a service's mode IS the
|
||||
// switch waitlist.<svc>, evaluated through the native engine); the admin board is the
|
||||
// /v1/admin/services lens and the guard's runtime mode read is /v1/featuregate/mode,
|
||||
// /v1/admin/services lens and the guard's runtime mode read is /v1/flags/waitlist,
|
||||
// both served there. This package owns only enforcement, decomplected into two axes:
|
||||
//
|
||||
// - PER-SERVICE waitlist mode on|off — the flags switch waitlist.<svc>,
|
||||
@@ -112,9 +112,9 @@ type EnforceConfig struct {
|
||||
// health, the auth/OIDC handshake, and the waitlist join API itself (so a gated
|
||||
// user can still submit the waitlist form).
|
||||
var defaultExemptPrefixes = []string{
|
||||
"/v1/featuregate/", // the mode read + the health route
|
||||
"/v1/iam/", // auth / OIDC / approval-status / get-account handshake
|
||||
"/v1/waitlist", // the waitlist join API (a gated user must reach it)
|
||||
"/v1/flags/waitlist", // the guard's public mode read (flags engine)
|
||||
"/v1/iam/", // auth / OIDC / approval-status / get-account handshake
|
||||
"/v1/waitlist", // the waitlist join API (a gated user must reach it)
|
||||
"/health",
|
||||
"/healthz",
|
||||
"/__guard/", // the @file guard's own callback surface (defense in depth)
|
||||
|
||||
@@ -186,7 +186,7 @@ func TestRule_UngovernedHost_PassesThrough(t *testing.T) {
|
||||
|
||||
func TestRule_ExemptPaths_NeverGated(t *testing.T) {
|
||||
app := gateApp(t, "pending")
|
||||
for _, p := range []string{"/health", "/v1/iam/get-account", "/v1/waitlist/join", "/v1/featuregate/mode"} {
|
||||
for _, p := range []string{"/health", "/v1/iam/get-account", "/v1/waitlist/join", "/v1/flags/waitlist"} {
|
||||
code, _ := drive(t, app, greq{host: "hanzo.chat", path: p, user: "u", org: "acme", accept: html})
|
||||
if code != 200 {
|
||||
t.Fatalf("exempt path %q = %d, want 200 (never gated)", p, code)
|
||||
|
||||
@@ -25,10 +25,10 @@ func routes(app *zip.App, s *cloud.Service[state]) {
|
||||
app.Put("/v1/flags/defs/:key", cloud.Handle(s, putDef))
|
||||
app.Delete("/v1/flags/defs/:key", cloud.Handle(s, deleteDef))
|
||||
app.Get("/v1/flags/activity", cloud.Handle(s, listActivity))
|
||||
// Repointed from the former featuregate: the guard's public runtime mode read,
|
||||
// now answered by the engine decide (host→service→waitlist.<svc>). Exempt from the
|
||||
// Enforce gate (/v1/featuregate/ prefix), so a gated user can still resolve mode.
|
||||
app.Get("/v1/featuregate/mode", cloud.Handle(s, waitlistModeRoute))
|
||||
// The guard's public runtime mode read, answered by the engine decide
|
||||
// (host→service→waitlist.<svc>). One namespace — it lives under /v1/flags. Exempt
|
||||
// from the Enforce gate (/v1/flags/waitlist), so a gated user can still resolve mode.
|
||||
app.Get("/v1/flags/waitlist", cloud.Handle(s, waitlistModeRoute))
|
||||
}
|
||||
|
||||
// tenant resolves the org — the tenant-isolation KEY — from the validated
|
||||
|
||||
@@ -11,7 +11,7 @@ package flags
|
||||
//
|
||||
// The decide is WaitlistModeForHost(host) → (mode, service, known): resolve host→svc,
|
||||
// then read waitlist.<svc>. featuregate.Enforce is now a CONSUMER of this decide, and
|
||||
// /v1/featuregate/mode + the /v1/admin/services board read it too. Per-user approval
|
||||
// /v1/flags/waitlist + the /v1/admin/services board read it too. Per-user approval
|
||||
// (pending|approved) stays IAM's (featuregate/approval.go) — the second, orthogonal
|
||||
// axis, unchanged.
|
||||
|
||||
@@ -101,7 +101,7 @@ func requireRegistry() (*waitlistStore, error) {
|
||||
return c.registry.For(platformOrg, platformProject)
|
||||
}
|
||||
|
||||
// WaitlistModeForHost is THE decide the Enforce consumer, /v1/featuregate/mode, and
|
||||
// WaitlistModeForHost is THE decide the Enforce consumer, /v1/flags/waitlist, and
|
||||
// the admin board call: resolve host→service, then read the waitlist.<svc> switch
|
||||
// through the engine. FAIL-OPEN by construction — an unmounted registry, a store
|
||||
// error, or an un-governed host all return known=false, so a request is NEVER gated
|
||||
@@ -224,7 +224,7 @@ func mountWaitlist(c *Client, brand string, log luxlog.Logger) {
|
||||
}
|
||||
}
|
||||
|
||||
// waitlistModeRoute answers GET /v1/featuregate/mode?host=<h> — the runtime lookup the
|
||||
// waitlistModeRoute answers GET /v1/flags/waitlist?host=<h> — the runtime lookup the
|
||||
// @file waitlist-guard caches. Public (in-cluster) read: it returns ONLY the boolean
|
||||
// mode for the ONE queried host, never an enumeration. Same wire shape as the former
|
||||
// featuregate route, so the interim guard ports 1:1.
|
||||
|
||||
Reference in New Issue
Block a user