Continuous Integration
All CI for cardano-wallet runs on GitHub Actions. Workflows are defined in .github/workflows/.
Workflows
Core CI
| Workflow | Trigger | Description |
|---|---|---|
ci.yml | push, PR | Main build & test pipeline — Linux unit/integration tests, builds all artifacts |
Platform-specific
| Workflow | Trigger | Description |
|---|---|---|
windows.yml | push, dispatch | Windows build & unit tests (self-hosted) |
macos-unit-tests.yml | push, dispatch | macOS unit tests (self-hosted Apple Silicon) |
macos-integration.yml | dispatch | macOS integration tests (self-hosted) |
End-to-end
| Workflow | Trigger | Description |
|---|---|---|
linux-e2e.yml | push, dispatch | Linux E2E tests against preprod |
windows-e2e.yml | dispatch | Windows E2E tests (self-hosted) |
Benchmarks & sync
| Workflow | Trigger | Description |
|---|---|---|
linux-benchmarks.yml | push, dispatch | Restoration benchmarks on mainnet (long-running) |
linux-mithril-sync.yml | push, dispatch | Mithril snapshot sync test |
Release
| Workflow | Trigger | Description |
|---|---|---|
release.yml | push, tags | Creates release candidate branches and release artifacts |
publish.yml | push, tags, PR | Publishes documentation to GitHub Pages |
Housekeeping
| Workflow | Trigger | Description |
|---|---|---|
cleanup.yml | dispatch | Deletes old workflow runs |
approve-docs.yml | PR target | Auto-approves docs-only PRs |
lean.yml | push, PR | Lean specification checks (path-filtered to specifications/) |
Nix verbosity
All nix commands in CI workflows must include the --quiet flag. This suppresses verbose build logs and warnings that clutter GitHub Actions output, making it easier to spot actual failures.
# Good
nix build --quiet .#cardano-wallet
nix shell --quiet .#cardano-node -c cardano-node --version
nix develop --quiet --command scripts/check.sh
# Bad — missing --quiet
nix build .#cardano-wallet
nix build -L .#cardano-wallet
When adding or modifying workflow steps that invoke nix, always include --quiet.
Self-hosted runners
Several workflows run on self-hosted machines. The GHA runner service replaces the former Buildkite agent on these machines.
Windows machine
System configuration
We assume the machine is configured with a recent Windows version (2022 Server) and has winget installed.
- Install the GitHub Actions runner as a Windows service
- Install the Ruby environment in version 2.7 using winget (needed for E2E tests):
winget install RubyInstallerTeam.Ruby.2.7 --force --disable-interactivity --accept-source-agreements --accept-package-agreements - Install Ruby installer toolkit to be able to compile native extensions:
ridk install - Install some more packages:
winget install zstandard— decompressing hosted archiveswinget install nssm— running cardano-node as a service
Runner configuration
- When launched as a service, the GHA runner runs as the
Local System Accountwhich does not inherit the environment from thehaluser. Ensure software installed throughwingetis on the runner's PATH. - Configure environment secrets (
FIXTURE_DECRYPTION_KEY, etc.) via the runner's.envfile or repository/org-level GitHub Actions secrets. - Ensure node DB files can be removed (they are created readonly which breaks
git clean -xfd):icacls . /grant hal:F /T /Q - Ensure
cardano-nodeandcardano-walletservices are cleaned up after each run to avoid leaks from interrupted workflows.
Troubleshooting
Windows permissions are complex. Stick to the default Local System Account as the user for the runner service.
-
Ensure the user
SYSTEMhas full control to the runner work directory and this right is inherited:PS C:\actions-runner> icacls.exe . . NT AUTHORITY\SYSTEM:(OI)(CI)(F) BUILTIN\Administrators:(F) ZUR1-S-D-027\hal:(OI)(CI)(F) -
To operate under the right identity, use pstools:
psexec -s -i cmd -
If steps fail to delete the checkout directory, ensure no other process is locking it.
macOS machine (hal-mac)
The macOS builder runs on a Mac Mini (Apple Silicon) managed via nix-darwin. Access via SSH through the jumpbox:
ssh mac-builder # requires SSH config with ProxyJump through jumpbox-dev
Runner configuration
The GHA runner runs as a launchd service. Key paths:
- Service plist:
/Library/LaunchDaemons/org.nixos.github-runner-hal-mac.plist - Runner directory:
/var/lib/github-runner-hal-mac/ - Log file: check via
journalctlor the runner's_diag/directory
Updating the runner token
If the runner token expires or becomes invalid:
- Create a new runner token at the repository's Settings > Actions > Runners page
- Update the token on the machine:
ssh mac-builder # Re-configure the runner with the new token - Restart the runner:
sudo launchctl kickstart -k system/org.nixos.github-runner-hal-mac - Verify the runner is connected in the repository's Settings > Actions > Runners page
Environment variables
Secrets are configured via:
ATTIC_TOKEN— from/var/lib/gha-runner-hal-mac/env-attic-tokenFIXTURE_DECRYPTION_KEY— from/var/lib/gha-runner-hal-mac/env-fixture-decryption-keyHAL_E2E_PREPROD_MNEMONICS— from/var/lib/gha-runner-hal-mac/env-hal-e2e-preprod-mnemonics
Troubleshooting
- Check runner status: repository Settings > Actions > Runners
- View logs: check the runner's
_diag/directory - Restart service:
sudo launchctl kickstart -k system/org.nixos.github-runner-hal-mac - Stop service:
sudo launchctl stop system/org.nixos.github-runner-hal-mac
Attic cache failures
The Attic cache job pushes build artifacts to the Attic cache server. If it fails:
-
Check Attic token — The JWT token in
/var/lib/gha-runner-hal-mac/env-attic-tokenmay have expired. Decode it:cat /var/lib/gha-runner-hal-mac/env-attic-token | cut -d. -f2 | base64 -dLook for the
expfield (Unix timestamp). -
Test Attic login:
ATTIC_TOKEN=$(cat /var/lib/gha-runner-hal-mac/env-attic-token) nix-shell -p attic-client --run "attic login adrestia https://attic.cf-app.org/ $ATTIC_TOKEN" -
Verify Attic server is reachable:
curl -I https://attic.cf-app.org/ -
SSL Certificate Error — If you see
invalid peer certificate: UnknownIssuer, the machine may be resolvingattic.cf-app.orgto an internal IP with an untrusted certificate.Check which IP is being used:
ping -c1 attic.cf-app.orgIf it resolves to an internal IP (e.g.,
10.1.21.x), override with the external IP in/etc/hosts:sudo sed -i '' 's/ attic.cf-app.org//g; s/ attic//g' /etc/hosts echo "195.48.82.220 attic.cf-app.org" | sudo tee -a /etc/hosts
Stale processes
Test cluster processes (cardano-node) may accumulate if builds are interrupted:
ps aux | grep cardano-node
pkill -f "cardano-node.*test-cluster"