Skip to content

ci(release): build, sign and publish wallet bundles for linux/darwin × amd64/arm64 - #41

Merged
TeoSlayer merged 2 commits into
mainfrom
ci/release-all-platforms
Oct 1, 2026
Merged

TeoSlayer merged 2 commits into
mainfrom
ci/release-all-platforms

Conversation

@TeoSlayer

Copy link
Copy Markdown
Contributor

Problem

The catalogue's io.pilot.wallet 0.3.3 entry has a single top-level bundle_url: wallet-v0.3.3 on pilot-protocol/pilotprotocol. It contains a darwin/arm64 Mach-O built by hand on a Mac (CGO_ENABLED=1, go1.25.3) and has no bundles map.

  • pilotctl before v1.13.10 installs it on every platform, and it then cannot exec:
    • linux/amd64 and linux/arm64 (debian:bookworm-slim): exec /b/bin/wallet: exec format error
    • Intel Mac (arch -x86_64): Bad CPU type in executable
  • pilotctl v1.13.10 refuses it with a platform mismatch.

This repo has no releases, no Actions secrets and no release workflow.

Change

.github/workflows/release.yml runs on a v* tag, or on workflow_dispatch with an existing tag:

  1. go test -race ./...
  2. Native CGO_ENABLED=0 go build -trimpath -ldflags='-s -w' on ubuntu-latest, ubuntu-24.04-arm, macos-15-intel and macos-15. Each job asserts the file output for its target and requires wallet -version to equal the tag.
  3. Pins the binary's sha256 into manifest.json and signs it with pilotctl appstore sign, using the PILOT_APP_PUBLISHER_KEY secret. It asserts that the publisher is the catalogue pin ed25519:VF8fdEP/Oe2aWN3ozQ7Ar22137tHb7dkSw0hlzlk/os=.
    • pilotctl is built from pilotprotocol v1.13.10, not main, because this step holds the private key.
  4. Packs io.pilot.wallet-<ver>-<os>-<arch>.tar.gz with the new scripts/pack-bundle.py:
    • The layout is manifest.json + bin/wallet, the same entries as the 0.3.3 bundle.
    • Packing is deterministic: owner 0:0, fixed mtime, gzip header without name or time.
    • No macOS AppleDouble or xattr entries.
  5. Publishes the four bundles with .sha256 files, checksums.txt and build provenance (actions/attest-build-provenance@v3).

The workflow is based on the unpushed WIP commit eb261f2, with three changes: the pilotctl ref is pinned, packing is deterministic, and the README has a Release section.

Verified locally

Before the first release (maintainer)

  1. Add the repo secret PILOT_APP_PUBLISHER_KEY (the private key for ed25519:VF8f…/os=). gh secret list -R pilot-protocol/wallet is empty today.
  2. Merge fix(wallet): exit when the daemon dies, stop per-call logging, never unlink a successor's socket #40, then tag (e.g. v0.4.0: cmd/wallet Version and manifest.json app_version are both 0.4.0).
  3. Update the catalogue in pilotprotocol:
    • Add a bundles entry for each platform.
    • Approve the stateful-app bump in catalogue/stateful-apps.json. catalogue-lint blocks wallet updates until the fleet runs a pilotctl with the app-state fix, v1.13.10.
    • Update the metadata and re-sign catalogue.json.

🤖 Generated with Claude Code

…forms

The catalogue ships io.pilot.wallet as a single darwin/arm64 Mach-O: the
top-level bundle_url of the wallet-v0.3.3 release on pilotprotocol, built
by hand with CGO. As a result:
- pilotctl before v1.13.10 installs it on every platform, and it cannot
  exec on linux/amd64, linux/arm64 or Intel Macs ("exec format error",
  "Bad CPU type in executable").
- v1.13.10 refuses it with platform_mismatch.
This repo has no release pipeline.

release.yml runs on a v* tag (or workflow_dispatch with a tag). It:
1. Runs the tests.
2. Builds CGO_ENABLED=0 binaries natively on ubuntu-latest,
   ubuntu-24.04-arm, macos-15-intel and macos-15, and asserts `file` output
   and `wallet -version` == tag.
3. Pins the sha256 into manifest.json and signs it with
   `pilotctl appstore sign`, using the PILOT_APP_PUBLISHER_KEY secret.
   Publisher must equal the catalogue pin ed25519:VF8f…/os=. pilotctl is
   built from the pinned tag v1.13.10, not from main, because this step
   holds the private key.
4. Packs io.pilot.wallet-<ver>-<os>-<arch>.tar.gz with
   scripts/pack-bundle.py. The packing is deterministic (0:0, fixed mtime,
   no AppleDouble/xattr entries from macOS tar).
5. Publishes the four bundles with checksums.txt and build provenance.

The workflow is based on the WIP commit eb261f2, with three changes: the
pilotctl ref is pinned, packing is deterministic, and it has a README
section.

Checked locally:
- actionlint passes.
- The build job's steps, run against pilotctl v1.13.10 with a throwaway
  key, produce a bundle whose signature, publisher pin, binary sha256 and
  Mach-O arm64 format all verify.

Before the first release, a maintainer must add the PILOT_APP_PUBLISHER_KEY
secret. `gh secret list -R pilot-protocol/wallet` is empty today.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Sep 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@TeoSlayer
TeoSlayer merged commit 7138daf into main Oct 1, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants