e2e-local.yml runs them on a persistent AWS EC2 self-hosted runner, because the tests boot real microVMs and need hardware virtualization. Below: how CI provisions the machine, how to read a failure, and the exact commands to reproduce the same run locally.
Prerequisites
- A working BoxLite install (Python
boxliteor Node@boxlite-ai/boxlite) and a machine with hardware virtualization — see Installation. - Install build dependencies: CI uses
scripts/setup/setup-ubuntu.sh(Ubuntu). Locally you can use the project’smake setup. - The repository root has a
Makefile(aggregatingmake/*.mk); the test entry point ismake test:integration. - Operating the CI infrastructure requires the GitHub
ghCLI and admin access to the repository (to dispatch the workflow and configure variables/secrets).
Quick Example (shortest reproduction path)
Reproduce locally (same commands as CI)
Tip: make test:integration actually boots microVMs. On a clean machine the first run compiles the whole toolchain first (roughly 5-10 minutes); subsequent runs reuse the cache and are significantly faster.
make test vs make test:integration:cli
These two targets are not interchangeable:
-
make testismake test:changed: it inspects the working tree, maps changed components to suites, and runs only those. With no detected changes it runs nothing (usemake test:allfor the full unit + integration matrix). Each changed component maps to its own suite — for example, a CLI change runsmake test:integration:cli. -
make test:integration:cliruns only the CLI integration tests. It depends onruntime:debug(it builds the debug runtime first unless setup already ran), then runs the suite with--no-fail-fastso one failure does not hide the rest:
boxlite binary against a microVM. They therefore require the same virtualization environment as the rest of make test:integration (KVM on Linux, Hypervisor.framework on macOS). To keep first-run image pulls cheap and avoid registry rate limits, a shared, pre-warmed cache is set up once per test process and the standard test images (alpine:latest, debian:bookworm-slim, python:alpine) are pre-pulled and reused. For how the CLI test harness itself is structured, see the CLI Development Guide.
Trigger a run in CI
How it runs (workflow structure)
The workflow has four jobs:
Note on the single-instance design: the workflow keeps one persistent EC2 instance for this test suite — started before a run and stopped afterward (never terminated) — so the build and image caches remain on the EBS volume. Because there is only one instance, only one e2e run can proceed at a time; a newer run cancels an older queued run.
Triggers
Note on source prefixes: the trigger paths use the real repository layoutsrc/<crate>/(src/boxlite,src/shared,src/cli,src/guest) andsdks/**, not the oldboxlite/src/prefix.
Instance & auth
Keeping the instance warm is why repeat runs are faster: a clean instance’s first run requires a full compile (roughly 5-10 minutes of initialization), after which it reuses the cached toolchain and build artifacts. Running cost is the instance’s on-demand rate while a run is in progress, plus the persistent root volume; price it against your own account and region.
Authentication uses no long-lived secrets:
- AWS — GitHub OIDC is exchanged for short-lived STS credentials via the
boxlite-e2e-github-actionsIAM role. No AWS key is stored in the repository. - GitHub — a GitHub App (
boxlite-e2e-runner) issues runner registration tokens at run time. There is no personal access token.
One-time setup (provisioning)
All AWS and GitHub infrastructure is provisioned by a single script:
And it sets the following on the repository:
The GitHub App is created through a script-driven browser manifest flow — follow the prompts to confirm and install the App.
EC2_E2E_INSTANCE_ID is written automatically the first time the instance is created; later runs use it to locate the instance directly.
Once provisioning is complete, trigger a run:
Parameters & Returns (key parameters)
Workflow environment and inputs (frome2e-local.yml):
Relevant make targets available locally:
The authoritative target list ismake help(aggregated inmake/help.mk); the table above is the common subset.
Troubleshooting
References (source)
The links below point to real files in the repository (these are for contributors to open directly):- Workflow:
.github/workflows/e2e-local.yml - Provisioning script:
scripts/ci/setup-ci-runner.sh - Build-dependency install:
scripts/setup/setup-ubuntu.sh - Test entry point (make targets):
Makefile+make/*.mk(runmake helpfor all targets) - CI overview:
.github/workflows/README.md
See also
- CLI Development Guide — building and testing the BoxLite CLI, including how the CLI integration tests differ from the full matrix.

