• This repository has been archived on 31/Oct/2023
  • Stars
    star
    1,461
  • Rank 32,191 (Top 0.7 %)
  • Language
    Go
  • License
    MIT License
  • Created about 5 years ago
  • Updated about 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Sign, notarize, and package macOS CLI tools and applications written in any language. Available as both a CLI and a Go library.

gon - CLI and Go Library for macOS Notarization

gon is a simple, no-frills tool for signing and notarizing your CLI binaries for macOS. gon is available as a CLI that can be run manually or in automation pipelines. It is also available as a Go library for embedding in projects written in Go. gon can sign and notarize binaries written in any language.

Beginning with macOS Catalina (10.15), Apple is requiring all software distributed outside of the Mac App Store to be signed and notarized. Software that isn't properly signed or notarized will be shown an error message with the only actionable option being to "Move to Bin". The software cannot be run even from the command-line. The workarounds are painful for users. gon helps you automate the process of notarization.

Features

  • Code sign one or multiple files written in any language
  • Package signed files into a dmg or zip
  • Notarize packages and wait for the notarization to complete
  • Concurrent notarization for multiple output formats
  • Stapling notarization tickets to supported formats (dmg) so that Gatekeeper validation works offline.

See roadmap for features that we want to support but don't yet.

Example

The example below runs gon against itself to generate a zip and dmg.

gon Example

Installation

The easiest way to install gon is via Homebrew:

$ brew install mitchellh/gon/gon

You may also download the appropriate release for your platform from the releases page. These are all signed and notarized to run out of the box on macOS 10.15+.

You can also compile from source using Go 1.13 or later using standard go build. Please ensure that Go modules are enabled.

Usage

gon requires a configuration file that can be specified as a file path or passed in via stdin. The configuration specifies all the settings gon will use to sign and package your files.

gon must be run on a macOS machine with XCode 11.0 or later. Code signing, notarization, and packaging all require tools that are only available on macOS machines.

$ gon [flags] [CONFIG]

When executed, gon will sign, package, and notarize configured files into requested formats. gon will exit with a 0 exit code on success and any other value on failure.

Prerequisite: Acquiring a Developer ID Certificate

Before using gon, you must acquire a Developer ID Certificate. To do this, you can either do it via the web or via Xcode locally on a Mac. Using Xcode is easier if you already have it installed.

Via the web:

  1. Sign into developer.apple.com with valid Apple ID credentials. You may need to sign up for an Apple developer account.

  2. Navigate to the certificates page.

  3. Click the "+" icon, select "Developer ID Application" and follow the steps.

  4. After downloading the certificate, double-click to import it into your keychain. If you're building on a CI machine, every CI machine must have this certificate in their keychain.

Via Xcode:

  1. Open Xcode and go to Xcode => Preferences => Accounts

  2. Click the "+" in the bottom left and add your Apple ID if you haven't already.

  3. Select your Apple account and click "Manage Certificates" in the bottom right corner.

  4. Click "+" in the bottom left corner and click "Developer ID Application".

  5. Right-click the newly created cert in the list, click "export" and export the file as a p12-formatted certificate. Save this somewhere. You'll never be able to download it again.

To verify you did this correctly, you can inspect your keychain:

$ security find-identity -v
  1) 97E4A93EAA8BAC7A8FD2383BFA459D2898100E56 "Developer ID Application: Mitchell Hashimoto (GK79KXBF4F)"
     1 valid identities found

You should see one or more certificates and at least one should be your Developer ID Application certificate. The hexadecimal string prefix is the value you can use in your configuration file to specify the identity.

Configuration File

The configuration file can specify allow/deny lists of licenses for reports, license overrides for specific dependencies, and more. The configuration file format is HCL or JSON.

Example:

source = ["./terraform"]
bundle_id = "com.mitchellh.example.terraform"

apple_id {
  username = "[email protected]"
  password = "@env:AC_PASSWORD"
}

sign {
  application_identity = "Developer ID Application: Mitchell Hashimoto"
}

dmg {
  output_path = "terraform.dmg"
  volume_name = "Terraform"
}

zip {
  output_path = "terraform.zip"
}
{
    "source" : ["./terraform"],
    "bundle_id" : "com.mitchellh.example.terraform",
    "apple_id": {
        "username" : "[email protected]",
        "password":  "@env:AC_PASSWORD"
    },
    "sign" :{
        "application_identity" : "Developer ID Application: Mitchell Hashimoto"
    },
    "dmg" :{
        "output_path":  "terraform.dmg",
        "volume_name":  "Terraform"
    },
    "zip" :{
        "output_path" : "terraform.zip"
    }
}

