diff --git a/reference.go b/reference.go index e07c43c..900398b 100644 --- a/reference.go +++ b/reference.go @@ -35,8 +35,13 @@ import ( ) const ( + // RepositoryNameTotalLengthMax is the maximum total number of characters in a repository name. + RepositoryNameTotalLengthMax = 255 + // NameTotalLengthMax is the maximum total number of characters in a repository name. - NameTotalLengthMax = 255 + // + // Deprecated: use [RepositoryNameTotalLengthMax] instead. + NameTotalLengthMax = RepositoryNameTotalLengthMax ) var ( @@ -55,8 +60,8 @@ var ( // ErrNameEmpty is returned for empty, invalid repository names. ErrNameEmpty = errors.New("repository name must have at least one component") - // ErrNameTooLong is returned when a repository name is longer than NameTotalLengthMax. - ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", NameTotalLengthMax) + // ErrNameTooLong is returned when a repository name is longer than RepositoryNameTotalLengthMax. + ErrNameTooLong = fmt.Errorf("repository name must not be more than %v characters", RepositoryNameTotalLengthMax) // ErrNameNotCanonical is returned when a name is not canonical. ErrNameNotCanonical = errors.New("repository name must be canonical") @@ -190,10 +195,6 @@ func Parse(s string) (Reference, error) { return nil, ErrReferenceInvalidFormat } - if len(matches[1]) > NameTotalLengthMax { - return nil, ErrNameTooLong - } - var repo repository nameMatch := anchoredNameRegexp.FindStringSubmatch(matches[1]) @@ -205,6 +206,10 @@ func Parse(s string) (Reference, error) { repo.path = matches[1] } + if len(repo.path) > RepositoryNameTotalLengthMax { + return nil, ErrNameTooLong + } + ref := reference{ namedRepository: repo, tag: matches[2], @@ -243,14 +248,15 @@ func ParseNamed(s string) (Named, error) { // WithName returns a named object representing the given string. If the input // is invalid ErrReferenceInvalidFormat will be returned. func WithName(name string) (Named, error) { - if len(name) > NameTotalLengthMax { - return nil, ErrNameTooLong - } - match := anchoredNameRegexp.FindStringSubmatch(name) if match == nil || len(match) != 3 { return nil, ErrReferenceInvalidFormat } + + if len(match[2]) > RepositoryNameTotalLengthMax { + return nil, ErrNameTooLong + } + return repository{ domain: match[1], path: match[2], diff --git a/reference_test.go b/reference_test.go index b2f0fe7..3a06e8f 100644 --- a/reference_test.go +++ b/reference_test.go @@ -4,6 +4,7 @@ import ( _ "crypto/sha256" _ "crypto/sha512" "encoding/json" + "errors" "strings" "testing" @@ -117,7 +118,7 @@ func TestReferenceParse(t *testing.T) { tag: "Uppercase", }, { - input: strings.Repeat("a/", 128) + "a:tag", + input: "domain/" + strings.Repeat("a", 256) + ":tag", err: ErrNameTooLong, }, { @@ -266,6 +267,12 @@ func TestReferenceParse(t *testing.T) { input: "[fe80::1%@invalidzone]:5000/repo", err: ErrReferenceInvalidFormat, }, + { + input: "domain/" + strings.Repeat("a", 255) + ":tag", + domain: "domain", + repository: "domain/" + strings.Repeat("a", 255), + tag: "tag", + }, } for _, tc := range tests { tc := tc @@ -337,7 +344,7 @@ func TestWithNameFailure(t *testing.T) { }{ { input: "", - err: ErrNameEmpty, + err: ErrReferenceInvalidFormat, }, { input: ":justtag", @@ -352,7 +359,11 @@ func TestWithNameFailure(t *testing.T) { err: ErrReferenceInvalidFormat, }, { - input: strings.Repeat("a/", 128) + "a:tag", + input: "domain/repo:tag", + err: ErrReferenceInvalidFormat, + }, + { + input: "domain/" + strings.Repeat("a", 256), err: ErrNameTooLong, }, { @@ -365,8 +376,8 @@ func TestWithNameFailure(t *testing.T) { t.Run(tc.input, func(t *testing.T) { t.Parallel() _, err := WithName(tc.input) - if err == nil { - t.Errorf("no error parsing name. expected: %s", tc.err) + if !errors.Is(err, tc.err) { + t.Errorf("unexpected error parsing name. expected: %s, got: %s", tc.err, err) } }) }