github.com/ahmet2mir/goreleaser@v0.180.3-0.20210927151101-8e5ee5a9b8c5/internal/pipe/sign/sign_test.go (about)

     1  package sign
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"math/rand"
     7  	"os"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"sort"
    11  	"strings"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/goreleaser/goreleaser/internal/artifact"
    16  	"github.com/goreleaser/goreleaser/pkg/config"
    17  	"github.com/goreleaser/goreleaser/pkg/context"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  var (
    22  	originKeyring = "testdata/gnupg"
    23  	keyring       string
    24  )
    25  
    26  const (
    27  	user             = "nopass"
    28  	passwordUser     = "password"
    29  	passwordUserTmpl = "{{ .Env.GPG_PASSWORD }}"
    30  	fakeGPGKeyID     = "23E7505E"
    31  )
    32  
    33  func TestMain(m *testing.M) {
    34  	rand.Seed(time.Now().UnixNano())
    35  	keyring = fmt.Sprintf("/tmp/gorel_gpg_test.%d", rand.Int())
    36  	fmt.Println("copying", originKeyring, "to", keyring)
    37  	if err := exec.Command("cp", "-Rf", originKeyring, keyring).Run(); err != nil {
    38  		fmt.Printf("failed to copy %s to %s: %s", originKeyring, keyring, err)
    39  		os.Exit(1)
    40  	}
    41  
    42  	defer os.RemoveAll(keyring)
    43  	os.Exit(m.Run())
    44  }
    45  
    46  func TestDescription(t *testing.T) {
    47  	require.NotEmpty(t, Pipe{}.String())
    48  }
    49  
    50  func TestSignDefault(t *testing.T) {
    51  	ctx := &context.Context{
    52  		Config: config.Project{
    53  			Signs: []config.Sign{{}},
    54  		},
    55  	}
    56  	err := Pipe{}.Default(ctx)
    57  	require.NoError(t, err)
    58  	require.Equal(t, ctx.Config.Signs[0].Cmd, "gpg")
    59  	require.Equal(t, ctx.Config.Signs[0].Signature, "${artifact}.sig")
    60  	require.Equal(t, ctx.Config.Signs[0].Args, []string{"--output", "$signature", "--detach-sig", "$artifact"})
    61  	require.Equal(t, ctx.Config.Signs[0].Artifacts, "none")
    62  }
    63  
    64  func TestSignDisabled(t *testing.T) {
    65  	ctx := context.New(config.Project{})
    66  	ctx.Config.Signs = []config.Sign{
    67  		{Artifacts: "none"},
    68  	}
    69  	err := Pipe{}.Run(ctx)
    70  	require.EqualError(t, err, "artifact signing is disabled")
    71  }
    72  
    73  func TestSignInvalidArtifacts(t *testing.T) {
    74  	ctx := context.New(config.Project{})
    75  	ctx.Config.Signs = []config.Sign{
    76  		{Artifacts: "foo"},
    77  	}
    78  	err := Pipe{}.Run(ctx)
    79  	require.EqualError(t, err, "invalid list of artifacts to sign: foo")
    80  }
    81  
    82  func TestSignArtifacts(t *testing.T) {
    83  	stdin := passwordUser
    84  	tmplStdin := passwordUserTmpl
    85  	tests := []struct {
    86  		desc           string
    87  		ctx            *context.Context
    88  		signaturePaths []string
    89  		signatureNames []string
    90  		expectedErrMsg string
    91  		user           string
    92  	}{
    93  		{
    94  			desc:           "sign errors",
    95  			expectedErrMsg: "sign: exit failed",
    96  			ctx: context.New(
    97  				config.Project{
    98  					Signs: []config.Sign{
    99  						{
   100  							Artifacts: "all",
   101  							Cmd:       "exit",
   102  							Args:      []string{"1"},
   103  						},
   104  					},
   105  				},
   106  			),
   107  		},
   108  		{
   109  			desc:           "invalid args template",
   110  			expectedErrMsg: `sign failed: ${FOO}-{{ .foo }{{}}{: invalid template: template: tmpl:1: unexpected "}" in operand`,
   111  			ctx: context.New(
   112  				config.Project{
   113  					Signs: []config.Sign{
   114  						{
   115  							Artifacts: "all",
   116  							Cmd:       "exit",
   117  							Args:      []string{"${FOO}-{{ .foo }{{}}{"},
   118  						},
   119  					},
   120  					Env: []string{
   121  						"FOO=BAR",
   122  					},
   123  				},
   124  			),
   125  		},
   126  		{
   127  			desc: "sign single",
   128  			ctx: context.New(
   129  				config.Project{
   130  					Signs: []config.Sign{
   131  						{Artifacts: "all"},
   132  					},
   133  				},
   134  			),
   135  			signaturePaths: []string{"artifact1.sig", "artifact2.sig", "artifact3.sig", "checksum.sig", "checksum2.sig", "linux_amd64/artifact4.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
   136  			signatureNames: []string{"artifact1.sig", "artifact2.sig", "artifact3_1.0.0_linux_amd64.sig", "checksum.sig", "checksum2.sig", "artifact4_1.0.0_linux_amd64.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
   137  		},
   138  		{
   139  			desc: "sign all artifacts",
   140  			ctx: context.New(
   141  				config.Project{
   142  					Signs: []config.Sign{
   143  						{
   144  							Artifacts: "all",
   145  						},
   146  					},
   147  				},
   148  			),
   149  			signaturePaths: []string{"artifact1.sig", "artifact2.sig", "artifact3.sig", "checksum.sig", "checksum2.sig", "linux_amd64/artifact4.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
   150  			signatureNames: []string{"artifact1.sig", "artifact2.sig", "artifact3_1.0.0_linux_amd64.sig", "checksum.sig", "checksum2.sig", "artifact4_1.0.0_linux_amd64.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
   151  		},
   152  		{
   153  			desc: "sign archives",
   154  			ctx: context.New(
   155  				config.Project{
   156  					Signs: []config.Sign{
   157  						{
   158  							Artifacts: "archive",
   159  						},
   160  					},
   161  				},
   162  			),
   163  			signaturePaths: []string{"artifact1.sig", "artifact2.sig"},
   164  			signatureNames: []string{"artifact1.sig", "artifact2.sig"},
   165  		},
   166  		{
   167  			desc: "sign packages",
   168  			ctx: context.New(
   169  				config.Project{
   170  					Signs: []config.Sign{
   171  						{
   172  							Artifacts: "package",
   173  						},
   174  					},
   175  				},
   176  			),
   177  			signaturePaths: []string{"package1.deb.sig"},
   178  			signatureNames: []string{"package1.deb.sig"},
   179  		},
   180  		{
   181  			desc: "sign binaries",
   182  			ctx: context.New(
   183  				config.Project{
   184  					Signs: []config.Sign{
   185  						{
   186  							Artifacts: "binary",
   187  						},
   188  					},
   189  				},
   190  			),
   191  			signaturePaths: []string{"artifact3.sig", "linux_amd64/artifact4.sig"},
   192  			signatureNames: []string{"artifact3_1.0.0_linux_amd64.sig", "artifact4_1.0.0_linux_amd64.sig"},
   193  		},
   194  		{
   195  			desc: "multiple sign configs",
   196  			ctx: context.New(
   197  				config.Project{
   198  					Env: []string{
   199  						"GPG_KEY_ID=" + fakeGPGKeyID,
   200  					},
   201  					Signs: []config.Sign{
   202  						{
   203  							ID:        "s1",
   204  							Artifacts: "checksum",
   205  						},
   206  						{
   207  							ID:        "s2",
   208  							Artifacts: "archive",
   209  							Signature: "${artifact}.{{ .Env.GPG_KEY_ID }}.sig",
   210  						},
   211  					},
   212  				},
   213  			),
   214  			signaturePaths: []string{
   215  				"artifact1." + fakeGPGKeyID + ".sig",
   216  				"artifact2." + fakeGPGKeyID + ".sig",
   217  				"checksum.sig",
   218  				"checksum2.sig",
   219  			},
   220  			signatureNames: []string{
   221  				"artifact1." + fakeGPGKeyID + ".sig",
   222  				"artifact2." + fakeGPGKeyID + ".sig",
   223  				"checksum.sig",
   224  				"checksum2.sig",
   225  			},
   226  		},
   227  		{
   228  			desc: "sign filtered artifacts",
   229  			ctx: context.New(
   230  				config.Project{
   231  					Signs: []config.Sign{
   232  						{
   233  							Artifacts: "all",
   234  							IDs:       []string{"foo"},
   235  						},
   236  					},
   237  				},
   238  			),
   239  			signaturePaths: []string{"artifact1.sig", "artifact3.sig", "checksum.sig", "checksum2.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
   240  			signatureNames: []string{"artifact1.sig", "artifact3_1.0.0_linux_amd64.sig", "checksum.sig", "checksum2.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
   241  		},
   242  		{
   243  			desc: "sign only checksums",
   244  			ctx: context.New(
   245  				config.Project{
   246  					Signs: []config.Sign{
   247  						{
   248  							Artifacts: "checksum",
   249  						},
   250  					},
   251  				},
   252  			),
   253  			signaturePaths: []string{"checksum.sig", "checksum2.sig"},
   254  			signatureNames: []string{"checksum.sig", "checksum2.sig"},
   255  		},
   256  		{
   257  			desc: "sign only filtered checksums",
   258  			ctx: context.New(
   259  				config.Project{
   260  					Signs: []config.Sign{
   261  						{
   262  							Artifacts: "checksum",
   263  							IDs:       []string{"foo"},
   264  						},
   265  					},
   266  				},
   267  			),
   268  			signaturePaths: []string{"checksum.sig", "checksum2.sig"},
   269  			signatureNames: []string{"checksum.sig", "checksum2.sig"},
   270  		},
   271  		{
   272  			desc: "sign only source",
   273  			ctx: context.New(
   274  				config.Project{
   275  					Signs: []config.Sign{
   276  						{
   277  							Artifacts: "source",
   278  						},
   279  					},
   280  				},
   281  			),
   282  			signaturePaths: []string{"artifact5.tar.gz.sig"},
   283  			signatureNames: []string{"artifact5.tar.gz.sig"},
   284  		},
   285  		{
   286  			desc: "sign all artifacts with env",
   287  			ctx: context.New(
   288  				config.Project{
   289  					Signs: []config.Sign{
   290  						{
   291  							Artifacts: "all",
   292  							Args: []string{
   293  								"-u",
   294  								"${TEST_USER}",
   295  								"--output",
   296  								"${signature}",
   297  								"--detach-sign",
   298  								"${artifact}",
   299  							},
   300  						},
   301  					},
   302  					Env: []string{
   303  						fmt.Sprintf("TEST_USER=%s", user),
   304  					},
   305  				},
   306  			),
   307  			signaturePaths: []string{"artifact1.sig", "artifact2.sig", "artifact3.sig", "checksum.sig", "checksum2.sig", "linux_amd64/artifact4.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
   308  			signatureNames: []string{"artifact1.sig", "artifact2.sig", "artifact3_1.0.0_linux_amd64.sig", "checksum.sig", "checksum2.sig", "artifact4_1.0.0_linux_amd64.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
   309  		},
   310  		{
   311  			desc: "sign all artifacts with template",
   312  			ctx: context.New(
   313  				config.Project{
   314  					Signs: []config.Sign{
   315  						{
   316  							Artifacts: "all",
   317  							Args: []string{
   318  								"-u",
   319  								"{{ .Env.SOME_TEST_USER }}",
   320  								"--output",
   321  								"${signature}",
   322  								"--detach-sign",
   323  								"${artifact}",
   324  							},
   325  						},
   326  					},
   327  					Env: []string{
   328  						fmt.Sprintf("SOME_TEST_USER=%s", user),
   329  					},
   330  				},
   331  			),
   332  			signaturePaths: []string{"artifact1.sig", "artifact2.sig", "artifact3.sig", "checksum.sig", "checksum2.sig", "linux_amd64/artifact4.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
   333  			signatureNames: []string{"artifact1.sig", "artifact2.sig", "artifact3_1.0.0_linux_amd64.sig", "checksum.sig", "checksum2.sig", "artifact4_1.0.0_linux_amd64.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
   334  		},
   335  		{
   336  			desc: "sign single with password from stdin",
   337  			ctx: context.New(
   338  				config.Project{
   339  					Signs: []config.Sign{
   340  						{
   341  							Artifacts: "all",
   342  							Args: []string{
   343  								"-u",
   344  								passwordUser,
   345  								"--batch",
   346  								"--pinentry-mode",
   347  								"loopback",
   348  								"--passphrase-fd",
   349  								"0",
   350  								"--output",
   351  								"${signature}",
   352  								"--detach-sign",
   353  								"${artifact}",
   354  							},
   355  							Stdin: &stdin,
   356  						},
   357  					},
   358  				},
   359  			),
   360  			signaturePaths: []string{"artifact1.sig", "artifact2.sig", "artifact3.sig", "checksum.sig", "checksum2.sig", "linux_amd64/artifact4.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
   361  			signatureNames: []string{"artifact1.sig", "artifact2.sig", "artifact3_1.0.0_linux_amd64.sig", "checksum.sig", "checksum2.sig", "artifact4_1.0.0_linux_amd64.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
   362  			user:           passwordUser,
   363  		},
   364  		{
   365  			desc: "sign single with password from templated stdin",
   366  			ctx: context.New(
   367  				config.Project{
   368  					Env: []string{"GPG_PASSWORD=" + stdin},
   369  					Signs: []config.Sign{
   370  						{
   371  							Artifacts: "all",
   372  							Args: []string{
   373  								"-u",
   374  								passwordUser,
   375  								"--batch",
   376  								"--pinentry-mode",
   377  								"loopback",
   378  								"--passphrase-fd",
   379  								"0",
   380  								"--output",
   381  								"${signature}",
   382  								"--detach-sign",
   383  								"${artifact}",
   384  							},
   385  							Stdin: &tmplStdin,
   386  						},
   387  					},
   388  				},
   389  			),
   390  			signaturePaths: []string{"artifact1.sig", "artifact2.sig", "artifact3.sig", "checksum.sig", "checksum2.sig", "linux_amd64/artifact4.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
   391  			signatureNames: []string{"artifact1.sig", "artifact2.sig", "artifact3_1.0.0_linux_amd64.sig", "checksum.sig", "checksum2.sig", "artifact4_1.0.0_linux_amd64.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
   392  			user:           passwordUser,
   393  		},
   394  		{
   395  			desc: "sign single with password from stdin_file",
   396  			ctx: context.New(
   397  				config.Project{
   398  					Signs: []config.Sign{
   399  						{
   400  							Artifacts: "all",
   401  							Args: []string{
   402  								"-u",
   403  								passwordUser,
   404  								"--batch",
   405  								"--pinentry-mode",
   406  								"loopback",
   407  								"--passphrase-fd",
   408  								"0",
   409  								"--output",
   410  								"${signature}",
   411  								"--detach-sign",
   412  								"${artifact}",
   413  							},
   414  							StdinFile: filepath.Join(keyring, passwordUser),
   415  						},
   416  					},
   417  				},
   418  			),
   419  			signaturePaths: []string{"artifact1.sig", "artifact2.sig", "artifact3.sig", "checksum.sig", "checksum2.sig", "linux_amd64/artifact4.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
   420  			signatureNames: []string{"artifact1.sig", "artifact2.sig", "artifact3_1.0.0_linux_amd64.sig", "checksum.sig", "checksum2.sig", "artifact4_1.0.0_linux_amd64.sig", "artifact5.tar.gz.sig", "package1.deb.sig"},
   421  			user:           passwordUser,
   422  		},
   423  		{
   424  			desc: "missing stdin_file",
   425  			ctx: context.New(
   426  				config.Project{
   427  					Signs: []config.Sign{
   428  						{
   429  							Artifacts: "all",
   430  							Args: []string{
   431  								"--batch",
   432  								"--pinentry-mode",
   433  								"loopback",
   434  								"--passphrase-fd",
   435  								"0",
   436  							},
   437  							StdinFile: "/tmp/non-existing-file",
   438  						},
   439  					},
   440  				},
   441  			),
   442  			expectedErrMsg: `sign failed: cannot open file /tmp/non-existing-file: open /tmp/non-existing-file: no such file or directory`,
   443  		},
   444  	}
   445  
   446  	for _, test := range tests {
   447  		if test.user == "" {
   448  			test.user = user
   449  		}
   450  
   451  		t.Run(test.desc, func(t *testing.T) {
   452  			testSign(t, test.ctx, test.signaturePaths, test.signatureNames, test.user, test.expectedErrMsg)
   453  		})
   454  	}
   455  }
   456  
   457  func testSign(tb testing.TB, ctx *context.Context, signaturePaths []string, signatureNames []string, user, expectedErrMsg string) {
   458  	tb.Helper()
   459  	tmpdir := tb.TempDir()
   460  
   461  	ctx.Config.Dist = tmpdir
   462  
   463  	// create some fake artifacts
   464  	artifacts := []string{"artifact1", "artifact2", "artifact3", "checksum", "checksum2", "package1.deb"}
   465  	require.NoError(tb, os.Mkdir(filepath.Join(tmpdir, "linux_amd64"), os.ModePerm))
   466  	for _, f := range artifacts {
   467  		file := filepath.Join(tmpdir, f)
   468  		require.NoError(tb, os.WriteFile(file, []byte("foo"), 0o644))
   469  	}
   470  	require.NoError(tb, os.WriteFile(filepath.Join(tmpdir, "linux_amd64", "artifact4"), []byte("foo"), 0o644))
   471  	artifacts = append(artifacts, "linux_amd64/artifact4")
   472  	require.NoError(tb, os.WriteFile(filepath.Join(tmpdir, "artifact5.tar.gz"), []byte("foo"), 0o644))
   473  	artifacts = append(artifacts, "artifact5.tar.gz")
   474  	ctx.Artifacts.Add(&artifact.Artifact{
   475  		Name: "artifact1",
   476  		Path: filepath.Join(tmpdir, "artifact1"),
   477  		Type: artifact.UploadableArchive,
   478  		Extra: map[string]interface{}{
   479  			"ID": "foo",
   480  		},
   481  	})
   482  	ctx.Artifacts.Add(&artifact.Artifact{
   483  		Name: "artifact2",
   484  		Path: filepath.Join(tmpdir, "artifact2"),
   485  		Type: artifact.UploadableArchive,
   486  		Extra: map[string]interface{}{
   487  			"ID": "foo3",
   488  		},
   489  	})
   490  	ctx.Artifacts.Add(&artifact.Artifact{
   491  		Name: "artifact3_1.0.0_linux_amd64",
   492  		Path: filepath.Join(tmpdir, "artifact3"),
   493  		Type: artifact.UploadableBinary,
   494  		Extra: map[string]interface{}{
   495  			"ID": "foo",
   496  		},
   497  	})
   498  	ctx.Artifacts.Add(&artifact.Artifact{
   499  		Name: "checksum",
   500  		Path: filepath.Join(tmpdir, "checksum"),
   501  		Type: artifact.Checksum,
   502  	})
   503  	ctx.Artifacts.Add(&artifact.Artifact{
   504  		Name: "checksum2",
   505  		Path: filepath.Join(tmpdir, "checksum2"),
   506  		Type: artifact.Checksum,
   507  	})
   508  	ctx.Artifacts.Add(&artifact.Artifact{
   509  		Name: "artifact4_1.0.0_linux_amd64",
   510  		Path: filepath.Join(tmpdir, "linux_amd64", "artifact4"),
   511  		Type: artifact.UploadableBinary,
   512  		Extra: map[string]interface{}{
   513  			"ID": "foo3",
   514  		},
   515  	})
   516  	ctx.Artifacts.Add(&artifact.Artifact{
   517  		Name: "artifact5.tar.gz",
   518  		Path: filepath.Join(tmpdir, "artifact5.tar.gz"),
   519  		Type: artifact.UploadableSourceArchive,
   520  	})
   521  	ctx.Artifacts.Add(&artifact.Artifact{
   522  		Name: "package1.deb",
   523  		Path: filepath.Join(tmpdir, "package1.deb"),
   524  		Type: artifact.LinuxPackage,
   525  		Extra: map[string]interface{}{
   526  			"ID": "foo",
   527  		},
   528  	})
   529  
   530  	// configure the pipeline
   531  	// make sure we are using the test keyring
   532  	require.NoError(tb, Pipe{}.Default(ctx))
   533  	for i := range ctx.Config.Signs {
   534  		ctx.Config.Signs[i].Args = append(
   535  			[]string{"--homedir", keyring},
   536  			ctx.Config.Signs[i].Args...,
   537  		)
   538  	}
   539  
   540  	// run the pipeline
   541  	if expectedErrMsg != "" {
   542  		err := Pipe{}.Run(ctx)
   543  		require.Error(tb, err)
   544  		require.Contains(tb, err.Error(), expectedErrMsg)
   545  		return
   546  	}
   547  
   548  	require.NoError(tb, Pipe{}.Run(ctx))
   549  
   550  	// ensure all artifacts have an ID
   551  	for _, arti := range ctx.Artifacts.Filter(artifact.ByType(artifact.Signature)).List() {
   552  		require.NotEmptyf(tb, arti.ExtraOr("ID", ""), ".Extra.ID on %s", arti.Path)
   553  	}
   554  
   555  	// verify that only the artifacts and the signatures are in the dist dir
   556  	gotFiles := []string{}
   557  
   558  	require.NoError(tb, filepath.Walk(tmpdir,
   559  		func(path string, info os.FileInfo, err error) error {
   560  			if err != nil {
   561  				return err
   562  			}
   563  			if info.IsDir() {
   564  				return nil
   565  			}
   566  			relPath, err := filepath.Rel(tmpdir, path)
   567  			if err != nil {
   568  				return err
   569  			}
   570  			gotFiles = append(gotFiles, relPath)
   571  			return nil
   572  		}),
   573  	)
   574  
   575  	wantFiles := append(artifacts, signaturePaths...)
   576  	sort.Strings(wantFiles)
   577  	require.ElementsMatch(tb, wantFiles, gotFiles)
   578  
   579  	// verify the signatures
   580  	for _, sig := range signaturePaths {
   581  		verifySignature(tb, ctx, sig, user)
   582  	}
   583  
   584  	var signArtifacts []string
   585  	for _, sig := range ctx.Artifacts.Filter(artifact.ByType(artifact.Signature)).List() {
   586  		signArtifacts = append(signArtifacts, sig.Name)
   587  	}
   588  	// check signature is an artifact
   589  	require.ElementsMatch(tb, signArtifacts, signatureNames)
   590  }
   591  
   592  func verifySignature(tb testing.TB, ctx *context.Context, sig string, user string) {
   593  	tb.Helper()
   594  	artifact := strings.TrimSuffix(sig, filepath.Ext(sig))
   595  	artifact = strings.TrimSuffix(artifact, "."+fakeGPGKeyID)
   596  
   597  	// verify signature was made with key for usesr 'nopass'
   598  	cmd := exec.Command("gpg", "--homedir", keyring, "--verify", filepath.Join(ctx.Config.Dist, sig), filepath.Join(ctx.Config.Dist, artifact))
   599  	out, err := cmd.CombinedOutput()
   600  	require.NoError(tb, err, string(out))
   601  
   602  	// check if the signature matches the user we expect to do this properly we
   603  	// might need to have either separate keyrings or export the key from the
   604  	// keyring before we do the verification. For now we punt and look in the
   605  	// output.
   606  	if !bytes.Contains(out, []byte(user)) {
   607  		tb.Fatalf("%s: signature is not from %s: %s", sig, user, string(out))
   608  	}
   609  }
   610  
   611  func TestSeveralSignsWithTheSameID(t *testing.T) {
   612  	ctx := &context.Context{
   613  		Config: config.Project{
   614  			Signs: []config.Sign{
   615  				{
   616  					ID: "a",
   617  				},
   618  				{
   619  					ID: "a",
   620  				},
   621  			},
   622  		},
   623  	}
   624  	require.EqualError(t, Pipe{}.Default(ctx), "found 2 signs with the ID 'a', please fix your config")
   625  }
   626  
   627  func TestSkip(t *testing.T) {
   628  	t.Run("skip", func(t *testing.T) {
   629  		require.True(t, Pipe{}.Skip(context.New(config.Project{})))
   630  	})
   631  
   632  	t.Run("skip sign", func(t *testing.T) {
   633  		ctx := context.New(config.Project{})
   634  		ctx.SkipSign = true
   635  		require.True(t, Pipe{}.Skip(ctx))
   636  	})
   637  
   638  	t.Run("dont skip", func(t *testing.T) {
   639  		ctx := context.New(config.Project{
   640  			Signs: []config.Sign{
   641  				{},
   642  			},
   643  		})
   644  		require.False(t, Pipe{}.Skip(ctx))
   645  	})
   646  }