From 371e1ebf07afb72121c1b5a31b9d751c75a2b75d Mon Sep 17 00:00:00 2001 From: Andrew Lytvynov Date: Thu, 3 Aug 2023 15:27:06 -0700 Subject: [PATCH] cmd/dist,release/dist: expose RPM signing hook (#8789) Plumb a signing callback function to `unixpkgs.rpmTarget` to allow signing RPMs. This callback is optional and RPMs will build unsigned if not set, just as before. Updates https://github.com/tailscale/tailscale/issues/1882 Signed-off-by: Andrew Lytvynov --- cmd/dist/dist.go | 5 ++-- release/dist/cli/cli.go | 7 +++--- release/dist/unixpkgs/pkgs.go | 42 ++++++++++++++++++-------------- release/dist/unixpkgs/targets.go | 21 ++++++++++------ 4 files changed, 44 insertions(+), 31 deletions(-) diff --git a/cmd/dist/dist.go b/cmd/dist/dist.go index 82f474193..1b7a73c16 100644 --- a/cmd/dist/dist.go +++ b/cmd/dist/dist.go @@ -6,7 +6,6 @@ package main import ( "context" - "crypto" "errors" "flag" "log" @@ -20,10 +19,10 @@ import ( var synologyPackageCenter bool -func getTargets(tgzSigner crypto.Signer) ([]dist.Target, error) { +func getTargets(signers unixpkgs.Signers) ([]dist.Target, error) { var ret []dist.Target - ret = append(ret, unixpkgs.Targets(tgzSigner)...) + ret = append(ret, unixpkgs.Targets(signers)...) // Synology packages can be built either for sideloading, or for // distribution by Synology in their package center. When // distributed through the package center, apps can request diff --git a/release/dist/cli/cli.go b/release/dist/cli/cli.go index b1d4ff9f5..0067b54a0 100644 --- a/release/dist/cli/cli.go +++ b/release/dist/cli/cli.go @@ -19,6 +19,7 @@ import ( "github.com/peterbourgon/ff/v3/ffcli" "tailscale.com/release/dist" + "tailscale.com/release/dist/unixpkgs" ) // CLI returns a CLI root command to build release packages. @@ -26,7 +27,7 @@ import ( // getTargets is a function that gets run in the Exec function of commands that // need to know the target list. Its execution is deferred in this way to allow // customization of command FlagSets with flags that influence the target list. -func CLI(getTargets func(tgzSigner crypto.Signer) ([]dist.Target, error)) *ffcli.Command { +func CLI(getTargets func(unixpkgs.Signers) ([]dist.Target, error)) *ffcli.Command { return &ffcli.Command{ Name: "dist", ShortUsage: "dist [flags] [command flags]", @@ -36,7 +37,7 @@ func CLI(getTargets func(tgzSigner crypto.Signer) ([]dist.Target, error)) *ffcli { Name: "list", Exec: func(ctx context.Context, args []string) error { - targets, err := getTargets(nil) + targets, err := getTargets(unixpkgs.Signers{}) if err != nil { return err } @@ -56,7 +57,7 @@ func CLI(getTargets func(tgzSigner crypto.Signer) ([]dist.Target, error)) *ffcli if err != nil { return err } - targets, err := getTargets(tgzSigner) + targets, err := getTargets(unixpkgs.Signers{Tarball: tgzSigner}) if err != nil { return err } diff --git a/release/dist/unixpkgs/pkgs.go b/release/dist/unixpkgs/pkgs.go index baaf623dc..0b45f5c11 100644 --- a/release/dist/unixpkgs/pkgs.go +++ b/release/dist/unixpkgs/pkgs.go @@ -24,8 +24,8 @@ import ( ) type tgzTarget struct { - filenameArch string // arch to use in filename instead of deriving from goenv["GOARCH"] - goenv map[string]string + filenameArch string // arch to use in filename instead of deriving from goEnv["GOARCH"] + goEnv map[string]string signer crypto.Signer } @@ -33,11 +33,11 @@ func (t *tgzTarget) arch() string { if t.filenameArch != "" { return t.filenameArch } - return t.goenv["GOARCH"] + return t.goEnv["GOARCH"] } func (t *tgzTarget) os() string { - return t.goenv["GOOS"] + return t.goEnv["GOOS"] } func (t *tgzTarget) String() string { @@ -46,18 +46,18 @@ func (t *tgzTarget) String() string { func (t *tgzTarget) Build(b *dist.Build) ([]string, error) { var filename string - if t.goenv["GOOS"] == "linux" { + if t.goEnv["GOOS"] == "linux" { // Linux used to be the only tgz architecture, so we didn't put the OS // name in the filename. filename = fmt.Sprintf("tailscale_%s_%s.tgz", b.Version.Short, t.arch()) } else { filename = fmt.Sprintf("tailscale_%s_%s_%s.tgz", b.Version.Short, t.os(), t.arch()) } - ts, err := b.BuildGoBinary("tailscale.com/cmd/tailscale", t.goenv) + ts, err := b.BuildGoBinary("tailscale.com/cmd/tailscale", t.goEnv) if err != nil { return nil, err } - tsd, err := b.BuildGoBinary("tailscale.com/cmd/tailscaled", t.goenv) + tsd, err := b.BuildGoBinary("tailscale.com/cmd/tailscaled", t.goEnv) if err != nil { return nil, err } @@ -173,19 +173,19 @@ func (t *tgzTarget) Build(b *dist.Build) ([]string, error) { } type debTarget struct { - goenv map[string]string + goEnv map[string]string } func (t *debTarget) os() string { - return t.goenv["GOOS"] + return t.goEnv["GOOS"] } func (t *debTarget) arch() string { - return t.goenv["GOARCH"] + return t.goEnv["GOARCH"] } func (t *debTarget) String() string { - return fmt.Sprintf("linux/%s/deb", t.goenv["GOARCH"]) + return fmt.Sprintf("linux/%s/deb", t.goEnv["GOARCH"]) } func (t *debTarget) Build(b *dist.Build) ([]string, error) { @@ -193,11 +193,11 @@ func (t *debTarget) Build(b *dist.Build) ([]string, error) { return nil, errors.New("deb only supported on linux") } - ts, err := b.BuildGoBinary("tailscale.com/cmd/tailscale", t.goenv) + ts, err := b.BuildGoBinary("tailscale.com/cmd/tailscale", t.goEnv) if err != nil { return nil, err } - tsd, err := b.BuildGoBinary("tailscale.com/cmd/tailscaled", t.goenv) + tsd, err := b.BuildGoBinary("tailscale.com/cmd/tailscaled", t.goEnv) if err != nil { return nil, err } @@ -284,15 +284,16 @@ func (t *debTarget) Build(b *dist.Build) ([]string, error) { } type rpmTarget struct { - goenv map[string]string + goEnv map[string]string + signFn func(io.Reader) ([]byte, error) } func (t *rpmTarget) os() string { - return t.goenv["GOOS"] + return t.goEnv["GOOS"] } func (t *rpmTarget) arch() string { - return t.goenv["GOARCH"] + return t.goEnv["GOARCH"] } func (t *rpmTarget) String() string { @@ -304,11 +305,11 @@ func (t *rpmTarget) Build(b *dist.Build) ([]string, error) { return nil, errors.New("rpm only supported on linux") } - ts, err := b.BuildGoBinary("tailscale.com/cmd/tailscale", t.goenv) + ts, err := b.BuildGoBinary("tailscale.com/cmd/tailscale", t.goEnv) if err != nil { return nil, err } - tsd, err := b.BuildGoBinary("tailscale.com/cmd/tailscaled", t.goenv) + tsd, err := b.BuildGoBinary("tailscale.com/cmd/tailscaled", t.goEnv) if err != nil { return nil, err } @@ -375,6 +376,11 @@ func (t *rpmTarget) Build(b *dist.Build) ([]string, error) { Conflicts: []string{"tailscale-relay"}, RPM: nfpm.RPM{ Group: "Network", + Signature: nfpm.RPMSignature{ + PackageSignature: nfpm.PackageSignature{ + SignFn: t.signFn, + }, + }, }, }, }) diff --git a/release/dist/unixpkgs/targets.go b/release/dist/unixpkgs/targets.go index d7e2a4d44..9a90bab4d 100644 --- a/release/dist/unixpkgs/targets.go +++ b/release/dist/unixpkgs/targets.go @@ -6,6 +6,7 @@ package unixpkgs import ( "crypto" "fmt" + "io" "sort" "strings" @@ -15,22 +16,27 @@ import ( _ "github.com/goreleaser/nfpm/v2/rpm" ) -func Targets(signer crypto.Signer) []dist.Target { +type Signers struct { + Tarball crypto.Signer + RPM func(io.Reader) ([]byte, error) +} + +func Targets(signers Signers) []dist.Target { var ret []dist.Target for goosgoarch := range tarballs { goos, goarch := splitGoosGoarch(goosgoarch) ret = append(ret, &tgzTarget{ - goenv: map[string]string{ + goEnv: map[string]string{ "GOOS": goos, "GOARCH": goarch, }, - signer: signer, + signer: signers.Tarball, }) } for goosgoarch := range debs { goos, goarch := splitGoosGoarch(goosgoarch) ret = append(ret, &debTarget{ - goenv: map[string]string{ + goEnv: map[string]string{ "GOOS": goos, "GOARCH": goarch, }, @@ -39,10 +45,11 @@ func Targets(signer crypto.Signer) []dist.Target { for goosgoarch := range rpms { goos, goarch := splitGoosGoarch(goosgoarch) ret = append(ret, &rpmTarget{ - goenv: map[string]string{ + goEnv: map[string]string{ "GOOS": goos, "GOARCH": goarch, }, + signFn: signers.RPM, }) } @@ -50,12 +57,12 @@ func Targets(signer crypto.Signer) []dist.Target { // an ancient architecture. ret = append(ret, &tgzTarget{ filenameArch: "geode", - goenv: map[string]string{ + goEnv: map[string]string{ "GOOS": "linux", "GOARCH": "386", "GO386": "softfloat", }, - signer: signer, + signer: signers.Tarball, }) sort.Slice(ret, func(i, j int) bool {