Skip to content

fix(driver-sql): fail-loud on unknown filter operators; real IS NULL / IS NOT NULL; $not (#2704)#2872

Merged
os-zhuang merged 1 commit into
mainfrom
claude/github-issue-2704-0d903e
Jul 13, 2026
Merged

fix(driver-sql): fail-loud on unknown filter operators; real IS NULL / IS NOT NULL; $not (#2704)#2872
os-zhuang merged 1 commit into
mainfrom
claude/github-issue-2704-0d903e

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Closes #2704.

问题

driver-sql 把它不认识的 filter 算子直接原样转发给 Knex。当比较值是 null 时,这会静默编译成整表匹配——于是一个按权限/负责人范围过滤的列表视图会把所有行都返回出去(数据泄漏)。触发场景很现实:ObjectUI 客户端对空值筛选发的是 is_null / isnull / is_empty 这类拼写。

具体三个坑:

  1. 数组格式 where 的 default 分支透传未知算子 → is_null + null 比较值 → 整表匹配;is_empty → Knex 直接抛 400。
  2. 对象格式({field:{$op:value}})把未知 $op 静默降级成相等比较,且完全没有 $null 处理。
  3. 没有真正的空值判断:field = null 在 SQL 里永远渲染不出 IS NULL

改动

  • 空值谓词渲染成真正的 SQL:is_null/isnull/is_empty(及否定式)→ IS NULL/IS NOT NULL,与 equals+null 语义对齐;!= nullIS NOT NULL
  • 两条 filter 路径都补齐 spec 全量算子 + 客户端别名:$between/$startsWith/$endsWith/$notContains/$null/$exists,以及逻辑算子 $not(取反子条件——CEL !expr 的权限 scope 会编成它,driver-mongodb/driver-memory 都已实现,driver-sql 此前是缺的)。
  • contains/startsWith/endsWith 的值做 LIKE 转义并显式 ESCAPE '\',防止用户输入里的 %/_ 扩大匹配范围。
  • 未知算子在两条路径都抛错(fail-loud),不再静默返回整表。
  • @objectstack/spec:VALID_AST_OPERATORS/AST_OPERATOR_MAP 识别客户端别名拼写并映射到 $null,保证数组-AST → 对象-filter 转换与驱动一致。

顺带修掉的潜在 bug:CEL 派生的 $startsWith/$endsWith/$null 范围过滤(此前对 SQL 静默错误)、better-auth $regex contains(此前退化成精确匹配)。

测试

新增 sql-driver-null-operators.test.ts(17 个用例,覆盖两条路径的空值算子、!=+null、$not$startsWith$regex、未知算子抛错、count 范围正确)。

  • driver-sql: 275 passed
  • spec: 6716 passed
  • plugin-auth: 322 passed(2 个预存在的无关 import 失败)
  • driver-sql / spec build 均成功

范围说明

本 PR 只覆盖 SQL 驱动。理想上"未知算子就报错"应在 parseFilterAST 边界统一做,但 objectql 引擎目前把 ast.where 原样透传给驱动、绕过了 parseFilterAST,所以驱动层是当前唯一能拦截的地方。让所有驱动统一 fail-loud 是一个更大的独立改动,单独开 issue 跟踪。

@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jul 13, 2026 4:00am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation protocol:data tests tooling size/m labels Jul 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/driver-sql, @objectstack/spec.

99 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/spec)
  • content/docs/api/environment-routing.mdx (via @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/driver-sql, @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/glossary.mdx (via @objectstack/driver-sql)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/anatomy.mdx (via @objectstack/driver-sql)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/driver-sql, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/i18n-standard.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/index.mdx (via @objectstack/driver-sql)
  • content/docs/protocol/objectos/lifecycle.mdx (via @objectstack/driver-sql, @objectstack/spec)
  • content/docs/protocol/objectos/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via packages/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via packages/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/driver-sql, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@baozhoutao

Copy link
Copy Markdown
Contributor Author

范围说明里提到的"让所有驱动统一 fail-loud"的更大改动,已单独开:#2873

@os-zhuang os-zhuang merged commit ce6d151 into main Jul 13, 2026
17 checks passed
@os-zhuang os-zhuang deleted the claude/github-issue-2704-0d903e branch July 13, 2026 05:48
…/ IS NOT NULL; $not (#2704)

The array-format where path forwarded any unrecognised operator straight to
Knex; on a null comparand that silently became a whole-table match, so a
permission/assignment-scoped list view could leak every row (an is_null /
is_empty operator from the client). The object-format path silently degraded an
unknown $op to equality and had no $null handling.

- Render null predicates as real IS NULL / IS NOT NULL, unified with equals+null;
  != null -> IS NOT NULL.
- Support the full spec operator set + client aliases in both filter shapes,
  incl. $between / $startsWith / $endsWith / $notContains / $null / $exists
  and the logical $not (negated sub-condition; CEL !expr scopes compile to it).
- LIKE-escape contains/startsWith/endsWith with explicit ESCAPE '\'.
- Throw on a genuinely unknown operator in BOTH paths (fail-loud, no leak).
- spec: recognise client alias spellings (isnull/is_empty/...) -> $null.

Adds sql-driver-null-operators.test.ts (17 cases across both paths).

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

Labels

documentation Improvements or additions to documentation protocol:data size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[driver-sql] 未知查询 operator(is/is_null)静默透传返整表,应报错;缺 $null 处理

2 participants