The Evidence Server¶
The dashboard is the only managed component a default install deploys.
evidence.enabled is false, and turning it on has three requirements the
chart will not guess for you. Settle the first one before you publish anything,
because it decides where the contract itself has to live.
Check the registry serves the native Referrers API¶
Evidence is stored as an
OCI 1.1 referrer of the contract revision it reports on, in that contract's own
repository, and Pacto does not fall back to the tag-based scheme. So the registry
holding the contract must implement Referrers discovery. GHCR does not
qualify — which matters here more than anywhere else on this site, because every
other page publishes to ghcr.io — and neither does CNCF distribution
(registry:2, registry:3). See Evidence in
OCI for the registries this was checked against.
Publishing the contract to a conformant registry is a decision to make before
pacto push, not after helm install.
Create the trust store¶
pacto evidence keygen mints an Ed25519 pair and
names the public key after the trust binding the server reads —
<producerId>__<keyId>.pub, or a bare <keyId>.pub when there is a single
producer:
The Secret is mounted whole and read-only at /etc/pacto/trust, so each
Secret key has to be the public-key filename — which is exactly what
--from-file gives you. One --from-file per trusted producer:
kubectl create secret generic pacto-evidence-trust \
--namespace pacto-operator-system \
--from-file=keys/acme-ci__release-2026.pub
The private .key stays with the producer that signs; the cluster never needs
it. Evidence security covers rotation and
multi-producer trust.
Get the subject digest¶
A subject is one immutable contract revision, and
pacto push prints the digest of the revision it just published:
Pushed payments-api@2.1.0 -> registry.example.com/your-org/your-service-pacto:2.1.0
Digest: sha256:<64 hex characters>
Then install:
helm install pacto-operator \
oci://ghcr.io/trianalab/pacto/charts/pacto-operator \
--namespace pacto-operator-system --create-namespace \
--set evidence.enabled=true \
--set 'evidence.registry.subjects[0]=oci://registry.example.com/your-org/your-service-pacto@sha256:<digest>' \
--set evidence.trust.existingSecret=pacto-evidence-trust
- At least one subject.
evidence.registry.subjectslists the exact, immutable contract revisions evidence may be reported against, each anoci://<repo>@sha256:<digest>reference. The chart's schema rejects an empty list, sohelm installfails before anything reaches the cluster:at '/evidence/registry/subjects': minItems: got 0, want 1. It rejects a short or tag-shaped reference the same way — the digest has to be all 64 hex characters. - A trust store.
evidence.trust.existingSecretnames the Secret you created above. The chart does not enforce this one, so an install without it succeeds and the operator then exits at startup withevidence enabled but no trust secret set: signature verification is mandatory. Verification is never optional. - A registry that serves the native Referrers API, as above. Nothing checks it at install time: the chart installs, the operator starts, and the failure surfaces later as an Evidence Server that never becomes ready.
If that registry is private, there is a fourth thing you create yourself: a
kubernetes.io/dockerconfigjson Secret named by
evidence.registry.credentialsSecret. It is mounted read-only as a
DOCKER_CONFIG directory, so the server authenticates exactly the way
pacto pull does — there is no second credential model. Leave the value empty
for an anonymous or in-cluster registry. Whatever name you pick is the one
Uninstall asks you to delete.
See the Helm reference for the full value list and the Operator configuration page for the underlying controller flags each value maps to.
Verifying the install¶
evidence.enabled=true adds a third Deployment, pacto-evidence, created by
the controller the same way the dashboard is:
NAME READY UP-TO-DATE AVAILABLE AGE
pacto-dashboard 1/1 1 1 16s
pacto-evidence 1/1 1 1 14s
pacto-operator 1/1 1 1 21s
1/1 here means more than "the process started". Readiness is
GET /api/evidence/v1/ready, which answers 503 until every subject in
evidence.registry.subjects resolves in the registry and answers native
Referrers discovery. So a pacto-evidence stuck at 0/1 is nearly always a
subject the cluster cannot pull or a registry without the Referrers API — read
its own log, not the controller's:
The Service is pacto-evidence on port 8686. Producers inside the cluster
POST signed envelopes to its ingestion endpoint:
A pacto fleet outside the cluster consumes the same server's read-only
contribution by base URL — --evidence-url appends
/api/evidence/v1/targets itself, so do not include it:
kubectl port-forward -n pacto-operator-system svc/pacto-evidence 8686:8686 &
pacto fleet search --evidence-url http://127.0.0.1:8686
Nothing durable lives in the cluster: there is no PersistentVolumeClaim and no data volume, because the registry is the store. Delete and recreate the Deployment and the accepted evidence is still there. Evidence in OCI covers what is written and where; the ingestion API lists all five endpoints.