diff --git a/docs/spec/api.md b/docs/spec/api.md index 5196d05c5..483f15f03 100644 --- a/docs/spec/api.md +++ b/docs/spec/api.md @@ -120,6 +120,12 @@ indicating what is different. Optionally, we may start marking parts of the specification to correspond with the versions enumerated here.
+
2.0.3
+
+
  • Allow repository name components to be one character.
  • +
  • Clarified that single component names are allowed.
  • +
    +
    2.0.2
  • Added section covering digest format.
  • @@ -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: 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 - must match the regular expression `[a-z0-9]+(?:[._-][a-z0-9]+)*` and the - matched result must be 2 or more characters in length. -2. The name of a repository must have at least two path components, separated - by a forward slash. + must match the regular expression `[a-z0-9]+(?:[._-][a-z0-9]+)*`. +2. If a repository name has two or more path components, they must be + separated by a forward slash ("/"). 3. The total length of a repository name, including slashes, must be less the 256 characters. diff --git a/docs/spec/api.md.tmpl b/docs/spec/api.md.tmpl index 878f0e4da..bc6d6f926 100644 --- a/docs/spec/api.md.tmpl +++ b/docs/spec/api.md.tmpl @@ -120,6 +120,12 @@ indicating what is different. Optionally, we may start marking parts of the specification to correspond with the versions enumerated here.
    +
    2.0.3
    +
    +
  • Allow repository name components to be one character.
  • +
  • Clarified that single component names are allowed.
  • +
    +
    2.0.2
  • Added section covering digest format.
  • @@ -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: 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 - must match the regular expression `[a-z0-9]+(?:[._-][a-z0-9]+)*` and the - matched result must be 2 or more characters in length. -2. The name of a repository must have at least two path components, separated - by a forward slash. + must match the regular expression `[a-z0-9]+(?:[._-][a-z0-9]+)*`. +2. If a repository name has two or more path components, they must be + separated by a forward slash ("/"). 3. The total length of a repository name, including slashes, must be less the 256 characters. diff --git a/registry/api/v2/names.go b/registry/api/v2/names.go index 19cb72a02..14b7ea60a 100644 --- a/registry/api/v2/names.go +++ b/registry/api/v2/names.go @@ -6,19 +6,10 @@ import ( "strings" ) -// TODO(stevvooe): Move these definitions back to an exported package. While -// they are used with v2 definitions, their relevance expands beyond. -// "distribution/names" is a candidate package. +// TODO(stevvooe): Move these definitions to the future "reference" package. +// While they are used with v2 definitions, their relevance expands beyond. 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 // a repository name RepositoryNameTotalLengthMax = 255 @@ -40,17 +31,13 @@ var RepositoryNameRegexp = regexp.MustCompile(`(?:` + RepositoryNameComponentReg // TagNameRegexp matches valid tag names. From docker/docker:graph/tags.go. 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 ( - // ErrRepositoryNameComponentShort is returned when a repository name - // contains a component which is shorter than - // 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) + // ErrRepositoryNameEmpty is returned for empty, invalid repository names. + ErrRepositoryNameEmpty = fmt.Errorf("repository name must have at least one component") // ErrRepositoryNameLong is returned when a repository name is longer than // RepositoryNameTotalLengthMax @@ -76,21 +63,17 @@ var ( // The result of the production, known as the "namespace", should be limited // to 255 characters. func ValidateRepositoryName(name string) error { + if name == "" { + return ErrRepositoryNameEmpty + } + if len(name) > RepositoryNameTotalLengthMax { return ErrRepositoryNameLong } components := strings.Split(name, "/") - if len(components) < RepositoryNameMinComponents { - return ErrRepositoryNameMissingComponents - } - for _, component := range components { - if len(component) < RepositoryNameComponentMinLength { - return ErrRepositoryNameComponentShort - } - if !RepositoryNameComponentAnchoredRegexp.MatchString(component) { return ErrRepositoryNameComponentInvalid } diff --git a/registry/api/v2/names_test.go b/registry/api/v2/names_test.go index 0975fb7c8..51e0ba8b3 100644 --- a/registry/api/v2/names_test.go +++ b/registry/api/v2/names_test.go @@ -1,6 +1,7 @@ package v2 import ( + "strconv" "strings" "testing" ) @@ -10,6 +11,10 @@ func TestRepositoryNameRegexp(t *testing.T) { input string err error }{ + { + input: "", + err: ErrRepositoryNameEmpty, + }, { input: "short", }, @@ -30,11 +35,26 @@ func TestRepositoryNameRegexp(t *testing.T) { }, { input: "a/a/a/b/b", - err: ErrRepositoryNameComponentShort, }, { 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", @@ -58,10 +78,6 @@ func TestRepositoryNameRegexp(t *testing.T) { { input: "a-a/a-a", }, - { - input: "a", - err: ErrRepositoryNameComponentShort, - }, { input: "a-/a/a/a", err: ErrRepositoryNameComponentInvalid, @@ -110,9 +126,8 @@ func TestRepositoryNameRegexp(t *testing.T) { err: ErrRepositoryNameComponentInvalid, }, } { - failf := func(format string, v ...interface{}) { - t.Logf(testcase.input+": "+format, v...) + t.Logf(strconv.Quote(testcase.input)+": "+format, v...) t.Fail() } diff --git a/registry/api/v2/routes_test.go b/registry/api/v2/routes_test.go index fb268336f..9fd29a4f5 100644 --- a/registry/api/v2/routes_test.go +++ b/registry/api/v2/routes_test.go @@ -263,6 +263,7 @@ func checkTestRouter(t *testing.T, testCases []routeTestCase, prefix string, dee } if testcase.StatusCode != http.StatusOK { + resp.Body.Close() // We don't care about json response. continue } @@ -291,6 +292,8 @@ func checkTestRouter(t *testing.T, testCases []routeTestCase, prefix string, dee if deeplyEqual && !reflect.DeepEqual(actualRouteInfo, testcase) { t.Fatalf("actual does not equal expected: %#v != %#v", actualRouteInfo, testcase) } + + resp.Body.Close() } }