Skip to content

refactor(security): migrate handleSecurity admin gate to shouldDenyAnonymous (#2567 follow-up)#2997

Merged
os-zhuang merged 1 commit into
mainfrom
claude/anonymous-posture-inconsistency-j43xco
Jul 16, 2026
Merged

refactor(security): migrate handleSecurity admin gate to shouldDenyAnonymous (#2567 follow-up)#2997
os-zhuang merged 1 commit into
mainfrom
claude/anonymous-posture-inconsistency-j43xco

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Final #2567 follow-up (Phases 1/2/docs merged as #2973 / #2987 / #2993). One-seam refactor — no behavior change beyond the 401 body adopting the shared shape.

Change

handleSecurity (/security/suggested-bindings, the ADR-0090 D5/D9 admin surface) was the last HTTP seam still hand-rolling the !userId && !isSystem → 401 check. It now delegates to the shared shouldDenyAnonymous decision like every other seam.

Semantics preserved deliberately: this gate is UNCONDITIONAL — requireAuth: true is hardcoded into the call, because an admin surface must deny anonymous callers even on a requireAuth: false demo deployment. The existing test pins this (dispatcher constructed with no options, where requireAuth defaults false, still expects 401); it now also asserts the shared body's code: 'unauthenticated'.

Triage — deliberately NOT migrated: handleNotification's !userId check. That is a "needs a user identity" predicate (the inbox is keyed by userId; a system context has no inbox), not an anonymous-posture decision — migrating it would let isSystem pass the gate and then query with an undefined userId.

Realtime "fourth door" investigation (no code — findings recorded here)

Also per the #2567 wrap-up, we audited whether a realtime/WebSocket/SSE surface constitutes an ungated fourth door. Verdict: no such door exists.

  • service-realtime is an in-process pub/sub bus only (registerService('realtime') + the sys_presence object; the contract's optional handleUpgrade WebSocket hook is unimplemented). It registers zero HTTP routes.
  • The dispatcher has no /realtime branch and no handleRealtime; neither the dispatcher-plugin nor the hono plugin mounts any realtime route — /api/v1/realtime falls through to the semantic 404.
  • Producers publish after the engine's security middleware; consumers (webhooks auto-enqueuer, knowledge sync) are in-process. No inbound request path reaches the bus.
  • AI SSE streaming enters exclusively through the gated handleAI path.
  • The conformance ratchet correctly omits realtime — there is no entry point to enumerate.

One cosmetic defect found (tracked separately, not in this PR): discovery advertises realtime: ${prefix}/realtime even though the route 404s, and metadata-protocol references a nonexistent plugin-realtime provider.

Verification

  • http-dispatcher + http-dispatcher.requireauth suites: 185/185 (401 case now also asserts the shared body code)
  • Lint clean; check:single-authz-resolver intact; changeset added (@objectstack/runtime patch)

🤖 Generated with Claude Code

https://claude.ai/code/session_01ShknNUYoSTspJLBiqorD8V


Generated by Claude Code

…onymous (#2567 follow-up)

The /security/suggested-bindings admin surface was the last HTTP seam still
hand-rolling the anonymous check. It now delegates to the shared
shouldDenyAnonymous decision with requireAuth:true hardcoded, preserving its
UNCONDITIONAL semantics (an admin surface denies anonymous even on a
requireAuth:false deployment — pinned by the existing test that constructs the
dispatcher with no options and still expects 401). The 401 body adopts the
shared shape (code: 'unauthenticated'), asserted in the test.

Deliberately NOT migrated: handleNotification's !userId check — a "needs a user
identity" predicate (inbox is keyed by userId; a system context has no inbox),
not an anonymous-posture decision.

Verified: http-dispatcher + http-dispatcher.requireauth suites 185/185, lint
clean, check-single-authz-resolver intact.

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

vercel Bot commented Jul 16, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 16, 2026 3:16am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/s labels Jul 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/runtime.

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

  • content/docs/api/index.mdx (via @objectstack/runtime)
  • content/docs/api/wire-format.mdx (via @objectstack/runtime)
  • content/docs/automation/hook-bodies.mdx (via @objectstack/runtime)
  • content/docs/concepts/north-star.mdx (via packages/runtime)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/runtime)
  • content/docs/deployment/index.mdx (via @objectstack/runtime)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/runtime)
  • content/docs/deployment/single-project-mode.mdx (via @objectstack/runtime)
  • content/docs/deployment/vercel.mdx (via @objectstack/runtime)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/runtime)
  • content/docs/permissions/authentication.mdx (via @objectstack/runtime)
  • content/docs/plugins/packages.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/http-protocol.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/index.mdx (via @objectstack/runtime)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/runtime)
  • content/docs/releases/implementation-status.mdx (via @objectstack/runtime)

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 marked this pull request as ready for review July 16, 2026 03:22
@os-zhuang os-zhuang merged commit 4c46ee0 into main Jul 16, 2026
16 checks passed
@os-zhuang os-zhuang deleted the claude/anonymous-posture-inconsistency-j43xco branch July 16, 2026 04:05
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 tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants