1- use serde:: {
2- de:: { Deserializer , Error } ,
3- Deserialize , Serialize ,
4- } ;
1+ use serde:: { Deserialize , Serialize } ;
52use std:: collections:: HashSet ;
63
74use strum_macros:: { Display , EnumString } ;
85
96/// Capabilities is a unique set of Capability values.
107pub type Capabilities = HashSet < Capability > ;
118
12- #[ derive( Clone , Copy , Debug , EnumString , Eq , Display , Hash , PartialEq , Serialize ) ]
9+ #[ derive( Clone , Copy , Debug , Deserialize , EnumString , Eq , Display , Hash , PartialEq , Serialize ) ]
1310/// All available capabilities.
1411///
1512/// For the purpose of performing permission checks, traditional UNIX
@@ -519,75 +516,6 @@ pub enum Capability {
519516 WakeAlarm ,
520517}
521518
522- impl < ' de > Deserialize < ' de > for Capability {
523- fn deserialize < D > ( deserializer : D ) -> Result < Self , D :: Error >
524- where
525- D : Deserializer < ' de > ,
526- {
527- let input = String :: deserialize ( deserializer) ?;
528- let upper = input. to_uppercase ( ) ;
529-
530- // Extract the capability name from various input formats.
531- //
532- // This function strips all "CAP_" prefixes to normalize capability names.
533- // This ensures correct adaptation regardless of whether users specify
534- // CAP_XXX or XXX directly at the upper layer(Specially k8s), making the
535- // API more flexible and user-friendly.
536- // Examples: "CAP_SYS_ADMIN", "SYS_ADMIN"
537- //
538- let mut clean_cap = upper. as_str ( ) ;
539- while let Some ( stripped) = clean_cap. strip_prefix ( "CAP_" ) {
540- clean_cap = stripped;
541- }
542- match clean_cap {
543- "AUDIT_CONTROL" => Ok ( Self :: AuditControl ) ,
544- "AUDIT_READ" => Ok ( Self :: AuditRead ) ,
545- "AUDIT_WRITE" => Ok ( Self :: AuditWrite ) ,
546- "BLOCK_SUSPEND" => Ok ( Self :: BlockSuspend ) ,
547- "BPF" => Ok ( Self :: Bpf ) ,
548- "CHECKPOINT_RESTORE" => Ok ( Self :: CheckpointRestore ) ,
549- "CHOWN" => Ok ( Self :: Chown ) ,
550- "DAC_OVERRIDE" => Ok ( Self :: DacOverride ) ,
551- "DAC_READ_SEARCH" => Ok ( Self :: DacReadSearch ) ,
552- "FOWNER" => Ok ( Self :: Fowner ) ,
553- "FSETID" => Ok ( Self :: Fsetid ) ,
554- "IPC_LOCK" => Ok ( Self :: IpcLock ) ,
555- "IPC_OWNER" => Ok ( Self :: IpcOwner ) ,
556- "KILL" => Ok ( Self :: Kill ) ,
557- "LEASE" => Ok ( Self :: Lease ) ,
558- "LINUX_IMMUTABLE" => Ok ( Self :: LinuxImmutable ) ,
559- "MAC_ADMIN" => Ok ( Self :: MacAdmin ) ,
560- "MAC_OVERRIDE" => Ok ( Self :: MacOverride ) ,
561- "MKNOD" => Ok ( Self :: Mknod ) ,
562- "NET_ADMIN" => Ok ( Self :: NetAdmin ) ,
563- "NET_BIND_SERVICE" => Ok ( Self :: NetBindService ) ,
564- "NET_BROADCAST" => Ok ( Self :: NetBroadcast ) ,
565- "NET_RAW" => Ok ( Self :: NetRaw ) ,
566- "PERFMON" => Ok ( Self :: Perfmon ) ,
567- "SETGID" => Ok ( Self :: Setgid ) ,
568- "SETFCAP" => Ok ( Self :: Setfcap ) ,
569- "SETPCAP" => Ok ( Self :: Setpcap ) ,
570- "SETUID" => Ok ( Self :: Setuid ) ,
571- "SYS_ADMIN" => Ok ( Self :: SysAdmin ) ,
572- "SYS_BOOT" => Ok ( Self :: SysBoot ) ,
573- "SYS_CHROOT" => Ok ( Self :: SysChroot ) ,
574- "SYS_MODULE" => Ok ( Self :: SysModule ) ,
575- "SYS_NICE" => Ok ( Self :: SysNice ) ,
576- "SYS_PACCT" => Ok ( Self :: SysPacct ) ,
577- "SYS_PTRACE" => Ok ( Self :: SysPtrace ) ,
578- "SYS_RAWIO" => Ok ( Self :: SysRawio ) ,
579- "SYS_RESOURCE" => Ok ( Self :: SysResource ) ,
580- "SYS_TIME" => Ok ( Self :: SysTime ) ,
581- "SYS_TTY_CONFIG" => Ok ( Self :: SysTtyConfig ) ,
582- "SYSLOG" => Ok ( Self :: Syslog ) ,
583- "WAKE_ALARM" => Ok ( Self :: WakeAlarm ) ,
584- other => Err ( Error :: custom ( format ! (
585- "no variant for {input} (converted to {other})" ,
586- ) ) ) ,
587- }
588- }
589- }
590-
591519#[ cfg( test) ]
592520mod tests {
593521 use super :: * ;
@@ -602,21 +530,34 @@ mod tests {
602530
603531 #[ test]
604532 fn deserialize ( ) -> Result < ( ) > {
605- for case in & [ "SYSLOG" , "CAP_SYSLOG" , "cap_SYSLOG" , "sySloG" ] {
606- let res: Capability = serde_json:: from_str ( & format ! ( "\" {case}\" " ) ) ?;
607- assert_eq ! ( Capability :: Syslog , res) ;
608- }
533+ let res: Capability = serde_json:: from_str ( "\" CAP_SYSLOG\" " ) ?;
534+ assert_eq ! ( Capability :: Syslog , res) ;
609535 Ok ( ( ) )
610536 }
611537
538+ #[ test]
539+ fn deserialize_rejects_non_canonical ( ) {
540+ for case in & [
541+ "SYSLOG" ,
542+ "cap_SYSLOG" ,
543+ "sySloG" ,
544+ "SYS_ADMIN" ,
545+ "cap_sys_admin" ,
546+ ] {
547+ let res: std:: result:: Result < Capability , _ > =
548+ serde_json:: from_str ( & format ! ( "\" {case}\" " ) ) ;
549+ assert ! ( res. is_err( ) , "expected {case} to be rejected" ) ;
550+ }
551+ }
552+
612553 #[ test]
613554 fn capabilities ( ) -> Result < ( ) > {
614555 let res: Capabilities = serde_json:: from_str (
615556 r#"[
616- "syslog ",
617- "SYSLOG ",
618- "chown ",
619- "cap_chown "
557+ "CAP_SYSLOG ",
558+ "CAP_SYSLOG ",
559+ "CAP_CHOWN ",
560+ "CAP_CHOWN "
620561 ]"# ,
621562 ) ?;
622563 assert_eq ! ( res. len( ) , 2 ) ;
@@ -682,11 +623,11 @@ mod tests {
682623 }
683624
684625 #[ test]
685- fn deserialize_one_more_cap_prefix ( ) -> Result < ( ) > {
686- for case in & [ "SYS_ADMIN" , "CAP_CAP_SYS_ADMIN" , "cap_CAP_cap_SYS_ADMIN" ] {
687- let res: Capability = serde_json:: from_str ( & format ! ( "\" {case}\" " ) ) ?;
688- assert_eq ! ( Capability :: SysAdmin , res) ;
626+ fn deserialize_rejects_extra_cap_prefix ( ) {
627+ for case in & [ "CAP_CAP_SYS_ADMIN" , "cap_CAP_cap_SYS_ADMIN" ] {
628+ let res: std:: result:: Result < Capability , _ > =
629+ serde_json:: from_str ( & format ! ( "\" {case}\" " ) ) ;
630+ assert ! ( res. is_err( ) , "expected {case} to be rejected" ) ;
689631 }
690- Ok ( ( ) )
691632 }
692633}
0 commit comments