<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged chart</title>
<link>https://coderlegion.com/tag/chart</link>
<description>Powered by Question2Answer</description>
<item>
<title>Helm Chart Testing in Production: Layers, Tools, and a Minimum CI Pipeline</title>
<link>https://coderlegion.com/11555/helm-chart-testing-in-production-layers-tools-and-a-minimum-ci-pipeline</link>
<description>
&lt;a href=&quot;https://alexandre-vazquez.com/helm-chart-testing-best-practices/&quot; title=&quot;Helm Chart Testing in Production: Layers, Tools, and a Minimum CI Pipeline&quot; rel=&quot;nofollow&quot;&gt;&lt;img width=&quot;1536&quot; height=&quot;1024&quot; src=&quot;https://mlk5tkvgfeoa.i.optimole.com/cb:s8WW.68/w:1536/h:1024/q:mauto/f:best/https://alexandre-vazquez.com/wp-content/uploads/2026/01/image.png&quot; class=&quot;webfeedsFeaturedVisual wp-post-image&quot; alt=&quot;Helm Chart Testing in Production: Layers, Tools, and a Minimum CI Pipeline&quot; style=&quot;display: block; margin: auto; margin-bottom: 5px;max-width: 100%;&quot; sizes=&quot;(max-width: 1536px) 100vw, 1536px&quot; title=&quot;Helm Chart Testing in Production: Layers, Tools, and a Minimum CI Pipeline 10&quot;&gt;&lt;/a&gt;
&lt;p&gt;When a Helm chart fails in production, the impact is immediate and visible. A misconfigured &lt;code&gt;ServiceAccount&lt;/code&gt;, a typo in a &lt;code&gt;ConfigMap&lt;/code&gt; key, or an untested conditional in templates can trigger incidents that cascade through your entire deployment pipeline. The irony is that most teams invest heavily in testing application code while treating Helm charts as &amp;ldquo;just configuration.&amp;rdquo;&lt;/p&gt;



&lt;p&gt;Chart testing is fundamental for production-quality Helm deployments. For comprehensive coverage of testing along with all other Helm best practices, visit our &lt;a rel=&quot;nofollow&quot; href=&quot;https://alexandre-vazquez.com/helm-charts-package-management-guide/&quot;&gt;complete Helm guide&lt;/a&gt;.&lt;/p&gt;



&lt;p&gt;Helm charts are infrastructure code. They define how your applications run, scale, and integrate with the cluster. Treating them with less rigor than your application logic is a risk most production environments cannot afford.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;The Real Cost of Untested Charts&lt;/h2&gt;



&lt;p&gt;In late 2024, a medium-sized SaaS company experienced a 4-hour outage because a chart update introduced a breaking change in RBAC permissions. The chart had been tested locally with &lt;code&gt;helm install --dry-run&lt;/code&gt;, but the dry-run validation doesn&amp;rsquo;t interact with the API server&amp;rsquo;s RBAC layer. The deployment succeeded syntactically but failed operationally.&lt;/p&gt;



&lt;p&gt;The incident revealed three gaps in their workflow:&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;No schema validation against the target Kubernetes version&lt;/li&gt;



&lt;li&gt;No integration tests in a live cluster&lt;/li&gt;



&lt;li&gt;No policy enforcement for security baselines&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;



&lt;p&gt;These gaps are common. According to a &lt;a href=&quot;https://www.cncf.io/announcements/2025/07/24/cncf-end-user-survey-finds-argo-cd-as-majority-adopted-gitops-solution-for-kubernetes/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;2024 CNCF survey on GitOps practices&lt;/a&gt;, fewer than 40% of organizations systematically test Helm charts before production deployment.&lt;/p&gt;



&lt;p&gt;The problem is not a lack of tools&amp;mdash;it&amp;rsquo;s understanding which layer each tool addresses.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Testing Layers: What Each Level Validates&lt;/h2&gt;



&lt;p&gt;Helm chart testing is not a single operation. It requires validation at multiple layers, each catching different classes of errors.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Layer 1: Syntax and Structure Validation&lt;/h3&gt;



