Skip to content
Registry stack docs v0 · draft

Run Registry Relay locally

This page walks you through building Registry Relay from source, pointing it at the bundled XLSX fixture, and confirming that entity and metadata routes respond correctly.

Use this guide when you need a running instance of Registry Relay on your laptop for local development, integration testing, or exploration. For a full multi-service topology that also starts Registry Notary and a static metadata publisher, see the Registry Lab tutorial instead.

  • Rust stable toolchain. Install via rustup.
  • just task runner. Install with cargo install just or your platform package manager.
  • curl for the verification steps.

The example config and fixture files are already present in the registry-relay repository. Clone it if you have not already done so.

Terminal window
just setup
just build

just setup installs the Rust toolchain dependencies. just build compiles the release binary to target/release/registry-relay. Source: README build section.

The default config (config/example.yaml) expects an XLSX file at ./data/social_registry.xlsx:

Terminal window
mkdir -p data
cp fixtures/example_social_registry.xlsx data/social_registry.xlsx

The bundled fixture is a synthetic social registry with about 20 individual records you can page through. Source: README run-locally section.

Registry Relay never stores raw API keys. Each configured key points at an environment variable that holds the SHA-256 fingerprint of the raw key. Source: docs/configuration.md API keys section.

Generate three keys for the three principals in the example config:

Terminal window
# Run once per key; first line = raw key, second line = SHA-256 fingerprint:
openssl rand -base64 32 | tee /dev/stderr | shasum -a 256 | awk '{print "sha256:" $1}'

Run the command three times (once for program_system, statistics_office, and verification_service).

Store the raw keys somewhere you can retrieve them for curl calls. Export the fingerprints as environment variables:

Terminal window
export PROGRAM_SYSTEM_API_KEY_HASH='sha256:<64 lowercase hex chars>'
export STATS_OFFICE_API_KEY_HASH='sha256:<64 lowercase hex chars>'
export VERIFICATION_SERVICE_API_KEY_HASH='sha256:<64 lowercase hex chars>'
export REGISTRY_RELAY_AUDIT_HASH_SECRET='<at least 32 random bytes>'

Replace each <64 lowercase hex chars> with the fingerprint output from generate_key. Set REGISTRY_RELAY_AUDIT_HASH_SECRET to deployment-specific random secret material. For a local demo value, run openssl rand -base64 32.

Terminal window
just run 2>relay.log

Running with 2>relay.log separates audit records (stdout) from operational logs (stderr) in your terminal, so the JSON audit stream isn’t mixed with startup messages.

just run starts the binary with config/example.yaml as the default config. Registry Relay binds the data-plane listener on 0.0.0.0:8080 as set in config/example.yaml.

You can also pass a config path explicitly:

Terminal window
./target/release/registry-relay --config config/example.yaml

Or set the REGISTRY_RELAY_CONFIG environment variable instead of using the flag. Source: src/main.rs config resolution.

Operational logs go to stderr. Audit records go to stdout (as configured by audit.sink: stdout in the example config).

In a second terminal, check the readiness probe:

Terminal window
curl -i http://127.0.0.1:8080/ready

/ready returns 200 only after all configured sources have ingested successfully. /health is a liveness probe and returns 200 as long as the process is running. Source: docs/ops.md probes section.

Set the raw key you noted for program_system:

Terminal window
PROGRAM_SYSTEM_API_KEY='<raw key from step 3>'

List individuals from the social registry:

Terminal window
curl -si \
-H "Authorization: Bearer $PROGRAM_SYSTEM_API_KEY" \
http://127.0.0.1:8080/datasets/social_registry/individual

A successful response returns 200 with a JSON array of individual records. The program_system key has social_registry:rows scope, so row reads are permitted. Source: config/example.yaml; docs/api.md entity reads section.

Fetch the Data Catalog Vocabulary (DCAT) metadata document:

Terminal window
curl -si \
-H "Authorization: Bearer $PROGRAM_SYSTEM_API_KEY" \
http://127.0.0.1:8080/metadata/dcat

A successful response returns 200 with a JSON-LD DCAT catalog document. The response Content-Type is application/ld+json.

Fetch the BRegDCAT-AP profile variant:

Terminal window
curl -si \
-H "Authorization: Bearer $PROGRAM_SYSTEM_API_KEY" \
http://127.0.0.1:8080/metadata/dcat/bregdcat-ap

Source: docs/metadata.md relay endpoints section.

Terminal window
curl -si \
-H "Authorization: Bearer $PROGRAM_SYSTEM_API_KEY" \
http://127.0.0.1:8080/openapi.json

The OpenAPI document is auth-gated and filtered to the scopes of the caller. The unauthenticated GET /docs route serves a Scalar HTML viewer that asks for a bearer token before fetching openapi.json.

Confirm an unauthenticated request is rejected

Section titled “Confirm an unauthenticated request is rejected”
Terminal window
curl -si http://127.0.0.1:8080/datasets/social_registry/individual

Registry Relay returns 401 with a Problem Details body whose code is auth.missing_credential.

Build the image and run it with the same example config and fixture:

Terminal window
docker buildx build --load \
--build-context registry-platform=../registry-platform \
-t registry-relay:local \
.
docker run --rm -p 8080:8080 \
-e PROGRAM_SYSTEM_API_KEY_HASH \
-e STATS_OFFICE_API_KEY_HASH \
-e VERIFICATION_SERVICE_API_KEY_HASH \
-e REGISTRY_RELAY_AUDIT_HASH_SECRET \
-v "$PWD/config/example.yaml:/etc/registry-relay/config.yaml:ro" \
-v "$PWD/fixtures:/var/lib/registry-relay/data:ro" \
registry-relay:local

The container exposes port 8080 and reads config from /etc/registry-relay/config.yaml by default. The build context must include a sibling registry-platform checkout because Relay consumes shared platform crates through path dependencies. Source: README container image section.

The process exits immediately at startup. Check that all three *_API_KEY_HASH environment variables are set and each value is in the exact format sha256:<64 lowercase hex chars>. The binary exits non-zero if required hash env vars are missing. Source: docs/ops.md troubleshooting section.

/ready returns 503. Inspect the stderr output for ingest errors. Confirm the XLSX file exists at ./data/social_registry.xlsx relative to your working directory. If the sheet name or range is wrong, adjust format.xlsx.sheet or format.xlsx.data_range in the config. Source: docs/ops.md readiness 503 troubleshooting.

Entity route returns 403. Confirm the key you are using has the social_registry:rows scope in the example config. The statistics_office key has only metadata and aggregate scopes; it cannot read rows. Source: config/example.yaml; docs/api.md scopes table.

Metadata route returns 403. Confirm the key has social_registry:metadata scope. The verification_service key has only evidence_verification scope.

Port 8080 is already in use. Edit server.bind in config/example.yaml to a different address or port, such as 127.0.0.1:8090. Source: docs/configuration.md server section.

Audit records are missing from stdout. The process writes audit JSONL to stdout and operational logs to stderr. If you are redirecting stdout, check that destination. Set audit.include_health: true in the config to also capture health-probe records. Source: docs/ops.md audit troubleshooting.