The `image build` flow spun up a transient Firecracker VM, SSHed in, and ran a large bash provisioning script to derive a new managed image from an existing one. It overlapped heavily with the golden- image Dockerfile flow (same mise/docker/tmux/opencode install logic duplicated in Go as `imagemgr.BuildProvisionScript`) and had far more machinery: async op state, RPC begin/status/cancel, webui form + operation page, preflight checks, API types, tests. For custom images, writing a Dockerfile is simpler and more reproducible. Removed end-to-end: - CLI `image build` subcommand + `absolutizeImageBuildPaths`. - Daemon: BuildImage method, imagebuild.go (transient-VM orchestration), image_build_ops.go (async begin/status/cancel), imagemgr/build.go (the 247-line provisioning script generator and all its append* helpers), validateImageBuildPrereqs + addImageBuildPrereqs. - RPC dispatches for image.build / .begin / .status / .cancel. - opstate registry `imageBuildOps`, daemon seam `imageBuild`, background pruner call. - API types: ImageBuildParams, ImageBuildOperation, ImageBuildBeginResult, ImageBuildStatusParams, ImageBuildStatusResult; model type ImageBuildRequest. - Web UI: Backend interface methods, handlers, form, routes, template branches (images.html build form, operation.html build branch, dashboard.html Build button). - Tests that directly exercised BuildImage. Doctor polish (task C): - Drop the "image build" preflight section entirely (its raison d'être is gone). - Default-image check now accepts "not local but in imagecat" as OK: vm create auto-pulls on first use. Only flag when the image is neither locally registered nor in the catalog. Net: 24 files touched, 1,373 lines deleted, 25 added. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
191 lines
5.6 KiB
Markdown
191 lines
5.6 KiB
Markdown
# banger
|
|
|
|
One-command development sandboxes on Firecracker microVMs.
|
|
|
|
## Quick start
|
|
|
|
```bash
|
|
make install
|
|
banger vm run --name sandbox
|
|
```
|
|
|
|
`banger vm run` auto-pulls the default golden image (Debian bookworm
|
|
with systemd, sshd, Docker CE, git, jq, mise, and the usual dev tools)
|
|
and kernel from the embedded catalog if they aren't already local,
|
|
creates a VM, starts it, and drops you into an interactive ssh
|
|
session. First run takes a couple minutes (bundle download);
|
|
subsequent `vm run`s are seconds.
|
|
|
|
## Requirements
|
|
|
|
- Linux with `/dev/kvm`
|
|
- `sudo`
|
|
- Firecracker on `PATH`, or `firecracker_bin` set in config
|
|
- host tools checked by `banger doctor`
|
|
|
|
## Build + install
|
|
|
|
```bash
|
|
make install
|
|
```
|
|
|
|
Installs:
|
|
|
|
- `banger` (CLI)
|
|
- `bangerd` (daemon, auto-starts on first CLI call)
|
|
- `banger-vsock-agent` (companion, under `$PREFIX/lib/banger/`)
|
|
|
|
## `vm run`
|
|
|
|
One command, three modes:
|
|
|
|
```bash
|
|
banger vm run # bare sandbox — drops into ssh
|
|
banger vm run ./repo # workspace at /root/repo — drops into ssh
|
|
banger vm run ./repo -- make test # workspace + run command, exit with its status
|
|
```
|
|
|
|
- Bare mode gives you a clean shell.
|
|
- Workspace mode (with a path) copies the repo's tracked + untracked
|
|
non-ignored files into `/root/repo` and kicks off a best-effort
|
|
mise tooling bootstrap from the repo's `.mise.toml` /
|
|
`.tool-versions`. Log: `/root/.cache/banger/vm-run-tooling-<repo>.log`.
|
|
- Command mode (`-- <cmd>`) runs the command in the guest; exit code
|
|
propagates through `banger`.
|
|
|
|
Disconnecting from an interactive session leaves the VM running. Use
|
|
`vm stop` / `vm delete` to clean up.
|
|
|
|
`--branch` and `--from` apply only to workspace mode.
|
|
|
|
## Image catalog
|
|
|
|
`banger image pull <name>` resolves `<name>` in the embedded catalog
|
|
and fetches a pre-built bundle (rootfs.ext4 + manifest, tar+zstd). The
|
|
kernel referenced by the manifest auto-pulls too. `vm run` calls this
|
|
for you on demand.
|
|
|
|
Today's catalog:
|
|
|
|
| Name | Distro | Kernel |
|
|
|------|--------|--------|
|
|
| `debian-bookworm` | Debian 12 slim + sshd + docker + dev tools | `generic-6.12` |
|
|
|
|
The catalog ships embedded in the banger binary. See
|
|
[`docs/image-catalog.md`](docs/image-catalog.md) for maintenance.
|
|
|
|
## Power-user flows
|
|
|
|
Skip this section if `vm run` is enough.
|
|
|
|
### `vm create` — low-level primitive
|
|
|
|
For scripting or `--no-start` provisioning:
|
|
|
|
```bash
|
|
banger vm create --image debian-bookworm --name testbox --no-start
|
|
banger vm start testbox
|
|
banger vm ssh testbox
|
|
banger vm stop testbox
|
|
```
|
|
|
|
### `image pull <oci-ref>` — arbitrary container images
|
|
|
|
For images outside the catalog, pull from any OCI registry:
|
|
|
|
```bash
|
|
banger image pull docker.io/library/alpine:3.20 --kernel-ref generic-6.12
|
|
```
|
|
|
|
Layers are flattened, ownership is fixed, banger's guest agents are
|
|
injected, and a first-boot service installs `openssh-server` via the
|
|
guest's package manager. See [`docs/oci-import.md`](docs/oci-import.md)
|
|
for supported distros and caveats.
|
|
|
|
### `image register` — existing host-side stack
|
|
|
|
```bash
|
|
banger image register --name base \
|
|
--rootfs /abs/path/rootfs.ext4 \
|
|
--kernel-ref generic-6.12
|
|
```
|
|
|
|
For custom images, write a Dockerfile and either publish to the
|
|
catalog (see `docs/image-catalog.md`) or pull it via the OCI path.
|
|
|
|
### Workspace + session primitives
|
|
|
|
Long-lived guest commands managed by the daemon, attachable over a
|
|
local Unix socket bridge:
|
|
|
|
```bash
|
|
banger vm workspace prepare <vm> ./other-repo --guest-path /root/repo
|
|
banger vm session start <vm> --name planner --cwd /root/repo --stdin-mode pipe -- pi --mode rpc
|
|
banger vm session attach <vm> planner
|
|
banger vm session logs <vm> planner --stream stderr
|
|
banger vm session stop <vm> planner
|
|
```
|
|
|
|
For ACP-aware host tooling: `banger vm acp <vm>` bridges stdio to
|
|
guest `opencode acp` over SSH.
|
|
|
|
## Config
|
|
|
|
Config lives at `~/.config/banger/config.toml`. All keys optional.
|
|
|
|
Commonly set:
|
|
|
|
- `default_image_name` — image to use when `--image` is omitted
|
|
(defaults to `debian-bookworm`, auto-pulled from the catalog if not
|
|
local).
|
|
- `ssh_key_path` — host SSH key; if unset banger creates
|
|
`~/.config/banger/ssh/id_ed25519`.
|
|
- `firecracker_bin` — override the auto-resolved `PATH` lookup.
|
|
- `web_listen_addr` — experimental web UI (default
|
|
`127.0.0.1:7777`; set to `""` to disable).
|
|
- Network: `bridge_name`, `bridge_ip`, `cidr`, `tap_pool_size`,
|
|
`default_dns`.
|
|
|
|
Full key list in `internal/config/config.go`.
|
|
|
|
## Credential sync
|
|
|
|
If these host auth files exist, banger syncs them into the guest at
|
|
VM start:
|
|
|
|
| Host | Guest |
|
|
|------|-------|
|
|
| `~/.local/share/opencode/auth.json` | `/root/.local/share/opencode/auth.json` |
|
|
| `~/.claude/.credentials.json` | `/root/.claude/.credentials.json` |
|
|
| `~/.pi/agent/auth.json` | `/root/.pi/agent/auth.json` |
|
|
|
|
Host-side changes take effect after the VM restarts. Session/history
|
|
directories are not copied.
|
|
|
|
## Web UI (experimental)
|
|
|
|
`bangerd` serves a local web UI at `http://127.0.0.1:7777` by default.
|
|
Convenient for local observability, **not a stable interface**. Do
|
|
not expose the listen address to a shared network.
|
|
|
|
## Security
|
|
|
|
Guest VMs are single-user development sandboxes, not multi-tenant
|
|
servers. Every provisioned image is configured with:
|
|
|
|
```
|
|
PermitRootLogin yes
|
|
StrictModes no
|
|
```
|
|
|
|
The host SSH key is the only authentication mechanism, no password
|
|
auth is enabled, and VMs are reachable only through the host bridge
|
|
network (`172.16.0.0/24` by default). Do not expose the bridge
|
|
interface or guest IPs to an untrusted network.
|
|
|
|
## Notes
|
|
|
|
- Managed image delete removes the daemon-owned artifact dir.
|
|
- Layer blob cache for OCI pulls lives under `~/.cache/banger/oci/`.
|
|
- Image bundle cache doesn't exist — bundles are extracted directly
|
|
into the image store; re-pulls download fresh.
|