Skip to content
Registry StackDocsDevelopment (unreleased)

Publish and consume a Registry Discovery index

For the operator and consumer or verifier

View as Markdown

You will package an index from one provider’s public description, serve it, and then, as an application, ask it which Registry Evidence service can answer a question.

Outcome
One local Discovery index, one resolved requirement, and one provider to select.
Time
About 15 minutes after the Rust dependencies are available
Level
Local development with synthetic data
Prerequisites
GitRust 1.95.0 through rustupPython 3curlLocal ports 38080 and 38090

discoveryctl checks and packages an index offline, and discovery serves one package. Clone the repository and build both from its root:

Terminal window
git clone --depth 1 --quiet https://github.com/registrystack/registry-stack.git
cd registry-stack
Terminal window
. scripts/cargo-runtime-library-path.sh
registry_cargo_build "$PWD" --locked --release -p registry-discovery -p registry-discoveryctl
export PATH="$PWD/target/release:$PATH"

The helper also sets the library path the binaries need on macOS, so run every discoveryctl and discovery command in this shell.

Copy the example project out of the checkout:

Terminal window
cp -R products/discovery/tutorial/project discovery-project

As the operator, you approve each provider by the URL of its public description, in discovery-project/origins.yaml:

apiVersion: id.registrystack.org/formats/discovery/origins/v1alpha1
kind: DiscoveryOrigins
origins:
- originId: tutorial-evidence
catalogUrl: http://127.0.0.1:38090/evidence.jsonld
profile: registry-discovery-v1alpha1
enabled: true

You also say which Evidence types meet a requirement an application may have. discovery-project/mappings/adult-status.yaml maps the adult-status requirement to one type:

apiVersion: id.registrystack.org/formats/discovery/evidence-mapping/v1alpha1
kind: DiscoveryEvidenceMapping
mappingId: urn:example:mapping:adult-status
mappingAuthorityId: urn:example:mapping-authority
requirementId: urn:example:requirement:adult-status
jurisdiction: urn:example:jurisdiction
alternatives:
- evidenceTypeListId: urn:example:evidence-type-list:adult-status
evidenceTypeIds:
- urn:example:evidence-type:adult-status

Check the project. --allow-loopback accepts the local http://127.0.0.1 URL; without it, only HTTPS origins pass.

Terminal window
discoveryctl check --project discovery-project --allow-loopback
valid origins=1 mappings=1
0 errors, 0 warnings in 3 files

The third file is runtime.yaml, which you use to serve the index. The check never contacts the provider URL; a refused file gets one finding per problem, with its line, column, and fix.

Play the provider: open a second shell at the checkout root and serve its description at the approved URL.

Terminal window
python3 products/discovery/tutorial/publication_server.py \
--descriptions products/discovery/fixtures/descriptions

Back in the first shell, package the index:

Terminal window
discoveryctl package \
--project discovery-project \
--output discovery-project/package \
--allow-loopback
packaged packageDigest=sha256:<package-digest> catalogRevision=sha256:7e0799f2c5fd24957e4d1372f757c40abef694110eb70fc260a0abdc312ca963 mappingRevision=sha256:332004ca3920c498539180946e8f2637e9998ba7e49cd98f31e19d6f818857ac

Packaging fetched the description once. The catalog revision digests what the descriptions mean and the mapping revision digests your mappings, so they match on any machine; the package digest also covers when this run fetched, so yours differs.

Stop the publication server with Ctrl+C. Discovery never contacts a provider while it serves.

discovery-project/runtime.yaml names the listener, the limits, and a package root read from DISCOVERY_PACKAGE_ROOT. Both paths must be absolute. In the first shell, start Discovery:

Terminal window
DISCOVERY_PACKAGE_ROOT="$PWD/discovery-project/package" \
discovery --runtime-config "$PWD/discovery-project/runtime.yaml"

It checks the package against its SHA256SUMS file before it listens. In the second shell:

Terminal window
curl -s http://127.0.0.1:38080/ready
{"status":"ready"}

Now play the application. It knows it must establish that a person is an adult, but not which provider can say so. Ask Discovery which Evidence types satisfy that requirement:

Terminal window
curl -s \
-H 'Content-Type: application/json' \
--data '{"requirementId":"urn:example:requirement:adult-status","jurisdiction":"urn:example:jurisdiction"}' \
http://127.0.0.1:38080/v1/evidence-types/resolve
{
"requirementId": "urn:example:requirement:adult-status",
"jurisdiction": "urn:example:jurisdiction",
"mappingRevision": "sha256:332004ca3920c498539180946e8f2637e9998ba7e49cd98f31e19d6f818857ac",
"alternatives": [
{
"evidenceTypeListId": "urn:example:evidence-type-list:adult-status",
"evidenceTypeIds": ["urn:example:evidence-type:adult-status"],
"mappingId": "urn:example:mapping:adult-status",
"mappingAuthorityId": "urn:example:mapping-authority"
}
]
}

Each alternative lists types that are required together; here there is one alternative with one type.

Search for Registry Evidence services that assert that type:

Terminal window
curl -s --get \
--data-urlencode 'serviceKind=evidence' \
--data-urlencode 'evidenceType=urn:example:evidence-type:adult-status' \
http://127.0.0.1:38080/v1/services

The response carries the catalogRevision from the package step and one item. Its key fields:

{
"recordId": "urn:registrystack:discovery:record:sha256:676659c10ce5cc9d353f4fd2816673c7947e612151efbbe1cc4d42372d9be9d5",
"bindingId": "urn:registrystack:discovery:binding:sha256:2f9ccc4629c7ea2409d986a9c0ee6e3afe6e63326ca7b1be7d9eb8c69082d96c",
"serviceKind": "evidence",
"endpointUrl": "https://evidence.example.org",
"originUrl": "http://127.0.0.1:38090/evidence.jsonld",
"originContentDigest": "sha256:fc96f3a8cb0d82239425ea5712dceca975a5899e5528616648174da661fae905"
}

originContentDigest is the SHA-256 of the exact bytes the provider published.

The application saves a selection: the recordId and bindingId it chose, and the two revisions it chose under. A selection is public metadata, not a credential. Whether to trust endpointUrl is decided by the application’s own Evidence configuration, and the call to it never passes through Discovery. The Discovery namespace of the Registry Stack client runs these searches and saves selections from Rust, Node.js, or Python.

SymptomCauseFix
A service stops at startupPort 38090 or 38080 is in useStop the process using the port, then start the service again
discoveryctl package cannot fetch an originThe publication server is not runningStart it, then package again; a failed run writes no package
discoveryctl package refuses the output directorydiscovery-project/package exists from an earlier runRemove it, then package again

Discovery is still running. Package and run a Discovery index continues from here, with HTTPS origins and a pinned package. To stop instead, press Ctrl+C in the first shell and remove discovery-project.

How Registry Discovery works explains why trust stays with the application.