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

     1  package sign
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"os/exec"
     7  	"path/filepath"
     8  
     9  	"github.com/goreleaser/goreleaser/context"
    10  	"github.com/goreleaser/goreleaser/internal/artifact"
    11  	"github.com/goreleaser/goreleaser/pipeline"
    12  )
    13  
    14  // Pipe for artifact signing.
    15  type Pipe struct{}
    16  
    17  func (Pipe) String() string {
    18  	return "signing artifacts"
    19  }
    20  
    21  // Default sets the Pipes defaults.
    22  func (Pipe) Default(ctx *context.Context) error {
    23  	cfg := &ctx.Config.Sign
    24  	if cfg.Cmd == "" {
    25  		cfg.Cmd = "gpg"
    26  	}
    27  	if cfg.Signature == "" {
    28  		cfg.Signature = "${artifact}.sig"
    29  	}
    30  	if len(cfg.Args) == 0 {
    31  		cfg.Args = []string{"--output", "$signature", "--detach-sig", "$artifact"}
    32  	}
    33  	if cfg.Artifacts == "" {
    34  		cfg.Artifacts = "none"
    35  	}
    36  	return nil
    37  }
    38  
    39  // Run executes the Pipe.
    40  func (Pipe) Run(ctx *context.Context) error {
    41  	switch ctx.Config.Sign.Artifacts {
    42  	case "checksum":
    43  		return sign(ctx, ctx.Artifacts.Filter(artifact.ByType(artifact.Checksum)).List())
    44  	case "all":
    45  		return sign(ctx, ctx.Artifacts.Filter(
    46  			artifact.Or(
    47  				artifact.ByType(artifact.UploadableArchive),
    48  				artifact.ByType(artifact.UploadableBinary),
    49  				artifact.ByType(artifact.Checksum),
    50  				artifact.ByType(artifact.LinuxPackage),
    51  			)).List())
    52  	case "none":
    53  		return pipeline.Skip("artifact signing disabled")
    54  	default:
    55  		return fmt.Errorf("invalid list of artifacts to sign: %s", ctx.Config.Sign.Artifacts)
    56  	}
    57  }
    58  
    59  func sign(ctx *context.Context, artifacts []artifact.Artifact) error {
    60  	var sigs []string
    61  	for _, a := range artifacts {
    62  		sig, err := signone(ctx, a)
    63  		if err != nil {
    64  			return err
    65  		}
    66  		sigs = append(sigs, sig)
    67  	}
    68  	for _, sig := range sigs {
    69  		ctx.Artifacts.Add(artifact.Artifact{
    70  			Type: artifact.Signature,
    71  			Name: sig,
    72  			Path: filepath.Join(ctx.Config.Dist, sig),
    73  		})
    74  	}
    75  	return nil
    76  }
    77  
    78  func signone(ctx *context.Context, artifact artifact.Artifact) (string, error) {
    79  	cfg := ctx.Config.Sign
    80  
    81  	env := map[string]string{
    82  		"artifact": artifact.Path,
    83  	}
    84  	env["signature"] = expand(cfg.Signature, env)
    85  
    86  	var args []string
    87  	for _, a := range cfg.Args {
    88  		args = append(args, expand(a, env))
    89  	}
    90  
    91  	// The GoASTScanner flags this as a security risk.
    92  	// However, this works as intended. The nosec annotation
    93  	// tells the scanner to ignore this.
    94  	// #nosec
    95  	cmd := exec.CommandContext(ctx, cfg.Cmd, args...)
    96  	output, err := cmd.CombinedOutput()
    97  	if err != nil {
    98  		return "", fmt.Errorf("sign: %s failed with %q", cfg.Cmd, string(output))
    99  	}
   100  	return filepath.Base(env["signature"]), nil
   101  }
   102  
   103  func expand(s string, env map[string]string) string {
   104  	return os.Expand(s, func(key string) string {
   105  		return env[key]
   106  	})
   107  }