github.com/goreleaser/goreleaser@v1.25.1/internal/pipe/sign/sign_docker_test.go (about)

     1  package sign
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/goreleaser/goreleaser/internal/artifact"
    10  	"github.com/goreleaser/goreleaser/internal/gio"
    11  	"github.com/goreleaser/goreleaser/internal/skips"
    12  	"github.com/goreleaser/goreleaser/internal/testctx"
    13  	"github.com/goreleaser/goreleaser/internal/testlib"
    14  	"github.com/goreleaser/goreleaser/pkg/config"
    15  	"github.com/stretchr/testify/require"
    16  )
    17  
    18  func TestDockerSignDescription(t *testing.T) {
    19  	require.NotEmpty(t, DockerPipe{}.String())
    20  }
    21  
    22  func TestDockerSignDefault(t *testing.T) {
    23  	ctx := testctx.NewWithCfg(config.Project{
    24  		DockerSigns: []config.Sign{{}},
    25  	})
    26  	err := DockerPipe{}.Default(ctx)
    27  	require.NoError(t, err)
    28  	require.Equal(t, "cosign", ctx.Config.DockerSigns[0].Cmd)
    29  	require.Equal(t, "", ctx.Config.DockerSigns[0].Signature)
    30  	require.Equal(t, []string{"sign", "--key=cosign.key", "${artifact}@${digest}", "--yes"}, ctx.Config.DockerSigns[0].Args)
    31  	require.Equal(t, "none", ctx.Config.DockerSigns[0].Artifacts)
    32  }
    33  
    34  func TestDockerSignDisabled(t *testing.T) {
    35  	ctx := testctx.NewWithCfg(config.Project{
    36  		DockerSigns: []config.Sign{
    37  			{Artifacts: "none"},
    38  		},
    39  	})
    40  	err := DockerPipe{}.Publish(ctx)
    41  	require.EqualError(t, err, "artifact signing is disabled")
    42  }
    43  
    44  func TestDockerSignInvalidArtifacts(t *testing.T) {
    45  	ctx := testctx.NewWithCfg(config.Project{
    46  		DockerSigns: []config.Sign{
    47  			{Artifacts: "foo"},
    48  		},
    49  	})
    50  	err := DockerPipe{}.Publish(ctx)
    51  	require.EqualError(t, err, "invalid list of artifacts to sign: foo")
    52  }
    53  
    54  func TestDockerSignArtifacts(t *testing.T) {
    55  	testlib.CheckPath(t, "cosign")
    56  	key := "cosign.key"
    57  	cmd := "sh"
    58  	args := []string{"-c", "echo ${artifact}@${digest} > ${signature} && cosign sign --key=" + key + " --upload=false ${artifact}@${digest} --yes > ${signature}"}
    59  	password := "password"
    60  
    61  	img1 := "ghcr.io/caarlos0/goreleaser-docker-manifest-actions-example:1.2.1-amd64"
    62  	img1Digest := "sha256:d7bf8be1b156cc0cd9d2e33765a69bc968d4ef6b2dea9b207d63129b9709862a"
    63  	img2 := "ghcr.io/caarlos0/goreleaser-docker-manifest-actions-example:1.2.1-arm64v8"
    64  	img2Digest := "sha256:551801b7f42f8c33bfabb06e25804c2aca14776d2b7df33e07de54e887910b72"
    65  	man1 := "ghcr.io/caarlos0/goreleaser-docker-manifest-actions-example:1.2.1"
    66  	man1Digest := "sha256:b5db21408555f1ef5d68008a0a03a7caba3f29b62c64f1404e139b005a20bf03"
    67  
    68  	for name, cfg := range map[string]struct {
    69  		Signs    []config.Sign
    70  		Expected []string
    71  	}{
    72  		"no signature file": {
    73  			Expected: nil, // no sigs
    74  			Signs: []config.Sign{
    75  				{
    76  					Artifacts: "all",
    77  					Stdin:     &password,
    78  					Cmd:       "cosign",
    79  					Args:      []string{"sign", "--key=" + key, "--upload=false", "${artifact}", "--yes"},
    80  				},
    81  			},
    82  		},
    83  		"only certificate": {
    84  			Expected: []string{
    85  				"ghcrio-caarlos0-goreleaser-docker-manifest-actions-example-121-amd64.pem",
    86  				"ghcrio-caarlos0-goreleaser-docker-manifest-actions-example-121-arm64v8.pem",
    87  				"ghcrio-caarlos0-goreleaser-docker-manifest-actions-example-121.pem",
    88  			},
    89  			Signs: []config.Sign{
    90  				{
    91  					Artifacts:   "all",
    92  					Stdin:       &password,
    93  					Cmd:         "cosign",
    94  					Certificate: `{{ replace (replace (replace .Env.artifact "/" "-") ":" "-") "." "" }}.pem`,
    95  					Args:        []string{"sign", "--output-certificate=${certificate}", "--key=" + key, "--upload=false", "${artifact}@${digest}", "--yes"},
    96  				},
    97  			},
    98  		},
    99  		"sign all": {
   100  			Expected: []string{
   101  				"all_img1.sig",
   102  				"all_img2.sig",
   103  				"all_man1.sig",
   104  			},
   105  			Signs: []config.Sign{
   106  				{
   107  					Artifacts: "all",
   108  					Stdin:     &password,
   109  					Signature: `all_${artifactID}.sig`,
   110  					Cmd:       cmd,
   111  					Args:      args,
   112  				},
   113  			},
   114  		},
   115  		"sign all filtering id": {
   116  			Expected: []string{"all_filter_by_id_img2.sig"},
   117  			Signs: []config.Sign{
   118  				{
   119  					Artifacts: "all",
   120  					IDs:       []string{"img2"},
   121  					Stdin:     &password,
   122  					Signature: "all_filter_by_id_${artifactID}.sig",
   123  					Cmd:       cmd,
   124  					Args:      args,
   125  				},
   126  			},
   127  		},
   128  		"sign images only": {
   129  			Expected: []string{
   130  				"images_img1.sig",
   131  				"images_img2.sig",
   132  			},
   133  			Signs: []config.Sign{
   134  				{
   135  					Artifacts: "images",
   136  					Stdin:     &password,
   137  					Signature: "images_${artifactID}.sig",
   138  					Cmd:       cmd,
   139  					Args:      args,
   140  				},
   141  			},
   142  		},
   143  		"sign manifests only": {
   144  			Expected: []string{"manifests_man1.sig"},
   145  			Signs: []config.Sign{
   146  				{
   147  					Artifacts: "manifests",
   148  					Stdin:     &password,
   149  					Signature: "manifests_${artifactID}.sig",
   150  					Cmd:       cmd,
   151  					Args:      args,
   152  				},
   153  			},
   154  		},
   155  		// TODO: keyless test?
   156  	} {
   157  		t.Run(name, func(t *testing.T) {
   158  			ctx := testctx.NewWithCfg(config.Project{
   159  				DockerSigns: cfg.Signs,
   160  			})
   161  			wd, err := os.Getwd()
   162  			require.NoError(t, err)
   163  			tmp := testlib.Mktmp(t)
   164  			require.NoError(t, gio.Copy(filepath.Join(wd, "testdata/cosign/"), tmp))
   165  			ctx.Config.Dist = "dist"
   166  			require.NoError(t, os.Mkdir("dist", 0o755))
   167  
   168  			ctx.Artifacts.Add(&artifact.Artifact{
   169  				Name: img1,
   170  				Path: img1,
   171  				Type: artifact.DockerImage,
   172  				Extra: map[string]interface{}{
   173  					artifact.ExtraID:     "img1",
   174  					artifact.ExtraDigest: img1Digest,
   175  				},
   176  			})
   177  			ctx.Artifacts.Add(&artifact.Artifact{
   178  				Name: img2,
   179  				Path: img2,
   180  				Type: artifact.DockerImage,
   181  				Extra: map[string]interface{}{
   182  					artifact.ExtraID:     "img2",
   183  					artifact.ExtraDigest: img2Digest,
   184  				},
   185  			})
   186  			ctx.Artifacts.Add(&artifact.Artifact{
   187  				Name: man1,
   188  				Path: man1,
   189  				Type: artifact.DockerManifest,
   190  				Extra: map[string]interface{}{
   191  					artifact.ExtraID:     "man1",
   192  					artifact.ExtraDigest: man1Digest,
   193  				},
   194  			})
   195  
   196  			require.NoError(t, DockerPipe{}.Default(ctx))
   197  			require.NoError(t, DockerPipe{}.Publish(ctx))
   198  			var sigs []string
   199  			for _, sig := range ctx.Artifacts.Filter(
   200  				artifact.Or(
   201  					artifact.ByType(artifact.Signature),
   202  					artifact.ByType(artifact.Certificate),
   203  				),
   204  			).List() {
   205  				sigs = append(sigs, sig.Name)
   206  				require.Truef(t, strings.HasPrefix(sig.Path, ctx.Config.Dist), "signature %q is not in dist dir %q", sig.Path, ctx.Config.Dist)
   207  			}
   208  			require.Equal(t, cfg.Expected, sigs)
   209  		})
   210  	}
   211  }
   212  
   213  func TestDockerSkip(t *testing.T) {
   214  	t.Run("skip", func(t *testing.T) {
   215  		require.True(t, DockerPipe{}.Skip(testctx.New()))
   216  	})
   217  
   218  	t.Run("skip sign", func(t *testing.T) {
   219  		ctx := testctx.New(testctx.Skip(skips.Sign))
   220  		require.True(t, DockerPipe{}.Skip(ctx))
   221  	})
   222  
   223  	t.Run("dont skip", func(t *testing.T) {
   224  		ctx := testctx.NewWithCfg(config.Project{
   225  			DockerSigns: []config.Sign{
   226  				{},
   227  			},
   228  		})
   229  		require.False(t, DockerPipe{}.Skip(ctx))
   230  	})
   231  }
   232  
   233  func TestDockerDependencies(t *testing.T) {
   234  	ctx := testctx.NewWithCfg(config.Project{
   235  		DockerSigns: []config.Sign{
   236  			{Cmd: "cosign"},
   237  			{Cmd: "gpg2"},
   238  		},
   239  	})
   240  	require.Equal(t, []string{"cosign", "gpg2"}, DockerPipe{}.Dependencies(ctx))
   241  }