Skip to content
Registry StackDocsv0.38.0

Package and run a Registry Discovery index

View as Markdown

Use this guide when you operate a Registry Discovery catalog for known Evidence Gateway and Registry Relay providers. You maintain provider URLs and evidence-type mappings, package one immutable index on demand, then restart the read-only service with that package.

Use Registry Discovery to curate public advertisements from providers your catalog operator has already chosen to index. It is useful when an application must find an Evidence Gateway by evidence type, or a Registry Relay by its public semantics, before it performs its normal product-specific connection.

You need these inputs:

  • A provider-supplied public description URL, such as https://<provider-host>/catalog.jsonld. Record the URL out of band with the provider.
  • A local directory for the catalog project, a new output directory for the package, and a separate deployment runtime file.
  • The discoveryctl and discovery binaries.

The provider description uses the closed Registry Discovery JSON-LD profile. The profile is a selected alignment with Data Catalog Vocabulary (DCAT) 3, DCAT-AP 3.0.1, and BRegDCAT-AP terms. It does not claim complete DCAT-AP or BRegDCAT-AP conformance.

Registry Stack releases publish the discovery-<tag>-linux-amd64 runtime asset. The first release eligible to publish a matching discoveryctl-<tag>-linux-amd64 authoring asset is v0.38.0. For a published v0.38.0 or later release, choose <tag> from the latest release and authenticate both assets through the shared SHA256SUMS procedure at https://github.com/registrystack/registry-stack/blob/<tag>/release/VERIFY.md, then install the exact pair:

Terminal window
tag="${TAG:?set TAG to the selected published tag}"
mkdir -p ~/.local/bin
for binary in discovery discoveryctl; do
install -m 0755 "${binary}-${tag}-linux-amd64" "$HOME/.local/bin/${binary}"
done
export PATH="$HOME/.local/bin:$PATH"
discovery --version
discoveryctl --version

Earlier releases contain the Linux runtime asset but require a source build for discoveryctl. For another platform, build both binaries from the same Registry Stack checkout:

Terminal window
cargo build --release --locked -p registry-discovery -p registry-discoveryctl
export PATH="$PWD/target/release:$PATH"

The release also publishes ghcr.io/registrystack/discovery:<tag>. Authenticate its digest through the release manifest and deploy that digest instead of the mutable tag. The image runs /usr/local/bin/discovery as the Distroless cc-debian13 nonroot user, with /etc/registry-discovery/runtime.yaml as its default runtime file. Mount that file and the complete package directory read-only. Discovery keeps no writable local state.

Create <discovery-project>/origins.yaml. Each enabled origin is fetched only during packaging.

schemaVersion: registry-discovery/origins/v1alpha1
origins:
- originId: evidence-provider
catalogUrl: https://<provider-host>/catalog.jsonld
profile: registry-discovery-v1alpha1
enabled: true

Use a unique originId for each approved URL. Production origins use HTTPS. The --allow-loopback option exists only for a local development origin.

Create <discovery-project>/mappings/adult-status.yaml for each requirement that needs evidence-type resolution. A mapping can offer alternatives, but every ID in one alternative is required together.

schemaVersion: registry-discovery/evidence-mapping/v1alpha1
mappingId: urn:example:mapping:adult-status
mappingAuthorityId: urn:example:authority
requirementId: urn:example:requirement:adult-status
jurisdiction: urn:example:jurisdiction
alternatives:
- evidenceTypeListId: urn:example:list:adult-status
evidenceTypeIds:
- urn:example:evidence-type:adult-status

jurisdiction is optional. Use the same exact identifier in a resolve request when your mapping declares one.

Run the offline check before packaging.

Terminal window
discoveryctl check --project "<discovery-project>"

Expected output reports the validated origin and mapping counts:

valid origins=1 mappings=1

The check reads the two authoring inputs but does not contact the provider URL.

Package into a new directory when the approved provider descriptions are available.

Terminal window
discoveryctl package \
--project "<discovery-project>" \
--output "<deployment-directory>/discovery-package" \
--revision "<source-revision>"

Expected output reports the package digest and independent semantic revisions:

packaged packageDigest=sha256:<64-lowercase-hex-digits> catalogRevision=sha256:<64-lowercase-hex-digits> mappingRevision=sha256:<64-lowercase-hex-digits>

The command fetches every enabled origin once, records the exact fetched-byte digest and fetch time, and records builtAt after every origin has been collected and the semantic revisions compile. It writes discovery-index.json, optional REVISION, and SHA256SUMS into a directory that must not already exist. The package digest is the SHA-256 digest of the exact SHA256SUMS bytes.

Packaging the same compiled index bytes and revision twice produces the same package digest. A new collection records new originFetchedAt and builtAt provenance, so its package digest may change even when catalogRevision and mappingRevision stay the same. Build a new directory and deploy it as a unit. Do not edit a package in place.

