NatLabRockies / NatLabRockies/openstudio-server-helm
Establish CI/CD Pipeline for Helm Chart Repository
Nobody has claimed this yet.
- Dominant language
- Go Template
- Stars
- 12
- Forks
- 24
- PR merge metrics
- No merged PRs in 30d
Description
Establishing a Reliable CI/CD Pipeline for Helm Chart Repository
Based on industry best practices for 2026, we need to implement a structured, multi-tiered CI/CD pipeline for our Helm chart repository that covers linting, static analysis, unit testing, integration testing on ephemeral clusters, and secure automated packaging/releasing.
Recommended Repository Structure
We should restructure our repository to segregate workflows, global configurations, and individual charts:
my-helm-charts/
├── .github/
│ └── workflows/
│ ├── lint-test.yml # Runs on PRs (Linting, Unit & Integration Tests)
│ └── release.yml # Runs on Merges/Tags (Packages & Publishes OCI/Pages)
├── charts/
│ ├── app-one/
│ │ ├── Chart.yaml
│ │ ├── values.yaml
│ │ ├── values.schema.json # Strongly recommended for strict input validation
│ │ ├── templates/
│ │ └── tests/ # Helm test templates (integration probes)
│ │ └── connection-test.yaml
├── ct.yaml # Chart-testing CLI configuration
├── lintconf.yaml # yamllint rule configuration
└── README.md
Multi-Tiered Testing Strategy
Our testing should be divided into four distinct layers:
Layer 1: Schema & Static Validation
- Helm Schema Validation: Maintain a
values.schema.jsonfile in each chart directory. This enforces parameter types and prevents invalid configurations before templates are even rendered. - YAML Linting: Use
yamllintto check all configuration files. - Chart-Testing CLI (
ct): The standard tool for multi-chart repositories. It detects modified files (to avoid testing unchanged charts) and enforces Semantic Versioning (SemVer) increments on modified charts.
Layer 2: Template & Unit Testing
- Helm Unit Test Plugin (
helm-unittest): This plugin allows you to write test suites in YAML to mock values and verify that templates render with the exact expected Kubernetes manifests. It catch typos or copy-paste errors early without requiring a live cluster.
Layer 3: Integration Testing (Ephemeral Cluster)
- KinD (Kubernetes in Docker): Spin up a lightweight local Kubernetes cluster directly inside the GitHub Actions runner.
ct install: Installs the changed chart onto the ephemeral cluster to verify that Kubernetes accepts the rendered manifests without runtime schema validation errors.helm testProbes: Include container probes (e.g., curl/ping checks) inside thetemplates/tests/directory. Run these post-installation to verify that the deployed pods can communicate and start up properly.
Layer 4: Security & Supply Chain Security
- Vulnerability & Misconfiguration Scanning: Use tools like Trivy or Checkov to scan rendered templates for Kubernetes security risks (like running as root, missing resource limits, or using vulnerable base images).
GitHub Actions Workflows
We need to implement two standard workflows:
Pipeline A: Lint, Unit Test, and Ephemeral Install (Run on Pull Requests)
This workflow handles checking out code, running static analysis, executing unit tests, booting a KinD cluster, and verifying live installation.
# .github/workflows/lint-test.yml
name: Lint and Test Charts
on:
pull_request:
paths:
- 'charts/**'
- '.github/workflows/lint-test.yml'
permissions:
contents: read
jobs:
lint-test:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0 # Essential for 'ct' to compare history against target branch
- name: Set up Helm
uses: azure/setup-helm@v4
with:
version: v3.14.0
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.x'
- name: Set up Chart-Testing
uses: helm/chart-testing-action@v2
- name: Run ct list-changed
id: list-changed
run: |
changed=$(ct list-changed --target-branch ${{ github.event.repository.default_branch }})
if [[ -n "$changed" ]]; then
echo "changed=true" >> "$GITHUB_OUTPUT"
fi
- name: Run ct lint
if: steps.list-changed.outputs.changed == 'true'
run: ct lint --config ct.yaml
- name: Install helm-unittest plugin
if: steps.list-changed.outputs.changed == 'true'
run: |
helm plugin install https://github.com/quintush/helm-unittest
- name: Run Helm Unit Tests
if: steps.list-changed.outputs.changed == 'true'
run: |
for chart in $(ct list-changed --target-branch ${{ github.event.repository.default_branch }}); do
if [ -d "$chart/tests" ]; then
helm unittest "$chart"
fi
done
- name: Create KinD Cluster
if: steps.list-changed.outputs.changed == 'true'
uses: helm/kind-action@v1.12.0
- name: Run ct install (Integration Test)
if: steps.list-changed.outputs.changed == 'true'
run: ct install --target-branch ${{ github.event.repository.default_branch }}
Pipeline B: Automate Releases (Run on Merge to main)
In 2026, publishing Helm charts relies on two primary channels: GitHub Pages (legacy standard) or OCI Registries (modern standard) using GitHub Container Registry (GHCR).
# .github/workflows/release.yml
name: Release Charts
on:
push:
branches:
- main
paths:
- 'charts/**'
permissions:
contents: write # Required for publishing to GH Pages releases
packages: write # Required for publishing to GHCR
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure Git
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
- name: Set up Helm
uses: azure/setup-helm@v4
# OPTION A: Release to OCI Registry (GitHub Container Registry)
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Package & Push OCI Charts
run: |
for chart in charts/*/; do
helm package "$chart"
helm push *.tgz oci://ghcr.io/${{ github.repository_owner }}/charts
rm *.tgz
done
# OPTION B (Alternative): Release using Chart Releaser (GitHub Pages/Releases)
- name: Run Chart Releaser
uses: helm/chart-releaser-action@v1.6.0
env:
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
Key Best Practices for 2026
- Prefer OCI Registries over Classic HTTP Repositories: Use OCI (like GHCR, AWS ECR, or Docker Hub) to store and version your Helm charts. They offer better access controls, benefit from native container vulnerability scanning, and align with modern deployment tools.
- Auto-Generate Documentation: Avoid manually editing your
README.mdvalues tables. Usehelm-docsin a pre-commit hook or GitHub Action to automatically generate comprehensive documentation directly from comments in yourvalues.yaml. - Always Set Strict Resource Limits: KinD clusters running inside free GitHub runners have limited CPU and memory. Make sure your charts use reasonable resource requests/limits, and configure generous startup timeouts (
--timeout 600s) on the install step to avoid pipeline failures caused by slow runner environments. - Sign Your Charts: To secure your software supply chain, integrate Cosign into your release pipeline to cryptographically sign your packaged charts, allowing consumers to verify chart authenticity.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reviewing the existing chart directories and the proposed .github/workflows/lint-test.yml and release.yml, then read the ct.yaml and chart tests described in the issue. The work is complete when pull requests validate changed charts through linting, unit tests, and KinD installation, while merges package and publish charts through the selected release channel with the required security checks.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- docker, github-actions, helm, kubernetes
- Domain
- ci-cd, devops, infrastructure
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100