Skip to content

Fix issuer registry lookups blocked by CORS - #51

Merged
dmitrizagidulin merged 5 commits into
mainfrom
fix-registries-fetch-skip-cors-proxy
Sep 1, 2026
Merged

Fix issuer registry lookups blocked by CORS#51
dmitrizagidulin merged 5 commits into
mainfrom
fix-registries-fetch-skip-cors-proxy

Conversation

@0marSalah

@0marSalah 0marSalah commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Bumps issuer-registry-client to 4.1.0 for its injectable fetch, and uses it to route oidf registry URLs through the CORS proxy. The wallet's own oidf lookup comes out; everything else stays direct.

Summary by CodeRabbit

  • New Features

    • Added unified support for legacy and OIDF issuer-registry lookups.
    • Improved handling of direct and proxied registry requests.
    • Added timeout protection, retries, fallback results, and lookup caching.
    • Added support for trust-anchor and federation endpoint lookups.
  • Bug Fixes

    • Improved handling of unavailable registries, missing metadata, empty identifiers, and 404 responses.
    • Prevented stalled proxy requests from hanging indefinitely.
  • Documentation

    • Updated guidance to clarify how registry requests are routed through the CORS proxy.

@coderabbitai

coderabbitai Bot commented Aug 27, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: b1170209-00b4-437a-a84d-7cb10ab95b29

📥 Commits

Reviewing files that changed from the base of the PR and between 7a29362 and fbdca43.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (1)
  • package.json

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The registry manager now delegates legacy and OIDF lookups to RegistryClient. It caches registry lists, routes requests directly or through the CORS proxy, applies shared timeouts, and returns upstream lookup results.

Changes

Registry lookup

Layer / File(s) Summary
Proxy cancellation support
src/lib/corsProxy.ts, tests/unit/corsProxy.test.ts, src/app.config.ts, src/lib/verify.ts
corsProxyFetch accepts and forwards an optional AbortSignal. Documentation describes proxy use for OIDF and registry-manager requests.
Registry list loading and routing
src/lib/registryManager.ts, tests/unit/registryManager.test.ts
Registry lists remain cached. Fallback lists remain lookup-scoped. Non-OIDF URLs use direct fetches, while OIDF requests use the proxy. Loading, timeout, retry, empty-DID, and cache-reset behavior are covered.
Unified legacy and OIDF lookup
src/lib/registryManager.ts, tests/unit/registryManager.test.ts, package.json, pnpm-workspace.yaml
Each lookup creates a RegistryClient with shared routing and timeout handling. The method returns LookupResult. OIDF trust-anchor and federation-fetch paths are covered by integration-style tests.

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

Merge Risk: 🟡 Moderate · up to fbdca

The change enables CORS-proxied OIDF registry lookups, but legacy lookup failures can still hang resolution or discard valid matches, and configured federation endpoints with existing query parameters can be treated as unavailable. These bounded correctness and availability issues should be fixed or explicitly accepted before merging.

Sequence Diagram(s)

sequenceDiagram
  participant RegistryManager
  participant RegistryClient
  participant corsProxyFetch
  participant RegistryEndpoint
  RegistryManager->>RegistryManager: Resolve cached registry list
  RegistryManager->>RegistryClient: Create client with routing fetch wrapper
  RegistryClient->>corsProxyFetch: Request OIDF registry data
  corsProxyFetch->>RegistryEndpoint: Fetch proxied registry data
  RegistryClient-->>RegistryManager: Return LookupResult
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 8 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: fixing issuer registry lookups that are blocked by CORS.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 8 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix-registries-fetch-skip-cors-proxy

Warning

Some tools did not complete. Review the errors below.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed: private package registry requires authentication. Disable ESLint in CodeRabbit settings or use public packages.

🔧 Checkov (3.3.11)
package.json

Checkov timed out on this file


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

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5ce6cb43-985b-4337-ba93-131a3aa5041f

📥 Commits

Reviewing files that changed from the base of the PR and between 32d36e9 and 6f6a66b.

📒 Files selected for processing (2)
  • src/lib/registryManager.ts
  • tests/unit/registryManager.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Comment thread src/lib/registryManager.ts Outdated
