Skip to content

test: run the regtest stack on an ephemeral VM - #204

Draft
mdozhdev wants to merge 1 commit into
synonymdev:mainfrom
mdozhdev:test/remote-regtest-backend
Draft

test: run the regtest stack on an ephemeral VM#204
mdozhdev wants to merge 1 commit into
synonymdev:mainfrom
mdozhdev:test/remote-regtest-backend

Conversation

@mdozhdev

Copy link
Copy Markdown

Problem

e2e-tests-local needs the regtest stack and the iOS Simulator on the same machine, because the app reaches Electrum and homegate on 127.0.0.1. GitHub-hosted macOS runners cannot run Docker — Apple's Virtualization framework has no nested virtualization for macOS guests, and GitHub closed the request as not planned in January 2026.

So the iOS suite runs on a self-hosted Mac. One machine, one owner, and because it is one machine the suite runs as a single shard: 104–127 min per run, against 12–24 min for the same suite on Android's GitHub-hosted Linux runners.

What this adds

Tooling to run the stack on a short-lived GCP VM, so the Mac only does the one thing only a Mac can do.

regtest-vm-up provisions a VM, opens a firewall scoped to the runner's egress /32, waits until the stack actually serves rather than merely listens
startup.sh on the VM: installs Docker, unpacks the stack from instance metadata, starts it, publishes LND's tls.cert and admin.macaroon on a random path
regtest-vm-down deletes the VM and the rule
regtest-reaper sweeps orphaned firewall rules, which have no native TTL
regtest-vm-smoke exercises the above without running the suite
setup-wif.sh one-off Workload Identity Federation setup

Two decisions worth knowing:

  • The stack travels in instance metadata, not a clone. The VM needs no repository access and no token, and the stack always matches the checkout the tests run from — no second ref to keep in sync.
  • Instances carry --max-run-duration with --instance-termination-action=DELETE, so GCE removes them even if teardown never runs. The reaper only exists because firewall rules have no equivalent.

Behaviour changes

Four, all keeping their current defaults, so existing runs are unaffected:

  • docker-compose.yml — LND advertises LND_EXTERNAL_IP instead of 127.0.0.1
  • constants.tslndConfig host, ports and credential paths from env
  • lnd.tsconnectToLND uses the configured host
  • wdio.conf.ts — forwards E2E_LOCAL_HOST into the app's launch environment

That is 29 lines of behaviour change; the rest is new, self-contained tooling.

Verified

On a GitHub-hosted macOS runner: VM provisioned, firewall scoped correctly, stack booted, bitcoind mining on regtest, LND reachable, credentials fetched, and a request from inside a booted Simulator recorded in the VM's own access log. Teardown left no orphaned resources.

Not yet verified: a full suite run against a remote stack. That needs the companion workflow in bitkit-ios and a configured GCP project.

Configuration needed before anything runs

Nothing project-specific is committed. A maintainer runs ci/regtest-vm/setup-wif.sh against a bitkit CI project and sets what it prints:

vars.REGTEST_GCP_PROJECT
secrets.REGTEST_WIF_PROVIDER
secrets.REGTEST_SERVICE_ACCOUNT

All new workflows are workflow_dispatch only, so merging without that configuration changes nothing and breaks nothing.

Related

  • synonymdev/pubky-stack#275
  • Companion PR in bitkit-ios adds the workflow that consumes these actions.

The iOS e2e suite needs the regtest stack and the iOS Simulator on one
machine, because the app reaches Electrum and homegate on 127.0.0.1.
GitHub-hosted macOS runners cannot run Docker — Apple's Virtualization
framework has no nested virtualization for macOS guests — so the suite
runs on a self-hosted Mac, serially, at ~2h per run against ~20m for the
same tests on Linux.

Add tooling to run the stack on a short-lived GCP VM instead, so the Mac
only has to do the one thing only a Mac can do.

  regtest-vm-up    provisions a VM, opens a firewall scoped to the
                   runner's egress /32, waits until the stack actually
                   serves rather than merely listens
  startup.sh       runs on the VM: installs Docker, unpacks the stack
                   from instance metadata, starts it, publishes LND's
                   tls.cert and admin.macaroon on a random path
  regtest-vm-down  deletes the VM and the rule
  regtest-reaper   sweeps orphaned firewall rules, which have no TTL
  regtest-vm-smoke exercises the above without running the suite
  setup-wif.sh     one-off Workload Identity Federation setup

The stack travels as a base64 tarball in instance metadata rather than
being cloned, so the VM needs no repository access and no token, and the
stack always matches the checkout the tests run from. Instances carry
--max-run-duration with --instance-termination-action=DELETE, so GCE
removes them even if teardown never runs.

Four changes let the tests and the app address a non-local stack, all
keeping their current defaults:

  docker-compose.yml  LND advertises LND_EXTERNAL_IP, not 127.0.0.1
  constants.ts        lndConfig host, ports and credential paths from env
  lnd.ts              connectToLND uses the configured host
  wdio.conf.ts        forwards E2E_LOCAL_HOST into the app's launch
                      environment, which is how a build made before the
                      VM existed learns its address

Verified on a GitHub-hosted macOS runner: VM provisioned, stack reached,
credentials fetched, and a request from inside a booted Simulator
recorded in the VM's own access log.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.

1 participant