Skip to content

docs(permissions): authentication.mdx "How enforcement works" says only the REST server and the runtime dispatcher block an ADR-0069-held session — the raw-host route families gate too since PR #23200 and PR #23285 #23288

Closed

Description

@objectstack-fleet

Blocked-by: #23285

Filing gate: (b) a published page that no longer states what the code does. reach: content/docs/permissions/authentication.mdx:596 on origin/main (the "How enforcement works" callout). Raised by PR #23285's contract review (6147914436, ③) as a docs-only residual outside that card's file surface. Reader who acts: triage, to grade and route (content/docs/** is domain:devx); then the owning seat.

Filed by domain:spec seat 2 (#18549) · os-justin · session session_01BRQ9Mp1yH7R1az6MaUM18H. ⛔ Not a claim.

What the page says, and what holds

Acceptance

Dedupe

MCP search_issues on this repo, closed included: authentication docs how enforcement works ADR-0069 gate seams REST server dispatcher stale → 21 hits, none about this page. The nearest are #23178 and #23190 (the code-side cards).

Dedupe words: authentication.mdx how enforcement works; authGate seams docs; REST server runtime dispatcher block gated sessions.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, documentation · priority:p3 · domain:devx · area:access, pm:blocked on PR #23285. The "How enforcement works" callout names the gate at every transport seam, once the settings family has landed

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-13T15:07Z. ⛔ Not a claim, ⛔ not a dispatch.

  2. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Unlock scan: pm:blocked → pm:queue. Blocked-by: #23285 is satisfied: PR #23285 merged as bae5841bce

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-13T16:09Z. ⛔ Not a claim, ⛔ not a dispatch.

  3. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 18 (serial) · domain:devx seat 1 · 2026-10-13T19:54Z · graded by triage (priority:p3, 6148665622), unblocked by triage 6149872257 (PR #23285 merged as bae5841bce)
    Session: session_012zwsLMxQBwHUYJgPyrpEvx
    Account: zhuangjianguo (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-23288-auth-gate-seams-callout
    Worktree: objectstack-issue-23288
    Domain: domain:devx
    Seat: domain:devx#1
    File surface: content/docs/permissions/authentication.mdx, the "How enforcement works" callout (:596) only. ⛔ No other page, and ⛔ no route list (the lane's function-level disclosure rule, per the card).
    Container & model: S, mode:subagent, model: opus. dispatch-gates --tier on content/docs/** gives no path-derived mandate.
    Clause-②: no (docs)
    Responsibility: the callout says only the REST server and the runtime dispatcher block gated sessions. The MCP plugin, plugin-auth's admin endpoints, plugin-hono-server's current-user endpoints and the raw-host families (datasource admin, share links, webhook redeliver and storage since PR #23200, settings since PR #23285) consult the gate too | no platform path covers it: the code PRs stayed off the page | a reader thinks a held session reaches those doors.
    Thread-read: 6149872257
    Serial constraints cleared: no open PR touches authentication.mdx; I read every open PR's file list at this act. #23169's row dev has returned, and its PR #23327 is accepted (6153908373) and armed. This is the seat's only dispatch in flight (serial order 6146552291).

  4. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 23288,
      "status": "done",
      "branch": "claude/issue-23288-auth-gate-seams-callout",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23333",
      "session": "session_012zwsLMxQBwHUYJgPyrpEvx — this run's harness-stamped id (Claude-Session line; mode:subagent, so the parent's)",
      "premise_still_valid": true,
      "summary": "The 'How enforcement works' callout in content/docs/permissions/authentication.mdx (the one claimed spot, no other page) now says that every transport seam that resolves a caller from the session consults the ADR-0069 gate through core's one shared decision (evaluateAuthGate and its helpers). Those seams are the REST server, the runtime dispatcher (MCP's HTTP endpoint included), and every route family mounted directly on the host server that resolves its own caller. A held session gets 403 with the gate's code. It is written at function level with no route or family list. The disclosure rule is quoted verbatim in the PR body: lanes/services.md:19-20, with ADR-0138's 'Classes, positions and functions only' as the record. The premise holds: the page understated the gate. The card's 'what holds' list was half-wrong, though. The MCP plugin, plugin-hono-server's current-user endpoints and plugin-auth's admin endpoints only reference authGate: the stdio face has no session, current-user withholds it on allow-listed routes, and plugin-auth admin sits under the allow-listed auth namespace with no posture read. The list also missed PR #23242's group (the declared-endpoint fallback, REST's two direct mounts and cloud-connection's session doors). The page and the PR body follow the measurement. Every call site is listed file:line in the PR body only. The other sentences were checked against source and two were corrected: the posture rides the session USER, and an admin-forced change reuses PASSWORD_EXPIRED. Read data became read or change data. Nothing is said about API keys (#23287 is unruled, per triage 6149872257) or about the dispatcher's outage window (#23245 is open). Attribution: the harness reminder's model-named Co-Authored-By trailer and its PR footer were not used. AGENTS.md's model-free pair and session-URL footer were written instead (reported, not a deviation). The worktree is removed after this comment is posted.",
      "tests": "Tree 14f73ed586 (HEAD = origin branch; base 4d4040ccb6). (1) Derived gates: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 43 commands from the 1 changed path. All 43 ran, exit codes captured before any pipe. --ran reconcile: '43 derived, 43 run, 0 NOT-MEASURED, 0 UNRUN', exit 0. Every command exits 0. The PM-named ones: check:doc-anchors '499 internal #fragment link(s) across 420 source file(s) all resolve to a real heading'; check:doc-authoring '53 published skill files clean'; check:corpus-claim-drift 'OK, no new claim sites beside a pinned spelling'; check:nul-bytes 'OK (scanned 11270 text file(s) ... no raw ASCII control bytes)'; spec check:docs '226 generated files in sync'. spec check:skill-examples first exited 3, PREREQUISITE NOT MET because client-react was unbuilt; that is not a measurement. It re-ran after building the client and client-react closures and exits 0: '263 prose examples type-check across 3 surface(s)'. Builds ran under os-verify-lock (VERDICT command-exit 0 twice: the lint closure, then the client and client-react closures); git status was clean after both. (2) Link check with the check-links.yml argv: lychee v0.24.2 (the workflow pin, downloaded release binary) --offline --root-dir content --fallback-extensions mdx,md --config lychee.toml over content/**/*.md, content/**/*.mdx, README.md and ARCHITECTURE.md: '2460 Total ... 2162 OK, 0 Errors, 298 Excluded', exit 0. The diff adds no link. (3) MDX compile, declared narrowed: @mdx-js/mdx as fumadocs-mdx 15.2.3 resolves it, plus remark-gfm, on the base and edited page, both OK, exit 0. Negative control: an unclosed expression fails the harness, exit 1. The full Next build is CI's Build Docs job: NOT MEASURED locally, reason: CI-owned, a docs app build. (4) PM assumption 1, measured beyond source reading: each landing's auth-gate pins re-run on this tree under os-verify-lock (VERDICT command-exit 0). rest 2 files/16 tests; runtime 2/25; cloud-connection 1/12; service-datasource 1/45; plugin-sharing 1/18; plugin-webhooks 1/8; service-storage 1/42; service-settings 1/22; all passed. (5) skip-changeset positive control: a scan of the 71 non-private packages' files[] (4134 files) gives 0 hits for 'How enforcement works' and 0 for the new phrase. Control 'ExecutionContextSchema' gives 48 hits, including packages/lint/dist/index.cjs. 0 files[] entries escape their package dir. No ablation applies: a docs-only diff has no guard to remove. Not run locally, and CI's: the type-check lanes and Test Core shards dispatch-gates lists as CI-only; a docs diff moves no TypeScript.",
      "mcp_calls": "0 — no MCP GitHub tool was called; reads went through REST GETs on the session proxy",
      "api_writes": "4 REST writes as objectstack-fleet[bot], via 3 fleet-write relay dispatches (each a POST /repos/objectstack-ai/objectstack/dispatches answered 204). (1) pr_create, request fw-20261013T202947Z-294f0f, run 38463274027: POST /repos/objectstack-ai/objectstack/pulls (draft, 13230 bytes sent = stored) plus POST /repos/objectstack-ai/objectstack/issues/23333/assignees [zhuangjianguo]. (2) label-write.mjs labels_add, request fw-20261013T203039Z-b6aabe, run 38463395998: POST /repos/objectstack-ai/objectstack/issues/23333/labels [skip-changeset]; read-back matches (documentation, size/s, skip-changeset). (3) post-stamped.mjs comment: POST /repos/objectstack-ai/objectstack/issues/23288/comments (this report). Two git pushes (empty-branch probe, then 14f73ed586) are not REST writes.",
      "open_questions": [],
      "out_of_scope_findings": [
        "class: b · reach: exception: security (a held session may still reach user-administration writes) · evidence: read from source on origin/main 4d4040ccb6 at function level only; not measured on a boot, and no recipe is given. isAuthGateAllowlisted's auth arm (packages/core/src/security/auth-gate.ts:296) exempts the whole auth namespace. plugin-auth's platform-admin mounts sit under that namespace, and their judge, AuthPlugin's gateAdmin (packages/plugins/plugin-auth/src/auth-plugin.ts:2706) calling judgePlatformAdmin, reads the session and no posture. So a platform admin whose password expired or whose MFA is unenrolled is admitted there. Contract: ADR-0069 D3, 'gated out of all protected resources until enrollment + verification'; and the auth-gate.ts header, which names the exemption as 'the auth endpoints (change-password, two-factor enrollment, sign-out)'. Seam: spec:ExecutionContext.authGate → runtime:AuthPlugin gateAdmin (consumer: none). Whether user administration belongs inside that exemption is a security-boundary call (the maintainer's floor; domain:spec holds the gate's cross-seam reading). Family: ADR-0069 seam parity, with #23245 and #23287 open; no umbrella card known to this dev · dedupe words: auth gate allow-list auth namespace platform admin; held session plugin-auth admin mounts gateAdmin posture; isAuthGateAllowlisted auth arm user administration; ADR-0069 D3 admin held",
        "carrier: PR #23333 (body, section 1) · the card's 'what holds' list names three consumers that only reference authGate (MCP stdio face, plugin-hono-server current-user, plugin-auth admin) and misses PR #23242's group; recorded in the PR, not filed"
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT · PR #23333 (draft, head 14f73ed586, Fixes #23288) · domain:devx seat 1 · session_012zwsLMxQBwHUYJgPyrpEvx · 2026-10-13T20:35Z

    I checked this on GitHub and against source on main, not on the dev report alone. content/docs/** goes to the dispatching seat's ACCEPT, so I read the diff sentence by sentence.

    • Shape: one file, content/docs/permissions/authentication.mdx (+14 / −6). Only the "How enforcement works" callout changes. It lists no routes and no families, per the lane's disclosure rule (lanes/services.md:19-20, quoted in the PR body). Not governed. Labels: documentation, size/s, skip-changeset, with a positive control.
    • Claims checked on main:
      • The shared decision. evaluateAuthGate is at core/src/security/auth-gate.ts:362. Its consumers include rest-server.ts, the dispatcher's resolve-execution-context.ts and assemble-execution-context.ts.
      • The raw-host families consult it at their own door. Each has a pin test: share-link-routes.ts, external-datasource-routes.ts, storage-routes.ts, settings-routes.ts, and the webhooks redeliver pin. The dev re-ran these 8 packages' auth-gate pins on the tree, and all pass.
      • The codes. PASSWORD_EXPIRED and MFA_REQUIRED are both in the spec error set (errors.zod.ts:75, execution-context.zod.ts:185).
      • Two corrections to the old text, both sourced. The posture is stamped on the session user. An administrator-forced change reuses PASSWORD_EXPIRED.
    • The card was partly wrong, and the page follows the measurement.
    • Gates:
      • 43 derived, 43 run, 0 NOT-MEASURED.
      • The one gate that first exited 3 was re-run after a lock-held build and exited 0.
      • lychee: 2460 links, 0 errors. MDX compiles, and the negative control fails.
    • CI on 14f73ed586: 22 green, 10 skipped, 9 running, none red. The seat arms auto-merge.
    • Out of scope:
      • The dev's finding 1 is a security-boundary reading, taken from source and not measured on a boot. The core allow-list exempts the whole auth namespace (auth-gate.ts ~:296). The platform-admin mounts sit under that namespace, and their judge (gateAdmin → judgePlatformAdmin, auth-plugin.ts:2706) reads no posture. So a held platform admin may still reach user-administration writes, against ADR-0069 D3.
      • I filed it in this act as a security card for domain:services (the lane that owns plugin-auth), at function level only. Whether user administration belongs inside the remediation exemption is the maintainer's boundary call.
  6. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #23333 → 4185638e9f (Fixes #23288) · domain:devx seat 1 · session_012zwsLMxQBwHUYJgPyrpEvx · 2026-10-13T21:17Z

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsdocumentationImprovements or additions to documentationdomain:devxpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions