Dashboard Container¶
The Pacto dashboard is published as a container image for production and Kubernetes deployments. It provides the same contract exploration experience as the CLI's pacto dashboard command — dependency graphs, version history, interfaces, configuration schemas, and diffs — in a deployable container.
Image¶
The image tag always matches the Pacto release version (e.g., 1.2.3). There is no latest tag. The container runs the exact pacto binary for that version.
Quick Start¶
# Run with OCI registry sources
docker run -p 3000:3000 \
-e PACTO_DASHBOARD_REPO=ghcr.io/org/svc-a,ghcr.io/org/svc-b \
ghcr.io/trianalab/pacto-dashboard:1.2.3
# Run with registry authentication
docker run -p 3000:3000 \
-e PACTO_DASHBOARD_REPO=ghcr.io/org/svc-a \
-e PACTO_REGISTRY_TOKEN=ghp_xxx \
ghcr.io/trianalab/pacto-dashboard:1.2.3
Local Development¶
Build and run the dashboard container locally using Make:
# Build the image (tagged with current git version)
make docker-build
# Build and run (mounts ~/.kube/config and ~/.cache/pacto automatically)
make docker-run
Environment Variables¶
| Variable | Description | Default |
|---|---|---|
PACTO_DASHBOARD_HOST |
Bind address for the server | 0.0.0.0 (in image), 127.0.0.1 (CLI) |
PACTO_DASHBOARD_PORT |
HTTP server port | 3000 |
PACTO_DASHBOARD_NAMESPACE |
Kubernetes namespace filter (empty = all) | "" |
PACTO_DASHBOARD_REPO |
Comma-separated OCI repositories to scan | "" |
PACTO_DASHBOARD_DIAGNOSTICS |
Enable source diagnostics panel (true) |
false |
PACTO_CACHE_DIR |
OCI bundle cache directory | /home/pacto/.cache/pacto/oci |
PACTO_NO_CACHE |
Disable OCI bundle caching (1) |
0 |
PACTO_NO_UPDATE_CHECK |
Disable update checks (1) |
1 (set in image) |
PACTO_REGISTRY_USERNAME |
Registry authentication username | "" |
PACTO_REGISTRY_PASSWORD |
Registry authentication password | "" |
PACTO_REGISTRY_TOKEN |
Registry authentication token | "" |
All PACTO_DASHBOARD_* variables map to the corresponding --host, --port, --namespace, --diagnostics, and --cors-origin CLI flags. OCI repositories can be passed as oci:// positional arguments on the CLI; in the container, use the comma-separated PACTO_DASHBOARD_REPO env var instead.
Note:
PACTO_CACHE_DIRis an environment variable only — there is no--cache-dirflag. When it is unset, the dashboard resolves the cache directory from the bundle store'sCacheDir()(defaulting to~/.cache/pacto/oci).
Data Sources¶
The dashboard auto-detects available data sources at startup:
- oci: Enabled when
PACTO_DASHBOARD_REPOis set, or automatically discovered from K8sresolvedReffields when the Kubernetes source is active. Scans OCI registries for published contracts — providing full contract bundles, version history, interfaces, and diffs. Materialized bundles on disk (/home/pacto/.cache/pacto/oci/) are used internally by the OCI source to enrich version data without appearing as a separate source. - cache: The on-disk OCI cache (
~/.cache/pacto/oci/) is internal to the OCI source and normally stays hidden. It surfaces as a distinctcachesource only when no live registry is reachable and the cache already has entries — an offline baseline of previously pulled bundles. When both a live registry and the cache hold data, OCI takes priority and the cache remains internal. - k8s: Enabled when a valid kubeconfig is mounted or when running inside a Kubernetes cluster (in-cluster config). Provides runtime state from the Pacto operator.
- local: Enabled when a
pacto.yamlis found in the working directory (mount via volume).
Kubernetes + OCI hybrid mode¶
When deployed alongside the Pacto operator in Kubernetes, the dashboard automatically discovers OCI repositories from the resolvedRef fields in Pacto CRD statuses — no PACTO_DASHBOARD_REPO needed. This creates a hybrid view: runtime truth from the operator + contract truth from OCI, giving you version history, interface details, configuration schemas, and diffs for every service the operator manages.
Prerequisites. Hybrid mode only activates when all of the following hold:
- A mounted kubeconfig or in-cluster config so the Kubernetes source is active.
- The Pacto operator is running and has populated
status.resolvedRefon the Pacto resources to discover. - The discovered registries are reachable and (for private repositories) authenticated via
PACTO_REGISTRY_*credentials.
If any prerequisite is missing — no resolvedRef, an unreachable registry, or missing credentials — the dashboard silently degrades to k8s-only: it still shows runtime state from the operator, but without the OCI-backed version history, interfaces, schemas, and diffs.
Kubernetes Source¶
To enable the Kubernetes data source, mount a kubeconfig:
docker run -p 3000:3000 \
-v ~/.kube/config:/home/pacto/.kube/config:ro \
-e PACTO_DASHBOARD_NAMESPACE=production \
ghcr.io/trianalab/pacto-dashboard:1.2.3
When running inside a Kubernetes cluster, the in-cluster config is used automatically (no mount needed).
Local Source¶
To scan a local contract directory:
docker run -p 3000:3000 \
-v /path/to/contracts:/data:ro \
ghcr.io/trianalab/pacto-dashboard:1.2.3 \
dashboard /data
Operational Endpoints¶
| Endpoint | Description |
|---|---|
GET /health |
Returns {"status": "ok", "version": "..."}. Use for liveness and readiness probes. |
GET /metrics |
Returns {"serviceCount": N, "sourceCount": N}. |
GET /openapi |
OpenAPI 3.1 specification (includes server URL matching the bind address). |
GET /docs |
Interactive API documentation. |
The image includes a Docker HEALTHCHECK that polls /health every 10 seconds.
Security¶
The dashboard is a read-mostly observability UI, but a few endpoints mutate
local state (POST /api/resolve, POST /api/versions, POST /api/refresh
pull and cache OCI artifacts). The server applies these protections:
- Same-origin only by default. No
Access-Control-Allow-Originheader is emitted, and cross-origin mutating requests are rejected with403. This prevents a malicious web page in the operator's browser from driving the dashboard (CSRF/SSRF). The bundled UI is served same-origin and is unaffected. - Explicit cross-origin opt-in. Pass
--cors-origin https://your-app(orPACTO_DASHBOARD_CORS_ORIGIN) to allow one trusted cross-origin client. - HTTP timeouts (
ReadHeaderTimeout,ReadTimeout,IdleTimeout) guard against slow-client (Slowloris) exhaustion, and shutdown is graceful.
The server binds to 127.0.0.1 by default. Setting --host 0.0.0.0 (as the
container image does) exposes the dashboard — including the unauthenticated
mutating endpoints — to the network, so run it only on a trusted network or
behind an authenticating proxy.
Kubernetes Deployment¶
apiVersion: apps/v1
kind: Deployment
metadata:
name: pacto-dashboard
spec:
replicas: 1
selector:
matchLabels:
app: pacto-dashboard
template:
metadata:
labels:
app: pacto-dashboard
spec:
containers:
- name: dashboard
image: ghcr.io/trianalab/pacto-dashboard:1.2.3
ports:
- containerPort: 3000
env:
- name: PACTO_DASHBOARD_REPO
value: "ghcr.io/org/svc-a,ghcr.io/org/svc-b"
- name: PACTO_REGISTRY_TOKEN
valueFrom:
secretKeyRef:
name: pacto-registry
key: token
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 3
periodSeconds: 5
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 128Mi
securityContext:
runAsNonRoot: true
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
volumeMounts:
- name: cache
mountPath: /home/pacto/.cache
- name: tmp
mountPath: /tmp
volumes:
- name: cache
emptyDir: {}
- name: tmp
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: pacto-dashboard
spec:
selector:
app: pacto-dashboard
ports:
- port: 80
targetPort: 3000
Build and Release¶
The dashboard image is built and published automatically when a new Pacto version is released. The docker job in the auto-release pipeline (.github/workflows/auto-release.yml) builds multi-architecture images (linux/amd64, linux/arm64) and pushes to ghcr.io/trianalab/pacto-dashboard with the matching version tag (without v prefix).
The image version always matches the Pacto CLI version. There is no separate versioning scheme for the dashboard container.