Skip to content

Commit

Permalink
Merge pull request #915 from crazy-max/image-format
Browse files Browse the repository at this point in the history
image:tag@digest format support
  • Loading branch information
crazy-max committed Sep 16, 2023
2 parents ce3c66d + 061c976 commit 281e28e
Show file tree
Hide file tree
Showing 15 changed files with 398 additions and 29 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ jobs:
loglevel: info
- folder: dockerfile1
loglevel: debug
- folder: dockerfile2
loglevel: debug
steps:
-
name: Checkout
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ require (
github.com/crazy-max/cron/v3 v3.1.1
github.com/crazy-max/gohealthchecks v0.4.1
github.com/crazy-max/gonfig v0.7.1
github.com/docker/distribution v2.8.2+incompatible
github.com/docker/docker v24.0.6+incompatible
github.com/docker/go-connections v0.4.0
github.com/docker/go-units v0.5.0
Expand Down Expand Up @@ -68,7 +69,6 @@ require (
github.com/containers/ocicrypt v1.1.7 // indirect
github.com/containers/storage v1.48.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/docker-credential-helpers v0.7.0 // indirect
github.com/emicklei/go-restful/v3 v3.10.1 // indirect
github.com/felixge/fgprof v0.9.3 // indirect
Expand Down
4 changes: 1 addition & 3 deletions internal/provider/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,15 @@ func TestValidateImage(t *testing.T) {
expectedImage model.Image
expectedErr interface{}
}{
// Test strip sha
{
name: "Test strip sha",
name: "Test strip digest",
image: "myimg@sha256:1234567890abcdef",
watchByDef: true,
expectedImage: model.Image{
Name: "myimg",
},
expectedErr: nil,
},
// Test enable and watch by default
{
name: "All excluded by default",
image: "myimg",
Expand Down
6 changes: 6 additions & 0 deletions pkg/dockerfile/fixtures/valid.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,9 @@ COPY --from=crazymax/yasu / /
RUN --mount=type=bind,target=.,rw \
--mount=type=bind,from=crazymax/docker:20.10.6,source=/usr/local/bin/docker,target=/usr/bin/docker \
yasu --version

# diun.platform=linux/amd64
# diun.metadata.foo=bar
RUN --mount=type=bind,target=.,rw \
--mount=type=bind,from=crazymax/ddns-route53:foo@sha256:9cb3af44cdd00615266c87e60bc05cac534297be14c4596800b57322f9313615,source=/usr/local/bin/ddns-route53,target=/usr/local/bin/ddns-route53 \
ddns-route53 --version
6 changes: 5 additions & 1 deletion pkg/dockerfile/image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func TestFromImages(t *testing.T) {
img, err := c.FromImages()
require.NoError(t, err)
require.NotNil(t, img)
require.Equal(t, 3, len(img))
require.Equal(t, 4, len(img))

assert.Equal(t, "alpine:3.14", img[0].Name)
assert.Equal(t, 5, img[0].Line)
Expand All @@ -30,4 +30,8 @@ func TestFromImages(t *testing.T) {
assert.Equal(t, "crazymax/docker:20.10.6", img[2].Name)
assert.Equal(t, 15, img[2].Line)
assert.Equal(t, []string{"diun.watch_repo=true", "diun.include_tags=^\\d+\\.\\d+\\.\\d+$", "diun.platform=linux/amd64"}, img[2].Comments)

assert.Equal(t, "crazymax/ddns-route53:foo@sha256:9cb3af44cdd00615266c87e60bc05cac534297be14c4596800b57322f9313615", img[3].Name)
assert.Equal(t, 21, img[3].Line)
assert.Equal(t, []string{"diun.platform=linux/amd64", "diun.metadata.foo=bar"}, img[3].Comments)
}
12 changes: 12 additions & 0 deletions pkg/registry/image_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,18 @@ func TestParseImage(t *testing.T) {
Tag: "latest",
},
},
{
desc: "gcr busybox tag/digest",
parseOpts: ParseImageOptions{
Name: "gcr.io/google-containers/busybox:latest" + sha256digest,
},
expected: Image{
Domain: "gcr.io",
Path: "google-containers/busybox",
Tag: "latest",
Digest: sha256digest,
},
},
{
desc: "github ddns-route53",
parseOpts: ParseImageOptions{
Expand Down
15 changes: 10 additions & 5 deletions pkg/registry/manifest.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,20 @@ func (c *Client) Manifest(image Image, dbManifest Manifest) (Manifest, bool, err
ctx, cancel := c.timeoutContext()
defer cancel()

rmRef, err := ParseReference(image.String())
rmRef, err := ImageReference(image.String())
if err != nil {
return Manifest{}, false, errors.Wrap(err, "cannot parse reference")
}

// Retrieve remote digest through HEAD request
rmDigest, err := docker.GetDigest(ctx, c.sysCtx, rmRef)
if err != nil {
return Manifest{}, false, errors.Wrap(err, "cannot get image digest from HEAD request")
// Retrieve remote digest through HEAD request or get one from image reference
var rmDigest digest.Digest
if len(image.Digest) > 0 {
rmDigest = image.Digest
} else {
rmDigest, err = docker.GetDigest(ctx, c.sysCtx, rmRef)
if err != nil {
return Manifest{}, false, errors.Wrap(err, "cannot get image digest from HEAD request")
}
}

// Digest match, returns db manifest
Expand Down
235 changes: 235 additions & 0 deletions pkg/registry/manifest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ func TestCompareDigest(t *testing.T) {
t.Parallel()
rc, err := New(Options{
CompareDigest: true,
ImageOs: "linux",
ImageArch: "amd64",
})
if err != nil {
t.Error(err)
Expand All @@ -22,6 +24,11 @@ func TestCompareDigest(t *testing.T) {
t.Error(err)
}

// download manifest
_, _, err = rc.Manifest(img, Manifest{})
assert.NoError(t, err)

// check manifest
manifest, _, err := rc.Manifest(img, Manifest{
Name: "docker.io/crazymax/diun",
Tag: "2.5.0",
Expand Down Expand Up @@ -55,6 +62,11 @@ func TestManifest(t *testing.T) {
t.Error(err)
}

// download manifest
_, _, err = rc.Manifest(img, Manifest{})
assert.NoError(t, err)

// check manifest
manifest, updated, err := rc.Manifest(img, Manifest{
Name: "docker.io/portainer/portainer-ce",
Tag: "linux-amd64-2.5.1",
Expand Down Expand Up @@ -116,6 +128,11 @@ func TestManifestMultiUpdatedPlatform(t *testing.T) {
t.Error(err)
}

// download manifest
_, _, err = rc.Manifest(img, Manifest{})
assert.NoError(t, err)

// check manifest
manifest, updated, err := rc.Manifest(img, Manifest{
Name: "docker.io/library/mongo",
Tag: "3.6.21",
Expand Down Expand Up @@ -196,6 +213,11 @@ func TestManifestMultiNotUpdatedPlatform(t *testing.T) {
t.Error(err)
}

// download manifest
_, _, err = rc.Manifest(img, Manifest{})
assert.NoError(t, err)

// check manifest
manifest, updated, err := rc.Manifest(img, Manifest{
Name: "docker.io/library/mongo",
Tag: "3.6.21",
Expand Down Expand Up @@ -284,3 +306,216 @@ func TestManifestVariant(t *testing.T) {
assert.Equal(t, "linux/arm/v7", manifest.Platform)
assert.Empty(t, manifest.DockerVersion)
}

func TestManifestTaggedDigest(t *testing.T) {
rc, err := New(Options{
CompareDigest: true,
ImageOs: "linux",
ImageArch: "amd64",
})
if err != nil {
t.Error(err)
}

img, err := ParseImage(ParseImageOptions{
Name: "crazymax/diun:latest@sha256:3fca3dd86c2710586208b0f92d1ec4ce25382f4cad4ae76a2275db8e8bb24031",
})
if err != nil {
t.Error(err)
}

// download manifest
_, _, err = rc.Manifest(img, Manifest{})
assert.NoError(t, err)

// check manifest
manifest, updated, err := rc.Manifest(img, manifestCrazymaxDiun4250)
assert.NoError(t, err)
assert.Equal(t, false, updated)
assert.Equal(t, "docker.io/crazymax/diun", manifest.Name)
assert.Equal(t, "latest", manifest.Tag)
assert.Equal(t, "application/vnd.oci.image.index.v1+json", manifest.MIMEType)
assert.Equal(t, "sha256:3fca3dd86c2710586208b0f92d1ec4ce25382f4cad4ae76a2275db8e8bb24031", manifest.Digest.String())
assert.Equal(t, "linux/amd64", manifest.Platform)
}

func TestManifestTaggedDigestDummyTag(t *testing.T) {
rc, err := New(Options{
CompareDigest: true,
ImageOs: "linux",
ImageArch: "amd64",
})
if err != nil {
t.Error(err)
}

img, err := ParseImage(ParseImageOptions{
Name: "crazymax/diun:foo@sha256:3fca3dd86c2710586208b0f92d1ec4ce25382f4cad4ae76a2275db8e8bb24031",
})
if err != nil {
t.Error(err)
}

// download manifest
_, _, err = rc.Manifest(img, Manifest{})
assert.NoError(t, err)

// check manifest
manifest, updated, err := rc.Manifest(img, manifestCrazymaxDiun4250)
assert.NoError(t, err)
assert.Equal(t, false, updated)
assert.Equal(t, "docker.io/crazymax/diun", manifest.Name)
assert.Equal(t, "latest", manifest.Tag)
assert.Equal(t, "application/vnd.oci.image.index.v1+json", manifest.MIMEType)
assert.Equal(t, "sha256:3fca3dd86c2710586208b0f92d1ec4ce25382f4cad4ae76a2275db8e8bb24031", manifest.Digest.String())
assert.Equal(t, "linux/amd64", manifest.Platform)
}

var manifestCrazymaxDiun4250 = Manifest{
Name: "docker.io/crazymax/diun",
Tag: "latest",
MIMEType: "application/vnd.oci.image.index.v1+json",
Digest: "sha256:3fca3dd86c2710586208b0f92d1ec4ce25382f4cad4ae76a2275db8e8bb24031",
Platform: "linux/amd64",
Raw: []byte(`{
"schemaVersion": 2,
"mediaType": "application/vnd.oci.image.index.v1+json",
"digest": "sha256:3fca3dd86c2710586208b0f92d1ec4ce25382f4cad4ae76a2275db8e8bb24031",
"size": 4661,
"manifests": [
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:bf782d6b2030c2a4c6884abb603ec5c99b5394554f57d56972cea24fb5d545d5",
"size": 866,
"platform": {
"architecture": "386",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:f44444abd33ee7c088d7527af84e3321f08313d12d9c679327bb8ae228e35f6a",
"size": 866,
"platform": {
"architecture": "amd64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:df77b6ef88fbdb6175a2c60a9487a235aa1bdb39f60ee0a277d480d3cbc9f34a",
"size": 866,
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v6"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:73e210387511588b38d16046de4ade809404b746cf6d16cd51ca23a96c8264b7",
"size": 866,
"platform": {
"architecture": "arm",
"os": "linux",
"variant": "v7"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:1e070a6b2a3b5bf7c2c296fba6b01c8896514ae62aae6e48f4c28a775e5218dd",
"size": 866,
"platform": {
"architecture": "arm64",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:b7f984a85faf86839928fef6854f21da7afd2f2405b6043bf2aca562f1e1aa77",
"size": 866,
"platform": {
"architecture": "ppc64le",
"os": "linux"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:baa9a5e6de3f155526071eb0e55dcf14c12dca5c4301475e038df88fa5cb7c5a",
"size": 568,
"annotations": {
"vnd.docker.reference.digest": "sha256:bf782d6b2030c2a4c6884abb603ec5c99b5394554f57d56972cea24fb5d545d5",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
"architecture": "unknown",
"os": "unknown"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:422bcf3cad62b4d8b21593387759889bcef02c28d7b0a3f6866b98b6502e8f01",
"size": 568,
"annotations": {
"vnd.docker.reference.digest": "sha256:f44444abd33ee7c088d7527af84e3321f08313d12d9c679327bb8ae228e35f6a",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
"architecture": "unknown",
"os": "unknown"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:8ca5e335824bf17c10143c88f0e6955b5571dd69e06cd1a0ba46681169aa355d",
"size": 568,
"annotations": {
"vnd.docker.reference.digest": "sha256:df77b6ef88fbdb6175a2c60a9487a235aa1bdb39f60ee0a277d480d3cbc9f34a",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
"architecture": "unknown",
"os": "unknown"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:01fdd0609476fe4da74af6bcb5a4fff97b0f9efbbea6b6ab142371ecc0738ffd",
"size": 568,
"annotations": {
"vnd.docker.reference.digest": "sha256:73e210387511588b38d16046de4ade809404b746cf6d16cd51ca23a96c8264b7",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
"architecture": "unknown",
"os": "unknown"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:93178a24195f522195951a2cf16719bbae5358686b3789339c1096a85375117c",
"size": 568,
"annotations": {
"vnd.docker.reference.digest": "sha256:1e070a6b2a3b5bf7c2c296fba6b01c8896514ae62aae6e48f4c28a775e5218dd",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
"architecture": "unknown",
"os": "unknown"
}
},
{
"mediaType": "application/vnd.oci.image.manifest.v1+json",
"digest": "sha256:1f5e5456e6f236c03684fea8070ca4095092a1d07a186acb03b15d160d100043",
"size": 568,
"annotations": {
"vnd.docker.reference.digest": "sha256:b7f984a85faf86839928fef6854f21da7afd2f2405b6043bf2aca562f1e1aa77",
"vnd.docker.reference.type": "attestation-manifest"
},
"platform": {
"architecture": "unknown",
"os": "unknown"
}
}
]
}`)}

0 comments on commit 281e28e

Please sign in to comment.