Skip to content

feat(auth)!: retire the api.requireAuth opt-out — anonymous data access is always denied (#3963 step 2) - #4043

Merged
os-zhuang merged 5 commits into
mainfrom
claude/drop-require-auth
Jul 30, 2026
Merged

feat(auth)!: retire the api.requireAuth opt-out — anonymous data access is always denied (#3963 step 2)#4043
os-zhuang merged 5 commits into
mainfrom
claude/drop-require-auth

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes #3963。这一系列的收尾。major —— 走了仓库的完整退役流程(墓碑 + 迁移链 + 生成物)。

做了什么

api.requireAuth: false 曾让一个部署用一个布尔值打开整个数据面。删掉。auth 是内核关注点、不是部署姿态:匿名调用者在每一个触及对象数据的 HTTP 面上被无条件 deny。

每一个合法地服务"无会话调用者"的面,本就各自从声明派生窄授权,没有一个需要这个全局开关:控制面 allowlist、publicFormGrant(公开表单)、分享链接 token(以 SYSTEM 读)、book.audience:'public'(#3995)、MCP token。

为什么是 major:仓库守门拦住了直接删键 —— 拦得对

第一版直接删 RestApiConfig.requireAuth 时,authorable-surface 闸门(ADR-0104 / #3733)报错:

❌ authorable key disappeared: api/RestApiConfig:requireAuth — 非 .strict() 的 schema 会静默剥掉未知键,作者继续写会得到"解析通过 + 设置永不生效",无从 grep。

这正是这一整轮在关的失败模式本身。 所以按规定改成墓碑化:

  • 两个 schema(RestApiConfigSchema + stack api 块)用 retiredKey(...),把处方编进拒绝消息 —— 作者升级 spec 时看到的就是它;
  • protocol-18 conversion stack-api-require-auth-removed(+ step18 接入迁移链),os migrate meta 自动删键;
  • spec-changes.json / protocol-upgrade-guide.md / api-surface.json / 生成的 reference doc 已重跑。

破坏性变更

  • api.requireAuth 是退役键,写它 → fix-it 报错(不再静默剥除)。
  • shouldDenyAnonymous(@objectstack/core)不再接受 requireAuth 入参。
  • 完全没有 auth 的 stack,在会服务数据 API 时启动即报错(A1,你定的),而不是拿到隐式 fail-open —— objectstack serve 和 plugin-dev 都是。给出两条出路(启用 auth,或不服务数据 API),并指明公开发布靠声明。

顺带补齐 #3960 的实测

这个开关一旦真能用(#4002 修好后),我拿到匿名可达部署,带对照组跑:匿名读 sys_user,带不带伪造 context.isSystem/__expandRead 结果都是 1 行 —— #3960 的修复成立(伪造 context 被剥),sys_user 被读到纯是 requireAuth:false 的语义(正是退役它的理由)。

测试(这是大头)

无条件 deny 后,所有靠 requireAuth:false 匿名 dispatch 的测试都需要一个已解析调用者 —— 单根因,175 个 rest 失败 + runtime/client/qa live-server 套件。分两类处理:

  • 机械型(测路由机制、非授权):经已有的 resolveExecCtx override 缝注入已认证 context;转发断言改为期望 context 被透传;
  • 行为型(测匿名/授权本身):rest-meta-authrest.test 的 audience 块、security-routes/explainhttp-dispatcher.requireauthhono-anonymous-deny 逐个重构断言到新姿态(匿名 /meta/object 401;匿名 public-book 仍可读;explain 仍 authenticated-only,现经共享 UNAUTHENTICATED gate)。

逐包全绿:rest 491 / runtime 904 / core 413 / spec 6897 / metadata-protocol 99 / cli 837 / client 200 / http-conformance 46 / plugin-hono-server 116 / plugin-dev 7。全量构建 71/71。

一个如实标注的既有失败(未碰)

runtime/src/datasource-autoconnect.test.ts 的一条 federation 测试,在干净的 origin/main 上于本沙箱一致失败(3/3,数据顺序不符、非 401、我的 diff 没碰它)。是环境既有 flaky,不在本 PR 范围。CI 的干净环境会给出它的真实状态。

审阅指引

  • 安全核心:packages/core/src/security/anonymous-deny.ts(无条件 deny)+ packages/rest/src/rest-server.tsenforceAuth
  • A1 报错:cli/src/commands/serve.ts + plugins/plugin-dev/src/dev-plugin.ts
  • 退役契约:spec/src/api/rest-server.zod.tsspec/src/stack.zod.tsspec/src/conversions/registry.tsspec/src/migrations/registry.ts

🤖 Generated with Claude Code

https://claude.ai/code/session_01TzLE9cw4gZKNyPN2ZP4iTt


Generated by Claude Code

claude added 3 commits July 30, 2026 05:07
…ss is always denied (#3963)

`api.requireAuth: false` let a deployment open its ENTIRE data plane with one
config key. Removed. Auth is a kernel concern, not a deployment posture:
anonymous callers are denied on every HTTP surface that reaches object data,
unconditionally. Every surface that legitimately serves a session-less caller
already derives its own narrow authorization from a declaration (control-plane
allowlist, publicFormGrant, share-link token → SYSTEM, book.audience:'public'
§6.7, MCP token), so none needed the global switch.

This commit is the production + spec + migration + docs change; the test-suite
rework (the seam that used requireAuth:false to dispatch handlers anonymously)
follows.

- core: shouldDenyAnonymous drops the `requireAuth` input — denies any
  anonymous, non-system caller outside the control-plane allowlist.
- spec: `api.requireAuth` tombstoned (retiredKey) in RestApiConfigSchema and the
  stack `api` block, so authoring it fails with a fix-it message instead of
  being silently stripped (ADR-0104 / #3733). Protocol-18 conversion
  `stack-api-require-auth-removed` drops it via `os migrate meta`;
  spec-changes.json / upgrade-guide / api-surface regenerated.
- rest / runtime / hono: every shouldDenyAnonymous call site loses the posture
  arg; the dispatcher's per-route gate is unconditional (only `auth:false` on a
  route opens it); boot warnings for the opt-out removed.
- cli / plugin-dev: an auth-less stack that would serve a data API now FAILS AT
  BOOT (A1) instead of getting an explicit fail-open carve-out.
- qa/verify: conformance matrix + harness updated to the unconditional posture.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TzLE9cw4gZKNyPN2ZP4iTt
Anonymous access to object data is denied unconditionally now, so every test that
used `requireAuth: false` to dispatch a handler anonymously needs a resolved
caller. 175 rest failures + the runtime/client/qa live-server suites, all one
root cause.

- rest (mechanical): inject a resolved context via the existing resolveExecCtx
  override seam where the test exercises route mechanics, not authorization.
  Forwarding assertions now expect the resolved context to be threaded.
- rest (behaviour): rest-meta-auth, the audience-gating block in rest.test.ts,
  and security-routes/explain reframed to the new posture — anonymous /meta/object
  is 401, anonymous public-book reads still work (publicBookGrant), explain stays
  authenticated-only (now via the shared UNAUTHENTICATED gate).
- runtime: authenticate the dispatcher mechanics tests (handleMetadata, error
  passthrough, error leak) with a stub auth service / executionContext;
  http-dispatcher.requireauth rewritten to assert the unconditional gate.
- client / http-conformance: register a minimal stub `auth` service in the
  live-server harnesses so the anonymous-deny gate is satisfied.
- core: anonymous-deny.test drops the `requireAuth` input.
- spec: step18 migration wires the stack-api-require-auth-removed conversion into
  the replay chain; generated reference doc + api-surface refreshed.
- cli: merge-boot test uses a live api key (enforceProjectMembership), not the
  retired requireAuth, as its per-key-merge example.

Pre-existing unrelated failure NOT touched: runtime datasource-autoconnect
federation test fails identically on pristine origin/main in this sandbox.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TzLE9cw4gZKNyPN2ZP4iTt
@vercel

vercel Bot commented Jul 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 30, 2026 6:38am

Request Review

claude added 2 commits July 30, 2026 06:28
…dead code block (#3963)

Follow-up cleanup after retiring the opt-out. Most were stale comments asserting
behaviour that no longer exists ("no-op when requireAuth is off", "when
requireAuth is set", "requireAuth=true deployments"), updated to the unconditional
anonymous-deny posture across rest-server, the runtime domains, plugin-security,
plugin-approvals, and metadata-protocol.

One was NOT just a comment: plugin-hono-server still computed
`const requireAuth = restConfig?.api?.requireAuth ?? true` and logged a boot
warning off it — dead plumbing, since denyAnonymous stopped reading requireAuth.
Removed. hono suite green (116).

Also merges origin/main (rest.test.ts discovery-route conflict — the route is
control-plane/allowlisted, so it takes the serviceExists constructor from main
and drops the unnecessary auth injection).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TzLE9cw4gZKNyPN2ZP4iTt
@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Jul 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 13 package(s): @objectstack/cli, @objectstack/client, @objectstack/core, @objectstack/metadata-protocol, @objectstack/plugin-approvals, @objectstack/plugin-dev, @objectstack/plugin-hono-server, @objectstack/plugin-security, packages/qa, @objectstack/rest, @objectstack/runtime, @objectstack/spec, @objectstack/verify.

130 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/actions-as-tools.mdx (via @objectstack/core)
  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/connect-mcp.mdx (via @objectstack/rest)
  • content/docs/ai/knowledge-rag.mdx (via @objectstack/core)
  • content/docs/ai/natural-language-queries.mdx (via @objectstack/core)
  • content/docs/ai/skills-reference.mdx (via packages/cli, packages/client, @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/cli, @objectstack/client, packages/runtime, @objectstack/spec)
  • content/docs/api/data-flow.mdx (via @objectstack/cli, @objectstack/client)
  • content/docs/api/environment-routing.mdx (via @objectstack/cli, @objectstack/client, @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/cli, @objectstack/client, @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/rest, @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/rest, @objectstack/runtime, @objectstack/spec)
  • content/docs/api/wire-format.mdx (via @objectstack/runtime)
  • content/docs/automation/approvals.mdx (via @objectstack/plugin-approvals, packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/cli, @objectstack/runtime, packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/core, @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via @objectstack/metadata-protocol, packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/core, packages/runtime, packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/runtime, @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/backup-restore.mdx (via @objectstack/cli)
  • content/docs/deployment/cli.mdx (via @objectstack/cli, @objectstack/plugin-security, @objectstack/spec)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • content/docs/deployment/migration-from-objectql.mdx (via @objectstack/core)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/runtime)
  • content/docs/deployment/self-hosting.mdx (via @objectstack/cli)
  • content/docs/deployment/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/deployment/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/deployment/vercel.mdx (via @objectstack/runtime)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/cli, @objectstack/client, @objectstack/plugin-hono-server, @objectstack/runtime, @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/core, @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/data-service.mdx (via packages/cli, packages/client)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/examples.mdx (via @objectstack/core)
  • content/docs/kernel/runtime-services/index.mdx (via packages/cli, packages/client, packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via @objectstack/plugin-security, packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/core, @objectstack/spec)
  • content/docs/kernel/services.mdx (via @objectstack/core)
  • content/docs/permissions/access-recipes.mdx (via packages/plugins/plugin-security)
  • content/docs/permissions/authentication.mdx (via @objectstack/cli, @objectstack/client, @objectstack/core, @objectstack/plugin-hono-server, @objectstack/runtime)
  • content/docs/permissions/authorization.mdx (via packages/core, @objectstack/plugin-security, packages/qa, packages/runtime, @objectstack/spec)
  • content/docs/permissions/delegated-administration.mdx (via packages/qa)
  • content/docs/permissions/explain.mdx (via @objectstack/plugin-security)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via packages/plugins/plugin-security, @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/rls.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/anatomy.mdx (via @objectstack/core)
  • content/docs/plugins/development.mdx (via @objectstack/core, @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/core, @objectstack/plugin-hono-server, @objectstack/plugin-security, @objectstack/rest, @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/cli, @objectstack/client, @objectstack/core, @objectstack/plugin-approvals, @objectstack/plugin-dev, @objectstack/plugin-hono-server, @objectstack/plugin-security, @objectstack/rest, @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/core, @objectstack/spec)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/i18n-standard.mdx (via packages/rest, @objectstack/spec)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/core, @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/core, @objectstack/runtime, @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/cli, @objectstack/core, @objectstack/spec)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/cli, @objectstack/client)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/cli, @objectstack/client, @objectstack/core, @objectstack/plugin-approvals, @objectstack/plugin-hono-server, @objectstack/plugin-security, @objectstack/rest, @objectstack/runtime, @objectstack/spec, @objectstack/verify)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/core, @objectstack/rest, @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v15.mdx (via @objectstack/core, @objectstack/verify)
  • content/docs/releases/v16.mdx (via @objectstack/cli, @objectstack/client, @objectstack/plugin-hono-server, @objectstack/spec)
  • content/docs/releases/v17.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/plugin-approvals, @objectstack/spec)
  • content/docs/ui/actions.mdx (via @objectstack/spec)
  • content/docs/ui/audience-based-interfaces.mdx (via packages/plugins/plugin-security)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/plugin-security, @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/public-data-collection.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)
  • content/docs/ui/translations.mdx (via @objectstack/spec)
  • content/docs/ui/views.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang merged commit 3c628ce into main Jul 30, 2026
18 checks passed
@os-zhuang
os-zhuang deleted the claude/drop-require-auth branch July 30, 2026 06:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xl tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

把 public 从"全局开关的副产品"升级为声明式能力,然后删掉 api.requireAuth 开关

2 participants