fix(registry): exclude digest references from tag list
- commit
- a0d4c75d4d3a536c9ae7acb68d9d2abd08487826
- author
- bnema · · 2026-02-02 20:01 UTC
- parent
- 43db1bb
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
4 files · +39 -2
M internal/adapters/out/filesystem/manifest.go +4 -0
| @@ -304,6 +304,10 @@ func (s *ManifestStorage) deleteManifestContentType(name, reference string) erro | |||
| 304 | 304 | // Tags management helpers | |
| 305 | 305 | ||
| 306 | 306 | func (s *ManifestStorage) updateTagsList(name, reference string) error { | |
| 307 | + | if validation.ValidateDigest(reference) == nil { | |
| 308 | + | return nil | |
| 309 | + | } | |
| 310 | + | ||
| 307 | 311 | tags, err := s.ListTags(name) | |
| 308 | 312 | if err != nil { | |
| 309 | 313 | return err | |
| @@ -304,6 +304,10 @@ func (s *ManifestStorage) deleteManifestContentType(name, reference string) erro | |||||
| 304 | // Tags management helpers | 304 | // Tags management helpers | ||
| 305 | 305 | ||||
| 306 | func (s *ManifestStorage) updateTagsList(name, reference string) error { | 306 | func (s *ManifestStorage) updateTagsList(name, reference string) error { | ||
| 307 | + | if validation.ValidateDigest(reference) == nil { | |||
| 308 | + | return nil | |||
| 309 | + | } | |||
| 310 | + | ||||
| 307 | tags, err := s.ListTags(name) | 311 | tags, err := s.ListTags(name) | ||
| 308 | if err != nil { | 312 | if err != nil { | ||
| 309 | return err | 313 | return err | ||
M internal/adapters/out/filesystem/manifest_test.go +19 -0
| @@ -173,6 +173,25 @@ func TestManifestStorage_ListTags_Empty(t *testing.T) { | |||
| 173 | 173 | assert.Empty(t, tags) | |
| 174 | 174 | } | |
| 175 | 175 | ||
| 176 | + | func TestManifestStorage_ListTags_SkipsDigestReference(t *testing.T) { | |
| 177 | + | tmpDir := t.TempDir() | |
| 178 | + | log := testLogger() | |
| 179 | + | ||
| 180 | + | storage, err := NewManifestStorage(tmpDir, log) | |
| 181 | + | require.NoError(t, err) | |
| 182 | + | ||
| 183 | + | manifestData := []byte(`{"schemaVersion": 2}`) | |
| 184 | + | contentType := "application/vnd.docker.distribution.manifest.v2+json" | |
| 185 | + | ||
| 186 | + | err = storage.PutManifest("myapp", "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", contentType, manifestData) | |
| 187 | + | require.NoError(t, err) | |
| 188 | + | ||
| 189 | + | tags, err := storage.ListTags("myapp") | |
| 190 | + | require.NoError(t, err) | |
| 191 | + | ||
| 192 | + | assert.Empty(t, tags) | |
| 193 | + | } | |
| 194 | + | ||
| 176 | 195 | func TestManifestStorage_ListTags_AfterDelete(t *testing.T) { | |
| 177 | 196 | tmpDir := t.TempDir() | |
| 178 | 197 | log := testLogger() | |
| @@ -173,6 +173,25 @@ func TestManifestStorage_ListTags_Empty(t *testing.T) { | |||||
| 173 | assert.Empty(t, tags) | 173 | assert.Empty(t, tags) | ||
| 174 | } | 174 | } | ||
| 175 | 175 | ||||
| 176 | + | func TestManifestStorage_ListTags_SkipsDigestReference(t *testing.T) { | |||
| 177 | + | tmpDir := t.TempDir() | |||
| 178 | + | log := testLogger() | |||
| 179 | + | ||||
| 180 | + | storage, err := NewManifestStorage(tmpDir, log) | |||
| 181 | + | require.NoError(t, err) | |||
| 182 | + | ||||
| 183 | + | manifestData := []byte(`{"schemaVersion": 2}`) | |||
| 184 | + | contentType := "application/vnd.docker.distribution.manifest.v2+json" | |||
| 185 | + | ||||
| 186 | + | err = storage.PutManifest("myapp", "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", contentType, manifestData) | |||
| 187 | + | require.NoError(t, err) | |||
| 188 | + | ||||
| 189 | + | tags, err := storage.ListTags("myapp") | |||
| 190 | + | require.NoError(t, err) | |||
| 191 | + | ||||
| 192 | + | assert.Empty(t, tags) | |||
| 193 | + | } | |||
| 194 | + | ||||
| 176 | func TestManifestStorage_ListTags_AfterDelete(t *testing.T) { | 195 | func TestManifestStorage_ListTags_AfterDelete(t *testing.T) { | ||
| 177 | tmpDir := t.TempDir() | 196 | tmpDir := t.TempDir() | ||
| 178 | log := testLogger() | 197 | log := testLogger() | ||
M internal/usecase/registry/service.go +10 -1
| @@ -11,6 +11,7 @@ import ( | |||
| 11 | 11 | ||
| 12 | 12 | "github.com/bnema/gordon/internal/boundaries/out" | |
| 13 | 13 | "github.com/bnema/gordon/internal/domain" | |
| 14 | + | "github.com/bnema/gordon/pkg/validation" | |
| 14 | 15 | ) | |
| 15 | 16 | ||
| 16 | 17 | // Service implements the RegistryService interface. | |
| @@ -250,7 +251,15 @@ func (s *Service) ListTags(ctx context.Context, name string) ([]string, error) { | |||
| 250 | 251 | return nil, log.WrapErr(err, "failed to list tags") | |
| 251 | 252 | } | |
| 252 | 253 | ||
| 253 | - | return tags, nil | |
| 254 | + | filtered := make([]string, 0, len(tags)) | |
| 255 | + | for _, tag := range tags { | |
| 256 | + | if validation.ValidateDigest(tag) == nil { | |
| 257 | + | continue | |
| 258 | + | } | |
| 259 | + | filtered = append(filtered, tag) | |
| 260 | + | } | |
| 261 | + | ||
| 262 | + | return filtered, nil | |
| 254 | 263 | } | |
| 255 | 264 | ||
| 256 | 265 | // ListRepositories returns all repository names. | |
| @@ -11,6 +11,7 @@ import ( | |||||
| 11 | 11 | ||||
| 12 | "github.com/bnema/gordon/internal/boundaries/out" | 12 | "github.com/bnema/gordon/internal/boundaries/out" | ||
| 13 | "github.com/bnema/gordon/internal/domain" | 13 | "github.com/bnema/gordon/internal/domain" | ||
| 14 | + | "github.com/bnema/gordon/pkg/validation" | |||
| 14 | ) | 15 | ) | ||
| 15 | 16 | ||||
| 16 | // Service implements the RegistryService interface. | 17 | // Service implements the RegistryService interface. | ||
| @@ -250,7 +251,15 @@ func (s *Service) ListTags(ctx context.Context, name string) ([]string, error) { | |||||
| 250 | return nil, log.WrapErr(err, "failed to list tags") | 251 | return nil, log.WrapErr(err, "failed to list tags") | ||
| 251 | } | 252 | } | ||
| 252 | 253 | ||||
| 253 | - | return tags, nil | 254 | + | filtered := make([]string, 0, len(tags)) |
| 255 | + | for _, tag := range tags { | |||
| 256 | + | if validation.ValidateDigest(tag) == nil { | |||
| 257 | + | continue | |||
| 258 | + | } | |||
| 259 | + | filtered = append(filtered, tag) | |||
| 260 | + | } | |||
| 261 | + | ||||
| 262 | + | return filtered, nil | |||
| 254 | } | 263 | } | ||
| 255 | 264 | ||||
| 256 | // ListRepositories returns all repository names. | 265 | // ListRepositories returns all repository names. | ||
M internal/usecase/registry/service_test.go +6 -1
| @@ -375,7 +375,12 @@ func TestService_ListTags_Success(t *testing.T) { | |||
| 375 | 375 | svc := NewService(blobStorage, manifestStorage, eventBus) | |
| 376 | 376 | ctx := testContext() | |
| 377 | 377 | ||
| 378 | - | manifestStorage.EXPECT().ListTags("myapp").Return([]string{"latest", "v1.0", "v2.0"}, nil) | |
| 378 | + | manifestStorage.EXPECT().ListTags("myapp").Return([]string{ | |
| 379 | + | "latest", | |
| 380 | + | "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", | |
| 381 | + | "v1.0", | |
| 382 | + | "v2.0", | |
| 383 | + | }, nil) | |
| 379 | 384 | ||
| 380 | 385 | tags, err := svc.ListTags(ctx, "myapp") | |
| 381 | 386 | ||
| @@ -375,7 +375,12 @@ func TestService_ListTags_Success(t *testing.T) { | |||||
| 375 | svc := NewService(blobStorage, manifestStorage, eventBus) | 375 | svc := NewService(blobStorage, manifestStorage, eventBus) | ||
| 376 | ctx := testContext() | 376 | ctx := testContext() | ||
| 377 | 377 | ||||
| 378 | - | manifestStorage.EXPECT().ListTags("myapp").Return([]string{"latest", "v1.0", "v2.0"}, nil) | 378 | + | manifestStorage.EXPECT().ListTags("myapp").Return([]string{ |
| 379 | + | "latest", | |||
| 380 | + | "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", | |||
| 381 | + | "v1.0", | |||
| 382 | + | "v2.0", | |||
| 383 | + | }, nil) | |||
| 379 | 384 | ||||
| 380 | tags, err := svc.ListTags(ctx, "myapp") | 385 | tags, err := svc.ListTags(ctx, "myapp") | ||
| 381 | 386 | ||||