Skip to content

fix v5 validation#52

Open
alexcos20 wants to merge 2 commits into
mainfrom
bug/fix_ddo_v5
Open

fix v5 validation#52
alexcos20 wants to merge 2 commits into
mainfrom
bug/fix_ddo_v5

Conversation

@alexcos20

@alexcos20 alexcos20 commented Jul 21, 2026

Copy link
Copy Markdown
Member

Closes #51

Fix v5 (enterprise / VerifiableCredential) DDO validation

Summary

validateDDO() did not properly validate v5 "enterprise" (VerifiableCredential)
DDOs. Well-formed v5 DDOs could pass without SHACL ever producing useful output,
malformed ones surfaced opaque errors instead of naming the offending field, and
an empty/absent address field crashed validation with a raw ethers TypeError.

This PR makes v5 validation produce a real, per-field SHACL report, hardens the
validators against thrown errors, and adds regression tests. v4 / deprecated
behavior is unchanged and all existing tests still pass.

What was wrong

  1. No per-field violations for v5. The v5 payload lives under
    credentialSubject, so rdf-validate-shacl reports nested failures as a
    generic "Value does not have shape …CredentialSubjectShape" on the parent
    path, hiding the actual failing field under result.detail. The old code only
    read the top-level results, so a bad nested field produced an unactionable
    message.

  2. Raw TypeError on bad address. makeDid() calls ethers getAddress().
    When nftAddress was empty/absent, getAddress() threw
    TypeError: invalid address. The existing try/catch only wrapped a separate
    getAddress call, not the one inside makeDid, so the throw escaped and was
    returned as a messy general error.

  3. Vacuous-pass / "Output is null or invalid" risk. If JSON-LD expansion ever
    dropped the Ocean vocabulary (e.g. an unmapped @context), toRDF yields a
    near-empty graph. SHACL then finds no target nodes and "conforms" vacuously,
    meaning a broken DDO could validate as true; the failure path also emitted the
    unhelpful "Output is null or invalid" string.

What changed

src/services/ddoManager.ts

  • runShaclValidation (base class)
    • Replaced the "Output is null or invalid" branch with a meaningful
      general error describing the RDF conversion failure.
    • Added a data.size === 0 guard: a near-empty/vacuous graph is now a hard
      validation failure instead of a silent pass.
  • New collectShaclViolations helper (base class) — recursively walks
    result.detail so errors are keyed by the real failing field (e.g. name,
    timeout) with the concrete SHACL message. Shared by both v4 and v5.
  • makeDid throw-guard (V4 + V5) — the DID is only derived when nftAddress
    is a valid address and chainId is present, wrapped in try/catch. Bad
    inputs now yield a clean field-level error instead of a thrown TypeError.
  • V5DDO.validate — guards a missing/invalid credentialSubject, keeps the
    @vocab context aligned with the shape's
    <https://www.w3.org/ns/credentials/v2/> namespace (documented), and routes
    violations through the recursive collector.

src/test/data/ddo.ts

  • Added validEnterpriseDDOV5: an immutable deep clone of the valid v5 fixture,
    captured at module-eval time so other suites' in-place mutations
    (updateFields) cannot corrupt the validation baseline.

src/test/unit/validation.test.ts

New regression tests:

  • valid v5 enterprise DDO → valid, expands into a full RDF graph (not vacuous);
  • v5 DDO missing a nested required field (metadata.name) → invalid with a
    specific per-field error (name), never "Output is null or invalid";
  • empty nftAddress → clean nftAddress error, no raw invalid address throw;
  • absent nftAddress → same clean field-level error.

Design note

Validation targets the whole VC envelope (the shape targets
VerifiableCredential and cascades into credentialSubject via sh:node), so
that model was kept rather than validating credentialSubject in isolation.

The if (report.conforms) return [true, {}] gate was intentionally preserved:
existing suites mutate the shared DDOExampleV4/V5 fixtures in place, and
tightening the gate broke the valid-V4/V5 tests once their id no longer matched
the mutated nftAddress.

Testing

  • npm run test:unit29 passing (25 existing + 4 new).
  • npm run lint — no new errors (pre-existing warnings only).

Summary by CodeRabbit

  • Bug Fixes
    • Improved validation error messages for malformed or incomplete credential data.
    • Validation failures now identify the affected fields, including nested credential details and NFT addresses.
    • Prevented empty or invalid data from being treated as successfully validated.
    • Address and DID validation errors are now handled cleanly without exposing technical runtime messages.
    • Improved reporting for data conversion failures with clearer general error messages.

