Skip to content

feat: frontend for Trust Service#934

Merged
coodos merged 2 commits intomainfrom
feat/trust-service-frontend
Mar 28, 2026
Merged

feat: frontend for Trust Service#934
coodos merged 2 commits intomainfrom
feat/trust-service-frontend

Conversation

@coodos
Copy link
Copy Markdown
Contributor

@coodos coodos commented Mar 28, 2026

Description of change

Issue Number

Type of change

  • Breaking (any change that would cause existing functionality to not work as expected)
  • New (a change which implements a new feature)
  • Update (a change which updates existing functionality)
  • Fix (a change which fixes an issue)
  • Docs (changes to the documentation)
  • Chore (refactoring, build scripts or anything else that isn't user-facing)

How the change has been tested

Change checklist

  • I have ensured that the CI Checks pass locally
  • I have removed any unnecessary logic
  • My code is well documented
  • I have signed my commits
  • My code follows the pattern of the application
  • I have self reviewed my code

Summary by CodeRabbit

  • New Features

    • Added Trust Score Tester UI for configuring registry URLs and retrieving trust scores with detailed breakdowns.
    • Implemented a configuration endpoint to dynamically set the registry URL.
    • Integrated real eVault backend for trust score calculations.
  • Tests

    • Expanded test coverage with comprehensive mocking scenarios.
  • Chores

    • Added dependencies: axios, graphql, graphql-request.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 28, 2026

📝 Walkthrough

Walkthrough

This pull request integrates real eVault backend functionality into the trust-score service, replacing mocked implementations with actual registry resolution, platform token retrieval, and GraphQL queries. It adds comprehensive test coverage, a configuration endpoint, and a static test UI.

Changes

Cohort / File(s) Summary
Schema Update
services/ontology/schemas/reference.json
Updated schemaId identifier from 7e94fada-581d-49b0-b6f5-1fe0766da360 to c20e9437-02a4-4917-8cee-de35dabbdb6a.
Dependencies
services/trust-score/package.json
Added runtime dependencies: axios (^1.13.6), graphql (^16.13.1), and graphql-request (^7.4.0) for eVault integration and GraphQL operations.
Service Implementation
services/trust-score/src/userDataService.js
Replaced mocked implementations with real eVault-backed flow: added registry resolution, platform token caching, GraphQL binding document fetching, and derived verification status, account age, key location, and social connections from actual document data.
API and Middleware
services/trust-score/src/index.js
Added static file serving from src/public, new POST /config endpoint for registry URL configuration, and updated imports to include setRegistryUrl.
Test Coverage
services/trust-score/src/__tests__/userDataService.test.js
Significantly expanded test suite with full axios mocking, end-to-end GraphQL binding document simulations, and comprehensive assertions for all data extraction functions including normalization, verification status, account age, key location, and connection counting.
Test UI
services/trust-score/src/public/index.html
New static HTML page providing interactive "Trust Score Tester" UI with registry configuration, eName lookup, score calculation, formatted breakdown display, and raw JSON response viewer.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API as Express API
    participant Config as Config Manager
    participant Registry as Registry Service
    participant eVault as eVault/GraphQL
    
    Client->>API: POST /config<br/>{registryUrl}
    API->>Config: setRegistryUrl(url)
    Config->>Config: Store registry URL
    API-->>Client: {ok: true, registryUrl}
    
    Client->>API: GET /trust-score/{eName}
    API->>Config: Retrieve stored registryUrl
    API->>Registry: Resolve eName to eVault URL
    Registry-->>API: eVault URL
    API->>eVault: Fetch platform token<br/>(with cached token)
    eVault-->>API: Bearer token
    API->>eVault: POST GraphQL query<br/>fetchBindingDocuments
    eVault-->>API: Binding documents array
    API->>API: Extract verification status,<br/>account age, key location,<br/>social connections
    API-->>Client: {score, verified, age, location, connections}
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested labels

evault-refactor

Suggested reviewers

  • sosweetham

Poem

🐰 A rabbit hops through vaults of trust,
Where binding documents gather dust,
GraphQL whispers secrets neat,
Registry paths and tokens sweet—
From mocks to real, the journey's true!

🚥 Pre-merge checks | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The title 'feat: frontend for Trust Service' is partially related to the changeset but not fully accurate. The PR includes substantial backend changes (userDataService.js, package.json, reference.json, and index.js) alongside the frontend. Consider a more accurate title like 'feat: Trust Service with eVault integration and test UI' or 'feat: add Trust Service implementation with frontend.'
Description check ⚠️ Warning The PR description is entirely unfilled—only the template structure remains with no actual implementation details, issue reference, testing approach, or checklist completion. Complete the description by filling all sections: add the issue number, select the change type (likely 'New'), describe how changes were tested, and check off completed items from the checklist.
Docstring Coverage ⚠️ Warning Docstring coverage is 78.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/trust-service-frontend

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.

@coodos coodos force-pushed the feat/trust-service-frontend branch from a73935e to f1c5981 Compare March 28, 2026 14:13
@coodos coodos marked this pull request as ready for review March 28, 2026 14:13
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

🧹 Nitpick comments (1)
services/trust-score/package.json (1)

16-20: Remove unused GraphQL dependencies from package.json.

The dependencies graphql and graphql-request are not imported anywhere in the service. The implementation sends raw GraphQL payloads through axios and these packages are not used elsewhere in services/trust-score. Remove both to reduce the runtime surface.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/trust-score/package.json` around lines 16 - 20, Remove the unused
GraphQL dependencies from package.json by deleting the "graphql" and
"graphql-request" entries; verify no code imports or references to graphql or
graphql-request exist in the services/trust-score codebase (the service
currently uses axios to send raw GraphQL payloads), then run npm/yarn install to
update lockfile and CI to ensure build passes without those packages.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@services/ontology/schemas/reference.json`:
- Line 3: You changed the schemaId value in
services/ontology/schemas/reference.json from
7e94fada-581d-49b0-b6f5-1fe0766da360 to c20e9437-02a4-4917-8cee-de35dabbdb6a;
either revert the change or explicitly document and propagate it: update the
repository documentation and change-log to explain why schemaId was changed,
confirm the new UUID (c20e9437-02a4-4917-8cee-de35dabbdb6a) with the
eVault/integration owners and update any mapping tables or configuration that
reference schemaId (used by the ontology service indexing, w3ds-gateway
resolution, web3 adapter mapping, and eVault operations), and add a short note
in the PR description linking this backend schemaId change to the "frontend for
Trust Service" work so reviewers have the required context.

In `@services/trust-score/src/index.js`:
- Around line 23-29: The /config POST handler (app.post("/config")) currently
allows unauthenticated callers to call setRegistryUrl and must be protected:
replace the public handler with an authenticated-only operation by adding an
auth middleware or inline check that validates a server-side admin secret or
token (from an env var) and rejects requests with 401/403 if missing/invalid;
only call setRegistryUrl when the auth check passes and log the change. Also
ensure CORS is tightened (restrict allowed origins or remove the open policy) so
browsers on third-party sites cannot call this endpoint.

In `@services/trust-score/src/userDataService.js`:
- Around line 72-83: The _platformToken is cached indefinitely in
getPlatformToken and must be refreshed when downstream auth fails; modify the
code so that on 401/403 responses from eVault calls the cached _platformToken is
cleared and a new token is fetched by re-invoking getPlatformToken (or by making
getPlatformToken always refetch after a failed call), and ensure any caller
logic using _platformToken (refer to getPlatformToken and the code paths that
consume _platformToken around lines 56–60 and 109–120) retries the request once
after clearing the cache so transient/stale-token errors recover automatically.
- Around line 109-123: The GraphQL call using axios.post (graphqlUrl,
BINDING_DOCUMENTS_QUERY, ...) currently treats any 200 response with errors as
if bindingDocuments.edges is empty; update the code around the axios response
handling (the response variable and the access of
response.data?.data?.bindingDocuments?.edges) to check for response.data.errors
(or missing response.data.data) and surface/throw an error (or return a clear
failure) instead of defaulting to [] so downstream code does not compute a false
low score; ensure the new behavior logs or propagates the GraphQL error details
(including response.data.errors and the query variables) so callers can handle
the failure.

---

Nitpick comments:
In `@services/trust-score/package.json`:
- Around line 16-20: Remove the unused GraphQL dependencies from package.json by
deleting the "graphql" and "graphql-request" entries; verify no code imports or
references to graphql or graphql-request exist in the services/trust-score
codebase (the service currently uses axios to send raw GraphQL payloads), then
run npm/yarn install to update lockfile and CI to ensure build passes without
those packages.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4dcdb44d-b462-4271-b62b-52e4bcc86967

📥 Commits

Reviewing files that changed from the base of the PR and between d2efd8b and 9623127.

⛔ Files ignored due to path filters (2)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • services/trust-score/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (6)
  • services/ontology/schemas/reference.json
  • services/trust-score/package.json
  • services/trust-score/src/__tests__/userDataService.test.js
  • services/trust-score/src/index.js
  • services/trust-score/src/public/index.html
  • services/trust-score/src/userDataService.js

{
"$schema": "http://json-schema.org/draft-07/schema#",
"schemaId": "7e94fada-581d-49b0-b6f5-1fe0766da360",
"schemaId": "c20e9437-02a4-4917-8cee-de35dabbdb6a",
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 | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for the old schema ID in the codebase
echo "=== Searching for old schema ID: 7e94fada-581d-49b0-b6f5-1fe0766da360 ==="
rg -i "7e94fada-581d-49b0-b6f5-1fe0766da360" -C 3

echo -e "\n=== Searching for partial UUID patterns ==="
rg -i "7e94fada" -C 2

Repository: MetaState-Prototype-Project/prototype

Length of output: 199


🏁 Script executed:

#!/bin/bash
# Look for database migrations, seed data, or test fixtures that might reference the old ID
echo "=== Checking migrations and seed data ==="
fd -e sql -e json -e yaml -e yml -x rg -l "7e94fada-581d-49b0-b6f5-1fe0766da360" {}

echo -e "\n=== Looking for migration scripts ==="
fd migration --exec cat {}

Repository: MetaState-Prototype-Project/prototype

Length of output: 51395


🏁 Script executed:

#!/bin/bash
# Search for GraphQL queries that might use schemaId
echo "=== Searching for schemaId usage in GraphQL ==="
rg -i "schemaId" --type graphql -C 3

echo -e "\n=== Searching for schemaId in JS/TS files ==="
rg -i "schemaId" --type ts --type js -C 3

echo -e "\n=== Searching for reference schema usage ==="
rg -i "reference.*schema" --type ts --type js -C 2

Repository: MetaState-Prototype-Project/prototype

Length of output: 50445


Remove or clarify the schema ID change—verify the new ID is documented and intentional.

The old schema ID (7e94fada-581d-49b0-b6f5-1fe0766da360) has no references in the codebase, so there are no direct breaking changes to existing code. However, the schemaId field is actively used throughout the system (ontology service indexing, w3ds-gateway resolution, web3 adapter mapping, and eVault operations), making this a structural change that requires:

  • Documentation of why this schema ID is being changed or introduced
  • Confirmation that the new ID (c20e9437-02a4-4917-8cee-de35dabbdb6a) aligns with external eVault integration or system architecture
  • Clarification of the relationship to the PR's "frontend for Trust Service" objective (this is a backend schema change)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/ontology/schemas/reference.json` at line 3, You changed the schemaId
value in services/ontology/schemas/reference.json from
7e94fada-581d-49b0-b6f5-1fe0766da360 to c20e9437-02a4-4917-8cee-de35dabbdb6a;
either revert the change or explicitly document and propagate it: update the
repository documentation and change-log to explain why schemaId was changed,
confirm the new UUID (c20e9437-02a4-4917-8cee-de35dabbdb6a) with the
eVault/integration owners and update any mapping tables or configuration that
reference schemaId (used by the ontology service indexing, w3ds-gateway
resolution, web3 adapter mapping, and eVault operations), and add a short note
in the PR description linking this backend schemaId change to the "frontend for
Trust Service" work so reviewers have the required context.

Comment on lines +23 to +29
app.post("/config", (req, res) => {
const { registryUrl } = req.body;
if (!registryUrl || typeof registryUrl !== "string") {
return res.status(400).json({ error: "registryUrl is required" });
}
setRegistryUrl(registryUrl);
return res.json({ ok: true, registryUrl });
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 | 🔴 Critical

Do not expose /config as an unauthenticated public endpoint.

Any caller can rewrite the process-wide REGISTRY_URL for all users. Combined with the open CORS policy on Line 11, a third-party site can repoint this service at an arbitrary host and make the backend issue outbound requests there.

Suggested fix
 app.post("/config", (req, res) => {
+    if (process.env.NODE_ENV === "production") {
+        return res.status(404).end();
+    }
+
     const { registryUrl } = req.body;
     if (!registryUrl || typeof registryUrl !== "string") {
         return res.status(400).json({ error: "registryUrl is required" });
     }
+
+    let parsed;
+    try {
+        parsed = new URL(registryUrl);
+    } catch {
+        return res.status(400).json({ error: "registryUrl must be a valid URL" });
+    }
+    if (!["http:", "https:"].includes(parsed.protocol)) {
+        return res.status(400).json({ error: "registryUrl must use http or https" });
+    }
+    if (!["localhost", "127.0.0.1"].includes(parsed.hostname)) {
+        return res.status(403).json({ error: "registryUrl is not allowed" });
+    }
+
     setRegistryUrl(registryUrl);
     return res.json({ ok: true, registryUrl });
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
app.post("/config", (req, res) => {
const { registryUrl } = req.body;
if (!registryUrl || typeof registryUrl !== "string") {
return res.status(400).json({ error: "registryUrl is required" });
}
setRegistryUrl(registryUrl);
return res.json({ ok: true, registryUrl });
app.post("/config", (req, res) => {
if (process.env.NODE_ENV === "production") {
return res.status(404).end();
}
const { registryUrl } = req.body;
if (!registryUrl || typeof registryUrl !== "string") {
return res.status(400).json({ error: "registryUrl is required" });
}
let parsed;
try {
parsed = new URL(registryUrl);
} catch {
return res.status(400).json({ error: "registryUrl must be a valid URL" });
}
if (!["http:", "https:"].includes(parsed.protocol)) {
return res.status(400).json({ error: "registryUrl must use http or https" });
}
if (!["localhost", "127.0.0.1"].includes(parsed.hostname)) {
return res.status(403).json({ error: "registryUrl is not allowed" });
}
setRegistryUrl(registryUrl);
return res.json({ ok: true, registryUrl });
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/trust-score/src/index.js` around lines 23 - 29, The /config POST
handler (app.post("/config")) currently allows unauthenticated callers to call
setRegistryUrl and must be protected: replace the public handler with an
authenticated-only operation by adding an auth middleware or inline check that
validates a server-side admin secret or token (from an env var) and rejects
requests with 401/403 if missing/invalid; only call setRegistryUrl when the auth
check passes and log the change. Also ensure CORS is tightened (restrict allowed
origins or remove the open policy) so browsers on third-party sites cannot call
this endpoint.

Comment on lines +72 to +83
async function getPlatformToken() {
if (_platformToken) return _platformToken;

const endpoint = new URL("/platforms/certification", REGISTRY_URL).toString();
const response = await axios.post(
endpoint,
{ platform: "trust-score" },
{ timeout: 10_000 },
);
_platformToken = response.data.token;
return _platformToken;
}
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

Refresh the cached platform token after auth failures.

_platformToken is cached indefinitely here. Once eVault starts returning 401/403 for a stale token, every later request reuses the same credential, and services/trust-score/src/index.js:56-60 turns that into a permanent 500 until the process is restarted.

Suggested fix
 async function fetchBindingDocuments(eName) {
     const normalized = normalizeEName(eName);
     const [evaultBaseUrl, token] = await Promise.all([
         resolveEVaultUrl(normalized),
         getPlatformToken(),
     ]);

     const graphqlUrl = new URL("/graphql", evaultBaseUrl).toString();
+    const requestBindingDocuments = (bearerToken) =>
+        axios.post(
+            graphqlUrl,
+            { query: BINDING_DOCUMENTS_QUERY, variables: { first: 100 } },
+            {
+                headers: {
+                    "Content-Type": "application/json",
+                    Authorization: `Bearer ${bearerToken}`,
+                    "X-ENAME": normalized,
+                },
+                timeout: 10_000,
+            },
+        );

-    const response = await axios.post(
-        graphqlUrl,
-        { query: BINDING_DOCUMENTS_QUERY, variables: { first: 100 } },
-        {
-            headers: {
-                "Content-Type": "application/json",
-                Authorization: `Bearer ${token}`,
-                "X-ENAME": normalized,
-            },
-            timeout: 10_000,
-        },
-    );
+    let response;
+    try {
+        response = await requestBindingDocuments(token);
+    } catch (error) {
+        const status = error.response?.status;
+        if (status !== 401 && status !== 403) throw error;
+
+        clearPlatformToken();
+        response = await requestBindingDocuments(await getPlatformToken());
+    }

Also applies to: 109-120

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/trust-score/src/userDataService.js` around lines 72 - 83, The
_platformToken is cached indefinitely in getPlatformToken and must be refreshed
when downstream auth fails; modify the code so that on 401/403 responses from
eVault calls the cached _platformToken is cleared and a new token is fetched by
re-invoking getPlatformToken (or by making getPlatformToken always refetch after
a failed call), and ensure any caller logic using _platformToken (refer to
getPlatformToken and the code paths that consume _platformToken around lines
56–60 and 109–120) retries the request once after clearing the cache so
transient/stale-token errors recover automatically.

Comment on lines +109 to +123
const response = await axios.post(
graphqlUrl,
{ query: BINDING_DOCUMENTS_QUERY, variables: { first: 100 } },
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
"X-ENAME": normalized,
},
timeout: 10_000,
},
);

const edges = response.data?.data?.bindingDocuments?.edges ?? [];

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

Do not treat GraphQL failures as an empty eVault.

A 200 response with errors currently falls through to edges ?? [], which makes downstream code compute a valid-looking low score from missing data instead of surfacing the failure.

Suggested fix
     const response = await axios.post(
         graphqlUrl,
         { query: BINDING_DOCUMENTS_QUERY, variables: { first: 100 } },
         {
             headers: {
                 "Content-Type": "application/json",
                 Authorization: `Bearer ${token}`,
                 "X-ENAME": normalized,
             },
             timeout: 10_000,
         },
     );

-    const edges = response.data?.data?.bindingDocuments?.edges ?? [];
+    if (Array.isArray(response.data?.errors) && response.data.errors.length > 0) {
+        const messages = response.data.errors
+            .map((error) => error.message)
+            .filter(Boolean)
+            .join("; ");
+        throw new Error(
+            `eVault GraphQL query failed${messages ? `: ${messages}` : ""}`,
+        );
+    }
+
+    const edges = response.data?.data?.bindingDocuments?.edges;
+    if (!Array.isArray(edges)) {
+        throw new Error("eVault GraphQL response is missing bindingDocuments.edges");
+    }

     return edges
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@services/trust-score/src/userDataService.js` around lines 109 - 123, The
GraphQL call using axios.post (graphqlUrl, BINDING_DOCUMENTS_QUERY, ...)
currently treats any 200 response with errors as if bindingDocuments.edges is
empty; update the code around the axios response handling (the response variable
and the access of response.data?.data?.bindingDocuments?.edges) to check for
response.data.errors (or missing response.data.data) and surface/throw an error
(or return a clear failure) instead of defaulting to [] so downstream code does
not compute a false low score; ensure the new behavior logs or propagates the
GraphQL error details (including response.data.errors and the query variables)
so callers can handle the failure.

@coodos coodos merged commit 718f013 into main Mar 28, 2026
4 checks passed
@coodos coodos deleted the feat/trust-service-frontend branch March 28, 2026 15:10
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.

1 participant