Skip to content

feat: implement opencert verify#125

Merged
rongquan1 merged 8 commits intomainfrom
feat/opencert-verification
Feb 6, 2026
Merged

feat: implement opencert verify#125
rongquan1 merged 8 commits intomainfrom
feat/opencert-verification

Conversation

@pennhan-dex
Copy link
Copy Markdown
Contributor

@pennhan-dex pennhan-dex commented Jan 30, 2026

Summary

Implement support for openCert verification

Changes

Implemented registryVerifier from openCert
Added registryVerifier to list of verifiers for OpenAttestation
Unit Tests

Summary by CodeRabbit

  • New Features

    • Added OpenCert registry verification and public OpenCert utilities, integrated into the verification pipeline.
  • Tests

    • Added extensive OpenCert test coverage for V2/V3 registry scenarios, RPC/network variants, signature tampering cases, and validation edge cases.
  • Documentation

    • Updated verification docs to include OpenCert verifiable documents and refreshed verification flow description.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 30, 2026

📝 Walkthrough

Walkthrough

Adds an OpenCerts registry verifier, exposes the open-cert module via barrel exports, integrates the registry verifier into the verification pipeline, expands fixtures with OPENCERT_VERIFIABLE_DOCUMENT_V2_0, and adds comprehensive OpenCert tests and README/JSDoc references. (49 words)

Changes

Cohort / File(s) Summary
OpenCerts Registry Verifier
src/open-cert/verify.ts
New verifier implementing registry types/schemas, test/skip/verify flows for V2/V3 shapes, error codes, helpers (isValidOpenCert, getOpencertsRegistryVerifierFragment), and verifyOpenCertSignature builder.
Public API / Barrel Exports
src/index.ts, src/open-cert/index.ts
Added export * from './open-cert' and export * from './verify' to expose open-cert public surface.
Verifier Integration
src/verify/verify.ts
Appended registryVerifier to the openAttestationVerifiers array, extending the verification pipeline.
Tests & Fixtures
src/__tests__/open-cert/verify.test.ts, src/__tests__/core/verify.test.ts, src/__tests__/fixtures/fixtures.ts
Added OPENCERT_VERIFIABLE_DOCUMENT_V2_0 fixture and extensive OpenCert tests: registry verifier snapshots (SKIPPED/VALID/INVALID), signature tampering matrix, DID/DNS integrations, and added fixture exports/imports.
Docs / JSDoc
src/core/verify.ts, README.md
JSDoc and README updated to explicitly include OpenCert verifiable documents among supported document types.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant Pipeline as Verification Pipeline
    participant RegistryVerifier as OpencertsRegistryVerifier
    participant Registry as External Registry (HTTP)

    Client->>Pipeline: submit document (V2 / V3 / OpenCert)
    Pipeline->>RegistryVerifier: test(document)
    RegistryVerifier-->>Pipeline: return SKIPPED if issuer store info missing
    alt registry applicable
      RegistryVerifier->>Registry: fetch registry JSON (RPC/URL)
      Registry-->>RegistryVerifier: registry data or error
      RegistryVerifier-->>Pipeline: return fragment(s) (VALID / INVALID) with data/reason
    end
    Pipeline-->>Client: aggregated verification result
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • rongquan1
  • Moiz47

Poem

