@@ -45,6 +45,8 @@ pub enum KubernetesDriverError {
4545 #[ error( "sandbox already exists" ) ]
4646 AlreadyExists ,
4747 #[ error( "{0}" ) ]
48+ InvalidArgument ( String ) ,
49+ #[ error( "{0}" ) ]
4850 Precondition ( String ) ,
4951 #[ error( "{0}" ) ]
5052 Message ( String ) ,
@@ -63,6 +65,7 @@ impl From<KubernetesDriverError> for openshell_core::ComputeDriverError {
6365 fn from ( err : KubernetesDriverError ) -> Self {
6466 match err {
6567 KubernetesDriverError :: AlreadyExists => Self :: AlreadyExists ,
68+ KubernetesDriverError :: InvalidArgument ( m) => Self :: InvalidArgument ( m) ,
6669 KubernetesDriverError :: Precondition ( m) => Self :: Precondition ( m) ,
6770 KubernetesDriverError :: Message ( m) => Self :: Message ( m) ,
6871 }
@@ -89,14 +92,38 @@ const SPIFFE_WORKLOAD_API_VOLUME_NAME: &str = "spiffe-workload-api";
8992// translation layer; the RFC boundary is Struct at the gateway, typed config in
9093// the selected driver.
9194#[ derive( Debug , Clone , Default , Deserialize ) ]
92- #[ serde( default ) ]
95+ #[ serde( default , deny_unknown_fields ) ]
9396struct KubernetesSandboxDriverConfig {
9497 pod : KubernetesPodDriverConfig ,
9598 containers : KubernetesDriverContainersConfig ,
9699}
97100
101+ impl KubernetesSandboxDriverConfig {
102+ fn from_sandbox ( sandbox : & Sandbox ) -> Result < Self , String > {
103+ let Some ( template) = sandbox
104+ . spec
105+ . as_ref ( )
106+ . and_then ( |spec| spec. template . as_ref ( ) )
107+ else {
108+ return Ok ( Self :: default ( ) ) ;
109+ } ;
110+
111+ Self :: from_template ( template)
112+ }
113+
114+ fn from_template ( template : & SandboxTemplate ) -> Result < Self , String > {
115+ let Some ( config) = template. driver_config . as_ref ( ) else {
116+ return Ok ( Self :: default ( ) ) ;
117+ } ;
118+
119+ let json = serde_json:: Value :: Object ( struct_to_json_object ( config) ) ;
120+ serde_json:: from_value ( json)
121+ . map_err ( |err| format ! ( "invalid kubernetes driver_config: {err}" ) )
122+ }
123+ }
124+
98125#[ derive( Debug , Clone , Default , Deserialize ) ]
99- #[ serde( default ) ]
126+ #[ serde( default , deny_unknown_fields ) ]
100127struct KubernetesPodDriverConfig {
101128 node_selector : BTreeMap < String , String > ,
102129 runtime_class_name : String ,
@@ -105,19 +132,19 @@ struct KubernetesPodDriverConfig {
105132}
106133
107134#[ derive( Debug , Clone , Default , Deserialize ) ]
108- #[ serde( default ) ]
135+ #[ serde( default , deny_unknown_fields ) ]
109136struct KubernetesDriverContainersConfig {
110137 agent : KubernetesContainerDriverConfig ,
111138}
112139
113140#[ derive( Debug , Clone , Default , Deserialize ) ]
114- #[ serde( default ) ]
141+ #[ serde( default , deny_unknown_fields ) ]
115142struct KubernetesContainerDriverConfig {
116143 resources : KubernetesContainerResourceConfig ,
117144}
118145
119146#[ derive( Debug , Clone , Default , Deserialize ) ]
120- #[ serde( default ) ]
147+ #[ serde( default , deny_unknown_fields ) ]
121148struct KubernetesContainerResourceConfig {
122149 requests : BTreeMap < String , String > ,
123150 limits : BTreeMap < String , String > ,
@@ -252,6 +279,8 @@ impl KubernetesComputeDriver {
252279 }
253280
254281 pub async fn validate_sandbox_create ( & self , sandbox : & Sandbox ) -> Result < ( ) , tonic:: Status > {
282+ let _ = KubernetesSandboxDriverConfig :: from_sandbox ( sandbox)
283+ . map_err ( tonic:: Status :: invalid_argument) ?;
255284 let gpu_requested = sandbox. spec . as_ref ( ) . is_some_and ( |spec| spec. gpu ) ;
256285 if gpu_requested
257286 && !self . has_gpu_capacity ( ) . await . map_err ( |err| {
@@ -345,6 +374,8 @@ impl KubernetesComputeDriver {
345374 }
346375
347376 pub async fn create_sandbox ( & self , sandbox : & Sandbox ) -> Result < ( ) , KubernetesDriverError > {
377+ let _ = KubernetesSandboxDriverConfig :: from_sandbox ( sandbox)
378+ . map_err ( KubernetesDriverError :: InvalidArgument ) ?;
348379 let name = sandbox. name . as_str ( ) ;
349380 info ! (
350381 sandbox_id = %sandbox. id,
@@ -1144,18 +1175,8 @@ fn spec_pod_env(spec: Option<&SandboxSpec>) -> std::collections::HashMap<String,
11441175}
11451176
11461177fn kubernetes_driver_config ( template : & SandboxTemplate ) -> KubernetesSandboxDriverConfig {
1147- let Some ( config) = template. driver_config . as_ref ( ) else {
1148- return KubernetesSandboxDriverConfig :: default ( ) ;
1149- } ;
1150-
1151- let json = serde_json:: Value :: Object ( struct_to_json_object ( config) ) ;
1152- match serde_json:: from_value ( json) {
1153- Ok ( config) => config,
1154- Err ( err) => {
1155- warn ! ( error = %err, "Ignoring invalid Kubernetes driver_config" ) ;
1156- KubernetesSandboxDriverConfig :: default ( )
1157- }
1158- }
1178+ KubernetesSandboxDriverConfig :: from_template ( template)
1179+ . expect ( "validated Kubernetes driver_config" )
11591180}
11601181
11611182fn sandbox_to_k8s_spec (
@@ -1947,19 +1968,52 @@ mod tests {
19471968 }
19481969
19491970 #[ test]
1950- fn driver_config_ignores_invalid_shape ( ) {
1971+ fn driver_config_rejects_invalid_shape ( ) {
19511972 let template = SandboxTemplate {
19521973 driver_config : Some ( json_struct ( serde_json:: json!( {
19531974 "pod" : "not-an-object"
19541975 } ) ) ) ,
19551976 ..SandboxTemplate :: default ( )
19561977 } ;
19571978
1958- let config = kubernetes_driver_config ( & template) ;
1979+ let err = KubernetesSandboxDriverConfig :: from_template ( & template) . unwrap_err ( ) ;
1980+
1981+ assert ! ( err. contains( "invalid kubernetes driver_config" ) ) ;
1982+ }
1983+
1984+ #[ test]
1985+ fn driver_config_rejects_unknown_fields ( ) {
1986+ let template = SandboxTemplate {
1987+ driver_config : Some ( json_struct ( serde_json:: json!( {
1988+ "cdi_devices" : [ "nvidia.com/gpu=0" ]
1989+ } ) ) ) ,
1990+ ..SandboxTemplate :: default ( )
1991+ } ;
1992+
1993+ let err = KubernetesSandboxDriverConfig :: from_template ( & template) . unwrap_err ( ) ;
1994+
1995+ assert ! ( err. contains( "unknown field" ) ) ;
1996+ }
1997+
1998+ #[ test]
1999+ fn driver_config_from_sandbox_rejects_unknown_fields ( ) {
2000+ let sandbox = Sandbox {
2001+ id : "sandbox-123" . to_string ( ) ,
2002+ spec : Some ( SandboxSpec {
2003+ gpu : true ,
2004+ template : Some ( SandboxTemplate {
2005+ driver_config : Some ( json_struct ( serde_json:: json!( {
2006+ "cdi_devices" : [ "nvidia.com/gpu=0" ]
2007+ } ) ) ) ,
2008+ ..Default :: default ( )
2009+ } ) ,
2010+ ..Default :: default ( )
2011+ } ) ,
2012+ ..Default :: default ( )
2013+ } ;
19592014
1960- assert ! ( config. pod. node_selector. is_empty( ) ) ;
1961- assert ! ( config. containers. agent. resources. requests. is_empty( ) ) ;
1962- assert ! ( config. containers. agent. resources. limits. is_empty( ) ) ;
2015+ let err = KubernetesSandboxDriverConfig :: from_sandbox ( & sandbox) . unwrap_err ( ) ;
2016+ assert ! ( err. contains( "unknown field" ) ) ;
19632017 }
19642018
19652019 #[ test]
0 commit comments