Skip to content

fix: reject user property name containing dot - #783

Open
vitorbari wants to merge 10 commits into
mainfrom
fix/reject-dotted-schema-property-names
Open

fix: reject user property name containing dot#783
vitorbari wants to merge 10 commits into
mainfrom
fix/reject-dotted-schema-property-names

Conversation

@vitorbari

@vitorbari vitorbari commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Update the user-meta-schema to prevent user property names containing dot ..

Screenshot 2026-08-07 at 17 46 12

Motivation:

Nested properties will be referenced with a dot notation on the flow-definition, so a property name itself can not contain a dot.

Flow-definition example:

{ "name": "address", "fields": ["address.street", "address.city"]}

Notes

  • Applies to the properties chain at every depth. A name hidden under $defs, allOf, or
    items is not caught. (to be fixed later)
  • Only applies where ValidateAgainstMetaSchema runs. A schema the resolver fetches from a URL
    is persisted without it. Unchanged by this PR.

A nested value is stored under its dotted path, so `{"a.b": …}` and
`{"a": {"b": …}}` flatten to the same attribute key. Reject the literal
dotted name at schema create so the two cannot collide.

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

vercel Bot commented Aug 7, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
nextgen Ready Ready Preview Aug 7, 2026 3:49pm
nextgen-docs Ready Ready Preview Aug 7, 2026 3:49pm
nextgen-mock-zitadel Ready Ready Preview Aug 7, 2026 3:49pm

Request Review

@github-actions

github-actions Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

🦋 Changeset detected

Latest commit: b2d4b99

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

This PR includes changesets to release 20 packages
Name Type
@zitadel/server Minor
@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-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

Updated comments to clarify the purpose of rejectDottedPropertyNames function.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR tightens user JSON schema validation by rejecting property names that contain a dot (.), preventing ambiguity between literal dotted keys (e.g. {"a.b": ...}) and nested objects (e.g. {"a": {"b": ...}}) when attributes are flattened and referenced via dotted paths.

Changes:

  • Add validation in NewJSONSchema to reject dotted property names within schema properties.
  • Add tests asserting dotted property names are rejected and ordinary nesting remains allowed.
  • Add a changeset bumping @zitadel/server (minor) to reflect the user-visible behavior change.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
internal/domain/json_schema.go Introduces schema validation to reject dotted property names (needs broader schema traversal to cover $defs/$ref).
internal/domain/json_schema_test.go Adds tests for dotted property name rejection and acceptance of ordinary nesting (missing $defs/$ref case).
.changeset/reject-dotted-schema-property-names.md Documents the behavior change and bumps @zitadel/server version.

Comment thread internal/domain/json_schema.go Outdated
Comment thread internal/domain/json_schema_test.go Outdated
A schema fetched from its URL is persisted straight from a struct
literal, without passing through NewJSONSchema. CreateSchemaByUrl and
the runtime auto-fetch both land there, so the name guard has to run at
that site as well.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The walk only descended through `properties`, so a name declared under
`$defs`, `allOf`, or `items` and pulled in by `$ref` slipped past and
still produced an ambiguous attribute key. Walk every node instead.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds propertyNames to the properties map in user-schema.json, and makes
user-property.json recurse into its own properties map so the rule
reaches every level rather than only the first. An editor validating
against the shipped dialect now flags a dotted name while authoring.

Drops the resolver fetch-path guard added earlier: the POST path is the
one worth covering in Go, and the remote path is better handled by
validating a fetched schema against the meta-schema.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Drops the Go walk in favour of the meta-schema rule. Coverage is
narrower — a name hidden under $defs, allOf, or items is not caught —
but the rule now lives with the dialect, so an editor flags it while
authoring rather than the server rejecting it after the fact.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@vitorbari vitorbari changed the title fix: reject dotted user schema property names fix: require a user schema property name to be a single attribute name Aug 7, 2026
@vitorbari vitorbari changed the title fix: require a user schema property name to be a single attribute name fix: reject user property name containing dot Aug 7, 2026

@fforootd fforootd left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Non-blocking recommendations, details inline — approval separate.

Verified locally on the PR head: TestTenantSchemaValidator_ValidateAgainstMetaSchema passes (both new cases), all 122 config tests pass (drift audit, Ajv dialect compile, shipped defaults/presets). The new user-property.json self-reference makes the schema graph cyclic, which I checked in all three consumers: the Go compiler caches the schema before Resolve (json_schema.go), Ajv resolves via filename registration, and editors resolve relative to .zitadel/meta/. Also nice that this lands before dot-notation flow fields ship — no grandfathered names to migrate.

"description": "The name of a single user attribute."
},
"additionalProperties": {
"$ref": "user-property.json"

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The wire-contract mirrors don't carry the new rule: user-property.yaml still has additionalProperties: true in its nested properties map, and user-schema.yaml has no propertyNames — so API docs and generated clients won't surface a constraint the server now rejects. The yamls deliberately drop the allOf for codegen compat, but propertyNames + pattern is plain OAS 3.1 and likely survives generators. Worth mirroring there in a follow-up, or at minimum stating the dot rule in the yaml description.

A user schema property name must be a single attribute name and may no longer
contain a dot. The rule lives in the user-schema meta-schema, so an editor
validating against the shipped dialect flags it while authoring, and the server
rejects it on create.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Recommend one more sentence here: the additionalProperties: true$ref recursion is a broader tightening than the dot rule. Nested property values must now be objects valid against UserProperty (and draft 2020-12), so e.g. a boolean subschema "foo": true or {"type": 123} two levels down passed before and is rejected now. That's the part most likely to surprise someone resubmitting an existing schema, so the release notes should mention it.

"type": "object",
"description": "A map of additional properties for the user definition, where the key is the property name and the value is the property schema",
"propertyNames": {
"pattern": "^[^.]+$",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The changeset's headline claim is that editors flag this while authoring, but meta-schemas.test.ts has no negative case for the new rule (the branding dialect tests do assert negatives, e.g. the http:// logo URL). A two-line Ajv case — dotted name fails, clean name passes — would pin the editor-facing artifact independently of the Go suite.

"type": "object",
"description": "A map of additional properties for the user definition, where the key is the property name and the value is the property schema",
"propertyNames": {
"pattern": "^[^.]+$",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

On the "to be fixed later" note: the escape-hatch list is a bit wider than $defs/allOf/items — since UserProperty keeps top-level additionalProperties: true and embeds the full 2020-12 meta-schema, patternProperties, additionalProperties-as-schema, and oneOf branches are the same class. When picking it up: the textbook mechanism is a $dynamicAnchor: meta dialect extension, which makes the constraint recursive across every subschema position in one move; an imperative walk at flow-definition validation time may end up simpler.

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.

bug(flow-engine): nested user-schema fields are unusable

3 participants