Skip to content

Commit cb4354c

Browse files
committed
fix: normalize OCI reference in store lookups to match Pull() key
ociSource.Read() was using the raw reference string to look up artifacts in the content store, while remote.Pull() stores them under a normalized key (e.g. 'agentcatalog/review-pr:latest'). This caused cache misses when using fully qualified references like 'index.docker.io/agentcatalog/review-pr:latest'. Extract NormalizeReference() from remote.Pull() and use it in ociSource.Read() so equivalent references resolve to the same store key. Assisted-By: docker-agent
1 parent 84d3fc2 commit cb4354c

3 files changed

Lines changed: 75 additions & 3 deletions

File tree

pkg/config/sources.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,16 +121,24 @@ func (a ociSource) Read(ctx context.Context) ([]byte, error) {
121121
return nil, fmt.Errorf("failed to create content store: %w", err)
122122
}
123123

124+
// Normalize the reference so that equivalent forms (e.g.
125+
// "agentcatalog/review-pr" and "index.docker.io/agentcatalog/review-pr:latest")
126+
// resolve to the same store key that remote.Pull uses.
127+
storeKey, err := remote.NormalizeReference(a.reference)
128+
if err != nil {
129+
return nil, fmt.Errorf("normalizing OCI reference %s: %w", a.reference, err)
130+
}
131+
124132
tryLoad := func() ([]byte, error) {
125-
af, err := store.GetArtifact(a.reference)
133+
af, err := store.GetArtifact(storeKey)
126134
if err != nil {
127135
return nil, err
128136
}
129137
return []byte(af), nil
130138
}
131139

132-
// Check if we have any local metadata (same as before)
133-
_, metaErr := store.GetArtifactMetadata(a.reference)
140+
// Check if we have any local metadata
141+
_, metaErr := store.GetArtifactMetadata(storeKey)
134142
hasLocal := metaErr == nil
135143

136144
// Always try normal pull first (preserves pull-interval behavior)

pkg/remote/pull.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,18 @@ import (
1010
"github.com/docker/docker-agent/pkg/content"
1111
)
1212

13+
// NormalizeReference parses an OCI reference and returns the normalized
14+
// store key that Pull uses to store artifacts. This ensures that equivalent
15+
// references (e.g. "agentcatalog/review-pr" and
16+
// "index.docker.io/agentcatalog/review-pr:latest") map to the same key.
17+
func NormalizeReference(registryRef string) (string, error) {
18+
ref, err := name.ParseReference(registryRef)
19+
if err != nil {
20+
return "", fmt.Errorf("parsing registry reference %s: %w", registryRef, err)
21+
}
22+
return ref.Context().RepositoryStr() + separator(ref) + ref.Identifier(), nil
23+
}
24+
1325
// Pull pulls an artifact from a registry and stores it in the content store
1426
func Pull(ctx context.Context, registryRef string, force bool, opts ...crane.Option) (string, error) {
1527
opts = append(opts, crane.WithContext(ctx))

pkg/remote/pull_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,58 @@ func TestPullIntegration(t *testing.T) {
7272
require.Error(t, err)
7373
}
7474

75+
func TestNormalizeReference(t *testing.T) {
76+
t.Parallel()
77+
78+
tests := []struct {
79+
name string
80+
ref string
81+
expected string
82+
}{
83+
{
84+
name: "short reference gets normalized",
85+
ref: "agentcatalog/review-pr",
86+
expected: "agentcatalog/review-pr:latest",
87+
},
88+
{
89+
name: "fully qualified reference gets normalized to same key",
90+
ref: "index.docker.io/agentcatalog/review-pr:latest",
91+
expected: "agentcatalog/review-pr:latest",
92+
},
93+
{
94+
name: "tagged reference preserves tag",
95+
ref: "agentcatalog/review-pr:v1",
96+
expected: "agentcatalog/review-pr:v1",
97+
},
98+
{
99+
name: "digest reference preserves digest",
100+
ref: "agentcatalog/review-pr@sha256:0000000000000000000000000000000000000000000000000000000000000000",
101+
expected: "agentcatalog/review-pr@sha256:0000000000000000000000000000000000000000000000000000000000000000",
102+
},
103+
{
104+
name: "non-docker-hub registry",
105+
ref: "ghcr.io/myorg/agent:v2",
106+
expected: "myorg/agent:v2",
107+
},
108+
}
109+
110+
for _, tt := range tests {
111+
t.Run(tt.name, func(t *testing.T) {
112+
t.Parallel()
113+
result, err := NormalizeReference(tt.ref)
114+
require.NoError(t, err)
115+
assert.Equal(t, tt.expected, result)
116+
})
117+
}
118+
}
119+
120+
func TestNormalizeReference_InvalidReference(t *testing.T) {
121+
t.Parallel()
122+
123+
_, err := NormalizeReference(":::invalid")
124+
require.Error(t, err)
125+
}
126+
75127
func TestSeparator(t *testing.T) {
76128
t.Parallel()
77129

0 commit comments

Comments
 (0)