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

vercelBot commented Jul 16, 2026

Copy link
Copy Markdown

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

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJul 16, 2026 3:16am

Request Review

@github-actionsgithub-actionsBot 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 mainJul 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 freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/steststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@os-zhuang@claude