Skip to content

fix(schema): make hoisted component names JSON-Pointer safe and hash strictly - #383

Merged
yeongseon merged 3 commits into
mainfrom
fix/379-jsonpointer-safe-hoisted-names
Aug 10, 2026
Merged

fix(schema): make hoisted component names JSON-Pointer safe and hash strictly#383
yeongseon merged 3 commits into
mainfrom
fix/379-jsonpointer-safe-hoisted-names

Conversation

@yeongseon

Copy link
Copy Markdown
Owner

Summary

  • Sanitize hoisted component names so / and ~ never leak into #/components/schemas/{name} refs (JSON-Pointer safe), using _sanitize_component_name.
  • Make _schema_short_hash strict: serialize with json.dumps(schema, sort_keys=True, separators=(",", ":")) and drop the default=str fallback so non-JSON-serializable schemas raise TypeError instead of silently producing unstable hashes.

Acceptance

  • Titles containing / or ~ are sanitized (e.g. Order/Item -> Order_Item).
  • Sanitized-name collisions get a distinct alias.
  • Non-JSON-serializable schema raises TypeError.
  • make check-all green (coverage >= 95%).

Closes #379

@yeongseon

Copy link
Copy Markdown
Owner Author

Scope widened after review (please re-review)

The original commit sanitized only inside _flat_schema_name, which fixed only the opt-in flat path. Review reproduction showed the JSON-Pointer bug also affects the default $defs path (hoist_flat=False):

hoist_inline_defs({"$defs": {"Order/Item": {...}}, "properties": {"x": {"$ref": "#/$defs/Order/Item"}}}, {})
# before: component key 'Order/Item', ref '#/components/schemas/Order/Item' (unresolvable)

New commit moves sanitization to _resolve_name_collision (the shared entry for $defs, model, and flat paths) and adds a default-$defs-path regression test. make check-all green.

This PR now closes #379 (JSON-Pointer safety, all paths) and #385 (strict _schema_short_hash, split out from the original issue B). GitHub's gh pr edit is currently failing on this repo due to the Projects-classic deprecation, so the header still shows the old body — the authoritative Closes list is here: Closes #379, Closes #385.

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.

Pull request overview

This PR hardens schema hoisting so generated #/components/schemas/{name} references remain JSON-Pointer safe (no raw / or ~ in component names), and makes anonymous-schema hashing deterministic by requiring strict JSON serialization.

Changes:

  • Sanitize hoisted component names centrally in _resolve_name_collision() to prevent JSON-Pointer breakage across hoisting paths.
  • Make _schema_short_hash() strict (no default=str, canonical separators) so non-JSON-serializable schemas raise TypeError.
  • Add regression tests for / and ~ sanitization, sanitized-name collisions, strict-hash failures, and the default $defs hoisting path.

Reviewed changes

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

File Description
src/azure_functions_openapi/utils.py Adds centralized component-name sanitization and strict canonical hashing for anonymous schema naming.
tests/test_hoist_flat.py Adds tests validating JSON-Pointer-safe component names, collision aliasing, strict hashing behavior, and default $defs path sanitization.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/azure_functions_openapi/utils.py Outdated
Comment on lines +72 to +75
# Sanitize first so JSON-Pointer-unsafe characters (``/``, ``~``) can never
# reach a ``#/components/schemas/<name>`` reference, regardless of which
# hoisting path (``$defs``, model class, or flat schema) supplied the name.
name = _sanitize_component_name(name)
@yeongseon

Copy link
Copy Markdown
Owner Author

Addressed Copilot review: removed the unreachable duplicate return name in _resolve_name_collision, and added test_model_path_sanitizes_name_and_rewrites_ref exercising the model_to_schema path with a /-bearing model name (created via pydantic.create_model) to confirm the root $ref is rewritten to the sanitized component key. make check-all green.

Delete the unreachable duplicate 'return name' in _resolve_name_collision
and add a regression test asserting the model hoisting path (model_to_schema)
sanitizes a '/'-bearing model name and rewrites the root $ref to the
resolvable component key.
@yeongseon
yeongseon force-pushed the fix/379-jsonpointer-safe-hoisted-names branch from ac7a90a to 4171935 Compare August 10, 2026 11:05
@yeongseon
yeongseon merged commit c4e80ac into main Aug 10, 2026
@yeongseon
yeongseon deleted the fix/379-jsonpointer-safe-hoisted-names branch August 10, 2026 11:05
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.

fix(schema): make hoisted component names JSON-Pointer safe and hash strictly

3 participants