Verified Commit e617c07d authored by Justin Farmiloe's avatar Justin Farmiloe Committed by GitLab
Browse files

fix: allow dots in namespace path segments for RenameRepository

parent d0f1eb5e
Loading
Loading
Loading
Loading
+1 −1
Changes for docs/spec/gitlab/api.md: 1 added line, 1 removed line.
Original line number Diff line number Diff line
@@ -555,7 +555,7 @@ The request body is an object with the following attributes:
 Key         | Value                                                                                                                                                                                            | Type   | Format                                                                                                   | Condition                                                                                                                                                                                                                                                                        |
 ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------   | ------ | -------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 `name`      | The new name of the origin repository.                                                                                                                                                           | String | `[a-z0-9]+([.-][a-z0-9]+)*(/[a-z0-9]+([.-][a-z0-9]+)*)` & `[a-z0-9]+(?:(?:(?:[._]\|__\|[-]*)[a-z0-9]+)+)?` | Must match the [OCI Distribution spec requirements for repository names](https://github.com/distribution/distribution/blob/main/docs/spec/api.md#overview). Cannot be used together with the `namespace` attribute. |
 `namespace` | The new origin namespace path for the target repository. The origin namespace path must not include the origin repository name in the path segment. Must be within the same top-level namespace. | String | `[a-zA-Z0-9_\-]+(?:/[a-zA-Z0-9_\-]+)*`                                                                   | Must match the [OCI Distribution spec requirements for repository names](https://github.com/distribution/distribution/blob/main/docs/spec/api.md#overview). Cannot be used together with the `name` attribute.                                                   |
 `namespace` | The new origin namespace path for the target repository. The origin namespace path must not include the origin repository name in the path segment. Must be within the same top-level namespace. | String | `[a-zA-Z0-9_\-]+(?:\.[a-zA-Z0-9_\-]+)*(?:/[a-zA-Z0-9_\-]+(?:\.[a-zA-Z0-9_\-]+)*)*`                     | Must match the [OCI Distribution spec requirements for repository names](https://github.com/distribution/distribution/blob/main/docs/spec/api.md#overview). Cannot be used together with the `name` attribute.                                                   |
<!-- markdownlint-enable MD056 -->

**NOTE**: Only `name` or `namespace` can be used in a request but not both together.
+3 −1
Changes for reference/regexp.go: 3 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -90,7 +90,9 @@ var (
	// namespace path to the gitlab namespace path pattern.
	// This regex is a less involved derivative of the namespace path regex in rails:
	// https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/path_regex.rb?ref_type=heads#L140
	GitLabNamespacePathRegex = regexp.MustCompile(`^[a-zA-Z0-9_\-]+(?:/[a-zA-Z0-9_\-]+)*$`)
	// Dots are allowed within path segments (e.g. `example.io`, `my.group/my.project`),
	// but leading dots, trailing dots, and consecutive dots within a segment are not permitted.
	GitLabNamespacePathRegex = regexp.MustCompile(`^[a-zA-Z0-9_\-]+(?:\.[a-zA-Z0-9_\-]+)*(?:/[a-zA-Z0-9_\-]+(?:\.[a-zA-Z0-9_\-]+)*)*$`)

	// anchoredIdentifierRegexp is used to check or match an
	// identifier value, anchored at start and end of string.
+40
Changes for reference/regexp_test.go: 40 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -482,6 +482,46 @@ func TestReferenceRegexp(t *testing.T) {
	}
}

func TestGitLabNamespacePathRegex(t *testing.T) {
	testcases := []regexpMatch{
		// Must accept: new capability - dots within segments
		{input: "my.app", match: true},
		{input: "gitlab.com", match: true},
		{input: "my.group/my.project", match: true},
		{input: "v1.2.3", match: true},
		{input: "php.ms-evenements.brakeman", match: true},
		{input: "example.io/some-project", match: true},
		{input: "a.b.c/d.e.f", match: true},

		// Must still accept: existing valid paths
		{input: "mygroup", match: true},
		{input: "mygroup/myproject", match: true},
		{input: "my-group/my_project", match: true},
		{input: "a", match: true},
		{input: "group/subgroup/project", match: true},

		// Must reject: OCI dot constraints
		{input: ".hidden", match: false},
		{input: "foo.", match: false},
		{input: "a..b", match: false},
		{input: "..", match: false},
		{input: "foo/../bar", match: false},
		{input: "group/.git", match: false},
		{input: ".", match: false},
		{input: "/foo", match: false},
		{input: "foo/", match: false},
		{input: "foo//bar", match: false},
		{input: "", match: false},

		// Must reject: characters not allowed
		{input: "foo bar", match: false},
		{input: "foo@bar", match: false},
	}
	for i := range testcases {
		checkRegexp(t, GitLabNamespacePathRegex, testcases[i])
	}
}

func TestIdentifierRegexp(t *testing.T) {
	fullCases := []regexpMatch{
		{
+2 −2
Changes for registry/handlers/api_gitlab_integration_test.go: 2 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -2260,8 +2260,8 @@ func TestGitlabAPI_RenameRepositoryNamespace(t *testing.T) {
			name:               "new namespace does not satisfy regex",
			expectedRespError:  &v1.ErrorCodeInvalidBodyParamType,
			expectedRespStatus: http.StatusBadRequest,
			tokenActions:       fullAccessNamespaceTokenWithProjectMeta(baseRepoName.Name(), "foo/foo.foo"),
			requestBody:        []byte(`{ "namespace" : "foo/foo.foo" }`),
			tokenActions:       fullAccessNamespaceTokenWithProjectMeta(baseRepoName.Name(), "foo/foo..foo"),
			requestBody:        []byte(`{ "namespace" : "foo/foo..foo" }`),
		},
		{
			name:                "rename to same top level namespace",