Single executable release specification.
Purpose
Distribute Canaryd as one executable file for each supported macOS architecture. Do not require the user to install Erlang or Elixir.
Scope
- In scope:
- Apple Silicon macOS executable.
- Intel macOS executable.
- The Erlang runtime and Canaryd resources inside each executable.
- GitHub Release archives and SHA-256 checksums.
- A release command that does not change local launchd state.
- Out of scope:
- Linux and Windows executables.
- Apple Developer ID signing and notarization.
- Automatic updates.
- The existing
macmon 0.8.0system dependency.
Distribution
- Build each executable with Burrito 1.6.0.
- Use one fixed Elixir, Erlang, and Zig version in the release workflow.
- Build
aarch64-apple-darwinandx86_64-apple-darwinassets. - Put one executable in each compressed release archive.
- Publish one SHA-256 checksum file for all archives.
- Publish
rc.Ntags as GitHub prereleases. - Keep the existing escript build for Hex users.
- Publish the matching package and documentation to Hex from the same release workflow.
Behavior
- Start the CLI with the arguments from the Burrito wrapper.
- Use the Burrito wrapper path when Canaryd writes launchd agent files.
- Keep the escript path behavior for an escript installation.
- Run
canaryd --versionwithout installing or loading the launchd agent. - Include ERTS and all
privresources in each executable. - Build each release from an existing semantic version tag.
- Require the tag version to match the Mix project version.
- Check release configuration changes before publication.
- Require explicit confirmation when configuration changes exist.
- Upload both architecture archives and their checksums to GitHub Releases.
- Upload an installation script that selects the correct Mac architecture.
- Verify the selected archive before installing its executable.
- Install the executable as
~/.local/bin/canarydby default. - Add the install directory to the current shell profile when necessary.
- Accept stable tags and
rc.Ntags that match the Mix project version. - Mark each
rc.NGitHub Release as a prerelease. - Resolve every user-specific directory from the runtime user environment.
- Do not include the release build user's home directory in runtime paths.
- Publish the GitHub Release and Hex package from the same version tag.
- Read the Hex publish key only from the
HEX_API_KEYGitHub Actions secret.
BDD Scenarios
BDD-01 Run without a system Erlang installation
Given:
- A user downloaded the executable for the Mac architecture.
- Erlang and Elixir are not present in the command search path.
When:
- The user runs
canaryd --version.
Then:
- Canaryd prints its version.
- Canaryd does not install or load a launchd agent.
- The command exits successfully.
Test Plan:
- Lowest useful level: CLI unit test and packaged executable smoke test.
- First failing test:
--versiondoes not call the setup function. - Follow-up test: run the packaged executable with an isolated
PATH.
BDD-02 Keep the installed executable path
Given:
- Canaryd runs from a Burrito executable.
When:
- Canaryd writes a launchd agent file.
Then:
- The agent command uses the Burrito wrapper path.
- The agent does not use a payload extraction path as its program path.
Test Plan:
- Lowest useful level: unit test for executable path selection.
- First failing test: the Burrito wrapper path has priority over the escript path.
BDD-03 Install with one command
Given:
- A stable GitHub Release contains both architecture archives and checksums.
When:
- The user pipes the release
install.shasset to Bash.
Then:
- The script selects the archive for the current Mac architecture.
- The script stops when SHA-256 verification fails.
- The script installs the executable as
canaryd. - A new shell can find
canarydthroughPATH.
Test Plan:
- Lowest useful level: shell integration test with local release fixtures.
- First failing test: install a verified local archive into an isolated directory.
- Follow-up test: reject an archive with an invalid checksum.
BDD-04 Publish a release candidate
Given:
- An
rc.Ntag matches the Mix project version.
When:
- The release workflow publishes the tag.
Then:
- GitHub marks the release as a prerelease.
- GitHub does not replace the latest stable release.
Test Plan:
- Lowest useful level: workflow contract test.
- Follow-up test: inspect the published GitHub Release.
BDD-05 Use the runtime user's directories
Given:
- A release executable was built by a different macOS user.
- The executable runs with the current user's
HOMEenvironment variable.
When:
- Canaryd installs its notification helper and launchd agent.
- Canaryd reads or writes its state and CleanClip history paths.
Then:
- Canaryd uses directories under the runtime user's home directory.
- Canaryd does not use the release build user's home directory.
Test Plan:
- Lowest useful level: unit tests for all user-specific path functions.
- First failing test: change
HOMEafter module compilation and resolve every user-specific path. - Follow-up test: inspect the packaged executable for a build-user application support path.
BDD-06 Publish the matching Hex package
Given:
- A release tag matches the Mix project version.
- GitHub Actions can read the
HEX_API_KEYsecret.
When:
- The release workflow publishes the tag.
Then:
- GitHub contains the release assets for the tag.
- Hex contains the package and documentation for the same version.
Test Plan:
- Lowest useful level: workflow contract test.
- First failing test: require one Hex publish step with a step-scoped secret.
- Follow-up test: inspect the public Hex package after the workflow completes.
Security and Operations
- Every GitHub Action reference uses a full commit SHA.
- Every action SHA has a readable version comment.
- The workflow uses only the minimum
contents: writepermission. - The release includes SHA-256 checksums.
- The first release is not notarized.
- macOS Gatekeeper can require a manual approval for the downloaded executable.
Acceptance Record
| Scenario | Status | Evidence | Notes |
|---|---|---|---|
| BDD-01 | passed | Canaryd.CLITest; signed ARM64 archive smoke test; x86_64 Rosetta smoke test; isolated PATH | Gatekeeper is not part of the local smoke test. |
| BDD-02 | passed | Canaryd.SetupTest | Both installation formats stay supported. |
| BDD-03 | passed | Canaryd.InstallScriptTest | The test uses local release fixtures. |
| BDD-04 | passed | Canaryd.ReleaseConfigTest | The release workflow adds the GitHub prerelease flag for rc.N tags. |
| BDD-05 | passed | Canaryd.RuntimePathsTest; ARM64 executable run with an isolated HOME; extracted payload inspection | Reported by the v0.3.0-rc.1 user test. |
| BDD-06 | passed | Release workflow, Hex package, and HexDocs | The workflow published 0.3.0 to GitHub and Hex. |