Supported configurations:

  • source (array<string>) - A list of files to sign, package, and notarize. If you want to sign multiple files with different identities or into different packages, then you should invoke gon with separate configurations. This is optional if you're using the notarization-only mode with the notarize block.

  • bundle_id (string) - The bundle ID for your application. You should choose something unique for your application. You can also register these with Apple. This is optional if you're using the notarization-only mode with the notarize block.

  • apple_id - Settings related to the Apple ID to use for notarization.

    • username (string) - The Apple ID username, typically an email address. This will default to the AC_USERNAME environment variable if not set.

    • password (string) - The password for the associated Apple ID. This can be specified directly or using @keychain:<name> or @env:<name> to avoid putting the plaintext password directly in a configuration file. The @keychain:<name> syntax will load the password from the macOS Keychain with the given name. The @env:<name> syntax will load the password from the named environmental variable. If this value isn't set, we'll attempt to use the AC_PASSWORD environment variable as a default.

      NOTE: If you have 2FA enabled, the password must be an application password, not your normal apple id password. See Troubleshooting for details.

    • provider (string optional) - The App Store Connect provider when using multiple teams within App Store Connect. If this isn't set, we'll attempt to read the AC_PROVIDER environment variable as a default.

  • sign - Settings related to signing files.

    • application_identity (string) - The name or ID of the "Developer ID Application" certificate to use to sign applications. This accepts any valid value for the -s flag for the codesign binary on macOS. See man codesign for detailed documentation on accepted values.

    • entitlements_file (string optional) - The full path to a plist format .entitlements file, used for the --entitlements argument to codesign

  • dmg (optional) - Settings related to creating a disk image (dmg) as output. This will only be created if this is specified. The dmg will also have the notarization ticket stapled so that it can be verified offline and do not require internet to use.

    • output_path (string) - The path to create the zip archive. If this path already exists, it will be overwritten. All files in source will be copied into the root of the zip archive.

    • volume_name (string) - The name of the mounted dmg that shows up in finder, the mounted file path, etc.

  • zip (optional) - Settings related to creating a zip archive as output. A zip archive will only be created if this is specified. Note that zip archives don't support stapling, meaning that files within the notarized zip archive will require an internet connection to verify on first use.

    • output_path (string) - The path to create the zip archive. If this path already exists, it will be overwritten. All files in source will be copied into the root of the zip archive.

Notarization-only mode:

  • notarize (optional) - Settings for notarizing already built files. This is an alternative to using the source option. This option can be repeated to notarize multiple files.

    • path (string) - The path to the file to notarize. This must be one of Apple's supported file types for notarization: dmg, pkg, app, or zip.

    • bundle_id (string) - The bundle ID to use for this notarization. This is used instead of the top-level bundle_id (which controls the value for source-based runs).

    • staple (bool optional) - Controls if stapler staple should run if notarization succeeds. This should only be set for filetypes that support it (dmg, pkg, or app).

Notarization-Only Configuration

You can configure gon to notarize already-signed files. This is useful if you're integrating gon into an existing build pipeline that may already support creation of pkg, app, etc. files.

Because notarization requires the payload of packages to also be signed, this mode assumes that you have codesigned the payload as well as the package itself. gon will not sign your package in the notarize blocks. Please do not confuse this with when source is set and gon itself creates your packages, in which case it will also sign them.

You can use this in addition to specifying source as well. In this case, we will codesign & package the files specified in source and then notarize those results as well as those in notarize blocks.

Example in HCL and then the identical configuration in JSON:

notarize {
  path = "/path/to/terraform.pkg"
  bundle_id = "com.mitchellh.example.terraform"
  staple = true
}

apple_id {
  username = "[email protected]"
  password = "@env:AC_PASSWORD"
}
{
  "notarize": [{
    "path": "/path/to/terraform.pkg",
    "bundle_id": "com.mitchellh.example.terraform",
    "staple": true
  }],

  "apple_id": {
     "username": "[email protected]",
     "password": "@env:AC_PASSWORD"
  }
}

Note you may specify multiple notarize blocks to notarize multipel files concurrently.

Processing Time

