diff --git a/src/pkg/packager/prepare.go b/src/pkg/packager/prepare.go index 7a1df0b982..ee8e59087c 100644 --- a/src/pkg/packager/prepare.go +++ b/src/pkg/packager/prepare.go @@ -44,6 +44,7 @@ func (p *Packager) FindImages() (imgMap map[string][]string, err error) { erroredCharts := []string{} erroredCosignLookups := []string{} whyResources := []string{} + erroredShaLookups := []string{} cwd, err := os.Getwd() if err != nil { @@ -232,7 +233,14 @@ func (p *Packager) FindImages() (imgMap map[string][]string, err error) { for _, image := range sortedImages { // Use print because we want this dumped to stdout imagesMap[component.Name] = append(imagesMap[component.Name], image) - componentDefinition += fmt.Sprintf(" - %s\n", image) + imageWithSha, err := utils.GetImageWithSha(image) + if err != nil { + message.WarnErrf(err, "Problem getting image with sha for %s: %s", image, err.Error()) + erroredShaLookups = append(erroredShaLookups, image) + continue + } + message.Debugf("Image with sha: %s", imageWithSha) + componentDefinition += fmt.Sprintf(" - %s\n", imageWithSha) } } @@ -303,7 +311,7 @@ func (p *Packager) FindImages() (imgMap map[string][]string, err error) { return nil, err } - if len(erroredCharts) > 0 || len(erroredCosignLookups) > 0 { + if len(erroredCharts) > 0 || len(erroredCosignLookups) > 0 || len(erroredShaLookups) > 0 { errMsg := "" if len(erroredCharts) > 0 { errMsg = fmt.Sprintf("the following charts had errors: %s", erroredCharts) @@ -314,6 +322,12 @@ func (p *Packager) FindImages() (imgMap map[string][]string, err error) { } errMsg += fmt.Sprintf("the following images errored on cosign lookups: %s", erroredCosignLookups) } + if len(erroredShaLookups) > 0 { + if errMsg != "" { + errMsg += "\n" + } + errMsg += fmt.Sprintf("the following images errored on sha lookups: %s", erroredShaLookups) + } return imagesMap, fmt.Errorf(errMsg) } diff --git a/src/pkg/utils/image.go b/src/pkg/utils/image.go index 0154953117..4d4c7a1b7b 100644 --- a/src/pkg/utils/image.go +++ b/src/pkg/utils/image.go @@ -7,8 +7,10 @@ package utils import ( "encoding/json" "fmt" + "github.com/google/go-containerregistry/pkg/crane" "os" "path/filepath" + "regexp" "github.com/defenseunicorns/zarf/src/pkg/transform" "github.com/defenseunicorns/zarf/src/pkg/utils/helpers" @@ -17,6 +19,21 @@ import ( ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) +// GetImageWithSha returns the image reference and the sha256 digest of the image. +func GetImageWithSha(imgSrc string) (string, error) { + regex := regexp.MustCompile(`^.*@sha256:[a-f0-9]{64}$`) + if regex.MatchString(imgSrc) { + return imgSrc, nil + } + + imgDescriptor, err := crane.Head(imgSrc) + if err != nil { + return "", err + } + + return fmt.Sprintf("%s@%s", imgSrc, imgDescriptor.Digest), nil +} + // LoadOCIImage returns a v1.Image with the image ref specified from a location provided, or an error if the image cannot be found. func LoadOCIImage(imgPath string, refInfo transform.Image) (v1.Image, error) { // Use the manifest within the index.json to load the specific image we want diff --git a/src/test/packages/13-find-images/dos-games-find-images-expected.txt b/src/test/packages/13-find-images/dos-games-find-images-expected.txt index 8d661f4e52..26535892a7 100644 --- a/src/test/packages/13-find-images/dos-games-find-images-expected.txt +++ b/src/test/packages/13-find-images/dos-games-find-images-expected.txt @@ -2,6 +2,6 @@ components: - name: baseline images: - - defenseunicorns/zarf-game:multi-tile-dark + - defenseunicorns/zarf-game:multi-tile-dark@sha256:0b694ca1c33afae97b7471488e07968599f1d2470c629f76af67145ca64428af # Cosign artifacts for images - dos-games - baseline - index.docker.io/defenseunicorns/zarf-game:sha256-0b694ca1c33afae97b7471488e07968599f1d2470c629f76af67145ca64428af.sig