diff --git a/oci/layout/oci_transport.go b/oci/layout/oci_transport.go index f1fc107139..118a863132 100644 --- a/oci/layout/oci_transport.go +++ b/oci/layout/oci_transport.go @@ -36,7 +36,12 @@ func (t ociTransport) ParseReference(reference string) (types.ImageReference, er return ParseReference(reference) } -var refRegexp = regexp.MustCompile(`^([A-Za-z0-9._-]+)+$`) +// See https://github.com/opencontainers/image-spec/blob/master/annotations.md +const separator = `(?:[-._:@+]|--)` +const alphanum = `(?:[A-Za-z0-9]+)` +const component = `(?:` + alphanum + `(?:` + separator + alphanum + `)*)` + +var refRegexp = regexp.MustCompile(`^` + component + `(?:/` + component + `)*$`) // ValidatePolicyConfigurationScope checks that scope is a valid name for a signature.PolicyTransportScopes keys // (i.e. a valid PolicyConfigurationIdentity() or PolicyConfigurationNamespaces() return value). @@ -44,7 +49,7 @@ var refRegexp = regexp.MustCompile(`^([A-Za-z0-9._-]+)+$`) // scope passed to this function will not be "", that value is always allowed. func (t ociTransport) ValidatePolicyConfigurationScope(scope string) error { var dir string - sep := strings.LastIndex(scope, ":") + sep := strings.Index(scope, ":") if sep == -1 { dir = scope } else { @@ -55,10 +60,6 @@ func (t ociTransport) ValidatePolicyConfigurationScope(scope string) error { } } - if strings.Contains(dir, ":") { - return errors.Errorf("Invalid OCI reference %s: path contains a colon", scope) - } - if !strings.HasPrefix(dir, "/") { return errors.Errorf("Invalid scope %s: must be an absolute path", scope) } @@ -91,7 +92,7 @@ type ociReference struct { // ParseReference converts a string, which should not start with the ImageTransport.Name prefix, into an OCI ImageReference. func ParseReference(reference string) (types.ImageReference, error) { var dir, tag string - sep := strings.LastIndex(reference, ":") + sep := strings.Index(reference, ":") if sep == -1 { dir = reference tag = "latest" diff --git a/oci/layout/oci_transport_test.go b/oci/layout/oci_transport_test.go index 9c63addd5c..a04ca19e78 100644 --- a/oci/layout/oci_transport_test.go +++ b/oci/layout/oci_transport_test.go @@ -25,6 +25,8 @@ func TestTransportValidatePolicyConfigurationScope(t *testing.T) { "/etc:notlatest", "/this/does/not/exist", "/this/does/not/exist:notlatest", + "/this/does/not/exist:a-b.c_d:e@f+g--h", + "/this/does/not/exist:ABZabz019", "/:strangecornercase", } { err := Transport.ValidatePolicyConfigurationScope(scope) @@ -38,9 +40,10 @@ func TestTransportValidatePolicyConfigurationScope(t *testing.T) { "/has/./dot", "/has/dot/../dot", "/trailing/slash/", - "/etc:invalid'tag!value@", - "/path:with/colons", - "/path:with/colons/and:tag", + "/etc:invalid!character!in!tag", + "/etc:_leading_separator", + "/etc:trailing_separator_", + "/etc:double__separator", } { err := Transport.ValidatePolicyConfigurationScope(scope) assert.Error(t, err, scope) @@ -66,6 +69,7 @@ func testParseReference(t *testing.T, fn func(string) (types.ImageReference, err } { for _, tag := range []struct{ suffix, tag string }{ {":notlatest", "notlatest"}, + {":notlatest:with:colons", "notlatest:with:colons"}, {"", "latest"}, } { input := path + tag.suffix @@ -78,9 +82,6 @@ func testParseReference(t *testing.T, fn func(string) (types.ImageReference, err } } - _, err = fn(tmpDir + "/with:multiple:colons:and:tag") - assert.Error(t, err) - _, err = fn(tmpDir + ":invalid'tag!value@") assert.Error(t, err) }