@@ -4263,8 +4263,7 @@ fn test_ls_context_long() {
4263
4263
let line: Vec < _ > = result. stdout_str ( ) . split ( ' ' ) . collect ( ) ;
4264
4264
assert ! ( line[ 0 ] . ends_with( '.' ) ) ;
4265
4265
assert ! ( line[ 4 ] . starts_with( "unconfined_u" ) ) ;
4266
- let s: Vec < _ > = line[ 4 ] . split ( ':' ) . collect ( ) ;
4267
- assert ! ( s. len( ) == 4 ) ;
4266
+ validate_selinux_context ( line[ 4 ] ) ;
4268
4267
}
4269
4268
}
4270
4269
@@ -4298,6 +4297,115 @@ fn test_ls_context_format() {
4298
4297
}
4299
4298
}
4300
4299
4300
+ /// Helper function to validate `SELinux` context format
4301
+ /// Returns the context parts if valid, panics with descriptive message if invalid
4302
+ #[ cfg( feature = "feat_selinux" ) ]
4303
+ fn validate_selinux_context ( context : & str ) {
4304
+ assert ! (
4305
+ context. contains( ':' ) ,
4306
+ "Expected SELinux context format (user:role:type:level), got: {}" ,
4307
+ context
4308
+ ) ;
4309
+
4310
+ let context_parts: Vec < & str > = context. split ( ':' ) . collect ( ) ;
4311
+ assert_eq ! (
4312
+ context_parts. len( ) ,
4313
+ 4 ,
4314
+ "SELinux context should have 4 components separated by colons, got: {}" ,
4315
+ context
4316
+ ) ;
4317
+ }
4318
+
4319
+ #[ test]
4320
+ #[ cfg( feature = "feat_selinux" ) ]
4321
+ fn test_ls_selinux_context_format ( ) {
4322
+ if !uucore:: selinux:: is_selinux_enabled ( ) {
4323
+ println ! ( "test skipped: Kernel has no support for SElinux context" ) ;
4324
+ return ;
4325
+ }
4326
+
4327
+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
4328
+ let at = & scene. fixtures ;
4329
+
4330
+ at. touch ( "file" ) ;
4331
+ at. symlink_file ( "file" , "link" ) ;
4332
+
4333
+ // Test that ls -lnZ properly shows the context
4334
+ for file in [ "file" , "link" ] {
4335
+ let result = scene. ucmd ( ) . args ( & [ "-lnZ" , file] ) . succeeds ( ) ;
4336
+ let output = result. stdout_str ( ) ;
4337
+
4338
+ let lines: Vec < & str > = output. lines ( ) . collect ( ) ;
4339
+ assert ! ( !lines. is_empty( ) , "Output should contain at least one line" ) ;
4340
+
4341
+ let first_line = lines[ 0 ] ;
4342
+ let parts: Vec < & str > = first_line. split_whitespace ( ) . collect ( ) ;
4343
+ assert ! ( parts. len( ) >= 6 , "Line should have at least 6 fields" ) ;
4344
+
4345
+ // The 5th field (0-indexed position 4) should contain the SELinux context
4346
+ // Format: permissions links owner group context size date time name
4347
+ let context = parts[ 4 ] ;
4348
+ validate_selinux_context ( context) ;
4349
+ }
4350
+ }
4351
+
4352
+ #[ test]
4353
+ #[ cfg( feature = "feat_selinux" ) ]
4354
+ fn test_ls_selinux_context_indicator ( ) {
4355
+ if !uucore:: selinux:: is_selinux_enabled ( ) {
4356
+ println ! ( "test skipped: Kernel has no support for SElinux context" ) ;
4357
+ return ;
4358
+ }
4359
+
4360
+ let scene = TestScenario :: new ( util_name ! ( ) ) ;
4361
+ let at = & scene. fixtures ;
4362
+
4363
+ at. touch ( "file" ) ;
4364
+ at. symlink_file ( "file" , "link" ) ;
4365
+
4366
+ // Test that ls -l shows "." indicator for files with SELinux contexts
4367
+ for file in [ "file" , "link" ] {
4368
+ let result = scene. ucmd ( ) . args ( & [ "-l" , file] ) . succeeds ( ) ;
4369
+ let output = result. stdout_str ( ) ;
4370
+
4371
+ // The 11th character should be "." indicating SELinux context
4372
+ // -rw-rw-r--. (permissions + context indicator)
4373
+ let lines: Vec < & str > = output. lines ( ) . collect ( ) ;
4374
+ assert ! ( !lines. is_empty( ) , "Output should contain at least one line" ) ;
4375
+
4376
+ let first_line = lines[ 0 ] ;
4377
+ let chars: Vec < char > = first_line. chars ( ) . collect ( ) ;
4378
+ assert ! (
4379
+ chars. len( ) >= 11 ,
4380
+ "Line should be at least 11 characters long"
4381
+ ) ;
4382
+
4383
+ // The 11th character (0-indexed position 10) should be "." for SELinux context
4384
+ assert_eq ! (
4385
+ chars[ 10 ] , '.' ,
4386
+ "Expected '.' indicator for SELinux context in position 11, got '{}' in line: {}" ,
4387
+ chars[ 10 ] , first_line
4388
+ ) ;
4389
+ }
4390
+
4391
+ // Test that ls -lnZ properly shows the context
4392
+ for file in [ "file" , "link" ] {
4393
+ let result = scene. ucmd ( ) . args ( & [ "-lnZ" , file] ) . succeeds ( ) ;
4394
+ let output = result. stdout_str ( ) ;
4395
+
4396
+ let lines: Vec < & str > = output. lines ( ) . collect ( ) ;
4397
+ assert ! ( !lines. is_empty( ) , "Output should contain at least one line" ) ;
4398
+
4399
+ let first_line = lines[ 0 ] ;
4400
+ let parts: Vec < & str > = first_line. split_whitespace ( ) . collect ( ) ;
4401
+ assert ! ( parts. len( ) >= 6 , "Line should have at least 6 fields" ) ;
4402
+
4403
+ // The 5th field (0-indexed position 4) should contain the SELinux context
4404
+ // Format: permissions links owner group context size date time name
4405
+ validate_selinux_context ( parts[ 4 ] ) ;
4406
+ }
4407
+ }
4408
+
4301
4409
#[ test]
4302
4410
#[ allow( non_snake_case) ]
4303
4411
fn test_ls_a_A ( ) {
0 commit comments