Skip to content

Deploy Pipeline

The deploy pipeline is Norn's core orchestration flow. It takes an app from source code to running Nomad allocations in 11 sequential steps. Canary policy can insert an additional evaluation step. For a deploy rehearsal that stops before runtime mutation, use norn preflight.

Pipeline Steps

1. Clone

Checks out the git repository at the specified ref (commit SHA, branch, or tag). Uses NORN_GIT_TOKEN or NORN_GIT_SSH_KEY for private repos.

2. Source admission

In production, rejects local or dirty source, missing build/registry policy, strict-secret violations, services without health checks, and endpoint-backed multiple allocations when no regional Traefik origin is configured.

3. Build

In development, builds a Docker image using the configured Dockerfile and can push it to NORN_REGISTRY_URL. In production, build.image must instead name an externally published image@sha256:.... This keeps signing credentials out of Norn and separates publisher authority from deploy authority. The external builder is responsible for tests, maximum-provenance/SBOM attestations, vulnerability approval, and signing the digest with the norn.git.sha=<full commit> annotation.

4. Artifact admission

Requires image@sha256:... in production, resolves that exact digest from the configured registry, verifies its Cosign signature and source-commit annotation, then runs Trivy against NORN_ARTIFACT_DENY_SEVERITIES (HIGH and CRITICAL by default). Rollback repeats registry, signature, and vulnerability admission before Nomad submission.

5. Test

Runs the test command from build.test if defined. A non-zero exit code fails the pipeline. Skipped if no test command is configured.

6. Snapshot

Creates a PostgreSQL database snapshot (pg_dump) if the app declares infrastructure.postgres. Prefer the versioned /api/v1 control route or the web/native clients to queue a durable restore using the exact inventory filename. The current CLI uses the legacy synchronous route: norn snapshots <app> restore <compact-utc-timestamp> --yes --pre-restore, and accepts the timestamp only when it matches exactly one inventory entry.

7. Migrate

Runs database migrations from the migrations directory if specified. Migrations are applied to the database declared in infrastructure.postgres.database.

8. Submit

The core translation step:

  1. Resolves secrets from SOPS-encrypted secrets.enc.yaml
  2. Provisions declared infrastructure.objectStorage buckets and app-scoped S3 env
  3. Resolves every declared region (or the compatible local region)
  4. Calls nomad.TranslateForRegion() and filters processes by placement
  5. Submits scheduled jobs only in their eligible region (primary by default)
  6. Records each regional evaluation and readiness state in deployment_regions

9. Healthy

Polls Nomad independently in every target region. A region begins with active traffic weight zero; after every eligible allocation is healthy, Norn promotes that region to its declared trafficWeight. Failure leaves its weight at zero and records the regional error for rollback and operator inspection.

The Nomad update strategy (set by the translator) handles rolling updates:

  • MaxParallel: 1 — one allocation at a time
  • MinHealthyTime: 30s — must be healthy for 30 seconds
  • AutoRevert: true — auto-rollback on health failure

10. Forge

Updates cloudflared tunnel ingress rules if the app defines endpoints. When NORN_INGRESS_URL is configured, every public hostname maps to the stable regional Traefik origin. Traefik then balances over passing Consul instances.

11. Cleanup

Removes temporary build artifacts (cloned repo, build context).

Preflight Pipeline

norn preflight <app> [ref] runs the front half of the deploy path without creating a deployment record or touching Nomad, Postgres snapshots, migrations, or cloudflared routing.

StepWhat it checks
validateRuns infraspec validation using the configured Norn network mode
clonePrepares the same source tree deploy would use, including repo auth and local fallback behavior
inspectVerifies infraspec.yaml, the configured Dockerfile, declared encrypted secrets, and known source footguns
buildRuns a local Docker build with the same build args as deploy, but does not push to the registry
testRuns build.test from the prepared source tree

Preflight warnings are emitted as saga progress events. They do not fail the run unless they reveal a hard deploy blocker. Current warnings include disabled repo.autoDeploy and Go module replace directives pointing at parent directories, because those can make host-side tests differ from the Docker build context.

The Docker image/layer cache may remain locally after preflight. Norn runtime state does not change.

Sequence Diagram

Real-Time Progress

The pipeline broadcasts WebSocket events at each step transition:

Event TypePayloadWhen
deploy.step{step, sagaId, status}Step starts, completes, or fails
deploy.failed{sagaId, error}Pipeline fails
deploy.completed{sagaId, imageTag}Pipeline succeeds
preflight.step{step, sagaId, status}Preflight step starts, completes, or fails
preflight.progress{sagaId, message}Preflight warning or informational check
preflight.failed{sagaId, error}Preflight fails
preflight.completed{sagaId, imageTag}Preflight succeeds

The CLI connects to the WebSocket during norn deploy and norn preflight and renders a live progress display. The UI dashboard updates the deploy panel in real time.

Saga Event Log

Every step transition is recorded as an immutable saga event. See Saga Events for the full event model.

Provenance

Deployments record source provenance in the deployment row as well as saga events. norn status, norn ops platform, and deployment history can show:

  • sourceKind: git_clone, local_copy, local_fallback, or rollback
  • sourceRef: the requested git ref, local fallback ref, or rollback source deployment
  • sourceDirty: whether the local source tree had uncommitted changes
  • sourceChanges: a value-safe list of changed file paths

Dirty local builds also receive an image tag suffix ending in -dirty, making runtime state visibly different from a clean commit build.