@alexcos20 alexcos20 self-assigned this Jul 21, 2026
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@alexcos20, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 35 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 777274e8-e995-4f35-b3db-61b69627ef67

📥 Commits

Reviewing files that changed from the base of the PR and between 2ad8d96 and 94a9b8a.

📒 Files selected for processing (1)
  • src/test/data/ddo.ts
📝 Walkthrough

Walkthrough

Validation now uses vocabulary-aware JSON-LD contexts, rejects empty RDF graphs, guards DID derivation, and maps nested SHACL violations to field-level errors. New V5 enterprise fixtures and regression tests cover valid graphs and invalid nested fields.

Changes

V5 validation error handling

Layer / File(s) Summary
RDF preparation and SHACL violation processing
src/services/ddoManager.ts
Conversion failures and empty RDF graphs produce explicit general errors; nested SHACL results are recursively mapped to deduplicated field messages.
V4 validation integration
src/services/ddoManager.ts
V4 validation uses the schema vocabulary, guards address validation and DID derivation, and delegates SHACL error mapping to the shared helper.
V5 enterprise validation and regression coverage
src/services/ddoManager.ts, src/test/data/ddo.ts, src/test/unit/validation.test.ts
V5 validates credentialSubject, uses the VC vocabulary, guards DID derivation, and tests valid graphs plus nested metadata and address errors.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant V5DDO
  participant runShaclValidation
  participant jsonld.toRDF
  participant SHACLValidator
  participant collectShaclViolations
  V5DDO->>runShaclValidation: validate vocabulary-aware DDO
  runShaclValidation->>jsonld.toRDF: convert JSON-LD to RDF
  jsonld.toRDF-->>runShaclValidation: RDF store or conversion failure
  runShaclValidation->>SHACLValidator: validate RDF graph
  SHACLValidator-->>V5DDO: SHACL results
  V5DDO->>collectShaclViolations: map nested results to field errors
Loading

Suggested reviewers: adrigeorge

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately reflects the main change: fixing v5 validation.
Linked Issues check ✅ Passed The PR addresses #51 by fixing v5 DDO validation, restoring meaningful SHACL results and field-level errors for enterprise v5 payloads.
Out of Scope Changes check ✅ Passed The changes stay focused on v5 validation, with supporting test and fixture updates and no clear unrelated additions.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bug/fix_ddo_v5

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@alexcos20 alexcos20 linked an issue Jul 21, 2026 that may be closed by this pull request
@alexcos20
alexcos20 requested a review from AdriGeorge July 21, 2026 15:33
@alexcos20

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot 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.

🧹 Nitpick comments (1)
src/test/data/ddo.ts (1)

376-381: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider freezing the fixture to actually guarantee the "immutable" contract.

The comment states this is meant as a stable baseline "other test suites" can rely on, but structuredClone alone doesn't prevent mutation — a future test that forgets to clone before mutating would silently corrupt this shared module-level fixture for every other test in the process.

♻️ Proposed defensive freeze
-export const validEnterpriseDDOV5 = structuredClone(DDOExampleV5);
+export const validEnterpriseDDOV5 = Object.freeze(
+  structuredClone(DDOExampleV5)
+);

Note: Object.freeze is shallow, so nested mutation (e.g. validEnterpriseDDOV5.credentialSubject.metadata.name = ...) would still succeed silently; a deep-freeze helper would be needed for full protection if that's a concern.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/test/data/ddo.ts` around lines 376 - 381, Protect the shared
validEnterpriseDDOV5 fixture from accidental mutation by applying the project’s
existing deep-freeze utility, or add a narrowly scoped deep-freeze
implementation if none exists. Update the fixture declaration while preserving
the structuredClone baseline and ensuring nested fields such as
credentialSubject.metadata are also immutable.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/test/data/ddo.ts`:
- Around line 376-381: Protect the shared validEnterpriseDDOV5 fixture from
accidental mutation by applying the project’s existing deep-freeze utility, or
add a narrowly scoped deep-freeze implementation if none exists. Update the
fixture declaration while preserving the structuredClone baseline and ensuring
nested fields such as credentialSubject.metadata are also immutable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c45762d5-79ba-47aa-90b8-a9e02ff88142

📥 Commits

Reviewing files that changed from the base of the PR and between da5a6ee and 2ad8d96.

📒 Files selected for processing (3)
  • src/services/ddoManager.ts
  • src/test/data/ddo.ts
  • src/test/unit/validation.test.ts

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.

v5 validation errors

1 participant