Skip to content

fix(server-core): declare a sort allow-list for the client-scope schema - #3447

Merged
tada5hi merged 2 commits into
masterfrom
fix/console-and-query-bugs
Aug 16, 2026
Merged

fix(server-core): declare a sort allow-list for the client-scope schema#3447
tada5hi merged 2 commits into
masterfrom
fix/console-and-query-bugs

Conversation

@tada5hi

@tada5hi tada5hi commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Closes #3441

The sessions-page half of this PR (#3443) landed separately via #3462, so that commit was dropped in a rebase onto master. What remains is the client-scope fix plus the kit spec that pins the offset-reset contract at the collection manager (the place a regression would reappear; #3462 shipped without one).

#3441clientScopeSchema declared no sort allow-list

It was the sole outlier among the 26 registered schemas (missed by the #3425 sweep). Without the block rapiq falls back to a syntactic name check, so GET /client-scopes?sort=totallyBogusColumn reached ORDER BY clientScope.totallyBogusColumn and surfaced as a 500, where every sibling endpoint fails soft and returns unsorted rows.

The allow-list is wide on purpose. default, clientId, scopeId, clientRealmId and scopeRealmId all sort correctly today through the missing-allow-list fallback and are all already indexed, so the narrow junction-sibling triple would have demoted them from working-and-sorted to silently unsorted. createdAt / updatedAt were the only listed keys with no backing index, which is what the migration adds.

Coverage

The new case is per schema, not per endpoint: a per-endpoint test would leave the next schema that forgets the block equally unguarded. It decodes { sort: 'totallyBogusColumn' } through the real codec for all 26 schemas and asserts the key is stripped.

Verified differentially: with the schema change reverted the suite reports exactly one failure (should strip an unknown sort key for clientScope); with it, the cases pass.

Kit spec: the offset reset a filter load has to carry

entity-collection.spec.ts drives the manager to page 3, then hands it the shape a filter control uses (an assembled Query carrying filters plus pagination: { offset: 0 }) and asserts the request returns to the first page with the retained page size intact. Dropping the reset from the load input makes the request carry offset 20, the #3443 bug.

Verification (after the rebase)

  • apps/server-core full suite: 196 files / 2214 tests passed; indexed-invariant.spec.ts + console-search-surface.spec.ts: 70 passed; kit entity-collection.spec.ts: 16 passed
  • postgres round trip on a scratch DB: migration run / revert / run clean, test:schema-drift matches; 1786631686318-ClientScopeSortIndexes is the newest migration (master's 1786436332251-QueryIndexes shipped in beta.60/61, so a new file is correct)
  • generated DDL touches auth_client_scopes only, and neither column is a foreign key, so the MySQL implicit-FK-index down() trap does not apply
  • check:types clean, eslint clean

Summary by CodeRabbit

  • Bug Fixes
    • Improved client-scope sorting performance for creation and update dates.
    • Prevented unsupported sort fields from causing database errors or server failures.
    • Fixed pagination so resetting the offset returns to the first results while preserving the selected page size.
  • Tests
    • Added regression coverage for invalid sort fields across schemas and pagination resets.

Copilot AI lite review requested due to automatic review settings August 13, 2026 14:40

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f5353bda-99e6-42bd-aade-ade7ddc95be9

📥 Commits

Reviewing files that changed from the base of the PR and between 86e3af6 and 969e91a.

📒 Files selected for processing (7)
  • .agents/architecture.md
  • apps/server-core/src/adapters/database/domains/client-scope/entity.ts
  • apps/server-core/src/adapters/database/migrations/mysql/1786631686318-ClientScopeSortIndexes.ts
  • apps/server-core/src/adapters/database/migrations/postgres/1786631686318-ClientScopeSortIndexes.ts
  • apps/server-core/src/core/entities/client-scope/schema.ts
  • apps/server-core/test/unit/core/query/indexed-invariant.spec.ts
  • packages/client-web-kit/test/unit/components/utility/entity-collection.spec.ts

Included review availability: Your plan includes up to 1 review per rolling hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The PR adds indexed timestamp sorting for client scopes, validates unknown sort-key removal across schemas, documents the invariant, and adds regression coverage for pagination offset reset behavior.

Changes

Query sorting safeguards

Layer / File(s) Summary
Client-scope indexes and sort contract
apps/server-core/src/adapters/database/domains/client-scope/entity.ts, apps/server-core/src/core/entities/client-scope/schema.ts, apps/server-core/src/adapters/database/migrations/*/1786631686318-ClientScopeSortIndexes.ts
Client-scope records add createdAt and updatedAt indexes. The schema allows sorting by indexed client-scope fields. MySQL and PostgreSQL migrations create and remove the timestamp indexes.
Unknown sort-key regression coverage
apps/server-core/test/unit/core/query/indexed-invariant.spec.ts, .agents/architecture.md
The invariant test checks every schema and removes unknown sort keys during decoding. The architecture documentation describes the required sorts block and the client-scope fix.

Entity collection pagination

Layer / File(s) Summary
Filter-load offset reset
packages/client-web-kit/test/unit/components/utility/entity-collection.spec.ts
The regression test verifies that a load with offset 0 replaces a retained offset while preserving the page limit.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 969e9

The PR adds the client-scope sort allow-list and supporting indexes while pinning the offset-reset behavior in tests; no actionable merge-blocking risk remains after normal checks and review.

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The pagination-reset test in packages/client-web-kit is unrelated to issue #3441 and falls outside its stated scope. Move the pagination-reset test to a separate pull request or link it to an issue that covers this behavior.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: adding a sort allow-list to the client-scope schema.
Linked Issues check ✅ Passed The PR adds the required allow-list, supporting indexes, and schema-wide regression coverage for issue #3441.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/console-and-query-bugs

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install timed out. The project may have too many dependencies for the sandbox.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Aug 13, 2026

Copy link
Copy Markdown

Open in StackBlitz

authup

npm i https://pkg.pr.new/authup@3447

@authup/client-account-console

npm i https://pkg.pr.new/@authup/client-account-console@3447

@authup/client-admin-console

npm i https://pkg.pr.new/@authup/client-admin-console@3447

@authup/client-auth-console

npm i https://pkg.pr.new/@authup/client-auth-console@3447

@authup/server-core

npm i https://pkg.pr.new/@authup/server-core@3447

@authup/access

npm i https://pkg.pr.new/@authup/access@3447

@authup/client-web-kit

npm i https://pkg.pr.new/@authup/client-web-kit@3447

@authup/client-web-kit-theme

npm i https://pkg.pr.new/@authup/client-web-kit-theme@3447

@authup/client-web-nuxt

npm i https://pkg.pr.new/@authup/client-web-nuxt@3447

@authup/client-web-theme

npm i https://pkg.pr.new/@authup/client-web-theme@3447

@authup/core-http-kit

npm i https://pkg.pr.new/@authup/core-http-kit@3447

@authup/core-kit

npm i https://pkg.pr.new/@authup/core-kit@3447

@authup/core-realtime-kit

npm i https://pkg.pr.new/@authup/core-realtime-kit@3447

@authup/errors

npm i https://pkg.pr.new/@authup/errors@3447

@authup/i18n

npm i https://pkg.pr.new/@authup/i18n@3447

@authup/kit

npm i https://pkg.pr.new/@authup/kit@3447

@authup/server-adapter-kit

npm i https://pkg.pr.new/@authup/server-adapter-kit@3447

@authup/server-adapter-node

npm i https://pkg.pr.new/@authup/server-adapter-node@3447

@authup/server-adapter-socket-io

npm i https://pkg.pr.new/@authup/server-adapter-socket-io@3447

@authup/server-adapter-web

npm i https://pkg.pr.new/@authup/server-adapter-web@3447

@authup/server-kit

npm i https://pkg.pr.new/@authup/server-kit@3447

@authup/server-test-kit

npm i https://pkg.pr.new/@authup/server-test-kit@3447

@authup/specs

npm i https://pkg.pr.new/@authup/specs@3447

commit: 969e91a

@tada5hi

tada5hi commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator Author

Audit outcome

Reviewed adversarially against the runtime rather than the diff. Verdict: sound, no defects.

The reviewer executed the real @rapiq/core + @rapiq/codec-url from node_modules rather than reasoning about them:

Acted on since

Noted, not changed

  • A multi-key sort on client-scope with no matching composite prefix now drops whole-parameter. That is the documented fail-soft narrowing every sibling schema already carries.
  • The subject-kind select drops a change made while a load is in flight (load early-returns on busy). Pre-existing and identical on master; ASearch debounces, this select does not.
  • ClientScopeService.getMany has no per-row realm gate, so a CLIENT_READ holder sees other realms' rows. Pre-existing on master and unrelated to this change, but it is what makes "sorting exposes nothing new" true here.

`clientScopeSchema` was the only registered schema with no `sorts` block,
so rapiq fell back to a syntactic name check: an arbitrary root sort key
survived decode, reached `ORDER BY` on a column that does not exist, and
`sanitizeError` mapped the driver rejection to a 500 where every sibling
endpoint fails soft and returns unsorted rows.

Allow-list every column the schema already indexes rather than the narrow
junction-sibling triple. `default`, `clientId`, `scopeId` and the two
owner-realm keys sort correctly today through the missing-allow-list
fallback, and a narrow list would demote them from working-and-sorted to
silently unsorted. `createdAt` / `updatedAt` were the only listed keys
without a backing index, hence the migration.

Pin the property per schema rather than per endpoint: the new case
decodes a bogus key through the real codec for all 26 registered schemas,
so the next schema that forgets the block fails the suite instead of one
endpoint. Verified differentially (1 failure without the schema change).

Closes #3441
From the audit of this branch: #3443 shipped with no test, and the manager
is where a regression would reappear. The case drives the manager to page 3,
then hands it the shape the sessions page uses (an assembled Query carrying
filters plus `pagination: { offset: 0 }`) and asserts the request returns to
the first page with the retained page size intact.

Verified by dropping the reset from the load input: the request then carries
offset 20, which is the reported bug.

Also records in the client-scope schema itself why its sort allow-list is
wider than its junction siblings', which until now lived only in the commit
body and the architecture doc.
@tada5hi
tada5hi force-pushed the fix/console-and-query-bugs branch from bd5b0a5 to 969e91a Compare August 16, 2026 16:19
@tada5hi tada5hi changed the title fix: sessions filter pagination reset and the client-scope sort allow-list fix(server-core): declare a sort allow-list for the client-scope schema Aug 16, 2026
@tada5hi
tada5hi merged commit 8cf2cfe into master Aug 16, 2026
11 of 13 checks passed
@tada5hi
tada5hi deleted the fix/console-and-query-bugs branch August 16, 2026 20:04
@github-actions github-actions Bot mentioned this pull request Aug 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

clientScopeSchema declares no sorts allow-list, so any ?sort= key reaches ORDER BY

2 participants