The notarization process requires submitting your package(s) to Apple and waiting for them to scan them. Apple provides no public SLA as far as I can tell.

In developing gon and working with the notarization process, I've found the process to be fast on average (< 10 minutes) but in some cases notarization requests have been queued for an hour or more.

gon will output status updates as it goes, and will wait indefinitely for notarization to complete. If gon is interrupted, you can check the status of a request yourself using the request UUID that gon outputs after submission.

Using within Automation

gon is built to support running within automated environments such as CI pipelines. In this environment, you should use JSON configuration files with gon and the -log-json flag to get structured logging output.

Machine-Readable Output

gon always outputs human-readable output on stdout (including errors) and all log output on stderr. By specifying -log-json the log entries will be structured with JSON. You can process the stream of JSON using a tool such as jq or any scripting language to extract critical information such as the request UUID, status, and more.

When gon is run in an environment with no TTY, the human output will not be colored. This makes it friendlier for output logs.

Example:

$ gon -log-level=info -log-json ./config.hcl
...

Note you must specify both -log-level and -log-json. The -log-level flag enables logging in general. An info level is enough in automation environments to get all the information you'd want.

Prompts

On first-run may be prompted multiple times for passwords. If you click "Always Allow" then you will not be prompted again. These prompts are originating from Apple software that gon is subprocessing, and not from gon itself.

I do not currently know how to script the approvals, so the recommendation on build machines is to run gon manually once. If anyone finds a way to automate this please open an issue, let me know, and I'll update this README.

Usage with GoReleaser

GoReleaser is a popular full featured release automation tool for Go-based projects. Gon can be used with GoReleaser to augment the signing step to notarize your binaries as part of a GoReleaser pipeline.

Here is an example GoReleaser configuration to sign your binaries:

builds:
- binary: foo
  id: foo
  goos:
  - linux
  - windows
  goarch:
  - amd64
# notice that we need a separated build for the macos binary only:
- binary: foo
  id: foo-macos
  goos:
  - darwin
  goarch:
  - amd64
signs:
  - signature: "${artifact}.dmg"
    ids:
    - foo-macos # here we filter the macos only build id
    # you'll need to have gon on PATH
    cmd: gon
    # you can follow the gon docs to properly create the gon.hcl config file:
    # https://github.com/mitchellh/gon
    args:
    - gon.hcl
    artifacts: all

To learn more, see the GoReleaser documentation.

Go Library

Godoc

We also expose a supported API for signing, packaging, and notarizing files using the Go programming language. Please see the linked Go documentation for more details.

The libraries exposed are purposely lower level and separate out the sign, package, notarization, and stapling steps. This lets you integrate this functionality into any tooling easily vs. having an opinionated gon-CLI experience.

Troubleshooting

"We are unable to create an authentication session. (-22016)"

You likely have Apple 2FA enabled. You'll need to generate an application password and use that instead of your Apple ID password.

Roadmap

These are some things I'd love to see but aren't currently implemented.

  • Expose more DMG customization so you can set backgrounds, icons, etc.
    • The underlying script we use already supports this.
  • Support adding additional files to the zip, dmg packages
  • Support the creation of '.app' bundles for CLI applications

More Repositories

1

mapstructure

Go library for decoding generic map values into native Go structures and vice versa.
Go
7,685
star
2

gox

A dead simple, no frills Go cross compile tool
Go
4,594
star
3

vagrant-aws

Use Vagrant to manage your EC2 and VPC instances.
Ruby
2,609
star
4

nixos-config

My NixOS configurations.
Nix
1,791
star
5

cli

A Go library for implementing command-line interfaces.
Go
1,724
star
6

libxev

libxev is a cross-platform, high-performance event loop that provides abstractions for non-blocking IO, timers, events, and more and works on Linux (io_uring or epoll), macOS (kqueue), and Wasm + WASI. Available as both a Zig and C API.
Zig
1,589
star
7

go-ps

Find, list, and inspect processes from Go (golang).
Go
1,449
star
8

go-homedir

Go library for detecting and expanding the user's home directory without cgo.
Go
1,390
star
9

go-server-timing

Go (golang) library for creating and consuming HTTP Server-Timing headers
Go
861
star
10

hashstructure

Get hash values for arbitrary values in Go (golang).
Go
745
star
11

goamz

Golang Amazon Library
Go
673
star
12

golicense

Scan and analyze OSS dependencies and licenses from compiled Go binaries
Go
666
star
13

