diff --git a/cmd/skopeo/utils.go b/cmd/skopeo/utils.go index bf277e3a..a14e0a08 100644 --- a/cmd/skopeo/utils.go +++ b/cmd/skopeo/utils.go @@ -419,9 +419,10 @@ func promptForPassphrase(privateKeyFile string, stdin, stdout *os.File) (string, // authentication error, an I/O error etc.) // TODO drive this into containers/image properly func isNotFoundImageError(err error) bool { + var layoutImageNotFoundError ocilayout.ImageNotFoundError return isDockerManifestUnknownError(err) || errors.Is(err, storage.ErrNoSuchImage) || - errors.Is(err, ocilayout.ImageNotFoundError{}) + errors.As(err, &layoutImageNotFoundError) } // isDockerManifestUnknownError is a copy of code from containers/image, diff --git a/integration/copy_test.go b/integration/copy_test.go index 8f7667c4..56f30c5f 100644 --- a/integration/copy_test.go +++ b/integration/copy_test.go @@ -497,6 +497,8 @@ func (s *copySuite) TestCopySimple() { assertSkopeoSucceeds(t, "", "copy", "docker://registry.k8s.io/pause:latest", "oci:"+ociDest+":"+ociImgName) _, err := os.Stat(ociDest) require.NoError(t, err) + // copy exits with status 2 if the image is not found within the container, in some transports. + assertSkopeoFailsWithStatus(t, 2, "copy", "oci:"+ociDest+":thisdoesnotexist", "dir:"+t.TempDir()) // docker v2s2 -> OCI image layout without image name ociDest = "pause-latest-noimage" diff --git a/integration/utils_test.go b/integration/utils_test.go index 326a4507..1d8dfc55 100644 --- a/integration/utils_test.go +++ b/integration/utils_test.go @@ -83,6 +83,16 @@ func assertSkopeoFails(t *testing.T, regexp string, args ...string) { assert.Regexp(t, "(?s)"+regexp, string(out)) // (?s) : '.' will also match newlines } +// assertSkopeoFailsWithStatus runs a skopeo command as if exec.Command().CombinedOutput, +// and verifies that it fails with a specific exit status. +func assertSkopeoFailsWithStatus(t *testing.T, status int, args ...string) { + t.Logf("Running %s %s", skopeoBinary, strings.Join(args, " ")) + _, err := exec.Command(skopeoBinary, args...).CombinedOutput() + var exitErr *exec.ExitError + require.ErrorAs(t, err, &exitErr) + assert.Equal(t, status, exitErr.ExitCode()) +} + // runCommandWithInput runs a command as if exec.Command(), sending it the input to stdin, // and verifies that the exit status is 0, or terminates t on failure. func runCommandWithInput(t *testing.T, input string, name string, args ...string) {