mirror of
https://github.com/project-zot/zot.git
synced 2026-06-17 12:58:02 +08:00
fix(digests): do not mandate sha256 as the only algorithm used for hashing blobs (#2075)
Signed-off-by: Andrei Aaron <aaaron@luxoft.com>
This commit is contained in:
@@ -88,9 +88,10 @@ type ManifestBuilder interface {
|
||||
}
|
||||
|
||||
type Image struct {
|
||||
Manifest ispec.Manifest
|
||||
Config ispec.Image
|
||||
Layers [][]byte
|
||||
Manifest ispec.Manifest
|
||||
Config ispec.Image
|
||||
Layers [][]byte
|
||||
digestAlgorithm godigest.Algorithm
|
||||
|
||||
ConfigDescriptor ispec.Descriptor
|
||||
ManifestDescriptor ispec.Descriptor
|
||||
@@ -108,13 +109,28 @@ func (img *Image) Digest() godigest.Digest {
|
||||
panic("unreachable: ispec.Manifest should always be marshable")
|
||||
}
|
||||
|
||||
return godigest.FromBytes(blob)
|
||||
digestAlgorithm := img.digestAlgorithm
|
||||
|
||||
if digestAlgorithm == "" {
|
||||
digestAlgorithm = godigest.Canonical
|
||||
}
|
||||
|
||||
return digestAlgorithm.FromBytes(blob)
|
||||
}
|
||||
|
||||
func (img *Image) DigestStr() string {
|
||||
return img.Digest().String()
|
||||
}
|
||||
|
||||
func (img *Image) DigestForAlgorithm(digestAlgorithm godigest.Algorithm) godigest.Digest {
|
||||
blob, err := json.Marshal(img.Manifest)
|
||||
if err != nil {
|
||||
panic("unreachable: ispec.Manifest should always be marshable")
|
||||
}
|
||||
|
||||
return digestAlgorithm.FromBytes(blob)
|
||||
}
|
||||
|
||||
func (img *Image) Size() int {
|
||||
size := img.ConfigDescriptor.Size + img.ManifestDescriptor.Size
|
||||
|
||||
@@ -167,7 +183,15 @@ type Layer struct {
|
||||
// specifying the layers of the image.
|
||||
func CreateImageWith() LayerBuilder {
|
||||
// set default values here
|
||||
return &BaseImageBuilder{}
|
||||
return &BaseImageBuilder{
|
||||
digestAlgorithm: godigest.Canonical,
|
||||
}
|
||||
}
|
||||
|
||||
func CreateImageWithDigestAlgorithm(digestAlgorithm godigest.Algorithm) LayerBuilder {
|
||||
return &BaseImageBuilder{
|
||||
digestAlgorithm: digestAlgorithm,
|
||||
}
|
||||
}
|
||||
|
||||
func CreateDefaultImage() Image {
|
||||
@@ -223,6 +247,8 @@ type BaseImageBuilder struct {
|
||||
annotations map[string]string
|
||||
subject *ispec.Descriptor
|
||||
artifactType string
|
||||
|
||||
digestAlgorithm godigest.Algorithm
|
||||
}
|
||||
|
||||
func (ib *BaseImageBuilder) Layers(layers []Layer) ConfigBuilder {
|
||||
@@ -236,7 +262,7 @@ func (ib *BaseImageBuilder) LayerBlobs(layers [][]byte) ConfigBuilder {
|
||||
ib.layers = append(ib.layers, Layer{
|
||||
Blob: layer,
|
||||
MediaType: ispec.MediaTypeImageLayerGzip,
|
||||
Digest: godigest.FromBytes(layer),
|
||||
Digest: ib.digestAlgorithm.FromBytes(layer),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -267,7 +293,7 @@ func (ib *BaseImageBuilder) RandomLayers(count, size int) ConfigBuilder {
|
||||
ib.layers = append(ib.layers, Layer{
|
||||
Blob: layer,
|
||||
MediaType: ispec.MediaTypeImageLayerGzip,
|
||||
Digest: godigest.FromBytes(layer),
|
||||
Digest: ib.digestAlgorithm.FromBytes(layer),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -290,7 +316,7 @@ func (ib *BaseImageBuilder) VulnerableLayers() VulnerableConfigBuilder {
|
||||
{
|
||||
Blob: layer,
|
||||
MediaType: ispec.MediaTypeImageLayerGzip,
|
||||
Digest: godigest.FromBytes(layer),
|
||||
Digest: ib.digestAlgorithm.FromBytes(layer),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -309,7 +335,7 @@ func (ib *BaseImageBuilder) ImageConfig(config ispec.Image) ManifestBuilder {
|
||||
MediaType: ispec.MediaTypeImageConfig,
|
||||
Size: int64(len(configBlob)),
|
||||
Data: configBlob,
|
||||
Digest: godigest.FromBytes(configBlob),
|
||||
Digest: ib.digestAlgorithm.FromBytes(configBlob),
|
||||
}
|
||||
|
||||
return ib
|
||||
@@ -351,7 +377,7 @@ func (ib *BaseImageBuilder) CustomConfigBlob(configBlob []byte, mediaType string
|
||||
MediaType: mediaType,
|
||||
Size: int64(len(configBlob)),
|
||||
Data: configBlob,
|
||||
Digest: godigest.FromBytes(configBlob),
|
||||
Digest: ib.digestAlgorithm.FromBytes(configBlob),
|
||||
}
|
||||
|
||||
return ib
|
||||
@@ -372,7 +398,7 @@ func (ib *BaseImageBuilder) RandomConfig() ManifestBuilder {
|
||||
|
||||
ib.configDescriptor = ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageConfig,
|
||||
Digest: godigest.FromBytes(configBlob),
|
||||
Digest: ib.digestAlgorithm.FromBytes(configBlob),
|
||||
Size: int64(len(configBlob)),
|
||||
Data: configBlob,
|
||||
}
|
||||
@@ -390,7 +416,7 @@ func (ib *BaseImageBuilder) DefaultVulnConfig() ManifestBuilder {
|
||||
|
||||
vulnConfigDescriptor := ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageConfig,
|
||||
Digest: godigest.FromBytes(configBlob),
|
||||
Digest: ib.digestAlgorithm.FromBytes(configBlob),
|
||||
Size: int64(len(configBlob)),
|
||||
Data: configBlob,
|
||||
}
|
||||
@@ -421,7 +447,7 @@ func (ib *BaseImageBuilder) VulnerableConfig(config ispec.Image) ManifestBuilder
|
||||
|
||||
vulnConfigDescriptor := ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageConfig,
|
||||
Digest: godigest.FromBytes(configBlob),
|
||||
Digest: ib.digestAlgorithm.FromBytes(configBlob),
|
||||
Size: int64(len(configBlob)),
|
||||
Data: configBlob,
|
||||
}
|
||||
@@ -446,7 +472,7 @@ func (ib *BaseImageBuilder) RandomVulnConfig() ManifestBuilder {
|
||||
|
||||
vulnConfigDescriptor := ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageConfig,
|
||||
Digest: godigest.FromBytes(configBlob),
|
||||
Digest: ib.digestAlgorithm.FromBytes(configBlob),
|
||||
Size: int64(len(configBlob)),
|
||||
Data: configBlob,
|
||||
}
|
||||
@@ -493,6 +519,7 @@ func (ib *BaseImageBuilder) Build() Image {
|
||||
Subject: ib.subject,
|
||||
Annotations: ib.annotations,
|
||||
},
|
||||
digestAlgorithm: ib.digestAlgorithm,
|
||||
}
|
||||
|
||||
manifestBlob, err := json.Marshal(img.Manifest)
|
||||
@@ -502,7 +529,7 @@ func (ib *BaseImageBuilder) Build() Image {
|
||||
|
||||
img.ManifestDescriptor = ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageManifest,
|
||||
Digest: godigest.FromBytes(manifestBlob),
|
||||
Digest: ib.digestAlgorithm.FromBytes(manifestBlob),
|
||||
Size: int64(len(manifestBlob)),
|
||||
Data: manifestBlob,
|
||||
}
|
||||
|
||||
@@ -11,8 +11,9 @@ import (
|
||||
)
|
||||
|
||||
type MultiarchImage struct {
|
||||
Index ispec.Index
|
||||
Images []Image
|
||||
Index ispec.Index
|
||||
Images []Image
|
||||
digestAlgorithm godigest.Algorithm
|
||||
|
||||
IndexDescriptor ispec.Descriptor
|
||||
}
|
||||
@@ -23,13 +24,28 @@ func (mi *MultiarchImage) Digest() godigest.Digest {
|
||||
panic("unreachable: ispec.Index should always be marshable")
|
||||
}
|
||||
|
||||
return godigest.FromBytes(indexBlob)
|
||||
digestAlgorithm := mi.digestAlgorithm
|
||||
|
||||
if digestAlgorithm == "" {
|
||||
digestAlgorithm = godigest.Canonical
|
||||
}
|
||||
|
||||
return digestAlgorithm.FromBytes(indexBlob)
|
||||
}
|
||||
|
||||
func (mi *MultiarchImage) DigestStr() string {
|
||||
return mi.Digest().String()
|
||||
}
|
||||
|
||||
func (mi *MultiarchImage) DigestForAlgorithm(digestAlgorithm godigest.Algorithm) godigest.Digest {
|
||||
blob, err := json.Marshal(mi.Index)
|
||||
if err != nil {
|
||||
panic("unreachable: ispec.Index should always be marshable")
|
||||
}
|
||||
|
||||
return digestAlgorithm.FromBytes(blob)
|
||||
}
|
||||
|
||||
func (mi MultiarchImage) AsImageMeta() mTypes.ImageMeta {
|
||||
index := mi.Index
|
||||
|
||||
@@ -61,7 +77,15 @@ type MultiarchBuilder interface {
|
||||
}
|
||||
|
||||
func CreateMultiarchWith() ImagesBuilder {
|
||||
return &BaseMultiarchBuilder{}
|
||||
return &BaseMultiarchBuilder{
|
||||
digestAlgorithm: godigest.Canonical,
|
||||
}
|
||||
}
|
||||
|
||||
func CreateMultiarchWithDigestAlgorithm(digestAlgorithm godigest.Algorithm) ImagesBuilder {
|
||||
return &BaseMultiarchBuilder{
|
||||
digestAlgorithm: digestAlgorithm,
|
||||
}
|
||||
}
|
||||
|
||||
func CreateRandomMultiarch() MultiarchImage {
|
||||
@@ -85,10 +109,11 @@ func CreateVulnerableMultiarch() MultiarchImage {
|
||||
}
|
||||
|
||||
type BaseMultiarchBuilder struct {
|
||||
images []Image
|
||||
subject *ispec.Descriptor
|
||||
artifactType string
|
||||
annotations map[string]string
|
||||
images []Image
|
||||
subject *ispec.Descriptor
|
||||
artifactType string
|
||||
annotations map[string]string
|
||||
digestAlgorithm godigest.Algorithm
|
||||
}
|
||||
|
||||
func (mb *BaseMultiarchBuilder) Images(images []Image) MultiarchBuilder {
|
||||
@@ -154,11 +179,12 @@ func (mb *BaseMultiarchBuilder) Build() MultiarchImage {
|
||||
panic("unreachable: ispec.Index should always be marshable")
|
||||
}
|
||||
|
||||
indexDigest := godigest.FromBytes(indexBlob)
|
||||
indexDigest := mb.digestAlgorithm.FromBytes(indexBlob)
|
||||
|
||||
return MultiarchImage{
|
||||
Index: index,
|
||||
Images: mb.images,
|
||||
Index: index,
|
||||
Images: mb.images,
|
||||
digestAlgorithm: mb.digestAlgorithm,
|
||||
|
||||
IndexDescriptor: ispec.Descriptor{
|
||||
MediaType: ispec.MediaTypeImageIndex,
|
||||
|
||||
@@ -21,6 +21,12 @@ var (
|
||||
)
|
||||
|
||||
func UploadImage(img Image, baseURL, repo, ref string) error {
|
||||
digestAlgorithm := img.digestAlgorithm
|
||||
|
||||
if digestAlgorithm == "" {
|
||||
digestAlgorithm = godigest.Canonical
|
||||
}
|
||||
|
||||
for _, blob := range img.Layers {
|
||||
resp, err := resty.R().Post(baseURL + "/v2/" + repo + "/blobs/uploads/")
|
||||
if err != nil {
|
||||
@@ -33,7 +39,7 @@ func UploadImage(img Image, baseURL, repo, ref string) error {
|
||||
|
||||
loc := resp.Header().Get("Location")
|
||||
|
||||
digest := godigest.FromBytes(blob).String()
|
||||
digest := digestAlgorithm.FromBytes(blob).String()
|
||||
|
||||
resp, err = resty.R().
|
||||
SetHeader("Content-Length", fmt.Sprintf("%d", len(blob))).
|
||||
@@ -63,7 +69,7 @@ func UploadImage(img Image, baseURL, repo, ref string) error {
|
||||
}
|
||||
}
|
||||
|
||||
cdigest := godigest.FromBytes(cblob)
|
||||
cdigest := digestAlgorithm.FromBytes(cblob)
|
||||
|
||||
if img.Manifest.Config.MediaType == ispec.MediaTypeEmptyJSON ||
|
||||
img.Manifest.Config.Digest == ispec.DescriptorEmptyJSON.Digest {
|
||||
@@ -117,14 +123,16 @@ func UploadImage(img Image, baseURL, repo, ref string) error {
|
||||
return ErrPutBlob
|
||||
}
|
||||
|
||||
if inject.ErrStatusCode(resp.StatusCode()) != http.StatusCreated {
|
||||
return ErrPutBlob
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func UploadImageWithBasicAuth(img Image, baseURL, repo, ref, user, password string) error {
|
||||
digestAlgorithm := img.digestAlgorithm
|
||||
|
||||
if digestAlgorithm == "" {
|
||||
digestAlgorithm = godigest.Canonical
|
||||
}
|
||||
|
||||
for _, blob := range img.Layers {
|
||||
resp, err := resty.R().
|
||||
SetBasicAuth(user, password).
|
||||
@@ -139,7 +147,7 @@ func UploadImageWithBasicAuth(img Image, baseURL, repo, ref, user, password stri
|
||||
|
||||
loc := resp.Header().Get("Location")
|
||||
|
||||
digest := godigest.FromBytes(blob).String()
|
||||
digest := digestAlgorithm.FromBytes(blob).String()
|
||||
|
||||
resp, err = resty.R().
|
||||
SetBasicAuth(user, password).
|
||||
@@ -163,7 +171,7 @@ func UploadImageWithBasicAuth(img Image, baseURL, repo, ref, user, password stri
|
||||
return err
|
||||
}
|
||||
|
||||
cdigest := godigest.FromBytes(cblob)
|
||||
cdigest := digestAlgorithm.FromBytes(cblob)
|
||||
|
||||
if img.Manifest.Config.MediaType == ispec.MediaTypeEmptyJSON {
|
||||
cblob = ispec.DescriptorEmptyJSON.Data
|
||||
|
||||
@@ -18,9 +18,15 @@ func WriteImageToFileSystem(image Image, repoName, ref string, storeController s
|
||||
return err
|
||||
}
|
||||
|
||||
digestAlgorithm := image.digestAlgorithm
|
||||
|
||||
if digestAlgorithm == "" {
|
||||
digestAlgorithm = godigest.Canonical
|
||||
}
|
||||
|
||||
for _, layerBlob := range image.Layers {
|
||||
layerReader := bytes.NewReader(layerBlob)
|
||||
layerDigest := godigest.FromBytes(layerBlob)
|
||||
layerDigest := digestAlgorithm.FromBytes(layerBlob)
|
||||
|
||||
_, _, err = store.FullBlobUpload(repoName, layerReader, layerDigest)
|
||||
if err != nil {
|
||||
@@ -34,7 +40,7 @@ func WriteImageToFileSystem(image Image, repoName, ref string, storeController s
|
||||
}
|
||||
|
||||
configReader := bytes.NewReader(configBlob)
|
||||
configDigest := godigest.FromBytes(configBlob)
|
||||
configDigest := digestAlgorithm.FromBytes(configBlob)
|
||||
|
||||
_, _, err = store.FullBlobUpload(repoName, configReader, configDigest)
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user