&lt;p&gt;&lt;strong&gt;What it catches:&lt;/strong&gt; Malformed YAML, invalid chart structure, missing required fields&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Tools:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;code&gt;helm lint&lt;/code&gt;: Built-in, minimal validation following &lt;a href=&quot;https://helm.sh/docs/chart_best_practices/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Helm best practices&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;&lt;code&gt;yamllint&lt;/code&gt;: Strict YAML formatting rules&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Example failure caught:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;# Invalid indentation breaks the chart
resources:
  limits:
      cpu: &quot;500m&quot;
    memory: &quot;512Mi&quot;  # Incorrect indentation
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Limitation:&lt;/strong&gt; Does not validate whether the rendered manifests are valid Kubernetes objects.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Layer 2: Schema Validation&lt;/h3&gt;



&lt;p&gt;&lt;strong&gt;What it catches:&lt;/strong&gt; Manifests that would be rejected by the Kubernetes API&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Primary tool: kubeconform&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;&lt;a href=&quot;https://github.com/yannh/kubeconform&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Kubeconform&lt;/a&gt; is the actively maintained successor to the deprecated &lt;code&gt;kubeval&lt;/code&gt;. It validates against OpenAPI schemas for specific Kubernetes versions and can include custom CRDs.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Project Profile:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;Maintenance:&lt;/strong&gt; Active, community-driven&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Strengths:&lt;/strong&gt; CRD support, multi-version validation, fast execution&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; &lt;code&gt;helm lint&lt;/code&gt; validates chart structure, but not if rendered manifests match Kubernetes schemas&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Example failure caught:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: app
        image: nginx:latest
# Missing required field: spec.selector
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Configuration example:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;helm template my-chart . | kubeconform \
  -kubernetes-version 1.30.0 \
  -schema-location default \
  -schema-location '&lt;a href=&quot;https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json&quot; rel=&quot;nofollow&quot;&gt;https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json&lt;/a&gt;' \
  -summary
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Example CI integration:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;#!/bin/bash
set -e

KUBE_VERSION=&quot;1.30.0&quot;

echo &quot;Rendering chart...&quot;
helm template my-release ./charts/my-chart &amp;gt; manifests.yaml

echo &quot;Validating against Kubernetes $KUBE_VERSION...&quot;
kubeconform \
  -kubernetes-version &quot;$KUBE_VERSION&quot; \
  -schema-location default \
  -summary \
  -output json \
  manifests.yaml | jq -e '.summary.invalid == 0'
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Alternative:&lt;/strong&gt; &lt;code&gt;kubectl --dry-run=server&lt;/code&gt; (requires cluster access, validates against actual API server)&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Layer 3: Unit Testing&lt;/h3&gt;



&lt;p&gt;&lt;strong&gt;What it catches:&lt;/strong&gt; Logic errors in templates, incorrect conditionals, wrong value interpolation&lt;/p&gt;



&lt;p&gt;Unit tests validate that given a set of input values, the chart produces the expected manifests. This is where template logic is verified before reaching a cluster.&lt;/p&gt;



&lt;h4 class=&quot;wp-block-heading&quot;&gt;Primary tool: helm-unittest&lt;/h4&gt;



&lt;p&gt;&lt;a href=&quot;https://github.com/helm-unittest/helm-unittest&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;helm-unittest&lt;/a&gt; is the most widely adopted unit testing framework for Helm charts.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Project Profile:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; 3.3k+ stars, ~100 contributors&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Maintenance:&lt;/strong&gt; Active (releases every 2-3 months)&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Primary maintainer:&lt;/strong&gt; Quentin Machu (originally @QubitProducts, now independent)&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Commercial backing:&lt;/strong&gt; None&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Bus Factor:&lt;/strong&gt; Medium-High (no institutional backing, but consistent community engagement)&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Fast execution (no cluster required)&lt;/li&gt;



&lt;li&gt;Familiar test syntax (similar to Jest/Mocha)&lt;/li&gt;



&lt;li&gt;Snapshot testing support&lt;/li&gt;



&lt;li&gt;Good documentation&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Doesn&amp;rsquo;t validate runtime behavior&lt;/li&gt;



&lt;li&gt;Cannot test interactions with admission controllers&lt;/li&gt;



&lt;li&gt;No validation against actual Kubernetes API&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Example test scenario:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;# tests/deployment_test.yaml
suite: test deployment
templates:
  - deployment.yaml
