schemagen: reject required entries with no matching properties key #65

Merged
andrew merged 1 commits from weaselbot/weaseljson:weaselbot/issue-63 into main 2026-08-31 17:44:05 +00:00
Member

Summary

schemagen silently dropped any required entry without a matching key in properties. Since additionalProperties: false is mandatory and rejects every key not listed in properties, such a schema is unsatisfiable — yet generation succeeded and the emitted parser had no seen bit for the dangling key, so documents missing it were accepted (requiredMask = { 0x0u }), contradicting the README contract ("missing required property (top-level or nested)" is rejected at parse time).

Following the pattern established by #55/#58, this rejects such schemas at generation time with a GenError — there is no correct parse-time fallback since the schema can never match any document.

Changes

  • contrib/schemagen/weaseljson_schemagen.py: in _build_object(), raise GenError when set(required) is not a subset of properties.keys(). Applies to root, nested, and $defs object schemas alike (single object build path). Message: required key 'b' has no matching properties entry (plural form when several keys are affected).
  • contrib/schemagen/README.md: list required entries with no matching properties key in the "Not supported (rejected at generation time, no fallback)" section.
  • contrib/schemagen/test_schemagen.py: new SchemagenRequiredPropertyTest covering the issue reproduction, multiple dangling keys, an object schema with required but no properties, and a nested $defs object; plus a positive control that a matching required key still generates.

Testing

  • python3 contrib/schemagen/test_schemagen.py: 28/28 pass (pre-commit black hook passes).
  • Full cmake && make && ctest: 26/26 pass, including schemagen_example, schemagen_big, schemagen_nullable_root.

Closes #63

## Summary `schemagen` silently dropped any `required` entry without a matching key in `properties`. Since `additionalProperties: false` is mandatory and rejects every key not listed in `properties`, such a schema is unsatisfiable — yet generation succeeded and the emitted parser had no seen bit for the dangling key, so documents missing it were accepted (`requiredMask` = `{ 0x0u }`), contradicting the README contract ("missing required property (top-level or nested)" is rejected at parse time). Following the pattern established by #55/#58, this rejects such schemas at generation time with a `GenError` — there is no correct parse-time fallback since the schema can never match any document. ## Changes - `contrib/schemagen/weaseljson_schemagen.py`: in `_build_object()`, raise `GenError` when `set(required)` is not a subset of `properties.keys()`. Applies to root, nested, and `$defs` object schemas alike (single object build path). Message: `required key 'b' has no matching properties entry` (plural form when several keys are affected). - `contrib/schemagen/README.md`: list `required` entries with no matching `properties` key in the "Not supported (rejected at generation time, no fallback)" section. - `contrib/schemagen/test_schemagen.py`: new `SchemagenRequiredPropertyTest` covering the issue reproduction, multiple dangling keys, an object schema with `required` but no `properties`, and a nested `$defs` object; plus a positive control that a matching required key still generates. ## Testing - `python3 contrib/schemagen/test_schemagen.py`: 28/28 pass (pre-commit `black` hook passes). - Full `cmake && make && ctest`: 26/26 pass, including `schemagen_example`, `schemagen_big`, `schemagen_nullable_root`. Closes #63
weaselbot added 1 commit 2026-08-31 01:51:39 +00:00
schemagen: reject required keys with no properties entry
CI / build (-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++, clang-arm64, ubuntu-latest-arm64, true) (pull_request) Successful in 58s
CI / pre-commit (pull_request) Successful in 59s
CI / build (-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++, gcc-arm64, ubuntu-latest-arm64, false) (pull_request) Successful in 51s
CI / build (-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++, clang-amd64, ubuntu-latest-amd64, true) (pull_request) Successful in 1m48s
CI / build (-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++, gcc-amd64, ubuntu-latest-amd64, false) (pull_request) Successful in 1m42s
fd34603ac0
A `required` entry without a matching `properties` key made the schema
unsatisfiable: additionalProperties: false (the only supported object
mode) rejects any key not listed in `properties`, so the required key
can never be present. Since no seen bit is emitted for such keys, the
generated parser silently accepted every document instead of rejecting
them as the README contract requires ("missing required property").

Follow the pattern from issue #55 and raise GenError at generation time
when set(required) is not a subset of properties.keys(), for root,
nested, and $defs object schemas alike. Update the README's
not-supported list accordingly.

Closes #63
andrew merged commit 730a4cd0f6 into main 2026-08-31 17:44:05 +00:00
andrew deleted branch weaselbot/issue-63 2026-08-31 17:44:06 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: weaselab/weaseljson#65