Skip to content

docs(kernel): auth-service handleRequest names the whole surface, the mount-layer checks and the transport argument - #33461

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/area-A1-32725
Nov 14, 2026
Merged

objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/area-A1-32725

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #32725

维护者速读

  • 改了什么: 只改一页合同文档 content/docs/kernel/contracts/auth-service.mdx 的 handleRequest 小节,补上三件事:转发宿主拿到插件的全部登录接口;IP 白名单等挂载层检查在这条路径上执行;可选的第二个参数 { remoteAddress } 与代理后的 server.trustProxy。示例改成两参数调用。
  • 为什么改: 上一轮改动合入后,转发给 handleRequest 的宿主会开始执行挂载层检查,文档仍是旧的单参数写法,接入方照抄会漏传客户端地址,在设了 allowed_ip_ranges 的部署上被 403 IP_NOT_ALLOWED 拒绝。
  • 风险与回滚: 纯文档,不发布任何包,无运行时影响;回滚即还原这一页。
  • 先看: content/docs/kernel/contracts/auth-service.mdx 的 ### handleRequest 小节(新增的三条要点和示例)。
  • 两分钟验证: 打开 PR 的 Files 视图,读 handleRequest 小节,预期看到三条要点与 authService.handleRequest(request, { remoteAddress })。
  • 需要你做的: 无,席位落地。

What changes

