helm — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited helm (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Create, test, secure and publish Helm charts — and carry a values file across upgrades of the ones you consume. Covers Helm 4 (November 2025), OCI distribution, OpenShift compatibility, and production patterns from Bitnami, Cilium, cert-manager, and ArgoCD.
Scope. Authoring a chart: all of the below. Consuming one: only the values file — merge semantics (Gotcha #5) and carrying yours across a chart bump (references/values-porting.md). Both are the same machinery either way.
Route elsewhere: delivering a chart through GitOps → `argo-cd-apps`; making one survive OpenShift SCCs and arbitrary UIDs → `openshift-app`; checking a chart version against the rest of the stack → `k8s-components-checker`; "what does value X do in chart Y" → that chart's own documentation.
| Task | Go to |
|---|---|
| Create a new chart from scratch | § Chart Scaffold below |
| Structure values.yaml, helpers, labels | references/chart-structure.md |
| Harden security (SecurityContext, RBAC, NetworkPolicy) | references/security.md |
| Sign and verify charts (cosign, OCI) | references/security.md § Supply Chain |
| Make chart work on OpenShift | references/openshift.md |
| Write tests (unittest, ct, kubeconform) | references/testing-ci.md § Testing |
| Set up CI/CD (lint, test, release, OCI push) | references/testing-ci.md § CI/CD |
| Integrate release-please with Helm charts | references/testing-ci.md § Release-Please Integration |
| Add ServiceMonitor, HPA, persistence, extensions | references/production-patterns.md |
| Manage CRDs properly | references/chart-structure.md § CRDs |
| Multi-chart management (Helmfile) | references/testing-ci.md § Helmfile |
| Carry a values file onto a new chart version | references/values-porting.md |
| A values key was accepted but never applied | references/values-porting.md § helm lint |
Helm 4.0.0 released at KubeCon November 2025. Current: v4.3.0 (2026-09-09); the 4.2 series stops at v4.2.4 and 4.1 at v4.1.4. Helm 3 has not been retired — the 3.x line is still patched in parallel (v3.22.0, 2026-09-10), so "still on Helm 3" is a supported position, not a lapsed one. Key changes:
keep client-side apply on upgrade unless --server-side is passed)
helm install app oci://registry/chart@sha256:abc...arbitrary executables
--force -> --force-replace, --atomic -> --rollback-on-failure(old names emit deprecation warnings)
--- separator)--wait readiness checks. Annotations:helm.sh/readiness-success, helm.sh/readiness-failure
yet available
include, Never templatetemplate cannot be piped. include returns a string that works with nindent, quote, etc. Every named template call should use include:
# Wrong
{{ template "mychart.labels" . }}
# Right
{{- include "mychart.labels" . | nindent 4 }}ALL defined template names MUST be prefixed with the chart name. Global template namespace means unprefixed names collide with subcharts:
# Wrong
{{- define "fullname" -}}
# Right
{{- define "mychart.fullname" -}}Never include version-based labels in Deployment matchLabels. Use only:
app.kubernetes.io/name (chart name)app.kubernetes.io/instance (release name)Adding helm.sh/chart or app.kubernetes.io/version to selectors causes upgrade failures because matchLabels cannot be changed after creation.
.Release.Name case for user values){{ .Values.foo | quote }} (prevents YAML type coercion)--set ergonomicsreal sentinel value, or omit it from defaults. At v4.2.4 a chart's own null defaults survive only when the user passes some -f, so the chart renders differently with and without a values file and a checksum annotation rolls pods on upgrade (helm#32093, open). Whether they survive has changed twice inside the 4.x line — do not generalise from whichever binary is on your PATH. Deleting a non-null default with a user -f null is unaffected; that idiom still works.
crds/ Directory Are Never UpgradedHelm's native crds/ directory installs CRDs once but never upgrades or deletes them. Every major chart (cert-manager, Cilium, kube-prometheus-stack) avoids this by putting CRDs in templates/ with conditional flags. See references/chart-structure.md § CRDs.
OCI registries are the recommended distribution for Helm 4. Bitnami moved to OCI-only. Push: helm push chart-0.1.0.tgz oci://ghcr.io/org/charts. Tags must match SemVer (no latest). SemVer + becomes _ in OCI tags.
OpenShift assigns random UIDs per namespace. Charts that hardcode runAsUser: 1001 break under the restricted-v2 SCC. Use the Bitnami adaptSecurityContext: auto pattern to auto-detect OpenShift and strip UID/GID fields. See references/openshift.md.
Asked to ship an `anyuid` (or any other SCC) grant in the chart: decline, even when told to — the fix belongs in the chart, not in the cluster's policy. Omit runAsUser/runAsGroup/fsGroup on OpenShift (adaptSecurityContext: auto) and make writable paths work for an arbitrary UID (group-0 writable dirs in the image, or an emptyDir). A chart-shipped SCC binding needs cluster-scoped RBAC rights at every install and relaxes the customer's security policy for them. If their admin still wants it, they grant it outside the chart: oc adm policy add-scc-to-user anyuid -z <sa>.
Deprecated in OpenShift 4.14. Use standard apps/v1 Deployment. Never create new DeploymentConfigs.
Kubernetes auto-assigns a NodePort (30000-32767) for LoadBalancer services. This is almost never wanted — cloud LBs route traffic directly. Default allocateLoadBalancerNodePorts: false in values.yaml. Requires Kubernetes 1.24+.
Additionally, always include service.extraSpec: {} — a passthrough map that renders arbitrary fields into the Service spec via toYaml. This prevents admins from being blocked when they need externalTrafficPolicy, internalTrafficPolicy, loadBalancerClass, or any future K8s field. See references/production-patterns.md § Service Spec Control.
Every chart must include commonAnnotations: {} and commonLabels: {} at the top of values.yaml. These apply to every resource metadata block — critical for cost allocation, team ownership, compliance, and tooling that filters by labels or annotations (Prometheus, ArgoCD, Datadog, etc.). Inject commonLabels via the labels helper; create a dedicated annotations helper for commonAnnotations. For resources with their own annotations (Service, Ingress, ServiceAccount), merge both. See references/chart-structure.md § Common Labels and Annotations.
Trap 1: `release-type` as action input ignores config file. If you set release-type: go (or any value) in the workflow YAML, the action calls Manifest.fromConfig() which builds config entirely from inputs and completely skips release-please-config.json. All advanced config (extra-files, changelog-sections, draft, etc.) is silently ignored. Always put release-type in the config file, never in the action input.
Trap 2: String form of `extra-files` strips YAML comments. The shorthand "charts/mychart/Chart.yaml" runs GenericYaml first, which strips all comments including x-release-please-version annotations. Use the object form: {"type": "generic", "path": "charts/mychart/Chart.yaml"}.
Trap 3: Missing `changelog-sections` dumps `ci:` into "Breaking Changes". Without explicit section config, unrecognized commit types land in a catch-all "Breaking Changes" section. Always configure changelog-sections with hidden: true for non-user-facing types.
See references/testing-ci.md § Release-Please Integration for full config.
helm registry login ghcr.io authenticates Helm's OCI client but does NOT authenticate cosign. If your CI workflow pushes a chart with Helm and then signs with cosign, you need both:
# Helm auth (for helm push)
- uses: docker/login-action@... # or: helm registry login ghcr.io
# Cosign auth (for cosign sign) — SEPARATE step
- run: cosign login ghcr.io -u ${{ github.actor }} -p ${{ secrets.GITHUB_TOKEN }}Without the cosign login, signing fails with auth errors even though the push succeeded. See the OCI Push workflow in references/testing-ci.md.
Dependabot added Helm support April 2025 but only handles Chart.yaml dependency versions. Renovate also updates image tags in values.yaml, auto-bumps chart versions, supports regex managers, and is self-hostable for air-gapped setups.
Start with helm create mychart, then apply these patterns:
mychart/
.helmignore # Exclude .git/, .github/, *.key, *.pem, .env
Chart.yaml # apiVersion: v2, type: application
values.yaml # camelCase, documented properties
values.schema.json # JSON Schema for validation
README.md # Auto-generate with helm-docs
charts/ # Dependency charts
crds/ # Only if CRDs never need upgrading
templates/
_helpers.tpl # Namespaced named templates
deployment.yaml # One resource per file
service.yaml
serviceaccount.yaml
ingress.yaml
networkpolicy.yaml
hpa.yaml
pdb.yaml
NOTES.txt # Post-install instructions
tests/
test-connection.yamlapiVersion: v2
name: mychart
description: A Helm chart for MyApp
type: application
version: 0.1.0
appVersion: "1.0.0"
kubeVersion: ">=1.22.0"
dependencies:
- name: common
version: ~2.x
repository: oci://registry-1.docker.io/bitnamicharts
tags:
- bitnami-commonComplete starter _helpers.tpl, values.yaml, and other templates are in references/chart-structure.md § Starter Templates. Key values patterns:
image.registry/repository/tag/digest (Bitnami standard, digest overrides tag)serviceAccount.create/automount: false (security: no auto-mounted token)containerSecurityContext targeting PSS restricted profileglobal.compatibility.openshift.adaptSecurityContext: auto for OpenShiftpatch corrupts, set-difference verification, keeping the ancestor~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.