Skip to content

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

ghcr.io/trianalab/pacto-dashboard:<version>

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_DIR is an environment variable only — there is no --cache-dir flag. When it is unset, the dashboard resolves the cache directory from the bundle store's CacheDir() (defaulting to ~/.cache/pacto/oci).

Data Sources

The dashboard auto-detects available data sources at startup:

  • oci: Enabled when PACTO_DASHBOARD_REPO is set, or automatically discovered from K8s resolvedRef fields 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 distinct cache source 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.yaml is 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.resolvedRef on 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-Origin header is emitted, and cross-origin mutating requests are rejected with 403. 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 (or PACTO_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.