ioprogress

Go (golang) package for progress bars around io.Reader/Writers.
Go
502
star
14

go-mruby

Go (golang) bindings to mruby.
Go
468
star
15

panicwrap

panicwrap is a Go library for catching and handling panics in Go applications.
Go
443
star
16

advent-2021-sql

Advent of Code 2021 using SQL (PostgreSQL-flavored)
PLpgSQL
436
star
17

boot2docker-vagrant-box

Packer scripts to build a Vagrant-compatible boot2docker box.
Smarty
425
star
18

copystructure

Go (golang) library for deep copying values in Go.
Go
345
star
19

vagrant-google

Vagrant provider for GCE.
Ruby
334
star
20

go-glint

Component-based UI-framework for command-line tools. Easily create highly dynamic CLI interfaces using shared, easily testable components.
Go
311
star
21

go-vnc

VNC client and server library for Go.
Go
283
star
22

colorstring

Go (golang) library for colorizing strings for terminal output.
Go
276
star
23

reflectwalk

reflectwalk is a Go library for "walking" complex structures, similar to walking a filesystem.
Go
274
star
24

virtualbox

[ABANDONED] Create and modify virtual machines in VirtualBox using pure ruby.
Ruby
244
star
25

vagrant-rackspace

Use Vagrant to manage Rackspace Cloud instances.
Ruby
234
star
26

protoc-gen-go-json

Protobuf compiler plugin to generate Go JSON Marshal/Unmarshal implementations for messages using jsonpb.
Go
225
star
27

pointerstructure

Go library for addressing and reading/writing a specific value within any Go structure using a string syntax.
Go
214
star
28

zig-overlay

Nix flake for the Zig compiler.
Nix
195
star
29

zig-js

Access the JS host environment from Zig compiled to WebAssembly.
Zig
178
star
30

dotfiles

My personal dotfiles.
Batchfile
176
star
31

protostructure

Encode and decode Go (golang) struct types via protocol buffers.
Go
172
star
32

consulstructure

Decode Consul data into Go (Golang) structures and watch for updates
Go
172
star
33

packer-ubuntu-12.04-docker

Packer template that builds images that are Docker-ready on Ubuntu 12.04.
Shell
157
star
34

zig-libgc

Zig-friendly library for interfacing with libgc (bdwgc) -- the Boehm-Demers-Weiser conservative garbage collector
Zig
156
star
35

zig-objc

Objective-C runtime bindings for Zig (Zig calling ObjC).
Zig
153
star
36

libflightplan

A library for reading and writing flight plans in various formats. Available as both a C and Zig library.
Zig
153
star
37

terraform-provider-multispace

Terraform Provider for cascading runs across multiple workspaces.
Go
147
star
38

multistep

multistep is a Go library for building up complex actions using discrete steps.
Go
146
star
39

go-z3

Go (golang) bindings to the Z3 SMT Solver
Go
138
star
40

go-sat

SAT solver written in Go (golang).
Go
136
star
41

go-wordwrap

A Go (golang) library for wrapping words in a string.
Go
107
star
42

vim-misc

My Vim configuration files.
Vim Script
99
star
43

middleware

Generalized middleware implementation for Ruby.
Ruby
94
star
44

go-fs

Filesystem library for Go, implementing FAT filesystems so far.
Go
88
star
45

zig-graph

Directed graph data structure for Zig
Zig
86
star
46

go-grpc-net-conn

Turn any gRPC stream into a Go `net.Conn` implementation.
Go
80
star
47

zig-libxml2

libxml2 built using Zig build system
Zig
76
star
48

lightcloud

Library for accessing Plurk's LightCloud distributed key-value store for Ruby
Ruby
75
star
49

tree-sitter-hcl

A tree-sitter grammar for HCL (HashiCorp Configuration Language), used by projects such as Terraform.
C
69
star
50

go-linereader

Golang package that reads lines from an io.Reader and puts them onto a channel.
Go
66
star
51

veewee-to-packer

A tool for converting Veewee templates into Packer templates.
Ruby
65
star
52

tree-sitter-proto

A tree-sitter grammar for protocol buffer files (proto3).
C
63
star
53

vagrant-rake

A Vagrant plugin to execute `rake` commands from the host in the VM
Ruby
62
star
54

libvirt-rb

[ABANDONED] A ruby client library providing an interface to libvirt via FFI.
Ruby
59
star
55

