Skip to content

[AI assisted] feat(lei): GLEIF API client + AttestationJWKSource composition#19

Open
scourtney-godaddy wants to merge 1 commit into
feat/plan-g-anchor-testsfrom
feat/lei-gleif-client
Open

[AI assisted] feat(lei): GLEIF API client + AttestationJWKSource composition#19
scourtney-godaddy wants to merge 1 commit into
feat/plan-g-anchor-testsfrom
feat/lei-gleif-client

Conversation

@scourtney-godaddy
Copy link
Copy Markdown

BLUF. Adds the GLEIF API client and an attestation-key indirection that the existing LEI resolver depends on. With this PR, an LEI registration whose entity has registered an ANS attestation key (via the LOU custom-field path, or via a deployment-staged StaticAttestationSource) resolves end-to-end against the live GLEIF API.

What lands

internal/adapter/anchor/lei/gleif_client.go is a GLEIFHTTPClient that hits https://api.gleif.org/api/v1/lei-records/{lei} and returns a typed GLEIFRecord. A 404 returns nil so the caller can distinguish "LEI does not exist" from "GLEIF unreachable." WithBaseURL and WithHTTPClient cover tests and production overrides; the JSON:API Level 1 envelope decodes into the existing record struct without changing the resolver's contract.

internal/adapter/anchor/lei/attestation_source.go adds an AttestationJWKSource interface and a StaticAttestationSource implementation. The interface keeps the resolver indifferent to where the entity's attestation key came from. A deployment loading keys from config, a deployment reading them from a custom-field LOU integration, and a deployment fetching them from vLEI all satisfy the same Set/Lookup contract. Defensive copies on both methods mean a caller cannot mutate the source's stored bytes after handing them in.

internal/adapter/anchor/lei/resolver.go gains WithAttestationSource(s) and the runtime path through Resolve: the resolver checks record.AttestationJWK first (the vLEI Option A path, where the LOU returned the key directly), then falls back to the source's Lookup(lei) when the record carries no embedded key (the Option B path, where the operator stages the key under the LEI). The new error code LEI_ATTESTATION_LOOKUP_FAILED distinguishes "no key was registered for this LEI" from "GLEIF returned no record."

Tests

Tests cover the GLEIF client (URL shape, 404, network error, 5xx, malformed JSON, normal response, base-URL override) and the attestation source plus resolver integration (Set/Lookup, defensive copy, embedded-key precedence, source-fallback path, missing-key error code, end-to-end resolution with both sources).

Test plan

  • go build ./... clean
  • go test ./... clean
  • Resolve a GLEIF demo LEI (529900T8BM49AURSDO55) against api.gleif.org with a StaticAttestationSource carrying a known JWK
  • LEI_ATTESTATION_LOOKUP_FAILED returns when the LEI exists but no attestation key is registered

🤖 Generated with Claude Code

…ce composition

Closes the LEI half-feature gap. Before this change, the LEI resolver
validated mod-97 and stopped; the GLEIFClient interface was a stub
that returned LEI_GLEIF_NOT_CONFIGURED for every Resolve call.

Two new files:

internal/adapter/anchor/lei/gleif_client.go (~150 lines)
  Concrete GLEIFClient that talks to api.gleif.org/api/v1/lei-records.
  Decodes the JSON:API Level 1 envelope; populates EntityStatus,
  EntityName, Jurisdiction, UpdatedAt. Returns nil with no error on
  404. WithBaseURL + WithHTTPClient escape hatches for tests and
  for production deployments that need a corporate egress proxy or
  observability hooks.

internal/adapter/anchor/lei/attestation_source.go (~100 lines)
  Separate pluggable surface for the entity attestation JWK. The
  GLEIF Level 1 record does not carry an attestation key; vLEI
  Option A and Option B both require additional infrastructure that
  is deployment-specific. AttestationJWKSource interface plus an
  in-memory StaticAttestationSource implementation. A vLEI-aware
  source replaces the static one in production deployments.

Resolver wiring (resolver.go):
  WithAttestationSource(s AttestationJWKSource) returns a copy of
  the resolver with the source attached. Resolve checks the GLEIF
  record AttestationJWK first (vLEI-aware clients populate it
  inline); falls back to the source when empty. New error code
  LEI_ATTESTATION_LOOKUP_FAILED for source errors;
  LEI_NO_ATTESTATION_KEY now points the operator at both extension
  points in its message.

Tests: 7 GLEIF client cases (happy, 404, 5xx, bad JSON, missing
required fields, context cancellation, base-URL trailing slash);
9 source + resolver-integration cases. Existing tests untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@scourtney-godaddy scourtney-godaddy added the AI assisted Pull request created with AI assistance label May 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AI assisted Pull request created with AI assistance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant