Skip to main content

Module error

Module error 

Source
Expand description

Typed validation errors shared by the admission webhook and the controller.

Per ADR-0003 §2.2 (principle 8) and the SKILL “one validator, two callers” rule, cross-field validation lives in crate::validate as pure functions returning these typed errors. The webhook rejects at admission; the controller calls the same functions defensively before reconcile. The error type is the contract between them, so messages must be actionable — they end up in a kubectl apply rejection and in controller logs verbatim.

§Accumulation vs. fail-fast

Per-field helpers (e.g. crate::validate::validate_repository_ref) are fail-fast: they return the first problem they find as ValidationResult. The per-CRD aggregate validators (validate_backup_config, …) accumulate every independent problem into a Vec<ValidationError> so a user fixing one manifest sees all issues at once rather than playing whack-a-mole across re-applies. Both styles share this one error enum.

use kopiur_api::ValidationError;

// Messages are written for a human reading a rejected `kubectl apply` — they
// say what is wrong and why, embedding the offending value.
let err = ValidationError::DiscoveredMustRetain { got: "Delete".to_string() };
assert!(err.to_string().contains("origin: discovered"));
assert!(err.to_string().contains("Delete"));

// `ValidationResult` defaults its Ok type to `()` for the pass/fail case.
let ok: kopiur_api::ValidationResult = Ok(());
assert!(ok.is_ok());

Enums§

ValidationError
A single cross-field validation failure. PartialEq so tests can assert the exact variant; messages are written for an end user reading a rejected apply.

Type Aliases§

ValidationResult
Result alias for validators. Defaults to () for the common “pass/fail with no value” case.