Repository navigation
Commit 33b6e8b
Fixes #20861
Clause-②: yes (widening)
## What this changes
The `no_sign_in_account_at_boot` boot report already stays quiet when a
deployment has a delegated sign-in path. Since #15074 that means
`ssoOnlyMode`, a configured social or OIDC provider, or enterprise SSO
with a registered IdP. All three are read off `getPublicConfig()`, which
is what the login page is told. A sign-in route the **host** owns, and
the login page does not show, was invisible to the gate. So a hosted
kernel whose owner hid the platform sign-in button logged the ERROR on
every rebuild while that owner signed in through the host's handoff.
Following triage's direction (5912860738), `SignInPathWiring` gains ONE
declared fact, and the host sets it:
- `AuthPluginOptions.hostSignInHandoff?: boolean` (default `false`).
This is the only way to state it: no env var, no setting.
- The `kernel:ready` hook hands the plugin's own options to
`probeSignInPathWiring` as a fourth argument (`SignInPathHostView`). The
gate then treats the fact like the other delegated paths: no `error`,
and a `debug` line under the same grep token that names
`hostSignInHandoff` as the reason.
- Only a literal `true` declares it; any other value reads as not
declared, which is the loud direction. A declared handoff also skips the
`sys_sso_provider` read, like any path proven without the store.
- ⛔ No inference. Nothing reads environment names,
`platform_sso_enabled` or row counts. The host states what it wires.
- ⛔ The public config does not lie. The option registers no provider,
and `getPublicConfig()` returns the same value with or without it
(pinned).
- ⛔ Not a remedy. The ERROR text does not mention the option. The
operator of a locked-out self-hosted deployment reads that line, and
offering a one-word switch that silences it would turn a loud dead end
into a silent one.
- A deployment that does not declare the fact reports exactly as before,
including every self-hosted deployment with no delegated path. The
#14353 suite (`boot-sign-in-reachability.test.ts`) is unedited and
green.
## For the cloud follow-up
Where the hosted kernel constructs `AuthPlugin` and mounts the owner
handoff (`sso_as_owner` to `sso-handoff-issue` to `sso-exchange`),
declare `new AuthPlugin({ /* existing options */ hostSignInHandoff: true
})`. The mutation leg of objectstack-ai/cloud#2504
(`platform_sso_enabled` false) should turn green once that is in place.
## Mechanism assumptions, measured (B1 to B6)
- **B1, holds.** The gate lives in
`packages/plugins/plugin-auth/src/boot-sign-in-reachability.ts`:
`resolveDelegatedSignInPath` (:414 on base),
`resolveNoSignInAccountReport` (:459) and
`reportIfNoSignInAccountExists` (:548). Before this PR,
`probeSignInPathWiring` (:388) resolved the three facts from
`SignInPathConfigView`. There is one call site, the `kernel:ready` hook
in `auth-plugin.ts`: `pub` comes from
`this.authManager.getPublicConfig()` (:1025), and the gate is called at
:1055 and :1056.
- **B2, the idiom.** A host states wiring facts as `AuthPluginOptions`
constructor options: `manifestDatasource`, `databaseHooks`, and
`membershipPolicy`. The organizations boot text says hosts declare
`membershipPolicy` in the `AuthPlugin` constructor, "what the cloud
control plane does". `os serve`
(`packages/cli/src/commands/serve.ts:3991`) passes explicit fields and
spreads no authored config into the plugin. So the option is reachable
only by code that constructs `AuthPlugin`, which is a host. The option
has one name and is read from one place. An env var would be a second
spelling, and it would let an operator declare a route that nothing
mounts.
- **B3, holds.** `getPublicConfig()` (`auth-manager.ts:6599` to `:6799`)
builds every field explicitly and never spreads `this.config`, so a new
plugin option cannot leak into it. A pin compares the full return value
with and without the declaration. Nothing needed to change there.
- **B4.** See the one-liner above. Nothing is filed in another
repository.
- **B5, `yes (widening)`.** `AuthPluginOptions` is re-exported by the
`.` entry (`export * from './auth-plugin.js'`). After `pnpm --filter
@objectstack/plugin-auth build`, `dist/index.d.ts` carries
`hostSignInHandoff?: boolean` at line 211. That line is inside
`interface AuthPluginOptions` (lines 119 to 212), and `files` is
`["dist","README.md","CHANGELOG.md"]`. `SignInPathWiring`,
`SignInPathHostView` and `probeSignInPathWiring` occur 0 times in both
`dist/index.d.ts` and `dist/rate-limit-storage.d.ts`, so the gate module
stays unpublished. Positive control on the same grep: `AuthPlugin`
occurs 40 and 1 times. The changeset is graded `minor`.
- **B6.** `content/docs/deployment/self-hosting.mdx` documents the boot
report. It now says when the same shape is logged at `debug` instead,
including the new declaration, and warns that setting the option without
a real handoff route hides the dead end. No docs page lists
`AuthPlugin`'s host options, so there was nothing else to update.
## Evidence
Pins first, then the fix, then an ablation. All pins are in
`boot-sign-in-reachability.sso-gate.test.ts`.
- **Red, pins only (`f6be56009`, source at base):** `Tests 8 failed | 26
passed (34)`. Six are the new #20861 pins. Two are the existing shape
pins, which now expect the four-fact `NOTHING_WIRED`. Every failure is
an `AssertionError`, for example `expected [ Array(1) ] to have a length
of +0 but got 1` on the declared boot. The CONTROL pin and the
`getPublicConfig()` pin are green, which is correct: they hold both
before and after the fix.
- **Green, fix (`88aff6fe7`):** the gate suite plus the #14353 suite
gives `Test Files 2 passed (2)` and `Tests 85 passed (85)`, against a
baseline of 77 at `9905e61ca`.
- **Ablation (`88aff6fe7`):** deleted the `if
(wiring.hostSignInHandoff)` branch in `resolveDelegatedSignInPath`
through `scripts/ablation-replace.mjs`, in WRAP mode with an
absolute-path trap. Anchor count went 1 to 0; blob went `cf6dd010f040`
to `67310dc47389`. Result: `Tests 3 failed | 31 passed (34)`, the three
predicted pins (the declared boot, the `debug` line, the gate-level
null). The resolver pins stay green because they test the resolver, not
the branch. Restore: blob after `cf6dd010f040` equals the HEAD blob, and
`git diff HEAD` and `git status --porcelain` are empty. The subject is
imported relatively (`./boot-sign-in-reachability`, which is `src`), so
no `dist/` sits on the resolution path.
- **Package (`88aff6fe7`):** `pnpm --filter @objectstack/plugin-auth
test` gives `Test Files 115 passed (115)` and `Tests 2472 passed
(2472)`. `typecheck` exits 0, including `check:test-typecheck` OK.
- **Gates (`88aff6fe7`):** `dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 95 commands. I ran all 95, plus
`check-changeset-fixed`, `check:authz-resolver`,
`check:error-code-casing` and `check:filter-alias-parity`
(`check:auth-mount-ledger` is in the 95). `--ran` answered `95 derived
famil(ies) accounted for — 95 run, 0 NOT-MEASURED (a DERIVED zero …)`.
Three gates first exited 3 (`PREREQUISITE NOT MET`):
`check:skill-examples`, `check:type-check-debt` and
`check:dual-build-cjs-loads`. After I built the
`@objectstack/client-react` closure, all three exited 0 on re-run.
`check:type-check-debt` reported "4 ledger entries re-measured … none
above its recorded number", and `check:dual-build-cjs-loads` reported
"105 published require entry points across 66 packages load".
- **Lint (narrowed, `88aff6fe7`):** eslint `--no-inline-config --format
json` over the three touched TS files checked 3 files with 0 errors and
0 warnings. The config itself says the two Markdown paths are "File
ignored because no matching configuration was supplied", so those 3
files are the diff's whole lint population. Type-aware linting is off
(`eslint.config.mjs:327`, and no `parserOptions.project`), and the diff
touches no lint config or rule, so it cannot change any untouched file's
lint result. The repo-wide `pnpm lint` is left to CI.
## Acceptance notes
- Noted, not filed: the walled-owner neighbour
(`warnIfWalledOwnerCannotVerify`) decides `hasFederatedSignIn` from
`pub` only and does not read `hostSignInHandoff`. That is by #15074's
design ("the neighbour is untouched by this gate", pinned). Whether a
hosted kernel with the button hidden also meets that neighbour's four
preconditions is NOT MEASURED here. Carrier: the cloud follow-up card,
whose rebuild log will show it.
- `main` moved five commits past the base (`9905e61ca` to `4edb61449`)
while this ran. None of them touches this PR's five paths (measured).
Per the dispatch's same-day-churn clause, no merge was made. CI's merge
ref checks the combined tree.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01XY5uCwTjZj7884yYtyur4H)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 93d4e0e commit 33b6e8b
5 files changed
Lines changed: 241 additions & 5 deletions
File tree
- .changeset
- content/docs/deployment
- packages/plugins/plugin-auth/src
| 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 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
540 | 540 | | |
541 | 541 | | |
542 | 542 | | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
543 | 554 | | |
544 | 555 | | |
545 | 556 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
225 | 225 | | |
226 | 226 | | |
227 | 227 | | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
228 | 253 | | |
229 | 254 | | |
230 | 255 | | |
| |||
1052 | 1077 | | |
1053 | 1078 | | |
1054 | 1079 | | |
1055 | | - | |
| 1080 | + | |
| 1081 | + | |
| 1082 | + | |
| 1083 | + | |
1056 | 1084 | | |
1057 | 1085 | | |
1058 | 1086 | | |
| |||
Lines changed: 100 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
53 | 53 | | |
54 | 54 | | |
55 | 55 | | |
| 56 | + | |
56 | 57 | | |
57 | 58 | | |
58 | 59 | | |
| |||
61 | 62 | | |
62 | 63 | | |
63 | 64 | | |
| 65 | + | |
64 | 66 | | |
65 | 67 | | |
66 | 68 | | |
| |||
174 | 176 | | |
175 | 177 | | |
176 | 178 | | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
177 | 183 | | |
178 | 184 | | |
179 | 185 | | |
| 186 | + | |
180 | 187 | | |
181 | 188 | | |
182 | 189 | | |
| |||
454 | 461 | | |
455 | 462 | | |
456 | 463 | | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
| 467 | + | |
| 468 | + | |
| 469 | + | |
| 470 | + | |
| 471 | + | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
| 475 | + | |
| 476 | + | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
| 503 | + | |
| 504 | + | |
| 505 | + | |
| 506 | + | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
Lines changed: 65 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
195 | 195 | | |
196 | 196 | | |
197 | 197 | | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
198 | 230 | | |
199 | 231 | | |
200 | 232 | | |
| |||
363 | 395 | | |
364 | 396 | | |
365 | 397 | | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
366 | 405 | | |
367 | 406 | | |
368 | 407 | | |
| |||
375 | 414 | | |
376 | 415 | | |
377 | 416 | | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
378 | 427 | | |
379 | 428 | | |
380 | 429 | | |
381 | 430 | | |
382 | 431 | | |
383 | 432 | | |
384 | | - | |
385 | | - | |
386 | | - | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
387 | 436 | | |
388 | 437 | | |
389 | 438 | | |
390 | 439 | | |
391 | 440 | | |
| 441 | + | |
392 | 442 | | |
393 | 443 | | |
394 | 444 | | |
| 445 | + | |
395 | 446 | | |
396 | 447 | | |
397 | 448 | | |
398 | 449 | | |
| 450 | + | |
399 | 451 | | |
400 | 452 | | |
401 | 453 | | |
402 | 454 | | |
403 | | - | |
| 455 | + | |
404 | 456 | | |
405 | 457 | | |
406 | 458 | | |
| |||
431 | 483 | | |
432 | 484 | | |
433 | 485 | | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
434 | 493 | | |
435 | 494 | | |
436 | 495 | | |
| |||
455 | 514 | | |
456 | 515 | | |
457 | 516 | | |
| 517 | + | |
| 518 | + | |
458 | 519 | | |
459 | 520 | | |
460 | 521 | | |
| |||
0 commit comments