Install opencode in Void rootfs

Bring the experimental Void image closer to the default dev image path by installing pinned mise inside the rootfs build, using it to install opencode, and activating mise automatically for root bash sessions.

Keep the change scoped to the Void builder rather than packages.void so the image still stays language-agnostic at the package-manifest level, then clean mise download/cache artifacts before sealing the rootfs and work-seed.

Extend verify-void so the smoke path now proves mise and opencode are actually present in a fresh void-exp VM. Verified with bash -n make-rootfs-void.sh verify.sh, GOCACHE=/tmp/banger-gocache go test ./..., and make build.
This commit is contained in:
Thales Maciel 2026-03-19 19:04:57 -03:00
parent 3096de0a7f
commit 7667249b47
No known key found for this signature in database
GPG key ID: 33112E6833C34679
4 changed files with 56 additions and 4 deletions

View file

@ -36,7 +36,7 @@
- Manual verification for VM lifecycle changes: `./banger vm create`, confirm SSH access, then stop/delete the VM.
- For host-integration changes, run `./banger doctor` as a quick readiness check before the live VM smoke.
- Rebuilt images now include `mise`, `opencode`, `tmux-resurrect`/`tmux-continuum` defaults for `root`, and the `banger-vsock-agent` service used by the SSH reminder and guest health-check path; if you change guest provisioning, document whether users need to rebuild `./runtime/rootfs-docker.ext4` or another base image to pick it up.
- The experimental Void rootfs path now includes the repo's basic dev baseline plus Docker and Compose, alongside boot, SSH, the vsock HTTP health agent, a `bash` root shell while leaving `/bin/sh` alone, and the `/root` work-seed. Keep further baked-in tooling deliberate and user-driven.
- The experimental Void rootfs path now includes the repo's basic dev baseline plus Docker and Compose, alongside boot, SSH, the vsock HTTP health agent, pinned `mise` plus `opencode` for `root`, a `bash` root shell while leaving `/bin/sh` alone, and the `/root` work-seed. Keep further baked-in tooling deliberate and user-driven.
- Rebuilt images also emit a `work-seed.ext4` sidecar used to speed up future VM creates. If you touch `/root` provisioning, verify both the rootfs and the work-seed output.
- The daemon may keep idle TAP devices in a pool for faster creates. Smoke tests should treat `tap-pool-*` devices as reusable capacity, not cleanup leaks.
- If you add a new operational workflow, document how to exercise it in `README.md`.

View file

@ -325,6 +325,8 @@ This path is intentionally local-only and does not change the default Debian
image flow. It reuses the current runtime bundle kernel, initrd, and modules,
but builds a lean `x86_64-glibc` Void userspace with:
- `bash` installed for interactive/admin use
- pinned `mise` installed at `/usr/local/bin/mise`, activated for `root` bash shells
- `opencode` installed through `mise`, with `/usr/local/bin/opencode` available by default
- `docker` plus `docker-compose` installed from Void packages
- the `docker` runit service enabled, with Docker netfilter/forwarding kernel prep
- `openssh` enabled under runit
@ -332,9 +334,7 @@ but builds a lean `x86_64-glibc` Void userspace with:
- `root` normalized to `/bin/bash` while keeping `/bin/sh` as the distro's system shell
- a generated `/root` work-seed for fast creates
It does not install the Debian-oriented extras from rebuilt default images:
- no `mise`
- no `opencode`
It still keeps some Debian-oriented extras out for now:
- no tmux plugin defaults
The builder fetches official static XBPS tools and packages from the Void

View file

