Merge pull request #689 from stevvooe/remove-repository-min-component-length
Allow single character repository names
This commit is contained in:
commit
419bbc2da6
5 changed files with 57 additions and 46 deletions
|
@ -120,6 +120,12 @@ indicating what is different. Optionally, we may start marking parts of the
|
||||||
specification to correspond with the versions enumerated here.
|
specification to correspond with the versions enumerated here.
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
|
<dt>2.0.3</dt>
|
||||||
|
<dd>
|
||||||
|
<li>Allow repository name components to be one character.</li>
|
||||||
|
<li>Clarified that single component names are allowed.</li>
|
||||||
|
</dd>
|
||||||
|
|
||||||
<dt>2.0.2</dt>
|
<dt>2.0.2</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<li>Added section covering digest format.</li>
|
<li>Added section covering digest format.</li>
|
||||||
|
@ -174,12 +180,11 @@ path component is less than 30 characters. The V2 registry API does not
|
||||||
enforce this. The rules for a repository name are as follows:
|
enforce this. The rules for a repository name are as follows:
|
||||||
|
|
||||||
1. A repository name is broken up into _path components_. A component of a
|
1. A repository name is broken up into _path components_. A component of a
|
||||||
repository name must be at least two lowercase, alpha-numeric characters,
|
repository name must be at least one lowercase, alpha-numeric characters,
|
||||||
optionally separated by periods, dashes or underscores. More strictly, it
|
optionally separated by periods, dashes or underscores. More strictly, it
|
||||||
must match the regular expression `[a-z0-9]+(?:[._-][a-z0-9]+)*` and the
|
must match the regular expression `[a-z0-9]+(?:[._-][a-z0-9]+)*`.
|
||||||
matched result must be 2 or more characters in length.
|
2. If a repository name has two or more path components, they must be
|
||||||
2. The name of a repository must have at least two path components, separated
|
separated by a forward slash ("/").
|
||||||
by a forward slash.
|
|
||||||
3. The total length of a repository name, including slashes, must be less the
|
3. The total length of a repository name, including slashes, must be less the
|
||||||
256 characters.
|
256 characters.
|
||||||
|
|
||||||
|
|
|
@ -120,6 +120,12 @@ indicating what is different. Optionally, we may start marking parts of the
|
||||||
specification to correspond with the versions enumerated here.
|
specification to correspond with the versions enumerated here.
|
||||||
|
|
||||||
<dl>
|
<dl>
|
||||||
|
<dt>2.0.3</dt>
|
||||||
|
<dd>
|
||||||
|
<li>Allow repository name components to be one character.</li>
|
||||||
|
<li>Clarified that single component names are allowed.</li>
|
||||||
|
</dd>
|
||||||
|
|
||||||
<dt>2.0.2</dt>
|
<dt>2.0.2</dt>
|
||||||
<dd>
|
<dd>
|
||||||
<li>Added section covering digest format.</li>
|
<li>Added section covering digest format.</li>
|
||||||
|
@ -174,12 +180,11 @@ path component is less than 30 characters. The V2 registry API does not
|
||||||
enforce this. The rules for a repository name are as follows:
|
enforce this. The rules for a repository name are as follows:
|
||||||
|
|
||||||
1. A repository name is broken up into _path components_. A component of a
|
1. A repository name is broken up into _path components_. A component of a
|
||||||
repository name must be at least two lowercase, alpha-numeric characters,
|
repository name must be at least one lowercase, alpha-numeric characters,
|
||||||
optionally separated by periods, dashes or underscores. More strictly, it
|
optionally separated by periods, dashes or underscores. More strictly, it
|
||||||
must match the regular expression `[a-z0-9]+(?:[._-][a-z0-9]+)*` and the
|
must match the regular expression `[a-z0-9]+(?:[._-][a-z0-9]+)*`.
|
||||||
matched result must be 2 or more characters in length.
|
2. If a repository name has two or more path components, they must be
|
||||||
2. The name of a repository must have at least two path components, separated
|
separated by a forward slash ("/").
|
||||||
by a forward slash.
|
|
||||||
3. The total length of a repository name, including slashes, must be less the
|
3. The total length of a repository name, including slashes, must be less the
|
||||||
256 characters.
|
256 characters.
|
||||||
|
|
||||||
|
|
|
@ -6,19 +6,10 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO(stevvooe): Move these definitions back to an exported package. While
|
// TODO(stevvooe): Move these definitions to the future "reference" package.
|
||||||
// they are used with v2 definitions, their relevance expands beyond.
|
// While they are used with v2 definitions, their relevance expands beyond.
|
||||||
// "distribution/names" is a candidate package.
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// RepositoryNameComponentMinLength is the minimum number of characters in a
|
|
||||||
// single repository name slash-delimited component
|
|
||||||
RepositoryNameComponentMinLength = 2
|
|
||||||
|
|
||||||
// RepositoryNameMinComponents is the minimum number of slash-delimited
|
|
||||||
// components that a repository name must have
|
|
||||||
RepositoryNameMinComponents = 1
|
|
||||||
|
|
||||||
// RepositoryNameTotalLengthMax is the maximum total number of characters in
|
// RepositoryNameTotalLengthMax is the maximum total number of characters in
|
||||||
// a repository name
|
// a repository name
|
||||||
RepositoryNameTotalLengthMax = 255
|
RepositoryNameTotalLengthMax = 255
|
||||||
|
@ -40,17 +31,13 @@ var RepositoryNameRegexp = regexp.MustCompile(`(?:` + RepositoryNameComponentReg
|
||||||
// TagNameRegexp matches valid tag names. From docker/docker:graph/tags.go.
|
// TagNameRegexp matches valid tag names. From docker/docker:graph/tags.go.
|
||||||
var TagNameRegexp = regexp.MustCompile(`[\w][\w.-]{0,127}`)
|
var TagNameRegexp = regexp.MustCompile(`[\w][\w.-]{0,127}`)
|
||||||
|
|
||||||
// TODO(stevvooe): Contribute these exports back to core, so they are shared.
|
// TagNameAnchoredRegexp matches valid tag names, anchored at the start and
|
||||||
|
// end of the matched string.
|
||||||
|
var TagNameAnchoredRegexp = regexp.MustCompile("^" + TagNameRegexp.String() + "$")
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// ErrRepositoryNameComponentShort is returned when a repository name
|
// ErrRepositoryNameEmpty is returned for empty, invalid repository names.
|
||||||
// contains a component which is shorter than
|
ErrRepositoryNameEmpty = fmt.Errorf("repository name must have at least one component")
|
||||||
// RepositoryNameComponentMinLength
|
|
||||||
ErrRepositoryNameComponentShort = fmt.Errorf("repository name component must be %v or more characters", RepositoryNameComponentMinLength)
|
|
||||||
|
|
||||||
// ErrRepositoryNameMissingComponents is returned when a repository name
|
|
||||||
// contains fewer than RepositoryNameMinComponents components
|
|
||||||
ErrRepositoryNameMissingComponents = fmt.Errorf("repository name must have at least %v components", RepositoryNameMinComponents)
|
|
||||||
|
|
||||||
// ErrRepositoryNameLong is returned when a repository name is longer than
|
// ErrRepositoryNameLong is returned when a repository name is longer than
|
||||||
// RepositoryNameTotalLengthMax
|
// RepositoryNameTotalLengthMax
|
||||||
|
@ -76,21 +63,17 @@ var (
|
||||||
// The result of the production, known as the "namespace", should be limited
|
// The result of the production, known as the "namespace", should be limited
|
||||||
// to 255 characters.
|
// to 255 characters.
|
||||||
func ValidateRepositoryName(name string) error {
|
func ValidateRepositoryName(name string) error {
|
||||||
|
if name == "" {
|
||||||
|
return ErrRepositoryNameEmpty
|
||||||
|
}
|
||||||
|
|
||||||
if len(name) > RepositoryNameTotalLengthMax {
|
if len(name) > RepositoryNameTotalLengthMax {
|
||||||
return ErrRepositoryNameLong
|
return ErrRepositoryNameLong
|
||||||
}
|
}
|
||||||
|
|
||||||
components := strings.Split(name, "/")
|
components := strings.Split(name, "/")
|
||||||
|
|
||||||
if len(components) < RepositoryNameMinComponents {
|
|
||||||
return ErrRepositoryNameMissingComponents
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, component := range components {
|
for _, component := range components {
|
||||||
if len(component) < RepositoryNameComponentMinLength {
|
|
||||||
return ErrRepositoryNameComponentShort
|
|
||||||
}
|
|
||||||
|
|
||||||
if !RepositoryNameComponentAnchoredRegexp.MatchString(component) {
|
if !RepositoryNameComponentAnchoredRegexp.MatchString(component) {
|
||||||
return ErrRepositoryNameComponentInvalid
|
return ErrRepositoryNameComponentInvalid
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package v2
|
package v2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
@ -10,6 +11,10 @@ func TestRepositoryNameRegexp(t *testing.T) {
|
||||||
input string
|
input string
|
||||||
err error
|
err error
|
||||||
}{
|
}{
|
||||||
|
{
|
||||||
|
input: "",
|
||||||
|
err: ErrRepositoryNameEmpty,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
input: "short",
|
input: "short",
|
||||||
},
|
},
|
||||||
|
@ -30,11 +35,26 @@ func TestRepositoryNameRegexp(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "a/a/a/b/b",
|
input: "a/a/a/b/b",
|
||||||
err: ErrRepositoryNameComponentShort,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "a/a/a/a/",
|
input: "a/a/a/a/",
|
||||||
err: ErrRepositoryNameComponentShort,
|
err: ErrRepositoryNameComponentInvalid,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "a//a/a",
|
||||||
|
err: ErrRepositoryNameComponentInvalid,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "a",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "a/aa",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "aa/a",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "a/aa/a",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
input: "foo.com/bar/baz",
|
input: "foo.com/bar/baz",
|
||||||
|
@ -58,10 +78,6 @@ func TestRepositoryNameRegexp(t *testing.T) {
|
||||||
{
|
{
|
||||||
input: "a-a/a-a",
|
input: "a-a/a-a",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
input: "a",
|
|
||||||
err: ErrRepositoryNameComponentShort,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
input: "a-/a/a/a",
|
input: "a-/a/a/a",
|
||||||
err: ErrRepositoryNameComponentInvalid,
|
err: ErrRepositoryNameComponentInvalid,
|
||||||
|
@ -110,9 +126,8 @@ func TestRepositoryNameRegexp(t *testing.T) {
|
||||||
err: ErrRepositoryNameComponentInvalid,
|
err: ErrRepositoryNameComponentInvalid,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
|
|
||||||
failf := func(format string, v ...interface{}) {
|
failf := func(format string, v ...interface{}) {
|
||||||
t.Logf(testcase.input+": "+format, v...)
|
t.Logf(strconv.Quote(testcase.input)+": "+format, v...)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -263,6 +263,7 @@ func checkTestRouter(t *testing.T, testCases []routeTestCase, prefix string, dee
|
||||||
}
|
}
|
||||||
|
|
||||||
if testcase.StatusCode != http.StatusOK {
|
if testcase.StatusCode != http.StatusOK {
|
||||||
|
resp.Body.Close()
|
||||||
// We don't care about json response.
|
// We don't care about json response.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -291,6 +292,8 @@ func checkTestRouter(t *testing.T, testCases []routeTestCase, prefix string, dee
|
||||||
if deeplyEqual && !reflect.DeepEqual(actualRouteInfo, testcase) {
|
if deeplyEqual && !reflect.DeepEqual(actualRouteInfo, testcase) {
|
||||||
t.Fatalf("actual does not equal expected: %#v != %#v", actualRouteInfo, testcase)
|
t.Fatalf("actual does not equal expected: %#v != %#v", actualRouteInfo, testcase)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resp.Body.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue