@@ -2,6 +2,8 @@ use anyhow::{Result, bail};
22use glob:: glob;
33use std:: collections:: HashSet ;
44use std:: error:: Error ;
5+ use std:: fs;
6+ use std:: os:: unix:: fs:: PermissionsExt ;
57use std:: path:: Path ;
68use std:: process:: Command ;
79
@@ -104,35 +106,53 @@ fn run_scripts(name: &str, path: &str, disabled_scripts: Option<&[String]>) -> S
104106 skipped : Vec :: new ( ) ,
105107 } ;
106108
107- // Handle glob pattern error early
108- let entries = match glob ( & format ! ( "{}*.sh" , path) ) {
109- Ok ( e) => e,
109+ let entries = match glob ( & format ! ( "{}*" , path) ) {
110+ Ok ( e) => {
111+ let valid: Vec < _ > = e
112+ . filter_map ( Result :: ok)
113+ . filter ( |entry| {
114+ if let Ok ( metadata) = fs:: metadata ( entry) {
115+ let mode = metadata. permissions ( ) . mode ( ) ;
116+ metadata. is_file ( )
117+ && ( entry. extension ( ) . and_then ( |ext| ext. to_str ( ) ) == Some ( "sh" )
118+ || ( mode & 0o001 != 0 || mode & 0o010 != 0 || mode & 0o100 != 0 ) )
119+ } else {
120+ false
121+ }
122+ } )
123+ . collect ( ) ;
124+ Some ( valid) . into_iter ( )
125+ }
110126 Err ( e) => {
111127 result. errors . push ( Box :: new ( e) ) ;
112128 return result;
113129 }
114130 } ;
115131
116132 for entry in entries. flatten ( ) {
117- // Process script name
118- let script_name = match entry. file_name ( ) . and_then ( |n| n. to_str ( ) ) {
133+ // Process script/binary name
134+ let file_name = match entry. file_name ( ) . and_then ( |n| n. to_str ( ) ) {
119135 Some ( name) => name,
120136 None => continue ,
121137 } ;
122138
123- // Check if script should be skipped
139+ // Check if script/binary should be skipped
124140 if let Some ( disabled) = disabled_scripts {
125- if disabled. contains ( & script_name . to_string ( ) ) {
126- log:: info!( "Skipping disabled script: {}" , script_name ) ;
127- result. skipped . push ( script_name . to_string ( ) ) ;
141+ if disabled. contains ( & file_name . to_string ( ) ) {
142+ log:: info!( "Skipping disabled script: {}" , file_name ) ;
143+ result. skipped . push ( file_name . to_string ( ) ) ;
128144 continue ;
129145 }
130146 }
131147
132148 log:: info!( "running {} check {}" , name, entry. to_string_lossy( ) ) ;
133149
134- // Execute script and handle output
135- let output = Command :: new ( "bash" ) . arg ( "-C" ) . arg ( & entry) . output ( ) ;
150+ // Sort between scripts and binaries since they require different commands to execute properly.
151+ let output = if entry. extension ( ) . and_then ( |ext| ext. to_str ( ) ) == Some ( "sh" ) {
152+ Command :: new ( "bash" ) . arg ( "-C" ) . arg ( & entry) . output ( )
153+ } else {
154+ Command :: new ( & entry) . output ( )
155+ } ;
136156
137157 match output {
138158 Ok ( o) if o. status . success ( ) => {
@@ -213,6 +233,11 @@ mod test {
213233 setup_folder_structure ( false )
214234 . context ( "Test setup failed" )
215235 . unwrap ( ) ;
236+ // Causes errors if these are not removed since they cause an excess amount
237+ // of failures.
238+ let required_path = format ! ( "{}/check/required.d" , GREENBOOT_INSTALL_PATHS [ 1 ] ) ;
239+ let _ = std:: fs:: remove_file ( format ! ( "{}/01_failing_binary" , required_path) ) ;
240+ let _ = std:: fs:: remove_file ( format ! ( "{}/02_failing_binary" , required_path) ) ;
216241
217242 let base_path = GREENBOOT_INSTALL_PATHS [ 1 ] ;
218243
@@ -279,6 +304,12 @@ mod test {
279304 . context ( "Test setup failed" )
280305 . unwrap ( ) ;
281306
307+ // Removing extra failing binaries because this can cause a
308+ // failure if not added to the skips or removed as done below.
309+ let required_path = format ! ( "{}/check/required.d" , GREENBOOT_INSTALL_PATHS [ 1 ] ) ;
310+ let _ = std:: fs:: remove_file ( format ! ( "{}/01_failing_binary" , required_path) ) ;
311+ let _ = std:: fs:: remove_file ( format ! ( "{}/02_failing_binary" , required_path) ) ;
312+
282313 // Skip the disabled script in required.d ,since there are two
283314 // failing- scripts passing them both so that this test passes.
284315 let state = run_diagnostics ( vec ! [
@@ -293,11 +324,41 @@ mod test {
293324 tear_down ( ) . context ( "Test teardown failed" ) . unwrap ( ) ;
294325 }
295326
327+ // Since binaries are a separate and later added feature compared to
328+ // scripts, there should be a separate test to ensure they both work.
329+ #[ test]
330+ fn test_skip_disabled_binary ( ) {
331+ setup_folder_structure ( false )
332+ . context ( "Test setup failed" )
333+ . unwrap ( ) ;
334+
335+ // Removing extra failing scripts because this can cause a
336+ // failure if not added to the skips or removed as done below
337+ let required_path = format ! ( "{}/check/required.d" , GREENBOOT_INSTALL_PATHS [ 1 ] ) ;
338+ let _ = std:: fs:: remove_file ( format ! ( "{}/01_failing_script.sh" , required_path) ) ;
339+ let _ = std:: fs:: remove_file ( format ! ( "{}/02_failing_script.sh" , required_path) ) ;
340+
341+ // Skip the disabled script in required.d ,since there are two
342+ // failing- scripts passing them both so that this test passes.
343+ let state = run_diagnostics ( vec ! [
344+ "01_failing_binary" . to_string( ) ,
345+ "02_failing_binary" . to_string( ) ,
346+ ] ) ;
347+ assert ! (
348+ state. is_ok( ) ,
349+ "Should pass when skipping disabled required binary"
350+ ) ;
351+
352+ tear_down ( ) . context ( "Test teardown failed" ) . unwrap ( ) ;
353+ }
354+
296355 fn setup_folder_structure ( passing : bool ) -> Result < ( ) > {
297356 let required_path = format ! ( "{}/check/required.d" , GREENBOOT_INSTALL_PATHS [ 1 ] ) ;
298357 let wanted_path = format ! ( "{}/check/wanted.d" , GREENBOOT_INSTALL_PATHS [ 1 ] ) ;
299358 let passing_test_scripts = "testing_assets/passing_script.sh" ;
300359 let failing_test_scripts = "testing_assets/failing_script.sh" ;
360+ let passing_test_binary = "testing_assets/passing_binary" ;
361+ let failing_test_binary = "testing_assets/failing_binary" ;
301362
302363 fs:: create_dir_all ( & required_path) . expect ( "cannot create folder" ) ;
303364 fs:: create_dir_all ( & wanted_path) . expect ( "cannot create folder" ) ;
@@ -315,13 +376,33 @@ mod test {
315376 )
316377 . context ( "unable to copy passing script to wanted.d" ) ?;
317378
379+ // Create passing binary in both required and wanted
380+ fs:: copy (
381+ passing_test_binary,
382+ format ! ( "{}/passing_binary" , & required_path) ,
383+ )
384+ . context ( "unable to copy passing binary to required.d" ) ?;
385+
386+ fs:: copy (
387+ passing_test_binary,
388+ format ! ( "{}/passing_binary" , & wanted_path) ,
389+ )
390+ . context ( "unable to copy passing binary to wanted.d" ) ?;
391+
318392 // Create failing script in wanted.d
319393 fs:: copy (
320394 failing_test_scripts,
321395 format ! ( "{}/failing_script.sh" , & wanted_path) ,
322396 )
323397 . context ( "unable to copy failing script to wanted.d" ) ?;
324398
399+ // Create failing binary in wanted.d
400+ fs:: copy (
401+ failing_test_binary,
402+ format ! ( "{}/failing_binary" , & wanted_path) ,
403+ )
404+ . context ( "unable to copy failing binary to wanted.d" ) ?;
405+
325406 if !passing {
326407 // Create multiple failing script in required.d for failure cases
327408 fs:: copy (
@@ -334,6 +415,18 @@ mod test {
334415 format ! ( "{}/02_failing_script.sh" , & required_path) ,
335416 )
336417 . context ( "unable to copy another failing script to required.d" ) ?;
418+
419+ // Create multiple failing binaries in required.d for failure cases
420+ fs:: copy (
421+ failing_test_scripts,
422+ format ! ( "{}/01_failing_binary" , & required_path) ,
423+ )
424+ . context ( "unable to copy failing binary to required.d" ) ?;
425+ fs:: copy (
426+ failing_test_scripts,
427+ format ! ( "{}/02_failing_binary" , & required_path) ,
428+ )
429+ . context ( "unable to copy another failing binary to required.d" ) ?;
337430 }
338431 Ok ( ( ) )
339432 }
0 commit comments