Fix $ref resolution when a schema is referenced by SAID alone - #12
Merged
Conversation
A schema can reference another schema by putting its SAID in a $ref value (e.g. one schema extending another via allOf). CacheResolver. resolver() only resolved "did:"-scheme $ref URIs; a $ref that was just the SAID by itself, with no "did:" prefix, always came back Unresolvable, even when the referenced schema was already cached in db.schema. Build the jsonschema resolver's store from db.schema so these SAID-only refs resolve locally too. Separately, Credentialer.validate() and Verifier.processCredential() never passed a resolver into Schemer at all, so no $ref-based schema could validate through either the issuance or the verification path. Schemer.__init__ now accepts an optional resolver argument and passes it through _inhale/_sniff (raw-based construction always re-detects typ, which was silently discarding any resolver passed in before), and both call sites now pass their existing CacheResolver in. Signed-off-by: arshdeep singh <arsh.binny@gmail.com>
There was a problem hiding this comment.
Pull request overview
This PR fixes JSON Schema $ref validation across the credential issuance and verification paths by (1) enabling resolution of bare-SAID $ref values from the local schema cache and (2) ensuring a CacheResolver is actually provided to schema validation so referenced schemas can be resolved during Schemer.verify().
Changes:
- Build the jsonschema resolver
storefromdb.schemaso$ref: "<SAID>"(nodid:prefix) resolves locally. - Thread an optional
resolverthroughSchemerconstruction from raw bytes and pass it fromCredentialer.validate()andVerifier.processCredential(). - Add tests covering chained bare-SAID
$refresolution, transitive enforcement, and fail-closed behavior when refs are unresolvable.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
src/keri/core/scheming.py |
Extends CacheResolver.resolver() to support bare-SAID $ref via a store; threads resolver through raw-based Schemer type detection. |
src/keri/vdr/verifying.py |
Passes the verifier’s CacheResolver into Schemer so $ref chains validate on the verification path. |
src/keri/vdr/credentialing.py |
Passes the verifier’s CacheResolver into Schemer so $ref chains validate on the issuance path. |
tests/core/test_scheming.py |
Adds unit tests for bare-SAID $ref resolution, transitive chaining, and fail-closed behavior. |
tests/vdr/test_credentialing.py |
Adds end-to-end issuance-path tests proving chained schema enforcement and unresolvable-ref failure. |
tests/vdr/test_verifying.py |
Adds end-to-end verification-path tests for chained schemas and enforcement of inherited requirements. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
CacheResolver.resolver() rebuilt its jsonschema store from every schema in db.schema on every single call. Since JSONSchema.verify_json calls this once per credential schema check, that meant re-reading and re-parsing the entire local schema cache on every credential validation, growing with however many schemas a Habery has ever cached. Cache the built store and only rebuild it when db.schema.cntAll() changes. db.schema entries are keyed by their own content SAID and are never removed, so that count can only change when a schema is added, making it an exact signal for when the store actually needs rebuilding. Signed-off-by: arshdeep singh <arsh.binny@gmail.com>
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.
A schema can reference another schema by putting its SAID in a $ref value (e.g. one schema extending another via allOf). CacheResolver. resolver() only resolved "did:"-scheme $ref URIs; a $ref that was just the SAID by itself, with no "did:" prefix, always came back Unresolvable, even when the referenced schema was already cached in db.schema. Build the jsonschema resolver's store from db.schema so these SAID-only refs resolve locally too.
Separately, Credentialer.validate() and Verifier.processCredential() never passed a resolver into Schemer at all, so no $ref-based schema could validate through either the issuance or the verification path. Schemer.init now accepts an optional resolver argument and passes it through _inhale/_sniff (raw-based construction always re-detects typ, which was silently discarding any resolver passed in before), and both call sites now pass their existing CacheResolver in.