Skip to content

Fix $ref resolution when a schema is referenced by SAID alone - #12

Merged
Arsh-Sandhu merged 2 commits into
pr-mainfrom
fix/ref-schema
Aug 7, 2026
Merged

Fix $ref resolution when a schema is referenced by SAID alone#12
Arsh-Sandhu merged 2 commits into
pr-mainfrom
fix/ref-schema

Conversation

@Arsh-Sandhu

Copy link
Copy Markdown
Member

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.

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>

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 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 store from db.schema so $ref: "<SAID>" (no did: prefix) resolves locally.
  • Thread an optional resolver through Schemer construction from raw bytes and pass it from Credentialer.validate() and Verifier.processCredential().
  • Add tests covering chained bare-SAID $ref resolution, 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.

Comment thread src/keri/core/scheming.py Outdated
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>
@Arsh-Sandhu
Arsh-Sandhu merged commit 051549c into pr-main Aug 7, 2026
6 checks passed
@Arsh-Sandhu
Arsh-Sandhu deleted the fix/ref-schema branch August 7, 2026 15:06
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.

2 participants