Skip to content
Registry stack docs v0 · draft

Registry Lab overview

Use this when you want to see the registry stack actually run end-to-end on your laptop in one command.

Registry Lab is a Docker Compose demo for the registry stack. It wires three Registry Relay instances, four Registry Notary instances, live Postgres and Zitadel services, a private OpenFn sidecar path, a static metadata publisher, and narrated demo clients into a single topology you can run on a laptop, with no production credentials and no remote services.

The goal is to let a developer, reviewer, or integrator observe every layer of the stack interacting end-to-end on local data before writing any integration code. Use Lab when you want to see the full stack interact locally; for production deployment guidance, look at each project’s own docs.

Stack commitments: interoperability, safeguards, reviewability (all three, with the distributed-custody premise visible in the federated topology).

Terminal window
git clone --recurse-submodules https://github.com/jeremi/registry-lab
cd registry-lab
scripts/release-check.sh
# Open output/ to inspect the demo artifacts

release-check.sh runs fixture generation, credential generation, static metadata publication, compose build, compose up, core smoke checks, demo client, live-service checks, OpenFn smoke checks, live-story walkthroughs, and compose down in one pass. The submodules use GitHub SSH URLs; configure SSH access or a Git URL rewrite before cloning with --recurse-submodules.

The topology runs three Relay instances, four Notary instances, live Postgres and Zitadel services, a private OpenFn sidecar, a static metadata publisher, and a narrated demo client. For service names, host ports, image sources, and network layout, see the Registry Lab reference.

scripts/generate-fixtures.py is a Python PEP 723 inline-dependency script (run with uv run). It produces three fixture files under data/:

  • data/civil/civil_registry.csv: children, caregivers, living adults, and deceased adults across five districts.
  • data/social-protection/social_protection_registry.xlsx: households, household members, and enrollments with active, inactive, suspended, and review-required cases.
  • data/health/health_registry.parquet: active, suspended, pending-renewal, and partially-serviceable facilities.

Timestamps are deterministic (2026-01-01). The fixture generator validates that every demo scenario has representative data before writing. The data/ directory is gitignored; only the .gitignore marker is committed.

scripts/generate-demo-secrets.py is a direct-executable Python script (not wrapped by uv run). It writes a .env file (gitignored) with local demo credentials. No raw token is committed to the repository.

The .env.example file in the repository root contains inert placeholder values only. Generated credentials now include OpenFn sidecar caller tokens and the private mock registry target token used by the OpenFn smoke path.

scripts/publish-static-metadata.sh reads the portable manifest at config/static-metadata/metadata.yaml and invokes the Registry Manifest CLI to publish a static bundle into static-metadata/metadata/. The static-metadata/ directory is gitignored except for its .gitignore.

The static-metadata-publisher service then serves that bundle at 127.0.0.1:4331. No authentication is required for the static publisher endpoints. The static bundle is generated from the portable metadata config, not scraped from a running Relay. It includes the Core Public Service Vocabulary Application Profile (CPSV-AP) service catalogue used by Registry Atlas for service-first discovery. The catalogue preserves grouped Core Criterion and Core Evidence Vocabulary (CCCEV) evidence options: one option can require separate civil, household, and health evidence records, while another can require a single combined support record.

scripts/smoke.sh runs more than 30 checks against the live compose topology. The checks cover health and readiness on all three Relay instances, discovery endpoints on all three core Notary instances with bearer-token and x-api-key credentials, OpenAPI endpoints on every service, authorization scope denial responses (403 with auth.scope_denied), positive row-read and aggregate-read responses on the social protection Relay, claim evaluation (POST /claims/evaluate) on civil, social protection, and shared eligibility notaries, a cross-authority result with source_count >= 2 on the shared eligibility notary, credential-bound evaluation returning application/dc+sd-jwt, and service-log assertions that generated raw secrets are not emitted.

Additional focused checks exercise live and adaptor-backed paths:

  • scripts/smoke-openfn.sh verifies the OpenFn-backed Notary path through host port 4324.
  • scripts/check-relay-postgres.sh runs Relay’s ignored live Postgres tests.
  • scripts/check-relay-zitadel.sh runs Relay’s ignored Zitadel OIDC tests.
  • scripts/smoke-oidc-relay.sh starts a temporary OIDC-protected Relay against the local Zitadel IdP.
  • scripts/demo-live-stories.sh runs narrated live-service stories for Postgres, Zitadel/OIDC, and OpenFn.

The smoke suite also checks the Registry Atlas service graph path when the sibling registry-atlas checkout is available. That check verifies the published CPSV-AP catalogue has at least one public service, one requirement, multiple evidence option groups, a form, providers, and data-service routes.

All smoke requests carry the correlation ID decentralized-demo-correlation-001 by default, overridable via the DEMO_CORRELATION_ID environment variable.

scripts/demo-flow.py runs three end-to-end scenarios in sequence.

Scenario 1: Birth registration to child support. Civil claim evaluation with predicate disclosure.

Scenario 2: Household benefit review. Protected row read and aggregate consultation with scope binding.

Scenario 3: Cross-authority conditional support. Multi-authority claim with source_count >= 2.

For the full narrated walkthrough, see demo flow.

All client requests are sent with the same correlation ID and saved as JSON artifacts to the output/ directory (default DEMO_OUTPUT_DIR). The client uses a custom Ed25519 holder key for credential binding and requires openssl on the PATH for holder proof signing.

The demo client is started with a profile flag so it does not start alongside the background services:

Terminal window
docker compose -f compose.yaml --profile client run --rm demo-client

scripts/demo-live-stories.sh runs four additional narrated checks against the live-service topology:

  1. A live Postgres source cutover that shows new database rows becoming visible without a Relay restart.
  2. A Zitadel-issued JWT flow against a temporary OIDC-protected Relay.
  3. An OpenFn sidecar lookup behind Registry Notary, with the sidecar and mock registry kept off host ports.
  4. A service-first discovery story that asks Atlas to read the static CPSV-AP catalogue and select a satisfiable grouped evidence option without reading protected person-level data.

The script writes artifacts to output/live-stories/.

Registry Lab is at v0. Fixture data covers only five districts and a maximum of approximately 100 rows per dataset; it is not representative of production scale. Core Notary services have no healthcheck in compose; Relay services use the CLI-help healthcheck, and the OpenFn sidecar uses an HTTP readiness healthcheck. Static metadata is not auto-regenerated on manifest changes; you must re-run scripts/publish-static-metadata.sh after modifying config/static-metadata/metadata.yaml. The demo client’s output/ directory is wiped on each run.