Awesome
Helm CEL Plugin
A Helm plugin that uses Common Expression Language (CEL) to validate values. Instead of using JSON Schema in values.schema.json
, you can write more expressive validation rules using CEL in values.cel.yaml
.
Installation
Using Helm Plugin Manager
helm plugin install https://github.com/idsulik/helm-cel
Using Docker
# Pull the image
docker pull idsulik/helm-cel:latest # main branch
docker pull idsulik/helm-cel:2.1.2 # specific version
# Run validation
docker run --rm -v $(pwd):/charts idsulik/helm-cel validate /charts/mychart
# Generate validation rules
docker run --rm -v $(pwd):/charts idsulik/helm-cel generate /charts/mychart
Building from Source
git clone https://github.com/idsulik/helm-cel
cd helm-cel
make install
Usage
Validation
Validate your chart values using the validate command:
helm cel validate ./mychart
Options:
--values-file, -v Values files to validate (comma-separated or multiple flags)
Defaults to values.yaml
--rules-file, -r Rules files to validate against (comma-separated or multiple flags)
Defaults to values.cel.yaml
Example with custom files:
# Using single values and rules files
helm cel validate ./mychart --values-file prod.values.yaml --rules-file prod.cel.yaml
# Using multiple values files (later files take precedence)
helm cel validate ./mychart --values-file common.yaml --values-file prod.yaml
# Using comma-separated values files
helm cel validate ./mychart --values-file common.yaml,prod.yaml,overrides.yaml
# Using multiple rules files
helm cel validate ./mychart --rules-file global.cel.yaml --rules-file ingress.cel.yaml
# Combining multiple values and rules files
helm cel validate ./mychart \
--values-file common.yaml,prod.yaml \
--rules-file global.cel.yaml,ingress.cel.yaml,deployment.cel.yaml
Generating Rules
You can automatically generate validation rules based on your values file structure:
helm cel generate ./mychart
Options:
--force, -f Force overwrite existing rules file
--values-file, -v Values file to generate rules from (defaults to values.yaml)
--output-file, -o Output file for generated rules (defaults to values.cel.yaml)
Example with custom files:
helm cel generate ./mychart --values-file prod.values.yaml --output-file prod.cel.yaml --force
Rule Organization
You can organize your validation rules into multiple files for better maintainability. Files must have the .cel.yaml
extension. Example structure:
mychart/
├── Chart.yaml
├── values.yaml
└── cel/
├── global.cel.yaml # Global configuration rules
├── ingress.cel.yaml # Ingress-specific rules
└── deployment.cel.yaml # Deployment-specific rules
When using multiple rule files, expressions are shared across all files but must be unique (no duplicate expression names allowed).
Rule Structure
Each rule in values.cel.yaml
consists of:
expr
: A CEL expression that should evaluate totrue
for valid valuesdesc
: A description of what the rule validatesseverity
: Optional severity level ("error" or "warning", defaults to "error")
Example values.cel.yaml
:
rules:
- expr: "has(values.service) && has(values.service.port)"
desc: "service port is required"
- expr: "values.service.port >= 1 && values.service.port <= 65535"
desc: "service port must be between 1 and 65535"
severity: warning
- expr: "!(has(values.replicaCount)) || values.replicaCount >= 1"
desc: "if replicaCount is set, it must be at least 1"
Severity Levels
Rules can have two severity levels:
error
: Validation fails if the rule is not satisfied (default)warning
: Shows a warning but allows validation to pass
Common Validation Patterns
- Required fields:
- expr: "has(values.fieldName)"
desc: "fieldName is required"
- Value constraints:
- expr: "values.number >= 0 && values.number <= 100"
desc: "number must be between 0 and 100"
- Type validation:
- expr: "type(values.ports) == list"
desc: "ports must be a list"
- Resource validation:
- expr: 'values.resources.requests.memory.matches("^[0-9]+(Mi|Gi)$")'
desc: "memory requests must be in Mi or Gi"
- Port validation:
- expr: "values.service.port >= 1 && values.service.port <= 65535"
desc: "port must be valid"
Reusable Expressions
You can define expressions to reuse across rules:
expressions:
portRange: 'values.service.port >= 1 && values.service.port <= 65535'
nodePortRange: 'values.service.nodePort >= 30000 && values.service.nodePort <= 32767'
rules:
- expr: "${portRange}"
desc: "Service port must be valid"
- expr: 'values.service.type == "NodePort" ? ${nodePortRange} : true'
desc: "NodePort must be valid when type is NodePort"
Validation Results
If validation fails, you'll get a clear error message:
❌ Validation failed: replica count must be at least 1
Rule: values.replicaCount >= 1
Path: replicaCount
Current value: 0
With warnings:
Found 1 warning(s):
⚠️ Service port must be between 1 and 65535
Rule: values.service.port >= 1 && values.service.port <= 65535
Path: service.port
Current value: 80801
-------------------------------------------------
⚠️✅ Values validation successful with warnings!
If all rules pass, you'll see a success message:
✅ Values validation successful!
Development
Requirements:
- Go 1.22 or later
Build:
make build
Install locally:
make install
Run tests:
make test
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
License
Distributed under the MIT License. See LICENSE
for more information.