github.com/containers/podman/v5@v5.1.0-rc1/test/e2e/exec_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"strings"
     8  
     9  	. "github.com/containers/podman/v5/test/utils"
    10  	. "github.com/onsi/ginkgo/v2"
    11  	. "github.com/onsi/gomega"
    12  	. "github.com/onsi/gomega/gexec"
    13  )
    14  
    15  var _ = Describe("Podman exec", func() {
    16  
    17  	It("podman exec into bogus container", func() {
    18  		session := podmanTest.Podman([]string{"exec", "foobar", "ls"})
    19  		session.WaitWithDefaultTimeout()
    20  		Expect(session).Should(ExitWithError(125, `no container with name or ID "foobar" found: no such container`))
    21  	})
    22  
    23  	It("podman exec simple command", func() {
    24  		setup := podmanTest.RunTopContainer("test1")
    25  		setup.WaitWithDefaultTimeout()
    26  		Expect(setup).Should(ExitCleanly())
    27  
    28  		session := podmanTest.Podman([]string{"exec", "test1", "ls"})
    29  		session.WaitWithDefaultTimeout()
    30  		Expect(session).Should(ExitCleanly())
    31  
    32  		// With no command
    33  		session = podmanTest.Podman([]string{"exec", "test1"})
    34  		session.WaitWithDefaultTimeout()
    35  		Expect(session).Should(ExitWithError(125, "must provide a non-empty command to start an exec session: invalid argument"))
    36  	})
    37  
    38  	It("podman container exec simple command", func() {
    39  		setup := podmanTest.RunTopContainer("test1")
    40  		setup.WaitWithDefaultTimeout()
    41  		Expect(setup).Should(ExitCleanly())
    42  
    43  		session := podmanTest.Podman([]string{"container", "exec", "test1", "ls"})
    44  		session.WaitWithDefaultTimeout()
    45  		Expect(session).Should(ExitCleanly())
    46  	})
    47  
    48  	It("podman exec simple command using latest", func() {
    49  		setup := podmanTest.RunTopContainer("test1")
    50  		setup.WaitWithDefaultTimeout()
    51  		Expect(setup).Should(ExitCleanly())
    52  		cid := "-l"
    53  		if IsRemote() {
    54  			cid = "test1"
    55  		}
    56  		session := podmanTest.Podman([]string{"exec", cid, "ls"})
    57  		session.WaitWithDefaultTimeout()
    58  		Expect(session).Should(ExitCleanly())
    59  	})
    60  
    61  	It("podman exec environment test", func() {
    62  		setup := podmanTest.RunTopContainer("test1")
    63  		setup.WaitWithDefaultTimeout()
    64  		Expect(setup).Should(ExitCleanly())
    65  
    66  		session := podmanTest.Podman([]string{"exec", "--env", "FOO=BAR", "test1", "printenv", "FOO"})
    67  		session.WaitWithDefaultTimeout()
    68  		Expect(session).Should(ExitCleanly())
    69  		Expect(session.OutputToString()).To(Equal("BAR"))
    70  
    71  		session = podmanTest.Podman([]string{"exec", "--env", "PATH=/bin", "test1", "printenv", "PATH"})
    72  		session.WaitWithDefaultTimeout()
    73  		Expect(session).Should(ExitCleanly())
    74  		Expect(session.OutputToString()).To(Equal("/bin"))
    75  	})
    76  
    77  	It("podman exec os.Setenv env", func() {
    78  		// remote doesn't properly interpret os.Setenv
    79  		setup := podmanTest.RunTopContainer("test1")
    80  		setup.WaitWithDefaultTimeout()
    81  		Expect(setup).Should(ExitCleanly())
    82  
    83  		os.Setenv("FOO", "BAR")
    84  		session := podmanTest.Podman([]string{"exec", "--env", "FOO", "test1", "printenv", "FOO"})
    85  		session.WaitWithDefaultTimeout()
    86  		Expect(session).Should(ExitCleanly())
    87  		Expect(session.OutputToString()).To(Equal("BAR"))
    88  		os.Unsetenv("FOO")
    89  	})
    90  
    91  	It("podman exec exit code", func() {
    92  		setup := podmanTest.RunTopContainer("test1")
    93  		setup.WaitWithDefaultTimeout()
    94  		Expect(setup).Should(ExitCleanly())
    95  
    96  		session := podmanTest.Podman([]string{"exec", "test1", "sh", "-c", "exit 100"})
    97  		session.WaitWithDefaultTimeout()
    98  		Expect(session).Should(Exit(100))
    99  	})
   100  
   101  	It("podman exec in keep-id container drops privileges", func() {
   102  		SkipIfNotRootless("This function is not enabled for rootful podman")
   103  		ctrName := "testctr1"
   104  		testCtr := podmanTest.Podman([]string{"run", "-d", "--name", ctrName, "--userns=keep-id", ALPINE, "top"})
   105  		testCtr.WaitWithDefaultTimeout()
   106  		Expect(testCtr).Should(ExitCleanly())
   107  
   108  		session := podmanTest.Podman([]string{"exec", ctrName, "grep", "CapEff", "/proc/self/status"})
   109  		session.WaitWithDefaultTimeout()
   110  		Expect(session).Should(ExitCleanly())
   111  		Expect(session.OutputToString()).To(ContainSubstring("0000000000000000"))
   112  	})
   113  
   114  	It("podman exec --privileged", func() {
   115  		session := podmanTest.Podman([]string{"run", "--privileged", "--rm", ALPINE, "sh", "-c", "grep ^CapBnd /proc/self/status | cut -f 2"})
   116  		session.WaitWithDefaultTimeout()
   117  		Expect(session).Should(ExitCleanly())
   118  		bndPerms := session.OutputToString()
   119  
   120  		session = podmanTest.Podman([]string{"run", "--privileged", "--rm", ALPINE, "sh", "-c", "grep ^CapEff /proc/self/status | cut -f 2"})
   121  		session.WaitWithDefaultTimeout()
   122  		Expect(session).Should(ExitCleanly())
   123  		effPerms := session.OutputToString()
   124  
   125  		setup := podmanTest.RunTopContainer("test-privileged")
   126  		setup.WaitWithDefaultTimeout()
   127  		Expect(setup).Should(ExitCleanly())
   128  
   129  		session = podmanTest.Podman([]string{"exec", "--privileged", "test-privileged", "sh", "-c", "grep ^CapEff /proc/self/status | cut -f 2"})
   130  		session.WaitWithDefaultTimeout()
   131  		Expect(session).Should(ExitCleanly())
   132  		Expect(session.OutputToString()).To(ContainSubstring(effPerms))
   133  
   134  		session = podmanTest.Podman([]string{"exec", "--privileged", "test-privileged", "sh", "-c", "grep ^CapBnd /proc/self/status | cut -f 2"})
   135  		session.WaitWithDefaultTimeout()
   136  		Expect(session).Should(ExitCleanly())
   137  		Expect(session.OutputToString()).To(ContainSubstring(bndPerms))
   138  	})
   139  
   140  	It("podman exec --privileged", func() {
   141  		session := podmanTest.Podman([]string{"run", "--privileged", "--user=bin", "--rm", ALPINE, "sh", "-c", "grep ^CapBnd /proc/self/status | cut -f 2"})
   142  		session.WaitWithDefaultTimeout()
   143  		Expect(session).Should(ExitCleanly())
   144  		bndPerms := session.OutputToString()
   145  
   146  		session = podmanTest.Podman([]string{"run", "--privileged", "--user=bin", "--rm", ALPINE, "sh", "-c", "grep ^CapEff /proc/self/status | cut -f 2"})
   147  		session.WaitWithDefaultTimeout()
   148  		Expect(session).Should(ExitCleanly())
   149  		effPerms := session.OutputToString()
   150  
   151  		setup := podmanTest.RunTopContainer("test-privileged")
   152  		setup.WaitWithDefaultTimeout()
   153  		Expect(setup).Should(ExitCleanly())
   154  
   155  		session = podmanTest.Podman([]string{"exec", "--privileged", "--user=bin", "test-privileged", "sh", "-c", "grep ^CapEff /proc/self/status | cut -f 2"})
   156  		session.WaitWithDefaultTimeout()
   157  		Expect(session).Should(ExitCleanly())
   158  		Expect(session.OutputToString()).To(ContainSubstring(effPerms))
   159  
   160  		session = podmanTest.Podman([]string{"exec", "--privileged", "--user=bin", "test-privileged", "sh", "-c", "grep ^CapBnd /proc/self/status | cut -f 2"})
   161  		session.WaitWithDefaultTimeout()
   162  		Expect(session).Should(ExitCleanly())
   163  		Expect(session.OutputToString()).To(ContainSubstring(bndPerms))
   164  
   165  	})
   166  
   167  	It("podman exec --privileged", func() {
   168  		session := podmanTest.Podman([]string{"run", "--privileged", "--rm", ALPINE, "sh", "-c", "grep ^CapBnd /proc/self/status | cut -f 2"})
   169  		session.WaitWithDefaultTimeout()
   170  		Expect(session).Should(ExitCleanly())
   171  		bndPerms := session.OutputToString()
   172  
   173  		setup := podmanTest.RunTopContainer("test-privileged")
   174  		setup.WaitWithDefaultTimeout()
   175  		Expect(setup).Should(ExitCleanly())
   176  
   177  		session = podmanTest.Podman([]string{"exec", "--privileged", "--user=bin", "test-privileged", "sh", "-c", "grep ^CapEff /proc/self/status | cut -f 2"})
   178  		session.WaitWithDefaultTimeout()
   179  		Expect(session).Should(ExitCleanly())
   180  		Expect(session.OutputToString()).To(ContainSubstring("00000000"))
   181  
   182  		session = podmanTest.Podman([]string{"exec", "--privileged", "--user=bin", "test-privileged", "sh", "-c", "grep ^CapBnd /proc/self/status | cut -f 2"})
   183  		session.WaitWithDefaultTimeout()
   184  		Expect(session).Should(ExitCleanly())
   185  		Expect(session.OutputToString()).To(ContainSubstring(bndPerms))
   186  	})
   187  
   188  	It("podman exec --privileged container not running as root", func() {
   189  		session := podmanTest.Podman([]string{"run", "--privileged", "--rm", ALPINE, "sh", "-c", "grep ^CapBnd /proc/self/status | cut -f 2"})
   190  		session.WaitWithDefaultTimeout()
   191  		Expect(session).Should(ExitCleanly())
   192  		bndPerms := session.OutputToString()
   193  
   194  		setup := podmanTest.RunTopContainerWithArgs("test-privileged", []string{"--user=bin"})
   195  		setup.WaitWithDefaultTimeout()
   196  		Expect(setup).Should(ExitCleanly())
   197  
   198  		session = podmanTest.Podman([]string{"exec", "--privileged", "test-privileged", "sh", "-c", "grep ^CapEff /proc/self/status | cut -f 2"})
   199  		session.WaitWithDefaultTimeout()
   200  		Expect(session).Should(ExitCleanly())
   201  		Expect(session.OutputToString()).To(ContainSubstring("00000000"))
   202  
   203  		session = podmanTest.Podman([]string{"exec", "--privileged", "--user=bin", "test-privileged", "sh", "-c", "grep ^CapEff /proc/self/status | cut -f 2"})
   204  		session.WaitWithDefaultTimeout()
   205  		Expect(session).Should(ExitCleanly())
   206  		Expect(session.OutputToString()).To(ContainSubstring("00000000"))
   207  
   208  		session = podmanTest.Podman([]string{"exec", "--privileged", "--user=root", "test-privileged", "sh", "-c", "grep ^CapEff /proc/self/status | cut -f 2"})
   209  		session.WaitWithDefaultTimeout()
   210  		Expect(session).Should(ExitCleanly())
   211  		Expect(session.OutputToString()).To(ContainSubstring(bndPerms))
   212  
   213  		session = podmanTest.Podman([]string{"exec", "--privileged", "--user=bin", "test-privileged", "sh", "-c", "grep ^CapBnd /proc/self/status | cut -f 2"})
   214  		session.WaitWithDefaultTimeout()
   215  		Expect(session).Should(ExitCleanly())
   216  		Expect(session.OutputToString()).To(ContainSubstring(bndPerms))
   217  	})
   218  
   219  	It("podman exec with user with cap-add", func() {
   220  		capAdd := "--cap-add=net_bind_service"
   221  		session := podmanTest.Podman([]string{"run", "--user=bin", capAdd, "--rm", ALPINE, "sh", "-c", "grep ^CapBnd /proc/self/status | cut -f 2"})
   222  		session.WaitWithDefaultTimeout()
   223  		Expect(session).Should(ExitCleanly())
   224  		bndPerms := session.OutputToString()
   225  
   226  		session = podmanTest.Podman([]string{"run", "--user=bin", capAdd, "--rm", ALPINE, "sh", "-c", "grep ^CapEff /proc/self/status | cut -f 2"})
   227  		session.WaitWithDefaultTimeout()
   228  		Expect(session).Should(ExitCleanly())
   229  		effPerms := session.OutputToString()
   230  
   231  		setup := podmanTest.RunTopContainerWithArgs("test-privileged", []string{"--user=bin", capAdd})
   232  		setup.WaitWithDefaultTimeout()
   233  		Expect(setup).Should(ExitCleanly())
   234  
   235  		session = podmanTest.Podman([]string{"exec", "test-privileged", "sh", "-c", "grep ^CapBnd /proc/self/status | cut -f 2"})
   236  		session.WaitWithDefaultTimeout()
   237  		Expect(session).Should(ExitCleanly())
   238  		Expect(session.OutputToString()).To(ContainSubstring(bndPerms))
   239  
   240  		session = podmanTest.Podman([]string{"exec", "test-privileged", "sh", "-c", "grep ^CapEff /proc/self/status | cut -f 2"})
   241  		session.WaitWithDefaultTimeout()
   242  		Expect(session).Should(ExitCleanly())
   243  		Expect(session.OutputToString()).To(ContainSubstring(effPerms))
   244  	})
   245  
   246  	It("podman exec with user with and cap-drop cap-add", func() {
   247  		capAdd := "--cap-add=net_bind_service"
   248  		capDrop := "--cap-drop=all"
   249  		session := podmanTest.Podman([]string{"run", "--user=bin", capDrop, capAdd, "--rm", ALPINE, "sh", "-c", "grep ^CapBnd /proc/self/status | cut -f 2"})
   250  		session.WaitWithDefaultTimeout()
   251  		Expect(session).Should(ExitCleanly())
   252  		bndPerms := session.OutputToString()
   253  
   254  		session = podmanTest.Podman([]string{"run", "--user=bin", capDrop, capAdd, "--rm", ALPINE, "sh", "-c", "grep ^CapEff /proc/self/status | cut -f 2"})
   255  		session.WaitWithDefaultTimeout()
   256  		Expect(session).Should(ExitCleanly())
   257  		effPerms := session.OutputToString()
   258  
   259  		setup := podmanTest.RunTopContainerWithArgs("test-privileged", []string{"--user=bin", capDrop, capAdd})
   260  		setup.WaitWithDefaultTimeout()
   261  		Expect(setup).Should(ExitCleanly())
   262  
   263  		session = podmanTest.Podman([]string{"exec", "test-privileged", "sh", "-c", "grep ^CapBnd /proc/self/status | cut -f 2"})
   264  		session.WaitWithDefaultTimeout()
   265  		Expect(session).Should(ExitCleanly())
   266  		Expect(session.OutputToString()).To(ContainSubstring(bndPerms))
   267  
   268  		session = podmanTest.Podman([]string{"exec", "--privileged", "test-privileged", "sh", "-c", "grep ^CapInh /proc/self/status | cut -f 2"})
   269  		session.WaitWithDefaultTimeout()
   270  		Expect(session).Should(ExitCleanly())
   271  		Expect(session.OutputToString()).To(ContainSubstring(effPerms))
   272  
   273  		session = podmanTest.Podman([]string{"exec", "test-privileged", "sh", "-c", "grep ^CapEff /proc/self/status | cut -f 2"})
   274  		session.WaitWithDefaultTimeout()
   275  		Expect(session).Should(ExitCleanly())
   276  		Expect(session.OutputToString()).To(ContainSubstring(effPerms))
   277  
   278  		session = podmanTest.Podman([]string{"exec", "test-privileged", "sh", "-c", "grep ^CapPrm /proc/self/status | cut -f 2"})
   279  		session.WaitWithDefaultTimeout()
   280  		Expect(session).Should(ExitCleanly())
   281  		Expect(session.OutputToString()).To(ContainSubstring(effPerms))
   282  
   283  		session = podmanTest.Podman([]string{"exec", "test-privileged", "sh", "-c", "grep ^CapAmb /proc/self/status | cut -f 2"})
   284  		session.WaitWithDefaultTimeout()
   285  		Expect(session).Should(ExitCleanly())
   286  		Expect(session.OutputToString()).To(ContainSubstring(effPerms))
   287  	})
   288  
   289  	It("podman exec --privileged with user", func() {
   290  		session := podmanTest.Podman([]string{"run", "--privileged", "--user=bin", "--rm", ALPINE, "sh", "-c", "grep ^CapBnd /proc/self/status | cut -f 2"})
   291  		session.WaitWithDefaultTimeout()
   292  		Expect(session).Should(ExitCleanly())
   293  		bindPerms := session.OutputToString()
   294  
   295  		setup := podmanTest.RunTopContainerWithArgs("test-privileged", []string{"--privileged", "--user=bin"})
   296  		setup.WaitWithDefaultTimeout()
   297  		Expect(setup).Should(ExitCleanly())
   298  
   299  		session = podmanTest.Podman([]string{"exec", "--privileged", "test-privileged", "sh", "-c", "grep ^CapBnd /proc/self/status | cut -f 2"})
   300  		session.WaitWithDefaultTimeout()
   301  		Expect(session).Should(ExitCleanly())
   302  		Expect(session.OutputToString()).To(ContainSubstring(bindPerms))
   303  
   304  		session = podmanTest.Podman([]string{"exec", "--privileged", "test-privileged", "sh", "-c", "grep ^CapEff /proc/self/status | cut -f 2"})
   305  		session.WaitWithDefaultTimeout()
   306  		Expect(session).Should(ExitCleanly())
   307  		Expect(session.OutputToString()).To(ContainSubstring("0000000000000000"))
   308  	})
   309  
   310  	// #10927 ("no logs from conmon"), one of our nastiest flakes
   311  	It("podman exec terminal doesn't hang", FlakeAttempts(3), func() {
   312  		setup := podmanTest.Podman([]string{"run", "-dti", "--name", "test1", fedoraMinimal, "sleep", "+Inf"})
   313  		setup.WaitWithDefaultTimeout()
   314  		Expect(setup).Should(Exit(0))
   315  		Expect(setup.ErrorToString()).To(ContainSubstring("The input device is not a TTY. The --tty and --interactive flags might not work properly"))
   316  
   317  		for i := 0; i < 5; i++ {
   318  			session := podmanTest.Podman([]string{"exec", "-ti", "test1", "true"})
   319  			session.WaitWithDefaultTimeout()
   320  			Expect(session).Should(ExitCleanly())
   321  		}
   322  	})
   323  
   324  	It("podman exec pseudo-terminal sanity check", func() {
   325  		setup := podmanTest.Podman([]string{"run", "--detach", "--name", "test1", fedoraMinimal, "sleep", "+Inf"})
   326  		setup.WaitWithDefaultTimeout()
   327  		Expect(setup).Should(ExitCleanly())
   328  
   329  		session := podmanTest.Podman([]string{"exec", "--interactive", "--tty", "test1", "/usr/bin/stty", "--all"})
   330  		session.WaitWithDefaultTimeout()
   331  		Expect(session).Should(ExitCleanly())
   332  		Expect(session.OutputToString()).To(ContainSubstring(" onlcr"))
   333  	})
   334  
   335  	It("podman exec simple command with user", func() {
   336  		setup := podmanTest.RunTopContainer("test1")
   337  		setup.WaitWithDefaultTimeout()
   338  		Expect(setup).Should(ExitCleanly())
   339  
   340  		session := podmanTest.Podman([]string{"exec", "--user", "root", "test1", "ls"})
   341  		session.WaitWithDefaultTimeout()
   342  		Expect(session).Should(ExitCleanly())
   343  	})
   344  
   345  	It("podman exec with user only in container", func() {
   346  		testUser := "test123"
   347  		setup := podmanTest.Podman([]string{"run", "--name", "test1", "-d", CITEST_IMAGE, "sleep", "60"})
   348  		setup.WaitWithDefaultTimeout()
   349  		Expect(setup).Should(ExitCleanly())
   350  
   351  		session := podmanTest.Podman([]string{"exec", "test1", "adduser", "-D", testUser})
   352  		session.WaitWithDefaultTimeout()
   353  		Expect(session).Should(ExitCleanly())
   354  
   355  		session2 := podmanTest.Podman([]string{"exec", "--user", testUser, "test1", "whoami"})
   356  		session2.WaitWithDefaultTimeout()
   357  		Expect(session2).Should(ExitCleanly())
   358  		Expect(session2.OutputToString()).To(Equal(testUser))
   359  	})
   360  
   361  	It("podman exec with user from run", func() {
   362  		testUser := "guest"
   363  		setup := podmanTest.Podman([]string{"run", "--user", testUser, "-d", ALPINE, "top"})
   364  		setup.WaitWithDefaultTimeout()
   365  		Expect(setup).Should(ExitCleanly())
   366  		ctrID := setup.OutputToString()
   367  
   368  		session := podmanTest.Podman([]string{"exec", ctrID, "whoami"})
   369  		session.WaitWithDefaultTimeout()
   370  		Expect(session).Should(ExitCleanly())
   371  		Expect(session.OutputToString()).To(ContainSubstring(testUser))
   372  
   373  		overrideUser := "root"
   374  		session = podmanTest.Podman([]string{"exec", "--user", overrideUser, ctrID, "whoami"})
   375  		session.WaitWithDefaultTimeout()
   376  		Expect(session).Should(ExitCleanly())
   377  		Expect(session.OutputToString()).To(ContainSubstring(overrideUser))
   378  	})
   379  
   380  	It("podman exec simple working directory test", func() {
   381  		setup := podmanTest.RunTopContainer("test1")
   382  		setup.WaitWithDefaultTimeout()
   383  		Expect(setup).Should(ExitCleanly())
   384  
   385  		session := podmanTest.Podman([]string{"exec", "--workdir", "/tmp", "test1", "pwd"})
   386  		session.WaitWithDefaultTimeout()
   387  		Expect(session).Should(ExitCleanly())
   388  		Expect(session.OutputToString()).To(Equal("/tmp"))
   389  
   390  		session = podmanTest.Podman([]string{"exec", "-w", "/tmp", "test1", "pwd"})
   391  		session.WaitWithDefaultTimeout()
   392  		Expect(session).Should(ExitCleanly())
   393  		Expect(session.OutputToString()).To(Equal("/tmp"))
   394  	})
   395  
   396  	It("podman exec missing working directory test", func() {
   397  		setup := podmanTest.RunTopContainer("test1")
   398  		setup.WaitWithDefaultTimeout()
   399  		Expect(setup).Should(ExitCleanly())
   400  
   401  		expect := "chdir to `/missing`: No such file or directory"
   402  		if podmanTest.OCIRuntime == "runc" {
   403  			expect = "chdir to cwd"
   404  		}
   405  		session := podmanTest.Podman([]string{"exec", "--workdir", "/missing", "test1", "pwd"})
   406  		session.WaitWithDefaultTimeout()
   407  		Expect(session).To(ExitWithError(127, expect))
   408  
   409  		session = podmanTest.Podman([]string{"exec", "-w", "/missing", "test1", "pwd"})
   410  		session.WaitWithDefaultTimeout()
   411  		Expect(session).To(ExitWithError(127, expect))
   412  	})
   413  
   414  	It("podman exec cannot be invoked", func() {
   415  		setup := podmanTest.RunTopContainer("test1")
   416  		setup.WaitWithDefaultTimeout()
   417  		Expect(setup).Should(ExitCleanly())
   418  
   419  		session := podmanTest.Podman([]string{"exec", "test1", "/etc"})
   420  		session.WaitWithDefaultTimeout()
   421  
   422  		// crun (and, we hope, any other future runtimes)
   423  		expectedStatus := 126
   424  		expectedMessage := "open executable: Operation not permitted: OCI permission denied"
   425  
   426  		// ...but it's much more complicated under runc (#19552)
   427  		if podmanTest.OCIRuntime == "runc" {
   428  			expectedMessage = `exec failed: unable to start container process: exec: "/etc": is a directory`
   429  			expectedStatus = 255
   430  			if IsRemote() {
   431  				expectedStatus = 125
   432  			}
   433  		}
   434  		Expect(session).Should(ExitWithError(expectedStatus, expectedMessage))
   435  	})
   436  
   437  	It("podman exec command not found", func() {
   438  		setup := podmanTest.RunTopContainer("test1")
   439  		setup.WaitWithDefaultTimeout()
   440  		Expect(setup).Should(ExitCleanly())
   441  
   442  		session := podmanTest.Podman([]string{"exec", "test1", "notthere"})
   443  		session.WaitWithDefaultTimeout()
   444  		Expect(session).Should(ExitWithError(127, "OCI runtime attempted to invoke a command that was not found"))
   445  	})
   446  
   447  	It("podman exec preserve fds sanity check", func() {
   448  		setup := podmanTest.RunTopContainer("test1")
   449  		setup.WaitWithDefaultTimeout()
   450  		Expect(setup).Should(ExitCleanly())
   451  
   452  		devNull, err := os.Open("/dev/null")
   453  		Expect(err).ToNot(HaveOccurred())
   454  		defer devNull.Close()
   455  		files := []*os.File{
   456  			devNull,
   457  		}
   458  		session := podmanTest.PodmanExtraFiles([]string{"exec", "--preserve-fds", "1", "test1", "ls"}, files)
   459  		session.WaitWithDefaultTimeout()
   460  		Expect(session).Should(ExitCleanly())
   461  	})
   462  
   463  	It("podman exec preserves --group-add groups", func() {
   464  		groupName := "group1"
   465  		gid := "4444"
   466  		ctrName1 := "ctr1"
   467  		ctr1 := podmanTest.Podman([]string{"run", "--name", ctrName1, fedoraMinimal, "groupadd", "-g", gid, groupName})
   468  		ctr1.WaitWithDefaultTimeout()
   469  		Expect(ctr1).Should(ExitCleanly())
   470  
   471  		imgName := "img1"
   472  		commit := podmanTest.Podman([]string{"commit", "-q", ctrName1, imgName})
   473  		commit.WaitWithDefaultTimeout()
   474  		Expect(commit).Should(ExitCleanly())
   475  
   476  		ctrName2 := "ctr2"
   477  		ctr2 := podmanTest.Podman([]string{"run", "-d", "--name", ctrName2, "--group-add", groupName, imgName, "sleep", "300"})
   478  		ctr2.WaitWithDefaultTimeout()
   479  		Expect(ctr2).Should(ExitCleanly())
   480  
   481  		exec := podmanTest.Podman([]string{"exec", ctrName2, "id"})
   482  		exec.WaitWithDefaultTimeout()
   483  		Expect(exec).Should(ExitCleanly())
   484  		Expect(exec.OutputToString()).To(ContainSubstring(fmt.Sprintf("%s(%s)", gid, groupName)))
   485  	})
   486  
   487  	It("podman exec preserves container groups with --user and --group-add", func() {
   488  		dockerfile := fmt.Sprintf(`FROM %s
   489  RUN groupadd -g 4000 first
   490  RUN groupadd -g 4001 second
   491  RUN useradd -u 1000 auser`, fedoraMinimal)
   492  		imgName := "testimg"
   493  		podmanTest.BuildImage(dockerfile, imgName, "false")
   494  
   495  		ctrName := "testctr"
   496  		ctr := podmanTest.Podman([]string{"run", "-d", "--name", ctrName, "--user", "auser:first", "--group-add", "second", imgName, "sleep", "300"})
   497  		ctr.WaitWithDefaultTimeout()
   498  		Expect(ctr).Should(ExitCleanly())
   499  
   500  		exec := podmanTest.Podman([]string{"exec", ctrName, "id"})
   501  		exec.WaitWithDefaultTimeout()
   502  		Expect(exec).Should(ExitCleanly())
   503  		output := exec.OutputToString()
   504  		Expect(output).To(ContainSubstring("4000(first)"))
   505  		Expect(output).To(ContainSubstring("4001(second)"))
   506  		Expect(output).To(ContainSubstring("1000(auser)"))
   507  
   508  		// Kill the container just so the test does not take 15 seconds to stop.
   509  		kill := podmanTest.Podman([]string{"kill", ctrName})
   510  		kill.WaitWithDefaultTimeout()
   511  		Expect(kill).Should(ExitCleanly())
   512  	})
   513  
   514  	It("podman exec --detach", func() {
   515  		ctrName := "testctr"
   516  		ctr := podmanTest.Podman([]string{"run", "-d", "--name", ctrName, ALPINE, "top"})
   517  		ctr.WaitWithDefaultTimeout()
   518  		Expect(ctr).Should(ExitCleanly())
   519  
   520  		exec1 := podmanTest.Podman([]string{"exec", "-d", ctrName, "top"})
   521  		exec1.WaitWithDefaultTimeout()
   522  		Expect(ctr).Should(ExitCleanly())
   523  
   524  		data := podmanTest.InspectContainer(ctrName)
   525  		Expect(data).To(HaveLen(1))
   526  		Expect(data[0].ExecIDs).To(HaveLen(1))
   527  		Expect(exec1.OutputToString()).To(ContainSubstring(data[0].ExecIDs[0]))
   528  
   529  		exec2 := podmanTest.Podman([]string{"exec", ctrName, "ps", "-a"})
   530  		exec2.WaitWithDefaultTimeout()
   531  		Expect(ctr).Should(ExitCleanly())
   532  		Expect(strings.Count(exec2.OutputToString(), "top")).To(Equal(2))
   533  
   534  		// Ensure that stop with a running detached exec session is
   535  		// clean.
   536  		podmanTest.StopContainer(ctrName)
   537  	})
   538  
   539  	It("podman exec with env var secret", func() {
   540  		secretsString := "somesecretdata"
   541  		secretFilePath := filepath.Join(podmanTest.TempDir, "secret")
   542  		err := os.WriteFile(secretFilePath, []byte(secretsString), 0755)
   543  		Expect(err).ToNot(HaveOccurred())
   544  
   545  		session := podmanTest.Podman([]string{"secret", "create", "mysecret", secretFilePath})
   546  		session.WaitWithDefaultTimeout()
   547  		Expect(session).Should(ExitCleanly())
   548  
   549  		session = podmanTest.Podman([]string{"run", "-d", "--secret", "source=mysecret,type=env", "--name", "secr", ALPINE, "top"})
   550  		session.WaitWithDefaultTimeout()
   551  		Expect(session).Should(ExitCleanly())
   552  
   553  		session = podmanTest.Podman([]string{"exec", "secr", "printenv", "mysecret"})
   554  		session.WaitWithDefaultTimeout()
   555  		Expect(session).Should(ExitCleanly())
   556  		Expect(session.OutputToString()).To(ContainSubstring(secretsString))
   557  
   558  		session = podmanTest.Podman([]string{"commit", "-q", "secr", "foobar.com/test1-image:latest"})
   559  		session.WaitWithDefaultTimeout()
   560  		Expect(session).Should(ExitCleanly())
   561  
   562  		session = podmanTest.Podman([]string{"run", "foobar.com/test1-image:latest", "printenv", "mysecret"})
   563  		session.WaitWithDefaultTimeout()
   564  		Expect(session.OutputToString()).To(Not(ContainSubstring(secretsString)))
   565  	})
   566  
   567  	It("podman exec --wait 2 seconds on bogus container", func() {
   568  		SkipIfRemote("not supported for --wait")
   569  		session := podmanTest.Podman([]string{"exec", "--wait", "2", "1234"})
   570  		session.WaitWithDefaultTimeout()
   571  		Expect(session).Should(ExitWithError(125, "timed out waiting for container: 1234"))
   572  	})
   573  
   574  	It("podman exec --wait 5 seconds for started container", func() {
   575  		SkipIfRemote("not supported for --wait")
   576  		ctrName := "waitCtr"
   577  
   578  		session := podmanTest.Podman([]string{"exec", "--wait", "5", ctrName, "whoami"})
   579  
   580  		session2 := podmanTest.Podman([]string{"run", "-d", "--name", ctrName, ALPINE, "top"})
   581  		session2.WaitWithDefaultTimeout()
   582  
   583  		session.Wait(6)
   584  
   585  		Expect(session2).Should(ExitCleanly())
   586  		Expect(session).Should(ExitCleanly())
   587  		Expect(session.OutputToString()).To(Equal("root"))
   588  	})
   589  })