detached a0d4c75

fix(registry): exclude digest references from tag list

commit
a0d4c75d4d3a536c9ae7acb68d9d2abd08487826
author
bnema · · 2026-02-02 20:01 UTC
parent
43db1bb
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · 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
304304 // Tags management helpers
305305
306306 func (s *ManifestStorage) updateTagsList(name, reference string) error {
307+ if validation.ValidateDigest(reference) == nil {
308+ return nil
309+ }
310+
307311 tags, err := s.ListTags(name)
308312 if err != nil {
309313 return err
@@ -304,6 +304,10 @@ func (s *ManifestStorage) deleteManifestContentType(name, reference string) erro
304 // Tags management helpers304 // 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 err313 return err
M internal/adapters/out/filesystem/manifest_test.go +19 -0
@@ -173,6 +173,25 @@ func TestManifestStorage_ListTags_Empty(t *testing.T) {
173173 assert.Empty(t, tags)
174174 }
175175
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+
176195 func TestManifestStorage_ListTags_AfterDelete(t *testing.T) {
177196 tmpDir := t.TempDir()
178197 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 (
1111
1212 "github.com/bnema/gordon/internal/boundaries/out"
1313 "github.com/bnema/gordon/internal/domain"
14+ "github.com/bnema/gordon/pkg/validation"
1415 )
1516
1617 // Service implements the RegistryService interface.
@@ -250,7 +251,15 @@ func (s *Service) ListTags(ctx context.Context, name string) ([]string, error) {
250251 return nil, log.WrapErr(err, "failed to list tags")
251252 }
252253
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
254263 }
255264
256265 // 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, nil254+ 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) {
375375 svc := NewService(blobStorage, manifestStorage, eventBus)
376376 ctx := testContext()
377377
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)
379384
380385 tags, err := svc.ListTags(ctx, "myapp")
381386
@@ -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

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