On this page
Using the registry
CommonLayer distributes container images and Helm charts from its own OCI registry, which anyone can pull from anonymously and only the platform can push to. This guide explains the names and tags, how to pull images and install charts, how anonymous access works, and what the preservation and retention rules mean for you.
Status. The registry, its token service, mirroring, promotion, preservation checks and
retention planning are implemented and were tested against a local CNCF Distribution
3.1.2 (WP-11). The publish drill (WP-70g, locally) promoted an image and a chart through
the real pipeline and pulled them anonymously with docker pull and helm pull. No
production registry is running and no artifact has been published to
registry.commonlayer.org; the host name below is the intended public name, and a
deployment may use another one (configuration registry.public_host).
Names
| Reference | Content |
|---|---|
registry.commonlayer.org/<project>[-<variant>] | container images, for example registry.commonlayer.org/nginx, registry.commonlayer.org/postgresql |
oci://registry.commonlayer.org/charts/<chart> | Helm charts, for example oci://registry.commonlayer.org/charts/postgresql-ha |
registry.commonlayer.org/base | the CommonLayer base image |
A repository path belongs to one artifact and is never reused.
Tags
| Tag | Example | Mutable |
|---|---|---|
<upstream version>-r<revision> | 1.30.6-r2 | no: the platform refuses to move it (database trigger) |
<upstream version> | 1.30.6 | yes, moves to the newest revision |
<version line> | 1.30 | yes |
| channel | stable, mainline | yes |
latest | yes |
A revision is a rebuild of the same upstream version (for example after a base image or dependency fix). Every tag move is recorded in the tag history and release history, which the portal shows next to the digest.
Deploy by digest. Tags help you find a digest; they are not an identity.
docker pull registry.commonlayer.org/nginx@sha256:<digest>
In Kubernetes manifests, use image: registry.commonlayer.org/nginx@sha256:<digest> (you may
keep a tag in front of the @ for readability; the digest decides).
Pulling
No login is needed for public projects:
docker pull registry.commonlayer.org/nginx:1.30.6-r1
helm pull oci://registry.commonlayer.org/charts/nginx --version <chart version>
helm install web oci://registry.commonlayer.org/charts/nginx --version <chart version>
Behind the scenes the client follows the Docker token flow: the registry answers 401 with
a realm pointing at the platform (/registry/token), the platform issues a short-lived
(5 minutes) ES256 token, and the client retries with it. Anonymous callers receive pull
on repositories of public projects and nothing else; a repository that does not exist or
belongs to a non-public project yields an empty access list. Token requests are limited
per IP (default 300 per minute).
Nobody can push: push and delete are granted only to the platform's promoter identity,
used by the worker. (The API, as the token realm, holds the same signing key; see the
threat model, open item O7.) In the publish drill an anonymous token request for
pull,push was granted pull only. Content reaches the registry only through the
verification pipeline (ADR-0009).
Images
Every image follows the image standard:
- runs as UID/GID
10001:10001, works with a read-only root filesystem when the documented writable paths are mounted, has no package manager, shell tools beyond a reduced BusyBox, or network clients; - configuration in
/etc/commonlayer/<app>, data in/var/lib/commonlayer/<app>, logs to stdout and stderr, scratch in/tmp; - secrets can be passed as files with
<VAR>_FILE; linux/amd64andlinux/arm64in one index (arm64 builds run only on native arm64 runners, which this repository does not have yet; no arm64 image has been built; see the implementation status).
Coming from images that run as UID 1001 or root, existing volumes need their ownership changed; the Bitnami migration guides cover this per application.
Each project documents its image in its own README: projects/nginx/README.md,
projects/postgresql/README.md, projects/valkey/README.md and
projects/base/README.md.
Charts
Every chart follows the chart standard: secure
defaults (runAsNonRoot, UID 10001, readOnlyRootFilesystem, all capabilities dropped,
RuntimeDefault seccomp, no service-account token), the same values block names in every
chart, values.schema.json, and an image reference that defaults to the released image
digest:
image:
registry: registry.commonlayer.org
repository: nginx
tag: "1.30.6-r1" # informational when digest is set
digest: "sha256:…" # set by the release; takes precedence
image.digest: "" is the explicit way to opt out of digest pinning.
PostgreSQL ships two charts: postgresql (single instance, not highly available) and
postgresql-ha (a CloudNativePG Cluster; needs the CloudNativePG operator installed
separately). Its install, failover, rolling update and helm test passed once on kind on
a GitHub runner; the reorganised test failed on its next run, and backups have never been
exercised (ADR-0015).
Verification
Before deploying, verify signatures and attestations; see
verifying artifacts. The platform publishes for every digest the
verification checks, signatures, attestations, SBOMs, scans and exact verification
commands (GET /api/v1/digests/{digest} and …/verify-instructions).
Preservation and retention
- Preservation. Every promoted digest is marked preserved. A daily job
(
registry.verify_preservation) checks that the manifest and all blobs still exist in the registry and that the manifest still hashes to its digest; failures raise an alert. If a project's GitHub organization disappears, its promoted artifacts, SBOMs, signatures, attestations and metadata remain available from CommonLayer. - Retention. In the default configuration nothing that was ever promoted is deleted;
only failed or abandoned uploads are candidates. Retention runs as a plan
(
registry.plan_retention, weekly, dry run by default) and deletes nothing unless an operator setsregistry.retention.mode = execute. A digest is protected when it is the current digest of a version that is not yanked, referenced by a tag, part of a protected index, referenced by a promoted chart, has an open finding or is named in a published security advisory (whatever its state, a withdrawn digest included), was promoted less thanregistry.retention.min_age_days(default 365) ago, or is covered by the preservation guarantee (default: every release). - Deprecated and yanked versions stay pullable by digest; their status is shown on the
artifact page and in the API (
support_status).
Pull statistics
The registry notifies the platform of pulls; registry.aggregate_pulls rolls them into
daily counts per artifact (manifest pulls only, not blob downloads), published per
artifact and day at GET /api/v1/projects/{slug}/artifacts/{name}/pulls (1–365 days,
zero-filled; gRPC RegistryService.GetPullStats) and on the artifact page. No IP
addresses or user agents are published.
Local development registry
The development stack runs the CommonLayer registry on localhost:5000 with token
authentication against a locally running API (http://localhost:8080/registry/token), and
a plain source registry on localhost:5001 that stands in for GHCR. See
CONTRIBUTING.md.