🐰 I hop through registries, nibble each line,
V2 or V3, I follow the sign.
I mark SKIPPED, VALID, or flag the glitch,
A twitch, a hop — I fetch every switch.
Hooray for verifications done just fine!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: implement opencert verify' clearly and concisely describes the main change—implementing OpenCert verification support—which aligns with the primary objective of adding a registryVerifier and support for OpenCert documents.
Description check ✅ Passed The description provides all required sections (Summary, Changes, Issues) and adequately covers the main changes: implementing registryVerifier, integrating it into OpenAttestation verifiers, and adding unit tests. While the description is brief, it contains sufficient information to understand the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/opencert-verification

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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@src/__tests__/core/verify.test.ts`:
- Around line 945-1153: The tests call out to the live registry and snapshot
volatile issuer payloads; update the two test cases that call verifyDocument
(using OPENCERT_VERIFIABLE_DOCUMENT_V2_0) to mock the network fetch for the
registry (e.g., vi.mock('node-fetch') to return a stable registry JSON) or stub
registryVerifier.verify to return a small deterministic issuer list, and then
change assertions to only check stable fields (name, status, type) and any
minimal required values instead of the full issuer payload / snapshot; reference
verifyDocument, OpencertsRegistryVerifier, registryVerifier.verify, node-fetch
and OPENCERT_VERIFIABLE_DOCUMENT_V2_0 when locating code to modify.

In `@src/__tests__/open-cert/verify.test.ts`:
- Around line 11-27: The test calls registryVerifier.verify (and
registryVerifier.test) which performs a live fetch of the OpenCert registry;
replace that network dependency by mocking node-fetch (or the fetch wrapper used
by src/open-cert/verify.ts) in this test: stub the fetch response to return a
local fixture JSON matching the expected registry format, ensure the mock is
applied before calling registryVerifier.verify and restored after the test, and
update the test to import/use the fixture so the assertions on
fragment.type/name/status remain the same.

In `@src/open-cert/verify.ts`:
- Around line 1-11: The Runtypes imports Boolean and String shadow JS globals
and must be aliased; change the imports to alias them (e.g., Boolean as RBoolean
and String as RString, similar to Array as RunTypesArray) and update every usage
in this module (types, Record/Union/Optional calls, Static<> references, etc.)
to use the new aliases (RBoolean, RString) so no global names are
shadowed—ensure RunTypesArray remains unchanged and only the Boolean and String
identifiers are renamed throughout verify.ts.
- Around line 154-158: Wrap the fetch/parse in the verify async function so
network or JSON errors are caught: use a try/catch around the
fetch('https://opencerts.io/static/registry.json') and await res.json(), check
res.ok before parsing, validate the parsed object conforms to the Registry shape
(e.g. ensure registry && Array.isArray(registry.issuers)), and on any failure
throw a CodedError constructed with OpencertsRegistryCode.UNEXPECTED_ERROR so
callers of OpencertsRegistryVerifierVerificationFragment receive a proper error
fragment; optionally use an AbortController with a short timeout to abort slow
requests.

Comment thread src/__tests__/core/verify.test.ts
Comment on lines +11 to +27
describe.concurrent('OpenCert registry verifier', () => {
it(
'given an OpenCert document (with documentStore/certificateStore), should run verifier and return fragment as return value',
{ timeout: 300000 },
async () => {
expect(registryVerifier.test(OPENCERT_VERIFIABLE_DOCUMENT_V2_0 as any, {} as any)).toBe(true);
const fragment = await registryVerifier.verify(
OPENCERT_VERIFIABLE_DOCUMENT_V2_0 as any,
{} as any,
);

// Uses real https://opencerts.io/static/registry.json
expect(fragment.type).toBe('ISSUER_IDENTITY');
expect(fragment.name).toBe('OpencertsRegistryVerifier');
expect(fragment.status).toBe('VALID');
},
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cd /tmp && find . -name "verify.test.ts" -o -name "*registry*verifier*" 2>/dev/null | head -20

Repository: TrustVC/trustvc

Length of output: 41


🏁 Script executed:

git ls-files | grep -E "(verify\.test\.ts|registry.*verifier)" | head -20

Repository: TrustVC/trustvc

Length of output: 210


🏁 Script executed:

fd "verify.test.ts"

Repository: TrustVC/trustvc

Length of output: 210


🏁 Script executed:

cat -n src/__tests__/open-cert/verify.test.ts

Repository: TrustVC/trustvc

Length of output: 11357


🏁 Script executed:

find . -name "*registryVerifier*" -o -name "*registry*" | grep -E "\.(ts|js)$" | head -20

Repository: TrustVC/trustvc

Length of output: 41


🏁 Script executed:

rg "registryVerifier\s*=" --type ts --type js -A 5 | head -50

Repository: TrustVC/trustvc

Length of output: 41


🏁 Script executed:

fd -e ts -e js | xargs grep -l "registryVerifier" | grep -v test | head -10

Repository: TrustVC/trustvc

Length of output: 103


🏁 Script executed:

rg "export.*registryVerifier" --type ts --type js

Repository: TrustVC/trustvc

Length of output: 130


🏁 Script executed:

cat -n src/open-cert/verify.ts

Repository: TrustVC/trustvc

Length of output: 9926


Mock the registry in this unit test to avoid live dependencies.

The test directly calls registryVerifier.verify(), which makes an HTTP request to https://opencerts.io/static/registry.json (line 155 in src/open-cert/verify.ts). This creates a flaky test that will fail if the registry is unreachable or changes, and the 300000ms timeout confirms network latency is expected. Mock node-fetch with a fixture so the test is deterministic and runs quickly.

🧪 Example: mock `node-fetch` with a local fixture
 import { verifySignature } from '@tradetrust-tt/tradetrust';
 import { cloneDeep } from 'lodash';
-import { describe, expect, it } from 'vitest';
+import { describe, expect, it, vi } from 'vitest';
 import { isValidOpenCert, registryVerifier } from '../..';
 import { OPENCERT_VERIFIABLE_DOCUMENT_V2_0 } from '../fixtures/fixtures';

+const REGISTRY_FIXTURE = {
+  issuers: {
+    '0xCFa2B7Fc3FdD5CA55715581e34420268CCcd3039': {
+      name: 'Singapore Management University',
+      displayCard: true,
+    },
+  },
+} as const;
+
+vi.mock('node-fetch', () => ({
+  default: vi.fn().mockResolvedValue({
+    ok: true,
+    json: async () => REGISTRY_FIXTURE,
+  }),
+}));
🤖 Prompt for AI Agents
In `@src/__tests__/open-cert/verify.test.ts` around lines 11 - 27, The test calls
registryVerifier.verify (and registryVerifier.test) which performs a live fetch
of the OpenCert registry; replace that network dependency by mocking node-fetch
(or the fetch wrapper used by src/open-cert/verify.ts) in this test: stub the
fetch response to return a local fixture JSON matching the expected registry
format, ensure the mock is applied before calling registryVerifier.verify and
restored after the test, and update the test to import/use the fixture so the
assertions on fragment.type/name/status remain the same.

Comment thread src/open-cert/verify.ts
Comment on lines +1 to +11
import fetch from 'node-fetch';
import {
Array as RunTypesArray,
Boolean,
Literal,
Optional,
Record,
Static,
String,
Union,
} from 'runtypes';
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

git ls-files src/open-cert/ | head -20

Repository: TrustVC/trustvc

Length of output: 105


🏁 Script executed:

# Check if the file exists and read the imports
cat -n src/open-cert/verify.ts | head -50

Repository: TrustVC/trustvc

Length of output: 1454


🏁 Script executed:

# Look for Biome configuration files
find . -name "biome.json" -o -name ".biomerc*" -o -name "biome.toml" | head -10

Repository: TrustVC/trustvc

Length of output: 71


🏁 Script executed:

# Search for Biome configuration in common locations
ls -la | grep -E "biome|eslint"

Repository: TrustVC/trustvc

Length of output: 190


🏁 Script executed:

cat biome.json

Repository: TrustVC/trustvc

Length of output: 1834


🏁 Script executed:

# Read the complete verify.ts file to see all usages
cat -n src/open-cert/verify.ts

Repository: TrustVC/trustvc

Length of output: 9926


🏁 Script executed:

# Check if index.ts or other files import from verify.ts
rg "from.*verify" src/open-cert/

Repository: TrustVC/trustvc

Length of output: 166


🏁 Script executed:

# Also check if Boolean or String are re-exported from verify.ts
rg "export.*Boolean|export.*String" src/open-cert/verify.ts

Repository: TrustVC/trustvc

Length of output: 41


Alias Runtypes Boolean and String imports to satisfy Biome's noShadowRestrictedNames rule.

These imports shadow JavaScript global built-ins and will trigger a lint error. Apply the following changes:

Fix aliasing and update all usages
 import {
   Array as RunTypesArray,
-  Boolean,
+  Boolean as RtBoolean,
   Literal,
   Optional,
   Record,
   Static,
-  String,
+  String as RtString,
   Union,
 } from 'runtypes';

 export const RegistryEntry = Record({
-  name: String,
-  displayCard: Boolean,
-  website: Optional(String),
-  email: Optional(String),
-  phone: Optional(String),
-  logo: Optional(String),
-  id: Optional(String),
+  name: RtString,
+  displayCard: RtBoolean,
+  website: Optional(RtString),
+  email: Optional(RtString),
+  phone: Optional(RtString),
+  logo: Optional(RtString),
+  id: Optional(RtString),
 });

 export const OpencertsRegistryVerificationValidData = RegistryEntry.And(
   Record({
-    value: String,
+    value: RtString,
     status: Literal('VALID'),
   }),
 );

 export const OpencertsRegistryVerificationInvalidData = Record({
-  value: String,
+  value: RtString,
   status: Literal('INVALID'),
   reason: Reason,
 });
🧰 Tools
🪛 Biome (2.3.13)

[error] 4-4: Do not shadow the global "Boolean" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)


[error] 9-9: Do not shadow the global "String" property.

Consider renaming this variable. It's easy to confuse the origin of variables when they're named after a known global.

(lint/suspicious/noShadowRestrictedNames)

🤖 Prompt for AI Agents
In `@src/open-cert/verify.ts` around lines 1 - 11, The Runtypes imports Boolean
and String shadow JS globals and must be aliased; change the imports to alias
them (e.g., Boolean as RBoolean and String as RString, similar to Array as
RunTypesArray) and update every usage in this module (types,
Record/Union/Optional calls, Static<> references, etc.) to use the new aliases
(RBoolean, RString) so no global names are shadowed—ensure RunTypesArray remains
unchanged and only the Boolean and String identifiers are renamed throughout
verify.ts.

Comment thread src/open-cert/verify.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@README.md`:
- Line 303: The README sentence about TrustVC's verification is grammatically
broken (missing a closing parenthesis) and awkwardly worded; update the
Verifying description to close the parenthesis and rephrase to clearly state
that TrustVC supports W3C Verifiable Credentials (VCs), OpenAttestation
Verifiable Documents (VDs) and OpenCert Verifiable Documents, and that for
ECDSA-SD-2023 and BBS-2023 signed documents the verifyDocument function will
automatically derive (if needed) and verify in a single step—refer to TrustVC
and verifyDocument when editing.
- Line 5: Replace the incorrect product name "OpenCert" with the official
branding "OpenCerts" in the README; search for occurrences of "OpenCert" (e.g.,
the sentence mentioning OpenCert for verification and any other mentions) and
update them to "OpenCerts" to match the project identifiers like
OpencertsRegistryVerifier and the upstream site opencerts.io.

