diff --git a/pkg/release/images/fake/tar.go b/pkg/release/images/fake/tar.go
new file mode 100644
index 0000000..4c3b30a
--- /dev/null
+++ b/pkg/release/images/fake/tar.go
@@ -0,0 +1,51 @@
+package fake
+
+import (
+	"github.com/cert-manager/release/pkg/release/images"
+)
+
+// FakeImageTar is a fake of the image.Tar struct
+type FakeImageTar struct {
+	architecture      string
+	imageArchitecture string
+	imageName         string
+	imageTag          string
+	filePath          string
+	os                string
+}
+
+// New gives a new FakeImageTar
+func New(imageName, imageTag, filePath, os, architecture, imageArchitecture string) images.TarInterface {
+	return &FakeImageTar{
+		architecture:      architecture,
+		imageArchitecture: imageArchitecture,
+		imageName:         imageName,
+		imageTag:          imageTag,
+		filePath:          filePath,
+		os:                os,
+	}
+}
+
+func (f *FakeImageTar) Architecture() string {
+	return f.architecture
+}
+
+func (f *FakeImageTar) ImageArchitecture() string {
+	return f.imageArchitecture
+}
+
+func (f *FakeImageTar) ImageName() string {
+	return f.imageName
+}
+
+func (f *FakeImageTar) ImageTag() string {
+	return f.imageTag
+}
+
+func (f *FakeImageTar) OS() string {
+	return f.os
+}
+
+func (f *FakeImageTar) Filepath() string {
+	return f.filePath
+}
diff --git a/pkg/release/images/tar.go b/pkg/release/images/tar.go
index d372722..a30671f 100644
--- a/pkg/release/images/tar.go
+++ b/pkg/release/images/tar.go
@@ -44,6 +44,15 @@ type Tar struct {
 	imageArchitecture string
 }
 
