Skip to content
Registry StackDocsDevelopment (unreleased)

Build and deploy a Registry Evidence project

For the assertion provider and operator

View as Markdown

You are the operator who puts the proved adult-status project in front of real callers: bind it to a host, package it into a candidate whose digest you can repeat, activate it, and prove its dependencies before it opens a listener.

Outcome
An activated Registry Evidence candidate with a recorded package digest and passing dependency preflight.
Time
About 30 minutes
Level
Operator handoff with synthetic data and a local signer
Prerequisites
The proved adult-status projectThe Evidence component installed for rstackFree loopback port 18090

You continue the adult-status project from Your first assertion. The deployment reaches the same synthetic source on port 8081 and trusts the same local token issuer on port 8082. If you stopped the source, start it again in another terminal:

Terminal window
python3 serve-source.py \
--port 8081 \
--token-file .generated/secrets/synthetic-source-token

If you stopped the development session, start it again from the project directory, so the token issuer answers on 8082:

Terminal window
rstack evidence dev start . \
--target local-target.yaml \
--evidence-port 18080 \
--issuer-port 8082

The assertion provider owns the Evidence project: assertionDefinitions, sources, functions, selectorProfiles, outputs, and each grantCeiling. You own the environment, in a deployment target kept beside the project. Step out of adult-status and create one from the project’s local settings:

Terminal window
cd ..
rstack evidence target new ./deploy-target --settings adult-status/local-target.yaml
Created Evidence target ./deploy-target

deploy-target/target.yaml names the project, the authority file that grants callers access, and every host binding. target new refuses an existing destination.

deploy-target/target.yaml
id: local
project: standalone-evidence
package:
root: .generated/package
authority: dev-authority.yaml

Give the deployment its own signing key:

Terminal window
umask 077
rstack evidence keygen signing --output-dir deploy-target/secrets \
--public-output deploy-target/public-keys/signing.jwk.json
wrote deploy-target/secrets/signing-p256-private-jwk
wrote deploy-target/public-keys/signing.jwk.json

keygen writes private material only to owner-only files, never to standard output. Production signs through Vault or OpenBao Transit instead; the next tutorial moves the signer there.

Point the package root, secret root, public key, and audit path at this host’s directories, relative to the target directory:

deploy-target/target.yaml
package:
root: .generated/package
root: package
deploy-target/target.yaml
secretProviders:
file:
root: .generated/secrets
root: secrets
signer:
type: local-jwk
algorithm: ES256
privateKeyRef: secret:file/signing-p256-private-jwk
publicJwkFile: .generated/secrets/signing-p256-public.jwk.json
publicJwkFile: public-keys/signing.jwk.json
deploy-target/target.yaml
audit:
path: .generated/audit/evidence.jsonl
path: audit/evidence.jsonl

The development session holds 18080, so listen on 18090, changing the bind and the public origin together:

deploy-target/target.yaml
publicOrigin: http://127.0.0.1:8080
publicOrigin: http://127.0.0.1:18090
trustDomain: urn:example:trust:standalone-evidence
listener:
bind: 127.0.0.1:8080
bind: 127.0.0.1:18090

The bind must be a loopback or private address unless listener.networkExposure says container-private. Read back what the target selects, offline:

Terminal window
rstack evidence target explain deploy-target/target.yaml adult-status
Target: local
Project: standalone-evidence
Authority: dev-authority.yaml
Access profiles: 1

Ask whether the target is fit for production:

Terminal window
rstack evidence check adult-status --target deploy-target/target.yaml --production
Evidence project check: domain-refusal
Project: adult-status
Target: deploy-target/target.yaml
error[evidence.target.production-assurance-required] deploy-target/target.yaml:/assuranceProfile
--production requires production or evidence-grade target assurance
next: Correct the selected project or target artifact and rerun check.
1 error, 0 warnings in 1 file

A local key file cannot meet a production assuranceProfile, so this target declares none and stays a rehearsal. Package it into a new directory outside the project:

Terminal window
rstack evidence package adult-status --target deploy-target/target.yaml --output candidate
Package digest: sha256:<digest>
Package: candidate/bundle
Runtime: candidate/runtime.yaml
Authority: candidate/compiled-authority.yaml
Provision secret:file/audit-hmac-key
Provision secret:file/signing-p256-private-jwk
Provision secret:file/subject-binding-hmac-key
Provision secret:file/synthetic-source-token
Target runtime paths and deployment secret material remain unverified until `evidencectl doctor --runtime-config candidate/runtime.yaml`.