go-testing-interface

Go (golang) library to expose *testing.T as an interface.
Go
58
star
56

patchstructure

Go library for representing and applying patches to modify existing Go structures
Go
55
star
57

squire

Go
55
star
58

go-libucl

Bindings to libucl from Go (golang).
Go
54
star
59

go-finger

Finger protocol library
Go
54
star
60

go-bnet

Go (golang) client for the Battle.net API
Go
52
star
61

libssh2-ruby

libssh2 bindings for Ruby
Ruby
47
star
62

iochan

A Go library for turning `io.Reader` into channels.
Go
43
star
63

prefixedio

Golang library that demultiplexes line-oriented data from an io.Reader into multiple io.Readers based on a prefix.
Go
42
star
64

flask-nix-example

Dockerfile
36
star
65

tlaplus-radix-tree

TLA+ modules, specifications, and models for Radix trees.
TLA
33
star
66

caststructure

A Go library that provides functions for downcasting types, composing values dynamically, and more.
Go
32
star
67

virtuoso

Dead simple virtual machine management over many hypervisors.
Ruby
30
star
68

hash_ring

Consistent hashing in Ruby. Ported from Amir Sailhefendic's hash_ring python library.
Ruby
28
star
69

terraform-aws-dynamic-keys

Terraform module that dynamically generates a public/private keypair.
HCL
26
star
70

go-spdx

Golang library for listing and looking up licenses using SPDX IDs.
Go
23
star
71

ruburple

A ruby interface to libpurple. Copied for git.
C
20
star
72

iorpc

Golang io interfaces across an RPC connection.
Go
18
star
73

fusion-m1-514-repro

Makefile
17
star
74

zig-build-macos-sdk

macOS SDK package for Zig build.
C
15
star
75

omniconfig

Flexible configuration for your Ruby applications and libraries.
Ruby
14
star
76

zig-libuv

Zig bindings for libuv. Also a build script to build libuv from scratch using only Zig (for easy cross-compilation, integration with Zig, etc.).
Zig
13
star
77

terraform-aws-fastai

Terraform module to create Fast.ai course instance.
HCL
12
star
78

radar

Easily report errors in your libraries and applications any way you want!
Ruby
12
star
79

zig-build-libxml2

The libxml2 library built and packaged for the Zig build system. These are not Zig language bindings to the library.
C
11
star
80

tiad-demo

Demo for The Incredible Automation Day in Paris.
Shell
10
star
81

waypoint-helm

WIP
Smarty
9
star
82

boto-route53

Route53 API built on top of Boto
Python
8
star
83

fogli

An efficient, simple, and intuitive Facebook Open Graph library
Ruby
8
star
84

minitest-mark

Proof of concept minitest extension to add test marking.
Ruby
7
star
85

vagrant-downloads

The Vagrant downloads website.
Ruby
7
star
86

minitest-parallel

Proof of concept to run your minitest tests in parallel.
Ruby
6
star
87

goconf

This is a copy of http://code.google.com/p/goconf/
Go
6
star
88

packer-go-bootcamp

Packer templates for the Go Bootcamp images.
Shell
6
star
89

larubyconf-vagrant-examples

Examples of using Vagrant from LARubyConf
Ruby
6
star
90

xidl

Parses XIDL files into Ruby objects.
Ruby
5
star
91

bintray-download-site

Simple Rack app for creating easy downloads for your Bintray packages.
Ruby
5
star
92

terraform-aws-vpc

Temporary, testing something, ignore this.
HCL
5
star
93

minitest-speed

Proof of concept speed tests using minitest.
Ruby
5
star
94

zig-build-xcode-frameworks

Exposing hexops/xcode-frameworks to the Zig package manager to work around some bugs.
Zig
5
star
95

homebrew-gon

Homebrew Tap for Gon (github.com/mitchellh/gon)
Ruby
4
star
96

osext

Copy of https://bitbucket.org/kardianos/osext
Go
4
star
97

minitest-funcarg

Proof of concept showing funcargs (style of DI) in minitest.
Ruby
4
star
98

lifeguard-random

Data source plugin for Lifeguard that generates random numbers.
Shell
4
star
99

go-bootcamp-remotecmds

My solution for the remotecmds problem for the Go Bootcamp I'm helping to instruct.
Go
4
star
100

lifeguard-graphite

Data source plugin for Lifeguard to query data from Graphite.
Shell
4
star