Skip to content

Lint enforcement: ban magic-string "user_profile_id" outside AuthClaimTypes #202

Description

@davidortinau

Context

Per the AuthClaimTypes decision (2026-05-08), all custom JWT claim names live in SentenceStudio.Contracts.AuthClaimTypes as public const string fields. Producers (Api JwtTokenService / DevAuthHandler, WebApp ServerAuthService) and consumers (every endpoint that scopes by user, plus tests) must reference the constant.

The current sweep is correct on main as of e341484, but nothing prevents a future PR from reintroducing a literal like User.FindFirst("user_profile_id") or new Claim("user_profile_id", ...). A typo (e.g. "user_profileid") silently degrades to anonymous-user behavior with no compile-time warning — a production-only bug.

Desired enforcement

Add a CI gate that fails when the literal "user_profile_id" appears in any .cs file under src/ or tests/ except the constant definition in src/SentenceStudio.Contracts/AuthClaimTypes.cs.

Two acceptable approaches — pick whichever is cheapest to maintain:

Option A — Roslyn analyzer (preferred long-term):

  • New analyzer project (or extend an existing one) that fires a diagnostic on any LiteralExpressionSyntax whose value matches a configured set of banned claim names.
  • Configurable via .editorconfig or analyzer settings so adding new banned literals is a one-line change.
  • Wire as <Analyzer> in Directory.Build.props so every project picks it up.

Option B — Unit test grep gate (cheaper to ship):

  • New xUnit test (in tests/SentenceStudio.Api.Tests/ or a dedicated lint test project) that walks src/ and tests/ .cs files and asserts the literal does not appear outside the allowlisted AuthClaimTypes.cs.
  • Runs as part of the normal dotnet test pass, so CI catches it.
  • Easy to extend to other banned literals later.

Whichever path is chosen, the rule should ideally read its banned set from the AuthClaimTypes constant class (via reflection) rather than a hardcoded copy, so adding a new claim constant automatically protects the new literal.

Acceptance criteria

  • Adding a literal "user_profile_id" to any non-allowlisted .cs file fails the build or dotnet test.
  • The check is mechanical and runs in CI on every PR.
  • False positives are limited to the single allowlisted file (AuthClaimTypes.cs) and any documentation/string-resource use cases (which can be allowlisted explicitly).
  • Adding a new claim constant to AuthClaimTypes automatically protects the new literal — or, at minimum, the registration is one line in the analyzer/test config.

Related

  • Decision: .squad/decisions/processed/2026-05-08/kaylee-authclaimtypes-constants.md
  • Most recent sweep: commit e341484 (refactor(auth): centralize AuthClaimTypes in SentenceStudio.Contracts)
  • Original review that surfaced the issue: commit 398a769 (Wash's api-endpoint-review-checklist SIGNIFICANT Fix ContinueConversation method typo #5)

Out of scope

  • Implementing the analyzer/test in this issue (filing for tracking; not doing the work today).
  • Banning unrelated magic strings — scope is JWT claim names only for now.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    go:needs-researchNeeds investigationpriority:p2Next sprintsquadSquad triage inbox — Lead will assign to a membersquad:washAssigned to Wash (Backend Dev)type:choreMaintenance, refactoring, cleanup

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions