Skip to main content
← Back to list
01Issue
FeatureShippedSwamp Club
Assigneesstack72

Relationships

#1228 Collective API token scopes: domain, persistence, and auth threading (phase 1 of #960)

Opened by stack72 · 7/17/2026· Shipped 7/17/2026

Context

Phase 1 of #960 (fine-grained scopes for collective API tokens). This PR delivers the invisible foundation — no user-facing behavior change. Every existing token continues to work exactly as it does today.

What this covers

1. TokenScopes value object (lib/domain/collective-api-token/token-scope.ts)

Define the canonical scope registry covering the 3 operations collective tokens currently have access to:

  • extensions:push — push + confirm
  • extensions:promote — channel promotion
  • extensions:read — search with private visibility
  • extensions:* — wildcard, grants all extension scopes

A TokenScopes value object wraps a validated Set<string> with hasScope(), toArray(), and isWildcard().

2. Scopes + legacy flag on the domain entity (lib/domain/collective-api-token/collective-api-token.ts)

  • Add scopes: string[] and legacyToken: boolean to CollectiveApiTokenData
  • create() accepts a required scopes parameter, sets legacyToken = false
  • fromStored() defaults missing scopes to ["extensions:*"] and sets legacyToken = true
  • Add hasScope(scope) method on the entity

3. MongoDB persistence (lib/infrastructure/mongo-collective-api-token-repository.ts)

  • Persist and read scopes array and legacyToken flag
  • Default to ["extensions:*"] / legacyToken = true when scopes is absent in stored documents
  • No migration needed — the default handles existing documents

4. Auth resolution threading

  • CollectiveTokenContext in utils.ts gains scopes: string[] and legacyToken: boolean
  • CachedCollectiveTokenAuth in auth-credential-cache.ts caches scopes and legacyToken
  • resolveRequestAuth in _middleware.ts resolves scopes from the token document and populates the context
  • No new DB pressure — scopes ride the existing lookup, cached for 60s

What this does NOT cover

  • No scope enforcement at routes (phase 2)
  • No changes to token creation API (phase 2)
  • No UI changes (phase 3)
  • No whoami changes (phase 2)

Testing

  • Domain tests: TokenScopes validation (valid/invalid scopes, wildcard matching, empty rejection)
  • Domain tests: CollectiveApiToken.create() with scopes produces legacyToken = false
  • Domain tests: fromStored() backwards compat with missing scopes produces legacyToken = true

Verification

  • deno task check passes
  • deno task test passes
  • deno task build passes
  • All existing tokens resolve with ["extensions:*"] and legacyToken = true
  • No user-visible behavior change
02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 5 MOREREVIEW+ 3 MOREPR_MERGED+ 1 MORENOTIFICATION_SKIPPED

Shipped

7/17/2026, 11:50:26 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack727/17/2026, 10:03:26 PM

Sign in to post a ripple.