#![allow(dead_code)]
use kube_cel::Validator;
use serde_json::{Value, json};
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Verdict {
Accept,
Reject,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum Expect {
Accept,
Reject,
RegistrationRejected,
}
impl Expect {
pub fn verdict(self) -> Verdict {
match self {
Expect::Accept => Verdict::Accept,
Expect::Reject => Verdict::Reject,
Expect::RegistrationRejected => {
panic!("RegistrationRejected has no runtime verdict")
}
}
}
}
pub struct ParityCase {
pub kind: &'static str,
pub plural: &'static str,
pub schema: Value,
pub object: Value,
pub expect: Expect,
pub note: &'static str,
}
pub fn kubecel_verdict(schema: &Value, object: &Value) -> Verdict {
match Validator::new().validate(schema, object, None) {
Ok(()) => Verdict::Accept,
Err(_) => Verdict::Reject,
}
}
pub fn kubecel_verdict_with_defaults(schema: &Value, object: &Value) -> Verdict {
match Validator::new().validate_with_defaults(schema, object, None) {
Ok(()) => Verdict::Accept,
Err(_) => Verdict::Reject,
}
}
pub fn cases() -> Vec<ParityCase> {
vec![
ParityCase {
kind: "PmapObj",
plural: "pmapobjs",
schema: json!({
"type": "object",
"properties": { "m": { "type": "object", "additionalProperties": {"type": "string"} } },
"x-kubernetes-validations": [{ "rule": "!('a.b/c' in self.m)", "message": "forbidden key" }]
}),
object: json!({"m": {"a.b/c": "x"}}),
expect: Expect::Reject,
note: "typed map with forbidden literal key → REJECT",
},
ParityCase {
kind: "PmapTrue",
plural: "pmaptrues",
schema: json!({
"type": "object",
"properties": { "m": { "type": "object", "additionalProperties": true } },
"x-kubernetes-validations": [{ "rule": "!('a.b/c' in self.m)", "message": "forbidden key" }]
}),
object: Value::Null,
expect: Expect::RegistrationRejected,
note: "`in` on a free-form map is not expressible → rejected at registration",
},
ParityCase {
kind: "PlistMap",
plural: "plistmaps",
schema: json!({
"type": "object",
"properties": {
"l": { "type": "array", "items": { "type": "object", "additionalProperties": {"type": "string"} } }
},
"x-kubernetes-validations": [{ "rule": "self.l.all(e, !('a.b/c' in e))", "message": "forbidden key" }]
}),
object: json!({"l": [{"a.b/c": "x"}]}),
expect: Expect::Reject,
note: "forbidden key in a list-element map → REJECT",
},
ParityCase {
kind: "PmapMap",
plural: "pmapmaps",
schema: json!({
"type": "object",
"properties": {
"m": {
"type": "object",
"additionalProperties": { "type": "object", "additionalProperties": {"type": "string"} }
}
},
"x-kubernetes-validations": [{ "rule": "self.m.all(k, !('a.b/c' in self.m[k]))", "message": "forbidden key" }]
}),
object: json!({"m": {"grp": {"a.b/c": "x"}}}),
expect: Expect::Reject,
note: "forbidden key in a nested map value → REJECT",
},
ParityCase {
kind: "PmapResv",
plural: "pmapresvs",
schema: json!({
"type": "object",
"properties": { "m": { "type": "object", "additionalProperties": {"type": "string"} } },
"x-kubernetes-validations": [{ "rule": "'in' in self.m", "message": "needs in" }]
}),
object: json!({"m": {"in": "x"}}),
expect: Expect::Accept,
note: "literal reserved-word map key satisfies the rule → ACCEPT",
},
ParityCase {
kind: "PmapOk",
plural: "pmapoks",
schema: json!({
"type": "object",
"properties": { "m": { "type": "object", "additionalProperties": {"type": "string"} } },
"x-kubernetes-validations": [{ "rule": "!('a.b/c' in self.m)", "message": "forbidden key" }]
}),
object: json!({"m": {"harmless": "x"}}),
expect: Expect::Accept,
note: "harmless map key → ACCEPT (control)",
},
ParityCase {
kind: "PstructEsc",
plural: "pstructescs",
schema: json!({
"type": "object",
"properties": {
"spec": {
"type": "object",
"properties": { "foo.bar": { "type": "string" } },
"x-kubernetes-validations": [{ "rule": "self.foo__dot__bar == 'ok'", "message": "bad" }]
}
}
}),
object: json!({"spec": {"foo.bar": "ok"}}),
expect: Expect::Accept,
note: "dotted declared field reached via escaped identifier → ACCEPT",
},
ParityCase {
kind: "Pdefclosed",
plural: "pdefcloseds",
schema: json!({
"type": "object",
"properties": { "x": { "type": "string", "default": "d" } },
"x-kubernetes-validations": [{ "rule": "self.x == 'd'", "message": "x must be d" }]
}),
object: json!({}),
expect: Expect::Accept,
note: "default applied → self.x == 'd' → ACCEPT (was fail-closed)",
},
ParityCase {
kind: "Pdefopen",
plural: "pdefopens",
schema: json!({
"type": "object",
"properties": { "x": { "type": "string", "default": "d" } },
"x-kubernetes-validations": [{ "rule": "!has(self.x)", "message": "x must be absent" }]
}),
object: json!({}),
expect: Expect::Reject,
note: "default makes x present → !has false → REJECT (was fail-open)",
},
ParityCase {
kind: "Pdefnest",
plural: "pdefnests",
schema: json!({
"type": "object",
"properties": {
"spec": {
"type": "object",
"properties": { "x": { "type": "string", "default": "d" } },
"x-kubernetes-validations": [{ "rule": "!has(self.x)", "message": "x must be absent" }]
}
}
}),
object: json!({ "spec": {} }),
expect: Expect::Reject,
note: "nested default makes spec.x present → REJECT",
},
ParityCase {
kind: "Pdefarr",
plural: "pdefarrs",
schema: json!({
"type": "object",
"properties": {
"list": {
"type": "array",
"items": {
"type": "object",
"properties": { "x": { "type": "string", "default": "d" } },
"x-kubernetes-validations": [{ "rule": "!has(self.x)", "message": "x must be absent" }]
}
}
}
}),
object: json!({ "list": [ {} ] }),
expect: Expect::Reject,
note: "item default makes x present → REJECT",
},
ParityCase {
kind: "Pdefap",
plural: "pdefaps",
schema: json!({
"type": "object",
"properties": {
"m": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": { "x": { "type": "string", "default": "d" } },
"x-kubernetes-validations": [{ "rule": "!has(self.x)", "message": "x must be absent" }]
}
}
}
}),
object: json!({ "m": { "a": {} } }),
expect: Expect::Reject,
note: "map-value default makes x present → REJECT (#9 nested-AP gap)",
},
ParityCase {
kind: "Pdefreq",
plural: "pdefreqs",
schema: json!({
"type": "object",
"properties": { "x": { "type": "string", "default": "d" } },
"required": ["x"],
"x-kubernetes-validations": [{ "rule": "self.x == 'd'", "message": "x must be d" }]
}),
object: json!({}),
expect: Expect::Accept,
note: "default fills required field → self.x == 'd' → ACCEPT",
},
ParityCase {
kind: "PfmtExp",
plural: "pfmtexps",
schema: json!({
"type": "object",
"properties": {},
"x-kubernetes-validations": [{ "rule": "'val: %.2e'.format([1500.0]) == 'val: 1.50e3'", "message": "exp" }]
}),
object: json!({}),
expect: Expect::Reject,
note: "format %e is Go-style 1.50e+03, not 1.50e3 → REJECT (F1a)",
},
ParityCase {
kind: "PfmtMap",
plural: "pfmtmaps",
schema: json!({
"type": "object",
"properties": {},
"x-kubernetes-validations": [{ "rule": "'%s'.format([{'a': 1}]) == '{\"a\": 1}'", "message": "map" }]
}),
object: json!({}),
expect: Expect::Reject,
note: "format %s on map is {\"a\":1} (no space) → REJECT (F1b)",
},
ParityCase {
kind: "PstrLast",
plural: "pstrlasts",
schema: json!({
"type": "object",
"properties": {},
"x-kubernetes-validations": [{ "rule": "'abcabc'.lastIndexOf('abc', 3) == 0", "message": "last" }]
}),
object: json!({}),
expect: Expect::Reject,
note: "lastIndexOf offset is inclusive start (=3), not 0 → REJECT (F2)",
},
ParityCase {
kind: "PbyteSize",
plural: "pbytesizes",
schema: json!({
"type": "object",
"properties": { "b": { "type": "string", "format": "byte" } },
"x-kubernetes-validations": [{ "rule": "self.b.size() == 5", "message": "byte" }]
}),
object: json!({ "b": "aGVsbG8=" }),
expect: Expect::Accept,
note: "format:byte binds as bytes → size()==5 → ACCEPT (F3)",
},
]
}