@0marSalah 0marSalah self-assigned this Aug 27, 2026
@0marSalah 0marSalah changed the title Fetch known-issuer registries directly, skip the CORS proxy Fix issuer registry lookups blocked by CORS Aug 27, 2026

@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 (3)
src/lib/registryManager.ts (2)

205-208: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Build the federation fetch URL with URL instead of string concatenation.

federation_fetch_endpoint is an arbitrary URL from the entity configuration. If it already carries a query string, ${endpoint}?sub=... produces two ? separators and the request fails. The registry is then reported as unchecked even though it is reachable. URL.searchParams handles both cases.

♻️ Proposed fix
-  const lookupRes = await corsProxyFetch({
-    url: `${endpoint}?sub=${encodeURIComponent(did)}`,
-    signal
-  })
+  const lookupUrl = new URL(endpoint)
+  lookupUrl.searchParams.set('sub', did)
+  const lookupRes = await corsProxyFetch({
+    url: lookupUrl.toString(),
+    signal
+  })

Note that the test fixture at tests/unit/registryManager.test.ts line 247 asserts the exact concatenated form, so update the expected URL if you apply this change.


296-299: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Bound and isolate the legacy lookup.

RegistryClient.lookupIssuersFor calls fetch without a signal or timeout. Its per-registry catch handles fetch errors, but a pending fetch keeps Promise.all pending. A rejection from the legacy promise also rejects lookupDid and discards OIDF results. Add a deadline wrapper and return an empty legacy result on rejection.

tests/unit/registryManager.test.ts (1)

233-260: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider adding a stalled-hop case to stubOidfFetch coverage.

The suite covers a rejected trust anchor, a 404, and a missing endpoint. It does not cover a proxy hop that never settles. That path is the reason corsProxyFetch gained the signal parameter in this cohort, and the shared AbortController in lookupOidfRegistries is the only thing that ends the lookup. A test with fake timers, a pending route, and advanceTimersByTimeAsync(LOAD_TIMEOUT_MS) would pin the "unchecked after deadline" behavior.

💚 Sketch
it('reports a stalled oidf hop as unchecked after the deadline', async () => {
  vi.useFakeTimers()
  stubOidfFetch({
    [proxied(TRUST_ANCHOR_EC)]: () =>
      new Promise<Response>((_, reject) => {
        // resolve never; the shared AbortController must end this hop
      })
  })

  const { registryManager, LOAD_TIMEOUT_MS } = await loadRegistryManager()
  const lookup = registryManager.lookupDid('did:key:z123')
  await vi.advanceTimersByTimeAsync(LOAD_TIMEOUT_MS)

  expect((await lookup).uncheckedRegistries).toEqual([OIDF_REGISTRY])
})

The stubbed fetch must observe the signal and reject on abort, because the stub does not inherit native abort behavior.


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bda75090-7290-4a67-b1b5-82b8327c6786

📥 Commits

Reviewing files that changed from the base of the PR and between e1c0fa9 and 3f795e0.

📒 Files selected for processing (6)
  • src/app.config.ts
  • src/lib/corsProxy.ts
  • src/lib/registryManager.ts
  • src/lib/verify.ts
  • tests/unit/corsProxy.test.ts
  • tests/unit/registryManager.test.ts

Included review availability: Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Signed-off-by: Omar Salah <itsdevomar@gmail.com>
Signed-off-by: Omar Salah <itsdevomar@gmail.com>
Signed-off-by: Omar Salah <itsdevomar@gmail.com>
Signed-off-by: Omar Salah <itsdevomar@gmail.com>
@dmitrizagidulin
dmitrizagidulin force-pushed the fix-registries-fetch-skip-cors-proxy branch from 7a29362 to fbdca43 Compare September 1, 2026 16:22
Signed-off-by: Dmitri Zagidulin <dzagidulin@gmail.com>
@dmitrizagidulin
dmitrizagidulin merged commit 3934fa4 into main Sep 1, 2026
1 check failed
@dmitrizagidulin
dmitrizagidulin deleted the fix-registries-fetch-skip-cors-proxy branch September 1, 2026 16:55
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