Documentation menu
Documentation
General
- CommonLayer documentation
CommonLayer is a community-funded platform for security-hardened container images and Helm charts: projects build from verified upstream source, the platform verifies, scans, mirrors and preserves…
- Implementation status
The final record of what CommonLayer implements, where, how it was tested and where that testing happened, and what is not done. It is compiled from the work-package status files in docs/status/…
API
- gRPC API
CommonLayer offers a gRPC API, package commonlayer.v1, for machine clients: CI pipelines, clctl and integrations. It calls the same application services as the REST API, so data, validation and…
- REST API
The CommonLayer REST API serves the portal, project CI and integrations under /api/v1, with JSON bodies, cookie or bearer-token authentication, RFC 9457 problem documents for errors and…
Architecture
- Architecture overview
CommonLayer is a modular monolith: one Rust workspace of domain crates, composed into three long-running processes (API, worker, scheduler) and an operator CLI, plus a Next.js portal and a CNCF…
- Database schema
CommonLayer keeps all state in one PostgreSQL database (version 16 or later; developed against 18): 121 tables and 2 views in 18 migration files (schema version 21) under…
Contributing
- Contributing
How to contribute to CommonLayer projects and to the platform: the standards every image and chart follows, how community contributions are recognised and rewarded, and which licenses apply to what.
- CommonLayer container image standard, version 1
Every CommonLayer image follows these rules. Each rule has an id; a project that cannot meet a rule records a deviation in its commonlayer.yaml:
- CommonLayer Helm chart standard, version 1
Applies to every chart published by CommonLayer. Reference implementation: templates/project-template/chart; worked example: the nginx project's chart/ (repository commonlayer-org/nginx; its tree…
- Contributor handbook
This handbook is for community contributors: people who improve a CommonLayer project without holding a maintainer assignment. It explains how contributions are recorded and reviewed, what…
- Licensing
CommonLayer involves several layers of software, and each has its own license. Applying Apache-2.0 to a Dockerfile does not relicense what the image contains. This guide explains which license…
Decisions (ADRs)
- Architecture decision records
These records explain why CommonLayer is built the way it is. ADR-0001 to ADR-0016 are the key decisions of the implementation plan (D1–D16); the later records capture decisions made while…
- ADR-0001: Modular monolith with thin binaries
The product brief forbids unnecessary microservices. CommonLayer has many domains (identity, projects, artifacts, registry, security, maintenance, funding, GitHub, notifications) that share one…
- ADR-0002: Vertical domain crates, ports and the event outbox
Domains are built in parallel by different engineers and must be testable on their own. Direct calls between domain crates would create a dependency web in which every change ripples everywhere…
- ADR-0003: SQLx with runtime-checked queries and real-database tests
SQLx can check queries at compile time against a live database or against committed offline metadata (.sqlx/). With many engineers editing migrations in parallel, offline metadata would conflict…
- ADR-0004: PostgreSQL is the job queue and the outbox; Valkey is optional
Most state changes have follow-up work: send a mail, settle a cycle, re-evaluate findings, fan out notifications. If that work is queued in a separate broker, a crash between the database commit…
- ADR-0005: Append-only double-entry ledger with database-enforced balances
CommonLayer holds money on behalf of projects and pays it to maintainers and contributors. "Funds that are not available cannot be spent" and "financial records are never edited" have to hold even…
- ADR-0006: RBAC with one static role-to-permission matrix, enforced in services
Permissions are a first-class requirement: maintainers, project admins, organization admins, billing managers and platform admins have overlapping but different rights, and several of them move…
- ADR-0007: REST with generated OpenAPI for browsers; gRPC for machine clients
The brief requires a REST API for browsers. The portal is TypeScript and should not hand-maintain response types. Machine clients (clctl, integrations) benefit from a typed RPC interface.
- ADR-0008: Server-side sessions, hashed tokens, JWTs only for the registry
The portal needs browser authentication with instant revocation (suspension, password reset, "log out everywhere"). Tokens held in browser-readable storage are exposed to any script injection.
- ADR-0009: CNCF Distribution as registry engine; the platform issues its tokens
CommonLayer must distribute images and charts that it has verified, and nothing else. Writing an OCI registry is unnecessary; the question is how to make "only verified content is published"…
- ADR-0010: Cosign, Trivy and Grype as CLIs behind traits; OSV over HTTP
Signature verification and vulnerability scanning have reference implementations (cosign, Trivy, Grype). Re-implementing them would be error-prone; depending on a single scanner would hide…
- ADR-0011: Images built from verified upstream source onto a from-scratch root
Images built FROM a distribution image inherit its package manager, shells and network tools, and their versions follow the distribution, not upstream. Distroless images drop the package database,…
- ADR-0012: Next.js App Router served same-origin with the API
The portal needs server-side rendering for public, indexable pages and first-party cookies for sessions. Cross-origin API calls would need CORS with credentials and make CSRF protection harder.
- ADR-0013: protox compiles protobuf definitions in build.rs
Tonic's usual code generation calls the system protoc binary, which is an extra, version-sensitive build dependency on every developer machine and CI image.
- ADR-0014: Money is i64 minor units plus an ISO 4217 code
Floating-point arithmetic cannot represent most decimal amounts exactly; rounding differences in splits (for example a $500 target split 40/30/10/20 percent, or a slot prorated by day) must never…
- ADR-0015: Highly available PostgreSQL through CloudNativePG
Many Helm charts call a StatefulSet with several replicas "high availability". It is not: without leader election, fencing and replica promotion, losing the primary means an outage and manual…
- ADR-0016: Apache-2.0 for the platform, template, charts and build configuration
The brief prefers a permissive license. Contributors and adopters want a patent grant. Container images contain third-party software under many licenses that CommonLayer cannot and must not relicense.
- ADR-0017: Project categories follow the manifests in the repository
The data model listed the seeded categories messaging, storage, runtime and base. The manifests written in parallel (the base image, the Bitnami migration candidates) used message-broker,…
- ADR-0018: commonlayer-observability is an allowed dependency of domain crates
The crate table in the plan did not list commonlayer-observability as a dependency of most domain crates. At the same time every metric must be recorded through the single metric catalog…
- ADR-0019: The global rate limit runs after authentication and fails open
The plan placed the global rate limit before authentication in the middleware stack. But the limits are per principal for authenticated requests (600 per minute) and per IP for anonymous ones (120…
- ADR-0020: BusyBox is rebuilt with network applets compiled out
The base image needs a POSIX shell and a few core utilities for entrypoints. Alpine's BusyBox also contains wget, nc, nslookup, sendmail, ping and administration applets. Removing only the…
- ADR-0021: PostgreSQL clusters use the ICU locale provider by default
The CommonLayer base is musl-based. musl's libc locale support does not provide the collations PostgreSQL users expect from glibc (en_US.UTF-8 and friends), so libc-based collation on musl would…
- ADR-0022: One integration-test binary per crate
Cargo builds each file in tests/ as a separate binary that links the whole dependency tree. With a dozen crates that each have a dozen test topics, that means hundreds of large binaries, long link…
- ADR-0023: An authentication gate answers 401 before body parsing
Authorization happens in the application services. A handler, however, parses the path and the body before it calls the service, so an anonymous caller of a private endpoint would receive a 422…
- ADR-0024: A workload principal for GitHub Actions OIDC submissions
Project CI submits built digests for verification. Giving CI a long-lived API token creates a secret that can leak. GitHub Actions can mint short-lived OIDC tokens that name the repository, ref…
- ADR-0025: One SSRF-safe client for user-influenced outbound HTTP
The platform fetches URLs that users influence: outbound webhook endpoints, manifest files from registered repositories, OAuth/OIDC providers. A naive client can be pointed at internal services,…
- ADR-0026: Signing identities are globs over the workflow path
The plan's example identity named release.yml. With reusable workflows, the Fulcio certificate cosign obtains names the called workflow (sign.yml, sbom.yml, …), not the caller, so an identity…
- ADR-0027: Referrer discovery without the OCI referrers API
Signatures, attestations and SBOMs are attached to an image as OCI referrers. The OCI 1.1 referrers API lists them, but CNCF Distribution 3.1.2 answers 404 on it.
- ADR-0028: Verification-policy waivers are explicit, and some checks are never waivable
The verification policy (17 checks) must block anything that is not what it claims to be, but some standards have legitimate exceptions (the base image cannot have a health check of its own; an…
- ADR-0029: SLA deadlines are permanent facts in their own table
The eligibility engine judges maintainers on whether acknowledgement and remediation deadlines were met. If a breach flag could be cleared (by acknowledging late, or by a finding reopening), past…
- ADR-0030: Embargoed findings never change a project's public security state
A project's security state (not_scanned, stale_scan, issues_overdue, issues_within_sla, no_known_issues) is public. Findings under coordinated disclosure are embargoed and visible only to the…
- ADR-0031: The ledger books the amount a provider confirms, not the amount requested
A provider can confirm a different amount than the checkout requested (partial payment, over-payment, bank transfers with the wrong amount), or confirm a payment after the contribution was marked…
- ADR-0032: Payout gates are identical for simulated and live runs
Paying people is the highest-risk operation of the platform. A simulated mode exists so the payout path can be exercised before any real money moves; if simulated runs skipped gates, the gates…
- ADR-0033: Eligibility evaluations are re-derivable and scoped to the assignment's time
Eligibility decides whether a maintainer is paid for a month. Such decisions must be explainable to the person concerned, reproducible later (for appeals and audits) and fair across hand-overs in…
- ADR-0034: The base image ships its OpenVEX statements, and derived images apply them
Scanners match vulnerabilities by package name and version. The rebuilt BusyBox keeps Alpine's package entry (ADR-0020), so Grype reports CVE-2025-60876 (BusyBox wget) although the wget applet…
- ADR-0035: Approval decisions are human-only; service accounts never hold them
Several rules put a second person in the loop: a reward above the single-approval limit needs two approvals, an exception is decided by someone other than its requester, a payout run is approved…
- ADR-0036: The processes connect as a least-privilege runtime database role
The ledger and audit tables are protected by triggers (append-only, balance guard). A role that owns the tables, or a superuser, can disable those triggers. Until WP-70a the API, worker and…
- ADR-0037: A second person confirms high-impact not_affected statements
A maintainer could close a critical finding alone by declaring it not_affected (manually or by importing an OpenVEX document). The statement is public and audited, but a single mistaken or…
- ADR-0038: Runtime settings are a closed, typed registry of policy values
WP-40 built a validated, versioned and audited key/value store for runtime settings (platform_settings), but no domain read it, and the administration page let an administrator write arbitrary…
- ADR-0039: Source-built components are declared in the SBOM; their scan coverage rests on Grype
CommonLayer images build their main software from upstream source. syft identifies some of those binaries (nginx, PostgreSQL) and not others (Valkey), so a clean scan of a Valkey image said…
- ADR-0040: A forwarded client address is honoured only behind a declared proxy
Per-IP rate limits (anonymous API, registration, sign-in, registry tokens) and audit records need the client's address. Behind an ingress, the direct peer is the ingress; for server-side…
- ADR-0041: An ambiguous payout stays unknown and keeps its idempotency key
Payout execution treated every provider error as a failure: a network timeout or a 5xx after Stripe had already created the transfer marked the payout failed and returned the obligation to…
- ADR-0042: Catalog entries stay in_development until signed artifacts are released
The plan expected the Bitnami migration catalog to mark nginx, Valkey and PostgreSQL as available once their projects existed. The catalog's own legend defines available as "released, signed…
- ADR-0043: One Playwright configuration against the portal on port 3000
The three page work packages ran their Playwright specs against private web servers on ports 3031–3033 with their own build directories. Because the API accepts state-changing requests only from…
- ADR-0044: Security workflows probe for code scanning and fall back to artifacts
The first runs on GitHub (2026-11-10) failed in steps that upload SARIF results, run dependency review and run OpenSSF Scorecard. The repository is private and GitHub Advanced Security is not…
- ADR-0045: The proposer never approves a reward, and a contribution is rewarded once
Up to the single-approval limit (default $100) one approval funded a reward, and the proposer could give it. Nothing limited how many rewards one approved contribution could carry. The security…
- ADR-0046: Repositories stay with their maintainers
The first design assumed the image and chart projects live in repositories CommonLayer owns. That takes projects away from the people who build them: their repository, their visibility, their name…
- ADR-0047: Onboarding a project is connecting its repository, and one rule engine checks it
A project used to be proposed by filling in a form with a repository URL. Nothing showed that the person controlled the repository, and whether it followed the image and chart standards came out…
- ADR-0048: CI spends runner time on the newest commit and on what changed
Every push to main started ci and security, and path-filtered workflows on top. The kind job of infra builds three images in release mode (about an hour) and started for any change under .github/.…
- ADR-0049: Every project is its own repository
ADR-0046 and plan 13 say that a project lives in a repository of its own, connected through the GitHub App. The first-party projects did not: the base image, nginx, Valkey and PostgreSQL were…
Funding
- Funding model
CommonLayer is funded by contributions that go to projects, not to people. Each project has a treasury with a monthly target and an allocation policy; once a month the treasury pays the maintainer…
- Ledger specification
This is the specification of CommonLayer's financial ledger as implemented in crates/commonlayer-funding and migrations 0010_funding.sql and 0020_funding_hardening.sql: the accounts, the…
Guides
- Guides
Task-oriented entry points into the documentation, by audience. Each guide links to the reference pages behind it. Every step names the portal page or API operation that exists today; where a step…
- Migrating from Bitnami
If you relied on Bitnami container images or Helm charts, the CommonLayer migration catalog in projects/bitnami-migration/ is the place to start: researched facts about what changed in the Bitnami…
- Project onboarding
This guide takes a maintainer from the project template to a first promoted release on CommonLayer. Your repository stays in your own GitHub account or organization: you connect it through the…
- 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…
- Verifying artifacts
This guide shows how to verify a CommonLayer container image or Helm chart yourself before you deploy it: resolve the digest, verify the signature against the project's registered identity, verify…
Maintenance
- Maintenance
How CommonLayer projects are maintained: who maintains them, what maintainers are responsible for, how fulfilment is evaluated each month, and how that connects to compensation. Security status…
- Maintainer handbook
This handbook is for people who maintain a CommonLayer project or want to: how to apply, how assignments work, what you are responsible for, the security deadlines, the periodic tasks, how your…
Operations
- Operations handbook
How to run CommonLayer day to day: what to watch, the recurring jobs and what to do when they fail, administering users and projects, money operations (reconciliation, payout runs, adjustments),…
- Backup and recovery
What CommonLayer must back up, how, how to restore, and how to prove that a restore is complete and consistent. The PostgreSQL database plus the two object-storage buckets plus one encryption key…
- Deployment guide
This guide describes how CommonLayer is deployed: the components and what they need, the configuration a production deployment must provide, the secrets, the network flows, and the steps from an…
- Disaster recovery
Scenarios that take part of CommonLayer away (the database, a bucket, the registry, GitHub, the payment provider, a key) and how to recover from each: what stops working, how it shows up, what to…
- Metric catalog
Every CommonLayer metric is declared once in commonlayer_observability::metrics::catalog. Labels are low-cardinality enumerations; route is the matched route template and project is a project slug…
- Publish drill
scripts/dev/e2e-publish.sh (make e2e-publish) runs the submission and promotion pipeline of 06 §3 with the real tools — cosign, Trivy, Grype, syft, Helm, Docker and CNCF Distribution — instead of…
- Repository settings for the CI workflows
What the GitHub repository must provide for the workflows in .github/workflows/ to do their work: required status checks, branch protection, repository variables and secrets, the GitHub features…
- Runbooks
One section per alert of the CommonLayer alerting rules (infrastructure/monitoring/prometheus/rules/ and the copy shipped in the Helm chart,…
- The CommonLayer GitHub App
How an operator creates and configures the GitHub App that connects maintainers' repositories to the platform: its permissions and events, the URLs GitHub must call, the settings and which process…
Security
- Security
How CommonLayer handles security: what is verified before an artifact is published, how vulnerabilities are tracked after publication, how private reports and advisories work, and the documents…
- Backend security review, November 2026
An independent, read-only review of the backend carried out on 2026-11-10 against the main branch before the hardening work. It was asked to construct concrete attacks on money, sessions,…
- Permission matrix
Generated from commonlayer_core::authz::policy::ROLE_PERMISSIONS. platform_admin additionally holds every permission in every scope.
- Privacy rules
CommonLayer publishes a lot on purpose: funding flows, maintainer compensation by slot, eligibility states, security findings and exceptions. It never publishes personal and payment data, private…
- Threat model
This threat model lists what CommonLayer protects, where trust changes hands, the threats at each boundary (STRIDE), and for each threat the mitigation that exists in code, with a file reference.…
- Verification policy
Every container image and Helm chart in the CommonLayer registry was submitted by its project's CI as a digest, fetched from the source registry, and checked against the verification policy before…