mirror of
https://github.com/nestriness/nestri.git
synced 2026-09-24 11:38:19 +03:00
## What Adds `build/` — a Dockerfile with `mesa-build`, `nestri-build`, `os-base`, `runtime`, `runtime_prod` and `runtime_debug` stages, plus the `etc/` overlay, `mkimage.sh` and a `Makefile` — laid out the way [borealis](https://chromium.googlesource.com/chromiumos/overlays/board-overlays/+/main/project-borealis) lays out its own `build/`. This moves the guest rootfs formula into this repo, targeting the four open guest components already here: `nescope`, `neshub`, `neswire`, `nescapture`. ## Two structural properties worth calling out - **No privileged host chroot.** A bare `chroot` into a hand-extracted rootfs needs `/proc`, `/sys`, `/dev` bind-mounted in first. `os-base` here is `FROM artixlinux/artixlinux:base-openrc` directly with `pacman -S` as plain `RUN` steps — a Docker build step already has its own `/proc`/`/sys`/`/dev`. - **No host-side ownership bug to guard against.** `COPY --from=` runs as root inside the build with no invoking-user uid in the loop. ## Scope boundary **Deliberately excludes Proton and Valve's `steamclient.so`** — both closed, and `CLAUDE.md` forbids closed content in this repo. `runtime_prod`, tagged `nestrilabs/nestri:base`, is a complete, bootable, Steam-less image — and also the shared foundation other builds start from. Whatever layers Proton/Steam on top of it is a closed build outside this repo, by design. ## Known gap Nothing starts a payload yet — `nesinit` isn't open code — so `/etc/init.d/nescope` boots it in plain-compositor mode (no command after `--`) rather than running a game. Real and testable, just not a full session yet. Details in `build/README.md`. ## Status Built and tagged locally as `nestrilabs/nestri:base` (podman, no `--no-cache` issues, greptile's three findings all fixed and verified against a real build). Not yet packed into a disk image or run inside nesbox. 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- greptile_comment --> <h3>Greptile Summary</h3> The PR adds a multi-stage Artix/OpenRC guest-rootfs build for the open Nestri components, with production and debug image flavors. - Builds patched Mesa and the Rust workspace in dedicated builder stages. - Assembles and configures the bootable guest environment and OpenRC services. - Packs a selected container image into an ext4 root filesystem while retaining rootless container storage access. <h3>Confidence Score: 5/5</h3> The PR appears safe to merge. No blocking failure remains. <h3>Important Files Changed</h3> | Filename | Overview | |----------|----------| | build/Dockerfile | Defines the complete multi-stage build, overlays repository-root-relative configuration paths, and creates production and debug runtime targets. | | build/Makefile | Provides consistent image build and packing targets using a repository-root context and matching image tags. | | build/scripts/mkimage.sh | Keeps container-runtime operations in the invoking user's storage while escalating only filesystem creation and mounting operations. | | build/etc/conf.d/nestri-user-env | Supplies the shared service environment and export function required by the OpenRC service scripts. | | build/etc/init.d/guest-net | Configures optional guest networking from kernel parameters or stable defaults. | | build/etc/init.d/neswire | Starts the audio sink after its dependencies and pins it as the PipeWire default once the graph is ready. | <h3>Flowchart</h3> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart TD A[Arch builder] --> B[Mesa build] A --> C[Nestri workspace build] D[Artix OpenRC base] --> E[Common runtime] B --> E C --> E F[build/etc overlay] --> E E --> G[runtime_prod] E --> H[runtime_debug] G --> I[Container image] H --> J[Debug container image] I --> K[mkimage.sh] J --> K K --> L[ext4 rootfs] ``` <sub>Reviews (6): Last reviewed commit: ["refactor(build): rename the published im..."](https://github.com/nestrilabs/nestri/commit/6fecc8cc31bc425db952193074d4b9b0f861de89) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=58981739)</sub> <!-- /greptile_comment -->
93 lines
3.0 KiB
Plaintext
93 lines
3.0 KiB
Plaintext
#!/sbin/openrc-run
|
|
|
|
description="Configure the guest's network to match the host's tap"
|
|
|
|
# Overridden from /etc/conf.d/guest-net if present. These defaults match
|
|
# nesbox's own defaults; if you change the `network` section in the VM's
|
|
# JSON, change these to match.
|
|
: ${GUEST_IFACE:=eth0}
|
|
: ${GUEST_IP:=172.30.0.2}
|
|
: ${GUEST_PREFIX:=24}
|
|
: ${GUEST_GATEWAY:=172.30.0.1}
|
|
|
|
depend() {
|
|
need localmount
|
|
provide net
|
|
keyword -shutdown
|
|
}
|
|
|
|
# Read one `nestri.<key>=<value>` from the kernel command line.
|
|
#
|
|
# The address has to come from somewhere per-boot, because the alternative --
|
|
# baking it into the image -- makes every guest built from that image the
|
|
# same host on the network. Two sandboxes then collide the moment they run
|
|
# together.
|
|
#
|
|
# `nestri.`-prefixed rather than the kernel's own `ip=`: that one needs
|
|
# CONFIG_IP_PNP and exists to configure NFS root, and the prefix makes it
|
|
# obvious whose parameter this is.
|
|
cmdline_value() {
|
|
local key="$1" word
|
|
for word in $(cat /proc/cmdline 2>/dev/null); do
|
|
case "$word" in
|
|
"nestri.${key}="*) printf '%s' "${word#nestri.${key}=}"; return 0 ;;
|
|
esac
|
|
done
|
|
return 1
|
|
}
|
|
|
|
start() {
|
|
ebegin "Bringing up loopback"
|
|
ip link set lo up
|
|
eend $?
|
|
|
|
# The command line wins over conf.d when it says anything, and conf.d is
|
|
# the fallback so a hand-written VM config with no parameters keeps
|
|
# working -- which is how a guest gets debugged.
|
|
local source="/etc/conf.d/guest-net"
|
|
local cmdline_ip
|
|
if cmdline_ip="$(cmdline_value ip)"; then
|
|
# Accepts address/prefix; a bare address keeps the configured prefix
|
|
# rather than guessing one.
|
|
case "$cmdline_ip" in
|
|
*/*)
|
|
GUEST_IP="${cmdline_ip%%/*}"
|
|
GUEST_PREFIX="${cmdline_ip##*/}"
|
|
;;
|
|
*) GUEST_IP="$cmdline_ip" ;;
|
|
esac
|
|
source="kernel command line"
|
|
fi
|
|
|
|
local cmdline_gw
|
|
if cmdline_gw="$(cmdline_value gw)"; then
|
|
GUEST_GATEWAY="$cmdline_gw"
|
|
source="kernel command line"
|
|
fi
|
|
|
|
# The VM may have been started with no network device at all, which is a
|
|
# perfectly good configuration. Do not fail the boot over it.
|
|
if [ ! -e "/sys/class/net/${GUEST_IFACE}" ]; then
|
|
einfo "no ${GUEST_IFACE}: this VM has no network device"
|
|
return 0
|
|
fi
|
|
|
|
# Says which source won, because "the address is wrong" and "the address
|
|
# came from somewhere unexpected" look identical from inside the guest.
|
|
ebegin "Configuring ${GUEST_IFACE} as ${GUEST_IP}/${GUEST_PREFIX} via ${GUEST_GATEWAY} (from ${source})"
|
|
# `replace` rather than `add` so a restart is not an error.
|
|
ip link set "${GUEST_IFACE}" up &&
|
|
ip addr replace "${GUEST_IP}/${GUEST_PREFIX}" dev "${GUEST_IFACE}" &&
|
|
ip route replace default via "${GUEST_GATEWAY}" dev "${GUEST_IFACE}"
|
|
eend $? "could not configure ${GUEST_IFACE}"
|
|
}
|
|
|
|
stop() {
|
|
if [ -e "/sys/class/net/${GUEST_IFACE}" ]; then
|
|
ebegin "Bringing down ${GUEST_IFACE}"
|
|
ip link set "${GUEST_IFACE}" down
|
|
eend 0
|
|
fi
|
|
return 0
|
|
}
|