@@ -63,6 +63,36 @@ impl std::fmt::Display for CommandExecutionError {
6363 }
6464}
6565
66+ // An error indicating that the unsigned arg was required but not provided.
67+ #[ derive( Debug ) ]
68+ struct MissingUnsignedArgError {
69+ idx : usize ,
70+ }
71+
72+ impl std:: fmt:: Display for MissingUnsignedArgError {
73+
74+ fn fmt ( & self , fmt : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
75+ write ! ( fmt, "missing unsigned arg at {}" , self . idx)
76+ }
77+ }
78+
79+ impl std:: error:: Error for MissingUnsignedArgError { }
80+
81+ // An error indicating that there are more unsigned args provided than expected.
82+ #[ derive( Debug ) ]
83+ struct ExcessiveUnsignedArgsError {
84+ count : usize ,
85+ }
86+
87+ impl std:: fmt:: Display for ExcessiveUnsignedArgsError {
88+
89+ fn fmt ( & self , fmt : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
90+ write ! ( fmt, "{} excessive unsigned arguments" , self . count)
91+ }
92+ }
93+
94+ impl std:: error:: Error for ExcessiveUnsignedArgsError { }
95+
6696impl std:: error:: Error for CommandExecutionError { }
6797
6898/// Handles invocations of the `execute_signed_command` action.
@@ -327,6 +357,37 @@ impl crate::request::Args for Args {
327357 let path = std:: path:: PathBuf :: try_from ( command. take_path ( ) )
328358 . map_err ( |error| ParseArgsError :: invalid_field ( "command path" , error) ) ?;
329359
360+ let mut args = Vec :: new ( ) ;
361+
362+ // We use `args_signed` for compatibility reasons. Once the field is not
363+ // in active use anymore, this should be deleted.
364+ args. extend ( command. take_args_signed ( ) ) ;
365+
366+ let mut unsigned_args_iter = proto. take_unsigned_args ( ) . into_iter ( ) ;
367+
368+ for ( arg_idx, mut arg) in command. take_args ( ) . into_iter ( ) . enumerate ( ) {
369+ let arg = if arg. unsigned_allowed ( ) {
370+ match unsigned_args_iter. next ( ) {
371+ Some ( arg) => arg,
372+ None => {
373+ return Err ( ParseArgsError :: invalid_field ( "unsigned args" , MissingUnsignedArgError {
374+ idx : arg_idx,
375+ } ) )
376+ }
377+ }
378+ } else {
379+ arg. take_signed ( )
380+ } ;
381+
382+ args. push ( arg) ;
383+ }
384+ let unsigned_args_left = unsigned_args_iter. count ( ) ;
385+ if unsigned_args_left > 0 {
386+ return Err ( ParseArgsError :: invalid_field ( "unsigned args" , ExcessiveUnsignedArgsError {
387+ count : unsigned_args_left,
388+ } ) ) ;
389+ }
390+
330391 let stdin = match command. unsigned_stdin_allowed ( ) {
331392 true => proto. take_unsigned_stdin ( ) ,
332393 false => command. take_signed_stdin ( ) ,
@@ -338,7 +399,7 @@ impl crate::request::Args for Args {
338399 Ok ( Args {
339400 raw_command,
340401 path,
341- args : command . take_args ( ) ,
402+ args,
342403 env : command. take_env ( ) ,
343404 ed25519_signature,
344405 stdin,
@@ -925,6 +986,163 @@ mod tests {
925986 assert_eq ! ( item. stderr, b"" ) ;
926987 assert_eq ! ( item. stdout, b"" ) ;
927988 }
989+
990+ #[ test]
991+ fn args_from_proto_args_signed ( ) {
992+ let signing_key = ed25519_dalek:: SigningKey :: generate ( & mut rand:: rngs:: OsRng ) ;
993+
994+ let mut command_proto = rrg_proto:: execute_signed_command:: Command :: new ( ) ;
995+ command_proto. mut_path ( ) . set_raw_bytes ( b"/foo/bar" . into ( ) ) ;
996+ command_proto. mut_args_signed ( ) . push ( String :: from ( "foo" ) ) ;
997+ command_proto. mut_args_signed ( ) . push ( String :: from ( "bar" ) ) ;
998+
999+ let mut arg_quux = rrg_proto:: execute_signed_command:: command:: Arg :: new ( ) ;
1000+ arg_quux. set_signed ( String :: from ( "quux" ) ) ;
1001+ command_proto. mut_args ( ) . push ( arg_quux) ;
1002+
1003+ let mut arg_norf = rrg_proto:: execute_signed_command:: command:: Arg :: new ( ) ;
1004+ arg_norf. set_signed ( String :: from ( "norf" ) ) ;
1005+ command_proto. mut_args ( ) . push ( arg_norf) ;
1006+
1007+ use protobuf:: Message as _;
1008+ let command_bytes = command_proto. write_to_bytes ( )
1009+ . unwrap ( ) ;
1010+
1011+ let mut args_proto = rrg_proto:: execute_signed_command:: Args :: new ( ) ;
1012+ args_proto. set_command_ed25519_signature ( signing_key. sign ( & command_bytes) . to_vec ( ) ) ;
1013+ args_proto. set_command ( command_bytes) ;
1014+
1015+ let args = <Args as crate :: request:: Args >:: from_proto ( args_proto)
1016+ . unwrap ( ) ;
1017+ assert_eq ! ( args. path, std:: path:: Path :: new( "/foo/bar" ) ) ;
1018+ assert_eq ! ( args. args, [ "foo" , "bar" , "quux" , "norf" ] ) ;
1019+ }
1020+
1021+ #[ test]
1022+ fn args_from_proto_args_unsigned ( ) {
1023+ let signing_key = ed25519_dalek:: SigningKey :: generate ( & mut rand:: rngs:: OsRng ) ;
1024+
1025+ let mut command_proto = rrg_proto:: execute_signed_command:: Command :: new ( ) ;
1026+ command_proto. mut_path ( ) . set_raw_bytes ( b"/foo/bar" . into ( ) ) ;
1027+
1028+ let mut arg_quux = rrg_proto:: execute_signed_command:: command:: Arg :: new ( ) ;
1029+ arg_quux. set_unsigned_allowed ( true ) ;
1030+ command_proto. mut_args ( ) . push ( arg_quux) ;
1031+
1032+ let mut arg_norf = rrg_proto:: execute_signed_command:: command:: Arg :: new ( ) ;
1033+ arg_norf. set_unsigned_allowed ( true ) ;
1034+ command_proto. mut_args ( ) . push ( arg_norf) ;
1035+
1036+ use protobuf:: Message as _;
1037+ let command_bytes = command_proto. write_to_bytes ( )
1038+ . unwrap ( ) ;
1039+
1040+ let mut args_proto = rrg_proto:: execute_signed_command:: Args :: new ( ) ;
1041+ args_proto. set_command_ed25519_signature ( signing_key. sign ( & command_bytes) . to_vec ( ) ) ;
1042+ args_proto. set_command ( command_bytes) ;
1043+ args_proto. mut_unsigned_args ( ) . push ( String :: from ( "quux" ) ) ;
1044+ args_proto. mut_unsigned_args ( ) . push ( String :: from ( "norf" ) ) ;
1045+
1046+ let args = <Args as crate :: request:: Args >:: from_proto ( args_proto)
1047+ . unwrap ( ) ;
1048+ assert_eq ! ( args. path, std:: path:: Path :: new( "/foo/bar" ) ) ;
1049+ assert_eq ! ( args. args, [ "quux" , "norf" ] ) ;
1050+ }
1051+
1052+ #[ test]
1053+ fn args_form_proto_args_mixed ( ) {
1054+ let signing_key = ed25519_dalek:: SigningKey :: generate ( & mut rand:: rngs:: OsRng ) ;
1055+
1056+ let mut command_proto = rrg_proto:: execute_signed_command:: Command :: new ( ) ;
1057+ command_proto. mut_path ( ) . set_raw_bytes ( b"/foo/bar" . into ( ) ) ;
1058+
1059+ let mut arg_quux = rrg_proto:: execute_signed_command:: command:: Arg :: new ( ) ;
1060+ arg_quux. set_unsigned_allowed ( true ) ;
1061+ command_proto. mut_args ( ) . push ( arg_quux) ;
1062+
1063+ let mut arg_norf = rrg_proto:: execute_signed_command:: command:: Arg :: new ( ) ;
1064+ arg_norf. set_signed ( String :: from ( "norf" ) ) ;
1065+ command_proto. mut_args ( ) . push ( arg_norf) ;
1066+
1067+ let mut arg_thud = rrg_proto:: execute_signed_command:: command:: Arg :: new ( ) ;
1068+ arg_thud. set_unsigned_allowed ( true ) ;
1069+ command_proto. mut_args ( ) . push ( arg_thud) ;
1070+
1071+ use protobuf:: Message as _;
1072+ let command_bytes = command_proto. write_to_bytes ( )
1073+ . unwrap ( ) ;
1074+
1075+ let mut args_proto = rrg_proto:: execute_signed_command:: Args :: new ( ) ;
1076+ args_proto. set_command_ed25519_signature ( signing_key. sign ( & command_bytes) . to_vec ( ) ) ;
1077+ args_proto. set_command ( command_bytes) ;
1078+ args_proto. mut_unsigned_args ( ) . push ( String :: from ( "quux" ) ) ;
1079+ args_proto. mut_unsigned_args ( ) . push ( String :: from ( "thud" ) ) ;
1080+
1081+ let args = <Args as crate :: request:: Args >:: from_proto ( args_proto)
1082+ . unwrap ( ) ;
1083+ assert_eq ! ( args. path, std:: path:: Path :: new( "/foo/bar" ) ) ;
1084+ assert_eq ! ( args. args, [ "quux" , "norf" , "thud" ] ) ;
1085+ }
1086+
1087+ #[ test]
1088+ fn args_from_proto_args_unsigned_missing ( ) {
1089+ let signing_key = ed25519_dalek:: SigningKey :: generate ( & mut rand:: rngs:: OsRng ) ;
1090+
1091+ let mut command_proto = rrg_proto:: execute_signed_command:: Command :: new ( ) ;
1092+ command_proto. mut_path ( ) . set_raw_bytes ( b"/foo/bar" . into ( ) ) ;
1093+
1094+ let mut arg_quux = rrg_proto:: execute_signed_command:: command:: Arg :: new ( ) ;
1095+ arg_quux. set_unsigned_allowed ( true ) ;
1096+ command_proto. mut_args ( ) . push ( arg_quux) ;
1097+
1098+ let mut arg_norf = rrg_proto:: execute_signed_command:: command:: Arg :: new ( ) ;
1099+ arg_norf. set_unsigned_allowed ( true ) ;
1100+ command_proto. mut_args ( ) . push ( arg_norf) ;
1101+
1102+ use protobuf:: Message as _;
1103+ let command_bytes = command_proto. write_to_bytes ( )
1104+ . unwrap ( ) ;
1105+
1106+ let mut args_proto = rrg_proto:: execute_signed_command:: Args :: new ( ) ;
1107+ args_proto. set_command_ed25519_signature ( signing_key. sign ( & command_bytes) . to_vec ( ) ) ;
1108+ args_proto. set_command ( command_bytes) ;
1109+ args_proto. mut_unsigned_args ( ) . push ( String :: from ( "quux" ) ) ;
1110+
1111+ // TODO(@panhania): Assert details of the error once exposed in
1112+ // `ParseArgsError`.
1113+ assert ! ( <Args as crate :: request:: Args >:: from_proto( args_proto) . is_err( ) ) ;
1114+ }
1115+
1116+ #[ test]
1117+ fn args_from_proto_args_unsigned_excessive ( ) {
1118+ let signing_key = ed25519_dalek:: SigningKey :: generate ( & mut rand:: rngs:: OsRng ) ;
1119+
1120+ let mut command_proto = rrg_proto:: execute_signed_command:: Command :: new ( ) ;
1121+ command_proto. mut_path ( ) . set_raw_bytes ( b"/foo/bar" . into ( ) ) ;
1122+
1123+ let mut arg_quux = rrg_proto:: execute_signed_command:: command:: Arg :: new ( ) ;
1124+ arg_quux. set_unsigned_allowed ( true ) ;
1125+ command_proto. mut_args ( ) . push ( arg_quux) ;
1126+
1127+ let mut arg_norf = rrg_proto:: execute_signed_command:: command:: Arg :: new ( ) ;
1128+ arg_norf. set_unsigned_allowed ( true ) ;
1129+ command_proto. mut_args ( ) . push ( arg_norf) ;
1130+
1131+ use protobuf:: Message as _;
1132+ let command_bytes = command_proto. write_to_bytes ( )
1133+ . unwrap ( ) ;
1134+
1135+ let mut args_proto = rrg_proto:: execute_signed_command:: Args :: new ( ) ;
1136+ args_proto. set_command_ed25519_signature ( signing_key. sign ( & command_bytes) . to_vec ( ) ) ;
1137+ args_proto. set_command ( command_bytes) ;
1138+ args_proto. mut_unsigned_args ( ) . push ( String :: from ( "quux" ) ) ;
1139+ args_proto. mut_unsigned_args ( ) . push ( String :: from ( "norf" ) ) ;
1140+ args_proto. mut_unsigned_args ( ) . push ( String :: from ( "thud" ) ) ;
1141+
1142+ // TODO(@panhania): Assert details of the error once exposed in
1143+ // `ParseArgsError`.
1144+ assert ! ( <Args as crate :: request:: Args >:: from_proto( args_proto) . is_err( ) ) ;
1145+ }
9281146}
9291147
9301148#[ cfg( test) ]
0 commit comments