helm-bjw-s-chart — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited helm-bjw-s-chart (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.
🆕 v5.0.0 — common 5.x is now the default — The skill is rebased oncommon: 5.0.1(released 2026-05-14). New charts target 5.x out of the box, and the migration path from 4.x is captured inreferences/migration-4-to-5.md. 4.x remains supported as a legacy track for clusters that can't meet the Kubernetes 1.31 / Helm 3.18 prerequisites.
>
🔄 Renamed in v3.0.0 — This skill was previously published as helm-chart-generator. Update any agent, automation, or documentation that still references the old name.Generate production-ready Helm charts using the bjw-s-labs common library (app-template v5, with v4 legacy support).
| common | Kubernetes | Helm | Status |
|---|---|---|---|
5.0.1 | >= 1.31 | >= 3.18 | Default — latest stable, all examples target it |
4.6.2 | >= 1.25 | >= 3.14 | Legacy — pin when the cluster can't meet 5.x reqs |
Everything documented here works on common 5.x by default. When a pattern is not available on 4.x it's tagged `(5.x only)` so agents pinned to the legacy track can skip it. See references/migration-4-to-5.md for the full 4 → 5 upgrade procedure.
Five things to know — full details in references/migration-4-to-5.md:
back to true per-pod if the workload needs to call the Kubernetes API.
Opt out with global.createDefaultServiceAccount: false when you reference an externally-managed SA.
spec: into a manifest: wrapper, and labels/annotations now live under metadata:. Only relevant if you use rawResources (rare).
app.kubernetes.io/name. Override if your Prometheus rules depended on the old metadata.name default.
assets/templates/helm dependency update to fetch dependencies (generates Chart.lock)scripts/validate_chart.py to check structurereferences/best-practices.mdhelm template and helm lintEvery chart consists of:
my-app/
├── Chart.yaml # Chart metadata and dependencies
├── values.yaml # Configuration values
└── templates/
├── common.yaml # Includes the bjw-s library
└── NOTES.txt # Post-install instructionsapiVersion: v2
name: <app-name>
description: <brief description>
type: application
version: 1.0.0
appVersion: "<app version>"
dependencies:
- name: common
repository: https://bjw-s-labs.github.io/helm-charts
version: 5.0.1 # Default. Pin to 4.6.2 for legacy clusters (K8s < 1.31 / Helm < 3.18).{{- include "bjw-s.common.loader.all" . }}Provide useful post-install information:
Follow this order for clarity:
# 1. Default Pod options (optional)
defaultPodOptions:
# 5.x default is false; set to true only if the pod calls the K8s API.
automountServiceAccountToken: false
securityContext: {}
annotations: {}
# 2. Controllers (required)
controllers:
main: # or custom name
containers:
main: # or custom name
image: {}
env: {}
probes: {}
# 3. Service (required if exposing)
service:
main:
controller: main
ports: {}
# 4. Ingress (optional)
ingress:
main:
className: ""
hosts: []
# 5. Persistence (optional)
persistence:
config:
type: persistentVolumeClaim
# or: emptyDir, configMap, secret, nfs, hostPath, ephemeral
# 6. ConfigMaps/Secrets (optional)
configMaps: {}
secrets: {}controllers:
main:
containers:
main:
image:
repository: nginx
tag: "1.25-alpine"
pullPolicy: IfNotPresent
service:
main:
controller: main
ports:
http:
port: 80
persistence:
config:
type: persistentVolumeClaim
accessMode: ReadWriteOnce
size: 1Gi
globalMounts:
- path: /configcontrollers:
main:
containers:
main:
image:
repository: myapp
tag: "1.0.0"
sidecar:
dependsOn: main
image:
repository: sidecar-image
tag: "1.0.0"See references/patterns.md for more examples:
imagePullSecretsThe patterns below require common >= 5.0.0. They are silently ignored or rejected on 4.x.
# 1. HorizontalPodAutoscaler tied to a controller
horizontalPodAutoscaler:
main:
enabled: true
controller: main # Target controller identifier
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
# 2. PodMonitor (alternative to ServiceMonitor — scrapes pods directly)
podMonitor:
main:
enabled: true
controller: main
endpoints:
- port: metrics
path: /metrics
interval: 30s
# 3. Generic ephemeral volumes (per-pod PVC, deleted with the pod)
persistence:
scratch:
type: ephemeral
accessMode: ReadWriteOnce
size: 5Gi
storageClass: fast-ssd
globalMounts:
- path: /scratch
# 4. Container / Pod resizePolicy (in-place vertical scaling)
# container resizePolicy: Kubernetes >= 1.35
# pod resizePolicy: Kubernetes >= 1.36
controllers:
main:
pod:
resizePolicy: PreferNoRestart # k8s >= 1.36
containers:
main:
resizePolicy: # k8s >= 1.35
- resourceName: cpu
restartPolicy: NotRequired
- resourceName: memory
restartPolicy: RestartContainer
# 5. NetworkPolicy auto-targets the only controller when neither
# `controller` nor `podSelector` is given. `controller` and
# `podSelector` are now mutually exclusive.
networkpolicies:
default-deny:
enabled: true
policyTypes:
- EgressAlways:
:latestNaming:
Security:
automountServiceAccountToken: false (5.x default) unless theworkload calls the K8s API — and even then, pair it with an explicit ServiceAccount + RBAC, not the auto-created default
securityContextimagePullSecrets for private registries (see references/patterns.md)Persistence:
globalMounts for simple casesadvancedMounts for complex multi-container scenariosexistingClaim for pre-created PVCstype: ephemeral for scratch space tied to the pod lifecycle (5.x only)See references/best-practices.md for comprehensive guidelines.
After generating a chart:
# 1. Fetch dependencies (required before helm commands)
cd /path/to/chart
helm dependency update
# 2. Validate structure
python scripts/validate_chart.py /path/to/chart
# Or with JSON output for CI:
python scripts/validate_chart.py --json /path/to/chart
# 3. Helm validation
helm lint .
helm template . --debug
# 4. Dry-run installation
helm install --dry-run --debug my-release .The validator warns when the chart still pins common 4.x, when rawResources uses the legacy spec: shape (removed in 5.x), when an external ServiceAccount is referenced without global.createDefaultServiceAccount: false, when Chart.lock is missing, or when a declared dependency has no vendored tarball under charts/.
Before deploying to a cluster, verify:
:latest)securityContext set: non-root, readOnlyRootFilesystem, drop ALL capabilitiesautomountServiceAccountToken: false unless explicitly neededglobal.createDefaultServiceAccount: false is setrawResources is in play, manifest uses the 5.x manifest: wrapper (not legacy spec:)helm dependency update run, with Chart.lock and the populated charts/ published (see Publishing the Chart)helm lint passes with no errorsA published chart must be self-contained. Both of these have to ship inside the packaged .tgz (and the committed chart):
Chart.lock — pins the exact resolved dependency versions and digests.charts/ directory — the vendored dependency tarballs(common-<version>.tgz, …) materialized by helm dependency update.
helm package bundles whatever is under charts/ at package time, and the default .helmignore excludes neither Chart.lock nor charts/. The rule is therefore about making sure both are present before you package:
# Vendor dependencies into charts/ and (re)generate Chart.lock
helm dependency update
# ...then package — the .tgz now embeds charts/common-<version>.tgz
helm package .Two equally valid ways to satisfy it:
self-contained; the publish step is just helm package.
Chart.lock, then runhelm dependency build in the publish pipeline before helm package. helm dependency build repopulates charts/ from the locked versions without re-resolving them.
Never publish a chart whose charts/ is empty while Chart.yaml declares dependencies: consumers without the bjw-s-labs.github.io/helm-charts repo pre-added (offline / air-gapped installs) cannot resolve the common library at install time. scripts/validate_chart.py warns when Chart.lock is missing or when a declared dependency has no matching tarball under charts/.
Services not found: Use identifier not name in ingress paths Mounts not working: Check globalMounts vs advancedMounts usage Names too long: Use nameOverride or fullnameOverride in global settings Controller not starting: Check dependsOn order for init/sidecar containers Unexpected ServiceAccount appears (5.x): Set global.createDefaultServiceAccount: false or define your own SA Pod can't talk to the K8s API (5.x): Set automountServiceAccountToken: true on the pod AND grant RBAC
references/migration-4-to-5.md - Full 4 → 5 upgrade procedurereferences/patterns.md - Common deployment patternsreferences/best-practices.md - Kubernetes/Helm best practicesreferences/values-schema.md - Complete values.yaml referenceassets/templates/ - Base templates for quick start~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.