Fix API-key scope wiring: polls UI, dedicated messages scope, no key self-minting#79
Merged
Conversation
Polls were unreachable via API keys: the backend supports polls:* but the key-creation UI never offered the scope, so keys couldn't be granted it (403 on every poll write). Add polls to the scope picker. Sweep of the rest of the scope system: - Give board messages their own messages:read/write/delete instead of reusing members:* - posting/deleting messages is a distinct capability from editing members and shouldn't be granted via it. Router mount + endpoints + _VALID_SCOPES + the key UI updated together. - Refuse API-key auth on the key-management endpoints (create / list / revoke). A key minting another key is privilege escalation: a leaked read-only key could create a write/delete key and outlive its own revocation. Key management is session/JWT-only now, matching the account + async-export posture. - Remove the dead, drifted _ALL_SCOPES in auth.dependencies (unused; _VALID_SCOPES in auth.py is the real list). Tests: a static guard that every require_scope() the API enforces is in _VALID_SCOPES (would have caught polls/messages), plus coverage that an API key cannot create/list/revoke keys.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Found while load-testing with an API key: poll creation always 403'd. The backend supports
polls:*, but the key-creation UI never offered the scope, so a key could never be granted it. Fixed that, then swept the rest of the API-key scope system.Changes
pollsto the scope picker so keys can actually be grantedpolls:read/write/delete(backend already enforced them).messages:*scope. Board messages were reusingmembers:*. Posting/deleting messages is a distinct capability from editing members, so they get their ownmessages:read/write/delete(router mount + the 8 endpoints +_VALID_SCOPES+ the UI, updated together). Least privilege: a member-management key no longer implies message access.create/list/revokekey endpoints now refuse API-key auth. A key minting another key is privilege escalation: a leaked read-only key could create a write/delete key and outlive its own revocation. Matches the existing account + async-export posture._ALL_SCOPESinauth.dependencies- unused and drifted out of sync;_VALID_SCOPESinauth.pyis the real grantable set.Sweep result (no other gaps)
require_scope()the API enforces (per-endpoint and at router mount) is now in_VALID_SCOPES. A new static test asserts this so the polls/messages class of bug can't recur.get_admin_user/get_admin_write_user.Tests
polls:write/messages:writeare grantable and enforced (a key lacking them is refused).55 passedacross api-keys + scope-coverage + messages; ruff / tsc / eslint clean.Compatibility
API-key scoping only; session/JWT (the web app) bypass scopes, so UI behavior is unchanged. The
messages:*split is a behavior change for any existing key that relied onmembers:*to reach messages (messages are new and pre-1.0, so likely none).Migrations
None.