mirror of https://github.com/containers/image.git
Add @sourceIndex syntax to oci/layout
Images in the index can now be referenced via the @sourceIndex syntax. Signed-off-by: Miloslav Trmač <mitr@redhat.com> Signed-off-by: Valentin Rothberg <vrothberg@redhat.com>
This commit is contained in:
parent
16e3aee517
commit
71e849a6b1
|
|
@ -71,13 +71,15 @@ An image stored in the docker daemon's internal storage.
|
|||
The image must be specified as a _docker-reference_ or in an alternative _algo_`:`_digest_ format when being used as an image source.
|
||||
The _algo_`:`_digest_ refers to the image ID reported by docker-inspect(1).
|
||||
|
||||
### **oci:**_path_[`:`_reference_]
|
||||
### **oci:**_path_[`:`{_reference_|`@`_source-index_}]
|
||||
|
||||
An image in a directory structure compliant with the "Open Container Image Layout Specification" at _path_.
|
||||
|
||||
The _path_ value terminates at the first `:` character; any further `:` characters are not separators, but a part of _reference_.
|
||||
The _reference_ is used to set, or match, the `org.opencontainers.image.ref.name` annotation in the top-level index.
|
||||
If _reference_ is not specified when reading an image, the directory must contain exactly one image.
|
||||
For reading images, @_source-index_ is a zero-based index in manifest (to access untagged images).
|
||||
If neither reference nor @_source_index is specified when reading an image, the path must contain exactly one image.
|
||||
|
||||
### **oci-archive:**_path_[`:`_reference_]
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
|
|
@ -119,3 +120,31 @@ func validateScopeNonWindows(scope string) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseOCIReferenceName parses the image from the oci reference.
|
||||
func parseOCIReferenceName(image string) (img string, index int, err error) {
|
||||
index = -1
|
||||
if strings.HasPrefix(image, "@") {
|
||||
idx, err := strconv.Atoi(image[1:])
|
||||
if err != nil {
|
||||
return "", index, fmt.Errorf("Invalid source index @%s: not an integer: %w", image[1:], err)
|
||||
}
|
||||
if idx < 0 {
|
||||
return "", index, fmt.Errorf("Invalid source index @%d: must not be negative", idx)
|
||||
}
|
||||
index = idx
|
||||
} else {
|
||||
img = image
|
||||
}
|
||||
return img, index, nil
|
||||
}
|
||||
|
||||
// ParseReferenceIntoElements splits the oci reference into location, image name and source index if exists
|
||||
func ParseReferenceIntoElements(reference string) (string, string, int, error) {
|
||||
dir, image := SplitPathAndImage(reference)
|
||||
image, index, err := parseOCIReferenceName(image)
|
||||
if err != nil {
|
||||
return "", "", -1, err
|
||||
}
|
||||
return dir, image, index, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,12 @@ type testDataScopeValidation struct {
|
|||
errMessage string
|
||||
}
|
||||
|
||||
type testOCIReference struct {
|
||||
ref string
|
||||
image string
|
||||
index int
|
||||
}
|
||||
|
||||
func TestSplitReferenceIntoDirAndImageWindows(t *testing.T) {
|
||||
tests := []testDataSplitReference{
|
||||
{`C:\foo\bar:busybox:latest`, `C:\foo\bar`, "busybox:latest"},
|
||||
|
|
@ -61,3 +67,25 @@ func TestValidateScopeWindows(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseOCIReferenceName(t *testing.T) {
|
||||
validTests := []testOCIReference{
|
||||
{"@0", "", 0},
|
||||
{"notlatest@1", "notlatest@1", -1},
|
||||
}
|
||||
for _, test := range validTests {
|
||||
img, idx, err := parseOCIReferenceName(test.ref)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, img, test.image)
|
||||
assert.Equal(t, idx, test.index)
|
||||
}
|
||||
|
||||
invalidTests := []string{
|
||||
"@-5",
|
||||
"@invalidIndex",
|
||||
}
|
||||
for _, test := range invalidTests {
|
||||
_, _, err := parseOCIReferenceName(test)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,9 @@ type ociImageDestination struct {
|
|||
|
||||
// newImageDestination returns an ImageDestination for writing to an existing directory.
|
||||
func newImageDestination(sys *types.SystemContext, ref ociReference) (private.ImageDestination, error) {
|
||||
if ref.sourceIndex != -1 {
|
||||
return nil, fmt.Errorf("Destination reference must not contain a manifest index @%d", ref.sourceIndex)
|
||||
}
|
||||
var index *imgspecv1.Index
|
||||
if indexExists(ref) {
|
||||
var err error
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ func TestPutBlobDigestFailure(t *testing.T) {
|
|||
const digestErrorString = "Simulated digest error"
|
||||
const blobDigest = "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f"
|
||||
|
||||
ref, _ := refToTempOCI(t)
|
||||
ref, _ := refToTempOCI(t, false)
|
||||
dirRef, ok := ref.(ociReference)
|
||||
require.True(t, ok)
|
||||
blobPath, err := dirRef.blobPath(blobDigest, "")
|
||||
|
|
@ -71,7 +71,7 @@ func TestPutBlobDigestFailure(t *testing.T) {
|
|||
|
||||
// TestPutManifestAppendsToExistingManifest tests that new manifests are getting added to existing index.
|
||||
func TestPutManifestAppendsToExistingManifest(t *testing.T) {
|
||||
ref, tmpDir := refToTempOCI(t)
|
||||
ref, tmpDir := refToTempOCI(t, false)
|
||||
|
||||
ociRef, ok := ref.(ociReference)
|
||||
require.True(t, ok)
|
||||
|
|
@ -94,7 +94,7 @@ func TestPutManifestAppendsToExistingManifest(t *testing.T) {
|
|||
|
||||
// TestPutManifestTwice tests that existing manifest gets updated and not appended.
|
||||
func TestPutManifestTwice(t *testing.T) {
|
||||
ref, tmpDir := refToTempOCI(t)
|
||||
ref, tmpDir := refToTempOCI(t, false)
|
||||
|
||||
ociRef, ok := ref.(ociReference)
|
||||
require.True(t, ok)
|
||||
|
|
@ -109,7 +109,7 @@ func TestPutManifestTwice(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestPutTwoDifferentTags(t *testing.T) {
|
||||
ref, tmpDir := refToTempOCI(t)
|
||||
ref, tmpDir := refToTempOCI(t, false)
|
||||
|
||||
ociRef, ok := ref.(ociReference)
|
||||
require.True(t, ok)
|
||||
|
|
|
|||
|
|
@ -61,22 +61,31 @@ type ociReference struct {
|
|||
// (But in general, we make no attempt to be completely safe against concurrent hostile filesystem modifications.)
|
||||
dir string // As specified by the user. May be relative, contain symlinks, etc.
|
||||
resolvedDir string // Absolute path with no symlinks, at least at the time of its creation. Primarily used for policy namespaces.
|
||||
// If image=="", it means the "only image" in the index.json is used in the case it is a source
|
||||
// for destinations, the image name annotation "image.ref.name" is not added to the index.json
|
||||
// If image=="" && sourceIndex==-1, it means the "only image" in the index.json is used in the case it is a source
|
||||
// for destinations, the image name annotation "image.ref.name" is not added to the index.json.
|
||||
//
|
||||
// Must not be set if sourceIndex is set (the value is not -1).
|
||||
image string
|
||||
// If not -1, a zero-based index of an image in the manifest index. Valid only for sources.
|
||||
// Must not be set if image is set.
|
||||
sourceIndex int
|
||||
}
|
||||
|
||||
// ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an OCI ImageReference.
|
||||
func ParseReference(reference string) (types.ImageReference, error) {
|
||||
dir, image := internal.SplitPathAndImage(reference)
|
||||
return NewReference(dir, image)
|
||||
dir, image, index, err := internal.ParseReferenceIntoElements(reference)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return newReference(dir, image, index)
|
||||
}
|
||||
|
||||
// NewReference returns an OCI reference for a directory and a image.
|
||||
// newReference returns an OCI reference for a directory, and an image name annotation or sourceIndex.
|
||||
//
|
||||
// If sourceIndex==-1, the index will not be valid to point out the source image, only image will be used.
|
||||
// We do not expose an API supplying the resolvedDir; we could, but recomputing it
|
||||
// is generally cheap enough that we prefer being confident about the properties of resolvedDir.
|
||||
func NewReference(dir, image string) (types.ImageReference, error) {
|
||||
func newReference(dir, image string, sourceIndex int) (types.ImageReference, error) {
|
||||
resolved, err := explicitfilepath.ResolvePathToFullyExplicit(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -90,7 +99,26 @@ func NewReference(dir, image string) (types.ImageReference, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return ociReference{dir: dir, resolvedDir: resolved, image: image}, nil
|
||||
if sourceIndex != -1 && sourceIndex < 0 {
|
||||
return nil, fmt.Errorf("Invalid oci: layout reference: index @%d must not be negative", sourceIndex)
|
||||
}
|
||||
if sourceIndex != -1 && image != "" {
|
||||
return nil, fmt.Errorf("Invalid oci: layout reference: cannot use both an image %s and a source index @%d", image, sourceIndex)
|
||||
}
|
||||
return ociReference{dir: dir, resolvedDir: resolved, image: image, sourceIndex: sourceIndex}, nil
|
||||
}
|
||||
|
||||
// NewIndexReference returns an OCI reference for a path and a zero-based source manifest index.
|
||||
func NewIndexReference(dir string, sourceIndex int) (types.ImageReference, error) {
|
||||
return newReference(dir, "", sourceIndex)
|
||||
}
|
||||
|
||||
// NewReference returns an OCI reference for a directory and a image.
|
||||
//
|
||||
// We do not expose an API supplying the resolvedDir; we could, but recomputing it
|
||||
// is generally cheap enough that we prefer being confident about the properties of resolvedDir.
|
||||
func NewReference(dir, image string) (types.ImageReference, error) {
|
||||
return newReference(dir, image, -1)
|
||||
}
|
||||
|
||||
func (ref ociReference) Transport() types.ImageTransport {
|
||||
|
|
@ -103,7 +131,10 @@ func (ref ociReference) Transport() types.ImageTransport {
|
|||
// e.g. default attribute values omitted by the user may be filled in the return value, or vice versa.
|
||||
// WARNING: Do not use the return value in the UI to describe an image, it does not contain the Transport().Name() prefix.
|
||||
func (ref ociReference) StringWithinTransport() string {
|
||||
return fmt.Sprintf("%s:%s", ref.dir, ref.image)
|
||||
if ref.sourceIndex == -1 {
|
||||
return fmt.Sprintf("%s:%s", ref.dir, ref.image)
|
||||
}
|
||||
return fmt.Sprintf("%s:@%d", ref.dir, ref.sourceIndex)
|
||||
}
|
||||
|
||||
// DockerReference returns a Docker reference associated with this reference
|
||||
|
|
@ -187,14 +218,18 @@ func (ref ociReference) getManifestDescriptor() (imgspecv1.Descriptor, int, erro
|
|||
return imgspecv1.Descriptor{}, -1, err
|
||||
}
|
||||
|
||||
if ref.image == "" {
|
||||
// return manifest if only one image is in the oci directory
|
||||
if len(index.Manifests) != 1 {
|
||||
// ask user to choose image when more than one image in the oci directory
|
||||
return imgspecv1.Descriptor{}, -1, ErrMoreThanOneImage
|
||||
switch {
|
||||
case ref.image != "" && ref.sourceIndex != -1:
|
||||
return imgspecv1.Descriptor{}, -1, fmt.Errorf("Internal error: Cannot have both ref %s and source index @%d",
|
||||
ref.image, ref.sourceIndex)
|
||||
|
||||
case ref.sourceIndex != -1:
|
||||
if ref.sourceIndex >= len(index.Manifests) {
|
||||
return imgspecv1.Descriptor{}, -1, fmt.Errorf("index %d is too large, only %d entries available", ref.sourceIndex, len(index.Manifests))
|
||||
}
|
||||
return index.Manifests[0], 0, nil
|
||||
} else {
|
||||
return index.Manifests[ref.sourceIndex], ref.sourceIndex, nil
|
||||
|
||||
case ref.image != "":
|
||||
// if image specified, look through all manifests for a match
|
||||
var unsupportedMIMETypes []string
|
||||
for i, md := range index.Manifests {
|
||||
|
|
@ -208,8 +243,16 @@ func (ref ociReference) getManifestDescriptor() (imgspecv1.Descriptor, int, erro
|
|||
if len(unsupportedMIMETypes) != 0 {
|
||||
return imgspecv1.Descriptor{}, -1, fmt.Errorf("reference %q matches unsupported manifest MIME types %q", ref.image, unsupportedMIMETypes)
|
||||
}
|
||||
return imgspecv1.Descriptor{}, -1, ImageNotFoundError{ref}
|
||||
|
||||
default:
|
||||
// return manifest if only one image is in the oci directory
|
||||
if len(index.Manifests) != 1 {
|
||||
// ask user to choose image when more than one image in the oci directory
|
||||
return imgspecv1.Descriptor{}, -1, ErrMoreThanOneImage
|
||||
}
|
||||
return index.Manifests[0], 0, nil
|
||||
}
|
||||
return imgspecv1.Descriptor{}, -1, ImageNotFoundError{ref}
|
||||
}
|
||||
|
||||
// LoadManifestDescriptor loads the manifest descriptor to be used to retrieve the image name
|
||||
|
|
|
|||
|
|
@ -101,6 +101,26 @@ func TestGetManifestDescriptor(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
ref, err := NewIndexReference("fixtures/two_images_manifest", 0)
|
||||
assert.NoError(t, err)
|
||||
res, err := LoadManifestDescriptor(ref)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, imgspecv1.Descriptor{
|
||||
MediaType: "application/vnd.oci.image.manifest.v1+json",
|
||||
Digest: "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f",
|
||||
Size: 7143,
|
||||
Platform: &imgspecv1.Platform{
|
||||
Architecture: "ppc64le",
|
||||
OS: "linux",
|
||||
}}, res)
|
||||
|
||||
// Out of bounds
|
||||
ref, err = NewIndexReference("fixtures/two_images_manifest", 6)
|
||||
assert.NoError(t, err)
|
||||
_, err = LoadManifestDescriptor(ref)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "index 6 is too large, only 2 entries available", err.Error())
|
||||
}
|
||||
|
||||
func TestTransportName(t *testing.T) {
|
||||
|
|
@ -148,11 +168,17 @@ func testParseReference(t *testing.T, fn func(string) (types.ImageReference, err
|
|||
"relativepath",
|
||||
tmpDir + "/thisdoesnotexist",
|
||||
} {
|
||||
for _, image := range []struct{ suffix, image string }{
|
||||
{":notlatest:image", "notlatest:image"},
|
||||
{":latestimage", "latestimage"},
|
||||
{":", ""},
|
||||
{"", ""},
|
||||
for _, image := range []struct {
|
||||
suffix, image string
|
||||
sourceIndex int
|
||||
}{
|
||||
{":notlatest:image", "notlatest:image", -1},
|
||||
{":latestimage", "latestimage", -1},
|
||||
{":", "", -1},
|
||||
{"", "", -1},
|
||||
{":@0", "", 0},
|
||||
{":@10", "", 10},
|
||||
{":@999999", "", 999999},
|
||||
} {
|
||||
input := path + image.suffix
|
||||
ref, err := fn(input)
|
||||
|
|
@ -161,11 +187,15 @@ func testParseReference(t *testing.T, fn func(string) (types.ImageReference, err
|
|||
require.True(t, ok)
|
||||
assert.Equal(t, path, ociRef.dir, input)
|
||||
assert.Equal(t, image.image, ociRef.image, input)
|
||||
assert.Equal(t, image.sourceIndex, ociRef.sourceIndex, input)
|
||||
}
|
||||
}
|
||||
|
||||
_, err := fn(tmpDir + ":invalid'image!value@")
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = fn(tmpDir + ":@-3")
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestNewReference(t *testing.T) {
|
||||
|
|
@ -182,6 +212,7 @@ func TestNewReference(t *testing.T) {
|
|||
require.True(t, ok)
|
||||
assert.Equal(t, tmpDir, ociRef.dir)
|
||||
assert.Equal(t, imageValue, ociRef.image)
|
||||
assert.Equal(t, -1, ociRef.sourceIndex)
|
||||
|
||||
ref, err = NewReference(tmpDir, noImageValue)
|
||||
require.NoError(t, err)
|
||||
|
|
@ -189,6 +220,7 @@ func TestNewReference(t *testing.T) {
|
|||
require.True(t, ok)
|
||||
assert.Equal(t, tmpDir, ociRef.dir)
|
||||
assert.Equal(t, noImageValue, ociRef.image)
|
||||
assert.Equal(t, -1, ociRef.sourceIndex)
|
||||
|
||||
_, err = NewReference(tmpDir+"/thisparentdoesnotexist/something", imageValue)
|
||||
assert.Error(t, err)
|
||||
|
|
@ -198,10 +230,50 @@ func TestNewReference(t *testing.T) {
|
|||
|
||||
_, err = NewReference(tmpDir+"/has:colon", imageValue)
|
||||
assert.Error(t, err)
|
||||
|
||||
// Test private newReference
|
||||
_, err = newReference(tmpDir, imageValue, 1)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestNewIndexReference(t *testing.T) {
|
||||
const imageValue = "imageValue"
|
||||
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
ref, err := NewIndexReference(tmpDir, 10)
|
||||
require.NoError(t, err)
|
||||
ociRef, ok := ref.(ociReference)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, tmpDir, ociRef.dir)
|
||||
assert.Equal(t, "", ociRef.image)
|
||||
assert.Equal(t, 10, ociRef.sourceIndex)
|
||||
|
||||
ref, err = NewIndexReference(tmpDir, 9999)
|
||||
require.NoError(t, err)
|
||||
ociRef, ok = ref.(ociReference)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, tmpDir, ociRef.dir)
|
||||
assert.Equal(t, "", ociRef.image)
|
||||
assert.Equal(t, 9999, ociRef.sourceIndex)
|
||||
|
||||
_, err = NewIndexReference(tmpDir+"/thisparentdoesnotexist/something", 10)
|
||||
assert.Error(t, err)
|
||||
|
||||
// sourceIndex cannot be less than -1
|
||||
_, err = NewIndexReference(tmpDir, -3)
|
||||
assert.Error(t, err)
|
||||
|
||||
_, err = NewIndexReference(tmpDir+"/has:colon", 99)
|
||||
assert.Error(t, err)
|
||||
|
||||
// Test private newReference
|
||||
_, err = newReference(tmpDir, imageValue, 1)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
// refToTempOCI creates a temporary directory and returns an reference to it.
|
||||
func refToTempOCI(t *testing.T) (types.ImageReference, string) {
|
||||
func refToTempOCI(t *testing.T, sourceIndex bool) (types.ImageReference, string) {
|
||||
tmpDir := t.TempDir()
|
||||
m := `{
|
||||
"schemaVersion": 2,
|
||||
|
|
@ -221,15 +293,39 @@ func refToTempOCI(t *testing.T) (types.ImageReference, string) {
|
|||
]
|
||||
}
|
||||
`
|
||||
if sourceIndex {
|
||||
m = `{
|
||||
"schemaVersion": 2,
|
||||
"manifests": [
|
||||
{
|
||||
"mediaType": "application/vnd.oci.image.manifest.v1+json",
|
||||
"size": 7143,
|
||||
"digest": "sha256:e692418e4cbaf90ca69d05a66403747baa33ee08806650b51fab815ad7fc331f",
|
||||
"platform": {
|
||||
"architecture": "ppc64le",
|
||||
"os": "linux"
|
||||
},
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
}
|
||||
|
||||
err := os.WriteFile(filepath.Join(tmpDir, "index.json"), []byte(m), 0644)
|
||||
require.NoError(t, err)
|
||||
ref, err := NewReference(tmpDir, "imageValue")
|
||||
require.NoError(t, err)
|
||||
var ref types.ImageReference
|
||||
if sourceIndex {
|
||||
ref, err = NewIndexReference(tmpDir, 1)
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
ref, err = NewReference(tmpDir, "imageValue")
|
||||
require.NoError(t, err)
|
||||
}
|
||||
return ref, tmpDir
|
||||
}
|
||||
|
||||
func TestReferenceTransport(t *testing.T) {
|
||||
ref, _ := refToTempOCI(t)
|
||||
ref, _ := refToTempOCI(t, false)
|
||||
assert.Equal(t, Transport, ref.Transport())
|
||||
}
|
||||
|
||||
|
|
@ -238,7 +334,8 @@ func TestReferenceStringWithinTransport(t *testing.T) {
|
|||
|
||||
for _, c := range []struct{ input, result string }{
|
||||
{"/dir1:notlatest:notlatest", "/dir1:notlatest:notlatest"}, // Explicit image
|
||||
{"/dir3:", "/dir3:"}, // No image
|
||||
{"/dir3:", "/dir3:"}, // No image
|
||||
{"/dir4:@1", "/dir4:@1"}, // Explicit sourceIndex of image
|
||||
} {
|
||||
ref, err := ParseReference(tmpDir + c.input)
|
||||
require.NoError(t, err, c.input)
|
||||
|
|
@ -253,12 +350,12 @@ func TestReferenceStringWithinTransport(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestReferenceDockerReference(t *testing.T) {
|
||||
ref, _ := refToTempOCI(t)
|
||||
ref, _ := refToTempOCI(t, false)
|
||||
assert.Nil(t, ref.DockerReference())
|
||||
}
|
||||
|
||||
func TestReferencePolicyConfigurationIdentity(t *testing.T) {
|
||||
ref, tmpDir := refToTempOCI(t)
|
||||
ref, tmpDir := refToTempOCI(t, false)
|
||||
|
||||
assert.Equal(t, tmpDir, ref.PolicyConfigurationIdentity())
|
||||
// A non-canonical path. Test just one, the various other cases are
|
||||
|
|
@ -267,14 +364,27 @@ func TestReferencePolicyConfigurationIdentity(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
assert.Equal(t, tmpDir, ref.PolicyConfigurationIdentity())
|
||||
|
||||
// Test the sourceIndex case
|
||||
ref, tmpDir = refToTempOCI(t, true)
|
||||
assert.Equal(t, tmpDir, ref.PolicyConfigurationIdentity())
|
||||
// A non-canonical path. Test just one, the various other cases are
|
||||
// tested in explicitfilepath.ResolvePathToFullyExplicit.
|
||||
ref, err = NewIndexReference(tmpDir+"/.", 1)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tmpDir, ref.PolicyConfigurationIdentity())
|
||||
|
||||
// "/" as a corner case.
|
||||
ref, err = NewReference("/", "image3")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "/", ref.PolicyConfigurationIdentity())
|
||||
|
||||
ref, err = NewIndexReference("/", 2)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, "/", ref.PolicyConfigurationIdentity())
|
||||
}
|
||||
|
||||
func TestReferencePolicyConfigurationNamespaces(t *testing.T) {
|
||||
ref, tmpDir := refToTempOCI(t)
|
||||
ref, tmpDir := refToTempOCI(t, false)
|
||||
// We don't really know enough to make a full equality test here.
|
||||
ns := ref.PolicyConfigurationNamespaces()
|
||||
require.NotNil(t, ns)
|
||||
|
|
@ -282,6 +392,15 @@ func TestReferencePolicyConfigurationNamespaces(t *testing.T) {
|
|||
assert.Equal(t, tmpDir, ns[0])
|
||||
assert.Equal(t, filepath.Dir(tmpDir), ns[1])
|
||||
|
||||
// Test the sourceIndex case
|
||||
ref, tmpDir = refToTempOCI(t, true)
|
||||
// We don't really know enough to make a full equality test here.
|
||||
ns = ref.PolicyConfigurationNamespaces()
|
||||
require.NotNil(t, ns)
|
||||
assert.True(t, len(ns) >= 2)
|
||||
assert.Equal(t, tmpDir, ns[0])
|
||||
assert.Equal(t, filepath.Dir(tmpDir), ns[1])
|
||||
|
||||
// Test with a known path which should exist. Test just one non-canonical
|
||||
// path, the various other cases are tested in explicitfilepath.ResolvePathToFullyExplicit.
|
||||
//
|
||||
|
|
@ -302,37 +421,41 @@ func TestReferencePolicyConfigurationNamespaces(t *testing.T) {
|
|||
ref, err := NewReference("/", "image3")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{}, ref.PolicyConfigurationNamespaces())
|
||||
|
||||
ref, err = NewIndexReference("/", 2)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []string{}, ref.PolicyConfigurationNamespaces())
|
||||
}
|
||||
|
||||
func TestReferenceNewImage(t *testing.T) {
|
||||
ref, _ := refToTempOCI(t)
|
||||
ref, _ := refToTempOCI(t, false)
|
||||
_, err := ref.NewImage(context.Background(), nil)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestReferenceNewImageSource(t *testing.T) {
|
||||
ref, _ := refToTempOCI(t)
|
||||
ref, _ := refToTempOCI(t, false)
|
||||
src, err := ref.NewImageSource(context.Background(), nil)
|
||||
assert.NoError(t, err)
|
||||
defer src.Close()
|
||||
}
|
||||
|
||||
func TestReferenceNewImageDestination(t *testing.T) {
|
||||
ref, _ := refToTempOCI(t)
|
||||
ref, _ := refToTempOCI(t, false)
|
||||
dest, err := ref.NewImageDestination(context.Background(), nil)
|
||||
assert.NoError(t, err)
|
||||
defer dest.Close()
|
||||
}
|
||||
|
||||
func TestReferenceOCILayoutPath(t *testing.T) {
|
||||
ref, tmpDir := refToTempOCI(t)
|
||||
ref, tmpDir := refToTempOCI(t, false)
|
||||
ociRef, ok := ref.(ociReference)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, tmpDir+"/oci-layout", ociRef.ociLayoutPath())
|
||||
}
|
||||
|
||||
func TestReferenceIndexPath(t *testing.T) {
|
||||
ref, tmpDir := refToTempOCI(t)
|
||||
ref, tmpDir := refToTempOCI(t, false)
|
||||
ociRef, ok := ref.(ociReference)
|
||||
require.True(t, ok)
|
||||
assert.Equal(t, tmpDir+"/index.json", ociRef.indexPath())
|
||||
|
|
@ -341,7 +464,7 @@ func TestReferenceIndexPath(t *testing.T) {
|
|||
func TestReferenceBlobPath(t *testing.T) {
|
||||
const hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
|
||||
ref, tmpDir := refToTempOCI(t)
|
||||
ref, tmpDir := refToTempOCI(t, false)
|
||||
ociRef, ok := ref.(ociReference)
|
||||
require.True(t, ok)
|
||||
bp, err := ociRef.blobPath("sha256:"+hex, "")
|
||||
|
|
@ -352,7 +475,7 @@ func TestReferenceBlobPath(t *testing.T) {
|
|||
func TestReferenceSharedBlobPathShared(t *testing.T) {
|
||||
const hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
|
||||
ref, _ := refToTempOCI(t)
|
||||
ref, _ := refToTempOCI(t, false)
|
||||
ociRef, ok := ref.(ociReference)
|
||||
require.True(t, ok)
|
||||
bp, err := ociRef.blobPath("sha256:"+hex, "/external/path")
|
||||
|
|
@ -363,7 +486,7 @@ func TestReferenceSharedBlobPathShared(t *testing.T) {
|
|||
func TestReferenceBlobPathInvalid(t *testing.T) {
|
||||
const hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
||||
|
||||
ref, _ := refToTempOCI(t)
|
||||
ref, _ := refToTempOCI(t, false)
|
||||
ociRef, ok := ref.(ociReference)
|
||||
require.True(t, ok)
|
||||
_, err := ociRef.blobPath(hex, "")
|
||||
|
|
|
|||
Loading…
Reference in New Issue