Build Envoy on a remote Mac mini and publish the binary as a GitHub release asset.
SSHes to your Mac mini, runs a Bazel build, streams logs live, downloads the result via scp, and publishes it to a GitHub release — all from a single command. Linux builds run inside OrbStack VMs on the mini.
sshandscp(standard on macOS/Linux)gh— GitHub CLI, authenticated
brew install gh
gh auth login-
OrbStack on the Mac mini — required for Linux builds; macOS builds run natively
Both Linux machines must use Debian 11 (Bullseye) — the bundled Envoy sysroots require glibc < 2.34:
orb create --arch arm64 debian:11 linux-arm64 orb create --arch amd64 debian:11 linux-amd64
brew install dio/tap/envoy-mini-builderOr download a binary from the releases page.
envoy-mini-builder build --sha <ref> [flags]
| Flag | Default | Description |
|---|---|---|
--sha |
(required) | Commit SHA, branch, or tag |
--repo |
envoyproxy/envoy |
Source repo (owner/repo); forks work |
--patch |
Patch applied before build: https:// URL or file:// local path |
|
--tag |
envoy-{sha8} |
Override release tag; required for variant builds |
--no-release |
false |
Build only, skip release create/upload |
--force-build |
false |
Always rebuild even if the asset already exists |
--out |
./dist |
Local directory for the downloaded binary |
--suffix |
Suffix appended to binary/asset name (e.g. -patched) |
|
--no-strip |
false |
Skip post-build strip -x |
--platform |
darwin-arm64 |
Target: darwin-arm64 | linux-arm64 | linux-amd64 |
--all-platforms |
false |
Build all supported platforms under one release |
--host |
dio@mini |
SSH host of the Mac mini |
--port |
22 |
SSH port |
--jobs |
HOST_CPUS |
Bazel --jobs value |
--bazel-arg |
Extra Bazel flag; repeatable; prefix platform: to scope (e.g. linux-arm64:--flag) |
|
--gh-repo |
dio/envoy-builder |
GitHub repo for release assets |
--bb-key |
BuildBuddy API key; see env vars below | |
--detach |
false |
Start build in background on the mini; use jobs/logs/fetch to manage |
# Minimal: build main, publish to dio/envoy-builder
envoy-mini-builder build --sha main
# All platforms under one release tag
envoy-mini-builder build --sha main --all-platforms
# Detached: start builds in background, check later
envoy-mini-builder build --sha main --all-platforms --detach
envoy-mini-builder jobs
envoy-mini-builder fetch envoy-abc123ef
# Fork + patch + custom tag
envoy-mini-builder build \
--repo your-org/envoy \
--sha a1b2c3d4 \
--patch https://raw.githubusercontent.com/.../my.patch \
--suffix -patched \
--tag envoy-a1b2c3d4-patched
# Build only, no release
envoy-mini-builder build --sha main --no-release --out ./dist
# Custom SSH host
envoy-mini-builder build --sha main --host user@192.168.1.10 --port 2222| Variable | Description |
|---|---|
BUILDBUDDY_API_KEY_DARWIN_ARM64 |
BuildBuddy key for darwin arm64 builds |
BUILDBUDDY_API_KEY_LINUX_ARM64 |
BuildBuddy key for Linux arm64 builds |
BUILDBUDDY_API_KEY_LINUX_AMD64 |
BuildBuddy key for Linux amd64 builds |
BUILDBUDDY_API_KEY |
Fallback key used when no platform-specific var is set |
test run compiles and runs Bazel test targets on the remote Mac mini without
producing a release binary. The main use-case is validate a patch before
building: apply the patch remotely, compile the affected test, run it,
stream the output live.
1. List test targets matching your change
# All test targets under the affected package
envoy-mini-builder test ls --sha 0d6e3c60aa55 \
--path test/extensions/clusters/dynamic_modules/...
# Narrow by name glob
envoy-mini-builder test ls "*cluster*" --sha 0d6e3c60aa55 \
--path test/extensions/clusters/...
# Only unit tests (size = small or medium)
envoy-mini-builder test ls --sha 0d6e3c60aa55 --type unit \
--path test/extensions/clusters/dynamic_modules/...Sample output:
//test/extensions/clusters/dynamic_modules:cluster_test
1 test target(s)
If your patch adds new cc_test targets, pass --patch to see them:
envoy-mini-builder test ls --sha 0d6e3c60aa55 \
--patch file:///path/to/my.patch \
--path test/extensions/clusters/dynamic_modules/...2. Run the whole test target
envoy-mini-builder test run \
--sha 0d6e3c60aa55 \
--patch file:///path/to/my.patch \
--target //test/extensions/clusters/dynamic_modules:cluster_testThe patch is uploaded via scp before the script runs; the remote
git apply happens inside the already-cloned workspace, so only the
incremental diff is compiled.
3. Run a single GTest case
Use --filter to pass --test_filter to Bazel (forwarded as
--gtest_filter inside the binary). Any GTest filter syntax works:
# Exact case
envoy-mini-builder test run \
--sha 0d6e3c60aa55 \
--patch file:///path/to/my.patch \
--target //test/extensions/clusters/dynamic_modules:cluster_test \
--filter "DynamicModuleClusterTest.AbiCallbacksAddHostsWithHostnames"
# Glob across cases in a suite
envoy-mini-builder test run \
--sha 0d6e3c60aa55 \
--patch file:///path/to/my.patch \
--target //test/extensions/clusters/dynamic_modules:cluster_test \
--filter "DynamicModuleClusterTest.*Hostname*"4. Multiple targets at once
--target is repeatable:
envoy-mini-builder test run \
--sha 0d6e3c60aa55 \
--patch file:///path/to/my.patch \
--target //test/extensions/clusters/dynamic_modules:cluster_test \
--target //test/extensions/dynamic_modules:abi_testquery runs a raw bazel query and prints all matching labels — not just
test targets. Useful for checking BUILD visibility or locating a library:
envoy-mini-builder query "dynamic_module*" --sha main \
--path source/extensions/clusters/dynamic_modules/...Both --patch flags accept:
| Form | Behaviour |
|---|---|
https://… or http://… |
fetched with curl on the remote |
file:///abs/path/to/file.patch |
uploaded via scp to a temp path; deleted on exit |
| Flag | Default | Description |
|---|---|---|
--sha |
(required) | Commit SHA, branch, or tag |
--patch |
Patch: https:// URL or file:// local path |
|
--target |
(required for run) |
Bazel test target; repeatable |
--filter |
GTest filter (--test_filter value) |
|
--path |
... |
Package path for ls |
--type |
unit or integration (size-based) for ls |
|
--repo |
envoyproxy/envoy |
Source repo |
--host |
dio@mini |
SSH host |
--port |
22 |
SSH port |
--jobs |
HOST_CPUS |
Bazel --jobs |
--bb-key |
BuildBuddy API key (remote cache) | |
--platform |
darwin-arm64 |
darwin-arm64 | linux-arm64 | linux-amd64 |
--detach starts the build in the background on the mini and returns immediately.
# Start
envoy-mini-builder build --sha main --all-platforms --detach
# Check status
envoy-mini-builder jobs
# Tail logs for a specific platform
envoy-mini-builder logs envoy-abc123ef --platform linux-arm64
# Download and publish once done
envoy-mini-builder fetch envoy-abc123ef
# Cancel and clean up
envoy-mini-builder cancel envoy-abc123effetch creates the GitHub release, uploads binaries, and publishes it — then removes local job state.
For each platform the CLI first checks the release for an existing asset. If found it is downloaded; its .params.json sidecar is verified to match current build params. Only missing or mismatched assets trigger a remote build. Use --force-build to always rebuild.
The auto tag envoy-{sha8} is reserved for default-param builds (envoyproxy/envoy, no patch, no extra Bazel args, no --no-strip). Variant builds must supply --tag explicitly — the CLI errors otherwise.
macOS builds
- SSH to the mini, pipe the build script to
bash -s - Stream build logs live; capture
BINARY_PATH:…sentinel from stdout - Download the binary via
scp - Upload to GitHub release via
gh
Linux builds
Same, but the build script runs inside an OrbStack VM via orb run -m <machine>. The binary lives inside the VM, so it is streamed directly to the local machine via orb run -m <machine> cat <path> over the existing SSH connection — no intermediate staging needed.
Mac mini — uses your local ssh-agent or ~/.ssh/id_{ed25519,rsa,ecdsa}. No passwords.
GitHub — uses gh CLI. Run gh auth login once; the token is never forwarded to the mini.
BuildBuddy — the API key is forwarded to the mini as a process environment variable, written to .bazelrc.cache outside the workspace, and deleted on script exit via trap. Never written to shell history or any persistent config.
git clone https://github.com/dio/envoy-mini-builder
cd envoy-mini-builder
go build -o envoy-mini-builder .MIT