Commit 9f987ae
fix(webapp): backwards-compat for type-level scope on runs list + tighten team action authz
Two related findings reviewing the RBAC route migration.
1. api.v1.runs / realtime.v1.runs: type-level scope no longer granted unfiltered access
Pre-RBAC the resource was a plain object (`{ tasks: searchParams[...] }`
for api.v1.runs, the searchParams object itself for realtime.v1.runs)
and the legacy `checkAuthorization` iterated `Object.keys`. So a JWT
with type-level `read:tasks` (api.v1.runs) or `read:tags`
(realtime.v1.runs) — no id — granted access to the unfiltered list.
The new `anyResource([…])` model only matches resources we list,
and the post-migration list dropped the type-level alternative when
no filter was set, so those JWTs started 403'ing on unfiltered
listings. Add `{ type: "tasks" }` and `{ type: "tags" }` (no id)
alongside `{ type: "runs" }` so the legacy semantic is preserved
verbatim — per-id `read:tasks:foo` / `read:tags:bar` still grants
only when the filter contains the matching id.
2. team action: explicit per-intent authz gate
The team route's action handler accepts three intents (set-role,
purchase-seats, remove-member). set-role already gates on
`manage:members`, but purchase-seats and remove-member relied on
model-layer enforcement (SetSeatsAddOnService, removeTeamMember).
The loader gates on `read:members` (broader audience than
pre-RBAC's owner/admin-only loader), so any user reaching the page
could submit those forms — banking on defense in depth at the
model layer.
Fix:
- purchase-seats → require `manage:billing`
- remove-member → require `manage:members`, with self-leave
(target.userId === actor.userId) carved out as always allowed
- removeTeamMember model fn previously only verified the actor was
a member of the org — any org member could remove any other
member by id. The new route gate closes that hole.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 2674417 commit 9f987ae
3 files changed
Lines changed: 49 additions & 3 deletions
File tree
- apps/webapp/app/routes
- _app.orgs.$organizationSlug.settings.team
Lines changed: 31 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
151 | 151 | | |
152 | 152 | | |
153 | 153 | | |
154 | | - | |
155 | | - | |
156 | | - | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
157 | 161 | | |
158 | 162 | | |
159 | 163 | | |
| |||
187 | 191 | | |
188 | 192 | | |
189 | 193 | | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
190 | 203 | | |
191 | 204 | | |
192 | 205 | | |
| |||
231 | 244 | | |
232 | 245 | | |
233 | 246 | | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
234 | 262 | | |
235 | 263 | | |
236 | 264 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
21 | 31 | | |
22 | 32 | | |
| 33 | + | |
23 | 34 | | |
24 | 35 | | |
25 | 36 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
25 | 25 | | |
26 | 26 | | |
27 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
28 | 34 | | |
29 | 35 | | |
| 36 | + | |
30 | 37 | | |
31 | 38 | | |
32 | 39 | | |
| |||
0 commit comments