tests:
  - it: should set resource limits when provided
    set:
      resources.limits.cpu: &quot;1000m&quot;
      resources.limits.memory: &quot;1Gi&quot;
    asserts:
      - equal:
          path: spec.template.spec.containers[0].resources.limits.cpu
          value: &quot;1000m&quot;
      - equal:
          path: spec.template.spec.containers[0].resources.limits.memory
          value: &quot;1Gi&quot;

  - it: should not create HPA when autoscaling disabled
    set:
      autoscaling.enabled: false
    template: hpa.yaml
    asserts:
      - hasDocuments:
          count: 0
&lt;/code&gt;&lt;/pre&gt;



&lt;h4 class=&quot;wp-block-heading&quot;&gt;Alternative: Terratest (Helm module)&lt;/h4&gt;



&lt;p&gt;&lt;a href=&quot;https://github.com/gruntwork-io/terratest&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Terratest&lt;/a&gt; is a Go-based testing framework from Gruntwork that includes first-class Helm support. Unlike helm-unittest, Terratest deploys charts to real clusters and allows programmatic assertions in Go.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Example Terratest test:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;func TestHelmChartDeployment(t *testing.T) {
    kubectlOptions := k8s.NewKubectlOptions(&quot;&quot;, &quot;&quot;, &quot;default&quot;)
    options := &amp;amp;helm.Options{
        KubectlOptions: kubectlOptions,
        SetValues: map[string]string{
            &quot;replicaCount&quot;: &quot;3&quot;,
        },
    }
    
    defer helm.Delete(t, options, &quot;my-release&quot;, true)
    helm.Install(t, options, &quot;../charts/my-chart&quot;, &quot;my-release&quot;)
    
    k8s.WaitUntilNumPodsCreated(t, kubectlOptions, metav1.ListOptions{
        LabelSelector: &quot;app=my-app&quot;,
    }, 3, 30, 10*time.Second)
}
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;When to use Terratest vs helm-unittest:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Use &lt;code&gt;helm-unittest&lt;/code&gt; for fast, template-focused validation in CI&lt;/li&gt;



&lt;li&gt;Use &lt;code&gt;Terratest&lt;/code&gt; when you need full integration testing with Go flexibility&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Layer 4: Integration Testing&lt;/h3&gt;



&lt;p&gt;&lt;strong&gt;What it catches:&lt;/strong&gt; Runtime failures, resource conflicts, actual Kubernetes behavior&lt;/p&gt;



&lt;p&gt;Integration tests deploy the chart to a real (or ephemeral) cluster and verify it works end-to-end.&lt;/p&gt;



&lt;h4 class=&quot;wp-block-heading&quot;&gt;Primary tool: chart-testing (ct)&lt;/h4&gt;



&lt;p&gt;&lt;a href=&quot;https://github.com/helm/chart-testing&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;chart-testing&lt;/a&gt; is the official Helm project for testing charts in live clusters.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Project Profile:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;Ownership:&lt;/strong&gt; Official Helm project (CNCF)&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Maintainers:&lt;/strong&gt; Helm team (contributors from Microsoft, IBM, Google)&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Governance:&lt;/strong&gt; CNCF-backed with public roadmap&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;LTS:&lt;/strong&gt; Aligned with Helm release cycle&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Bus Factor:&lt;/strong&gt; Low (institutional backing from CNCF provides strong long-term guarantees)&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;De facto standard for public Helm charts&lt;/li&gt;



&lt;li&gt;Built-in upgrade testing (validates migrations)&lt;/li&gt;



&lt;li&gt;Detects which charts changed in a PR (efficient for monorepos)&lt;/li&gt;



&lt;li&gt;Integration with GitHub Actions via official action&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Requires a live Kubernetes cluster&lt;/li&gt;



&lt;li&gt;Initial setup more complex than unit testing&lt;/li&gt;



&lt;li&gt;Does not include security scanning&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;What ct validates:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Chart installs successfully&lt;/li&gt;



&lt;li&gt;Upgrades work without breaking state&lt;/li&gt;



&lt;li&gt;Linting passes&lt;/li&gt;



&lt;li&gt;Version constraints are respected&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Example ct configuration:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;# ct.yaml
target-branch: main
chart-dirs:
  - charts
chart-repos:
  - bitnami=&lt;a href=&quot;https://charts.bitnami.com/bitnami&quot; rel=&quot;nofollow&quot;&gt;https://charts.bitnami.com/bitnami&lt;/a&gt;
helm-extra-args: --timeout 600s
check-version-increment: true
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Typical GitHub Actions workflow:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;name: Lint and Test Charts

