Skip to content

Add static reserved username denylist for signup - #632

Merged
kentcdodds merged 3 commits into
mainfrom
cursor/username-denylist-8ab0
Jul 6, 2026
Merged

kentcdodds merged 3 commits into
mainfrom
cursor/username-denylist-8ab0

Conversation

@kody-bot

@kody-bot kody-bot commented Jul 6, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Adds a static code-level denylist so reserved usernames cannot be claimed during signup or profile updates. Covers brand/product names, support/trust surfaces, infrastructure/route-like names, and common email mailbox locals (postmaster, abuse, noreply, etc.). No database changes and no email routing changes.

Changes

  • New reserved-usernames.ts with isReservedUsername / getReservedUsernameError
  • getUsernameValidationError now rejects reserved names (signup, profile update, admin user creation)
  • Split getUsernameFormatValidationError so existing /@username routing and public username resolution are unaffected
  • Unit tests for denylist helpers and validation integration

Testing

  • npx vitest run --project node-unit packages/worker/src/app/reserved-usernames.node.test.ts
  • Full npm run test via pre-push hook (unit + E2E)
System recap — extends existing primitive (medium risk)

Mode: recap · Base: main · Head: cursor/username-denylist-8ab0

Classification: extends — tightens signup/profile username validation on the existing auth primitive; no new primitives or storage.

Primitives touched

Primitive Group Impact
session-auth auth extends — signup and profile username validation now rejects a static reserved-name denylist

System map

flowchart LR
  signup["Signup / profile update"] --> validate["getUsernameValidationError"]
  validate --> format["Format check"]
  validate --> denylist["reserved-usernames.ts"]
  routing["/@username routing"] --> formatOnly["getUsernameFormatValidationError"]
Loading

What changed

  • Added static reserved username set (~120 names) in worker app code
  • Registration paths reject reserved names with "This username is reserved."
  • Lookup/routing paths continue using format-only validation

Summary by CodeRabbit

  • New Features

    • Added a reserved-username denylist with user-friendly feedback when a username can’t be used.
    • Improved username validation consistency across account lookup and OAuth sign-in.
  • Bug Fixes

    • Corrected which username validation rules are applied for public user resolution, reserved-name handling, request path matching, and derived display names.
  • Tests

    • Added coverage for reserved-username detection and validation behavior.
  • Chores

    • Updated test seeding username for MCP test support.

Introduce a code-level denylist for brand, support, infrastructure,
and email-local usernames. Wire isReservedUsername into username
validation so signup and profile updates reject reserved names.
Split format validation from reserved-name checks so existing
/@username routes and public username resolution still work while
signup and profile updates reject reserved names.
@coderabbitai

coderabbitai Bot commented Jul 6, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e9490307-0bc4-40cd-8b3b-897af3f704c8

📥 Commits

Reviewing files that changed from the base of the PR and between 95f7e97 and 4ca59df.

📒 Files selected for processing (1)
  • tools/mcp-test-support.ts

📝 Walkthrough

Walkthrough

This PR adds reserved-username detection, splits username validation into format-only and full validation, updates lookup and matching call sites to use the format-only helper, and changes one test database seed username.

Changes

Reserved Username Validation

Layer / File(s) Summary
Reserved usernames denylist and helpers
packages/worker/src/app/reserved-usernames.ts, packages/worker/src/app/reserved-usernames.node.test.ts
New module defines a static denylist, isReservedUsername() for normalized lookup, and getReservedUsernameError() for a fixed error message; tests cover reserved/non-reserved cases and integration with getUsernameValidationError.
Split format vs. reserved validation
packages/worker/src/app/username.ts
Introduces exported getUsernameFormatValidationError() containing prior format checks; getUsernameValidationError() now delegates to format validation first, then reserved-username validation.
Call sites switched to format-only validation
packages/worker/src/app/handlers/package-app.ts, packages/worker/src/app/request-auth-cache.ts, packages/worker/src/app/user-lookup.ts, packages/worker/src/oauth-handlers.ts
Path parsing, display-name derivation, user lookup, and OAuth username resolution now validate usernames using getUsernameFormatValidationError instead of getUsernameValidationError.
Test seed username update
tools/mcp-test-support.ts
The seeded test database user now uses mcp-test-user instead of kody.

Estimated code review effort: 2 (Simple) | ~12 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant getUsernameValidationError
  participant getUsernameFormatValidationError
  participant getReservedUsernameError
  Caller->>getUsernameValidationError: validate(username)
  getUsernameValidationError->>getUsernameFormatValidationError: check required/pattern
  getUsernameFormatValidationError-->>getUsernameValidationError: format error or null
  alt format valid
    getUsernameValidationError->>getReservedUsernameError: check denylist
    getReservedUsernameError-->>getUsernameValidationError: reserved error or null
  end
  getUsernameValidationError-->>Caller: final error or null
Loading

Related Issues: None specified

Related PRs: None specified

Suggested labels: enhancement, security

Suggested reviewers: kentcdodds

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately captures the new static reserved-username denylist, though it narrows the scope to signup more than the full change.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/username-denylist-8ab0

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 6, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-632.kentcdodds.workers.dev

Worker: kody-pr-632
D1: kody-pr-632-db
KV: kody-pr-632-oauth-kv

Mocks:

The MCP smoke tests sign up through /auth, so the default fixture
username must not be on the reserved denylist.
@kentcdodds
kentcdodds merged commit f4d1002 into main Jul 6, 2026
4 checks passed
@kentcdodds
kentcdodds deleted the cursor/username-denylist-8ab0 branch July 6, 2026 05:08
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.

3 participants