Skip to content

fix(auth): treat "anonymous" as a built-in credential-less role#26

Open
cunninghambe wants to merge 1 commit into
feat/multi-surface-v0.3.0from
fix/anonymous-role-builtin
Open

fix(auth): treat "anonymous" as a built-in credential-less role#26
cunninghambe wants to merge 1 commit into
feat/multi-surface-v0.3.0from
fix/anonymous-role-builtin

Conversation

@cunninghambe

Copy link
Copy Markdown
Owner

Why

RoleMutex.refresh() threw Unknown role: anonymous for any role not declared in surfacemcp.config.json roles[]. Since surfacemcp init writes roles: [] for a fresh project, every anonymous surface_call was rejected — breaking the entire unauthenticated surface for consumers like BugHunter, whose default no-login role is anonymous.

The design already intended to support this: doLogin() returns an unauthenticated session for a credential-less role (and types.ts documents "A role without credentials is anonymous: requests go unauthenticated"). The bug was purely that the roles[] lookup at the top of refresh() threw before reaching that logic.

What

Synthesize the built-in anonymous role when it isn't declared, so the public surface can always be exercised unauthenticated. A genuinely unknown, non-anonymous role still throws.

Verified

  • New unit tests (role-mutex.test.ts, TDD): anonymous returns an unauthenticated session with empty roles[]; caches; a real unknown role still throws; an explicitly-declared anonymous behaves identically. 4/4 green, typecheck clean.
  • End-to-end: a BugHunter calibrate run against a bench Next.js app went from 12 Unknown role: anonymous infra failures → 0; the interactive/API surface now executes as anonymous.

🤖 Generated with Claude Code

RoleMutex.refresh() threw "Unknown role: anonymous" whenever a caller
exercised a role not declared in surfacemcp.config.json roles[]. Since
`surfacemcp init` writes roles:[] for a fresh project, any anonymous
surface_call was rejected — breaking the entire unauthenticated surface
for consumers like BugHunter (whose default no-login role is "anonymous").

doLogin() already handles a credential-less role (returns an
unauthenticated session); the bug was purely the roles[] lookup throwing
first. Synthesize the built-in "anonymous" role when it is not declared,
so the public surface can always be exercised. A genuinely unknown,
non-anonymous role still throws.

Verified end-to-end: a BugHunter calibrate run against a bench Next.js
app went from 12 "Unknown role: anonymous" infra failures to 0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant