Commit 79856c7
committed
RBAC: PAT creation flow with role selection (TRI-8749)
Lets users pick a system role at PAT-create time and persists it via
enterprise.TokenRole so PAT-authenticated requests will run with that
role's permissions once the auth-side wiring lands.
V1 scope decisions (worth flagging for review):
1. System roles only. PATs are user-scoped (not org-scoped) and
custom roles are per-org — the role-to-org mapping for a multi-org
user's PAT is a non-trivial design question that doesn't need to
be answered for v1. Show the four seeded system roles
(Owner/Admin/Member/Viewer); a follow-up can add custom roles
once we've decided what "this PAT uses an org X custom role"
means semantically.
2. Default to caller's own role. Loader queries rbac.getUserRole
against the user's first org membership (createdAt ASC) and uses
that as the dropdown default — a PAT can't be more privileged
than the person creating it without an explicit upgrade. Falls
back to Member for users with no role assignment yet (OSS or new
user pre-backfill).
3. No plan gating. Plan tiers are per-org; PAT roles are global.
Plan gating only made sense in the org-scoped Teams page UI
(TRI-8748).
4. No privilege-escalation check. Today's PATs run through the
legacy auth path with full superScopes — even a "Owner" PAT here
is strictly less permissive than the status quo. Locking down
"the PAT can't exceed the creator's role" is a hardening for a
later ticket once the read-side actually keys off TokenRole.
Changes:
- services/personalAccessToken.server.ts: createPersonalAccessToken
takes an optional roleId. When provided, calls rbac.setTokenRole
after the Prisma PAT row is created. On a real failure the PAT is
compensating-deleted (the two writes live on different ORMs sharing
one connection — co-transactions are awkward, compensating delete
is simpler). The OSS fallback's "RBAC plugin not installed" return
is treated as success-with-no-role: the PAT row stays, just no
TokenRole gets written, matching pre-RBAC behaviour.
- routes/account.tokens/route.tsx: loader fetches system roles +
caller's current role; create form shows a role <Select> with the
caller's role as default; OSS path (allRoles returns []) hides the
dropdown entirely. Action passes roleId through to the service.
Out of scope here (covered elsewhere):
- The PAT auth-side path that will JOIN TokenRole and build an ability
from the role's permissions. Lives in the enterprise plugin's
authenticatePat path; tracked under the TRI-8741 test surface and
the broader auth-consolidation work in TRI-8744.
- CLI auth-code PAT (createPersonalAccessTokenFromAuthorizationCode)
unchanged. CLI PATs continue to be created without an explicit
role — they go through the legacy permissive path and existing
user expectations of "trigger dev just works" are preserved.
Verification: typecheck clean on webapp. Browser smoke test deferred
to your local run.1 parent ac55499 commit 79856c7
3 files changed
Lines changed: 172 additions & 4 deletions
File tree
- .server-changes
- apps/webapp/app
- routes/account.tokens
- services
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
5 | 5 | | |
6 | 6 | | |
7 | 7 | | |
| 8 | + | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
| |||
22 | 23 | | |
23 | 24 | | |
24 | 25 | | |
| 26 | + | |
25 | 27 | | |
26 | 28 | | |
27 | 29 | | |
| |||
34 | 36 | | |
35 | 37 | | |
36 | 38 | | |
| 39 | + | |
| 40 | + | |
37 | 41 | | |
38 | 42 | | |
39 | 43 | | |
| |||
52 | 56 | | |
53 | 57 | | |
54 | 58 | | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
55 | 86 | | |
56 | 87 | | |
57 | 88 | | |
58 | 89 | | |
59 | | - | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
60 | 100 | | |
61 | 101 | | |
62 | 102 | | |
| 103 | + | |
| 104 | + | |
63 | 105 | | |
64 | 106 | | |
65 | 107 | | |
| |||
81 | 123 | | |
82 | 124 | | |
83 | 125 | | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
84 | 131 | | |
85 | 132 | | |
86 | 133 | | |
| |||
103 | 150 | | |
104 | 151 | | |
105 | 152 | | |
| 153 | + | |
106 | 154 | | |
107 | 155 | | |
108 | 156 | | |
| |||
131 | 179 | | |
132 | 180 | | |
133 | 181 | | |
134 | | - | |
| 182 | + | |
135 | 183 | | |
136 | 184 | | |
137 | 185 | | |
| |||
151 | 199 | | |
152 | 200 | | |
153 | 201 | | |
154 | | - | |
| 202 | + | |
155 | 203 | | |
156 | 204 | | |
157 | 205 | | |
| |||
211 | 259 | | |
212 | 260 | | |
213 | 261 | | |
214 | | - | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
215 | 271 | | |
216 | 272 | | |
217 | 273 | | |
| |||
228 | 284 | | |
229 | 285 | | |
230 | 286 | | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
231 | 294 | | |
232 | 295 | | |
233 | 296 | | |
| |||
248 | 311 | | |
249 | 312 | | |
250 | 313 | | |
| 314 | + | |
251 | 315 | | |
252 | 316 | | |
253 | 317 | | |
| |||
265 | 329 | | |
266 | 330 | | |
267 | 331 | | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
268 | 363 | | |
269 | 364 | | |
270 | 365 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
6 | 7 | | |
7 | 8 | | |
8 | 9 | | |
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
13 | 21 | | |
14 | 22 | | |
15 | 23 | | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
16 | 30 | | |
17 | 31 | | |
18 | 32 | | |
| |||
322 | 336 | | |
323 | 337 | | |
324 | 338 | | |
| 339 | + | |
325 | 340 | | |
326 | 341 | | |
327 | 342 | | |
| |||
336 | 351 | | |
337 | 352 | | |
338 | 353 | | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
339 | 396 | | |
340 | 397 | | |
341 | 398 | | |
| |||
0 commit comments