[AI assisted] feat(lei): GLEIF API client + AttestationJWKSource composition#19
Open
scourtney-godaddy wants to merge 1 commit into
Open
[AI assisted] feat(lei): GLEIF API client + AttestationJWKSource composition#19scourtney-godaddy wants to merge 1 commit into
scourtney-godaddy wants to merge 1 commit into
Conversation
…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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.gois aGLEIFHTTPClientthat hitshttps://api.gleif.org/api/v1/lei-records/{lei}and returns a typedGLEIFRecord. A 404 returns nil so the caller can distinguish "LEI does not exist" from "GLEIF unreachable."WithBaseURLandWithHTTPClientcover 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.goadds anAttestationJWKSourceinterface and aStaticAttestationSourceimplementation. 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 sameSet/Lookupcontract. Defensive copies on both methods mean a caller cannot mutate the source's stored bytes after handing them in.internal/adapter/anchor/lei/resolver.gogainsWithAttestationSource(s)and the runtime path throughResolve: the resolver checksrecord.AttestationJWKfirst (the vLEI Option A path, where the LOU returned the key directly), then falls back to the source'sLookup(lei)when the record carries no embedded key (the Option B path, where the operator stages the key under the LEI). The new error codeLEI_ATTESTATION_LOOKUP_FAILEDdistinguishes "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 ./...cleango test ./...clean529900T8BM49AURSDO55) againstapi.gleif.orgwith aStaticAttestationSourcecarrying a known JWKLEI_ATTESTATION_LOOKUP_FAILEDreturns when the LEI exists but no attestation key is registered🤖 Generated with Claude Code