+type TarInterface interface {
+	Architecture() string
+	ImageArchitecture() string
+	ImageName() string
+	ImageTag() string
+	Filepath() string
+	OS() string
+}
+
 func NewTar(path, osStr, arch string) (*Tar, error) {
 	f, err := os.Open(path)
 	if err != nil {
diff --git a/pkg/release/publish/registry/registry.go b/pkg/release/publish/registry/registry.go
index ca0a8db..434510e 100644
--- a/pkg/release/publish/registry/registry.go
+++ b/pkg/release/publish/registry/registry.go
@@ -27,7 +27,7 @@ func Push(image images.Tar) error {
 	return docker.Push(image.ImageName())
 }
 
-func CreateManifestList(name string, tars []images.Tar) error {
+func CreateManifestList(name string, tars []images.TarInterface) error {
 	imageNames := make([]string, len(tars))
 	for i, t := range tars {
 		imageNames[i] = t.ImageName()
diff --git a/pkg/release/unpacker.go b/pkg/release/unpacker.go
index 05b8e70..e5e4645 100644
--- a/pkg/release/unpacker.go
+++ b/pkg/release/unpacker.go
@@ -44,7 +44,7 @@ type Unpacked struct {
 	Charts                []manifests.Chart
 	YAMLs                 []manifests.YAML
 	CtlBinaryBundles      []binaries.Tar
-	ComponentImageBundles map[string][]images.Tar
+	ComponentImageBundles map[string][]images.TarInterface
 }
 
 // Unpack takes a staged release, inspects its metadata, fetches referenced
@@ -115,7 +115,7 @@ func Unpack(ctx context.Context, s *Staged) (*Unpacked, error) {
 // unpackServerImagesFromRelease will extract all 'image-like' tar archives
 // from the various 'server' .tar.gz files and return a map of component name
 // to a slice of images.Tar for each image in the bundle.
-func unpackServerImagesFromRelease(ctx context.Context, s *Staged) (map[string][]images.Tar, error) {
+func unpackServerImagesFromRelease(ctx context.Context, s *Staged) (map[string][]images.TarInterface, error) {
 	log.Printf("Unpacking 'server' type artifacts")
 	serverA := s.ArtifactsOfKind("server")
 	return unpackImages(ctx, serverA, "")
@@ -151,9 +151,9 @@ func unpackCtlFromRelease(ctx context.Context, s *Staged) ([]binaries.Tar, error
 	return binaryTarBundles, nil
 }
 
-func unpackImages(ctx context.Context, artifacts []StagedArtifact, trimSuffix string) (map[string][]images.Tar, error) {
+func unpackImages(ctx context.Context, artifacts []StagedArtifact, trimSuffix string) (map[string][]images.TarInterface, error) {
 	// tarBundles is a map from component name to slices of images.Tar
-	tarBundles := make(map[string][]images.Tar)
+	tarBundles := make(map[string][]images.TarInterface)
 	for _, a := range artifacts {
 		dir, err := extractStagedArtifactToTempDir(ctx, &a)
 		if err != nil {
@@ -172,7 +172,7 @@ func unpackImages(ctx context.Context, artifacts []StagedArtifact, trimSuffix st
 			baseName := filepath.Base(archive)
 			componentName := strings.TrimSuffix(baseName[:len(baseName)-len(filepath.Ext(baseName))], trimSuffix)
 			log.Printf("Found image for component %q with name %q", componentName, imageTar.ImageName())
-			tarBundles[componentName] = append(tarBundles[componentName], *imageTar)
+			tarBundles[componentName] = append(tarBundles[componentName], imageTar)
 		}
 	}
 	return tarBundles, nil
diff --git a/pkg/release/validation/validate.go b/pkg/release/validation/validate.go
index 237ec08..fd44eb9 100644
--- a/pkg/release/validation/validate.go
+++ b/pkg/release/validation/validate.go
@@ -20,12 +20,20 @@ import (
 	"fmt"
 	"strings"
 
+	"github.com/cert-manager/release/pkg/release/images"
+
 	"github.com/blang/semver"
 
 	"github.com/cert-manager/release/pkg/release"
-	"github.com/cert-manager/release/pkg/release/images"
 )
 
+type tarImage interface {
+	Architecture() string
+	ImageArchitecture() string
+	ImageName() string
+	ImageTag() string
+}
+
 type Options struct {
 	// ReleaseVersion is used to ensure that the artifacts in a staged release
 	// all specify the same image tag and define a consistent version.
@@ -67,7 +75,7 @@ func validateSemver(v string) error {
 	return err
 }
 
-func validateImageBundles(bundles map[string][]images.Tar, opts Options) []string {
+func validateImageBundles(bundles map[string][]images.TarInterface, opts Options) []string {
 	var violations []string
 	for componentName, tars := range bundles {
 		for _, tar := range tars {
diff --git a/pkg/release/validation/validate_test.go b/pkg/release/validation/validate_test.go
index c70e414..7fa6f6b 100644
--- a/pkg/release/validation/validate_test.go
+++ b/pkg/release/validation/validate_test.go
@@ -4,6 +4,10 @@ import (
 	"reflect"
 	"testing"
 
+	"github.com/cert-manager/release/pkg/release/images/fake"
+
+	"github.com/cert-manager/release/pkg/release/images"
+
 	"github.com/cert-manager/release/pkg/release"
 )
 
@@ -51,3 +55,67 @@ func TestValidate_Semver(t *testing.T) {
 		})
 	}
 }
+
+func Test_validateImageBundles(t *testing.T) {
+	type args struct {
+		bundles map[string][]images.TarInterface
+		opts    Options
+	}
+	tests := []struct {
+		name string
+		args args
+		want []string
+	}{
+		{
+			name: "no errors on a correct image name",
+			args: args{
+				bundles: map[string][]images.TarInterface{"controller": []images.TarInterface{fake.New("quay.io/jetstack/cert-manager-controller-amd64", "v0.15.0", "dummy", "linux", "amd64", "amd64")}},
+				opts: Options{
+					ReleaseVersion:  "v0.15.0",
+					ImageRepository: "quay.io/jetstack",
+				},
+			},
+			want: nil,
+		},
+		{
+			name: "error on incorrect image name",
+			args: args{
+				bundles: map[string][]images.TarInterface{"controller": []images.TarInterface{fake.New("nginx", "v0.15.0", "dummy", "linux", "amd64", "amd64")}},
+				opts: Options{
+					ReleaseVersion:  "v0.15.0",
+					ImageRepository: "quay.io/jetstack",
+				},
+			},
+			want: []string{`Image "nginx" does not match expected name "quay.io/jetstack/cert-manager-controller-amd64"`},
+		},
+		{
+			name: "error on incorrect image tag",
+			args: args{
+				bundles: map[string][]images.TarInterface{"controller": []images.TarInterface{fake.New("quay.io/jetstack/cert-manager-controller-amd64", "v0.8.0", "dummy", "linux", "amd64", "amd64")}},
+				opts: Options{
+					ReleaseVersion:  "v0.15.0",
+					ImageRepository: "quay.io/jetstack",
+				},
+			},
+			want: []string{`Image "quay.io/jetstack/cert-manager-controller-amd64" does not have expected tag "v0.15.0"`},
+		},
+		{
+			name: "error on incorrect image architecture",
+			args: args{
+				bundles: map[string][]images.TarInterface{"controller": []images.TarInterface{fake.New("quay.io/jetstack/cert-manager-controller-arm", "v0.15.0", "dummy", "linux", "arm", "amd64")}},
+				opts: Options{
+					ReleaseVersion:  "v0.15.0",
+					ImageRepository: "quay.io/jetstack",
+				},
+			},
+			want: []string{`Image architecture "amd64" does not match expected architecture "arm"`},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := validateImageBundles(tt.args.bundles, tt.args.opts); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("validateImageBundles() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}