Skip to content

Commit f8744f3

Browse files
lsm5claude
andcommitted
image/directory: digest algorithm agility with manifest constraints
When storing blobs with non-canonical digest algorithms (e.g., sha512): - Store the blob under the provided digest algorithm (e.g., "sha512-abc") - Also compute and store a hard link under the canonical digest (sha256) Co-Authored-By: Claude Code <[email protected]> Signed-off-by: Lokesh Mandvekar <[email protected]>
1 parent 5d5a780 commit f8744f3

File tree

3 files changed

+40
-6
lines changed

3 files changed

+40
-6
lines changed

image/directory/directory_dest.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,15 @@ func (d *dirImageDestination) PutBlobWithOptions(ctx context.Context, stream io.
151151
}
152152
}()
153153

154-
digester, stream := putblobdigest.DigestIfCanonicalUnknown(stream, inputInfo)
154+
digester, stream := putblobdigest.DigestIfUnknown(stream, inputInfo)
155+
156+
var canonicalDigester digest.Digester
157+
computeCanonical := inputInfo.Digest != "" && inputInfo.Digest.Algorithm() != digest.Canonical
158+
if computeCanonical {
159+
canonicalDigester = digest.Canonical.Digester()
160+
stream = io.TeeReader(stream, canonicalDigester.Hash())
161+
}
162+
155163
// TODO: This can take quite some time, and should ideally be cancellable using ctx.Done().
156164
size, err := io.Copy(blobFile, stream)
157165
if err != nil {
@@ -185,6 +193,18 @@ func (d *dirImageDestination) PutBlobWithOptions(ctx context.Context, stream io.
185193
if err := os.Rename(blobFile.Name(), blobPath); err != nil {
186194
return private.UploadedBlob{}, err
187195
}
196+
197+
if computeCanonical {
198+
canonicalDigest := canonicalDigester.Digest()
199+
canonicalPath, err := d.ref.layerPath(canonicalDigest)
200+
if err != nil {
201+
return private.UploadedBlob{}, err
202+
}
203+
if err := os.Link(blobPath, canonicalPath); err != nil && !os.IsExist(err) {
204+
return private.UploadedBlob{}, fmt.Errorf("creating canonical digest link: %w", err)
205+
}
206+
}
207+
188208
succeeded = true
189209
return private.UploadedBlob{Digest: blobDigest, Size: size}, nil
190210
}

image/directory/directory_transport.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,15 @@ func (ref dirReference) layerPath(digest digest.Digest) (string, error) {
176176
if err := digest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, and could possibly result in a path with ../, so validate explicitly.
177177
return "", err
178178
}
179-
// FIXME: Should we keep the digest identification?
180-
return filepath.Join(ref.path, digest.Encoded()), nil
179+
180+
var filename string
181+
if digest.Algorithm().String() == "sha256" {
182+
filename = digest.Encoded()
183+
} else {
184+
filename = digest.Algorithm().String() + "-" + digest.Encoded()
185+
}
186+
187+
return filepath.Join(ref.path, filename), nil
181188
}
182189

183190
// signaturePath returns a path for a signature within a directory using our conventions.

image/directory/directory_transport_test.go

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,14 +209,21 @@ func TestReferenceManifestPath(t *testing.T) {
209209
}
210210

211211
func TestReferenceLayerPath(t *testing.T) {
212-
const hex = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
212+
const hex256 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
213+
const hex512 = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
213214

214215
ref, tmpDir := refToTempDir(t)
215216
dirRef, ok := ref.(dirReference)
216217
require.True(t, ok)
217-
res, err := dirRef.layerPath("sha256:" + hex)
218+
219+
res, err := dirRef.layerPath("sha256:" + hex256)
220+
require.NoError(t, err)
221+
assert.Equal(t, tmpDir+"/"+hex256, res)
222+
223+
res, err = dirRef.layerPath("sha512:" + hex512)
218224
require.NoError(t, err)
219-
assert.Equal(t, tmpDir+"/"+hex, res)
225+
assert.Equal(t, tmpDir+"/sha512-"+hex512, res)
226+
220227
_, err = dirRef.layerPath(digest.Digest("sha256:../hello"))
221228
assert.Error(t, err)
222229
}

0 commit comments

Comments
 (0)