From devops-skills
Validates and audits Helm charts with linting, template rendering, YAML/schema checks, CRD verification, dry-runs, and security best practices.
npx claudepluginhub akin-ozer/cc-devops-skills --plugin devops-skillsThis skill uses the workspace's default tool permissions.
This skill provides a comprehensive validation and analysis workflow for Helm charts, combining Helm-native linting, template rendering, YAML validation, schema validation, CRD documentation lookup, and security best practices checking.
assets/values.schema.jsonreferences/helm_best_practices.mdreferences/k8s_best_practices.mdreferences/template_functions.mdscripts/detect_crd.pyscripts/detect_crd_wrapper.shscripts/generate_helpers.shscripts/setup_tools.shscripts/validate_chart_structure.shtest/test-crd-chart/Chart.yamltest/test-crd-chart/README.mdtest/test-crd-chart/templates/NOTES.txttest/test-crd-chart/templates/_helpers.tpltest/test-crd-chart/templates/certificate.yamltest/test-crd-chart/templates/servicemonitor.yamltest/test-crd-chart/values.yamltest/test-workload-chart/Chart.yamltest/test-workload-chart/README.mdtest/test-workload-chart/templates/NOTES.txttest/test-workload-chart/templates/_helpers.tplSearches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
This skill provides a comprehensive validation and analysis workflow for Helm charts, combining Helm-native linting, template rendering, YAML validation, schema validation, CRD documentation lookup, and security best practices checking.
IMPORTANT: This validator is read-only by default. It analyzes charts and proposes improvements. Only modify files when the user explicitly asks to apply fixes.
Use this skill when one or more of these top cases apply:
Trigger phrase examples:
helm template fail?"Out of scope by default:
helm-generator)bash scripts/setup_tools.sh
bash scripts/validate_chart_structure.sh <chart-directory>
helm lint <chart-directory> --strict
helm template <release-name> <chart-directory> --values <values-file> --debug --output-dir ./rendered
find ./rendered -type f \( -name "*.yaml" -o -name "*.yml" \) -exec yamllint -c assets/.yamllint {} +
find ./rendered -type f \( -name "*.yaml" -o -name "*.yml" \) -exec kubeconform -summary -verbose {} +
Run Mode A plus Stage 8 dry-run commands in this document.
Follow this sequential validation workflow. Each stage catches different types of issues:
Before starting validation, verify required tools are installed:
bash scripts/setup_tools.sh
Required tools:
Fallback policy for unavailable tools or environment constraints:
| Condition | Action | Stage status |
|---|---|---|
helm missing | Run Stage 2 only, then report Stages 3 to 9 as skipped/blocked | ⚠️ Warning |
yamllint missing | Use yq syntax checks if available; otherwise skip Stage 5 | ⚠️ Warning |
kubeconform missing | Skip Stage 7 and rely on Stage 6 CRD/manual checks | ⚠️ Warning |
kubectl missing or no kube-context | Skip Stage 8, continue with remaining stages | ⚠️ Warning |
| No internet access for CRD docs | Use local CRD manifests and kubeconform output, mark doc lookup incomplete | ⚠️ Warning |
If tools are missing, provide installation instructions from scripts/setup_tools.sh output and continue with the fallback path above.
Verify the chart follows the standard Helm directory structure:
bash scripts/validate_chart_structure.sh <chart-directory>
Expected structure:
mychart/
Chart.yaml # Chart metadata (required)
values.yaml # Default values (required)
values.schema.json # JSON Schema for values validation (optional)
templates/ # Template directory (required)
_helpers.tpl # Template helpers (recommended)
NOTES.txt # Post-install notes (recommended)
*.yaml # Kubernetes manifest templates
charts/ # Chart dependencies (optional)
crds/ # Custom Resource Definitions (optional)
.helmignore # Files to ignore during packaging (optional)
Common issues caught:
Run Helm's built-in linter to catch chart-specific issues:
helm lint <chart-directory> --strict
Optional flags:
--values <values-file>: Test with specific values--set key=value: Override specific values--debug: Show detailed error informationCommon issues caught:
Auto-fix approach:
helm lint after fixes are appliedRender templates locally to verify they produce valid YAML:
helm template <release-name> <chart-directory> \
--values <values-file> \
--debug \
--output-dir ./rendered
Options to consider:
--values values.yaml: Use specific values file--set key=value: Override individual values--show-only templates/deployment.yaml: Render specific template--validate: Validate against Kubernetes OpenAPI schema--include-crds: Include CRDs in rendered output--is-upgrade: Simulate upgrade scenario--kube-version 1.28.0: Target specific Kubernetes versionCommon issues caught:
For template errors:
Validate YAML syntax and formatting of rendered templates:
find ./rendered -type f \( -name "*.yaml" -o -name "*.yml" \) \
-exec yamllint -c assets/.yamllint {} +
Common issues caught:
Auto-fix approach:
Before schema validation, detect if the chart contains or renders Custom Resource Definitions:
# Check crds/ directory
if [ -d <chart-directory>/crds ]; then
find <chart-directory>/crds -type f \( -name "*.yaml" -o -name "*.yml" \) \
-exec bash scripts/detect_crd_wrapper.sh {} +
fi
# Check rendered templates
find ./rendered -type f \( -name "*.yaml" -o -name "*.yml" \) \
-exec bash scripts/detect_crd_wrapper.sh {} +
The script outputs JSON with resource information:
[
{
"kind": "Certificate",
"apiVersion": "cert-manager.io/v1",
"group": "cert-manager.io",
"version": "v1",
"isCRD": true,
"name": "example-cert"
}
]
For each detected CRD:
Try context7 MCP first (preferred):
Use mcp__context7__resolve-library-id with the CRD project name
Example: "cert-manager" for cert-manager.io CRDs
"prometheus-operator" for monitoring.coreos.com CRDs
"istio" for networking.istio.io CRDs
Then use mcp__context7__query-docs with:
- libraryId from resolve step
- query: The CRD kind and relevant features (e.g., "Certificate spec required fields")
Fallback to web.search_query (web search) if Context7 fails:
Search query pattern:
"<kind>" "<group>" kubernetes CRD "<version>" documentation spec
Example:
"Certificate" "cert-manager.io" kubernetes CRD "v1" documentation spec
"Prometheus" "monitoring.coreos.com" kubernetes CRD "v1" documentation spec
Extract key information:
specWhy this matters: CRDs have custom schemas not available in standard Kubernetes validation tools. Understanding the CRD's spec requirements prevents validation errors and ensures correct resource configuration.
Validate rendered templates against Kubernetes schemas:
find ./rendered -type f \( -name "*.yaml" -o -name "*.yml" \) -exec \
kubeconform \
-schema-location default \
-schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json' \
-summary \
-verbose \
{} +
Options to consider:
-strict to reject unknown fields (recommended for production)-ignore-missing-schemas if working with custom/internal CRDs-kubernetes-version 1.28.0 to validate against specific K8s version-output json for programmatic processingCommon issues caught:
For CRDs: If kubeconform reports "no schema found", this is expected. Use the documentation from Stage 6 to manually validate the spec fields.
Stage 7 success criteria (explicit):
kubeconform exits 0, and no invalid resources are reported.If kubectl is configured and cluster access is available, perform a server-side dry-run:
# Test installation
helm install <release-name> <chart-directory> \
--dry-run=server \
--debug \
--values <values-file>
# Test upgrade
helm upgrade <release-name> <chart-directory> \
--dry-run=server \
--debug \
--values <values-file>
If the Helm version does not support --dry-run=server, use --dry-run and document that only client-side Helm simulation was executed.
This catches:
If dry-run is not possible:
kubectl apply --dry-run=server -f ./rendered/For updates to existing releases:
helm diff upgrade <release-name> <chart-directory>
This shows what would change, helping catch unintended modifications. (Requires helm-diff plugin)
Stage 8 success criteria (explicit):
0 with no admission/policy errors.kubectl/cluster context/access is unavailable, or only client-side fallback was possible.IMPORTANT: This stage is MANDATORY. Analyze rendered templates for security best practices compliance.
Check rendered Deployment/Pod templates for:
Missing securityContext - Look for pods/containers without security settings:
# Check if pod-level securityContext exists
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
Missing container securityContext - Each container should have:
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
capabilities:
drop:
- ALL
Missing resource limits/requests - Check for:
resources:
limits:
cpu: "100m"
memory: "128Mi"
requests:
cpu: "100m"
memory: "128Mi"
Image tag issues - Flag if using :latest or no tag
Missing probes - Check for liveness/readiness probes
How to check: Read the rendered deployment YAML files and grep for these patterns:
# Check for securityContext
find ./rendered -type f \( -name "*.yaml" -o -name "*.yml" \) \
-exec grep -l "securityContext" {} +
# Check for resources
find ./rendered -type f \( -name "*.yaml" -o -name "*.yml" \) \
-exec grep -l "resources:" {} +
# Check for latest tag
find ./rendered -type f \( -name "*.yaml" -o -name "*.yml" \) \
-exec grep "image:.*:latest" {} +
IMPORTANT: This stage is MANDATORY even if all validations pass. You MUST complete ALL of the following actions.
Default behavior is read-only. Do not modify files unless the user explicitly asks you to apply fixes.
If ANY warnings, errors, or security issues were found, you MUST read:
Read references/helm_best_practices.md
Read references/k8s_best_practices.md
Use these references to provide context and recommendations for each issue found.
Always present a validation summary formatted as a table showing:
Example:
| Stage | Status | Issues |
|-------|--------|--------|
| 1. Tool Check | ✅ Passed | All tools available |
| 2. Structure | ⚠️ Warning | Missing: .helmignore, NOTES.txt |
| 3. Helm Lint | ✅ Passed | 0 errors |
| 4. Template Render | ✅ Passed | 5 templates rendered |
| 5. YAML Syntax | ✅ Passed | No yamllint errors |
| 6. CRD Detection | ✅ Passed | 1 CRD documented |
| 7. Schema Validation | ✅ Passed | All resources valid |
| 8. Dry-Run | ✅ Passed | No cluster errors |
| 9. Security Check | ⚠️ Warning | Missing securityContext |
Group findings by severity:
❌ Errors (must fix):
⚠️ Warnings (should fix):
:latest image tagℹ️ Info (recommendations):
For each issue, provide a proposed fix with:
Example format:
## Proposed Changes
### 1. Add securityContext to Deployment
**File:** templates/deployment.yaml:25
**Severity:** ⚠️ Warning
**Reason:** Running containers as root is a security risk
**Current:**
```yaml
spec:
containers:
- name: app
image: nginx:1.21
Proposed:
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
containers:
- name: app
image: nginx:1.21
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
File: .helmignore (new file) Severity: ⚠️ Warning Reason: Excludes unnecessary files from chart packaging
Proposed: Copy from assets/.helmignore
#### Step 5: Automation Opportunities
List all detected automation opportunities:
- If `_helpers.tpl` is missing → Recommend: `bash scripts/generate_helpers.sh <chart>`
- If `.helmignore` is missing → Recommend: Copy from `assets/.helmignore`
- If `values.schema.json` is missing → Recommend: Copy and customize from `assets/values.schema.json`
- If `NOTES.txt` is missing → Recommend: Create post-install notes template
- If `README.md` is missing → Recommend: Create chart documentation
#### Step 6: Final Summary
Provide a final summary:
Chart: Status: ⚠️ Warnings Found (or ✅ Ready for Deployment)
Issues Found:
Proposed Changes: N changes recommended
Next Steps:
## Workflow Done Criteria
Validation is complete only when all of the following are true:
- A Stage 1 to Stage 10 status table is present with `✅ Passed`, `⚠️ Warning`, `❌ Failed`, or `⏭️ Skipped` for each stage.
- Every skipped stage includes a concrete tool or environment reason.
- Stage 7 and Stage 8 are evaluated against their explicit success criteria above.
- Severity totals are reported (`Errors`, `Warnings`, `Info`) with proposed remediation actions.
- Role boundary is respected: no file edits unless explicitly requested by the user.
## Helm Templating Automation & Best Practices
This section covers advanced Helm templating techniques, helper functions, and automation strategies.
### Template Helpers (`_helpers.tpl`)
Template helpers are reusable functions defined in `templates/_helpers.tpl`. They promote DRY principles and consistency.
**Standard helper patterns:**
1. **Chart name helper:**
```yaml
{{/*
Expand the name of the chart.
*/}}
{{- define "mychart.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
*/}}
{{- define "mychart.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "mychart.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "mychart.labels" -}}
helm.sh/chart: {{ include "mychart.chart" . }}
{{ include "mychart.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "mychart.selectorLabels" -}}
app.kubernetes.io/name: {{ include "mychart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "mychart.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "mychart.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
When to create helpers:
Reference and use these Helm template functions for robust charts:
required - Enforce required values:apiVersion: v1
kind: Service
metadata:
name: {{ required "A valid service name is required!" .Values.service.name }}
default - Provide fallback values:replicas: {{ .Values.replicaCount | default 1 }}
quote - Safely quote string values:env:
- name: DATABASE_HOST
value: {{ .Values.database.host | quote }}
include - Use helpers with pipeline:metadata:
labels:
{{- include "mychart.labels" . | nindent 4 }}
tpl - Render strings as templates:{{- tpl .Values.customConfig . }}
toYaml - Convert objects to YAML:{{- with .Values.resources }}
resources:
{{- toYaml . | nindent 2 }}
{{- end }}
fromYaml - Parse YAML strings:{{- $config := .Values.configYaml | fromYaml }}
merge - Merge maps:{{- $merged := merge .Values.override .Values.defaults }}
lookup - Query cluster resources (use carefully):{{- $secret := lookup "v1" "Secret" .Release.Namespace "my-secret" }}
{{- if $secret }}
# Secret exists, use it
{{- else }}
# Create new secret
{{- end }}
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
# ... ingress definition
{{- end }}
{{- range .Values.extraEnvVars }}
- name: {{ .name }}
value: {{ .value | quote }}
{{- end }}
{{- range $key, $value := .Values.configMap }}
{{ $key }}: {{ $value | quote }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 2 }}
{{- end }}
{{- include "mychart.container" (dict "root" . "container" .Values.mainContainer) }}
Prefer flat structures when possible:
# Good - Flat structure
serverName: nginx
serverPort: 80
# Acceptable - Nested structure for related settings
server:
name: nginx
port: 80
replicas: 3
Always provide defaults in values.yaml:
replicaCount: 1
image:
repository: nginx
pullPolicy: IfNotPresent
tag: "1.21.0"
service:
type: ClusterIP
port: 80
resources:
limits:
cpu: 100m
memory: 128Mi
requests:
cpu: 100m
memory: 128Mi
Document all values:
# replicaCount is the number of pod replicas for the deployment
replicaCount: 1
# image configures the container image
image:
# image.repository is the container image registry and name
repository: nginx
# image.tag overrides the image tag (default is chart appVersion)
tag: "1.21.0"
Use Helm template comments for documentation:
{{- /*
mychart.fullname generates the fullname for resources.
It supports nameOverride and fullnameOverride values.
Usage: {{ include "mychart.fullname" . }}
*/ -}}
{{- define "mychart.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name .Chart.Name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
Use YAML comments for user-facing notes:
# WARNING: Changing the storage class will not migrate existing data
storageClass: "standard"
Use - to chomp whitespace in template directives:
{{- if .Values.enabled }}
# Remove leading whitespace
{{- end }}
{{ .Values.name -}}
# Remove trailing whitespace
Good formatting:
{{- if .Values.enabled }}
key: value
{{- end }}
Bad formatting:
{{if .Values.enabled}}
key: value
{{end}}
When analyzing charts, identify opportunities for helper functions:
Identify repetition:
Common helper patterns to recommend:
.name).fullname).chart).labels).selectorLabels).serviceAccountName)When to recommend helpers:
_helpers.tpl fileFor detailed Helm and Kubernetes best practices, load the references:
Read references/helm_best_practices.md
Read references/k8s_best_practices.md
These references include:
When to load: When validation reveals issues that need context, when implementing new features, or when the user asks about best practices.
When a chart has dependencies (in Chart.yaml or charts/ directory):
helm dependency update <chart-directory>
helm dependency list <chart-directory>
Validate dependencies:
Override dependency values:
# values.yaml
postgresql:
enabled: true
postgresqlPassword: "secret"
persistence:
size: 10Gi
scripts/setup_tools.sh to check availability--debug flag for detailed error messageskubectl get crd <crd-name>.group -o yaml
kubectl explain <kind>
Symptom: Helm reports "Chart.yaml file is missing" even though the file exists and is readable.
Cause: On macOS, files created programmatically (via Write tool, scripts, or certain editors) may have extended attributes (e.g., com.apple.provenance, com.apple.quarantine) that interfere with Helm's file detection.
Diagnosis:
# Check for extended attributes
xattr /path/to/chart/Chart.yaml
# If attributes are present, you'll see output like:
# com.apple.provenance
# com.apple.quarantine
Solutions:
Remove extended attributes:
# Remove all extended attributes from a file
xattr -c /path/to/chart/Chart.yaml
# Remove all extended attributes recursively from chart directory
xattr -cr /path/to/chart/
Create files using shell commands instead:
# Use cat with heredoc instead of direct file writes
cat > Chart.yaml << 'EOF'
apiVersion: v2
name: mychart
version: 0.1.0
EOF
Copy from helm-created chart:
# Create a fresh chart and copy structure
helm create temp-chart
cp -r temp-chart/* /path/to/your/chart/
rm -rf temp-chart
Prevention: When creating new chart files on macOS, prefer using helm create as a base or use shell heredocs (cat > file << 'EOF') rather than direct file creation tools.
When presenting validation results and fixes:
Always consider Kubernetes and Helm version compatibility:
kubectl api-versions to list available API versionskubeVersion constraint in Chart.yaml if neededFor comprehensive testing, use Helm test resources:
# templates/tests/test-connection.yaml
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "mychart.fullname" . }}-test-connection"
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "mychart.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never
helm test <release-name>
During Stage 10 (Final Report), list all detected automation opportunities in the summary.
Do NOT ask user questions or modify files. Simply list recommendations.
Automation opportunities to detect and list:
| Missing Item | Recommendation |
|---|---|
_helpers.tpl | Run: bash scripts/generate_helpers.sh <chart> |
.helmignore | Copy from: assets/.helmignore |
values.schema.json | Copy and customize from: assets/values.schema.json |
NOTES.txt | Create post-install notes template |
README.md | Create chart documentation |
| Repeated patterns | Extract to helper functions |
Security recommendations to include when issues found:
| Issue | Recommendation |
|---|---|
| Missing pod securityContext | Add runAsNonRoot: true, runAsUser: 1000, fsGroup: 2000 |
| Missing container securityContext | Add allowPrivilegeEscalation: false, readOnlyRootFilesystem: true, capabilities.drop: [ALL] |
| Missing resource limits | Add CPU/memory limits and requests |
Using :latest tag | Pin to specific image version |
| Missing probes | Add liveness and readiness probes |
Template improvement recommendations:
| Issue | Recommendation |
|---|---|
Using template instead of include | Replace with include for pipeline support |
Missing nindent | Add nindent for proper YAML indentation |
| No default values | Add default function for optional values |
Missing required function | Add required for critical values |
setup_tools.sh
bash scripts/setup_tools.shvalidate_chart_structure.sh
bash scripts/validate_chart_structure.sh <chart-directory>detect_crd_wrapper.sh
bash scripts/detect_crd_wrapper.sh <file.yaml> [file2.yaml ...]detect_crd.py
python3 scripts/detect_crd.py <file.yaml> [file2.yaml ...]generate_helpers.sh
bash scripts/generate_helpers.sh <chart-directory>helm_best_practices.md
k8s_best_practices.md
template_functions.md
.helmignore
.yamllint
yamllint -c assets/.yamllint <file.yaml>values.schema.json