on: pull_request

jobs:
  lint-test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Set up Helm
        uses: azure/setup-helm@v3

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'

      - name: Set up chart-testing
        uses: helm/chart-testing-action@v2

      - name: Run chart-testing (lint)
        run: ct lint --config ct.yaml

      - name: Create kind cluster
        uses: helm/kind-action@v1

      - name: Run chart-testing (install)
        run: ct install --config ct.yaml
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;When ct is essential:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Public chart repositories (expected by community)&lt;/li&gt;



&lt;li&gt;Charts with complex upgrade paths&lt;/li&gt;



&lt;li&gt;Multi-chart repositories with CI optimization needs&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Layer 5: Security and Policy Validation&lt;/h3&gt;



&lt;p&gt;&lt;strong&gt;What it catches:&lt;/strong&gt; Security misconfigurations, policy violations, compliance issues&lt;/p&gt;



&lt;p&gt;This layer prevents deploying charts that pass functional tests but violate organizational security baselines or contain vulnerabilities.&lt;/p&gt;



&lt;h4 class=&quot;wp-block-heading&quot;&gt;Policy Enforcement: Conftest (Open Policy Agent)&lt;/h4&gt;



&lt;p&gt;&lt;a href=&quot;https://www.conftest.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Conftest&lt;/a&gt; is the CLI interface to &lt;a href=&quot;https://www.openpolicyagent.org/docs/latest/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Open Policy Agent&lt;/a&gt; for policy-as-code validation.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Project Profile:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;Parent:&lt;/strong&gt; Open Policy Agent (CNCF Graduated Project)&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Governance:&lt;/strong&gt; Strong CNCF backing, multi-vendor support&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Production adoption:&lt;/strong&gt; Netflix, Pinterest, Goldman Sachs&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Bus Factor:&lt;/strong&gt; Low (graduated CNCF project with multi-vendor backing)&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Policies written in Rego (reusable, composable)&lt;/li&gt;



&lt;li&gt;Works with any YAML/JSON input (not Helm-specific)&lt;/li&gt;



&lt;li&gt;Can enforce organizational standards programmatically&lt;/li&gt;



&lt;li&gt;Integration with admission controllers (Gatekeeper)&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Rego has a learning curve&lt;/li&gt;



&lt;li&gt;Does not replace functional testing&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Example Conftest policy:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;# policy/security.rego
package main

import future.keywords.contains
import future.keywords.if
import future.keywords.in

deny[msg] {
  input.kind == &quot;Deployment&quot;
  container := input.spec.template.spec.containers[_]
  not container.resources.limits.memory
  msg := sprintf(&quot;Container '%s' must define memory limits&quot;, [container.name])
}

deny[msg] {
  input.kind == &quot;Deployment&quot;
  container := input.spec.template.spec.containers[_]
  not container.resources.limits.cpu
  msg := sprintf(&quot;Container '%s' must define CPU limits&quot;, [container.name])
}
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Running the validation:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;helm template my-chart . | conftest test -p policy/ -
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Alternative: Kyverno&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;&lt;a href=&quot;https://kyverno.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Kyverno&lt;/a&gt; offers policy enforcement using native Kubernetes manifests instead of Rego. Policies are written in YAML and can validate, mutate, or generate resources.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Example Kyverno policy:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-resource-limits
spec:
  validationFailureAction: Enforce
  rules:
  - name: check-container-limits
    match:
      resources:
        kinds:
        - Pod
    validate:
      message: &quot;All containers must have CPU and memory limits&quot;
      pattern:
        spec:
          containers:
          - resources:
              limits:
                memory: &quot;?*&quot;
                cpu: &quot;?*&quot;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Conftest vs Kyverno:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Conftest: Policies run in CI, flexible for any YAML&lt;/li&gt;



&lt;li&gt;Kyverno: Runtime enforcement in-cluster, Kubernetes-native&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;Both can coexist: Conftest in CI for early feedback, Kyverno in cluster for runtime enforcement.&lt;/p&gt;



&lt;h4 class=&quot;wp-block-heading&quot;&gt;Vulnerability Scanning: Trivy&lt;/h4&gt;



