fix(auth): enforce declared auth:true on /meta + /ai route families#2841
Merged
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 3 package(s): 29 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
The /data routes gate anonymous callers via RestServer.enforceAuth (requireAuth), but the /meta routes (rest-server) and /ai routes (dispatcher) never applied that gate. Three handlers each assumed the auth check ran "upstream"/"separately", yet no dispatch stage enforces RouteDefinition.auth: enforceAuthGate only covers ADR-0069 password/MFA gates and enforceProjectMembership bails on anonymous/unscoped requests. On a requireAuth deployment an anonymous caller could read object/field schemas and AI adapter/model status; on a tenant-less runtime host those are SYSTEM-object schemas and the host is publicly reachable. - rest-server: wrap registerMetadataEndpoints so every /meta route inherits the enforceAuth gate (present and future routes) instead of per-handler checks the next route would forget. - http-dispatcher: add a requireAuth option; gate handleAI (honouring the declared route.auth) and the metadata catch-all. Authenticated or internal system contexts pass; anonymous -> 401. - dispatcher-plugin: add requireAuth config (read top-level, or from the stack `api` block the cloud apps pass as `scoping`); thread it to the HttpDispatcher and to mountRouteOnServer so explicit AI routes enforce it too. - serve: pass requireAuth through to the dispatcher plugin. No-op when requireAuth is off (demo / single-tenant), so the previously public surface there is unchanged; an authenticated user passes exactly as on /data. Adds regression tests for the dispatcher and REST gates. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TCMvtvZuEQznmJr3dccV9K
os-zhuang
force-pushed
the
claude/gracious-babbage-n42vyw
branch
from
July 11, 2026 14:40
269841b to
cb662a5
Compare
os-zhuang
marked this pull request as ready for review
July 11, 2026 15:29
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On a
requireAuthruntime host, several routes declaredauth: truereturned HTTP 200 without authentication. On the tenant-less objectos host (publicly reachable) this leaked system-object schemas and AI adapter/model config:GET /api/v1/meta/object→ 200 (realsys_*field definitions)GET /api/v1/ai/status→ 200 ({"model": …})GET /api/v1/ai/effective-model→ 200 (model config + env-var presence)GET /api/v1/data/sys_user→ 401 (data plane correctly protected)Root cause
The
/dataroutes gate anonymous callers viaRestServer.enforceAuth(driven byapi.requireAuth), but the/metaroutes (rest-server) and/airoutes (dispatcher) never applied that gate. Four code sites each assumed the auth check ran "upstream"/"separately", yet no dispatch stage enforcesRouteDefinition.auth:enforceAuthGateonly covers ADR-0069 password/MFA gatesenforceProjectMembershipbails when the request is anonymous or unscopedSo
/metaand/aiwere unauthenticated on everyrequireAuthhost; the tenant-less runtime host merely made it publicly visible with system data.Fix
Enforce the declared
auth: true/requireAuthcontract on/metaand/ai, mirroring/data:registerMetadataEndpointsso every/metaroute inherits theenforceAuthgate (present and future routes) instead of per-handler checks the next route would forget.requireAuthoption; gatehandleAI(honouringroute.auth) and the metadata catch-all. Authenticated or internal system contexts pass; anonymous → 401.requireAuthconfig (read top-level, or from the stackapiblock the cloud apps pass asscoping); thread it to theHttpDispatcherandmountRouteOnServer.requireAuththrough to the dispatcher plugin.No-op when
requireAuthis off (demo / single-tenant) — the previously public surface there is unchanged; an authenticated user passes exactly as on/data.Tests
http-dispatcher.requireauth.test.ts— 8 tests: anon → 401, authed/system → pass,requireAuth=false→ open,auth:falseroute → open (handleAI + handleMetadata).rest-meta-auth.test.ts— 3 tests: anon → 401 (schema read never invoked), authed → pass-through,requireAuth=false→ open.🤖 Generated with Claude Code
https://claude.ai/code/session_01TCMvtvZuEQznmJr3dccV9K
Generated by Claude Code