Skip to content

fix(import): sanitize row errors — never leak raw SQL, friendly constraint messages (#3566) - #3572

Merged
os-zhuang merged 1 commit into
mainfrom
claude/personnel-import-required-fields-38926f
Jul 27, 2026
Merged

fix(import): sanitize row errors — never leak raw SQL, friendly constraint messages (#3566)#3572
os-zhuang merged 1 commit into
mainfrom
claude/personnel-import-required-fields-38926f

Conversation

@baozhoutao

@baozhoutao baozhoutao commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Fixes #3566 (server side). Companion UI PR: objectstack-ai/objectui#2840.

Problem

A failing import row surfaced the driver's raw error verbatim. When a write hit a DB constraint (e.g. sys_user.phone_number is unique), the query builder embeds the entire failing statement in err.message, and toFailedResult handed it straight back — the importer saw:

insert into `sys_user` (`__search`, `ai_access`, ... `phone_number`, ...) values ('zhoujunyi zjy', false, 0, '2026-07-2... - UNIQUE constraint failed: sys_user.phone_number

Unreadable, and an information disclosure of the schema.

Changes

  • sanitizeRowError() (packages/rest/src/import-runner.ts) — maps common constraint failures to human wording and never lets a raw SQL statement reach the client:
    • UNIQUE (SQLite / MySQL / Postgres) → "A record with this <column> already exists."
    • NOT NULL → "<column> is required."
    • Anything still reading as a SQL statement → salvage the driver's trailing reason, else a generic message.
    • Already-friendly messages (e.g. better-auth's "User already exists. Use another email.") pass through unchanged.
    • Applies to every import path (generic /data/:object/import and the identity import).
  • isLikelyEmail (packages/plugins/plugin-auth/src/admin-user-endpoints.ts) — now rejects non-ASCII, so an address like x@柴仟.com fails the import dry-run pre-check instead of passing client + dry-run validation only to be rejected by better-auth's strict ASCII validator at real-import time. Single linear char-class test — no ReDoS.

Tests

  • packages/rest/src/import-runner-error-sanitize.test.ts — 8 cases (SQLite/MySQL/PG unique, not-null, SQL backstop, friendly passthrough, empty).
  • admin-user-endpoints.test.ts — non-ASCII rejection cases.
  • rest import-runner suite (30) and plugin-auth (59) green.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 27, 2026 7:02am

Request Review

@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/plugin-auth, @objectstack/rest.

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

  • content/docs/api/error-catalog.mdx (via @objectstack/rest)
  • content/docs/api/error-handling-server.mdx (via @objectstack/rest)
  • content/docs/api/index.mdx (via @objectstack/rest)
  • content/docs/deployment/cli.mdx (via @objectstack/plugin-auth)
  • content/docs/deployment/production-readiness.mdx (via @objectstack/plugin-auth)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/plugin-auth)
  • content/docs/permissions/authentication.mdx (via @objectstack/plugin-auth)
  • content/docs/permissions/sso.mdx (via @objectstack/plugin-auth)
  • content/docs/plugins/index.mdx (via @objectstack/plugin-auth, @objectstack/rest)
  • content/docs/plugins/packages.mdx (via @objectstack/plugin-auth, @objectstack/rest)
  • content/docs/protocol/kernel/i18n-standard.mdx (via packages/rest)
  • content/docs/releases/implementation-status.mdx (via @objectstack/plugin-auth, @objectstack/rest)
  • content/docs/releases/v12.mdx (via @objectstack/rest)
  • content/docs/releases/v9.mdx (via @objectstack/plugin-auth)

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.

@os-zhuang
os-zhuang merged commit 65ac468 into main Jul 27, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the claude/personnel-import-required-fields-38926f branch July 27, 2026 08:38
…raint messages (#3566)

Import rows that hit a DB constraint surfaced the driver's raw error verbatim —
including the full failing SQL statement (e.g. `insert into sys_user (...) - UNIQUE
constraint failed: sys_user.phone_number`), which is unreadable and leaks the schema.

- sanitizeRowError() maps SQLite/MySQL/Postgres UNIQUE and NOT NULL failures to
  human wording and, as a backstop, never lets a raw SQL statement reach the client.
  Already-friendly messages (better-auth's "User already exists") pass through.
- isLikelyEmail rejects non-ASCII, so `x@柴仟.com` fails the import dry-run instead
  of only at real-import time inside better-auth.
- Unit tests for both.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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 size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Identity import: raw SQL leaks into row errors; DB constraint failures need sanitized, friendly messages

2 participants