Skip to content
CommonLayer
Documentation menu
On this page

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 is kept under projects/nginx until that repository exists).

Rule ids

The repository scan (docs/plan/13-repository-stewardship.md §11) checks charts against this standard. A chart that cannot follow a rule declares a deviation with a reason in commonlayer.yaml (charts[].deviations: [{standard: <id>, reason: <text>}]); the scan then reports a deviation instead of a failure, and the project page shows it.

IdRule
valuesvalues.yaml has the standard value blocks (image, imagePullSecrets, nameOverride, fullnameOverride, commonLabels, commonAnnotations, serviceAccount, podSecurityContext, containerSecurityContext, resources, livenessProbe, readinessProbe, service, networkPolicy, podDisruptionBudget)
secure-defaultsthe defaults of "Secure defaults" below, including serviceAccount.automountServiceAccountToken: false
image-digestimages are referenced by digest (image.digest, rendered by commonlayer.image or a chart helper that pins @digest)
helpertemplates/_commonlayer.tpl is identical to the template's
schemavalues.schema.json exists and is a JSON schema

Packaging

  • apiVersion: v2. version is SemVer and independent of appVersion (bump it on every chart change); appVersion is the upstream version of the default image line. kubeVersion is set.
  • Distributed as OCI artifacts (oci://registry.commonlayer.org/charts/<chart>), signed with cosign (keyless), with build provenance attached (publish.yml).
  • No third-party library chart.
  • Chart.yaml carries the annotation org.commonlayer/chart-standard: v1.

Shared helper file

templates/_commonlayer.tpl is byte-identical in the template and in every CommonLayer chart; scripts/check-template-drift.sh fails CI otherwise. Change it only in the template and copy it everywhere (check-template-drift.sh --fix). It provides:

HelperUse
commonlayer.name, commonlayer.fullname, commonlayer.chartnames (63 characters)
commonlayer.labels (dict "context" . "component" "server")the standard labels below plus commonLabels
commonlayer.selectorLabels (same arguments)immutable selector labels (name, instance, component)
commonlayer.annotations (dict "context" . "annotations" .Values.x)commonAnnotations merged with object-specific ones
commonlayer.image (dict "image" .Values.image "context" .)registry/repository@digest when a digest is set (validated), otherwise registry/repository:tag
commonlayer.imagePullSecrets, commonlayer.serviceAccountName, commonlayer.podSecurityContext, commonlayer.containerSecurityContext, commonlayer.tplValuethe corresponding blocks

Chart-specific helpers go into another file (for example _helpers.tpl).

Labels

Every object carries app.kubernetes.io/{name,instance,version,component,part-of,managed-by}, helm.sh/chart and commonLabels. Selectors use only name, instance and component, so that the helm test pod (component test) is never selected by a Service.

Image values

image:
  registry: registry.commonlayer.org
  repository: nginx
  tag: "1.30.6-r1"        # informational when digest is set
  digest: "sha256:..."    # the released digest; takes precedence
  pullPolicy: IfNotPresent

Released charts ship with digest filled in by the release workflow (scripts/publish-chart.sh), so a default install pulls exactly the promoted image. In the repository the value is "" until the first release; "" is also the documented, explicit way for a user to opt out and use the tag. The platform's chart.images_pinned check requires released charts to reference promoted digests.

Required values blocks

Every chart has these top-level values, with these names: image, imagePullSecrets, nameOverride, fullnameOverride, commonLabels, commonAnnotations, serviceAccount {create, name, annotations, automountServiceAccountToken}, podSecurityContext, containerSecurityContext, resources, livenessProbe, readinessProbe, startupProbe, service, networkPolicy, podDisruptionBudget, topologySpreadConstraints, affinity, nodeSelector, tolerations, priorityClassName, persistence (stateful charts), metrics {enabled, serviceMonitor}, extraEnv, extraVolumes, extraVolumeMounts, podAnnotations, podLabels.

A probe set to null is disabled (Helm merges maps, so {} cannot remove a default). A chart whose software has no metrics endpoint keeps the metrics block and fixes enabled to false in its schema.

Secure defaults

SettingDefault
podSecurityContextrunAsNonRoot: true, runAsUser/runAsGroup/fsGroup: 10001, seccompProfile: RuntimeDefault
containerSecurityContextthe same user, allowPrivilegeEscalation: false, readOnlyRootFilesystem: true, privileged: false, capabilities.drop: [ALL], seccompProfile: RuntimeDefault
service accountcreated, token not mounted (automountServiceAccountToken: false)
resourcesrequests and limits set
writable pathsemptyDir for /tmp (with sizeLimit) and the image's declared volumes
networkPolicy.enabled: truedefault deny: ingress only to the service ports from pods labelled <fullname>-client: "true" and networkPolicy.ingressFrom; egress only DNS and networkPolicy.extraEgress
enableServiceLinksfalse

Schema and documentation

  • values.schema.json validates every value (additionalProperties: false at the top level and in each block the chart defines; Kubernetes objects such as affinity are accepted as objects).
  • README.md is generated by helm-docs from README.md.gotmpl and the # -- comments in values.yaml; scripts/validate.sh fails when it is stale.

Tests

TestCommand (in scripts/test-chart.sh unless noted)
linthelm lint --strict with the defaults and every chart/ci/*.yaml
render + schemahelm template for the same value sets, validated with kubeconform -strict against Kubernetes 1.31 and 1.37 schemas and CRD schemas (ServiceMonitor, HTTPRoute), schema sources pinned by commit
unit testshelm unittest suites in chart/tests/*_test.yaml
policytrivy config on the rendered manifests; HIGH or CRITICAL findings fail
install/upgradescripts/test-chart-kind.sh on kind in CI: install the previous release (when published), upgrade to the working tree, helm test

chart/ci/*.yaml must together enable every optional object of the chart, so that each template is rendered and validated at least once.

helm test uses the chart's own image (which carries cl-probe), so no extra test image has to be trusted.