Skip to content

feat(cli): validate user-schema identity designations at plan time - #1128

Draft
livio-a wants to merge 1 commit into
mainfrom
feat-cli-designation-validation
Draft

livio-a wants to merge 1 commit into
mainfrom
feat-cli-designation-validation

Conversation

@livio-a

@livio-a livio-a commented Sep 3, 2026

Copy link
Copy Markdown
Member

Ports the server's user-schema designation validator into @zitadel/config, so zitadel plan, apply, and doctor reject a schema file locally instead of letting apply fail with a 400 from the server.

Closes #1057

What it validates

The same rules as validateUserSchemaDesignations (internal/domain/schema_designation.go, ADR 058 §1–§2):

  • x-identifier must name a reachable scalar leaf carrying x-unique: "project".
  • Every x-display entry must name a reachable scalar leaf (dot-paths descend through object-shaped parents only).
  • A password-enabled schema must designate an identifier (passkey deliberately not in the trigger — discoverable credentials identify the user through the assertion).

Error messages mirror the Go detail strings verbatim, so a user who bypasses plan sees identical text from the server. One documented divergence: the CLI collects every violation instead of failing fast.

Design notes

  • The refine runs on the raw document, not the generated Zod's parse output. CreateSchemaBody's parse strips unmodeled keywords (leaf type, root type, $id) and injects defaults, which would break the scalar-leaf checks. schemaConfigSchema is now a z.custom(...).superRefine that checks shape first via CreateSchemaBody.safeParse (issues re-emitted), then designations on the raw document — the same order as the server's schema_validator.go, and the server stores the raw bytes verbatim anyway.
  • Drift audit, same contract as the flow-validator port: SCHEMA_DESIGNATION_RULES maps each rule id to the Go function it ports; a test asserts those functions still exist in internal/domain/schema_designation.go and that the shared message literals still match. Verified it fires: typoing a goRef fails the audit.
  • The test suite mirrors TestTenantSchemaValidator_UserSchemaDesignations case for case (27 cases), plus collect-all ordering and the wiring through schemaConfigSchema.
  • SchemaSyncer.validate folds the issues into the thrown message (validatePlannedFlows pattern), and doctor's SchemaCheck renders path message per issue.
  • Existing test fixtures that enabled password without designating an identifier were updated — the server would reject those documents on apply, which is exactly the gap this PR closes. The scaffolded default (packages/config/defaults/default-human-user.json) already designates correctly and passes.

Follow-up

Like the flow port, this is a local-first interim; the designed successor is the server-side validate-only bundle endpoint (#449).

🤖 Generated with Claude Code

Port the server's designation validator (validateUserSchemaDesignations,
internal/domain/schema_designation.go) into @zitadel/config and wire it
into schemaConfigSchema, so zitadel plan, apply, and doctor reject a
schema file the server would 400 on apply — with the server's own error
messages, verbatim.

The refine runs on the raw document, not the generated Zod's parse
output: CreateSchemaBody strips unmodeled keywords (leaf `type`, root
`type`, `$id`) and injects defaults, so shape is checked first via
safeParse (issues re-emitted), then designations on the raw bytes — the
same order as the server's schema_validator.go. Unlike the server
(fail-fast), the port collects every violation; a drift-audit test pins
the ported Go functions and shared message literals.

Closes #1057

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Sep 3, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
nextgen Ready Ready Preview Sep 3, 2026 11:19am UTC
nextgen-docs Ready Ready Preview Sep 3, 2026 11:19am UTC
nextgen-mock-zitadel Ready Ready Preview Sep 3, 2026 11:19am UTC

Request Review

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

🦋 Changeset detected

Latest commit: 90f5aa0

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 20 packages
Name Type
@zitadel/config Minor
@zitadel/cli Minor
@zitadel/components Minor
@zitadel/testing Minor
@zitadel/sdk-angular Minor
@zitadel/sdk-next Minor
@zitadel/sdk-nuxt Minor
@zitadel/sdk-qwik Minor
@zitadel/sdk-react Minor
@zitadel/sdk-solid Minor
@zitadel/sdk-svelte Minor
@zitadel/sdk-vue Minor
@zitadel/server Minor
@zitadel/server-linux-x64 Minor
@zitadel/server-linux-arm64 Minor
@zitadel/server-darwin-x64 Minor
@zitadel/server-darwin-arm64 Minor
@zitadel/server-win32-x64 Minor
@zitadel/api Minor
@zitadel/sdk-core Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

This branch was successfully deployed

3 active deployments
Preview – nextgen-docs — 90f5aa00 Deployed Sep 3, 2026 by vercel[bot]
Preview – nextgen — 90f5aa00 Deployed Sep 3, 2026 by vercel[bot]
Preview – nextgen-mock-zitadel — 90f5aa00 Deployed Sep 3, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Inbox

Development

Successfully merging this pull request may close these issues.

Port the user-schema designation rules to the CLI (zitadel plan/doctor)

1 participant