Skip to content

Commit 061c976

Browse files
committed
image:tag@digest format support
1 parent 78879b3 commit 061c976

File tree

14 files changed

+397
-26
lines changed

14 files changed

+397
-26
lines changed

.github/workflows/e2e.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ jobs:
4747
loglevel: info
4848
- folder: dockerfile1
4949
loglevel: debug
50+
- folder: dockerfile2
51+
loglevel: debug
5052
steps:
5153
-
5254
name: Checkout

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ require (
1111
github.com/crazy-max/cron/v3 v3.1.1
1212
github.com/crazy-max/gohealthchecks v0.4.1
1313
github.com/crazy-max/gonfig v0.7.1
14+
github.com/docker/distribution v2.8.2+incompatible
1415
github.com/docker/docker v24.0.6+incompatible
1516
github.com/docker/go-connections v0.4.0
1617
github.com/docker/go-units v0.5.0
@@ -68,7 +69,6 @@ require (
6869
github.com/containers/ocicrypt v1.1.7 // indirect
6970
github.com/containers/storage v1.48.0 // indirect
7071
github.com/davecgh/go-spew v1.1.1 // indirect
71-
github.com/docker/distribution v2.8.2+incompatible // indirect
7272
github.com/docker/docker-credential-helpers v0.7.0 // indirect
7373
github.com/emicklei/go-restful/v3 v3.10.1 // indirect
7474
github.com/felixge/fgprof v0.9.3 // indirect

pkg/dockerfile/fixtures/valid.Dockerfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,9 @@ COPY --from=crazymax/yasu / /
1515
RUN --mount=type=bind,target=.,rw \
1616
--mount=type=bind,from=crazymax/docker:20.10.6,source=/usr/local/bin/docker,target=/usr/bin/docker \
1717
yasu --version
18+
19+
# diun.platform=linux/amd64
20+
# diun.metadata.foo=bar
21+
RUN --mount=type=bind,target=.,rw \
22+
--mount=type=bind,from=crazymax/ddns-route53:foo@sha256:9cb3af44cdd00615266c87e60bc05cac534297be14c4596800b57322f9313615,source=/usr/local/bin/ddns-route53,target=/usr/local/bin/ddns-route53 \
23+
ddns-route53 --version

pkg/dockerfile/image_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func TestFromImages(t *testing.T) {
1717
img, err := c.FromImages()
1818
require.NoError(t, err)
1919
require.NotNil(t, img)
20-
require.Equal(t, 3, len(img))
20+
require.Equal(t, 4, len(img))
2121

2222
assert.Equal(t, "alpine:3.14", img[0].Name)
2323
assert.Equal(t, 5, img[0].Line)
@@ -30,4 +30,8 @@ func TestFromImages(t *testing.T) {
3030
assert.Equal(t, "crazymax/docker:20.10.6", img[2].Name)
3131
assert.Equal(t, 15, img[2].Line)
3232
assert.Equal(t, []string{"diun.watch_repo=true", "diun.include_tags=^\\d+\\.\\d+\\.\\d+$", "diun.platform=linux/amd64"}, img[2].Comments)
33+
34+
assert.Equal(t, "crazymax/ddns-route53:foo@sha256:9cb3af44cdd00615266c87e60bc05cac534297be14c4596800b57322f9313615", img[3].Name)
35+
assert.Equal(t, 21, img[3].Line)
36+
assert.Equal(t, []string{"diun.platform=linux/amd64", "diun.metadata.foo=bar"}, img[3].Comments)
3337
}

pkg/registry/image_test.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,18 @@ func TestParseImage(t *testing.T) {
6767
Tag: "latest",
6868
},
6969
},
70+
{
71+
desc: "gcr busybox tag/digest",
72+
parseOpts: ParseImageOptions{
73+
Name: "gcr.io/google-containers/busybox:latest" + sha256digest,
74+
},
75+
expected: Image{
76+
Domain: "gcr.io",
77+
Path: "google-containers/busybox",
78+
Tag: "latest",
79+
Digest: sha256digest,
80+
},
81+
},
7082
{
7183
desc: "github ddns-route53",
7284
parseOpts: ParseImageOptions{

pkg/registry/manifest.go

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,20 @@ func (c *Client) Manifest(image Image, dbManifest Manifest) (Manifest, bool, err
3030
ctx, cancel := c.timeoutContext()
3131
defer cancel()
3232

33-
rmRef, err := ParseReference(image.String())
33+
rmRef, err := ImageReference(image.String())
3434
if err != nil {
3535
return Manifest{}, false, errors.Wrap(err, "cannot parse reference")
3636
}
3737

38-
// Retrieve remote digest through HEAD request
39-
rmDigest, err := docker.GetDigest(ctx, c.sysCtx, rmRef)
40-
if err != nil {
41-
return Manifest{}, false, errors.Wrap(err, "cannot get image digest from HEAD request")
38+
// Retrieve remote digest through HEAD request or get one from image reference
39+
var rmDigest digest.Digest
40+
if len(image.Digest) > 0 {
41+
rmDigest = image.Digest
42+
} else {
43+
rmDigest, err = docker.GetDigest(ctx, c.sysCtx, rmRef)
44+
if err != nil {
45+
return Manifest{}, false, errors.Wrap(err, "cannot get image digest from HEAD request")
46+
}
4247
}
4348

4449
// Digest match, returns db manifest

pkg/registry/manifest_test.go

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ func TestCompareDigest(t *testing.T) {
1010
t.Parallel()
1111
rc, err := New(Options{
1212
CompareDigest: true,
13+
ImageOs: "linux",
14+
ImageArch: "amd64",
1315
})
1416
if err != nil {
1517
t.Error(err)
@@ -22,6 +24,11 @@ func TestCompareDigest(t *testing.T) {
2224
t.Error(err)
2325
}
2426

27+
// download manifest
28+
_, _, err = rc.Manifest(img, Manifest{})
29+
assert.NoError(t, err)
30+
31+
// check manifest
2532
manifest, _, err := rc.Manifest(img, Manifest{
2633
Name: "docker.io/crazymax/diun",
2734
Tag: "2.5.0",
@@ -55,6 +62,11 @@ func TestManifest(t *testing.T) {
5562
t.Error(err)
5663
}
5764

65+
// download manifest
66+
_, _, err = rc.Manifest(img, Manifest{})
67+
assert.NoError(t, err)
68+
69+
// check manifest
5870
manifest, updated, err := rc.Manifest(img, Manifest{
5971
Name: "docker.io/portainer/portainer-ce",
6072
Tag: "linux-amd64-2.5.1",
@@ -116,6 +128,11 @@ func TestManifestMultiUpdatedPlatform(t *testing.T) {
116128
t.Error(err)
117129
}
118130

131+
// download manifest
132+
_, _, err = rc.Manifest(img, Manifest{})
133+
assert.NoError(t, err)
134+
135+
// check manifest
119136
manifest, updated, err := rc.Manifest(img, Manifest{
120137
Name: "docker.io/library/mongo",
121138
Tag: "3.6.21",
@@ -196,6 +213,11 @@ func TestManifestMultiNotUpdatedPlatform(t *testing.T) {
196213
t.Error(err)
197214
}
198215

216+
// download manifest
217+
_, _, err = rc.Manifest(img, Manifest{})
218+
assert.NoError(t, err)
219+
220+
// check manifest
199221
manifest, updated, err := rc.Manifest(img, Manifest{
200222
Name: "docker.io/library/mongo",
201223
Tag: "3.6.21",
@@ -284,3 +306,216 @@ func TestManifestVariant(t *testing.T) {
284306
assert.Equal(t, "linux/arm/v7", manifest.Platform)
285307
assert.Empty(t, manifest.DockerVersion)
286308
}
309+
310+
func TestManifestTaggedDigest(t *testing.T) {
311+
rc, err := New(Options{
312+
CompareDigest: true,
313+
ImageOs: "linux",
314+
ImageArch: "amd64",
315+
})
316+
if err != nil {
317+
t.Error(err)
318+
}
319+
320+
img, err := ParseImage(ParseImageOptions{
321+
Name: "crazymax/diun:latest@sha256:3fca3dd86c2710586208b0f92d1ec4ce25382f4cad4ae76a2275db8e8bb24031",
322+
})
323+
if err != nil {
324+
t.Error(err)
325+
}
326+
327+
// download manifest
328+
_, _, err = rc.Manifest(img, Manifest{})
329+
assert.NoError(t, err)
330+
331+
// check manifest
332+
manifest, updated, err := rc.Manifest(img, manifestCrazymaxDiun4250)
333+
assert.NoError(t, err)
334+
assert.Equal(t, false, updated)
335+
assert.Equal(t, "docker.io/crazymax/diun", manifest.Name)
336+
assert.Equal(t, "latest", manifest.Tag)
337+
assert.Equal(t, "application/vnd.oci.image.index.v1+json", manifest.MIMEType)
338+
assert.Equal(t, "sha256:3fca3dd86c2710586208b0f92d1ec4ce25382f4cad4ae76a2275db8e8bb24031", manifest.Digest.String())
339+
assert.Equal(t, "linux/amd64", manifest.Platform)
340+
}
341+
342+
func TestManifestTaggedDigestDummyTag(t *testing.T) {
343+
rc, err := New(Options{
344+
CompareDigest: true,
345+
ImageOs: "linux",
346+
ImageArch: "amd64",
347+
})
348+
if err != nil {
349+
t.Error(err)
350+
}
351+
352+
img, err := ParseImage(ParseImageOptions{
353+
Name: "crazymax/diun:foo@sha256:3fca3dd86c2710586208b0f92d1ec4ce25382f4cad4ae76a2275db8e8bb24031",
354+
})
355+
if err != nil {
356+
t.Error(err)
357+
}
358+
359+
// download manifest
360+
_, _, err = rc.Manifest(img, Manifest{})
361+
assert.NoError(t, err)
362+
363+
// check manifest
364+
manifest, updated, err := rc.Manifest(img, manifestCrazymaxDiun4250)
365+
assert.NoError(t, err)
366+
assert.Equal(t, false, updated)
367+
assert.Equal(t, "docker.io/crazymax/diun", manifest.Name)
368+
assert.Equal(t, "latest", manifest.Tag)
369+
assert.Equal(t, "application/vnd.oci.image.index.v1+json", manifest.MIMEType)
370+
assert.Equal(t, "sha256:3fca3dd86c2710586208b0f92d1ec4ce25382f4cad4ae76a2275db8e8bb24031", manifest.Digest.String())
371+
assert.Equal(t, "linux/amd64", manifest.Platform)
372+
}
373+
374+
var manifestCrazymaxDiun4250 = Manifest{
375+
Name: "docker.io/crazymax/diun",
376+
Tag: "latest",
377+
MIMEType: "application/vnd.oci.image.index.v1+json",
378+
Digest: "sha256:3fca3dd86c2710586208b0f92d1ec4ce25382f4cad4ae76a2275db8e8bb24031",
379+
Platform: "linux/amd64",
380+
Raw: []byte(`{
381+
"schemaVersion": 2,
382+
"mediaType": "application/vnd.oci.image.index.v1+json",
383+
"digest": "sha256:3fca3dd86c2710586208b0f92d1ec4ce25382f4cad4ae76a2275db8e8bb24031",
384+
"size": 4661,
385+
"manifests": [
386+
{
387+
"mediaType": "application/vnd.oci.image.manifest.v1+json",
388+
"digest": "sha256:bf782d6b2030c2a4c6884abb603ec5c99b5394554f57d56972cea24fb5d545d5",
389+
"size": 866,
390+
"platform": {
391+
"architecture": "386",
392+
"os": "linux"
393+
}
394+
},
395+
{
396+
"mediaType": "application/vnd.oci.image.manifest.v1+json",
397+
"digest": "sha256:f44444abd33ee7c088d7527af84e3321f08313d12d9c679327bb8ae228e35f6a",
398+
"size": 866,
399+
"platform": {
400+
"architecture": "amd64",
401+
"os": "linux"
402+
}
403+
},
404+
{
405+
"mediaType": "application/vnd.oci.image.manifest.v1+json",
406+
"digest": "sha256:df77b6ef88fbdb6175a2c60a9487a235aa1bdb39f60ee0a277d480d3cbc9f34a",
407+
"size": 866,
408+
"platform": {
409+
"architecture": "arm",
410+
"os": "linux",
411+
"variant": "v6"
412+
}
413+
},
414+
{
415+
"mediaType": "application/vnd.oci.image.manifest.v1+json",
416+
"digest": "sha256:73e210387511588b38d16046de4ade809404b746cf6d16cd51ca23a96c8264b7",
417+
"size": 866,
418+
"platform": {
419+
"architecture": "arm",
420+
"os": "linux",
421+
"variant": "v7"
422+
}
423+
},
424+
{
425+
"mediaType": "application/vnd.oci.image.manifest.v1+json",
426+
"digest": "sha256:1e070a6b2a3b5bf7c2c296fba6b01c8896514ae62aae6e48f4c28a775e5218dd",
427+
"size": 866,
428+
"platform": {
429+
"architecture": "arm64",
430+
"os": "linux"
431+
}
432+
},
433+
{
434+
"mediaType": "application/vnd.oci.image.manifest.v1+json",
435+
"digest": "sha256:b7f984a85faf86839928fef6854f21da7afd2f2405b6043bf2aca562f1e1aa77",
436+
"size": 866,
437+
"platform": {
438+
"architecture": "ppc64le",
439+
"os": "linux"
440+
}
441+
},
442+
{
443+
"mediaType": "application/vnd.oci.image.manifest.v1+json",
444+
"digest": "sha256:baa9a5e6de3f155526071eb0e55dcf14c12dca5c4301475e038df88fa5cb7c5a",
445+
"size": 568,
446+
"annotations": {
447+
"vnd.docker.reference.digest": "sha256:bf782d6b2030c2a4c6884abb603ec5c99b5394554f57d56972cea24fb5d545d5",
448+
"vnd.docker.reference.type": "attestation-manifest"
449+
},
450+
"platform": {
451+
"architecture": "unknown",
452+
"os": "unknown"
453+
}
454+
},
455+
{
456+
"mediaType": "application/vnd.oci.image.manifest.v1+json",
457+
"digest": "sha256:422bcf3cad62b4d8b21593387759889bcef02c28d7b0a3f6866b98b6502e8f01",
458+
"size": 568,
459+
"annotations": {
460+
"vnd.docker.reference.digest": "sha256:f44444abd33ee7c088d7527af84e3321f08313d12d9c679327bb8ae228e35f6a",
461+
"vnd.docker.reference.type": "attestation-manifest"
462+
},
463+
"platform": {
464+
"architecture": "unknown",
465+
"os": "unknown"
466+
}
467+
},
468+
{
469+
"mediaType": "application/vnd.oci.image.manifest.v1+json",
470+
"digest": "sha256:8ca5e335824bf17c10143c88f0e6955b5571dd69e06cd1a0ba46681169aa355d",
471+
"size": 568,
472+
"annotations": {
473+
"vnd.docker.reference.digest": "sha256:df77b6ef88fbdb6175a2c60a9487a235aa1bdb39f60ee0a277d480d3cbc9f34a",
474+
"vnd.docker.reference.type": "attestation-manifest"
475+
},
476+
"platform": {
477+
"architecture": "unknown",
478+
"os": "unknown"
479+
}
480+
},
481+
{
482+
"mediaType": "application/vnd.oci.image.manifest.v1+json",
483+
"digest": "sha256:01fdd0609476fe4da74af6bcb5a4fff97b0f9efbbea6b6ab142371ecc0738ffd",
484+
"size": 568,
485+
"annotations": {
486+
"vnd.docker.reference.digest": "sha256:73e210387511588b38d16046de4ade809404b746cf6d16cd51ca23a96c8264b7",
487+
"vnd.docker.reference.type": "attestation-manifest"
488+
},
489+
"platform": {
490+
"architecture": "unknown",
491+
"os": "unknown"
492+
}
493+
},
494+
{
495+
"mediaType": "application/vnd.oci.image.manifest.v1+json",
496+
"digest": "sha256:93178a24195f522195951a2cf16719bbae5358686b3789339c1096a85375117c",
497+
"size": 568,
498+
"annotations": {
499+
"vnd.docker.reference.digest": "sha256:1e070a6b2a3b5bf7c2c296fba6b01c8896514ae62aae6e48f4c28a775e5218dd",
500+
"vnd.docker.reference.type": "attestation-manifest"
501+
},
502+
"platform": {
503+
"architecture": "unknown",
504+
"os": "unknown"
505+
}
506+
},
507+
{
508+
"mediaType": "application/vnd.oci.image.manifest.v1+json",
509+
"digest": "sha256:1f5e5456e6f236c03684fea8070ca4095092a1d07a186acb03b15d160d100043",
510+
"size": 568,
511+
"annotations": {
512+
"vnd.docker.reference.digest": "sha256:b7f984a85faf86839928fef6854f21da7afd2f2405b6043bf2aca562f1e1aa77",
513+
"vnd.docker.reference.type": "attestation-manifest"
514+
},
515+
"platform": {
516+
"architecture": "unknown",
517+
"os": "unknown"
518+
}
519+
}
520+
]
521+
}`)}

0 commit comments

Comments
 (0)