Skip to content

Commit

Permalink
build: sign and notarize packaged binaries made for macos (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
zimeg authored Feb 18, 2024
1 parent 85d091e commit 71d163e
Show file tree
Hide file tree
Showing 11 changed files with 192 additions and 30 deletions.
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Signing and notarization
AC_USERNAME=
AC_PASSWORD=
AC_PROVIDER=
1 change: 1 addition & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
use flake
dotenv
68 changes: 65 additions & 3 deletions .github/MAINTAINERS_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,16 @@ Hey there! It's about time... Watt have you been jouling!?

## Project setup

After setting up the project for normal usage, you're ready for development!
Building from source to reflect any code changes only takes a few fast steps.

1. Install the latest version of [Go][golang].
2. From a directory for development, download the source and compile `etime`:

```sh
$ git clone https://github.com/zimeg/emporia-time.git
$ cd emporia-time
$ make build
```

An [understanding of Go][learn_go] is a likely prerequisite for any programming
and can be an enjoyable language to learn!
Expand All @@ -35,7 +44,7 @@ currently using the following structure:

- `/` – primary project files and metadata for the repository
- `.github/` – information for collaboration and continuous integrations
- `cmd/` - controllers for the different stages of the command
- `cmd/` controllers for the different stages of the command
- `internal/` – helpful utilities needed to create the program
- `pkg/` – various concerns that are pieced together to form the program

Expand All @@ -44,6 +53,8 @@ currently using the following structure:
For ease of development, some commands are added in a `Makefile`:

- `make build` – build the program binary
- `make staging` – package a distribution
- `make release` – sign and notarize packages
- `make test` – perform the written code tests
- `make clean` – remove all program artifacts

Expand Down Expand Up @@ -107,13 +118,60 @@ the following steps can be taken:
3. Commit these changes to a branch called by the version name – e.g. `v1.2.3`
4. Open then merge a pull request with these changes
5. Draft a [new release][releases] using the version name and entries from the
`CHANGELOG.md`
`CHANGELOG.md`
6. Publish this as the latest release!
7. Close the current milestone for the latest release then create a new one

In deciding a version number, best judgement should be used to follow
[semantic versioning][semver].

### Signing notarizations

Packaging for the release process begins after a new version tag is created.

Builds for various targets are made with [goreleaser][goreleaser] then signed by
[gon][gon] and uploaded to the action artifacts.

Only compilations for macOS are signed at this time. Verifying binaries made for
other operating systems is left as an exercise for the developer.

#### Keychaining certificates

Certain credentials and certificates are requested for the signing processes.

Apple holds the keys for [developer credentials][credentials] and
[system certificates][certificates]. A "Developer ID Application" is needed on
the system keychain and any missing but matching certificates too.

Account information is also needed as environment variables in the `.env` file.

#### Processing packages

Signing and notarizing binaries is an automatic process that happens after
making a release build.

Special tooling and a macOS system is required for this process. Tooling can be
setup with a packaging flake:

```sh
$ flake develop .#gon
```

With the above ready the following commands will hopefully officiate things:

```sh
$ make release # Build and notarize a release
$ gon .gon.hcl # Troubleshoot specific errors
```

#### Verifying a signature

Unpackage the output disk image to make sure everything was successful with:

```sh
$ spctl -a -vvv -t install ./etime
```

## Runner setup

A self-hosted runner is used to verify valid measurements are made when
Expand All @@ -127,6 +185,10 @@ in your action repository secrets using your Emporia information. Also add these
for Dependabot to configure this workflow.

<!-- a collection of links -->
[certificates]: https://www.apple.com/certificateauthority/
[credentials]: https://developer.apple.com/account/resources/certificates/list
[gon]: https://github.com/Bearer/gon
[goreleaser]: https://github.com/goreleaser/goreleaser
[learn_go]: https://go.dev/learn/
[nix]: https://zero-to-nix.com
[releases]: https://github.com/zimeg/emporia-time/releases
Expand Down
21 changes: 18 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
- name: Install a flaked Nix
uses: DeterminateSystems/nix-installer-action@v9
- name: Create snapshots
run: nix develop -c goreleaser release --clean --snapshot --skip=publish
run: nix develop -c goreleaser release --clean --snapshot --skip=publish --config .goreleaser.staging.yml
- name: Collect the current version
id: tag
run: |
Expand Down Expand Up @@ -101,15 +101,30 @@ jobs:
release:
name: Distribute a release
if: ${{ startsWith(github.ref, 'refs/tags/') }}
runs-on: ubuntu-latest
runs-on: macos-latest
steps:
- name: Checkout the repo
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Secure the keychain
run: |
echo $CERTIFICATE_P12 | base64 --decode > certificate.p12
security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
security import certificate.p12 -k build.keychain -P $CERTIFICATE_PASSWORD -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain
env:
CERTIFICATE_P12: ${{ secrets.CERTIFICATE_P12 }}
CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
- name: Install a flaked Nix
uses: DeterminateSystems/nix-installer-action@v9
- name: Create releases
run: nix develop -c goreleaser release --clean
run: nix develop .#gon -c goreleaser release --clean --config .goreleaser.release.yml
env:
AC_USERNAME: ${{ secrets.AC_USERNAME }}
AC_PASSWORD: ${{ secrets.AC_PASSWORD }}
AC_PROVIDER: ${{ secrets.AC_PROVIDER }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Built binaries
.gon.hcl
etime
dist/*

Expand All @@ -8,3 +9,4 @@ dist/*

# Environment settings
.direnv
.env
52 changes: 52 additions & 0 deletions .goreleaser.release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# yaml-language-server: $schema=https://goreleaser.com/static/schema.json
version: 1
before:
hooks:
- go mod tidy
builds:
- id: etime
binary: etime_{{.Summary}}
ldflags:
- -s -w -X main.version={{.Summary}}
env:
- CGO_ENABLED=0
goos:
- linux
- windows
- id: etime_macos
binary: etime_{{.Summary}}
goos:
- darwin
hooks:
post: |-
sh -c '
cat > .gon.hcl << EOF
source = ["./dist/etime_macos_{{.Target}}/etime_{{.Summary}}"]
bundle_id = "net.o526.etime"
sign {
application_identity = "Developer ID Application: Ethan Garrett Zimbelman (SA8WRA75UN)"
}
dmg {
output_path = "./dist/etime_{{.Target}}_{{.Summary}}.dmg"
volume_name = "etime_{{.Target}}"
}
EOF
gon .gon.hcl
'
archives:
- format: tar.gz
name_template: >-
etime_
{{- .Summary }}_
{{- .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
format_overrides:
- goos: windows
format: zip
changelog:
skip: true
checksum:
name_template: "etime_{{ .Summary }}_checksums.txt"
File renamed without changes.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Output outputs in an unbuffered manner as output happens
- Capture timing information for erroneous commands
- Sign and notarize packaged binaries made for macOS

### Maintenance

Expand Down
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: build test release clean
.PHONY: build test staging release clean

BIN=etime
VERSION="$(shell git describe --dirty --tags --always)"
Expand All @@ -9,10 +9,14 @@ build:
test: build
go test ./...

staging: clean
goreleaser build --snapshot --config .goreleaser.staging.yml

release: clean
goreleaser build --snapshot
goreleaser build --snapshot --config .goreleaser.release.yml

clean:
rm -f $(BIN)
rm -rf ~/.config/etime
rm -f .gon.hcl
rm -rf dist
31 changes: 13 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,18 @@ The `time` command, with energy awareness.
## Getting started

1. Purchase an [Emporia Smart Plug][plug] and set your device up.
2. Install the latest version of [Go][golang].
3. From a directory for development, download the source and compile `etime`:

```sh
$ git clone https://github.com/zimeg/emporia-time.git
$ cd emporia-time
$ make build
```

4. Optionally, create a symbolic link to or move the compiled binary into your
`/bin` to run the command globally:
2. Install the [latest released version][releases] or
[build from source][source].
3. Optionally, create a symbolic link to or move the compiled binary into your
`/bin` to run the command globally:

```sh
$ ln -s ~/path/to/emporia-time/etime /usr/local/bin

$ mv etime /usr/local/bin
```

5. Use the binary with your favorite command or script:
4. Use the binary with your favorite command or script:

```sh
$ ./etime sleep 12
Expand Down Expand Up @@ -134,12 +127,14 @@ Details on the processes around code for this repository are shared in the
[`.github/MAINTAINERS_GUIDE.md`][maintainers].

<!-- a collection of links -->
[plug]: https://www.emporiaenergy.com/emporia-smart-plug
[golang]: https://go.dev/dl
[contributing]: ./.github/CONTRIBUTING.md
[dashboard]: https://web.emporiaenergy.com/#/home
[time]: https://stackoverflow.com/a/556411
[energy]: https://en.wikipedia.org/wiki/Energy
[power]: https://en.wikipedia.org/wiki/Power_(physics)
[docs]: https://github.com/magico13/PyEmVue/blob/master/api_docs.md
[contributing]: ./.github/CONTRIBUTING.md
[energy]: https://en.wikipedia.org/wiki/Energy
[golang]: https://go.dev/dl
[maintainers]: ./.github/MAINTAINERS_GUIDE.md
[plug]: https://www.emporiaenergy.com/emporia-smart-plug
[power]: https://en.wikipedia.org/wiki/Power_(physics)
[releases]: https://github.com/zimeg/emporia-time/releases
[source]: ./.github/MAINTAINERS_GUIDE.md#project-setup
[time]: https://stackoverflow.com/a/556411
34 changes: 30 additions & 4 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,41 @@
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
gon = if system == "x86_64-darwin" || system == "aarch64-darwin" then
let
gonZip = pkgs.fetchurl {
url = "https://github.com/Bearer/gon/releases/download/v0.0.36/gon_macos.zip";
sha256 = "1firj23pgdfx9hybjjr91chn1jzf7lzjrbx3nm1s9h3xbpx945x2";
};
in
pkgs.runCommand "gon" { nativeBuildInputs = [ pkgs.unzip ]; } ''
mkdir -p $out/bin
unzip ${gonZip} -d $out/bin
''
else
null;
in
{
devShells.default = pkgs.mkShell {
packages = [
pkgs.gnumake
pkgs.go
pkgs.goreleaser
packages = with pkgs; [
gnumake
go
goreleaser
];
shellHook = "go mod tidy";
};
devShells.gon = if system == "x86_64-darwin" || system == "aarch64-darwin" then
pkgs.mkShell {
buildInputs = with pkgs; [
go
gon
goreleaser
];
shellHook = ''
export PATH=/usr/bin:$PATH:${gon}/bin
'';
}
else
null;
});
}

0 comments on commit 71d163e

Please sign in to comment.