refactor(digests): standardise representation of digests to digest.Digest (#898)

- Digests were represented by different ways
  - We needed a uniform way to represent the digests and enforce a format
  - also replace usage of github.com/google/go-containerregistry/pkg/v1
    with github.com/opencontainers/image-spec/specs-go/v1

Signed-off-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>
(cherry picked from commit 96b2f29d6d57070a913ce419149cd481c0723815)
(cherry picked from commit 3d41b583daea654c98378ce3dcb78937d71538e8)

Co-authored-by: Laurentiu Niculae <niculae.laurentiu1@gmail.com>
This commit is contained in:
Andrei Aaron
2022-10-22 23:46:13 +03:00
committed by GitHub
parent 5f99f9a445
commit ac6c6a844c
41 changed files with 970 additions and 952 deletions
+3 -7
View File
@@ -17,7 +17,6 @@ import (
"os"
"path/filepath"
"strconv"
"strings"
"sync"
"time"
@@ -272,11 +271,8 @@ func (p *requestsPool) doJob(ctx context.Context, job *manifestJob) {
p.outputCh <- stringResult{"", err}
}
digest := header.Get("docker-content-digest")
digest = strings.TrimPrefix(digest, "sha256:")
digestStr := header.Get("docker-content-digest")
configDigest := job.manifestResp.Config.Digest
configDigest = strings.TrimPrefix(configDigest, "sha256:")
var size uint64
@@ -289,7 +285,7 @@ func (p *requestsPool) doJob(ctx context.Context, job *manifestJob) {
layers,
layer{
Size: entry.Size,
Digest: strings.TrimPrefix(entry.Digest, "sha256:"),
Digest: entry.Digest,
},
)
}
@@ -298,7 +294,7 @@ func (p *requestsPool) doJob(ctx context.Context, job *manifestJob) {
image.verbose = *job.config.verbose
image.RepoName = job.imageName
image.Tag = job.tagName
image.Digest = digest
image.Digest = digestStr
image.Size = strconv.Itoa(int(size))
image.ConfigDigest = configDigest
image.Layers = layers
+4 -4
View File
@@ -183,7 +183,7 @@ func TestSearchCVECmd(t *testing.T) {
So(err, ShouldBeNil)
space := regexp.MustCompile(`\s+`)
str := space.ReplaceAllString(buff.String(), " ")
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE dummyImageName tag DigestsA false 123kB")
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE dummyImageName tag 6e2f80bf false 123kB")
Convey("using shorthand", func() {
args := []string{"cvetest", "-I", "dummyImageName", "--cve-id", "aCVEID", "--url", "someURL"}
buff := bytes.NewBufferString("")
@@ -197,7 +197,7 @@ func TestSearchCVECmd(t *testing.T) {
So(err, ShouldBeNil)
space := regexp.MustCompile(`\s+`)
str := space.ReplaceAllString(buff.String(), " ")
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE dummyImageName tag DigestsA false 123kB")
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE dummyImageName tag 6e2f80bf false 123kB")
})
})
@@ -281,7 +281,7 @@ func TestSearchCVECmd(t *testing.T) {
err := cveCmd.Execute()
space := regexp.MustCompile(`\s+`)
str := space.ReplaceAllString(buff.String(), " ")
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE anImage tag DigestsA false 123kB")
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE anImage tag 6e2f80bf false 123kB")
So(err, ShouldBeNil)
Convey("invalid CVE ID", func() {
@@ -326,7 +326,7 @@ func TestSearchCVECmd(t *testing.T) {
space := regexp.MustCompile(`\s+`)
str := space.ReplaceAllString(buff.String(), " ")
So(err, ShouldBeNil)
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE fixedImage tag DigestsA false 123kB")
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE fixedImage tag 6e2f80bf false 123kB")
Convey("invalid image name", func() {
args := []string{"cvetest", "--cve-id", "aCVEID", "--image", "invalidImageName"}
+174 -136
View File
@@ -187,7 +187,7 @@ func TestSearchImageCmd(t *testing.T) {
err := cmd.Execute()
space := regexp.MustCompile(`\s+`)
str := space.ReplaceAllString(buff.String(), " ")
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE dummyImageName tag DigestsA false 123kB")
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE dummyImageName tag 6e2f80bf false 123kB")
So(err, ShouldBeNil)
})
@@ -203,7 +203,7 @@ func TestSearchImageCmd(t *testing.T) {
err := imageCmd.Execute()
space := regexp.MustCompile(`\s+`)
str := space.ReplaceAllString(buff.String(), " ")
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE dummyImageName tag DigestsA false 123kB")
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE dummyImageName tag 6e2f80bf false 123kB")
So(err, ShouldBeNil)
Convey("using shorthand", func() {
args := []string{"imagetest", "-n", "dummyImageName", "--url", "someUrlImage"}
@@ -218,13 +218,13 @@ func TestSearchImageCmd(t *testing.T) {
space := regexp.MustCompile(`\s+`)
str := space.ReplaceAllString(buff.String(), " ")
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE dummyImageName tag DigestsA false 123kB")
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE dummyImageName tag 6e2f80bf false 123kB")
So(err, ShouldBeNil)
})
})
Convey("Test image by digest", t, func() {
args := []string{"imagetest", "--digest", "DigestsA", "--url", "someUrlImage"}
args := []string{"imagetest", "--digest", "6e2f80bf", "--url", "someUrlImage"}
configPath := makeConfigFile(`{"configs":[{"_name":"imagetest","showspinner":false}]}`)
defer os.Remove(configPath)
imageCmd := NewImageCommand(new(mockService))
@@ -235,7 +235,7 @@ func TestSearchImageCmd(t *testing.T) {
err := imageCmd.Execute()
space := regexp.MustCompile(`\s+`)
str := space.ReplaceAllString(buff.String(), " ")
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE anImage tag DigestsA false 123kB")
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE anImage tag 6e2f80bf false 123kB")
So(err, ShouldBeNil)
Convey("invalid URL format", func() {
@@ -385,42 +385,47 @@ func TestSignature(t *testing.T) {
//nolint:dupl
func TestDerivedImageList(t *testing.T) {
port := test.GetFreePort()
url := test.GetBaseURL(port)
conf := config.New()
conf.HTTP.Port = port
defaultVal := true
conf.Extensions = &extconf.ExtensionConfig{
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
}
ctlr := api.NewController(conf)
ctlr.Config.Storage.RootDirectory = t.TempDir()
go func(controller *api.Controller) {
// this blocks
if err := controller.Run(context.Background()); err != nil {
return
}
}(ctlr)
// wait till ready
for {
_, err := resty.R().Get(url)
if err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
defer func(controller *api.Controller) {
ctx := context.Background()
_ = controller.Server.Shutdown(ctx)
}(ctlr)
err := uploadManifest(url)
if err != nil {
panic(err)
}
t.Logf("rootDir: %s", ctlr.Config.Storage.RootDirectory)
Convey("Test from real server", t, func() {
port := test.GetFreePort()
url := test.GetBaseURL(port)
conf := config.New()
conf.HTTP.Port = port
defaultVal := true
conf.Extensions = &extconf.ExtensionConfig{
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
}
ctlr := api.NewController(conf)
ctlr.Config.Storage.RootDirectory = t.TempDir()
go func(controller *api.Controller) {
// this blocks
if err := controller.Run(context.Background()); err != nil {
return
}
}(ctlr)
// wait till ready
for {
_, err := resty.R().Get(url)
if err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
defer func(controller *api.Controller) {
ctx := context.Background()
_ = controller.Server.Shutdown(ctx)
}(ctlr)
err := uploadManifest(url)
So(err, ShouldBeNil)
t.Logf("rootDir: %s", ctlr.Config.Storage.RootDirectory)
Convey("Test derived images list working", func() {
t.Logf("%s", ctlr.Config.Storage.RootDirectory)
args := []string{"imagetest", "--derived-images", "repo7:test:1.0"}
@@ -479,42 +484,47 @@ func TestDerivedImageList(t *testing.T) {
//nolint:dupl
func TestBaseImageList(t *testing.T) {
port := test.GetFreePort()
url := test.GetBaseURL(port)
conf := config.New()
conf.HTTP.Port = port
defaultVal := true
conf.Extensions = &extconf.ExtensionConfig{
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
}
ctlr := api.NewController(conf)
ctlr.Config.Storage.RootDirectory = t.TempDir()
go func(controller *api.Controller) {
// this blocks
if err := controller.Run(context.Background()); err != nil {
return
}
}(ctlr)
// wait till ready
for {
_, err := resty.R().Get(url)
if err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
defer func(controller *api.Controller) {
ctx := context.Background()
_ = controller.Server.Shutdown(ctx)
}(ctlr)
err := uploadManifest(url)
if err != nil {
panic(err)
}
t.Logf("rootDir: %s", ctlr.Config.Storage.RootDirectory)
Convey("Test from real server", t, func() {
port := test.GetFreePort()
url := test.GetBaseURL(port)
conf := config.New()
conf.HTTP.Port = port
defaultVal := true
conf.Extensions = &extconf.ExtensionConfig{
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
}
ctlr := api.NewController(conf)
ctlr.Config.Storage.RootDirectory = t.TempDir()
go func(controller *api.Controller) {
// this blocks
if err := controller.Run(context.Background()); err != nil {
return
}
}(ctlr)
// wait till ready
for {
_, err := resty.R().Get(url)
if err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
defer func(controller *api.Controller) {
ctx := context.Background()
_ = controller.Server.Shutdown(ctx)
}(ctlr)
err := uploadManifest(url)
So(err, ShouldBeNil)
t.Logf("rootDir: %s", ctlr.Config.Storage.RootDirectory)
Convey("Test base images list working", func() {
t.Logf("%s", ctlr.Config.Storage.RootDirectory)
args := []string{"imagetest", "--base-images", "repo7:test:1.0"}
@@ -727,7 +737,7 @@ func TestOutputFormat(t *testing.T) {
err := cmd.Execute()
space := regexp.MustCompile(`\s+`)
str := space.ReplaceAllString(buff.String(), " ")
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE dummyImageName tag DigestsA false 123kB")
So(strings.TrimSpace(str), ShouldEqual, "IMAGE NAME TAG DIGEST SIGNED SIZE dummyImageName tag 6e2f80bf false 123kB")
So(err, ShouldBeNil)
})
@@ -746,7 +756,11 @@ func TestOutputFormat(t *testing.T) {
space := regexp.MustCompile(`\s+`)
str := space.ReplaceAllString(buff.String(), " ")
So(strings.TrimSpace(str), ShouldEqual, `{ "repoName": "dummyImageName", "tag": "tag", `+
`"configDigest": "", "digest": "DigestsAreReallyLong", "layers": null, "size": "123445", "isSigned": false }`)
`"configDigest": "sha256:4c10985c40365538426f2ba8cf0c21384a7769be502a550dcc0601b3736625e0", `+
`"digest": "sha256:6e2f80bf9cfaabad474fbaf8ad68fdb652f776ea80b63492ecca404e5f6446a6", `+
`"layers": [ { "size": "0", `+
`"digest": "sha256:c122a146f0d02349be211bb95cc2530f4a5793f96edbdfa00860f741e5d8c0e6" } ], `+
`"size": "123445", "isSigned": false }`)
So(err, ShouldBeNil)
})
@@ -765,9 +779,11 @@ func TestOutputFormat(t *testing.T) {
So(
strings.TrimSpace(str),
ShouldEqual,
`reponame: dummyImageName tag: tag configdigest: "" `+
`digest: DigestsAreReallyLong layers: [] size: "123445" `+
`issigned: false`,
`reponame: dummyImageName tag: tag `+
`configdigest: sha256:4c10985c40365538426f2ba8cf0c21384a7769be502a550dcc0601b3736625e0 `+
`digest: sha256:6e2f80bf9cfaabad474fbaf8ad68fdb652f776ea80b63492ecca404e5f6446a6 `+
`layers: - size: 0 digest: sha256:c122a146f0d02349be211bb95cc2530f4a5793f96edbdfa00860f741e5d8c0e6 `+
`size: "123445" issigned: false`,
)
So(err, ShouldBeNil)
@@ -789,9 +805,11 @@ func TestOutputFormat(t *testing.T) {
So(
strings.TrimSpace(str),
ShouldEqual,
`reponame: dummyImageName tag: tag configdigest: "" `+
`digest: DigestsAreReallyLong layers: [] size: "123445" `+
`issigned: false`,
`reponame: dummyImageName tag: tag `+
`configdigest: sha256:4c10985c40365538426f2ba8cf0c21384a7769be502a550dcc0601b3736625e0 `+
`digest: sha256:6e2f80bf9cfaabad474fbaf8ad68fdb652f776ea80b63492ecca404e5f6446a6 `+
`layers: - size: 0 digest: sha256:c122a146f0d02349be211bb95cc2530f4a5793f96edbdfa00860f741e5d8c0e6 `+
`size: "123445" issigned: false`,
)
So(err, ShouldBeNil)
})
@@ -1086,41 +1104,47 @@ func TestServerResponseGQL(t *testing.T) {
}
func TestServerResponse(t *testing.T) {
port := test.GetFreePort()
url := test.GetBaseURL(port)
conf := config.New()
conf.HTTP.Port = port
defaultVal := true
conf.Extensions = &extconf.ExtensionConfig{
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
}
ctlr := api.NewController(conf)
ctlr.Config.Storage.RootDirectory = t.TempDir()
go func(controller *api.Controller) {
// this blocks
if err := controller.Run(context.Background()); err != nil {
return
}
}(ctlr)
// wait till ready
for {
_, err := resty.R().Get(url)
if err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
defer func(controller *api.Controller) {
ctx := context.Background()
_ = controller.Server.Shutdown(ctx)
}(ctlr)
err := uploadManifest(url)
if err != nil {
panic(err)
}
t.Logf("%s", ctlr.Config.Storage.RootDirectory)
Convey("Test from real server", t, func() {
port := test.GetFreePort()
url := test.GetBaseURL(port)
conf := config.New()
conf.HTTP.Port = port
defaultVal := true
conf.Extensions = &extconf.ExtensionConfig{
Search: &extconf.SearchConfig{BaseConfig: extconf.BaseConfig{Enable: &defaultVal}},
}
ctlr := api.NewController(conf)
ctlr.Config.Storage.RootDirectory = t.TempDir()
go func(controller *api.Controller) {
// this blocks
if err := controller.Run(context.Background()); err != nil {
return
}
}(ctlr)
// wait till ready
for {
_, err := resty.R().Get(url)
if err == nil {
break
}
time.Sleep(100 * time.Millisecond)
}
defer func(controller *api.Controller) {
ctx := context.Background()
_ = controller.Server.Shutdown(ctx)
}(ctlr)
err := uploadManifest(url)
t.Logf("%s", ctlr.Config.Storage.RootDirectory)
So(err, ShouldBeNil)
Convey("Test all images", func() {
t.Logf("%s", ctlr.Config.Storage.RootDirectory)
args := []string{"imagetest"}
@@ -1555,10 +1579,12 @@ func (service mockService) getDerivedImageListGQL(ctx context.Context, config se
imageListGQLResponse := &imageListStructForDerivedImagesGQL{}
imageListGQLResponse.Data.ImageList = []imageStruct{
{
RepoName: "dummyImageName",
Tag: "tag",
Digest: "DigestsAreReallyLong",
Size: "123445",
RepoName: "dummyImageName",
Tag: "tag",
Digest: godigest.FromString("Digest").String(),
ConfigDigest: godigest.FromString("ConfigDigest").String(),
Size: "123445",
Layers: []layer{{Digest: godigest.FromString("LayerDigest").String()}},
},
}
@@ -1571,10 +1597,12 @@ func (service mockService) getBaseImageListGQL(ctx context.Context, config searc
imageListGQLResponse := &imageListStructForBaseImagesGQL{}
imageListGQLResponse.Data.ImageList = []imageStruct{
{
RepoName: "dummyImageName",
Tag: "tag",
Digest: "DigestsAreReallyLong",
Size: "123445",
RepoName: "dummyImageName",
Tag: "tag",
Digest: godigest.FromString("Digest").String(),
ConfigDigest: godigest.FromString("ConfigDigest").String(),
Size: "123445",
Layers: []layer{{Digest: godigest.FromString("LayerDigest").String()}},
},
}
@@ -1587,10 +1615,12 @@ func (service mockService) getImagesGQL(ctx context.Context, config searchConfig
imageListGQLResponse := &imageListStructGQL{}
imageListGQLResponse.Data.ImageList = []imageStruct{
{
RepoName: "dummyImageName",
Tag: "tag",
Digest: "DigestsAreReallyLong",
Size: "123445",
RepoName: "dummyImageName",
Tag: "tag",
Digest: godigest.FromString("Digest").String(),
ConfigDigest: godigest.FromString("ConfigDigest").String(),
Size: "123445",
Layers: []layer{{Digest: godigest.FromString("LayerDigest").String()}},
},
}
@@ -1603,10 +1633,12 @@ func (service mockService) getImagesByDigestGQL(ctx context.Context, config sear
imageListGQLResponse := &imageListStructForDigestGQL{}
imageListGQLResponse.Data.ImageList = []imageStruct{
{
RepoName: "randomimageName",
Tag: "tag",
Digest: "DigestsAreReallyLong",
Size: "123445",
RepoName: "randomimageName",
Tag: "tag",
Digest: godigest.FromString("Digest").String(),
ConfigDigest: godigest.FromString("ConfigDigest").String(),
Size: "123445",
Layers: []layer{{Digest: godigest.FromString("LayerDigest").String()}},
},
}
@@ -1700,8 +1732,10 @@ func (service mockService) getMockedImageByName(imageName string) imageStruct {
image := imageStruct{}
image.RepoName = imageName
image.Tag = "tag"
image.Digest = "DigestsAreReallyLong"
image.Digest = godigest.FromString("Digest").String()
image.ConfigDigest = godigest.FromString("ConfigDigest").String()
image.Size = "123445"
image.Layers = []layer{{Digest: godigest.FromString("LayerDigest").String()}}
return image
}
@@ -1715,8 +1749,10 @@ func (service mockService) getAllImages(ctx context.Context, config searchConfig
image := &imageStruct{}
image.RepoName = "randomimageName"
image.Tag = "tag"
image.Digest = "DigestsAreReallyLong"
image.Digest = godigest.FromString("Digest").String()
image.ConfigDigest = godigest.FromString("ConfigDigest").String()
image.Size = "123445"
image.Layers = []layer{{Digest: godigest.FromString("LayerDigest").String()}}
str, err := image.string(*config.outputFormat, len(image.RepoName), len(image.Tag))
if err != nil {
@@ -1737,8 +1773,10 @@ func (service mockService) getImageByName(ctx context.Context, config searchConf
image := &imageStruct{}
image.RepoName = imageName
image.Tag = "tag"
image.Digest = "DigestsAreReallyLong"
image.Digest = godigest.FromString("Digest").String()
image.ConfigDigest = godigest.FromString("ConfigDigest").String()
image.Size = "123445"
image.Layers = []layer{{Digest: godigest.FromString("LayerDigest").String()}}
str, err := image.string(*config.outputFormat, len(image.RepoName), len(image.Tag))
if err != nil {
+31 -11
View File
@@ -16,6 +16,7 @@ import (
"github.com/dustin/go-humanize"
jsoniter "github.com/json-iterator/go"
"github.com/olekukonko/tablewriter"
godigest "github.com/opencontainers/go-digest"
"gopkg.in/yaml.v2"
zotErrors "zotregistry.io/zot/errors"
@@ -74,6 +75,7 @@ func (service searchService) getDerivedImageListGQL(ctx context.Context, config
Tag,
Digest,
ConfigDigest,
Layers {Size Digest},
LastUpdated,
IsSigned,
Size
@@ -100,6 +102,7 @@ func (service searchService) getBaseImageListGQL(ctx context.Context, config sea
Tag,
Digest,
ConfigDigest,
Layers {Size Digest},
LastUpdated,
IsSigned,
Size
@@ -156,7 +159,7 @@ func (service searchService) getImagesByCveIDGQL(ctx context.Context, config sea
password, cveID string,
) (*imagesForCve, error) {
query := fmt.Sprintf(`{ImageListForCVE(id: "%s") {`+`
RepoName Tag Digest Size}
RepoName Tag Digest ConfigDigest Layers {Size Digest} Size}
}`,
cveID)
result := &imagesForCve{}
@@ -193,7 +196,7 @@ func (service searchService) getTagsForCVEGQL(ctx context.Context, config search
username, password, imageName, cveID string,
) (*imagesForCve, error) {
query := fmt.Sprintf(`{ImageListForCVE(id: "%s") {`+`
RepoName Tag Digest Size}
RepoName Tag Digest ConfigDigest Layers {Size Digest} Size}
}`,
cveID)
result := &imagesForCve{}
@@ -211,7 +214,7 @@ func (service searchService) getFixedTagsForCVEGQL(ctx context.Context, config s
username, password, imageName, cveID string,
) (*fixedTags, error) {
query := fmt.Sprintf(`{ImageListWithCVEFixed(id: "%s", image: "%s") {`+`
RepoName Tag Digest Size}
RepoName Tag Digest ConfigDigest Layers {Size Digest} Size}
}`,
cveID, imageName)
@@ -334,7 +337,7 @@ func (service searchService) getImagesByCveID(ctx context.Context, config search
defer close(rch)
query := fmt.Sprintf(`{ImageListForCVE(id: "%s") {`+`
RepoName Tag Digest Size}
RepoName Tag Digest ConfigDigest Layers {Size Digest} Size}
}`,
cvid)
result := &imagesForCve{}
@@ -551,7 +554,7 @@ func (service searchService) getFixedTagsForCVE(ctx context.Context, config sear
defer close(rch)
query := fmt.Sprintf(`{ImageListWithCVEFixed (id: "%s", image: "%s") {`+`
RepoName Tag Digest Size}
RepoName Tag Digest ConfigDigest Layers {Size Digest} Size}
}`,
cvid, imageName)
result := &fixedTags{}
@@ -924,21 +927,32 @@ func (img imageStruct) stringPlainText(maxImgNameLen, maxTagLen int) (string, er
imageName = img.RepoName
tagName = img.Tag
digest := ellipsize(img.Digest, digestWidth, "")
manifestDigest, err := godigest.Parse(img.Digest)
if err != nil {
return "", fmt.Errorf("error parsing manifest digest %s: %w", img.Digest, err)
}
configDigest, err := godigest.Parse(img.ConfigDigest)
if err != nil {
return "", fmt.Errorf("error parsing config digest %s: %w", img.ConfigDigest, err)
}
minifestDigestStr := ellipsize(manifestDigest.Encoded(), digestWidth, "")
configDigestStr := ellipsize(configDigest.Encoded(), configWidth, "")
imgSize, _ := strconv.ParseUint(img.Size, 10, 64)
size := ellipsize(strings.ReplaceAll(humanize.Bytes(imgSize), " ", ""), sizeWidth, ellipsis)
config := ellipsize(img.ConfigDigest, configWidth, "")
isSigned := img.IsSigned
row := make([]string, 7) //nolint:gomnd
row[colImageNameIndex] = imageName
row[colTagIndex] = tagName
row[colDigestIndex] = digest
row[colDigestIndex] = minifestDigestStr
row[colSizeIndex] = size
row[colIsSignedIndex] = strconv.FormatBool(isSigned)
if img.verbose {
row[colConfigIndex] = config
row[colConfigIndex] = configDigestStr
row[colLayersIndex] = ""
}
@@ -948,7 +962,13 @@ func (img imageStruct) stringPlainText(maxImgNameLen, maxTagLen int) (string, er
for _, entry := range img.Layers {
layerSize := entry.Size
size := ellipsize(strings.ReplaceAll(humanize.Bytes(layerSize), " ", ""), sizeWidth, ellipsis)
layerDigest := ellipsize(entry.Digest, digestWidth, "")
layerDigest, err := godigest.Parse(entry.Digest)
if err != nil {
return "", fmt.Errorf("error parsing layer digest %s: %w", entry.Digest, err)
}
layerDigestStr := ellipsize(layerDigest.Encoded(), digestWidth, "")
layerRow := make([]string, 7) //nolint:gomnd
layerRow[colImageNameIndex] = ""
@@ -956,7 +976,7 @@ func (img imageStruct) stringPlainText(maxImgNameLen, maxTagLen int) (string, er
layerRow[colDigestIndex] = ""
layerRow[colSizeIndex] = size
layerRow[colConfigIndex] = ""
layerRow[colLayersIndex] = layerDigest
layerRow[colLayersIndex] = layerDigestStr
table.Append(layerRow)
}