Skip to content

Commit cb9aeb0

Browse files
committed
Consolidate security options to use = as separator.
All other options we have use `=` as separator, labels, log configurations, graph configurations and so on. We should be consistent and use `=` for the security options too. Signed-off-by: David Calavera <david.calavera@gmail.com>
1 parent b4da157 commit cb9aeb0

File tree

11 files changed

+120
-64
lines changed

11 files changed

+120
-64
lines changed

contrib/completion/bash/docker

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1788,17 +1788,17 @@ _docker_run() {
17881788
;;
17891789
--security-opt)
17901790
case "$cur" in
1791-
label:*:*)
1791+
label=*:*)
17921792
;;
1793-
label:*)
1794-
local cur=${cur##*:}
1793+
label=*)
1794+
local cur=${cur##*=}
17951795
COMPREPLY=( $( compgen -W "user: role: type: level: disable" -- "$cur") )
17961796
if [ "${COMPREPLY[*]}" != "disable" ] ; then
17971797
__docker_nospace
17981798
fi
17991799
;;
1800-
seccomp:*)
1801-
local cur=${cur##*:}
1800+
seccomp=*)
1801+
local cur=${cur##*=}
18021802
_filedir
18031803
COMPREPLY+=( $( compgen -W "unconfined" -- "$cur" ) )
18041804
;;

daemon/daemon_unix.go

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,15 +73,21 @@ func parseSecurityOpt(container *container.Container, config *containertypes.Hos
7373
)
7474

7575
for _, opt := range config.SecurityOpt {
76-
con := strings.SplitN(opt, ":", 2)
77-
if len(con) == 1 {
78-
switch con[0] {
79-
case "no-new-privileges":
80-
container.NoNewPrivileges = true
81-
default:
76+
if opt == "no-new-privileges" {
77+
container.NoNewPrivileges = true
78+
} else {
79+
var con []string
80+
if strings.Contains(opt, "=") {
81+
con = strings.SplitN(opt, "=", 2)
82+
} else if strings.Contains(opt, ":") {
83+
con = strings.SplitN(opt, ":", 2)
84+
logrus.Warnf("Security options with `:` as a separator are deprecated and will be completely unsupported in 1.13, use `=` instead.")
85+
}
86+
87+
if len(con) != 2 {
8288
return fmt.Errorf("Invalid --security-opt 1: %q", opt)
8389
}
84-
} else {
90+
8591
switch con[0] {
8692
case "label":
8793
labelOpts = append(labelOpts, con[1])

daemon/daemon_unix_test.go

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,12 @@ func TestAdjustCPUSharesNoAdjustment(t *testing.T) {
9090
}
9191

9292
// Unix test as uses settings which are not available on Windows
93-
func TestParseSecurityOpt(t *testing.T) {
93+
func TestParseSecurityOptWithDeprecatedColon(t *testing.T) {
9494
container := &container.Container{}
9595
config := &containertypes.HostConfig{}
9696

9797
// test apparmor
98-
config.SecurityOpt = []string{"apparmor:test_profile"}
98+
config.SecurityOpt = []string{"apparmor=test_profile"}
9999
if err := parseSecurityOpt(container, config); err != nil {
100100
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
101101
}
@@ -105,7 +105,7 @@ func TestParseSecurityOpt(t *testing.T) {
105105

106106
// test seccomp
107107
sp := "/path/to/seccomp_test.json"
108-
config.SecurityOpt = []string{"seccomp:" + sp}
108+
config.SecurityOpt = []string{"seccomp=" + sp}
109109
if err := parseSecurityOpt(container, config); err != nil {
110110
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
111111
}
@@ -114,7 +114,49 @@ func TestParseSecurityOpt(t *testing.T) {
114114
}
115115

116116
// test valid label
117-
config.SecurityOpt = []string{"label:user:USER"}
117+
config.SecurityOpt = []string{"label=user:USER"}
118+
if err := parseSecurityOpt(container, config); err != nil {
119+
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
120+
}
121+
122+
// test invalid label
123+
config.SecurityOpt = []string{"label"}
124+
if err := parseSecurityOpt(container, config); err == nil {
125+
t.Fatal("Expected parseSecurityOpt error, got nil")
126+
}
127+
128+
// test invalid opt
129+
config.SecurityOpt = []string{"test"}
130+
if err := parseSecurityOpt(container, config); err == nil {
131+
t.Fatal("Expected parseSecurityOpt error, got nil")
132+
}
133+
}
134+
135+
func TestParseSecurityOpt(t *testing.T) {
136+
container := &container.Container{}
137+
config := &containertypes.HostConfig{}
138+
139+
// test apparmor
140+
config.SecurityOpt = []string{"apparmor=test_profile"}
141+
if err := parseSecurityOpt(container, config); err != nil {
142+
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
143+
}
144+
if container.AppArmorProfile != "test_profile" {
145+
t.Fatalf("Unexpected AppArmorProfile, expected: \"test_profile\", got %q", container.AppArmorProfile)
146+
}
147+
148+
// test seccomp
149+
sp := "/path/to/seccomp_test.json"
150+
config.SecurityOpt = []string{"seccomp=" + sp}
151+
if err := parseSecurityOpt(container, config); err != nil {
152+
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
153+
}
154+
if container.SeccompProfile != sp {
155+
t.Fatalf("Unexpected SeccompProfile, expected: %q, got %q", sp, container.SeccompProfile)
156+
}
157+
158+
// test valid label
159+
config.SecurityOpt = []string{"label=user:USER"}
118160
if err := parseSecurityOpt(container, config); err != nil {
119161
t.Fatalf("Unexpected parseSecurityOpt error: %v", err)
120162
}

docs/deprecated.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ The following list of features are deprecated in Engine.
2121

2222
The docker login command is removing the ability to automatically register for an account with the target registry if the given username doesn't exist. Due to this change, the email flag is no longer required, and will be deprecated.
2323

24+
The flag `--security-opt` doesn't use the colon separator(`:`) anymore to divide keys and values, it uses the equal symbol(`=`) for consinstency with other similar flags, like `--storage-opt`.
25+
2426
### Ambiguous event fields in API
2527
**Deprecated In Release: v1.10**
2628

docs/reference/run.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -599,12 +599,12 @@ but the volume for `/bar` will not. Volumes inheritted via `--volumes-from` will
599599
with the same logic -- if the original volume was specified with a name it will **not** be removed.
600600

601601
## Security configuration
602-
--security-opt="label:user:USER" : Set the label user for the container
603-
--security-opt="label:role:ROLE" : Set the label role for the container
604-
--security-opt="label:type:TYPE" : Set the label type for the container
605-
--security-opt="label:level:LEVEL" : Set the label level for the container
606-
--security-opt="label:disable" : Turn off label confinement for the container
607-
--security-opt="apparmor:PROFILE" : Set the apparmor profile to be applied
602+
--security-opt="label=user:USER" : Set the label user for the container
603+
--security-opt="label=role:ROLE" : Set the label role for the container
604+
--security-opt="label=type:TYPE" : Set the label type for the container
605+
--security-opt="label=level:LEVEL" : Set the label level for the container
606+
--security-opt="label=disable" : Turn off label confinement for the container
607+
--security-opt="apparmor=PROFILE" : Set the apparmor profile to be applied
608608
to the container
609609
--security-opt="no-new-privileges" : Disable container processes from gaining
610610
new privileges
@@ -617,23 +617,23 @@ the `--security-opt` flag. For example, you can specify the MCS/MLS level, a
617617
requirement for MLS systems. Specifying the level in the following command
618618
allows you to share the same content between containers.
619619

620-
$ docker run --security-opt label:level:s0:c100,c200 -it fedora bash
620+
$ docker run --security-opt label=level:s0:c100,c200 -it fedora bash
621621

622622
An MLS example might be:
623623

624-
$ docker run --security-opt label:level:TopSecret -it rhel7 bash
624+
$ docker run --security-opt label=level:TopSecret -it rhel7 bash
625625

626626
To disable the security labeling for this container versus running with the
627627
`--permissive` flag, use the following command:
628628

629-
$ docker run --security-opt label:disable -it fedora bash
629+
$ docker run --security-opt label=disable -it fedora bash
630630

631631
If you want a tighter security policy on the processes within a container,
632632
you can specify an alternate type for the container. You could run a container
633633
that is only allowed to listen on Apache ports by executing the following
634634
command:
635635

636-
$ docker run --security-opt label:type:svirt_apache_t -it centos bash
636+
$ docker run --security-opt label=type:svirt_apache_t -it centos bash
637637

638638
> **Note**: You would have to write policy defining a `svirt_apache_t` type.
639639
@@ -1078,7 +1078,7 @@ one can use this flag:
10781078
> these cases to create your own custom seccomp profile based off our
10791079
> [default](https://github.com/docker/docker/blob/master/profiles/seccomp/default.json).
10801080
> Or if you don't want to run with the default seccomp profile, you can pass
1081-
> `--security-opt=seccomp:unconfined` on run.
1081+
> `--security-opt=seccomp=unconfined` on run.
10821082
10831083
By default, Docker containers are "unprivileged" and cannot, for
10841084
example, run a Docker daemon inside a Docker container. This is because

docs/security/apparmor.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ override it with the `security-opt` option. For example, the following
6969
explicitly specifies the default policy:
7070

7171
```bash
72-
$ docker run --rm -it --security-opt apparmor:docker-default hello-world
72+
$ docker run --rm -it --security-opt apparmor=docker-default hello-world
7373
```
7474

7575
## Loading and Unloading Profiles
@@ -83,7 +83,7 @@ $ apparmor_parser -r -W /path/to/your_profile
8383
Then you can run the custom profile with `--security-opt` like so:
8484

8585
```bash
86-
$ docker run --rm -it --security-opt apparmor:your_profile hello-world
86+
$ docker run --rm -it --security-opt apparmor=your_profile hello-world
8787
```
8888

8989
To unload a profile from AppArmor:

docs/security/seccomp.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ it with the `security-opt` option. For example, the following explicitly
6666
specifies the default policy:
6767

6868
```
69-
$ docker run --rm -it --security-opt seccomp:/path/to/seccomp/profile.json hello-world
69+
$ docker run --rm -it --security-opt seccomp=/path/to/seccomp/profile.json hello-world
7070
```
7171

7272
### Significant syscalls blocked by the default profile
@@ -138,6 +138,6 @@ You can pass `unconfined` to run a container without the default seccomp
138138
profile.
139139

140140
```
141-
$ docker run --rm -it --security-opt seccomp:unconfined debian:jessie \
141+
$ docker run --rm -it --security-opt seccomp=unconfined debian:jessie \
142142
unshare --map-root-user --user sh -c whoami
143143
```

integration-cli/docker_cli_run_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2971,7 +2971,7 @@ func (s *DockerSuite) TestRunReadFilteredProc(c *check.C) {
29712971
name := fmt.Sprintf("procsieve-%d", i)
29722972
shellCmd := fmt.Sprintf("exec 3<%s", filePath)
29732973

2974-
out, exitCode, err := dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor:docker-default", "--name", name, "busybox", "sh", "-c", shellCmd)
2974+
out, exitCode, err := dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor=docker-default", "--name", name, "busybox", "sh", "-c", shellCmd)
29752975
if exitCode != 0 {
29762976
return
29772977
}
@@ -3006,7 +3006,7 @@ func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
30063006

30073007
go func() {
30083008
name := "acidburn"
3009-
out, _, err := dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp:unconfined", "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "--mount-proc=/proc", "mount")
3009+
out, _, err := dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp=unconfined", "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "--mount-proc=/proc", "mount")
30103010
if err == nil ||
30113011
!(strings.Contains(strings.ToLower(out), "permission denied") ||
30123012
strings.Contains(strings.ToLower(out), "operation not permitted")) {
@@ -3018,7 +3018,7 @@ func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
30183018

30193019
go func() {
30203020
name := "cereal"
3021-
out, _, err := dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp:unconfined", "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
3021+
out, _, err := dockerCmdWithError("run", "--name", name, "--security-opt", "seccomp=unconfined", "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
30223022
if err == nil ||
30233023
!(strings.Contains(strings.ToLower(out), "mount: cannot mount none") ||
30243024
strings.Contains(strings.ToLower(out), "permission denied")) {
@@ -3031,7 +3031,7 @@ func (s *DockerSuite) TestRunUnshareProc(c *check.C) {
30313031
/* Ensure still fails if running privileged with the default policy */
30323032
go func() {
30333033
name := "crashoverride"
3034-
out, _, err := dockerCmdWithError("run", "--privileged", "--security-opt", "seccomp:unconfined", "--security-opt", "apparmor:docker-default", "--name", name, "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
3034+
out, _, err := dockerCmdWithError("run", "--privileged", "--security-opt", "seccomp=unconfined", "--security-opt", "apparmor=docker-default", "--name", name, "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
30353035
if err == nil ||
30363036
!(strings.Contains(strings.ToLower(out), "mount: cannot mount none") ||
30373037
strings.Contains(strings.ToLower(out), "permission denied")) {
@@ -3128,7 +3128,7 @@ func (s *DockerSuite) TestRunWriteFilteredProc(c *check.C) {
31283128
name := fmt.Sprintf("writeprocsieve-%d", i)
31293129

31303130
shellCmd := fmt.Sprintf("exec 3>%s", filePath)
3131-
out, code, err := dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor:docker-default", "--name", name, "busybox", "sh", "-c", shellCmd)
3131+
out, code, err := dockerCmdWithError("run", "--privileged", "--security-opt", "apparmor=docker-default", "--name", name, "busybox", "sh", "-c", shellCmd)
31323132
if code != 0 {
31333133
return
31343134
}

integration-cli/docker_cli_run_unix_test.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@ func (s *DockerSuite) TestRunTmpfsMounts(c *check.C) {
709709
}
710710
}
711711

712-
// TestRunSeccompProfileDenyUnshare checks that 'docker run --security-opt seccomp:/tmp/profile.json debian:jessie unshare' exits with operation not permitted.
712+
// TestRunSeccompProfileDenyUnshare checks that 'docker run --security-opt seccomp=/tmp/profile.json debian:jessie unshare' exits with operation not permitted.
713713
func (s *DockerSuite) TestRunSeccompProfileDenyUnshare(c *check.C) {
714714
testRequires(c, SameHostDaemon, seccompEnabled, NotArm, Apparmor)
715715
jsonData := `{
@@ -730,14 +730,14 @@ func (s *DockerSuite) TestRunSeccompProfileDenyUnshare(c *check.C) {
730730
if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
731731
c.Fatal(err)
732732
}
733-
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "apparmor:unconfined", "--security-opt", "seccomp:"+tmpFile.Name(), "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
733+
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "apparmor=unconfined", "--security-opt", "seccomp="+tmpFile.Name(), "debian:jessie", "unshare", "-p", "-m", "-f", "-r", "mount", "-t", "proc", "none", "/proc")
734734
out, _, _ := runCommandWithOutput(runCmd)
735735
if !strings.Contains(out, "Operation not permitted") {
736736
c.Fatalf("expected unshare with seccomp profile denied to fail, got %s", out)
737737
}
738738
}
739739

740-
// TestRunSeccompProfileDenyChmod checks that 'docker run --security-opt seccomp:/tmp/profile.json busybox chmod 400 /etc/hostname' exits with operation not permitted.
740+
// TestRunSeccompProfileDenyChmod checks that 'docker run --security-opt seccomp=/tmp/profile.json busybox chmod 400 /etc/hostname' exits with operation not permitted.
741741
func (s *DockerSuite) TestRunSeccompProfileDenyChmod(c *check.C) {
742742
testRequires(c, SameHostDaemon, seccompEnabled)
743743
jsonData := `{
@@ -758,7 +758,7 @@ func (s *DockerSuite) TestRunSeccompProfileDenyChmod(c *check.C) {
758758
if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
759759
c.Fatal(err)
760760
}
761-
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp:"+tmpFile.Name(), "busybox", "chmod", "400", "/etc/hostname")
761+
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp="+tmpFile.Name(), "busybox", "chmod", "400", "/etc/hostname")
762762
out, _, _ := runCommandWithOutput(runCmd)
763763
if !strings.Contains(out, "Operation not permitted") {
764764
c.Fatalf("expected chmod with seccomp profile denied to fail, got %s", out)
@@ -795,7 +795,7 @@ func (s *DockerSuite) TestRunSeccompProfileDenyUnshareUserns(c *check.C) {
795795
if _, err := tmpFile.Write([]byte(jsonData)); err != nil {
796796
c.Fatal(err)
797797
}
798-
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "apparmor:unconfined", "--security-opt", "seccomp:"+tmpFile.Name(), "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami")
798+
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "apparmor=unconfined", "--security-opt", "seccomp="+tmpFile.Name(), "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami")
799799
out, _, _ := runCommandWithOutput(runCmd)
800800
if !strings.Contains(out, "Operation not permitted") {
801801
c.Fatalf("expected unshare userns with seccomp profile denied to fail, got %s", out)
@@ -815,14 +815,14 @@ func (s *DockerSuite) TestRunSeccompProfileDenyCloneUserns(c *check.C) {
815815
}
816816

817817
// TestRunSeccompUnconfinedCloneUserns checks that
818-
// 'docker run --security-opt seccomp:unconfined syscall-test' allows creating a userns.
818+
// 'docker run --security-opt seccomp=unconfined syscall-test' allows creating a userns.
819819
func (s *DockerSuite) TestRunSeccompUnconfinedCloneUserns(c *check.C) {
820820
testRequires(c, SameHostDaemon, seccompEnabled, UserNamespaceInKernel, NotUserNamespace)
821821

822822
// make sure running w privileged is ok
823-
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp:unconfined", "syscall-test", "userns-test", "id")
823+
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "syscall-test", "userns-test", "id")
824824
if out, _, err := runCommandWithOutput(runCmd); err != nil || !strings.Contains(out, "nobody") {
825-
c.Fatalf("expected clone userns with --security-opt seccomp:unconfined to succeed, got %s: %v", out, err)
825+
c.Fatalf("expected clone userns with --security-opt seccomp=unconfined to succeed, got %s: %v", out, err)
826826
}
827827
}
828828

@@ -872,15 +872,15 @@ func (s *DockerSuite) TestRunSeccompDefaultProfile(c *check.C) {
872872
}()
873873

874874
go func() {
875-
out, _, err := dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp:unconfined", "syscall-test", "acct-test")
875+
out, _, err := dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp=unconfined", "syscall-test", "acct-test")
876876
if err == nil || !strings.Contains(out, "No such file or directory") {
877877
errChan <- fmt.Errorf("expected No such file or directory, got: %s", out)
878878
}
879879
group.Done()
880880
}()
881881

882882
go func() {
883-
out, _, err := dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp:unconfined", "syscall-test", "ns-test", "echo", "hello")
883+
out, _, err := dockerCmdWithError("run", "--cap-add", "ALL", "--security-opt", "seccomp=unconfined", "syscall-test", "ns-test", "echo", "hello")
884884
if err != nil || !strings.Contains(out, "hello") {
885885
errChan <- fmt.Errorf("expected hello, got: %s, %v", out, err)
886886
}
@@ -911,12 +911,12 @@ func (s *DockerSuite) TestRunApparmorProcDirectory(c *check.C) {
911911
testRequires(c, SameHostDaemon, Apparmor)
912912

913913
// running w seccomp unconfined tests the apparmor profile
914-
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp:unconfined", "busybox", "chmod", "777", "/proc/1/cgroup")
914+
runCmd := exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "busybox", "chmod", "777", "/proc/1/cgroup")
915915
if out, _, err := runCommandWithOutput(runCmd); err == nil || !(strings.Contains(out, "Permission denied") || strings.Contains(out, "Operation not permitted")) {
916916
c.Fatalf("expected chmod 777 /proc/1/cgroup to fail, got %s: %v", out, err)
917917
}
918918

919-
runCmd = exec.Command(dockerBinary, "run", "--security-opt", "seccomp:unconfined", "busybox", "chmod", "777", "/proc/1/attr/current")
919+
runCmd = exec.Command(dockerBinary, "run", "--security-opt", "seccomp=unconfined", "busybox", "chmod", "777", "/proc/1/attr/current")
920920
if out, _, err := runCommandWithOutput(runCmd); err == nil || !(strings.Contains(out, "Permission denied") || strings.Contains(out, "Operation not permitted")) {
921921
c.Fatalf("expected chmod 777 /proc/1/attr/current to fail, got %s: %v", out, err)
922922
}
@@ -927,7 +927,7 @@ func (s *DockerSuite) TestRunApparmorProcDirectory(c *check.C) {
927927
func (s *DockerSuite) TestRunSeccompWithDefaultProfile(c *check.C) {
928928
testRequires(c, SameHostDaemon, seccompEnabled)
929929

930-
out, _, err := dockerCmdWithError("run", "--security-opt", "seccomp:../profiles/seccomp/default.json", "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami")
930+
out, _, err := dockerCmdWithError("run", "--security-opt", "seccomp=../profiles/seccomp/default.json", "debian:jessie", "unshare", "--map-root-user", "--user", "sh", "-c", "whoami")
931931
c.Assert(err, checker.NotNil, check.Commentf(out))
932932
c.Assert(strings.TrimSpace(out), checker.Equals, "unshare: unshare failed: Operation not permitted")
933933
}

0 commit comments

Comments
 (0)