&lt;p&gt;&lt;a href=&quot;https://github.com/aquasecurity/trivy&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Trivy&lt;/a&gt; by Aqua Security provides comprehensive security scanning for Helm charts.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Project Profile:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;Maintainer:&lt;/strong&gt; Aqua Security (commercial backing with open-source core)&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Scope:&lt;/strong&gt; Vulnerability scanning + misconfiguration detection&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Helm integration:&lt;/strong&gt; Official &lt;code&gt;trivy helm&lt;/code&gt; command&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Bus Factor:&lt;/strong&gt; Low (commercial backing + strong open-source adoption)&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;What Trivy scans in Helm charts:&lt;/strong&gt;&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Vulnerabilities in referenced container images&lt;/li&gt;



&lt;li&gt;Misconfigurations (similar to Conftest but pre-built rules)&lt;/li&gt;



&lt;li&gt;Secrets accidentally committed in templates&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;



&lt;p&gt;&lt;strong&gt;Example scan:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;trivy helm ./charts/my-chart --severity HIGH,CRITICAL --exit-code 1
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Sample output:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;myapp/templates/deployment.yaml (helm)
====================================

Tests: 12 (SUCCESSES: 10, FAILURES: 2)
Failures: 2 (HIGH: 1, CRITICAL: 1)

HIGH: Container 'app' of Deployment 'myapp' should set 'securityContext.runAsNonRoot' to true
&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;
Ensure containers run as non-root users

See &lt;a href=&quot;https://kubernetes.io/docs/concepts/security/pod-security-standards/&quot; rel=&quot;nofollow&quot;&gt;https://kubernetes.io/docs/concepts/security/pod-security-standards/&lt;/a&gt;
&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;
 myapp/templates/deployment.yaml:42
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Commercial support:&lt;/strong&gt;&lt;br&gt;Aqua Security offers Trivy Enterprise with advanced features (centralized scanning, compliance reporting). For most teams, the open-source version is sufficient.&lt;/p&gt;



&lt;h4 class=&quot;wp-block-heading&quot;&gt;Other Security Tools&lt;/h4&gt;



&lt;p&gt;&lt;strong&gt;Polaris (Fairwinds)&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;Polaris scores charts based on security and reliability best practices. Unlike enforcement tools, it provides a health score and actionable recommendations.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Use case:&lt;/strong&gt; Dashboard for chart quality across a platform&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Checkov (Bridgecrew/Palo Alto)&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;Similar to Trivy but with a broader IaC focus (Terraform, CloudFormation, Kubernetes, Helm). Pre-built policies for compliance frameworks (CIS, PCI-DSS).&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;When to use Checkov:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Multi-IaC environment (not just Helm)&lt;/li&gt;