The handleRequest section of the IAuthService contract page now states, in the wording of the merged changeset auth-handlerequest-whole-surface and the IAuthService.handleRequest docblock in packages/spec/src/contracts/auth-service.ts:

  1. An implementation answers its whole auth route surface there; with the shipped plugin-auth, a forwarding host gets every route the self-hosted mount serves under /api/v1/auth/* (the platform's own mounts and better-auth behind them), not better-auth alone.
  2. The mount-layer checks run on that path: the IP allow-list (allowed_ip_ranges), the one-account-per-request rule, the organization IP list and the platform-admin wrappers.
  3. The optional second argument, handleRequest(request, { remoteAddress }), or server.trustProxy behind a proxy that sets X-Forwarded-For; with neither, a deployment that sets allowed_ip_ranges answers 403 IP_NOT_ALLOWED.

The example now shows the two-argument call. One sentence notes that the second argument belongs to the plugin's AuthManager and that the IAuthService shape on the page is unchanged (the changeset's own last line), so a reader typed against the interface is not misled. The interface block above stays as the spec declares it. skills/** is untouched.

Each claim was checked against main before writing it:

  • AuthManager.handleRequest(request, transport?: { remoteAddress?: string }) answers through the bound route surface for any path under basePath (packages/plugins/plugin-auth/src/auth-manager.ts); DEFAULT_AUTH_BASE_PATH is /api/v1/auth.
  • AuthPlugin.bindAuthRouteSurface runs mountAuthRoutes on the private table in init(); that function registers the D5 allow-list middleware (answering 403 with code IP_NOT_ALLOWED), the organization IP list middleware (runAtMountDoor), the one-account-per-request middleware and the /admin/* routes behind judgePlatformAdmin (packages/plugins/plugin-auth/src/auth-plugin.ts).
  • isClientIpAllowed refuses an undetermined address while ranges are set, and resolveClientAddress reads forwarded headers only under trustProxy.

No changeset: the page ships in no package's files[], so this PR carries skip-changeset.

Tests

Docs-only; no package test is owed. The derived gate families were run locally (see Verification).

Acceptance notes

None.

Verification

All 43 families from node scripts/pm/dispatch-gates.mjs --commands ran on head df9fea6f4d (after merging current origin/main), each exit 0; reconciliation: Run reconciliation — 43 derived, 43 run, 0 NOT-MEASURED, 0 UNRUN with a derived zero (every line carried its exit code).

Gate readings
  • pnpm check:doc-authoring exit 0, pnpm check:doc-anchors exit 0, pnpm check:doc-frontmatter exit 0, pnpm check:docs-single-h1 exit 0, pnpm check:nul-bytes exit 0, pnpm check:docs-transcript-drift exit 0, pnpm --filter @objectstack/spec run check:docs exit 0, pnpm --filter @objectstack/spec run check:skill-examples exit 0 (344 prose examples type-check across 3 surfaces), the two @objectstack/lint doc gates exit 0, and the remaining derived families exit 0.
  • Prerequisite builds run first under the verify lock: @objectstack/lint closure (VERDICT command-exit 0) and the @objectstack/client / @objectstack/client-react closures (VERDICT command-exit 0); before those builds three families answered exit 3 (nothing measured) and were re-run green.
  • CI-owned families (type-check lanes, artifact rosters, wide-population families) are left to the PR's check-runs.

Generated by Claude Code

… mount-layer checks and the transport argument

Claude-Session: https://claude.ai/code/session_016WV4d1NJYFGVi2FRztyBNo
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Nov 14, 2026
@github-actions github-actions Bot added size/s documentation Improvements or additions to documentation labels Nov 14, 2026
…ansport argument on AuthManager

Claude-Session: https://claude.ai/code/session_016WV4d1NJYFGVi2FRztyBNo
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#5 · os-elon-musk · session_016WV4d1NJYFGVi2FRztyBNo

ACCEPT · area A1 · Fixes #32725 · head 0d4ce51 · 2026-11-14T22:00Z

  • Review: seat self-review of a small docs-only PR (maintainer 2026-11-14, small PRs self-review and land). Each statement checked against main: AuthManager.handleRequest(request, transport?), the four mount-layer checks, isClientIpAllowed refusing an undetermined address while ranges are set, and IAuthService.handleRequest(request) still one-argument (packages/spec/src/contracts/auth-service.ts:171).
  • Seat change at 0d4ce51: the example keeps the IAuthService call one-argument and shows the transport argument on AuthManager, so the snippet type-checks against the contract it documents.
  • Governed: check-governed-merges.mjs --pr 33461 → NOT governed, 11 changed lines.
  • Checks at 0d4ce51: 47 check runs completed, none red. Local: 43 derived gate families exit 0 at df9fea6 (os-dev report, docs(kernel): the auth-service contract page says what a host that forwards to auth.handleRequest gets — the whole plugin surface, the mount-layer checks, and the optional transport argument #32725 comment 6884626264).
  • Main since the PR's base: no commit touches the page.
  • Landing: ready + auto-merge (maintainer 2026-11-14 15:21Z).

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 14, 2026 22:00
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 14, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⛔ merge queue 构建失败 — 先分诊,再决定要不要重排

队列构建 43645884813 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集),
所以失败的测试可能在本 PR 没碰过的包里 —— 那不是重排能修的。每次盲目重排都会让排在后面的所有 PR 重建一轮。

分类:failure —— 按下面的日志分诊。

失败的 job(日志抽取,best effort):

  • Dogfood Regression Gate (3/3) — 失败步骤: Boot example apps and exercise real user flows

    @objectstack/dogfood:test:  FAIL   isolated  test/bare-name-one-holder-flow-family.dogfood.test.ts > one package holder per flow, webhook, connector and email template name, on a booted showcase > the
      ↳ 失败原因: @objectstack/dogfood:test: AssertionError: one warning line: expected [] to have a length of 1 but got +0
    @objectstack/dogfood:test:  FAIL   isolated  test/bare-name-one-holder-flow-family.dogfood.test.ts > one package holder per flow, webhook, connector and email template name, on a booted showcase > ins
      ↳ 失败原因: @objectstack/dogfood:test: AssertionError: {"success":true,"data":{"manifestId":"com.qa.bare.delta","version":"1.0.0","versionId":"1.0.0","installedAt":"2026-11-14T22:04:32.522Z","hotLoaded":true,"upg
    @objectstack/dogfood:test:  FAIL   isolated  test/bare-name-one-holder-flow-family.dogfood.test.ts > one package holder per flow, webhook, connector and email template name, on a booted showcase > the
      ↳ 失败原因: @objectstack/dogfood:test: AssertionError: expected [ Array(3) ] to deeply equal [ Array(2) ]
    @objectstack/dogfood:test:  FAIL   isolated  test/bare-name-one-holder-flow-family.dogfood.test.ts > one package holder per flow, webhook, connector and email template name, on a booted showcase > the
      ↳ 失败原因: @objectstack/dogfood:test: AssertionError: expected [ Array(3) ] to deeply equal [ Array(2) ]
    @objectstack/dogfood:test:  FAIL   isolated  test/bare-name-one-holder-flow-family.dogfood.test.ts > one package holder per flow, webhook, connector and email template name, on a booted showcase > the
      ↳ 失败原因: @objectstack/dogfood:test: AssertionError: expected [ [ 'com.qa.bare.alpha', true ], …(2) ] to deeply equal [ [ 'com.qa.bare.alpha', true ], …(1) ]
    @objectstack/dogfood:test:  FAIL   isolated  test/bare-name-one-holder-flow-family.dogfood.test.ts > one package holder per flow, webhook, connector and email template name, on a booted showcase > the
      ↳ 失败原因: @objectstack/dogfood:test: AssertionError: expected [ 'com.qa.bare.alpha', …(3) ] to deeply equal [ 'com.qa.bare.alpha', …(2) ]
    

↳ 失败原因 是判读的关键:超时(Test timed out in … / Hook timed out in …)多半是负载/时序,不是本 PR 的回归;
断言(AssertionError: …)才指向真实的行为改变。两者的 FAIL 行长得一模一样,只有这一行能区分。

⚠️ 断言这一侧有一类例外,判据是断言在测什么,不是它是不是 AssertionError。 断言的对象是产品行为(一个值、一个形状、一次拒收)⇒ 照上面读:真实的行为改变,去查,⛔ 不要重排掉;
断言的对象是这次实验自身的有效性前提(跑完的耗时、负载下的先后、任何只在时间预算内才成立的条件)⇒ 它跟超时是同一类,同样对负载敏感,重排一次是合法的判别手段。
识别是机械的:断言的消息或它比较的值本身点名了一段时长、一个时间戳、一个耗时计数。实测过的一对 —— AssertionError: SecurityPlugin.init() ran: expected false to be true 测的是产品行为(真回归);
AssertionError: this run took over a second, so second-precision stamps could have differed too: expected 1006 to be less than 1000 测的是实验前提:它守护的那条不变式当时是绿的,同一个 head 原样重排一次即成功。
穿着 AssertionError 外衣的时间测量,仍然是时间测量。(⛔ 这只改「怎么读一次红」,不改「哪些测试可以重排」——后者由别处管。)

跨 PR 相同签名(24h,按失败测试文件聚合):

历史信号:

  • 本 PR 过去 24h 无队列失败记录(首次)。
  • 过去 24h 队列共有 15 个失败构建(不含本次)。

分诊清单:

  1. 失败测试在本 PR 改动的包里 → 真回归,修 PR。
  2. 失败测试与本 PR 无关 → 看上面的「跨 PR 相同签名」;已有汇总 issue ⇒ flaky/环境问题实锤,去那张 issue 上谈,修好前重排只会再烧一轮全队列。
  3. 两者都不是 → 可能与同组 PR 语义冲突;等前面的 PR 落地或失败出队后再重排一次即可,不要连续重排。

Generated by Claude Code · merge-queue-triage workflow (#4859)

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/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants