detached e62cfa8

fix(validation): enforce UUID v4 in regex pattern

Update UUID validation regex to specifically enforce UUID v4 format instead of accepting generic UUIDs. Update related test cases to use valid v4 UUIDs.
commit
e62cfa88c829ba3839affb8f30e7526659d33af2
author
brice · · 2026-02-06 05:56 UTC
parent
0f04747
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
3 files · +11 -7
M internal/adapters/out/filesystem/blob_test.go +3 -3
@@ -260,7 +260,7 @@ func TestBlobStorage_AppendBlobChunk_NotFound(t *testing.T) {
260260 storage, err := NewBlobStorage(tmpDir, log)
261261 require.NoError(t, err)
262262
263- _, err = storage.AppendBlobChunk("myapp", "00000000-0000-0000-0000-000000000000", []byte("data"))
263+ _, err = storage.AppendBlobChunk("myapp", "00000000-0000-4000-a000-000000000000", []byte("data"))
264264
265265 assert.Error(t, err)
266266 assert.Contains(t, err.Error(), "upload not found")
@@ -292,7 +292,7 @@ func TestBlobStorage_GetBlobUpload_NotFound(t *testing.T) {
292292 storage, err := NewBlobStorage(tmpDir, log)
293293 require.NoError(t, err)
294294
295- writer, err := storage.GetBlobUpload("00000000-0000-0000-0000-000000000000")
295+ writer, err := storage.GetBlobUpload("00000000-0000-4000-a000-000000000000")
296296
297297 assert.Error(t, err)
298298 assert.Nil(t, writer)
@@ -355,7 +355,7 @@ func TestBlobStorage_CancelBlobUpload_NotFound(t *testing.T) {
355355 storage, err := NewBlobStorage(tmpDir, log)
356356 require.NoError(t, err)
357357
358- err = storage.CancelBlobUpload("00000000-0000-0000-0000-000000000000")
358+ err = storage.CancelBlobUpload("00000000-0000-4000-a000-000000000000")
359359
360360 assert.Error(t, err)
361361 assert.Contains(t, err.Error(), "upload not found")
@@ -260,7 +260,7 @@ func TestBlobStorage_AppendBlobChunk_NotFound(t *testing.T) {
260 storage, err := NewBlobStorage(tmpDir, log)260 storage, err := NewBlobStorage(tmpDir, log)
261 require.NoError(t, err)261 require.NoError(t, err)
262 262
263- _, err = storage.AppendBlobChunk("myapp", "00000000-0000-0000-0000-000000000000", []byte("data"))263+ _, err = storage.AppendBlobChunk("myapp", "00000000-0000-4000-a000-000000000000", []byte("data"))
264 264
265 assert.Error(t, err)265 assert.Error(t, err)
266 assert.Contains(t, err.Error(), "upload not found")266 assert.Contains(t, err.Error(), "upload not found")
@@ -292,7 +292,7 @@ func TestBlobStorage_GetBlobUpload_NotFound(t *testing.T) {
292 storage, err := NewBlobStorage(tmpDir, log)292 storage, err := NewBlobStorage(tmpDir, log)
293 require.NoError(t, err)293 require.NoError(t, err)
294 294
295- writer, err := storage.GetBlobUpload("00000000-0000-0000-0000-000000000000")295+ writer, err := storage.GetBlobUpload("00000000-0000-4000-a000-000000000000")
296 296
297 assert.Error(t, err)297 assert.Error(t, err)
298 assert.Nil(t, writer)298 assert.Nil(t, writer)
@@ -355,7 +355,7 @@ func TestBlobStorage_CancelBlobUpload_NotFound(t *testing.T) {
355 storage, err := NewBlobStorage(tmpDir, log)355 storage, err := NewBlobStorage(tmpDir, log)
356 require.NoError(t, err)356 require.NoError(t, err)
357 357
358- err = storage.CancelBlobUpload("00000000-0000-0000-0000-000000000000")358+ err = storage.CancelBlobUpload("00000000-0000-4000-a000-000000000000")
359 359
360 assert.Error(t, err)360 assert.Error(t, err)
361 assert.Contains(t, err.Error(), "upload not found")361 assert.Contains(t, err.Error(), "upload not found")
M pkg/validation/path.go +1 -1
@@ -29,7 +29,7 @@ var digestRegex = regexp.MustCompile(`^(sha256:[a-f0-9]{64}|sha512:[a-f0-9]{128}
2929
3030 // UUID validation for blob uploads:
3131 // - Format: standard UUID v4 (e.g., 550e8400-e29b-41d4-a716-446655440000)
32-var uuidRegex = regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`)
32+var uuidRegex = regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`)
3333
3434 // MaxRepositoryNameLength is the maximum allowed length for repository names.
3535 const MaxRepositoryNameLength = 256
@@ -29,7 +29,7 @@ var digestRegex = regexp.MustCompile(`^(sha256:[a-f0-9]{64}|sha512:[a-f0-9]{128}
29 29
30 // UUID validation for blob uploads:30 // UUID validation for blob uploads:
31 // - Format: standard UUID v4 (e.g., 550e8400-e29b-41d4-a716-446655440000)31 // - Format: standard UUID v4 (e.g., 550e8400-e29b-41d4-a716-446655440000)
32-var uuidRegex = regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$`)32+var uuidRegex = regexp.MustCompile(`^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$`)
33 33
34 // MaxRepositoryNameLength is the maximum allowed length for repository names.34 // MaxRepositoryNameLength is the maximum allowed length for repository names.
35 const MaxRepositoryNameLength = 25635 const MaxRepositoryNameLength = 256
M pkg/validation/path_test.go +7 -3
@@ -164,9 +164,13 @@ func TestValidateUUID(t *testing.T) {
164164 errMsg string
165165 }{
166166 // Valid cases - standard UUID v4
167- {"valid uuid", "550e8400-e29b-41d4-a716-446655440000", false, ""},
168- {"another valid uuid", "6ba7b810-9dad-11d1-80b4-00c04fd430c8", false, ""},
169- {"all zeros", "00000000-0000-0000-0000-000000000000", false, ""},
167+ {"valid uuid v4", "550e8400-e29b-41d4-a716-446655440000", false, ""},
168+ {"another valid uuid v4", "f47ac10b-58cc-4372-a567-0e02b2c3d479", false, ""},
169+
170+ // Invalid cases - not UUID v4
171+ {"uuid v1 wrong version", "6ba7b810-9dad-11d1-80b4-00c04fd430c8", true, "invalid UUID format"},
172+ {"all zeros not v4", "00000000-0000-0000-0000-000000000000", true, "invalid UUID format"},
173+ {"wrong variant nibble", "550e8400-e29b-41d4-7716-446655440000", true, "invalid UUID format"},
170174
171175 // Invalid cases - path traversal
172176 {"path traversal", "../etc/passwd", true, "path traversal"},
@@ -164,9 +164,13 @@ func TestValidateUUID(t *testing.T) {
164 errMsg string164 errMsg string
165 }{165 }{
166 // Valid cases - standard UUID v4166 // Valid cases - standard UUID v4
167- {"valid uuid", "550e8400-e29b-41d4-a716-446655440000", false, ""},167+ {"valid uuid v4", "550e8400-e29b-41d4-a716-446655440000", false, ""},
168- {"another valid uuid", "6ba7b810-9dad-11d1-80b4-00c04fd430c8", false, ""},168+ {"another valid uuid v4", "f47ac10b-58cc-4372-a567-0e02b2c3d479", false, ""},
169- {"all zeros", "00000000-0000-0000-0000-000000000000", false, ""},169+
170+ // Invalid cases - not UUID v4
171+ {"uuid v1 wrong version", "6ba7b810-9dad-11d1-80b4-00c04fd430c8", true, "invalid UUID format"},
172+ {"all zeros not v4", "00000000-0000-0000-0000-000000000000", true, "invalid UUID format"},
173+ {"wrong variant nibble", "550e8400-e29b-41d4-7716-446655440000", true, "invalid UUID format"},
170 174
171 // Invalid cases - path traversal175 // Invalid cases - path traversal
172 {"path traversal", "../etc/passwd", true, "path traversal"},176 {"path traversal", "../etc/passwd", true, "path traversal"},

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close