Skip to content

Commit 76d76b9

Browse files
committed
changed mind about oenps
1 parent 04cdac4 commit 76d76b9

File tree

1 file changed

+16
-14
lines changed
  • keps/sig-api-machinery/4153-declarative-validation

1 file changed

+16
-14
lines changed

keps/sig-api-machinery/4153-declarative-validation/README.md

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -799,7 +799,7 @@ We will need to add the ability for fields that re-use a type to specify a
799799
field-level for its nested fields. Kube-openapi gen will inline the custom
800800
definition.
801801

802-
#### Representing Go-isms in Schema
802+
#### Zero values, `null`, and `omitempty`
803803

804804
Our native types are backed by Go and serialized into Go for mutation, defaulting
805805
and other transformations before being used for validation. The schemas presented
@@ -822,7 +822,7 @@ and propose additional schema annotations to make our native type schemas more
822822
representative of their implicit constraints to ensure all validations are
823823
ported correctly.
824824

825-
##### Dropped Fields in Unstructured Conversion
825+
##### `omitempty` Primitives Have Incorrect Schema
826826

827827
Consider the following omitempty non-pointer field from `DeploymentSpec`:
828828

@@ -857,23 +857,25 @@ field not to be considered during validation, even if it was included.
857857
This would surface as:
858858
1. `has(self.paused)` in CEL on the Container object always returns `false` if
859859
that value is `false`. But a CRD with identical schema would return `true`.
860+
A proof of concept example of how this bug could bite users of ValidatingAdmissionPolicy
861+
is [here](https://github.com/kubernetes/kubernetes/pull/120244).
860862
2. CEL and JSONSchema Validations of the field if they exist also will not run.
863+
But this is not a concern as long as empty values are assumed to match the schema.
861864

862-
This class of problem exclusively affects `omitempty` non-pointer fields: pointers
863-
to the openapi-generater are treated as optionals and nil used to disambiguate
864-
set/unset.
865+
There are two alternative approaches to address the difference in behavior
866+
of native types vs CRDs in the schema.
865867

866-
There are two alternative approaches to address this in the schema:
868+
1. Express in schema that zero values are considered unset: by adding an
869+
x-kubernetes extension like `x-kubernetes-zero-is-unset: true` to fields where
870+
this is true.
871+
2. Express in schema that unset values are considered zero: by settings its
872+
`default` to the empty value for the type.
873+
874+
Option 2 has the drawback of applying a default to fields where the zero
875+
value is not considered a default. For cases like `Paused` this is correct,
876+
but for most cases involving `string`, the empty string is treated as `unset`.
867877

868-
1. Express in schema that zero values are considered unset by adding
869-
an x-kubernetes extension like `x-kubernetes-zero-unset: true` to fields where
870-
this is true.
871-
2. Express in schema that unset values are considered zero by settings
872-
its `default` to the empty value.
873878

874-
Option 2 seems best, since this is already done for `struct` types, there is
875-
already support for `default` in OpenAPI, and the solution naturally expresses
876-
Go's behavior of `unset` being implicitly defaulted to zero.
877879

878880
An exhaustive list of all 730 omit-empty non-pointer is [found here](https://gist.github.com/alexzielenski/05f594f3974aec9b3e74620b8dc7dde1). Struct types already have their
879881
defaults populated with the go zero value, so they are excluded from this list.

0 commit comments

Comments
 (0)