Skip to content

test(plugin-auth): register sys_position / sys_user_position in the sso-register harness - #16305

Merged
os-warren merged 1 commit into
mainfrom
claude/issue-14846-sso-register-harness-positions
Sep 6, 2026
Merged

test(plugin-auth): register sys_position / sys_user_position in the sso-register harness#16305
os-warren merged 1 commit into
mainfrom
claude/issue-14846-sso-register-harness-positions

Conversation

@os-warren

Copy link
Copy Markdown
Collaborator

Fixes #14846

What this changes

bootEngine() in packages/plugins/plugin-auth/src/sso-register-platform-admin-gate.test.ts
registered the auth identity objects plus hand-declared sys_permission_set and
sys_user_permission_set fixtures, but never the position pair the platform-admin standing
resolver also reads. This registers sys_position and sys_user_position the same
hand-declared way, with only the columns the judge reads. Test-only; no source, contract or
export surface is touched.

The defect, and why the suite could not see it

resolveAuthzContext reads sys_user_position on every resolution, and sys_position
whenever the principal holds any position — which is always here, because every
authenticated member implicitly holds the ADR-0090 D5 everyone anchor. With neither table
registered, both reads were refused by the driver and tryFind's loud-failure arm logged
them, while the resolver went on treating each refusal as "this principal holds no
positions".

So the file reported Tests 4 passed (4) sitting on top of eight
[sql-driver] DATABASE_ERROR ... no such table lines, four per table, and not one assertion
could notice.

That is a latent false green on a security-adjacent resolver, not untidy log output:
a future change that made platform-admin standing genuinely depend on a position row would
have been measured against an engine that can never return one, and this file would have
stayed green.
It is the same shape #14756 exists to remove — a harness whose registered
object set is narrower than the code path it drives — kept invisible because the errors are
logged rather than thrown.

Measurement

The acceptance instrument is one vitest run of that single file, counting
[sql-driver] DATABASE_ERROR ... no such table lines. Re-derived on this branch's own head
rather than quoting the card's two-day-old tally. The before-leg was measured by restoring
the file to origin/main on the same tree; the mutation and the restore were both proven by
blob hash (git hash-object against the HEAD blob), and the tree was verified clean
afterwards.

line class before after
refused read on sys_position 4 0
refused read on sys_user_position 4 0
total driver refusals 8 0
non-deterministic paging warnings 6 0
suite result Tests 4 passed (4) Tests 4 passed (4)

The six paging warnings fall out for the same root cause and are not a second fix: the driver
emitted them because it had not created those tables and therefore could not name a unique
column to order by. Its own remedy line says "declare the object so this driver manages its
table", which is exactly what registering them does.

No test turned red.

Which columns, and why

Both fixtures follow the permission-set pair already in the file — a plain object literal
with the columns the resolver actually touches, so a fixture adds no dependency edge from
plugin-auth to plugin-security.

  • sys_position: id, name, active, organization_id. active is the ADR-0049
    predicate the resolver applies through isRowActive in section 6a; organization_id is
    what the driver's applyTenantScope filters the organization-scoped sys_position read
    on, so omitting it would have quietly dropped that wall from the harness.
  • sys_user_position: id, user_id, position, organization_id — the where key plus
    the three columns section 4 reads to place a row as global or another tenant's.

Scope

The card offered a second direction — deciding the resolver's absent-table read is a benign
discriminated case and no longer logging it. That one is not taken here: it overlaps the
fenced arm of #14615 and belongs to that card, per triage. Also untouched, deliberately:
packages/core/src/security/admin-standing-surface.ts, the two plugin-security object
definitions, and the other four plugin-auth harnesses.

Verification

Run at 519a76915, the head this PR carries.

  • pnpm --filter @objectstack/plugin-auth exec vitest run --maxWorkers=2 src/sso-register-platform-admin-gate.test.ts
    Test Files 1 passed (1) / Tests 4 passed (4), zero DATABASE_ERROR lines.
  • pnpm --filter @objectstack/plugin-auth exec vitest run --maxWorkers=2
    Test Files 102 passed (102) / Tests 2158 passed (2158).
  • pnpm --filter @objectstack/plugin-auth typecheck — green, including the
    check:test-typecheck leg that covers the test layer (the package's own tsconfig.json
    excludes **/*.test.ts, so that third leg is the one that measures this file). Its debt
    ledger is unmoved: 10 files / 94 errors / 23 pinned signatures held.
  • Gate family derived mechanically at this head with
    node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands, plus the
    four artifact rosters the tool flags as sitting in a directory this diff's path is in
    (check:auth-mount-ledger, check:authz-resolver, check:error-code-casing,
    check:filter-alias-parity). All 50 commands run, all exit 0, each exit code captured
    immediately after a single redirect and never through a pipe. Two of them
    (check:dual-build-cjs-loads, check:type-check-debt) first answered exit 3
    PREREQUISITE NOT MET; the closure was built with
    pnpm exec turbo run build --filter='./packages/*' --filter='./packages/*/*' and both were
    re-run to a real green rather than recorded as passes.

Changeset

Carries skip-changeset, judged rather than assumed: the diff is one *.test.ts file, and
plugin-auth publishes files: ["dist", "README.md", "CHANGELOG.md"] with two tsup entries
(src/index.ts, src/rate-limit-storage.ts). No test file reaches dist, so this PR
releases nothing from any package and there is no user-visible change to describe.


Generated by Claude Code

…so-register harness

`bootEngine()` in `sso-register-platform-admin-gate.test.ts` registered the auth
identity objects plus hand-declared `sys_permission_set` and
`sys_user_permission_set`, but never the position pair the platform-admin
standing resolver also reads.

`resolveAuthzContext` reads `sys_user_position` on every resolution, and
`sys_position` whenever the principal holds any position — always, since every
authenticated member implicitly holds the ADR-0090 D5 `everyone` anchor. With no
such tables, both reads were refused by the driver and `tryFind`'s loud-failure
arm logged them, while the resolver went on treating each refusal as "this
principal holds no positions". The suite reported `Tests 4 passed (4)` over
eight `[sql-driver] DATABASE_ERROR ... no such table` lines, four per table, and
no assertion could notice.

That is a latent false green on a security-adjacent resolver: a change making
platform-admin standing genuinely depend on a position row would have been
measured against an engine that can never return one, and this file would have
stayed green. Same shape #14756 exists to remove — a harness whose registered
object set is narrower than the code path it drives.

Registers both objects the way the file already hand-declares the permission-set
pair, with only the columns the judge reads: `active` (the ADR-0049 predicate
`isRowActive` applies in §6a) and `organization_id` (what the driver's
`applyTenantScope` filters the organization-scoped `sys_position` read on, and
what §4 tests to place a `sys_user_position` row).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XpTx2tbq3pZRYAdoGt6E6Y
@github-actions github-actions Bot added the size/s label Sep 6, 2026
@os-warren os-warren added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 6, 2026 — with Claude
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 7beaaa32ccb1295eeaec73bdca4aea36e713232dpackageMentionDocs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

2 participants