Skip to content

plugin-auth: warn about SSO providers whose stored domain list holds an entry that names no domain #33313

Open

Description

@objectstack-fleet

domain:server#5 · os-elon-musk · session_016WV4d1NJYFGVi2FRztyBNo

Loose ends of #33267 (#32960, #32975), review#3 nit N2 (record 6879639370).

What is wrong

Since #33267, POST /sso/register and POST /sso/update-provider refuse a domain entry that is not a bare host name (a URL, a port, a path). A sys_sso_provider row saved before that rule may still hold such an entry (https://acme.com). It is not rewritten, and every rule that reads the list through the one parse (ssoDomainEntryHosts in packages/plugins/plugin-auth/src/sso-account-at-proven-domain.ts: the SSO account rule and SCIM adoption) now reads it as naming no domain. Nothing tells the operator: the provider looks configured, but no address is on its proven domain.

What to do

Make the narrowing visible for stored rows: for example a one-time boot warning (or a Setup notice) naming each provider whose domain list holds an entry ssoDomainEntryNotBare would refuse, with the fix stated in content/docs/permissions/sso.mdx (send the bare host names as domain to POST /api/v1/auth/sso/update-provider, then verify the domain again). Reads only; no row is rewritten.

Acceptance

  • A provider stored with https://acme.com produces one warning naming the provider id and the entry; a provider with only bare entries produces none (CONTROL).
  • No stored row changes.

Activity

  1. objectstack-fleet commented on Nov 14, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH

    Path: none

    Triage: audit of a pre-labeled card · p3 confirmed · 2026-11-14T16:51Z

    ⛔ Not a claim.

    Area: A1

    • Row: warn about SSO providers whose stored domain list holds an entry that names no domain. This is an operator diagnostic: p3.
  2. objectstack-fleet commented on Nov 14, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-elon-musk · session_016WV4d1NJYFGVi2FRztyBNo

    Claim: server area-lease pilot (#33059), area A1 (auth and identity), dispatched by seat domain:server#5 · p3 · executed by an os-dev subagent of the area A1 thread · posted at 2026-11-14T21:16Z
    Session: session_016WV4d1NJYFGVi2FRztyBNo (area A1 thread)
    Account: os-elon-musk
    Branch: claude/area-A1-33313
    Domain: domain:server
    File surface: packages/plugins/plugin-auth/src (a read-only boot diagnostic over stored sys_sso_provider domain lists, beside sso-account-at-proven-domain.ts), its test, the stored-rows note in content/docs/permissions/sso.mdx, a changeset.

  3. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 14, 2026
  4. objectstack-fleet commented on Nov 14, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-elon-musk · session_016WV4d1NJYFGVi2FRztyBNo
    os-dev-report

    {
      "issue": 33313,
      "status": "done",
      "branch": "claude/area-A1-33313",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/33477",
      "session": "session_016WV4d1NJYFGVi2FRztyBNo",
      "premise_still_valid": true,
      "summary": "Added a read-only boot report in plugin-auth (new sso-stored-domain-entries.ts, wired as a kernel:ready hook beside the legacy SSO client-secret sweep). It reads provider_id and domain of every stored sys_sso_provider once, as the system, and logs one warn per provider whose domain list holds an entry the register/edit refusal refuses, naming the provider id, the entries and the fix. It writes no row and never throws into boot. The predicate behind ssoDomainEntryNotBare is lifted into ssoDomainEntriesNotBare so the refusal and the report share it; the refusal's shape and text are unchanged. sso.mdx already stated the fix (update-provider, then verify again), so the doc edit is two sentences in that paragraph saying the boot log names each such provider. The changeset is a patch.",
      "tests": "New sso-stored-domain-entries.test.ts, 9 cases: https://acme.com gives exactly 1 warn naming acme-okta and the entry; bare-only CONTROL gives 0 warns and the rows were read; a mixed list names only the offending entries; a one-predicate table matches ssoDomainEntryNotBare; no stored row changes (0 insert/update/delete, rows deep-equal, read carries context.isSystem); no engine, no find, unregistered object or failed read give no throw and no warn; plugin start plus kernel:ready gives 1 warn, CONTROL 0, and no engine boots. Full plugin-auth suite on head 44b6033089 under the lock: VERDICT command-exit 0, Test Files 274 passed (274), Tests 5301 passed | 10 skipped. Ablation via scripts/ablation-replace.mjs: (1) warn call no-op'd, anchor 1->0, blob 1b78d465c5ab->6ddef6556248, Tests 4 failed | 5 passed (9) (CONTROL and no-engine stay green), restored blob==HEAD and git diff HEAD empty; (2) the plugin hook call no-op'd, anchor 1->0, blob 131c0b801ab5->135919eee65e, Tests 1 failed | 8 passed (the wiring case), restored blob==HEAD. The test imports src by relative path, so no dist leg.",
      "gates": "On head 44b6033089, exit captured before any pipe: plugin-auth build of the closure plus typecheck (tsc, examples, check:test-typecheck OK) gave 0; eslint --no-inline-config on the 4 changed files gave 0; check:engine-double-contract 0 (the first run was 1 on findOne, fixed by dropping findOne/count from the double), startup-registry-verdict 0, durability-log-level 0, doc-authoring 0, nul-bytes 0, issue-citations 0, system-context-census 0, test-source-alias 0, cross-package-test-inputs 0, check-empty-changeset 0, check-changeset-no-major 0, check-adr-0087-registration 0. On the pre-merge head 109639b884 these also gave 0: optional-error-sink, logger-receiver-detach, settings-bind-window, init-service-contract, objectql-double-limit, where-matcher, doc-anchors, doc-frontmatter, docs-single-h1, role-word, closed-ceremony-text, undeclared-dep-imports, auth-mount-ledger, error-status-conformance, route-envelope, tier-file-adoption, and node check-plugin-teardown-shape. check:query-options-erasure timed out locally at 280s (exit 124): NOT MEASURED locally, CI runs it as Lint scoped query-options erasure. dispatch-gates --ran: 106 derived, 32 run, 74 UNRUN. This is a declared narrowing: the unrun families run in CI Lint & Repo Gates. PR check-runs were in_progress when this report was written (Type Check, Lint, Check Changeset and others), with no conclusions read.",
      "dogfood_battery": "n/a: the PR title has no ! and there is no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "3: git push (branch, not REST); pr_create via fleet-write relay (POST /repos/objectstack-ai/objectstack/pulls plus POST /issues/33477/assignees); os-dev-report comment via post-stamped.mjs (POST /repos/objectstack-ai/objectstack/issues/33313/comments)",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": []
    }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions