@@ -426,6 +426,69 @@ func TestContainerCopyLeaksMounts(t *testing.T) {
426426 assert .Equal (t , mountsBefore , mountsAfter )
427427}
428428
429+ func TestContainerBindMountReadOnlyDefault (t * testing.T ) {
430+ skip .If (t , testEnv .IsRemoteDaemon )
431+
432+ ctx := setupTest (t )
433+
434+ // The test will run a container with a simple readonly /dev bind mount (-v /dev:/dev:ro)
435+ // It will then check /proc/self/mountinfo for the mount type of /dev/shm (submount of /dev)
436+ // If /dev/shm is rw, that will mean that the read-only mounts are NOT recursive by default.
437+ const nonRecursive = " /dev/shm rw,"
438+ // If /dev/shm is ro, that will mean that the read-only mounts ARE recursive by default.
439+ const recursive = " /dev/shm ro,"
440+
441+ for _ , tc := range []struct {
442+ version string
443+ expectedOut string
444+ name string
445+ }{
446+ {version : "" , expectedOut : recursive , name : "latest should be the same as 1.44" },
447+ {version : "1.44" , expectedOut : recursive , name : "submount should be recursive by default on 1.44" },
448+
449+ {version : "1.43" , expectedOut : nonRecursive , name : "older should be non-recursive by default" },
450+ } {
451+ t .Run (tc .name , func (t * testing.T ) {
452+ apiClient := testEnv .APIClient ()
453+
454+ if tc .version != "" {
455+ skip .If (t , versions .LessThan (testEnv .DaemonAPIVersion (), tc .version ), "requires API v" + tc .version )
456+ c , err := client .NewClientWithOpts (client .FromEnv , client .WithVersion (tc .version ))
457+ assert .NilError (t , err , "failed to create client with version v%s" , tc .version )
458+ apiClient = c
459+ }
460+
461+ for _ , tc2 := range []struct {
462+ subname string
463+ mountOpt func (* container.TestContainerConfig )
464+ }{
465+ {"mount" , container .WithMount (mounttypes.Mount {
466+ Type : mounttypes .TypeBind ,
467+ Source : "/dev" ,
468+ Target : "/dev" ,
469+ ReadOnly : true ,
470+ })},
471+ {"bind mount" , container .WithBindRaw ("/dev:/dev:ro" )},
472+ } {
473+ t .Run (tc2 .subname , func (t * testing.T ) {
474+ cid := container .Run (ctx , t , apiClient , tc2 .mountOpt ,
475+ container .WithCmd ("sh" , "-c" , "grep /dev/shm /proc/self/mountinfo" ),
476+ )
477+ out , err := container .Output (ctx , apiClient , cid )
478+ assert .NilError (t , err )
479+
480+ assert .Check (t , is .Equal (out .Stderr , "" ))
481+ // Output should be either:
482+ // 545 526 0:160 / /dev/shm ro,nosuid,nodev,noexec,relatime shared:90 - tmpfs shm rw,size=65536k
483+ // or
484+ // 545 526 0:160 / /dev/shm rw,nosuid,nodev,noexec,relatime shared:90 - tmpfs shm rw,size=65536k
485+ assert .Check (t , is .Contains (out .Stdout , tc .expectedOut ))
486+ })
487+ }
488+ })
489+ }
490+ }
491+
429492func TestContainerBindMountRecursivelyReadOnly (t * testing.T ) {
430493 skip .If (t , testEnv .IsRemoteDaemon )
431494 skip .If (t , versions .LessThan (testEnv .DaemonAPIVersion (), "1.44" ), "requires API v1.44" )
0 commit comments