candidate is the deployment candidate. The package digest identifies its immutable bundle/: the same project and target produce the same digest, so record it. Editing the target, even its port, changes the digest but no definition’s configurationRevision, which moves only with the definition’s semantics (How Registry Evidence works). package first checks the bundle and runs every fixture through the evidence binary on PATH (or EVIDENCE_BIN), contacting no source, issuer, or signer.

List the candidate to see the three parts that travel to the host:

Terminal window
ls candidate
bundle
compiled-authority.yaml
runtime.yaml

bundle/ is the package the digest names, and it holds no secret. compiled-authority.yaml is the access authority you activate next. runtime.yaml records the target’s paths as absolute paths, so write a target for another host with that host’s paths.

Only the candidate travels to the target host, here this same directory. Provision each secret the summary named beneath secretProviders.file.root. The source token is the source owner’s to issue, and the running source accepts only the one it was started with, so copy that one:

Terminal window
rstack evidence keygen secret --output deploy-target/secrets/audit-hmac-key
rstack evidence keygen secret --output deploy-target/secrets/subject-binding-hmac-key
cp adult-status/.generated/secrets/synthetic-source-token deploy-target/secrets/
cp -R candidate/bundle deploy-target/package
wrote deploy-target/secrets/audit-hmac-key
wrote deploy-target/secrets/subject-binding-hmac-key

Activate the authority against the installed package:

Terminal window
rstack evidence runtime authority activate --runtime-config candidate/runtime.yaml \
--document candidate/compiled-authority.yaml
ACTIVATED sha256:<revision> sha256:<snapshot> sequence=1

Activation records the authority snapshot for the next start; a running process keeps its own until restart. Check the installed package, which reads no secret and contacts no network service:

Terminal window
rstack evidence runtime check --runtime-config candidate/runtime.yaml
Evidence package sha256:<digest> passed check (4 requirements)
0 errors, 0 warnings in 23 files

The digest matches the one package printed. Then prove the startup dependencies: doctor resolves every secret, proves the signer, opens the audit log, and fetches the token issuer’s keys, as startup does. Name the runtime file by absolute path:

Terminal window
rstack evidence doctor --runtime-config "$PWD/candidate/runtime.yaml"
Dependency preflight passed for <runtime-file>

An unreachable dependency refuses with evidence.deployment.dependency-unavailable. doctor opens no listener, sends no evidence request, appends no application audit event, and does not call the source.

Start the service in a terminal of its own; it logs evidence service listening with the package digest:

Terminal window
rstack evidence runtime serve --runtime-config "$PWD/candidate/runtime.yaml"

Route traffic through your TLS front only after the readiness request succeeds:

Terminal window
rstack evidence api /ready --url http://127.0.0.1:18090

Create deployment-check-client.json by following Create the client profile. Use this deployment’s reviewed endpoint and trust pins, plus the client registration, assertion audience, resource, and scopes issued for that endpoint. A loopback-only smoke may use --local-loopback-discovery; a deployed call uses its HTTPS origin and reviewed pinned trust after the deployment signer has been provisioned. Do not carry the development session’s identity or discovery settings into this profile.

Prepare a new synthetic request from that profile. This discovers the deployment’s published contract and retains the pinned verification context before any response exists:

Terminal window
rstack evidence request prepare \
--profile deployment-check-client.json \
--requirement urn:example:requirement:adult-status:v1 \
--subject record-id=adult \
--name deployment-check

This creates owner-only .evidence/requests/deployment-check/request.json, .evidence/requests/deployment-check/verification.json, and .evidence/requests/deployment-check/curl.config. The curl config is a raw-HTTP handoff and is not input to rstack evidence api. Create an owner-only destination for a fresh, short-lived access token for the same registered client, resource, and scopes:

Terminal window
umask 077
install -m 600 /dev/null "<owner-only-token-file>"

Have your secret-management path write the token into that file. Replace https://<evidence-host> with the same endpoint the profile names, then send the emitted request and verify the response against the emitted retained context:

Terminal window
rstack evidence api /v1/evidence \
--url 'https://<evidence-host>' \
--token-file "<owner-only-token-file>" \
--input .evidence/requests/deployment-check/request.json \
--accept application/jose+json \
--output .evidence/requests/deployment-check/response.jws.json
rstack evidence verify .evidence/requests/deployment-check/response.jws.json \
--context .evidence/requests/deployment-check/verification.json \
--output .evidence/requests/deployment-check/verified.json

The verification command must print VERIFIED before you inspect the assertion. Remove the token file through the same secret-management path after the check. In production only, where the deployment ships audit.path to an append-only audit store, confirm that the request’s access-attempt and disclosure-release entries, which share one correlation, reached that store.

Configure Transit signing for Registry Evidence