Skip to content

Commit 11eddca

Browse files
authored
Merge pull request #535 from lsm5/more-dir-digest
image/directory: store manifest and signature with digest algorithm prefix
2 parents 840976b + 98b23d8 commit 11eddca

File tree

4 files changed

+112
-45
lines changed

4 files changed

+112
-45
lines changed

image/directory/directory_dest.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ func (d *dirImageDestination) TryReusingBlobWithOptions(ctx context.Context, inf
227227
// If the destination is in principle available, refuses this manifest type (e.g. it does not recognize the schema),
228228
// but may accept a different manifest type, the returned error must be an ManifestTypeRejectedError.
229229
func (d *dirImageDestination) PutManifest(ctx context.Context, manifest []byte, instanceDigest *digest.Digest) error {
230+
if instanceDigest != nil && instanceDigest.Algorithm() != digest.Canonical { // compare the special case in manifestPath
231+
d.usesNonSHA256Digest = true
232+
}
230233
path, err := d.ref.manifestPath(instanceDigest)
231234
if err != nil {
232235
return err
@@ -239,6 +242,9 @@ func (d *dirImageDestination) PutManifest(ctx context.Context, manifest []byte,
239242
// (when the primary manifest is a manifest list); this should always be nil if the primary manifest is not a manifest list.
240243
// MUST be called after PutManifest (signatures may reference manifest contents).
241244
func (d *dirImageDestination) PutSignaturesWithFormat(ctx context.Context, signatures []signature.Signature, instanceDigest *digest.Digest) error {
245+
if instanceDigest != nil && instanceDigest.Algorithm() != digest.Canonical { // compare the special case in signaturePath
246+
d.usesNonSHA256Digest = true
247+
}
242248
for i, sig := range signatures {
243249
blob, err := signature.Blob(sig)
244250
if err != nil {

image/directory/directory_dest_test.go

Lines changed: 67 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -15,53 +15,85 @@ import (
1515
)
1616

1717
func TestVersionAssignment(t *testing.T) {
18-
for _, c := range []struct {
19-
name string
20-
algorithms []digest.Algorithm
21-
expectedVersion version
18+
for _, contentType := range []struct {
19+
name string
20+
put func(*testing.T, types.ImageDestination, digest.Algorithm, int, types.BlobInfoCache)
2221
}{
2322
{
24-
name: "SHA256 only gets version 1.1",
25-
algorithms: []digest.Algorithm{digest.SHA256},
26-
expectedVersion: version1_1,
23+
name: "blob",
24+
put: func(t *testing.T, dest types.ImageDestination, algo digest.Algorithm, i int, cache types.BlobInfoCache) {
25+
blobData := []byte("test-blob-" + algo.String() + "-" + string(rune(i)))
26+
var blobDigest digest.Digest
27+
if algo == digest.SHA256 {
28+
blobDigest = ""
29+
} else {
30+
blobDigest = algo.FromBytes(blobData)
31+
}
32+
_, err := dest.PutBlob(context.Background(), bytes.NewReader(blobData), types.BlobInfo{Digest: blobDigest, Size: int64(len(blobData))}, cache, false)
33+
require.NoError(t, err)
34+
},
2735
},
2836
{
29-
name: "SHA512 only gets version 1.2",
30-
algorithms: []digest.Algorithm{digest.SHA512},
31-
expectedVersion: version1_2,
37+
name: "manifest",
38+
put: func(t *testing.T, dest types.ImageDestination, algo digest.Algorithm, i int, cache types.BlobInfoCache) {
39+
manifestData := []byte("test-manifest-" + algo.String() + "-" + string(rune(i)))
40+
instanceDigest := algo.FromBytes(manifestData)
41+
err := dest.PutManifest(context.Background(), manifestData, &instanceDigest)
42+
require.NoError(t, err)
43+
},
3244
},
3345
{
34-
name: "Mixed SHA256 and SHA512 gets version 1.2",
35-
algorithms: []digest.Algorithm{digest.SHA256, digest.SHA512},
36-
expectedVersion: version1_2,
46+
name: "signature",
47+
put: func(t *testing.T, dest types.ImageDestination, algo digest.Algorithm, i int, cache types.BlobInfoCache) {
48+
manifestData := []byte("test-manifest-" + algo.String() + "-" + string(rune(i)))
49+
instanceDigest := algo.FromBytes(manifestData)
50+
// These signatures are completely invalid; start with 0xA3 just to be minimally plausible to signature.FromBlob.
51+
signatures := [][]byte{[]byte("\xA3sig" + algo.String() + "-" + string(rune(i)))}
52+
err := dest.PutSignatures(context.Background(), signatures, &instanceDigest)
53+
require.NoError(t, err)
54+
},
3755
},
3856
} {
39-
t.Run(c.name, func(t *testing.T) {
40-
ref, tmpDir := refToTempDir(t)
41-
cache := memory.New()
57+
for _, c := range []struct {
58+
name string
59+
algorithms []digest.Algorithm
60+
expectedVersion version
61+
}{
62+
{
63+
name: "SHA256 only gets version 1.1",
64+
algorithms: []digest.Algorithm{digest.SHA256},
65+
expectedVersion: version1_1,
66+
},
67+
{
68+
name: "SHA512 only gets version 1.2",
69+
algorithms: []digest.Algorithm{digest.SHA512},
70+
expectedVersion: version1_2,
71+
},
72+
{
73+
name: "Mixed SHA256 and SHA512 gets version 1.2",
74+
algorithms: []digest.Algorithm{digest.SHA256, digest.SHA512},
75+
expectedVersion: version1_2,
76+
},
77+
} {
78+
t.Run(contentType.name+": "+c.name, func(t *testing.T) {
79+
ref, tmpDir := refToTempDir(t)
80+
cache := memory.New()
4281

43-
dest, err := ref.NewImageDestination(context.Background(), nil)
44-
require.NoError(t, err)
45-
defer dest.Close()
82+
dest, err := ref.NewImageDestination(context.Background(), nil)
83+
require.NoError(t, err)
84+
defer dest.Close()
4685

47-
for i, algo := range c.algorithms {
48-
blobData := []byte("test-blob-" + algo.String() + "-" + string(rune(i)))
49-
var blobDigest digest.Digest
50-
if algo == digest.SHA256 {
51-
blobDigest = ""
52-
} else {
53-
blobDigest = algo.FromBytes(blobData)
86+
for i, algo := range c.algorithms {
87+
contentType.put(t, dest, algo, i, cache)
5488
}
55-
_, err = dest.PutBlob(context.Background(), bytes.NewReader(blobData), types.BlobInfo{Digest: blobDigest, Size: int64(len(blobData))}, cache, false)
56-
require.NoError(t, err)
57-
}
5889

59-
err = dest.Commit(context.Background(), nil)
60-
require.NoError(t, err)
90+
err = dest.Commit(context.Background(), nil)
91+
require.NoError(t, err)
6192

62-
versionBytes, err := os.ReadFile(filepath.Join(tmpDir, "version"))
63-
require.NoError(t, err)
64-
assert.Equal(t, c.expectedVersion.String(), string(versionBytes))
65-
})
93+
versionBytes, err := os.ReadFile(filepath.Join(tmpDir, "version"))
94+
require.NoError(t, err)
95+
assert.Equal(t, c.expectedVersion.String(), string(versionBytes))
96+
})
97+
}
6698
}
6799
}

image/directory/directory_transport.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,13 @@ func (ref dirReference) manifestPath(instanceDigest *digest.Digest) (string, err
166166
if err := instanceDigest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, and could possibly result in a path with ../, so validate explicitly.
167167
return "", err
168168
}
169-
return filepath.Join(ref.path, instanceDigest.Encoded()+".manifest.json"), nil
169+
var filename string
170+
if instanceDigest.Algorithm() == digest.Canonical {
171+
filename = instanceDigest.Encoded() + ".manifest.json"
172+
} else {
173+
filename = instanceDigest.Algorithm().String() + "-" + instanceDigest.Encoded() + ".manifest.json"
174+
}
175+
return filepath.Join(ref.path, filename), nil
170176
}
171177
return filepath.Join(ref.path, "manifest.json"), nil
172178
}
@@ -193,7 +199,13 @@ func (ref dirReference) signaturePath(index int, instanceDigest *digest.Digest)
193199
if err := instanceDigest.Validate(); err != nil { // digest.Digest.Encoded() panics on failure, and could possibly result in a path with ../, so validate explicitly.
194200
return "", err
195201
}
196-
return filepath.Join(ref.path, fmt.Sprintf(instanceDigest.Encoded()+".signature-%d", index+1)), nil
202+
var prefix string
203+
if instanceDigest.Algorithm() == digest.Canonical {
204+
prefix = instanceDigest.Encoded()
205+
} else {
206+
prefix = instanceDigest.Algorithm().String() + "-" + instanceDigest.Encoded()
207+
}
208+
return filepath.Join(ref.path, fmt.Sprintf(prefix+".signature-%d", index+1)), nil
197209
}
198210
return filepath.Join(ref.path, fmt.Sprintf("signature-%d", index+1)), nil
199211
}

image/directory/directory_transport_test.go

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -194,17 +194,24 @@ func TestReferenceDeleteImage(t *testing.T) {
194194
}
195195

196196
func TestReferenceManifestPath(t *testing.T) {
197-
dhex := digest.Digest("sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
197+
dhex256 := digest.Digest("sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
198+
dhex512 := digest.Digest("sha512:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
198199

199200
ref, tmpDir := refToTempDir(t)
200201
dirRef, ok := ref.(dirReference)
201202
require.True(t, ok)
202203
res, err := dirRef.manifestPath(nil)
203204
require.NoError(t, err)
204205
assert.Equal(t, tmpDir+"/manifest.json", res)
205-
res, err = dirRef.manifestPath(&dhex)
206+
207+
res, err = dirRef.manifestPath(&dhex256)
208+
require.NoError(t, err)
209+
assert.Equal(t, tmpDir+"/"+dhex256.Encoded()+".manifest.json", res)
210+
211+
res, err = dirRef.manifestPath(&dhex512)
206212
require.NoError(t, err)
207-
assert.Equal(t, tmpDir+"/"+dhex.Encoded()+".manifest.json", res)
213+
assert.Equal(t, tmpDir+"/sha512-"+dhex512.Encoded()+".manifest.json", res)
214+
208215
invalidDigest := digest.Digest("sha256:../hello")
209216
_, err = dirRef.manifestPath(&invalidDigest)
210217
assert.Error(t, err)
@@ -231,7 +238,8 @@ func TestReferenceLayerPath(t *testing.T) {
231238
}
232239

233240
func TestReferenceSignaturePath(t *testing.T) {
234-
dhex := digest.Digest("sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
241+
dhex256 := digest.Digest("sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
242+
dhex512 := digest.Digest("sha512:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef")
235243

236244
ref, tmpDir := refToTempDir(t)
237245
dirRef, ok := ref.(dirReference)
@@ -242,12 +250,21 @@ func TestReferenceSignaturePath(t *testing.T) {
242250
res, err = dirRef.signaturePath(9, nil)
243251
require.NoError(t, err)
244252
assert.Equal(t, tmpDir+"/signature-10", res)
245-
res, err = dirRef.signaturePath(0, &dhex)
253+
254+
res, err = dirRef.signaturePath(0, &dhex256)
246255
require.NoError(t, err)
247-
assert.Equal(t, tmpDir+"/"+dhex.Encoded()+".signature-1", res)
248-
res, err = dirRef.signaturePath(9, &dhex)
256+
assert.Equal(t, tmpDir+"/"+dhex256.Encoded()+".signature-1", res)
257+
res, err = dirRef.signaturePath(9, &dhex256)
249258
require.NoError(t, err)
250-
assert.Equal(t, tmpDir+"/"+dhex.Encoded()+".signature-10", res)
259+
assert.Equal(t, tmpDir+"/"+dhex256.Encoded()+".signature-10", res)
260+
261+
res, err = dirRef.signaturePath(0, &dhex512)
262+
require.NoError(t, err)
263+
assert.Equal(t, tmpDir+"/sha512-"+dhex512.Encoded()+".signature-1", res)
264+
res, err = dirRef.signaturePath(9, &dhex512)
265+
require.NoError(t, err)
266+
assert.Equal(t, tmpDir+"/sha512-"+dhex512.Encoded()+".signature-10", res)
267+
251268
invalidDigest := digest.Digest("sha256:../hello")
252269
_, err = dirRef.signaturePath(0, &invalidDigest)
253270
assert.Error(t, err)

0 commit comments

Comments
 (0)