Skip to content

Build a local registry stand-in so the whole loop runs on our own infrastructure #326

Description

@LKSNDRTMLKV

The seal side now has a local backend faithful enough to stand in for a provider: it emits the whole B-LTA structure, so a sandbox exercises the same shape a real seal has. The registry side has no equivalent. GhostRegistrySync discards, and the only thing that speaks the registry's wire contract is an axum server inside a test file (dpp-node/src/infra/registry/tests.rs), which nothing outside cargo test can reach.

So a sandbox environment can publish, seal and resolve, and cannot register. That is the last gap before the whole loop runs on our own infrastructure.

What it would serve

The three routes the adapter calls, plus the token exchange in front of them:

route today
register POST {base}/registrations in-test only
poll GET {base}/registrations/{id}/status in-test only
transfer POST {base}/registrations/{id}/transfer in-test only
token the OAuth2 client-credentials exchange in registry::client::get_token in-test only

The in-test double already implements all four against the real adapter, so this is mostly promotion, not invention: lift it out of tests.rs into something with a main, a port and a container image, and keep the test using it so the two cannot drift.

The thing this must not be allowed to imply

The Commission has published no API specification. #90 records what that means, and it is worth repeating here because a running "registry" is exactly the artefact that makes people forget it:

  • the paths above are invented/api/v1 was observed on the registry's own web client, not read from a spec;
  • api_version "1.0" is provisional;
  • the authentication model is structurally wrong. The adapter models an OAuth2 client-credentials exchange; registry identity is a qualified electronic seal or a qualified electronic attestation of attributes (IR 2026/1778 Arts. 4–5). That is a wrong mechanism, not a wrong URL.

So this mimics our adapter's assumptions, not the registry. It proves our outbox, drain, backoff, polling, verdict handling and operator-facing rollup work end to end. It proves nothing about whether we match the Commission, and the day the real specification lands, this simulator is what has to change first — not the thing that reassures anyone it already works.

That should be said in the service itself: a name that cannot be mistaken for the real one, a banner on every response, and a refusal to run against anything but a local/dev profile. The seal backend's convention is a good one to copy — its certificate literally says NOT A QUALIFIED SEAL, so the envelope carries the caveat rather than the README.

Worth deciding while building it

  • How faithful should the verdicts be? Registration is asynchronous: an accepted submission is polled. A simulator that always accepts immediately exercises the happy path and nothing else. Being able to make it reject, hold in submitted, or fail intermittently is where the drain's backoff and exhaustion actually get tested.
  • Operator verification lapse. The drain holds without consuming attempts when verified-operator status has lapsed (Art. 4(4), at most three years). A simulator that cannot express a lapsed operator cannot exercise that hold, which is a silent-queue path worth being sure about.
  • Does it persist? A restart that forgets every registration makes the polling path untestable across restarts, which is one of the things a sandbox is for.
  • Enrolment is a different artefact. Organisation enrolment counter-seals an EC-generated PDF declaration and wants PAdES embedded in the PDF; the seal adapter emits detached CAdES. Simulating enrolment would need that second artefact, so it is probably out of scope for a first cut — but say so deliberately rather than discovering it.

What it unlocks

Publish → seal (local, B-LTA) → register (local registry) → poll → resolve, entirely on our own infrastructure, with no QTSP credential and no Commission endpoint. That is the whole loop under test for the first time.

Related

#90 (what the real integration is blocked on, and why) · odal-node/dpp-core#98 (the registry types) · the in-test double at crates/dpp-node/src/infra/registry/tests.rs · the seal backend's local stand-in, which is the pattern to copy.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions