From 7667249b47b9eacae1bea45cd8f291b02ce68d6b Mon Sep 17 00:00:00 2001 From: Thales Maciel Date: Thu, 19 Mar 2026 19:04:57 -0300 Subject: [PATCH] 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. --- AGENTS.md | 2 +- README.md | 6 +++--- make-rootfs-void.sh | 47 +++++++++++++++++++++++++++++++++++++++++++++ verify.sh | 5 +++++ 4 files changed, 56 insertions(+), 4 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 036e48c..b81aaec 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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`. diff --git a/README.md b/README.md index dc2fd32..e4a33de 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/make-rootfs-void.sh b/make-rootfs-void.sh index 0056313..fb21397 100755 --- a/make-rootfs-void.sh +++ b/make-rootfs-void.sh @@ -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 <&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" diff --git a/verify.sh b/verify.sh index 4e5e652..8c0af2d 100755 --- a/verify.sh +++ b/verify.sh @@ -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