Repository navigation
Commit 874a38d
feat(core): allow-list the exact ADR-0043 approvals act route on the ADR-0069 auth gate (#22602)
Fixes #22577
Clause-②: yes
Refs #22438 (segment 3 of ruling A, the maintainer's 「A + 扫类」, director
record 6079645593)
**Boundary, in one line:** the ADR-0069 auth-gate allow-list now admits
exactly one more route, `approvals/act` (the ADR-0043 action page: `GET`
renders, `POST` redeems), at the mount bases and environment scope the
gate already normalises, and nothing else; that is the same token-only
authentication the self-hosted raw-app mount (`plugin-approvals`
`ACT_PATH = '/api/v1/approvals/act'`) has always had.
## The change
- `packages/core/src/security/auth-gate.ts`: one entry, `['approvals',
'act']`, in `ALLOW_ROUTES`. Those entries are exact routes at a mount: a
route matches only when the path, after the base and the optional scope,
is that route and ends there. The `auth` rule is the gate's one prefix
rule, and it is untouched. No prefix entry, no wildcard, no other
approvals path. The docstrings say why the route is exempt (ADR-0043:
the single-use token is the whole authorization) and that anything wider
is the maintainer's decision.
- `packages/core/src/security/auth-gate.test.ts`: four pins (below).
- `.changeset/22577-approvals-act-allowlist.md`: `@objectstack/core` at
`minor` (it widens what the gate admits).
## Mechanism, measured on `origin/main` 99801d8 before writing
1. **Who reads the allow-list.** `isAuthGateAllowlisted` has three
production readers: REST `enforceAuth` (`rest-server.ts`, passes
`req.path`), the dispatcher `enforceAuthGate` (`http-dispatcher.ts`,
passes `cleanPath` before the scoped-URL strip), and
`shouldDenyAnonymous` (`anonymous-deny.ts`, only when a seam passes a
path). No shipped seam passes a path to `shouldDenyAnonymous`: all 13
call sites outside core pass `userId`/`isSystem`/`method` only. So the
one live effect is on the dispatcher, for a session that an
authentication policy holds (expired password, required MFA). No REST
route serves `approvals/act`, so REST `enforceAuth` never sees this
path.
2. **The self-hosted mount.** Confirmed at `approvals-plugin.ts:392`:
`ACT_PATH = '/api/v1/approvals/act'`, mounted with `rawApp.get` (renders
through `peekActionToken`) and `rawApp.post` (redeems through
`redeemActionToken`) on `http.server.getRawApp()`. Two global
middlewares run in front of every raw-app route: the Hono server's
`use('*')` seams, and the one registered middleware, the dispatcher
plugin's rate limiter. Neither reads a session or this allow-list. So
the self-hosted route has never passed this gate, and the entry adds no
authentication the self-hosted path lacks.
3. **Spellings tried** (each one is a pin, with ablation evidence
below).
- **Admitted:** `/api/v1/approvals/act`, `/approvals/act` (the
dispatcher's prefix-stripped shape), `/api/approvals/act`, `?token=abc`
on both main spellings, a trailing slash, a doubled trailing slash,
doubled inner slashes, `/environments/env_1/approvals/act`,
`/api/v1/environments/env_1/approvals/act`, and
`/api/v1/projects/env_1/approvals/act`.
- **Refused:**
- extensions: `/approvals/act/x`, `/api/v1/approvals/act/x/y`,
`/approvals/actx`, `/approvals/act-x`, `/api/v1/approvals/acts`.
- siblings: `/approvals`, `/api/v1/approvals/requests`,
`/api/v1/approvals/requests/req_1/approve`.
- the route below a non-mount segment: `/data/approvals/act`,
`/api/v1/data/approvals/act`, `/meta/approvals/act`,
`/api/v2/approvals/act`, `/rest/v1/approvals/act`.
- a scope with no id: `/environments/approvals/act`.
- case variants: `/api/v1/Approvals/act`, `/APPROVALS/ACT`.
- percent-encoding: `/api/v1/approvals%2Fact`, `/approvals/%61ct`.
- The gate does not normalise case or percent-encoding, and this change
does not make it.
- 1 parent b27b894 commit 874a38d
3 files changed
Lines changed: 184 additions & 2 deletions
File tree
- .changeset
- packages/core/src/security
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
293 | 293 | | |
294 | 294 | | |
295 | 295 | | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 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 | + | |
| 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 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
296 | 446 | | |
297 | 447 | | |
298 | 448 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
| 9 | + | |
| 10 | + | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
| |||
103 | 104 | | |
104 | 105 | | |
105 | 106 | | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
106 | 125 | | |
107 | 126 | | |
108 | 127 | | |
109 | 128 | | |
110 | 129 | | |
111 | 130 | | |
112 | 131 | | |
| 132 | + | |
113 | 133 | | |
114 | 134 | | |
115 | 135 | | |
| |||
168 | 188 | | |
169 | 189 | | |
170 | 190 | | |
171 | | - | |
| 191 | + | |
| 192 | + | |
172 | 193 | | |
173 | 194 | | |
174 | 195 | | |
| |||
0 commit comments