Add RBAC authorization roles#285
Conversation
The Marketing Guru — Round 1 ReviewVerdict: REQUEST_CHANGES Exact test command passed: I do not recommend a totally different implementation path from a marketing/docs lens. I do recommend blocking this until the public-facing docs stop making readers guess. Required fixes:
This PR changes access control. Slow is smooth: security docs have to be more precise than normal feature docs, not less. |
The Craftsperson — Round 1 ReviewVerdict: REQUEST_CHANGES Test command passed: I read I do not recommend a totally different path. Persisted roles plus route-level authorization is a workable shape. The implementation is not reviewable as shipped because the behavior is not tested. Required fixes:
This skipped the refactor/test step. A security boundary cannot ship with only pure helper tests while the actual Express middleware, route composition, DB role persistence, and UI gating are effectively untested. |
The Minimalist — Round 1 ReviewVerdict: REQUEST_CHANGES Exact test command passed: I do not recommend a totally different path. A small Required changes:
The skipped plan review shows here: the extra role header and split identity model are complexity that should have been questioned before implementation. |
The Steward — Round 1 ReviewVerdict: REQUEST_CHANGES Test command passed: I read I do not recommend a totally different path for the feature. Persisted RBAC plus server-side enforcement is the right shape. I do recommend a different path for the trust boundary: do not accept roles from client-controlled request headers. Identity must come from a trusted auth/proxy boundary; roles must come from persisted server state or an explicit dev-only bypass. Blocking issues:
Add API-level tests for these cases before re-review: spoofed |
The Architect — Round 1 ReviewVerdict: REQUEST_CHANGES Tests passed with the exact required command: This implementation is not coherent enough to ship. It adds an RBAC-shaped layer, but the security boundary is porous and the ownership model is wrong. I do recommend a different path for the identity/ownership seam: do not use the user-editable comment Required fixes:
This should have gone through plan review. The missed plan review shows up in the final shape: RBAC, identity, API docs, and tests are not aligned. |
The Minimalist — Round 2 ReviewVerdict: REQUEST_CHANGES Exact test command passed: I read the current PR diff and changed files. I still do not recommend a totally different path: One material issue remains:
Fix this without adding a framework: keep the actor id returned by |
The Craftsperson — Round 2 ReviewVerdict: APPROVE Exact test command passed: I read the current PR diff, changed files, and Round 1 feedback. I do not recommend a totally different path. The Round 2 changes moved this from helper-only confidence to behavior confidence: there are now API-level RBAC tests for default viewer denial, role-header spoofing, invalid role rejection, own-vs-other edit, resolver-only status changes, and document-delete denial. The author/ownership seam is now server-owned when an actor header is present, and the client fallback was refactored into explicit From the Craftsperson lens, the important refactor was extracting browser permission decisions into Non-blocking cleanup for the next pass: split the broad RBAC integration test into smaller role-focused |
The Marketing Guru — Round 2 ReviewVerdict: REQUEST_CHANGES Exact test command passed: I read the current PR diff and changed files. I do not recommend a totally different implementation path from a marketing/docs lens. The changelog entry and OpenAPI coverage are now present. Two public-doc issues remain material for an access-control PR:
Security docs are part of the security boundary. Readers should not have to infer how to use or verify RBAC from code. |
The Steward — Round 2 ReviewVerdict: REQUEST_CHANGES Exact test command passed: I read the current PR diff, Two material issues remain from the Steward lens:
Non-blocking but should be fixed while touching the UI: the add-reaction button is still rendered for viewers even though the server now rejects reaction writes. Hiding unavailable actions keeps the right path obvious and avoids turning expected authorization into user-visible errors. |
The Architect — Round 2 ReviewVerdict: REQUEST_CHANGES Exact test command passed: I read the current PR diff and changed files. A totally different path is no longer warranted: the Round 2 fixes moved the implementation into the right shape. One material coherence issue remains:
Fix this by carrying the actor id returned from After that, ship it. The remaining gaps are follow-up material, not reasons to redesign the PR. |
The Marketing Guru — Round 3 ReviewVerdict: REQUEST_CHANGES Exact test command passed: I read the current PR diff and changed files. A totally different implementation path is not warranted from the docs/marketing lens. The public docs are still not safe enough for an access-control feature. Blocking issues:
Security docs are part of the security boundary. The right path has to be obvious and copy-pasteable. |
The Craftsperson — Round 3 ReviewVerdict: APPROVE Exact test command passed: I read the current PR diff and changed files for Round 3. I still do not recommend a totally different path. The implementation is now coherent enough from the Craftsperson lens: the authorization rules live in small named helpers, the server-side behavior has integration coverage, and the Round 3 actor-id change removes the last identity/display-name coupling in the sidebar without adding a larger framework. The new Non-blocking cleanup for a future PR: reset the new |
The Steward — Round 3 ReviewVerdict: REQUEST_CHANGES Exact test command passed: I read the current PR diff and changed files. A totally different path is not warranted; persisted roles plus route-level enforcement is the right shape, and the Round 3 actor-id pass-through closes the browser ownership issue from my last review. One material API-contract issue remains:
Fix: add |
The Minimalist — Round 3 ReviewVerdict: REQUEST_CHANGES Exact test command passed: I read the current PR diff and changed files. A totally different path is not warranted: a small One material issue remains:
Do the small thing: rebuild/copy the client artifact ( |
The Architect — Round 3 ReviewVerdict: REQUEST_CHANGES Exact test command passed: A totally different path is still not warranted. The core shape is now coherent: persisted roles, no client role header, server-owned author for authenticated requests, guarded comment/document destructive paths, and the browser now carries the actor id into edit-own checks. One material system-level gap remains: webhook management is outside the RBAC boundary. Required fix:
After that, ship it. The identity/ownership concern from Round 2 is resolved. |
The Marketing Guru — Round 4 ReviewVerdict: REQUEST_CHANGES Exact test command passed: I fetched/read the current PR diff and changed files. A totally different implementation path is not warranted from the docs/marketing lens; the RBAC docs are now much clearer and the verification flow is copy-pasteable. One material docs issue remains:
While touching |
The Minimalist — Round 4 ReviewVerdict: APPROVE Exact test command passed: I read the current PR diff and changed files. A totally different path is not warranted. The shape is still small enough: one From the Minimalist lens, this is now the simplest viable RBAC implementation for the stated requirement. Ship it. |
The Craftsperson — Round 4 ReviewVerdict: APPROVE Exact test command passed: I read the current PR diff, changed files, and prior Round 4-relevant changes from this worktree. A totally different path is not warranted. The implementation remains in the right small shape: authorization rules are isolated in named helpers, route enforcement is direct, and behavior is covered with API-level tests instead of only permission-map tests. The Round 4 changes address the material implementation/test concerns from the current loop: the served browser artifact now carries the actor id through to edit-own checks, and webhook management is guarded at the route prefix with a negative authenticated-user test while the existing anonymous/admin-compatible webhook tests continue to cover the happy paths. Non-blocking cleanup if this RBAC test section grows again: split the broad integration case into role-focused subtests and reset the |
The Steward — Round 4 ReviewVerdict: REQUEST_CHANGES Exact test command passed: I read the current PR diff and changed files. A totally different implementation path is not warranted; persisted roles with direct route guards is still the right shape, and the webhook control-plane gap from Round 3 is now closed server-side. One material API-contract issue still blocks shipping:
Fix: add |
The Architect — Round 4 ReviewVerdict: REQUEST_CHANGES Exact test command passed: I fetched/read the current PR diff and changed files. A totally different path is not warranted. The implementation shape now holds together: persisted roles, trusted-header identity, no client role override, server-owned author under authenticated requests, guarded comment/document writes, actor-id UI gating, rebuilt served asset, and webhook management now sits behind admin permission. One material contract gap remains:
Required fix: add After that, ship it. Do not redesign the RBAC path. |
The Craftsperson — Round 5 ReviewVerdict: APPROVE Exact test command passed: I fetched/read the current PR diff and changed files, including the Round 5 OpenAPI/docs/test follow-up. A totally different path is not warranted. The implementation is still the right small shape: authorization rules are isolated in From the Craftsperson lens, the Round 5 changes are appropriately covered: the OpenAPI contract now has a regression test for protected operations' |
The Minimalist — Round 5 ReviewVerdict: APPROVE Exact test command passed: I fetched/read the current PR diff and changed files. A totally different path is not warranted. The implementation is still the small viable shape: one The Round 5 contract/doc additions do not turn this into a framework or add speculative flexibility. They close the API-contract gap without changing the core design. From the Minimalist lens, this is enough RBAC for the stated requirement. Ship it. |
The Steward — Round 5 ReviewVerdict: APPROVE Exact test command passed: I fetched/read the current PR diff and changed files from A totally different path is not warranted. The implementation now holds the operational contract together: roles are persisted server-side, client-controlled role escalation is gone, authenticated author ownership is server-derived, destructive comment/document/reaction/webhook paths are permission-gated, and From the Steward lens, the prior blocking API-contract issue is resolved. The remaining trusted-header deployment caveat is documented in |
The Marketing Guru — Round 5 ReviewVerdict: REQUEST_CHANGES Exact test command passed: I fetched/read the current PR diff and changed files. A totally different implementation path is not warranted; the RBAC shape and the OpenAPI contract are now aligned enough to ship once the human API reference stops contradicting the runtime. One material docs issue remains:
Fix: add |
The Architect — Round 5 ReviewVerdict: APPROVE Exact test command passed: I fetched/read the current PR diff and changed files. A totally different path is not warranted. The implementation now holds together: persisted roles, trusted-header identity, server-owned authorship for authenticated comment/reaction writes, direct route guards, UI permission gates using the actor id for ownership, rebuilt served asset, admin-only webhook management, and docs that name the trusted-header boundary. The Round 4 material contract gap is closed. Remaining nits are follow-up material, not blockers. Ship it. |
The Steward — Round 6 ReviewVerdict: APPROVE Exact test command passed: I fetched/read the current PR diff and changed files from A totally different path is not warranted. The current shape remains operationally sound: roles are persisted server-side, client-supplied role escalation is ignored, authenticated authorship is server-derived for ownership checks, protected comment/document/reaction/webhook operations return The Round 6 docs-only change does not weaken the API contract. From the Steward lens, the remaining trusted-header requirement is correctly called out as a deployment boundary: production must put Remarq behind a proxy that sets and strips identity headers. That is an operational requirement, not a blocker for this PR. |
The Minimalist — Round 6 ReviewVerdict: APPROVE Exact test command passed: I fetched/read the current PR diff and changed files. A totally different path is not warranted. The design remains the small viable shape for #276: one The Round 6 change is docs-only and just makes existing |
The Marketing Guru — Round 6 ReviewVerdict: REQUEST_CHANGES Exact test command passed: I fetched/read the current PR diff and changed files. A totally different implementation path is not warranted; the RBAC shape, changelog, OpenAPI contract, and dedicated RBAC doc are close. The remaining issues are in the human API reference, and they still matter because this is access-control documentation. Blocking fixes:
Principles: right thing should be the easy thing; slow is smooth. Security docs need to make the expected RBAC behavior obvious without readers inferring setup steps from code. |
The Craftsperson — Round 6 ReviewVerdict: APPROVE Exact test command passed: I fetched/read the current PR diff, changed-file list, and the changed source/test/docs files from A totally different path is not warranted. The implementation remains in the right small shape: RBAC decisions are isolated in From the Craftsperson lens, Round 6 only adds the remaining human API-reference status-code documentation. It does not disturb the tested implementation. The behavior-sensitive pieces still have coverage at the useful levels: API integration tests for RBAC enforcement and OpenAPI contract regression, plus focused client utility tests for permission decisions. Remaining cleanup stays non-blocking: split the broad RBAC integration test if it grows again, and reset the |
The Architect — Round 6 ReviewVerdict: APPROVE Exact test command passed: I fetched/read the current PR diff and changed files from A totally different path is not warranted. The implementation is now coherent enough to ship: persisted server-side roles, trusted-header identity, no client-controlled role escalation, server-owned authorship for authenticated writes, direct route guards on protected comment/document/reaction/webhook mutations, actor-id UI ownership checks, rebuilt served asset, OpenAPI 403 coverage, and API docs updated for the protected document/comment paths. The remaining imperfections are follow-up material, not round-6 blockers. Ship it. |
The Minimalist — Round 7 ReviewVerdict: APPROVE Exact test command passed: I fetched/read the current PR diff and changed files from A totally different path is still not warranted. The implementation remains the smallest viable RBAC shape for this codebase: one From the Minimalist lens: enough. Ship it. |
The Craftsperson — Round 7 ReviewVerdict: APPROVE Exact test command passed: I fetched/read the current PR diff, changed-file list, prior Craftsperson feedback, and the changed source/test/docs files from A totally different path is still not warranted. The implementation keeps the right small shape: RBAC rules live in From the Craftsperson lens, the behavior-sensitive pieces remain covered at useful levels: API integration tests exercise viewer denial, header spoofing denial, invalid roles, own-vs-other edit, resolver-only status changes, delete/webhook denial, plus OpenAPI 403 regression checks; the client permission utility has focused tests for legacy fallback and role-gated actions. Round 7 only clarifies docs examples and does not disturb the implementation. Non-blocking cleanup remains the same: if the RBAC integration case grows, split it into smaller role-focused tests; reset |
The Architect — Round 7 ReviewVerdict: APPROVE Exact test command passed: I fetched/read the current PR diff and changed files from A totally different path is not warranted. The implementation remains coherent: persisted server-side roles, trusted-header actor identity, no client-controlled role escalation, server-owned authorship for authenticated writes, direct route guards, browser permission gates based on Round 7 is a docs clarity fix. It reduces operational ambiguity; it does not add scope or introduce a new pattern. We are past material architecture risk and into review fatigue territory. Under Principles 7, 10, and 11: ship it. |
The Steward — Round 7 ReviewVerdict: APPROVE Exact test command passed: I fetched/read the current PR diff and changed files from A totally different path is not warranted. The current implementation remains operationally coherent: roles are persisted server-side, client-supplied role escalation is ignored, authenticated authorship is server-derived for ownership checks, protected comment/document/reaction/webhook operations return The Round 7 docs fixes close the remaining consumer-experience gap: |
The Marketing Guru — Round 7 ReviewVerdict: APPROVE Exact test command passed: I fetched/read the current PR diff and changed files. A totally different implementation path is not warranted from the docs/marketing lens. The prior blockers are resolved: No material public-facing docs or brand blocker remains. |
What changed
Added persisted RBAC roles (
viewer,commenter,resolver,admin), server-side permission enforcement, ownership checks for comment edits, role management endpoints, and UI permission gating.Why
Closes #276. Block Security requires authorization boundaries for read/create/edit/resolve/delete/admin actions.
New/Changed Endpoints
GET/me/permissionsPUT/users/:id/roleHow to verify
npm run checkX-Remarq-Userwith users assigned different roles and verify unauthorized actions return403.Manual testing checklist
npm run start)npm test)