Place this runtime.yaml outside the package directory. Set package.root to its absolute path and copy the reported package digest into package.expectedDigest when you want to pin the deployment.

apiVersion: registry.registrystack.org/discovery-runtime/v1alpha1
kind: DiscoveryRuntimeConfig
listener:
bind: 127.0.0.1:8080
package:
root: /srv/registry-discovery/package
expectedDigest: sha256:<digest-of-SHA256SUMS>
limits:
maximumRequestBytes: 65536
maximumResponseBytes: 1048576
maximumResultRecords: 100
maximumResultAlternatives: 100
requestTimeoutSeconds: 10
shutdownTimeoutSeconds: 10
logLevel: info

Start the new revision after deploying the complete package directory.

Terminal window
discovery --runtime-config "<absolute-deployment-directory>/runtime.yaml"

The runtime file is read through the shared runtime configuration loader, as the other Registry Stack runtimes read theirs. Its path must be absolute and free of symbolic links, listener.bind is required and takes an IP address host, and a string value may name an environment variable as ${NAME}, ${NAME:-default}, or ${NAME:?message}. A key from the earlier grammar, such as schemaVersion, listener.address, or indexPath, is refused with the name of its replacement.

Before binding the listener, the runtime recomputes every SHA256SUMS entry, refuses changed, missing, or extra files by name, checks package.expectedDigest when set, then parses the exact verified discovery-index.json bytes. The process remains running with that captured index. Verify readiness from a network location that can reach the listener.

Terminal window
curl --fail-with-body "http://127.0.0.1:8080/ready"
{"status":"ready"}

The runtime accepts only its listener, package location and optional pin, limits, and log level. It does not carry provider credentials, origin-fetch configuration, mappings, or application trust configuration. The runtime acquires one of four request-body permits before reading a body and holds the permit through request handling. It also rejects malformed percent escapes, invalid UTF-8 query values, duplicate media-type headers, and request media parameters other than UTF-8 JSON.

Resolve an application requirement to its evidence-type alternatives.

Terminal window
curl --fail-with-body \
-H 'Content-Type: application/json' \
--data '{"requirementId":"urn:example:requirement:adult-status","jurisdiction":"urn:example:jurisdiction"}' \
"http://127.0.0.1:8080/v1/evidence-types/resolve"

The response contains mappingRevision and the configured alternative with its mapping authority.

{"requirementId":"urn:example:requirement:adult-status","jurisdiction":"urn:example:jurisdiction","mappingRevision":"sha256:<64-lowercase-hex-digits>","alternatives":[{"evidenceTypeListId":"urn:example:list:adult-status","evidenceTypeIds":["urn:example:evidence-type:adult-status"],"mappingId":"urn:example:mapping:adult-status","mappingAuthorityId":"urn:example:authority"}]}

Search the catalog for a public Evidence Gateway advertisement. Copy the selected recordId, endpointUrl, and origin provenance from the result into your application selection record.

Terminal window
curl --fail-with-body --get \
--data-urlencode 'serviceKind=evidence' \
--data-urlencode 'evidenceType=urn:example:evidence-type:adult-status' \
"http://127.0.0.1:8080/v1/services"

The response has a catalogRevision and an items array. Each item carries the provider endpoint, its advertised capability IDs, and the origin URL, content digest, and fetch time.

For Registry Relay, use serviceKind=relay and one or both of semanticClass and operationFamily as repeated query filters. A protected-only Relay can advertise neither public semantic class nor operation family.

Discovery selection is metadata only. Before an application creates a native request, use its own Evidence Gateway or Registry Relay trust configuration to accept or reject the selected provider, then invoke the selected endpointUrl directly with that product’s native client. Do not send credentials or native request data to Registry Discovery.

SymptomCauseFix
discoveryctl check failsThe origins or mapping document is not in the closed authoring shape.Correct the schema version, identifiers, and duplicate values, then run the offline check again.
discoveryctl package failsAn enabled provider URL could not be fetched safely, did not return the exact profile media type, or the output directory already exists.Confirm the provider’s public description deployment and choose a new output directory. Keep the previous package running until packaging succeeds.
Startup says the package does not match SHA256SUMSA listed file changed, is missing, or an extra file appeared in the package directory.Redeploy the whole directory produced by discoveryctl package.
Startup reports different expected and found package digestspackage.expectedDigest pins a different package.Deploy the pinned package or update the pin to the reviewed packageDigest.
A search returns no itemsThe index contains no advertisement that matches every supplied filter.Inspect the advertised capability IDs and use a narrower or correct filter set.
Native connection is refusedThe application did not accept the selected provider under its local product trust configuration.Resolve the native Evidence Gateway or Registry Relay trust decision before retrying the direct connection.