1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-03-17 20:47:50 +02:00

test: add test for sign pipeline

The unit tests needs a test key to work with. I have tried to create a
test keyring on the fly and while that worked I was not able to
successfully sign with that. gpg would bail with an ioctl error which I
didn't track down since using a static key works.
This commit is contained in:
Frank Schroeder 2017-12-13 22:57:24 +01:00
parent 7b95e1e342
commit d68b864f01
No known key found for this signature in database
GPG Key ID: 4D65C6EAEC87DECD
13 changed files with 206 additions and 8 deletions

View File

@ -7,7 +7,7 @@ that the artifacts have been generated by yourself and your users can verify
that by comparing the generated signature with your public signing key.
Signing works in combination with checksum files and it is generally sufficient
to sign the checksum files only.
to sign the checksum files only.
The default is configured to create a detached signature for the checksum files
with [GunPG](https://www.gnupg.org/) and your default key. To enable signing
@ -24,7 +24,7 @@ To customize the signing pipeline you can use the following options:
```yml
# .goreleaser.yml
sign:
# name of the signature file.
# name of the signature file.
# '${in}' is the path to the artifact that should be signed.
#
# signature: "${artifact}.sig"

View File

@ -10,12 +10,14 @@ import (
"github.com/goreleaser/goreleaser/pipeline"
)
// Pipe for artifact signing.
type Pipe struct{}
func (Pipe) String() string {
return "signing artifacts"
}
// Default sets the Pipes defaults.
func (Pipe) Default(ctx *context.Context) error {
cfg := &ctx.Config.Sign
if cfg.Cmd == "" {
@ -33,6 +35,7 @@ func (Pipe) Default(ctx *context.Context) error {
return nil
}
// Run executes the Pipe.
func (Pipe) Run(ctx *context.Context) error {
switch ctx.Config.Sign.Artifacts {
case "checksum":
@ -85,6 +88,10 @@ func signone(ctx *context.Context, artifact string) (string, error) {
args = append(args, expand(a, env))
}
// The GoASTScanner flags this as a security risk.
// However, this works as intended. The nosec annotation
// tells the scanner to ignore this.
// #nosec
cmd := exec.Command(cfg.Cmd, args...)
output, err := cmd.CombinedOutput()
if len(output) > 200 {

View File

@ -1,18 +1,96 @@
package sign
import (
"bytes"
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"testing"
"github.com/goreleaser/goreleaser/config"
"github.com/goreleaser/goreleaser/context"
"github.com/stretchr/testify/assert"
)
const (
gpgPlainKeyID = "0279C27FC1602A0E"
gpgEncryptedKeyID = "2AB4ABE1A4A47546"
gpgPassword = "secret"
gpgHome = "./testdata/gnupg"
)
const keyring = "testdata/gnupg"
func TestDescription(t *testing.T) {
assert.NotEmpty(t, Pipe{}.String())
}
func TestSign(t *testing.T) {
// create temp dir for file and signature
tmpdir, err := ioutil.TempDir("", "goreleaser")
if err != nil {
t.Fatal("TempDir: ", err)
}
defer os.RemoveAll(tmpdir)
artifact := "foo.txt"
signature := artifact + ".sig"
// create fake artifact
file := filepath.Join(tmpdir, artifact)
if err = ioutil.WriteFile(file, []byte("foo"), 0644); err != nil {
t.Fatal("WriteFile: ", err)
}
// fix permission on keyring dir to suppress warning about insecure permissions
if err = os.Chmod(keyring, 0700); err != nil {
t.Fatal("Chmod: ", err)
}
// sign artifact
ctx := &context.Context{
Config: config.Project{
Dist: tmpdir,
Sign: config.Sign{
Artifacts: "all",
},
},
}
ctx.AddArtifact(artifact)
err = Pipe{}.Default(ctx)
if err != nil {
t.Fatal("Default: ", err)
}
// make sure we are using the test keyring
ctx.Config.Sign.Args = append([]string{"--homedir", keyring}, ctx.Config.Sign.Args...)
err = Pipe{}.Run(ctx)
if err != nil {
t.Fatal("Run: ", err)
}
// verify signature was made with key for usesr 'nopass'
if err := verifySig(t, keyring, file, filepath.Join(tmpdir, signature), "nopass"); err != nil {
t.Fatal("verify: ", err)
}
// check signature is an artifact
assert.Equal(t, ctx.Artifacts, []string{artifact, signature})
}
func verifySig(t *testing.T, keyring, file, sig, user string) error {
cmd := exec.Command("gpg", "--homedir", keyring, "--verify", sig, file)
out, err := cmd.CombinedOutput()
if err != nil {
t.Log(string(out))
return err
}
// check if the signature matches the user we expect to do this properly we
// might need to have either separate keyrings or export the key from the
// keyring before we do the verification. For now we punt and look in the
// output.
if !bytes.Contains(out, []byte(user)) {
return fmt.Errorf("signature is not from %s", user)
}
return nil
}

1
pipeline/sign/testdata/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
S-*

80
pipeline/sign/testdata/README.md vendored Normal file
View File

@ -0,0 +1,80 @@
# Creating test keys for GnuPG
The unit tests needs a test key to work with. I have tried to create a test keyring
on the fly and while that worked I was not able to successfully sign with that.
gpg would bail with an ioctl error which I didn't track down since using a static
key works.
This uses the `--homedir .` option to create the test keys so that we do not touch
the local keyring file.
1. Create signing keys
cd $GOPATH/src/github.com/goreleaser/goreleaser/pipeline/sign/testdata/gnupg
gpg --homedir . --quick-generate-key --batch --passphrase '' nopass default default 10y
1. Check that the key exists
## $ gpg --homedir . --list-keys
pub rsa2048 2017-12-13 [SC][expires: 2027-12-11]
FB6BEDFCECE1761EDD68BF32EF2D274B0EDAAE12
uid [ultimate] nopass
sub rsa2048 2017-12-13 [E]
1) Check that signing works
# create a test file
echo "bar" > foo
# sign and verfiy
gpg --homedir . --detach-sign foo
gpg --homedir . --verify foo.sig foo
gpg: Signature made Wed Dec 13 22:02:49 2017 CET
gpg: using RSA key FB6BEDFCECE1761EDD68BF32EF2D274B0EDAAE12
gpg: Good signature from "nopass" [ultimate]
# cleanup
rm foo foo.sig
1) Make sure you have keyrings for both gpg1 and gpg2
travis-ci.org runs on an old Ubuntu installation which
has gpg 1.4 installed. We need to provide keyrings that
have the same keys and users for both formats.
This demonstrates the conversion from gpg2 to gpg1
format but should work the same the other way around.
# get gpg version
gpg --version
gpg (GnuPG) 2.2.3
...
# install gpg1
brew install gpg1
# brew install gpg2 # if you have gpg1 installed
# migrate the keys from gpg2 to gpg1
gpg --homedir . --export nopass | gpg1 --homedir . --import
gpg --homedir . --export-secret-key nopass | gpg1 --homedir . --import
# check keys are the same
gpg --homedir . --list-keys --keyid-format LONG
gpg1 --homedir . --list-keys --keyid-format LONG
gpg --homedir . --list-secret-keys --keyid-format LONG
gpg1 --homedir . --list-secret-keys --keyid-format LONG
```
```

View File

View File

@ -0,0 +1,32 @@
This is a revocation certificate for the OpenPGP key:
pub rsa2048 2017-12-13 [SC] [expires: 2027-12-11]
23E7505EC0A490C582CB9B27F1D733BF0B343347
uid nopass
A revocation certificate is a kind of "kill switch" to publicly
declare that a key shall not anymore be used. It is not possible
to retract such a revocation certificate once it has been published.
Use it to revoke this key in case of a compromise or loss of
the secret key. However, if the secret key is still accessible,
it is better to generate a new revocation certificate and give
a reason for the revocation. For details see the description of
of the gpg command "--generate-revocation" in the GnuPG manual.
To avoid an accidental use of this file, a colon has been inserted
before the 5 dashes below. Remove this colon with a text editor
before importing and publishing this revocation certificate.
:-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: This is a revocation certificate
iQE2BCABCAAgFiEEI+dQXsCkkMWCy5sn8dczvws0M0cFAloxnpUCHQAACgkQ8dcz
vws0M0dbdwf+KevSTLl688bOMMKcexoUra4porA/JJvtrkQAdHWqspqf+lQ+1rK0
Y4YNHkXixv6+R0aoECSrnx4ehk9nLH7hx5423DXEvmPkF70rWkF0eGeG8gVrUz2O
YWobOMldWPk6QPZ6rV5c5PdQSCx8+WHVXu/ym7u70fbmJV4IHuFlKiFUXsGk2PYj
k38ssFeqGo1bNZlIfuCggOurpfSXhKAsLRHjJVQe7ZowmloPiwHFfMwtuiBWpsZ/
3niEy3A5mdBC+ebtEL1KyaqjV6IN58YT3z0aBnDjA/qeweeT2jKjEWqHAPsJaJke
AyC0e8t71lnH4RZyKyfsBveKFfC4KN9SUA==
=DnZE
-----END PGP PUBLIC KEY BLOCK-----

BIN
pipeline/sign/testdata/gnupg/pubring.gpg vendored Normal file

Binary file not shown.

BIN
pipeline/sign/testdata/gnupg/pubring.kbx vendored Normal file

Binary file not shown.

BIN
pipeline/sign/testdata/gnupg/secring.gpg vendored Normal file

Binary file not shown.

BIN
pipeline/sign/testdata/gnupg/trustdb.gpg vendored Normal file

Binary file not shown.