Repository navigation
fix(frontend): reject protected role grants in demo mode - #76
Merged
Merged
Conversation
Return HTTP 400 with Role is protected for internal and SuperAdmin role grants when creating API keys or creating and updating users. Cover rejected mixed grants, unchanged state, and ordinary admin grants. Co-Authored-By: GPT-6.1 Sol <[email protected]>
Inherited property names such as 'constructor' threw non-API errors because the protected check ran before the existence check. API keys and user creation now report unknown roles first and role additions protected roles first, as on the backend. Demo roles cannot hold the SuperAdmin privilege, so the predicate only needs the built-in super-admin name. Co-Authored-By: Claude Opus 5.5 <[email protected]>
VibeSWE
commented
Oct 25, 2026
VibeSWE
left a comment
Author
There was a problem hiding this comment.
Adversarial review of PR #76 (at a40561fd, fixes in 25f5b6b1)
One Opus 5.5 and one Sol 6.1 reviewer. Neither found a reachable escalation path or anything blocking.
Both found the same two Low issues, fixed in 25f5b6b1 with failing tests first:
| Severity | Finding | Fix |
|---|---|---|
| Low | The protected check ran before the unknown-role check and read inherited properties, so ['constructor'], ['toString'] or ['__proto__'] threw a DataCloneError/TypeError instead of a 400 |
Unknown roles are checked against own properties first; new test for all three names on all three methods |
| Low | ['missing', 'super-admin'] returned "Role is protected" for API keys and user creation, where the backend reports the missing role first |
API keys and user creation check unknown roles first, role additions protected roles first, as on the backend; new test pins both orders |
Also changed: demo roles can only hold admin/editor/reader/writer/ingestor (TypeScript rejects superadmin), so the privilege === 'superadmin' branch was unreachable. The check is now just the built-in super-admin name.
Checked and fine:
- Role create/update rejects
superadmin. setDefaultRole('super-admin')andputRole('super-admin', …)are already rejected.- Demo has no group-mutation or API-key edit methods.
- OIDC
manualRolesadditions go through the new guard. - Root
adminprotections and ordinary grants are unchanged.
Local at 25f5b6b1: npm test 2,432 passed, 14 skipped; build (includes tsc --noEmit) and format:check pass.
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
Demo mode's mock backend (
frontend/src/lib/demo.ts) accepted role grants that the real backend rejects. It now returns HTTP 400Role is protectedwhen a grant includessuper-adminor any role carrying the SuperAdmin privilege, for:This mirrors the backend checks in #67 (API keys and querier user endpoints) and the existing standalone
post_user/add_roles_to_userchecks. Demo mode has no internal or protected users, sosuper-adminstands in for the internal-role check.Follow-up from the #67 review.
Tests
demoTeam.test.ts: 12 cases, committed red then green. They cover rejected grants (including ones mixed with ordinary roles), unchanged state after a rejection, and ordinary admin grants still working.format:checkandbuild(includestsc --noEmit) pass🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.