Skip to content

feat(validation): add oldSelf support to x-deckhouse-validations CEL rules#764

Merged
ldmonster merged 2 commits into
mainfrom
feature/validation-check-oldself
May 25, 2026
Merged

feat(validation): add oldSelf support to x-deckhouse-validations CEL rules#764
ldmonster merged 2 commits into
mainfrom
feature/validation-check-oldself

Conversation

@ldmonster
Copy link
Copy Markdown
Collaborator

Summary

Adds oldSelf transition-rule support to x-deckhouse-validations CEL expressions, mirroring the semantics of x-kubernetes-validations in Kubernetes CRD validation.

Previously, CEL rules in module schemas could only inspect the current value (self). This change threads the previous value through the entire validation stack so that rules can also reference oldSelf to implement update-time invariants — most notably immutability constraints on ModuleConfig fields.

Changes

pkg/values/validation/cel/cel.go

  • Renamed Validate to a thin wrapper; introduced ValidateTransition(schema, values, oldValues) as the main entry point.
  • oldSelf is bound as a CEL variable at each schema level and resolved recursively by matching property names in the old value map.
  • Rules that reference oldSelf are detected via AST traversal (expressionUsesOldSelf) and skipped when no previous value exists at that schema level (create path or newly added subtrees). This prevents oldSelf-referencing rules from failing on initial creation.

pkg/values/validation/schemas.go

  • Added ValidateTransition, ValidateConfigValuesTransition, ValidateValuesTransition, and ValidateModuleHelmValuesTransition on SchemaStorage.
  • Validate now delegates to ValidateTransition(…, nil), keeping all existing callers working without changes.
  • validateObject accepts an optional oldDataObj and passes it to cel.ValidateTransition.

pkg/module_manager/models/modules/values_storage.go

  • validateConfigValues now calls ValidateConfigValuesTransition, passing the currently stored configValues as the old state.
  • validateValues now calls ValidateValuesTransition, passing the currently merged resultValues as the old state.

pkg/values/validation/cel/cel_test.go (new)

Full test suite covering:

  • No rules / plain rules (no regression)
  • oldSelf-only rules skipped on create
  • oldSelf rules fire correctly on update
  • Nested immutable field enforcement
  • Newly added subtree treated as create (transition skipped)
  • Mixed plain + transition rules
  • oldSelf inside CEL macros/comprehensions (e.g. all(x, x in oldSelf.items))
  • Backward compatibility via the Validate wrapper

Usage example

x-deckhouse-validations:
  - expression: "self.mode == oldSelf.mode"
    message: "mode is immutable after creation"

Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
Signed-off-by: Pavel Okhlopkov <pavel.okhlopkov@flant.com>
@ldmonster ldmonster merged commit 1dd3f48 into main May 25, 2026
8 of 9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant