Skip to content

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.

License

Notifications You must be signed in to change notification settings

idsulik/helm-cel

Repository files navigation

License Current Release GitHub Repo stars GitHub issues GitHub pull requests codecov Artifact Hub

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
--output, -o         Output format: text, json, or yaml
                     Defaults to text

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 JSON output format
helm cel validate ./mychart -o json

# 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 to true for valid values
  • desc: A description of what the rule validates
  • severity: 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

  1. Required fields:
- expr: "has(values.fieldName)"
  desc: "fieldName is required"
  1. Value constraints:
- expr: "values.number >= 0 && values.number <= 100"
  desc: "number must be between 0 and 100"
  1. Type validation:
- expr: "type(values.ports) == list"
  desc: "ports must be a list"
  1. Resource validation:
- expr: 'values.resources.requests.memory.matches("^[0-9]+(Mi|Gi)$")'
  desc: "memory requests must be in Mi or Gi"
  1. 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!

Structured Output Formats

You can output validation results in JSON or YAML format for integration with CI/CD pipelines:

# JSON output
helm cel validate ./mychart -o json

# YAML output
helm cel validate ./mychart -o yaml

JSON output example:

{
  "has_errors": true,
  "has_warnings": true,
  "result": {
    "errors": [
      {
        "description": "replicaCount must be at least 1",
        "expression": "values.replicaCount >= 1",
        "value": 0,
        "path": "replicaCount"
      }
    ],
    "warnings": [
      {
        "description": "service port should be between 1 and 65535",
        "expression": "values.service.port >= 1 && values.service.port <= 65535",
        "value": 80801,
        "path": "service.port"
      }
    ]
  }
}

YAML output example:

has_errors: true
has_warnings: true
result:
  errors:
  - description: replicaCount must be at least 1
    expression: values.replicaCount >= 1
    value: 0
    path: replicaCount
  warnings:
  - description: service port should be between 1 and 65535
    expression: values.service.port >= 1 && values.service.port <= 65535
    value: 80801
    path: service.port

Development

Requirements:

  • Go 1.22 or later

Build:

make build

Install locally:

make install

Run tests:

make test

Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

Distributed under the MIT License. See LICENSE for more information.

About

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.

Topics

Resources

License

Stars

Watchers

Forks

Languages