github.com/containers/podman/v4@v4.9.4/test/e2e/push_test.go (about)

     1  package integration
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"os/exec"
     7  	"path/filepath"
     8  	"strings"
     9  
    10  	. "github.com/containers/podman/v4/test/utils"
    11  	"github.com/containers/storage/pkg/archive"
    12  	. "github.com/onsi/ginkgo/v2"
    13  	. "github.com/onsi/gomega"
    14  	. "github.com/onsi/gomega/gexec"
    15  )
    16  
    17  var _ = Describe("Podman push", func() {
    18  
    19  	BeforeEach(func() {
    20  		podmanTest.AddImageToRWStore(ALPINE)
    21  	})
    22  
    23  	It("podman push to containers/storage", func() {
    24  		SkipIfRemote("Remote push does not support containers-storage transport")
    25  		session := podmanTest.Podman([]string{"push", "-q", ALPINE, "containers-storage:busybox:test"})
    26  		session.WaitWithDefaultTimeout()
    27  		Expect(session).Should(ExitCleanly())
    28  
    29  		session = podmanTest.Podman([]string{"rmi", ALPINE})
    30  		session.WaitWithDefaultTimeout()
    31  		Expect(session).Should(ExitCleanly())
    32  	})
    33  
    34  	It("podman push to dir", func() {
    35  		SkipIfRemote("Remote push does not support dir transport")
    36  		bbdir := filepath.Join(podmanTest.TempDir, "busybox")
    37  		session := podmanTest.Podman([]string{"push", "-q", "--remove-signatures", ALPINE,
    38  			fmt.Sprintf("dir:%s", bbdir)})
    39  		session.WaitWithDefaultTimeout()
    40  		Expect(session).Should(ExitCleanly())
    41  
    42  		bbdir = filepath.Join(podmanTest.TempDir, "busybox")
    43  		session = podmanTest.Podman([]string{"push", "-q", "--format", "oci", ALPINE,
    44  			fmt.Sprintf("dir:%s", bbdir)})
    45  		session.WaitWithDefaultTimeout()
    46  		Expect(session).Should(ExitCleanly())
    47  	})
    48  
    49  	It("podman push to oci with compression-format and compression-level", func() {
    50  		SkipIfRemote("Remote push does not support dir transport")
    51  		bbdir := filepath.Join(podmanTest.TempDir, "busybox-oci")
    52  
    53  		// Invalid compression format specified, it must fail
    54  		session := podmanTest.Podman([]string{"push", "-q", "--compression-format=gzip", "--compression-level=40", ALPINE, fmt.Sprintf("oci:%s", bbdir)})
    55  		session.WaitWithDefaultTimeout()
    56  		Expect(session).Should(Exit(125))
    57  		output := session.ErrorToString()
    58  		Expect(output).To(ContainSubstring("invalid compression level"))
    59  
    60  		session = podmanTest.Podman([]string{"push", "-q", "--compression-format=zstd", "--remove-signatures", ALPINE,
    61  			fmt.Sprintf("oci:%s", bbdir)})
    62  		session.WaitWithDefaultTimeout()
    63  		Expect(session).Should(ExitCleanly())
    64  
    65  		foundZstdFile := false
    66  
    67  		blobsDir := filepath.Join(bbdir, "blobs/sha256")
    68  
    69  		blobs, err := os.ReadDir(blobsDir)
    70  		Expect(err).ToNot(HaveOccurred())
    71  
    72  		for _, f := range blobs {
    73  			blobPath := filepath.Join(blobsDir, f.Name())
    74  
    75  			sourceFile, err := os.ReadFile(blobPath)
    76  			Expect(err).ToNot(HaveOccurred())
    77  
    78  			compressionType := archive.DetectCompression(sourceFile)
    79  			if compressionType == archive.Zstd {
    80  				foundZstdFile = true
    81  				break
    82  			}
    83  		}
    84  		Expect(foundZstdFile).To(BeTrue(), "found zstd file")
    85  	})
    86  
    87  	It("push test --force-compression", func() {
    88  		if podmanTest.Host.Arch == "ppc64le" {
    89  			Skip("No registry image for ppc64le")
    90  		}
    91  		if isRootless() {
    92  			err := podmanTest.RestoreArtifact(REGISTRY_IMAGE)
    93  			Expect(err).ToNot(HaveOccurred())
    94  		}
    95  		lock := GetPortLock("5000")
    96  		defer lock.Unlock()
    97  		session := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", "5000:5000", REGISTRY_IMAGE, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
    98  		session.WaitWithDefaultTimeout()
    99  		Expect(session).Should(ExitCleanly())
   100  
   101  		if !WaitContainerReady(podmanTest, "registry", "listening on", 20, 1) {
   102  			Skip("Cannot start docker registry.")
   103  		}
   104  
   105  		session = podmanTest.Podman([]string{"build", "-t", "imageone", "build/basicalpine"})
   106  		session.WaitWithDefaultTimeout()
   107  		Expect(session).Should(ExitCleanly())
   108  
   109  		push := podmanTest.Podman([]string{"push", "-q", "--tls-verify=false", "--remove-signatures", "imageone", "localhost:5000/image"})
   110  		push.WaitWithDefaultTimeout()
   111  		Expect(push).Should(ExitCleanly())
   112  
   113  		skopeoInspect := []string{"inspect", "--tls-verify=false", "--raw", "docker://localhost:5000/image:latest"}
   114  		skopeo := SystemExec("skopeo", skopeoInspect)
   115  		skopeo.WaitWithDefaultTimeout()
   116  		Expect(skopeo).Should(ExitCleanly())
   117  		output := skopeo.OutputToString()
   118  		// Default compression is gzip and push with `--force-compression=false` no traces of `zstd` should be there.
   119  		Expect(output).ToNot(ContainSubstring("zstd"))
   120  
   121  		push = podmanTest.Podman([]string{"push", "-q", "--tls-verify=false", "--force-compression=false", "--compression-format", "zstd", "--remove-signatures", "imageone", "localhost:5000/image"})
   122  		push.WaitWithDefaultTimeout()
   123  		Expect(push).Should(ExitCleanly())
   124  
   125  		skopeo = SystemExec("skopeo", skopeoInspect)
   126  		skopeo.WaitWithDefaultTimeout()
   127  		Expect(skopeo).Should(ExitCleanly())
   128  		output = skopeo.OutputToString()
   129  		// Although `--compression-format` is `zstd` but still no traces of `zstd` should be in image
   130  		// since blobs must be reused from last `gzip` image.
   131  		Expect(output).ToNot(ContainSubstring("zstd"))
   132  
   133  		push = podmanTest.Podman([]string{"push", "-q", "--tls-verify=false", "--compression-format", "zstd", "--force-compression", "--remove-signatures", "imageone", "localhost:5000/image"})
   134  		push.WaitWithDefaultTimeout()
   135  		Expect(push).Should(ExitCleanly())
   136  
   137  		skopeo = SystemExec("skopeo", skopeoInspect)
   138  		skopeo.WaitWithDefaultTimeout()
   139  		Expect(skopeo).Should(ExitCleanly())
   140  		output = skopeo.OutputToString()
   141  		// Should contain `zstd` layer, substring `zstd` is enough to confirm in skopeo inspect output that `zstd` layer is present.
   142  		Expect(output).To(ContainSubstring("zstd"))
   143  	})
   144  
   145  	It("podman push to local registry", func() {
   146  		if podmanTest.Host.Arch == "ppc64le" {
   147  			Skip("No registry image for ppc64le")
   148  		}
   149  		if isRootless() {
   150  			err := podmanTest.RestoreArtifact(REGISTRY_IMAGE)
   151  			Expect(err).ToNot(HaveOccurred())
   152  		}
   153  		lock := GetPortLock("5000")
   154  		defer lock.Unlock()
   155  		session := podmanTest.Podman([]string{"run", "-d", "--name", "registry", "-p", "5000:5000", REGISTRY_IMAGE, "/entrypoint.sh", "/etc/docker/registry/config.yml"})
   156  		session.WaitWithDefaultTimeout()
   157  		Expect(session).Should(ExitCleanly())
   158  
   159  		if !WaitContainerReady(podmanTest, "registry", "listening on", 20, 1) {
   160  			Skip("Cannot start docker registry.")
   161  		}
   162  
   163  		push := podmanTest.Podman([]string{"push", "-q", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:5000/my-alpine"})
   164  		push.WaitWithDefaultTimeout()
   165  		Expect(push).Should(ExitCleanly())
   166  
   167  		push = podmanTest.Podman([]string{"push", "--compression-format=gzip", "--compression-level=1", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:5000/my-alpine"})
   168  		push.WaitWithDefaultTimeout()
   169  		Expect(push).Should(Exit(0))
   170  		output := push.ErrorToString()
   171  		Expect(output).To(ContainSubstring("Copying blob "))
   172  		Expect(output).To(ContainSubstring("Copying config "))
   173  		Expect(output).To(ContainSubstring("Writing manifest to image destination"))
   174  
   175  		bitSize := 1024
   176  		keyFileName := filepath.Join(podmanTest.TempDir, "key")
   177  		publicKeyFileName, _, err := WriteRSAKeyPair(keyFileName, bitSize)
   178  		Expect(err).ToNot(HaveOccurred())
   179  
   180  		if !IsRemote() { // Remote does not support --encryption-key
   181  			push = podmanTest.Podman([]string{"push", "-q", "--encryption-key", "jwe:" + publicKeyFileName, "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:5000/my-alpine"})
   182  			push.WaitWithDefaultTimeout()
   183  			Expect(push).Should(ExitCleanly())
   184  		}
   185  
   186  		// Test --digestfile option
   187  		digestFile := filepath.Join(podmanTest.TempDir, "digestfile.txt")
   188  		push2 := podmanTest.Podman([]string{"push", "-q", "--tls-verify=false", "--digestfile=" + digestFile, "--remove-signatures", ALPINE, "localhost:5000/my-alpine"})
   189  		push2.WaitWithDefaultTimeout()
   190  		fi, err := os.Lstat(digestFile)
   191  		Expect(err).ToNot(HaveOccurred())
   192  		Expect(fi.Name()).To(Equal("digestfile.txt"))
   193  		Expect(push2).Should(ExitCleanly())
   194  
   195  		if !IsRemote() { // Remote does not support signing
   196  			By("pushing and pulling with --sign-by-sigstore-private-key")
   197  			// Ideally, this should set SystemContext.RegistriesDirPath, but Podman currently doesn’t
   198  			// expose that as an option. So, for now, modify /etc/directly, and skip testing sigstore if
   199  			// we don’t have permission to do so.
   200  			systemRegistriesDAddition := "/etc/containers/registries.d/podman-test-only-temporary-addition.yaml"
   201  			cmd := exec.Command("cp", "testdata/sigstore-registries.d-fragment.yaml", systemRegistriesDAddition)
   202  			output, err := cmd.CombinedOutput()
   203  			if err != nil {
   204  				GinkgoWriter.Printf("Skipping sigstore tests because /etc/containers/registries.d isn’t writable: %s\n", string(output))
   205  			} else {
   206  				defer func() {
   207  					err := os.Remove(systemRegistriesDAddition)
   208  					Expect(err).ToNot(HaveOccurred())
   209  				}()
   210  				// Generate a signature verification policy file
   211  				policyPath := generatePolicyFile(podmanTest.TempDir)
   212  				defer os.Remove(policyPath)
   213  
   214  				// Verify that the policy rejects unsigned images
   215  				push := podmanTest.Podman([]string{"push", "-q", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:5000/sigstore-signed"})
   216  				push.WaitWithDefaultTimeout()
   217  				Expect(push).Should(ExitCleanly())
   218  
   219  				pull := podmanTest.Podman([]string{"pull", "-q", "--tls-verify=false", "--signature-policy", policyPath, "localhost:5000/sigstore-signed"})
   220  				pull.WaitWithDefaultTimeout()
   221  				Expect(pull).To(ExitWithError())
   222  				Expect(pull.ErrorToString()).To(ContainSubstring("A signature was required, but no signature exists"))
   223  
   224  				// Sign an image, and verify it is accepted.
   225  				push = podmanTest.Podman([]string{"push", "-q", "--tls-verify=false", "--remove-signatures", "--sign-by-sigstore-private-key", "testdata/sigstore-key.key", "--sign-passphrase-file", "testdata/sigstore-key.key.pass", ALPINE, "localhost:5000/sigstore-signed"})
   226  				push.WaitWithDefaultTimeout()
   227  				Expect(push).Should(ExitCleanly())
   228  
   229  				pull = podmanTest.Podman([]string{"pull", "-q", "--tls-verify=false", "--signature-policy", policyPath, "localhost:5000/sigstore-signed"})
   230  				pull.WaitWithDefaultTimeout()
   231  				Expect(pull).Should(ExitCleanly())
   232  
   233  				By("pushing and pulling with --sign-by-sigstore")
   234  				// Verify that the policy rejects unsigned images
   235  				push = podmanTest.Podman([]string{"push", "-q", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:5000/sigstore-signed-params"})
   236  				push.WaitWithDefaultTimeout()
   237  				Expect(push).Should(ExitCleanly())
   238  
   239  				pull = podmanTest.Podman([]string{"pull", "-q", "--tls-verify=false", "--signature-policy", policyPath, "localhost:5000/sigstore-signed-params"})
   240  				pull.WaitWithDefaultTimeout()
   241  				Expect(pull).To(ExitWithError())
   242  				Expect(pull.ErrorToString()).To(ContainSubstring("A signature was required, but no signature exists"))
   243  
   244  				// Sign an image, and verify it is accepted.
   245  				push = podmanTest.Podman([]string{"push", "-q", "--tls-verify=false", "--remove-signatures", "--sign-by-sigstore", "testdata/sigstore-signing-params.yaml", ALPINE, "localhost:5000/sigstore-signed-params"})
   246  				push.WaitWithDefaultTimeout()
   247  				Expect(push).Should(ExitCleanly())
   248  
   249  				pull = podmanTest.Podman([]string{"pull", "-q", "--tls-verify=false", "--signature-policy", policyPath, "localhost:5000/sigstore-signed-params"})
   250  				pull.WaitWithDefaultTimeout()
   251  				Expect(pull).Should(ExitCleanly())
   252  			}
   253  		}
   254  	})
   255  
   256  	It("podman push from local storage with nothing-allowed signature policy", func() {
   257  		SkipIfRemote("Remote push does not support dir transport")
   258  		denyAllPolicy := filepath.Join(INTEGRATION_ROOT, "test/deny.json")
   259  
   260  		inspect := podmanTest.Podman([]string{"inspect", "--format={{.ID}}", ALPINE})
   261  		inspect.WaitWithDefaultTimeout()
   262  		Expect(inspect).Should(ExitCleanly())
   263  		imageID := inspect.OutputToString()
   264  
   265  		// FIXME FIXME
   266  		push := podmanTest.Podman([]string{"push", "--signature-policy", denyAllPolicy, "-q", imageID, "dir:" + filepath.Join(podmanTest.TempDir, imageID)})
   267  		push.WaitWithDefaultTimeout()
   268  		Expect(push).Should(ExitCleanly())
   269  	})
   270  
   271  	It("podman push to local registry with authorization", func() {
   272  		SkipIfRootless("/etc/containers/certs.d not writable")
   273  		if podmanTest.Host.Arch == "ppc64le" {
   274  			Skip("No registry image for ppc64le")
   275  		}
   276  		authPath := filepath.Join(podmanTest.TempDir, "auth")
   277  		err = os.Mkdir(authPath, os.ModePerm)
   278  		Expect(err).ToNot(HaveOccurred())
   279  		err = os.MkdirAll("/etc/containers/certs.d/localhost:5000", os.ModePerm)
   280  		Expect(err).ToNot(HaveOccurred())
   281  		defer os.RemoveAll("/etc/containers/certs.d/localhost:5000")
   282  
   283  		cwd, _ := os.Getwd()
   284  		certPath := filepath.Join(cwd, "../", "certs")
   285  
   286  		lock := GetPortLock("5000")
   287  		defer lock.Unlock()
   288  		htpasswd := SystemExec("htpasswd", []string{"-Bbn", "podmantest", "test"})
   289  		htpasswd.WaitWithDefaultTimeout()
   290  		Expect(htpasswd).Should(ExitCleanly())
   291  
   292  		f, err := os.Create(filepath.Join(authPath, "htpasswd"))
   293  		Expect(err).ToNot(HaveOccurred())
   294  		defer f.Close()
   295  
   296  		_, err = f.WriteString(htpasswd.OutputToString())
   297  		Expect(err).ToNot(HaveOccurred())
   298  		err = f.Sync()
   299  		Expect(err).ToNot(HaveOccurred())
   300  
   301  		session := podmanTest.Podman([]string{"run", "-d", "-p", "5000:5000", "--name", "registry", "-v",
   302  			strings.Join([]string{authPath, "/auth", "z"}, ":"), "-e", "REGISTRY_AUTH=htpasswd", "-e",
   303  			"REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm", "-e", "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd",
   304  			"-v", strings.Join([]string{certPath, "/certs", "z"}, ":"), "-e", "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt",
   305  			"-e", "REGISTRY_HTTP_TLS_KEY=/certs/domain.key", REGISTRY_IMAGE})
   306  		session.WaitWithDefaultTimeout()
   307  		Expect(session).Should(ExitCleanly())
   308  
   309  		Expect(WaitContainerReady(podmanTest, "registry", "listening on", 20, 1)).To(BeTrue(), "registry container ready")
   310  
   311  		push := podmanTest.Podman([]string{"push", "--tls-verify=true", "--format=v2s2", "--creds=podmantest:test", ALPINE, "localhost:5000/tlstest"})
   312  		push.WaitWithDefaultTimeout()
   313  		Expect(push).To(ExitWithError())
   314  		Expect(push.ErrorToString()).To(ContainSubstring("x509: certificate signed by unknown authority"))
   315  
   316  		push = podmanTest.Podman([]string{"push", "--creds=podmantest:test", "--tls-verify=false", ALPINE, "localhost:5000/tlstest"})
   317  		push.WaitWithDefaultTimeout()
   318  		Expect(push).Should(Exit(0))
   319  		Expect(push.ErrorToString()).To(ContainSubstring("Writing manifest to image destination"))
   320  
   321  		setup := SystemExec("cp", []string{filepath.Join(certPath, "domain.crt"), "/etc/containers/certs.d/localhost:5000/ca.crt"})
   322  		Expect(setup).Should(ExitCleanly())
   323  
   324  		push = podmanTest.Podman([]string{"push", "--creds=podmantest:wrongpasswd", ALPINE, "localhost:5000/credstest"})
   325  		push.WaitWithDefaultTimeout()
   326  		Expect(push).To(ExitWithError())
   327  		Expect(push.ErrorToString()).To(ContainSubstring("/credstest: authentication required"))
   328  
   329  		if !IsRemote() {
   330  			// remote does not support --cert-dir
   331  			push = podmanTest.Podman([]string{"push", "--tls-verify=true", "--creds=podmantest:test", "--cert-dir=fakedir", ALPINE, "localhost:5000/certdirtest"})
   332  			push.WaitWithDefaultTimeout()
   333  			Expect(push).To(ExitWithError())
   334  			Expect(push.ErrorToString()).To(ContainSubstring("x509: certificate signed by unknown authority"))
   335  		}
   336  
   337  		push = podmanTest.Podman([]string{"push", "--creds=podmantest:test", ALPINE, "localhost:5000/defaultflags"})
   338  		push.WaitWithDefaultTimeout()
   339  		Expect(push).Should(Exit(0))
   340  		Expect(push.ErrorToString()).To(ContainSubstring("Writing manifest to image destination"))
   341  
   342  		// create and push manifest
   343  		session = podmanTest.Podman([]string{"manifest", "create", "localhost:5000/manifesttest"})
   344  		session.WaitWithDefaultTimeout()
   345  		Expect(session).Should(ExitCleanly())
   346  
   347  		session = podmanTest.Podman([]string{"manifest", "push", "--creds=podmantest:test", "--tls-verify=false", "--all", "localhost:5000/manifesttest"})
   348  		session.WaitWithDefaultTimeout()
   349  		Expect(session).Should(Exit(0))
   350  		Expect(session.ErrorToString()).To(ContainSubstring("Writing manifest list to image destination"))
   351  	})
   352  
   353  	It("podman push and encrypt to oci", func() {
   354  		SkipIfRemote("Remote push neither supports oci transport, nor encryption")
   355  
   356  		bbdir := filepath.Join(podmanTest.TempDir, "busybox-oci")
   357  
   358  		bitSize := 1024
   359  		keyFileName := filepath.Join(podmanTest.TempDir, "key")
   360  		publicKeyFileName, _, err := WriteRSAKeyPair(keyFileName, bitSize)
   361  		Expect(err).ToNot(HaveOccurred())
   362  
   363  		session := podmanTest.Podman([]string{"push", "-q", "--encryption-key", "jwe:" + publicKeyFileName, ALPINE, fmt.Sprintf("oci:%s", bbdir)})
   364  		session.WaitWithDefaultTimeout()
   365  		Expect(session).Should(ExitCleanly())
   366  
   367  		session = podmanTest.Podman([]string{"rmi", ALPINE})
   368  		session.WaitWithDefaultTimeout()
   369  		Expect(session).Should(ExitCleanly())
   370  	})
   371  
   372  	It("podman push to docker-archive", func() {
   373  		SkipIfRemote("Remote push does not support docker-archive transport")
   374  		tarfn := filepath.Join(podmanTest.TempDir, "alp.tar")
   375  		session := podmanTest.Podman([]string{"push", "-q", ALPINE,
   376  			fmt.Sprintf("docker-archive:%s:latest", tarfn)})
   377  		session.WaitWithDefaultTimeout()
   378  		Expect(session).Should(ExitCleanly())
   379  	})
   380  
   381  	It("podman push to docker daemon", func() {
   382  		SkipIfRemote("Remote push does not support docker-daemon transport")
   383  		SkipIfRootless("rootless user has no permission to use default docker.sock")
   384  		setup := SystemExec("bash", []string{"-c", "systemctl status docker 2>&1"})
   385  
   386  		if setup.LineInOutputContains("Active: inactive") {
   387  			setup = SystemExec("systemctl", []string{"start", "docker"})
   388  			Expect(setup).Should(ExitCleanly())
   389  			defer func() {
   390  				stop := SystemExec("systemctl", []string{"stop", "docker"})
   391  				Expect(stop).Should(Exit(0))
   392  			}()
   393  		} else if setup.ExitCode() != 0 {
   394  			Skip("Docker is not available")
   395  		}
   396  
   397  		session := podmanTest.Podman([]string{"push", "-q", ALPINE, "docker-daemon:alpine:podmantest"})
   398  		session.WaitWithDefaultTimeout()
   399  		Expect(session).Should(ExitCleanly())
   400  
   401  		check := SystemExec("docker", []string{"images", "--format", "{{.Repository}}:{{.Tag}}"})
   402  		Expect(check).Should(ExitCleanly())
   403  		Expect(check.OutputToString()).To(ContainSubstring("alpine:podmantest"))
   404  
   405  		clean := SystemExec("docker", []string{"rmi", "alpine:podmantest"})
   406  		Expect(clean).Should(ExitCleanly())
   407  	})
   408  
   409  	It("podman push to oci-archive", func() {
   410  		SkipIfRemote("Remote push does not support oci-archive transport")
   411  		tarfn := filepath.Join(podmanTest.TempDir, "alp.tar")
   412  		session := podmanTest.Podman([]string{"push", "-q", ALPINE,
   413  			fmt.Sprintf("oci-archive:%s:latest", tarfn)})
   414  		session.WaitWithDefaultTimeout()
   415  		Expect(session).Should(ExitCleanly())
   416  	})
   417  
   418  	It("podman push to docker-archive no reference", func() {
   419  		SkipIfRemote("Remote push does not support docker-archive transport")
   420  		tarfn := filepath.Join(podmanTest.TempDir, "alp.tar")
   421  		session := podmanTest.Podman([]string{"push", "-q", ALPINE,
   422  			fmt.Sprintf("docker-archive:%s", tarfn)})
   423  		session.WaitWithDefaultTimeout()
   424  		Expect(session).Should(ExitCleanly())
   425  	})
   426  
   427  	It("podman push to oci-archive no reference", func() {
   428  		SkipIfRemote("Remote push does not support oci-archive transport")
   429  		ociarc := filepath.Join(podmanTest.TempDir, "alp-oci")
   430  		session := podmanTest.Podman([]string{"push", "-q", ALPINE,
   431  			fmt.Sprintf("oci-archive:%s", ociarc)})
   432  
   433  		session.WaitWithDefaultTimeout()
   434  		Expect(session).Should(ExitCleanly())
   435  	})
   436  
   437  })