Skip to content

Commit 31e17c1

Browse files
committed
fix(webhook): prevent duplicate repository CR on trailing slash
The webhook admission controller's checkIfRepoExist used exact string equality to compare repository URLs. This allowed users to create a second Repository CR with the same URL by simply appending a trailing slash (e.g. https://github.com/org/repo vs https://github.com/org/repo/), bypassing the uniqueness validation. - pkg/webhook/validation.go: - Normalize URLs with strings.TrimSuffix before comparison in checkIfRepoExist to treat trailing slash variants as identical - pkg/webhook/validation_test.go: - Add test case for rejecting repository URL with trailing slash when a matching repo already exists - test/repository_webhook_test.go: - Add e2e test TestOthersRepositoryCreationWithTrailingSlash to verify the webhook rejects duplicate repos created via trailing slash bypass Signed-off-by: Zaki Shaikh <zashaikh@redhat.com>
1 parent a6e4aab commit 31e17c1

File tree

3 files changed

+55
-1
lines changed

3 files changed

+55
-1
lines changed

pkg/webhook/validation.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ func checkIfRepoExist(pac pac.RepositoryLister, repo *v1alpha1.Repository, ns st
9090
}
9191
for i := len(repositories) - 1; i >= 0; i-- {
9292
repoFromCluster := repositories[i]
93-
if repoFromCluster.Spec.URL == repo.Spec.URL &&
93+
if strings.TrimRight(strings.TrimSpace(repoFromCluster.Spec.URL), "/") == strings.TrimRight(strings.TrimSpace(repo.Spec.URL), "/") &&
9494
(repoFromCluster.Name != repo.Name || repoFromCluster.Namespace != repo.Namespace) {
9595
return true, nil
9696
}

pkg/webhook/validation_test.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,26 @@ func TestReconcilerAdmit(t *testing.T) {
171171
}),
172172
allowed: true,
173173
},
174+
{
175+
name: "reject repository URL with trailing slash",
176+
repo: testnewrepo.NewRepo(testnewrepo.RepoTestcreationOpts{
177+
Name: "test-run",
178+
InstallNamespace: "namespace",
179+
URL: "https://pac.test/already/installed/",
180+
}),
181+
allowed: false,
182+
result: "repository already exists with URL: https://pac.test/already/installed/",
183+
},
184+
{
185+
name: "reject repository URL with multiple trailing slashes",
186+
repo: testnewrepo.NewRepo(testnewrepo.RepoTestcreationOpts{
187+
Name: "test-run",
188+
InstallNamespace: "namespace",
189+
URL: "https://pac.test/already/installed//////",
190+
}),
191+
allowed: false,
192+
result: "repository already exists with URL: https://pac.test/already/installed//////",
193+
},
174194
}
175195
for _, tt := range tests {
176196
t.Run(tt.name, func(t *testing.T) {

test/repository_webhook_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,37 @@ func TestOthersRepositoryCreation(t *testing.T) {
4646
assert.Assert(t, err != nil)
4747
assert.Equal(t, err.Error(), "admission webhook \"validation.pipelinesascode.tekton.dev\" denied the request: repository already exists with URL: https://pac.test/pac/app")
4848
}
49+
50+
func TestOthersRepositoryCreationWithTrailingSlash(t *testing.T) {
51+
ctx := context.TODO()
52+
ctx, runcnx, _, _, err := ghtest.Setup(ctx, false, false)
53+
assert.NilError(t, err)
54+
55+
targetNs := names.SimpleNameGenerator.RestrictLengthWithRandomSuffix("test-repo")
56+
repo := &v1alpha1.Repository{
57+
ObjectMeta: metav1.ObjectMeta{
58+
Name: targetNs,
59+
},
60+
Spec: v1alpha1.RepositorySpec{
61+
URL: "https://pac.test/pac/app",
62+
},
63+
}
64+
65+
defer repository.NSTearDown(ctx, t, runcnx, targetNs)
66+
err = repository.CreateNS(ctx, targetNs, runcnx)
67+
assert.NilError(t, err)
68+
err = repository.CreateRepo(ctx, targetNs, runcnx, repo)
69+
assert.NilError(t, err)
70+
71+
// create a new cr with same git url
72+
targetNsNew := names.SimpleNameGenerator.RestrictLengthWithRandomSuffix("test-repo-new")
73+
repo.Name = "test-repo-new"
74+
repo.Spec.URL = "https://pac.test/pac/app/"
75+
76+
defer repository.NSTearDown(ctx, t, runcnx, targetNsNew)
77+
err = repository.CreateNS(ctx, targetNsNew, runcnx)
78+
assert.NilError(t, err)
79+
err = repository.CreateRepo(ctx, targetNsNew, runcnx, repo)
80+
assert.Assert(t, err != nil)
81+
assert.Equal(t, err.Error(), "admission webhook \"validation.pipelinesascode.tekton.dev\" denied the request: repository already exists with URL: https://pac.test/pac/app/")
82+
}

0 commit comments

Comments
 (0)