Registry

4 min read

How do I publish a Katalog to the registry?

Create a pattern directory with a katalog.yaml and push it:

ork push postgres:v14 ./patterns/postgres/

The minimal directory is just katalog.yaml. In practice, include a simulate.yaml and e2e.yaml — they gate the push automatically and bake a quality signal into the artifact that consumers can see before importing.

postgres/
  katalog.yaml    # required
  crd.yaml        # recommended — CRD manifest for consumers who don't have it
  cr.yaml         # recommended — sample CR
  simulate.yaml   # runs before e2e, blocks push if assertions fail
  e2e.yaml        # runs against a real kind cluster, blocks push if expectations fail
  README.md       # shown in registry UI

Katalog patterns in the registry


How do I publish a Motif?

Same command — Motifs push to ORK_MOTIFS_REGISTRY instead of ORK_REGISTRY:

ork push security-baseline:v1 ./motifs/security-baseline/

If a pattern directory contains both a katalog.yaml and a motif.yaml, one push publishes both — the Katalog to the Katalog registry and the Motif to the Motif registry.

Motif patterns in the registry


How do simulate and e2e gate publication?

When simulate.yaml and e2e.yaml are present in a pattern directory, ork push runs them automatically — simulate first, then e2e — and blocks publication if either fails.

ork push postgres:v14 ./patterns/postgres/
  → simulate runs  (< 1s, no cluster)
  → e2e runs       (kind cluster, 2–5 min)
  → artifact pushed with quality annotations

The gates are ordered deliberately. Simulate is instant — it catches template errors, wrong resource names, and wrong cycle order without spinning up a cluster. E2E runs after because there is no point provisioning a cluster when the reconciler is already broken.

The result is baked into the OCI artifact:

io.orkestra.simulate.status   passed | no-assertion | skipped
io.orkestra.e2e.status        passed | skipped | forced

ork patterns shows an E2E column. ork inspect shows both simulate and e2e status. Consumers can see what quality guarantees a pattern carries before they import it.

To skip individual gates:

ork push postgres:v14 ./patterns/postgres/ --no-simulate   # skip simulate only
ork push postgres:v14 ./patterns/postgres/ --no-e2e        # skip e2e only
ork push postgres:v14 ./patterns/postgres/ --force         # skip both

Skipping is recorded in the annotations — consumers can see it.

How simulate gates publication
How e2e gates publication


Can I use a private registry?

Yes — point Orkestra at any OCI-compatible registry:

export ORK_REGISTRY=oci://ghcr.io/myorg/katalogs
export ORK_MOTIFS_REGISTRY=oci://ghcr.io/myorg/motifs

Push and pull work identically. Credentials come from ~/.docker/config.json — run docker login before pushing.



How do I sign a pattern?

Push first, then sign:

ork push postgres:v14 ./patterns/postgres/
ork pattern sign postgres:v14

Or in one step:

ork push postgres:v14 ./patterns/postgres/ --sign

Signing uses Cosign keyless — no keys, no secrets. The ambient OIDC token in CI is the credential. In GitHub Actions this is the workflow identity; locally it opens a browser-based OIDC flow.

After signing, ork inspect shows the signer on the Signed: row without any extra flags.

Artifact Signing


How do I test signing without a real registry?

Use --sign-local or ork pattern sign --local. This pushes to ttl.sh — a free ephemeral OCI registry — signs it, and prints the exact verify and inspect commands:

# From push
ork push postgres:v14 ./ --sign-local --ttl 24h

# Or directly
ork pattern sign postgres:v14 --local --dir ./patterns/postgres/ --ttl 24h
✓ Pushed  oci://ttl.sh/ork-a3f9c2/postgres:24h
✓ Signed

  Expires in   24h
  Verify:      ork pattern verify oci://ttl.sh/ork-a3f9c2/postgres:24h --no-tlog
  Inspect:     ork inspect oci://ttl.sh/ork-a3f9c2/postgres:24h

Use --no-tlog when verifying ephemeral artifacts — the Rekor transparency log is not useful for a short-lived test artifact.


How do I require consumers to verify the signature?

Add a publish: block to katalog.yaml:

publish:
  signing:
    verify: true
    expectedIdentities:
      - github.com/myorg/postgres/.github/workflows/release.yaml@refs/heads/main

With verify: true, consumers who run ork pull --verify are blocked unless a valid signature from one of the listed identities is present.

publish: schema


How do I mark a pattern as deprecated?

Set lifecycle.maturity: deprecated and fill in lifecycle.deprecation:

lifecycle:
  maturity: deprecated
  deprecation:
    migratedTo: ghcr.io/myorg/katalogs/webapp@v2.0.0
    message: "Migrate to v2.0.0 before 2027-01-01."
    timeline:
      from: "2026-01-01"
      to: "2027-01-01"

Then push normally — ork push creates a new artifact with the deprecation metadata baked in. The previous version is not modified.

Lifecycle guide


What does maturity: alpha mean for consumers?

ork validate prints a non-fatal warning when a Katalog or an imported pattern carries maturity: alpha or maturity: beta. The warning does not block validation — it is informational.

To acknowledge the warning on a Komposer, list the pattern in lifecycle.accept.patterns:

lifecycle:
  accept:
    patterns:
      - name: cache-operator
        author: myorg

How do I suppress lifecycle warnings in ork validate?

Warnings for deprecated or pre-stable imports are suppressed by declaring acceptance on the Komposer — not by a flag, and not on the Katalog itself.

lifecycle:
  accept:
    patterns:
      - name: webapp-operator
        author: myorg

Each patterns entry covers all lifecycle concerns for that import — deprecated, alpha, beta.

Lifecycle — Accept


Further reading