Comment thread README.md Outdated
## About

TrustVC is a comprehensive wrapper library designed to simplify the signing and verification processes for TrustVC W3C [Verifiable Credentials (VC)](https://github.com/TrustVC/w3c) and OpenAttestation Verifiable Documents (VD), adhering to the W3C [VC](https://www.w3.org/TR/vc-data-model/) Data Model v2.0 (W3C Standard). It ensures compatibility and interoperability for Verifiable Credentials while supporting OpenAttestation [Verifiable Documents (VD)](https://github.com/Open-Attestation/open-attestation) v6.9.5. TrustVC seamlessly integrates functionalities for handling W3C Verifiable Credentials and OpenAttestation Verifiable Documents, leveraging existing TradeTrust libraries and smart contracts for [Token Registry](https://github.com/TradeTrust/token-registry) (V4 and V5). Additionally, it includes essential utility functions for strings, networks, and chains, making it a versatile tool for developers working with decentralized identity and verifiable data solutions.
TrustVC is a comprehensive wrapper library designed to simplify the signing and verification processes for TrustVC W3C [Verifiable Credentials (VC)](https://github.com/TrustVC/w3c) and OpenAttestation Verifiable Documents (VD), including OpenCert for verification, adhering to the W3C [VC](https://www.w3.org/TR/vc-data-model/) Data Model v2.0 (W3C Standard). It ensures compatibility and interoperability for Verifiable Credentials while supporting OpenAttestation [Verifiable Documents (VD)](https://github.com/Open-Attestation/open-attestation) v6.9.5. TrustVC seamlessly integrates functionalities for handling W3C Verifiable Credentials and OpenAttestation Verifiable Documents, leveraging existing TradeTrust libraries and smart contracts for [Token Registry](https://github.com/TradeTrust/token-registry) (V4 and V5). Additionally, it includes essential utility functions for strings, networks, and chains, making it a versatile tool for developers working with decentralized identity and verifiable data solutions.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Jan 30, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's check the README.md file at the specified lines
head -20 README.md | tail -16

Repository: TrustVC/trustvc

Length of output: 1664


🏁 Script executed:

# Check line 303 as well
sed -n '300,310p' README.md

Repository: TrustVC/trustvc

Length of output: 829


🏁 Script executed:

# Search for all occurrences of "OpenCert" (with or without 's')
rg "OpenCert" --ignore-case

Repository: TrustVC/trustvc

Length of output: 9106


🏁 Script executed:

# Check for references to OpenCerts GitHub or official sources
rg "github.com.*[Oo]pen[Cc]ert" -A 2 -B 2

Repository: TrustVC/trustvc

Length of output: 1163


Use "OpenCerts" (with 's') instead of "OpenCert" to match official branding.

The official product name is "OpenCerts" (evidenced by https://opencerts.io and consistent code identifiers like OpencertsRegistryVerifier). Update lines 5 and 303 in README.md to use "OpenCerts" for consistency with the official branding and codebase.

🤖 Prompt for AI Agents
In `@README.md` at line 5, Replace the incorrect product name "OpenCert" with the
official branding "OpenCerts" in the README; search for occurrences of
"OpenCert" (e.g., the sentence mentioning OpenCert for verification and any
other mentions) and update them to "OpenCerts" to match the project identifiers
like OpencertsRegistryVerifier and the upstream site opencerts.io.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ignored

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pennhan-dex, understood! I've noted your decision to keep the current naming convention.

Comment thread README.md Outdated
@pennhan-dex pennhan-dex requested a review from rongquan1 February 2, 2026 07:32
@sonarqubecloud
Copy link
Copy Markdown

sonarqubecloud Bot commented Feb 6, 2026

Quality Gate Failed Quality Gate failed

Failed conditions
5.1% Duplication on New Code (required ≤ 3%)

See analysis details on SonarQube Cloud

@rongquan1 rongquan1 merged commit 6885892 into main Feb 6, 2026
20 of 21 checks passed
@rongquan1 rongquan1 deleted the feat/opencert-verification branch February 6, 2026 04:37
nghaninn pushed a commit that referenced this pull request Feb 6, 2026
## [2.6.0](v2.5.2...v2.6.0) (2026-02-06)

### Features

* implement opencert verify ([#125](#125)) ([6885892](6885892))
@tradetrustimda
Copy link
Copy Markdown

🎉 This PR is included in version 2.6.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants