Skip to content

Helm Values Schema

Reference documentation for the values.schema.json JSON Schema that validates Helm chart values for the keystone-operator chart. Helm enforces this schema automatically during helm install, helm upgrade, helm lint, and helm template.

File Location

text
operators/keystone/helm/keystone-operator/values.schema.json

Generated file

This schema is generated from the shared source in hack/gen-helm-values-schema.py, which also emits the c5c3-operator schema from the same definitions so the two cannot drift. Edit the generator and run make gen-helm-schema; do not hand-edit values.schema.jsonmake verify-helm-schema (run in CI) fails on drift.

Schema Overview

The schema uses JSON Schema Draft-07 and defines constraints for every configurable parameter in values.yaml. No additional properties are allowed at any object level, ensuring typos and unsupported keys are caught at deploy time rather than silently ignored.

PropertyValue
JSON Schema Draftdraft-07
Chart version0.2.0 (bumped from 0.1.0 to signal the schema validation feature)
additionalPropertiesfalse at all object levels

Validated Properties

image

FieldTypeConstraintDefault
image.repositorystringghcr.io/c5c3/keystone-operator
image.tagstring""
image.pullPolicystringenum: Always, IfNotPresent, NeverIfNotPresent

replicas

FieldTypeConstraintDefault
replicasintegerminimum: 12

resources

Resource fields (cpu, memory) use a shared resourceQuantity definition that accepts either a Kubernetes quantity string matching the pattern ^(\.[0-9]+|[0-9]+(\.[0-9]*)?)((e[0-9]+)|(m|k|M|G|T|P|E|Ki|Mi|Gi|Ti|Pi|Ei))?$ or a non-negative number. The pattern enforces mutual exclusion between exponent notation (e[0-9]+) and SI/binary suffixes — values like 1e3m or 1e3Ki are rejected because the Kubernetes quantity grammar does not allow combining both.

FieldTypeConstraintDefault
resources.limits.cpuresourceQuantitypattern or number >= 0500m
resources.limits.memoryresourceQuantitypattern or number >= 0128Mi
resources.requests.cpuresourceQuantitypattern or number >= 010m
resources.requests.memoryresourceQuantitypattern or number >= 064Mi

rbac

FieldTypeConstraintDefault
rbac.namespaceScopedbooleanconditional: requires webhook.enabled=falsefalse

Conditional constraint: When rbac.namespaceScoped is true, the schema requires webhook.enabled to be false. This is enforced via a top-level if/then rule. Namespace-scoped RBAC cannot coexist with webhooks because ValidatingWebhookConfiguration and MutatingWebhookConfiguration are cluster-scoped resources that require a ClusterRole to manage.

Production recommendation: For a control plane confined to a single namespace, set rbac.namespaceScoped: true to bound a compromised operator pod to one namespace's Secrets instead of the cluster-wide Secret access the default ClusterRole grants — see Multi-Tenant Deployment → Security trade-off for the privilege-escalation path this closes. The default stays false because some capabilities still need cluster scope.

leaderElection

FieldTypeConstraintDefault
leaderElection.enabledbooleantrue

webhook

FieldTypeConstraintDefault
webhook.enabledbooleantrue

metrics

FieldTypeConstraintDefault
metrics.portintegerminimum: 1, maximum: 655358080

logging

The operator runs the controller-runtime zap logger in the production profile by default (development: false): JSON encoder, info-level verbosity, and stack traces only at error level. Override these for human-readable console output during local development. Each value maps to a controller-runtime --zap-* flag and is omitted from the operator args when left at its default, so the production profile is the behaviour unless a field is set explicitly.

FieldTypeConstraintDefault
logging.developmentbooleanfalse
logging.levelstringpattern: debug, info, error, panic, or a positive integer (empty allowed)""
logging.encoderstringenum: json, console (empty allowed)""

serviceAccount

FieldTypeConstraintDefault
serviceAccount.createbooleantrue
serviceAccount.namestring""

Name Overrides

FieldTypeConstraintDefault
nameOverridestring""
fullnameOverridestring""

Validation Behavior

Helm validates the merged values object against the schema before template rendering. Validation failures produce errors with the JSON path of the offending value:

text
Error: values don't meet the specifications of the schema(s) in the following chart(s):
keystone-operator:
- at '/image/pullPolicy': value must be one of 'Always', 'IfNotPresent', 'Never'

Commands That Trigger Validation

CommandValidates
helm installYes
helm upgradeYes
helm lintYes
helm templateYes

Resource Quantity Definition

The resourceQuantity definition uses anyOf to accept two formats:

  1. String format — matches the Kubernetes resource quantity pattern (e.g., 500m, 128Mi, 1Gi, 0.5).
  2. Numeric format — any non-negative number (e.g., 0, 0.5, 1).

This allows both cpu: "500m" (string) and cpu: 0.5 (number) as valid inputs while rejecting malformed strings like cpu: "not-valid" and negative numbers like cpu: -1.

Test Coverage

Schema validation is tested with helm-unittest in operators/keystone/helm/keystone-operator/tests/schema_validation_test.yaml.

Negative Tests (rejection)

CategoryExample
Type violationsreplicas: "abc" (string instead of integer)
Enum violationsimage.pullPolicy: "InvalidPolicy"
Range violationsreplicas: 0, metrics.port: 65536
Unknown propertiesimage.digest: "sha256:abc"
Invalid quantitiesresources.limits.cpu: "not-valid"
Exponent+suffixcpu: "1e3m", memory: "1e3Ki"
Conditional constraintrbac.namespaceScoped=true with webhook.enabled=true
Logging constraintslogging.development: "yes", logging.encoder: "xml", logging.level: "verbose"

Positive Tests (acceptance)

CategoryExample
Custom replicasreplicas: 5
Custom metrics portmetrics.port: 9090
String resource quantitiescpu: "2", memory: "1Gi"
Numeric resource quantitiescpu: 0.5
Exponent-only quantitiescpu: "1e3"
Conditional constraintrbac.namespaceScoped=true with webhook.enabled=false
Logging overridesdevelopment: true, level: debug, encoder: console