mirror of
https://github.com/jimeh/build-emacs-for-macos.git
synced 2026-02-19 06:06:40 +00:00
feat(sign): add sign command to sign Emacs.app bundles with codesign
The sign command signs Emacs.app application bundles with Apple's codesign utility. It does a few things outside of just executing codesign: - Is aware of *.eln native-compilation files, which need to be explicitly searched for on disk and passed to codesign, as they are not detected when using the "--deep" option. - Is aware of Contents/MacOS/bin/emacs CLI helper tool which we add into the application bundle, and specifically passed it to codesign as well. - By default provides a set of entitlements which are relevant for Emacs when running codesign.
This commit is contained in:
3
go.mod
3
go.mod
@@ -9,9 +9,10 @@ require (
|
||||
github.com/google/go-github/v35 v35.3.0
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/hashicorp/go-hclog v0.16.1
|
||||
github.com/jimeh/undent v1.1.0
|
||||
github.com/mattn/go-isatty v0.0.13 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/stretchr/testify v1.6.1 // indirect
|
||||
github.com/stretchr/testify v1.7.0
|
||||
github.com/urfave/cli/v2 v2.3.0
|
||||
golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect
|
||||
golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect
|
||||
|
||||
7
go.sum
7
go.sum
@@ -117,6 +117,8 @@ github.com/hashicorp/go-hclog v0.16.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/jimeh/undent v1.1.0 h1:Cge7P4Ws6buy0SVuHBluY/aOKdFuJUMzoJswfAHZ4zE=
|
||||
github.com/jimeh/undent v1.1.0/go.mod h1:oxYCIzdbyQNy8GXnCnjRJ2NS6Uq4p4yWoeawiGFqoHI=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
@@ -136,6 +138,8 @@ github.com/mattn/go-isatty v0.0.13/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rhysd/go-fakeio v1.0.0 h1:+TjiKCOs32dONY7DaoVz/VPOdvRkPfBkEyUDIpM8FQY=
|
||||
github.com/rhysd/go-fakeio v1.0.0/go.mod h1:joYxF906trVwp2JLrE4jlN7A0z6wrz8O6o1UjarbFzE=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
@@ -144,8 +148,9 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/urfave/cli/v2 v2.3.0 h1:qph92Y649prgesehzOrQjdWyxFOp/QVM+6imKHad91M=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
|
||||
@@ -45,6 +45,7 @@ func New(version, commit, date string) *CLI {
|
||||
},
|
||||
Commands: []*cli2.Command{
|
||||
planCmd(),
|
||||
signCmd(),
|
||||
{
|
||||
Name: "version",
|
||||
Usage: "print the version",
|
||||
|
||||
114
pkg/cli/sign.go
Normal file
114
pkg/cli/sign.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/jimeh/build-emacs-for-macos/pkg/plan"
|
||||
"github.com/jimeh/build-emacs-for-macos/pkg/sign"
|
||||
cli2 "github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func signCmd() *cli2.Command {
|
||||
return &cli2.Command{
|
||||
Name: "sign",
|
||||
Usage: "sign a Emacs.app bundle with codesign",
|
||||
ArgsUsage: "<emacs-app>",
|
||||
Flags: []cli2.Flag{
|
||||
&cli2.StringFlag{
|
||||
Name: "sign",
|
||||
Aliases: []string{"s"},
|
||||
Usage: "signing identity passed to codeside",
|
||||
EnvVars: []string{"AC_SIGN_IDENTITY"},
|
||||
Required: true,
|
||||
},
|
||||
&cli2.StringSliceFlag{
|
||||
Name: "entitlements",
|
||||
Aliases: []string{"e"},
|
||||
Usage: "comma-separated list of entitlements to enable",
|
||||
Value: cli2.NewStringSlice(sign.DefaultEmacsEntitlements...),
|
||||
},
|
||||
&cli2.BoolFlag{
|
||||
Name: "deep",
|
||||
Aliases: []string{"d"},
|
||||
Usage: "pass --deep to codesign",
|
||||
Value: true,
|
||||
},
|
||||
&cli2.BoolFlag{
|
||||
Name: "timestamp",
|
||||
Aliases: []string{"t"},
|
||||
Usage: "pass --timestamp to codesign",
|
||||
Value: true,
|
||||
},
|
||||
&cli2.BoolFlag{
|
||||
Name: "force",
|
||||
Aliases: []string{"f"},
|
||||
Usage: "pass --force to codesign",
|
||||
Value: true,
|
||||
},
|
||||
&cli2.BoolFlag{
|
||||
Name: "verbose",
|
||||
Aliases: []string{"v"},
|
||||
Usage: "pass --verbose to codesign",
|
||||
Value: false,
|
||||
},
|
||||
&cli2.StringSliceFlag{
|
||||
Name: "options",
|
||||
Aliases: []string{"o"},
|
||||
Usage: "options passed to codesign",
|
||||
Value: cli2.NewStringSlice("runtime"),
|
||||
},
|
||||
&cli2.StringFlag{
|
||||
Name: "codesign",
|
||||
Usage: "specify custom path to codesign executable",
|
||||
},
|
||||
&cli2.StringFlag{
|
||||
Name: "plan",
|
||||
Usage: "path to build plan YAML file produced by " +
|
||||
"emacs-builder plan",
|
||||
Aliases: []string{"p"},
|
||||
EnvVars: []string{"EMACS_BUILDER_PLAN"},
|
||||
TakesFile: true,
|
||||
},
|
||||
},
|
||||
Action: actionWrapper(signAction),
|
||||
}
|
||||
}
|
||||
|
||||
func signAction(c *cli2.Context, opts *Options) error {
|
||||
signOpts := &sign.Options{
|
||||
Identity: c.String("sign"),
|
||||
Options: c.StringSlice("options"),
|
||||
Deep: c.Bool("deep"),
|
||||
Timestamp: c.Bool("timestamp"),
|
||||
Force: c.Bool("force"),
|
||||
Verbose: c.Bool("verbose"),
|
||||
CodeSignCmd: c.String("codesign"),
|
||||
}
|
||||
|
||||
if v := c.StringSlice("entitlements"); len(v) > 0 {
|
||||
e := sign.Entitlements(v)
|
||||
signOpts.Entitlements = &e
|
||||
}
|
||||
|
||||
if !opts.quiet {
|
||||
signOpts.Output = os.Stdout
|
||||
}
|
||||
|
||||
app := c.Args().Get(0)
|
||||
|
||||
if f := c.String("plan"); f != "" {
|
||||
p, err := plan.Load(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if p.Output != nil && p.Build != nil {
|
||||
app = filepath.Join(
|
||||
p.Output.Directory, p.Build.Name, "Emacs.app",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return sign.Emacs(c.Context, app, signOpts)
|
||||
}
|
||||
159
pkg/sign/emacs.go
Normal file
159
pkg/sign/emacs.go
Normal file
@@ -0,0 +1,159 @@
|
||||
package sign
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
)
|
||||
|
||||
// Emacs signs a Emacs.app application bundle with Apple's codesign utility,
|
||||
// using correct default entitlements, and also pre-signing any *.eln files
|
||||
// which are in the bundle, as codesign will not detect them as requiring
|
||||
// signing even with the --deep flag.
|
||||
func Emacs(ctx context.Context, appBundle string, opts *Options) error {
|
||||
if !strings.HasSuffix(appBundle, ".app") {
|
||||
return fmt.Errorf("%s is not a .app application bundle", appBundle)
|
||||
}
|
||||
|
||||
appBundle, err := filepath.Abs(appBundle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = os.Stat(appBundle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger := hclog.FromContext(ctx).Named("sign")
|
||||
logger.Info("preparing to sign Emacs.app", "app", appBundle)
|
||||
|
||||
newOpts := *opts
|
||||
|
||||
if newOpts.EntitlementsFile == "" {
|
||||
if newOpts.Entitlements == nil {
|
||||
e := Entitlements(DefaultEmacsEntitlements)
|
||||
newOpts.Entitlements = &e
|
||||
}
|
||||
|
||||
f, err2 := newOpts.Entitlements.TempFile()
|
||||
if err2 != nil {
|
||||
return err2
|
||||
}
|
||||
defer os.Remove(f)
|
||||
|
||||
newOpts.EntitlementsFile = f
|
||||
newOpts.Entitlements = nil
|
||||
}
|
||||
|
||||
err = signElnFiles(ctx, appBundle, &newOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = signCLIHelper(ctx, appBundle, &newOpts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Ensure app bundle is signed last, as modifications to the bundle after
|
||||
// signing will invalidate the signature. Hence anything within it that
|
||||
// needs to be separately signed, has to happen before signing the whole
|
||||
// application bundle.
|
||||
return Files(ctx, []string{appBundle}, &newOpts)
|
||||
}
|
||||
|
||||
func signElnFiles(ctx context.Context, appBundle string, opts *Options) error {
|
||||
logger := hclog.FromContext(ctx).Named("sign")
|
||||
|
||||
elnFiles, err := elnFiles(appBundle)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(elnFiles) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
logger.Info(fmt.Sprintf(
|
||||
"found %d native-lisp *.eln files in %s to sign",
|
||||
len(elnFiles), filepath.Base(appBundle),
|
||||
))
|
||||
for _, file := range elnFiles {
|
||||
err := Files(ctx, []string{file}, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func signCLIHelper(ctx context.Context, appBundle string, opts *Options) error {
|
||||
logger := hclog.FromContext(ctx).Named("sign")
|
||||
|
||||
cliHelper := filepath.Join(appBundle, "Contents", "MacOS", "bin", "emacs")
|
||||
fi, err := os.Stat(cliHelper)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
} else if err == nil && fi.Mode().IsRegular() {
|
||||
logger.Info(fmt.Sprintf(
|
||||
"found Contents/MacOS/bin/emacs CLI helper script in %s to sign",
|
||||
filepath.Base(appBundle),
|
||||
))
|
||||
|
||||
err = Files(ctx, []string{cliHelper}, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// elnFiles finds all native-compilation *.eln files within a Emacs.app bundle,
|
||||
// based on expected paths they might be stored in.
|
||||
func elnFiles(emacsApp string) ([]string, error) {
|
||||
dirs := []string{
|
||||
// Current *.eln location.
|
||||
filepath.Join(emacsApp, "Contents", "Resources", "native-lisp"),
|
||||
// Legacy *.eln location.
|
||||
filepath.Join(emacsApp, "Contents", "MacOS", "lib", "emacs"),
|
||||
}
|
||||
|
||||
var files []string
|
||||
walkDirFunc := func(path string, _d fs.DirEntry, _err error) error {
|
||||
if strings.HasSuffix(path, ".eln") {
|
||||
files = append(files, path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, dir := range dirs {
|
||||
fi, err := os.Stat(dir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !fi.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
err = filepath.WalkDir(dir, walkDirFunc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
54
pkg/sign/entitlements.go
Normal file
54
pkg/sign/entitlements.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package sign
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
_ "embed"
|
||||
"io"
|
||||
"os"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
// DefaultEmacsEntitlements is the default set of entitlements application
|
||||
// bundles are signed with if no entitlements are provided.
|
||||
var DefaultEmacsEntitlements = []string{
|
||||
"com.apple.security.cs.allow-jit",
|
||||
"com.apple.security.network.client",
|
||||
"com.apple.security.cs.disable-library-validation",
|
||||
"com.apple.security.automation.apple-events",
|
||||
}
|
||||
|
||||
//go:embed entitlements.tpl
|
||||
var entitlementsTemplate string
|
||||
|
||||
type Entitlements []string
|
||||
|
||||
func (e Entitlements) XML() ([]byte, error) {
|
||||
var buf bytes.Buffer
|
||||
err := e.Write(&buf)
|
||||
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
|
||||
func (e Entitlements) Write(w io.Writer) error {
|
||||
tpl, err := template.New("entitlements.plist").Parse(entitlementsTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tpl.Execute(w, e)
|
||||
}
|
||||
|
||||
func (e Entitlements) TempFile() (string, error) {
|
||||
f, err := os.CreateTemp("", "*.entitlements.plist")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
err = e.Write(f)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return f.Name(), nil
|
||||
}
|
||||
9
pkg/sign/entitlements.tpl
Normal file
9
pkg/sign/entitlements.tpl
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
{{- range . }}
|
||||
<key>{{ . }}</key>
|
||||
<true/>{{ end }}
|
||||
</dict>
|
||||
</plist>
|
||||
117
pkg/sign/entitlements_test.go
Normal file
117
pkg/sign/entitlements_test.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package sign
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/jimeh/undent"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var entitlementsTestCases = []struct {
|
||||
name string
|
||||
entitlements Entitlements
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "none",
|
||||
entitlements: Entitlements{},
|
||||
//nolint:lll
|
||||
want: undent.String(`
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
</dict>
|
||||
</plist>`,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "one",
|
||||
entitlements: Entitlements{"com.apple.security.cs.allow-jit"},
|
||||
//nolint:lll
|
||||
want: undent.String(`
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>`,
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "many",
|
||||
entitlements: Entitlements{
|
||||
"com.apple.security.cs.allow-jit",
|
||||
"com.apple.security.network.client",
|
||||
"com.apple.security.cs.disable-library-validation",
|
||||
"com.apple.security.automation.apple-events",
|
||||
},
|
||||
//nolint:lll
|
||||
want: undent.String(`
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.network.client</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.disable-library-validation</key>
|
||||
<true/>
|
||||
<key>com.apple.security.automation.apple-events</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>`,
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
func TestDefaultEmacsEntitlements(t *testing.T) {
|
||||
assert.Equal(t,
|
||||
[]string{
|
||||
"com.apple.security.cs.allow-jit",
|
||||
"com.apple.security.network.client",
|
||||
"com.apple.security.cs.disable-library-validation",
|
||||
"com.apple.security.automation.apple-events",
|
||||
},
|
||||
DefaultEmacsEntitlements,
|
||||
)
|
||||
}
|
||||
|
||||
func TestEntitlements_Write(t *testing.T) {
|
||||
for _, tt := range entitlementsTestCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
err := tt.entitlements.Write(&buf)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, tt.want, strings.TrimSpace(buf.String()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestEntitlements_TempFile(t *testing.T) {
|
||||
for _, tt := range entitlementsTestCases {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tmpFile, err := tt.entitlements.TempFile()
|
||||
require.NoError(t, err)
|
||||
defer os.Remove(tmpFile)
|
||||
|
||||
content, err := os.ReadFile(tmpFile)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, tt.want, strings.TrimSpace(string(content)))
|
||||
assert.True(t,
|
||||
strings.HasSuffix(tmpFile, ".entitlements.plist"),
|
||||
"temp file name does not match \"*.entitlements.plist\"",
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
67
pkg/sign/files.go
Normal file
67
pkg/sign/files.go
Normal file
@@ -0,0 +1,67 @@
|
||||
package sign
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
)
|
||||
|
||||
func Files(ctx context.Context, files []string, opts *Options) error {
|
||||
logger := hclog.FromContext(ctx).Named("sign")
|
||||
args := []string{}
|
||||
|
||||
if opts.Identity != "" {
|
||||
args = append(args, "--sign", opts.Identity)
|
||||
}
|
||||
if opts.Deep {
|
||||
args = append(args, "--deep")
|
||||
}
|
||||
if opts.Timestamp {
|
||||
args = append(args, "--timestamp")
|
||||
}
|
||||
if opts.Force {
|
||||
args = append(args, "--force")
|
||||
}
|
||||
if opts.Verbose {
|
||||
args = append(args, "--verbose")
|
||||
}
|
||||
if len(opts.Options) > 0 {
|
||||
args = append(args, "--options", strings.Join(opts.Options, ","))
|
||||
}
|
||||
|
||||
if opts.EntitlementsFile != "" {
|
||||
args = append(args, "--entitlements", opts.EntitlementsFile)
|
||||
} else if opts.Entitlements != nil {
|
||||
entitlementsFile, err := opts.Entitlements.TempFile()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(entitlementsFile)
|
||||
logger.Debug("wrote entitlements", "file", entitlementsFile)
|
||||
|
||||
args = append(args, "--entitlements", entitlementsFile)
|
||||
}
|
||||
|
||||
baseCmd := opts.CodeSignCmd
|
||||
if baseCmd == "" {
|
||||
path, err := exec.LookPath("codesign")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
baseCmd = path
|
||||
}
|
||||
|
||||
args = append(args, files...)
|
||||
|
||||
logger.Debug("executing", "command", baseCmd, "args", args)
|
||||
cmd := exec.CommandContext(ctx, baseCmd, args...)
|
||||
if opts.Output != nil {
|
||||
cmd.Stdout = opts.Output
|
||||
cmd.Stderr = opts.Output
|
||||
}
|
||||
|
||||
return cmd.Run()
|
||||
}
|
||||
16
pkg/sign/options.go
Normal file
16
pkg/sign/options.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package sign
|
||||
|
||||
import "io"
|
||||
|
||||
type Options struct {
|
||||
Identity string
|
||||
Entitlements *Entitlements
|
||||
EntitlementsFile string
|
||||
Options []string
|
||||
Deep bool
|
||||
Timestamp bool
|
||||
Force bool
|
||||
Verbose bool
|
||||
Output io.Writer
|
||||
CodeSignCmd string
|
||||
}
|
||||
Reference in New Issue
Block a user