@ -260,6 +260,11 @@ case "$-" in
*) return ;;
esac
if [ -z "${BANGER_MISE_ACTIVATED:-}" ] && [ -x '/usr/local/bin/mise' ]; then
export BANGER_MISE_ACTIVATED=1
eval "$(/usr/local/bin/mise activate bash)"
fi
PS1='\u@\h:\w\$ '
EOF
cat <<'EOF' | sudo tee "$bash_profile" >/dev/null
@ -280,6 +285,38 @@ EOF
sudo chmod 0644 "$bashrc" "$bash_profile" "$profile_prompt"
}
install_mise_and_opencode() {
local profile_mise="$ROOT_MOUNT/etc/profile.d/mise.sh"
sudo mkdir -p "$ROOT_MOUNT/etc/profile.d"
if [[ -r /etc/resolv.conf ]]; then
sudo install -m 0644 /etc/resolv.conf "$ROOT_MOUNT/etc/resolv.conf"
fi
sudo env \
HOME=/root \
PATH=/usr/local/bin:/usr/bin:/bin \
chroot "$ROOT_MOUNT" /bin/bash -se <<EOF
set -euo pipefail
curl -fsSL https://mise.run | MISE_INSTALL_PATH="$MISE_INSTALL_PATH" MISE_VERSION="$MISE_VERSION" sh
"$MISE_INSTALL_PATH" use -g "$OPENCODE_TOOL"
"$MISE_INSTALL_PATH" reshim
if [[ ! -e /root/.local/share/mise/shims/opencode ]]; then
echo "opencode shim not found after mise install" >&2
exit 1
fi
ln -snf /root/.local/share/mise/shims/opencode /usr/local/bin/opencode
EOF
cat <<'EOF' | sudo tee "$profile_mise" >/dev/null
if [ -n "${BASH_VERSION:-}" ] && [ -z "${BANGER_MISE_ACTIVATED:-}" ] && [ -x '/usr/local/bin/mise' ]; then
export BANGER_MISE_ACTIVATED=1
eval "$(/usr/local/bin/mise activate bash)"
fi
EOF
sudo chmod 0644 "$profile_mise"
}
cleanup() {
if [[ -n "${ROOT_MOUNT:-}" ]] && command -v mountpoint >/dev/null 2>&1 && mountpoint -q "$ROOT_MOUNT"; then
sudo umount "$ROOT_MOUNT" || true
@ -313,6 +350,9 @@ OUT_ROOTFS="$RUNTIME_DIR/rootfs-void.ext4"
SIZE_SPEC="2G"
MIRROR="https://repo-default.voidlinux.org"
ARCH="x86_64"
MISE_VERSION="v2025.12.0"
MISE_INSTALL_PATH="/usr/local/bin/mise"
OPENCODE_TOOL="github:anomalyco/opencode"
MODULES_DIR="$(bundle_path default_modules_dir "$RUNTIME_DIR/wtf/root/lib/modules/6.8.0-94-generic")"
VSOCK_AGENT="$(bundle_path vsock_agent_path "$RUNTIME_DIR/banger-vsock-agent")"
if [[ "$VSOCK_AGENT" == "$RUNTIME_DIR/banger-vsock-agent" && ! -x "$VSOCK_AGENT" ]]; then
@ -474,6 +514,8 @@ configure_docker_bootstrap
enable_docker_service
normalize_root_shell
configure_root_bash_prompt
log "installing mise and opencode"
install_mise_and_opencode
sudo mkdir -p "$ROOT_MOUNT/root/.ssh"
sudo touch "$ROOT_MOUNT/etc/fstab" "$ROOT_MOUNT/etc/hostname"
sudo chroot "$ROOT_MOUNT" /usr/bin/ssh-keygen -A
@ -487,8 +529,13 @@ sudo rm -rf \
sudo rm -f \
"$ROOT_MOUNT/root/get-docker" \
"$ROOT_MOUNT/root/get-docker.sh" \
"$ROOT_MOUNT/root/.cache/opencode" \
"$ROOT_MOUNT/tmp/get-docker" \
"$ROOT_MOUNT/tmp/get-docker.sh"
sudo rm -rf \
"$ROOT_MOUNT/root/.cache/mise" \
"$ROOT_MOUNT/root/.local/share/mise/downloads" \
"$ROOT_MOUNT/root/.local/share/mise/tmp"
sudo umount "$ROOT_MOUNT"

View file

@ -240,6 +240,11 @@ if ! wait_for_ssh "$GUEST_IP" "$BOOT_DEADLINE"; then
fi
ssh "${SSH_COMMON_ARGS[@]}" "root@${GUEST_IP}" "uname -a" >/dev/null
if [[ "$IMAGE_NAME" == "void-exp" ]]; then
log "asserting mise and opencode are available in the Void guest"
ssh "${SSH_COMMON_ARGS[@]}" "root@${GUEST_IP}" "command -v mise >/dev/null 2>&1 && command -v opencode >/dev/null 2>&1 && mise --version >/dev/null 2>&1 && opencode --version >/dev/null 2>&1" >/dev/null
fi
if (( NAT_ENABLED )); then
log "asserting VM has outbound network access"
ssh "${SSH_COMMON_ARGS[@]}" "root@${GUEST_IP}" "curl -fsS https://example.com >/dev/null" >/dev/null