fix: keep conditional rules on branches that carry a title - #74
Open
vishkaty wants to merge 1 commit into
Open
Conversation
`EcKeysCarryCrvXYSchema`, the published signing key type, accepted
`{ kid, kty: "EC" }` with no curve and no coordinates, and the OKP equivalent.
profile.json states both as conditional branches on jwk_public_key.
Two things in the recorder combined to drop them.
`describeConditionalRule` rejected any branch carrying a key other than `if`
or `then`. Every jwk_public_key branch carries a `title`, so all five were
judged unmodellable even though two are plain `required` consequences the
recorder already knows how to express. Annotation keywords assert nothing, so
they are now ignored when the branch shape is checked.
`recordConditionalRules` then discarded the whole rule list when any branch was
unmodellable, which would still have dropped the two expressible branches
because the three that pair a curve with an algorithm use a `properties`
consequence the recorder does not model. Unmodellable branches are now skipped
individually. Every `if`/`then` only adds constraints, so keeping the
expressible subset can only enforce more, never reject something the schema
permits.
Still not enforced, and out of scope here: the three curve to algorithm
pairings, because their consequence shape is not modelled. A P-256 key
declaring ES384 is accepted as before.
Testing. Four cases, of which two fail before this change and pass after;
reverting either half alone reproduces the two failures. Suite 151 passed, from
147. Regeneration against release/2026-08-25 is idempotent and the exported
name set is unchanged. Only `EcKeysCarryCrvXYSchema` changes, one hunk. All
seven JSON Web Keys the specification publishes, and the profile response
scaffold, still parse, so the regression surface is empty.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Observed
EcKeysCarryCrvXYSchema, the type for a published signing key, accepts a keythat declares an elliptic curve type and carries neither a curve nor
coordinates:
profile.jsonstates both obligations as conditional branches onjwk_public_key, and a standards validator rejects both inputs, reporting that crv is a required property.Root cause
Two things combined, and both are needed to reach the bug.
describeConditionalRulerejected any branch carrying a key other thanifor
then. Everyjwk_public_keybranch carries atitle, for example"EC keys carry crv, x, y", so all five were judged unmodellable even though two
of them are plain
requiredconsequences the recorder already expresses.Annotation keywords assert nothing, so they are now ignored when the branch
shape is checked.
recordConditionalRulesthen emptied the whole rule list whenever any branchwas unmodellable. That alone would still have dropped the two expressible
branches, because the other three pair a curve with an algorithm through a
propertiesconsequence the recorder does not model. Unmodellable branchesare now skipped individually rather than taking the list down with them. Every
if/thenonly adds constraints, so keeping the expressible subset canonly enforce more, never reject something the schema permits.
Still not enforced, deliberately
The three curve to algorithm pairings. Their consequence shape is not modelled,
so a P-256 key declaring ES384 is accepted exactly as before. Widening the
consequence handler is a larger change and I did not want to bundle it.
Testing
Four cases in a new
tests/profile-key-conditionals.test.js. Two fail beforethis change and pass after, and reverting either half alone reproduces
those two failures, so both parts are load bearing. The other two are controls:
an unrelated key type carries neither obligation, and the members the base
schema already requires still hold.
Suite 151 passed, from 147. Regeneration against
release/2026-08-25isidempotent, and the exported name set is identical to main. Only
EcKeysCarryCrvXYSchemachanges, one hunk.Regression surface checked rather than assumed: all seven JSON Web Keys the
specification publishes across its documentation and the profile response
scaffold still parse.
Workflow runs on fork pull requests are held behind the approval gate, so I ran
them on my fork for this exact commit. Tests and Lint both green:
Relationship to #73
Independent. #73 changes
project-current-ucp-schemas.mjsand the discoveryprofile shape; this changes
inject-schema-constraints.mjsand the conditionalrecorder. Different files, different defect class, no textual overlap. Happy to
sequence them in whichever order suits.