&lt;li&gt;Compliance-driven validation requirements&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Enterprise Selection Criteria&lt;/h2&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Bus Factor and Long-Term Viab&lt;/h3&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/11555/helm-chart-testing-in-production-layers-tools-and-a-minimum-ci-pipeline</guid>
<pubDate>Sat, 14 Feb 2026 09:43:36 +0000</pubDate>
</item>
<item>
<title>Project Weather (Extras): Beyond AI - Building a Robust, User-Centric Dashboard</title>
<link>https://coderlegion.com/10332/project-weather-extras-beyond-ai-building-a-robust-user-centric-dashboard</link>
<description>&lt;p&gt;In previous posts, we explored the core of the &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/apps/weather&quot;&gt;&lt;strong&gt;Project Weather&lt;/strong&gt;&lt;/a&gt;, focusing on its basic backend-frontend platform and its AI prediction capabilities. Once these points were achieved and the application was operational, certain improvement aspects arose concerning a more fluid and intuitive frontend experience.&lt;/p&gt;
&lt;p&gt;This post unveils the &quot;extras&quot;—the significant enhancements and design decisions that transformed Project Weather from a basic pilot into a comprehensive, production-ready weather dashboard. These improvements, although not directly related to AI prediction, were crucial for building a reliable, scalable, and delightful user experience.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://datalaria.com/en/posts/app_openweather_part4_extras_ux/Image_Weather_Extra.png&quot; alt=&quot;Conceptual image of Project Weather Extras Dashboard&quot;&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;1-expanding-metrics-and-data-collection-from-basic-to-comprehensive&quot;&gt;1. Expanding Metrics and Data Collection: From Basic to Comprehensive&lt;/h4&gt;
&lt;p&gt;Our initial weather dashboard, while functional, only provided basic metrics like temperature, wind, and humidity. To evolve into a truly useful weather station, we needed more data. This required significant modifications in both our backend data collection script and the frontend visualization.&lt;/p&gt;
&lt;h5 id=&quot;new-metrics-amp-dynamic-visualizations&quot;&gt;New Metrics &amp;amp; Dynamic Visualizations&lt;/h5&gt;
&lt;p&gt;We revamped our Python &lt;code&gt;read_weather.py&lt;/code&gt; script to fetch and store four new critical weather variables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cloudiness (%):&lt;/strong&gt; Percentage of sky covered.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visibility (km):&lt;/strong&gt; Distance of vision (crucial for fog or haze conditions).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rain (mm):&lt;/strong&gt; Rainfall in the last hour.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Snow (mm):&lt;/strong&gt; Snowfall in the last hour.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the frontend, effectively visualizing these diverse data types was key. We implemented conditional logic within &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.chartjs.org/&quot;&gt;Chart.js&lt;/a&gt; to adapt the chart type based on the data:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Line charts&lt;/strong&gt; for continuous variables like temperature and wind speed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Area (filled) charts&lt;/strong&gt; for humidity and cloudiness, providing a sense of accumulation or coverage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bar charts&lt;/strong&gt; for precipitation (rain/snow), as bars visually represent accumulated amounts more intuitively.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;automatic-data-migration&quot;&gt;Automatic Data Migration&lt;/h5&gt;
&lt;p&gt;A common challenge when adding new data fields to an existing system is managing historical data. We designed a robust backend system to automatically detect and migrate older CSV files (with 11 columns) to the new 15-column format. Crucially, this system elegantly handled the missing values for the new metrics, filling them with sensible default values (e.g., &lt;code&gt;0&lt;/code&gt; for rain/snow), thus preventing any loss of historical context and ensuring data integrity across the entire dataset. This automated process was vital for a smooth, fluid transition without requiring manual intervention.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;2-comprehensive-internationalization-i18n-system-a-truly-global-application&quot;&gt;2. Comprehensive Internationalization (i18n) System: A Truly Global Application&lt;/h4&gt;
&lt;p&gt;To make the Project Weather accessible to a wider audience, a complete internationalization (i18n) system was a top priority. We transformed the web application into a fully bilingual platform (Spanish/English) with dynamic language switching, without the need for page reloads.&lt;/p&gt;
&lt;h5 id=&quot;translation-architecture&quot;&gt;Translation Architecture&lt;/h5&gt;
&lt;p&gt;We built a centralized &lt;code&gt;const translations&lt;/code&gt; dictionary in JavaScript, containing all text strings used in the application. This approach ensured consistency and simplified maintenance.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Static Texts:&lt;/strong&gt; HTML elements requiring translation were tagged with a &lt;code&gt;data-i18n-key&lt;/code&gt; attribute. A JavaScript function then automatically iterated through these elements, replacing their content with the corresponding translation from the active dictionary.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dynamic Texts:&lt;/strong&gt; Crucially, all JavaScript logic responsible for generating dynamic strings (e.g., &quot;Feels like,&quot; &quot;Wind speed,&quot; KPI labels, and chart tooltips) was refactored to read directly from the currently selected language dictionary. This ensured that every piece of text, regardless of whether it was static HTML or dynamically generated, was correctly localized.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;date-and-number-formatting&quot;&gt;Date and Number Formatting&lt;/h5&gt;
&lt;p&gt;Beyond text, cultural formatting for dates and numbers is essential. We leveraged &lt;code&gt;Intl.DateTimeFormat&lt;/code&gt; and integrated it with Chart.js to ensure that dates on chart axes and in data cards were displayed in the culturally correct format (e.g., &quot;10 nov&quot; vs. &quot;Nov 10&quot;). Number formats (e.g., decimal separators) were also adapted accordingly.&lt;/p&gt;
&lt;h5 id=&quot;persistence&quot;&gt;Persistence&lt;/h5&gt;
&lt;p&gt;To enhance user experience, the language preference is stored in &lt;code&gt;localStorage&lt;/code&gt;, so the application remembers the user's chosen language across visits.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;3-advanced-interactivity-custom-time-range-filtering&quot;&gt;3. Advanced Interactivity: Custom Time Range Filtering&lt;/h4&gt;
&lt;p&gt;Empowering users with precise data exploration capabilities was a key objective. We significantly improved the dashboard's interactivity by introducing advanced time range filtering.&lt;/p&gt;
&lt;h5 id=&quot;custom-range-selector&quot;&gt;Custom Range Selector&lt;/h5&gt;
&lt;p&gt;Alongside the predefined ranges (1H, 1D, 1W, 1M, 1Y, All), we added a &quot;Custom&quot; option. Activating this option dynamically reveals two date input fields (&lt;code&gt;start-date&lt;/code&gt; and &lt;code&gt;end-date&lt;/code&gt;).&lt;/p&gt;
&lt;h5 id=&quot;dynamic-filtering-logic&quot;&gt;Dynamic Filtering Logic&lt;/h5&gt;
&lt;p&gt;The core rendering engine for our charts was modified to accept arbitrary start and end dates. This allows users to define any time window. Upon selection, the system recalculates all statistics (maximums, minimums, and averages) and re-renders the graphs based exclusively on the user-defined period. This granular control dramatically improves the analytical utility of the dashboard.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;4-ui-ux-enhancements-polishing-the-user-experience&quot;&gt;4. UI/UX Enhancements: Polishing the User Experience&lt;/h4&gt;
&lt;p&gt;The final touches on UI/UX consisted of refining the aesthetics and usability, transforming a functional dashboard into a polished and engaging application.&lt;/p&gt;
&lt;h5 id=&quot;dynamic-weather-icons&quot;&gt;Dynamic Weather Icons&lt;/h5&gt;
&lt;p&gt;We developed a smart &lt;code&gt;getWeatherIcon&lt;/code&gt; logic that analyzes the weather description returned by the API (e.g., &quot;scattered clouds,&quot; &quot;drizzle&quot;) and the cloudiness percentage. This function dynamically displays the most representative icon from &lt;a rel=&quot;nofollow&quot; href=&quot;https://feathericons.com/&quot;&gt;Feather Icons&lt;/a&gt; (sun, cloud, rain, snow, fog) alongside the city name and current weather condition, providing immediate visual cues about the weather.&lt;/p&gt;
&lt;h5 id=&quot;professional-corporate-header&quot;&gt;Professional Corporate Header&lt;/h5&gt;
&lt;p&gt;The simple page title was replaced by a professional-grade &lt;code&gt;&amp;lt;header&amp;gt;&lt;/code&gt; that integrates:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Datalaria logo.&lt;/li&gt;
&lt;li&gt;A dynamic &quot;How it was made&quot; link that intelligently switches the URL to the English or Spanish version of this blog post, depending on the application's current language setting.&lt;/li&gt;
&lt;li&gt;Grouped configuration controls for language selection and dark mode toggle, providing a clean and organized interface for user preferences.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5 id=&quot;loading-feedback&quot;&gt;Loading Feedback&lt;/h5&gt;
&lt;p&gt;Addressing visual bugs and improving user feedback during asynchronous data processing was critical. We implemented a subtle loading spinner and clear status messages that appear while data is being fetched and rendered. This prevents users from seeing blank or partially loaded charts and assures them that the application is actively processing their requests.&lt;/p&gt;
&lt;hr&gt;
&lt;h4 id=&quot;conclusion-a-holistic-approach-to-application-development&quot;&gt;Conclusion: A Holistic Approach to Application Development&lt;/h4&gt;
&lt;p&gt;While the AI prediction model is a testament to the power of machine learning, these &quot;extra&quot; features are evidence of the comprehensive development approach adopted with the Project Weather. They demonstrate that building a truly valuable application goes beyond its core functionality, encompassing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Robust Data Engineering:&lt;/strong&gt; Ensuring data quality and smooth migration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Global Accessibility:&lt;/strong&gt; Through thoughtful internationalization.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User Empowerment:&lt;/strong&gt; Via advanced filtering options.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Refined User Experience:&lt;/strong&gt; With intuitive visuals and clear feedback.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The result is a weather dashboard with a degree of intelligence, intuitive, and easy to use, in which backend logic and careful frontend design converge.&lt;/p&gt;
&lt;p&gt;Finally, these improvements represent the closing of the first operational version of the project, and from which, in the medium term, we will incorporate new enhancements and changes as they are required and allow us to improve the user experience and experiment with new features and characteristics.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/10332/project-weather-extras-beyond-ai-building-a-robust-user-centric-dashboard</guid>
<pubDate>Fri, 23 Jan 2026 07:06:46 +0000</pubDate>
</item>
</channel>
</rss>