github.com/szyn/goreleaser@v0.76.1-0.20180517112710-333da09a1297/pipeline/sign/sign_test.go (about)

     1  package sign
     2  
     3  import (
     4  	"bytes"
     5  	"io/ioutil"
     6  	"os"
     7  	"os/exec"
     8  	"path/filepath"
     9  	"sort"
    10  	"testing"
    11  
    12  	"github.com/goreleaser/goreleaser/config"
    13  	"github.com/goreleaser/goreleaser/context"
    14  	"github.com/goreleaser/goreleaser/internal/artifact"
    15  	"github.com/stretchr/testify/assert"
    16  )
    17  
    18  func TestDescription(t *testing.T) {
    19  	assert.NotEmpty(t, Pipe{}.String())
    20  }
    21  
    22  func TestSignDefault(t *testing.T) {
    23  	ctx := &context.Context{}
    24  	Pipe{}.Default(ctx)
    25  	assert.Equal(t, ctx.Config.Sign.Cmd, "gpg")
    26  	assert.Equal(t, ctx.Config.Sign.Signature, "${artifact}.sig")
    27  	assert.Equal(t, ctx.Config.Sign.Args, []string{"--output", "$signature", "--detach-sig", "$artifact"})
    28  	assert.Equal(t, ctx.Config.Sign.Artifacts, "none")
    29  }
    30  
    31  func TestSignDisabled(t *testing.T) {
    32  	ctx := &context.Context{}
    33  	ctx.Config.Sign.Artifacts = "none"
    34  	err := Pipe{}.Run(ctx)
    35  	assert.EqualError(t, err, "artifact signing disabled")
    36  }
    37  
    38  func TestSignInvalidArtifacts(t *testing.T) {
    39  	ctx := &context.Context{}
    40  	ctx.Config.Sign.Artifacts = "foo"
    41  	err := Pipe{}.Run(ctx)
    42  	assert.EqualError(t, err, "invalid list of artifacts to sign: foo")
    43  }
    44  
    45  func TestSignArtifacts(t *testing.T) {
    46  	// fix permission on keyring dir to suppress warning about insecure permissions
    47  	assert.NoError(t, os.Chmod(keyring, 0700))
    48  
    49  	tests := []struct {
    50  		desc       string
    51  		ctx        *context.Context
    52  		signatures []string
    53  	}{
    54  		{
    55  			desc: "sign all artifacts",
    56  			ctx: context.New(
    57  				config.Project{
    58  					Sign: config.Sign{Artifacts: "all"},
    59  				},
    60  			),
    61  			signatures: []string{"artifact1.sig", "artifact2.sig", "checksum.sig"},
    62  		},
    63  		{
    64  			desc: "sign only checksums",
    65  			ctx: context.New(
    66  				config.Project{
    67  					Sign: config.Sign{Artifacts: "checksum"},
    68  				},
    69  			),
    70  			signatures: []string{"checksum.sig"},
    71  		},
    72  	}
    73  
    74  	for _, tt := range tests {
    75  		t.Run(tt.desc, func(t *testing.T) {
    76  			testSign(t, tt.ctx, tt.signatures)
    77  		})
    78  	}
    79  }
    80  
    81  const keyring = "testdata/gnupg"
    82  const user = "nopass"
    83  
    84  func testSign(t *testing.T, ctx *context.Context, signatures []string) {
    85  	// create temp dir for file and signature
    86  	tmpdir, err := ioutil.TempDir("", "goreleaser")
    87  	assert.NoError(t, err)
    88  	defer os.RemoveAll(tmpdir)
    89  
    90  	ctx.Config.Dist = tmpdir
    91  
    92  	// create some fake artifacts
    93  	var artifacts = []string{"artifact1", "artifact2", "checksum"}
    94  	for _, f := range artifacts {
    95  		file := filepath.Join(tmpdir, f)
    96  		assert.NoError(t, ioutil.WriteFile(file, []byte("foo"), 0644))
    97  	}
    98  	ctx.Artifacts.Add(artifact.Artifact{
    99  		Name: "artifact1",
   100  		Path: filepath.Join(tmpdir, "artifact1"),
   101  		Type: artifact.UploadableArchive,
   102  	})
   103  	ctx.Artifacts.Add(artifact.Artifact{
   104  		Name: "artifact2",
   105  		Path: filepath.Join(tmpdir, "artifact2"),
   106  		Type: artifact.UploadableArchive,
   107  	})
   108  	ctx.Artifacts.Add(artifact.Artifact{
   109  		Name: "checksum",
   110  		Path: filepath.Join(tmpdir, "checksum"),
   111  		Type: artifact.Checksum,
   112  	})
   113  
   114  	// configure the pipeline
   115  	// make sure we are using the test keyring
   116  	assert.NoError(t, Pipe{}.Default(ctx))
   117  	ctx.Config.Sign.Args = append([]string{"--homedir", keyring}, ctx.Config.Sign.Args...)
   118  
   119  	// run the pipeline
   120  	assert.NoError(t, Pipe{}.Run(ctx))
   121  
   122  	// verify that only the artifacts and the signatures are in the dist dir
   123  	files, err := ioutil.ReadDir(tmpdir)
   124  	assert.NoError(t, err)
   125  	gotFiles := []string{}
   126  	for _, f := range files {
   127  		gotFiles = append(gotFiles, f.Name())
   128  	}
   129  	wantFiles := append(artifacts, signatures...)
   130  	sort.Strings(wantFiles)
   131  	assert.Equal(t, wantFiles, gotFiles)
   132  
   133  	// verify the signatures
   134  	for _, sig := range signatures {
   135  		verifySignature(t, ctx, sig)
   136  	}
   137  
   138  	var signArtifacts []string
   139  	for _, sig := range ctx.Artifacts.Filter(artifact.ByType(artifact.Signature)).List() {
   140  		signArtifacts = append(signArtifacts, sig.Name)
   141  	}
   142  	// check signature is an artifact
   143  	assert.Equal(t, signArtifacts, signatures)
   144  }
   145  
   146  func verifySignature(t *testing.T, ctx *context.Context, sig string) {
   147  	artifact := sig[:len(sig)-len(".sig")]
   148  
   149  	// verify signature was made with key for usesr 'nopass'
   150  	cmd := exec.Command("gpg", "--homedir", keyring, "--verify", filepath.Join(ctx.Config.Dist, sig), filepath.Join(ctx.Config.Dist, artifact))
   151  	out, err := cmd.CombinedOutput()
   152  	assert.NoError(t, err)
   153  
   154  	// check if the signature matches the user we expect to do this properly we
   155  	// might need to have either separate keyrings or export the key from the
   156  	// keyring before we do the verification. For now we punt and look in the
   157  	// output.
   158  	if !bytes.Contains(out, []byte(user)) {
   159  		t.Fatalf("signature is not from %s", user)
   160  	}
   161  }