From f8e2473afa3c6f3c5a9a350c3722d1e205fd3807 Mon Sep 17 00:00:00 2001 From: rickpeters Date: Sun, 27 Sep 2026 19:53:23 +0200 Subject: [PATCH] feat: steam-machine-iso skill (ISO build in podman on the Steam Machine, installer simulation, first-login test) and scripts/vminstallsim.sh --- .claude/skills/steam-machine-iso/SKILL.md | 123 ++++++++++++++++++++++ CHANGELOG.md | 6 ++ scripts/vminstallsim.sh | 30 ++++++ 3 files changed, 159 insertions(+) create mode 100644 .claude/skills/steam-machine-iso/SKILL.md create mode 100755 scripts/vminstallsim.sh diff --git a/.claude/skills/steam-machine-iso/SKILL.md b/.claude/skills/steam-machine-iso/SKILL.md new file mode 100644 index 0000000..5970487 --- /dev/null +++ b/.claude/skills/steam-machine-iso/SKILL.md @@ -0,0 +1,123 @@ +--- +name: steam-machine-iso +description: Use when working on the Steam Machine CachyOS ISO (repo steammachine-cachyos-live-iso) or Steamify's install-time mode (steamify.sh --defaults, --first-login) - building the ISO in podman on the Steam Machine, the Calamares Steamify step, simulating the installer in the test VM, and testing the first desktop login. +--- + +# Steam Machine ISO and Steamify's install-time mode + +A CachyOS live ISO for the Steam Machine that installs Steamify's default +setup during the install. Two repos: + +- `steamify-cachyos` (Steamify): `steamify.sh --defaults` applies what the + menu would preselect, no prompts, passwordless sudo required. Without a + session (installer) `user_systemctl` only changes unit files, the theme + replaces an untouched `/etc/skel` Plasma layout so Plasma builds Vapor's at + first login, and `lib/first-login.sh` leaves a one-time autostart + (`--first-login`: single user's launcher on the new layout, then the app, + next to CachyOS Hello). See AGENTS.md there. +- `steammachine-cachyos-live-iso` (fork of CachyOS-Live-ISO), branch work + never on master: + - `archiso/airootfs/etc/calamares/settings.conf`: CachyOS's own (from the + `cachyos-calamares-next` package, `/usr/share/calamares/settings.conf`; + `/etc/calamares` wins) with `shellprocess@steamify` before + `cleanup_calamares`. Refresh it from the package when CachyOS changes + theirs. + - `modules/shellprocess_steamify.conf` runs + `/usr/local/bin/steamify-install ${ROOT} ${USER}` outside the chroot; that + gives the user a temporary NOPASSWD rule, runs the bundle with + `arch-chroot ... runuser -u -- env -i ... --defaults`, logs to + `/var/log/steamify-install.log` in the target, never fails the install. + - `steamify-prepare.sh [steamify checkout]` puts the bundle on the ISO + (`archiso/airootfs/usr/local/share/steamify/steamify.sh`, git-ignored): + from a checkout, else the newest release; refuses one without `--defaults`. + +## Everything visible + +The user watches the Steam Machine over Moonlight: run builds and tests in a +Konsole on its desktop (or open one that follows the log), never hidden. + +```bash +ssh steammachine bash -c "'export XDG_RUNTIME_DIR=/run/user/1000 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus; systemd-run --user -q konsole --hold -e bash -c \"tail -n 50 -F ~/projects/iso-build.log\"'" +``` + +## Steam Machine gotchas + +- Login shells there and in the VM are **fish**: wrap loops in + `bash -c '...'` or pipe a script to `bash -s`. +- Never `pkill -f ` from a remote command containing that pattern: + it kills its own shell (exit 255). +- The VM's host key lives in `~/projects/steamify-cachyos-dev/known_hosts`. + Scripts calling plain `ssh` (vmreset.sh) need a wrapper first in `PATH`: + `/tmp/steamify-sshwrap/ssh` = + `exec /usr/bin/ssh -o UserKnownHostsFile=$HOME/projects/steamify-cachyos-dev/known_hosts -o StrictHostKeyChecking=accept-new "$@"` + (recreate after a reboot). +- Run vmreset.sh as a systemd user unit with `-p KillMode=process`, a unique + unit name, `--setenv=REPO=$HOME/projects/steamify-cachyos`, the wrapper + `PATH` and `SSH_AUTH_SOCK` (connect with `ssh -A`, keep the session open with + `--wait`). Without KillMode=process QEMU dies with the unit; without REPO + QEMU fails on the old repo path and the script waits 5 minutes for SSH. + +## Building the ISO (podman on the Steam Machine) + +Only podman is installed on the Steam Machine itself; the build tools live in +the container. Rootful (loop devices, mounts), so `sudo podman ps` shows it, +not a rootless podman GUI. Clone: `~/projects/steammachine-cachyos-live-iso`. + +```bash +cd ~/projects/steammachine-cachyos-live-iso +git checkout feat/steamify && ./steamify-prepare.sh ~/projects/steamify-cachyos +sudo rm -rf build out +systemd-run --user --collect -q -u isobuild-$(date +%s) --working-directory=$PWD bash -c \ + "sudo podman run --rm -t --pids-limit=-1 --ulimit nofile=65536:65536 --privileged --network=host \ + -v $PWD:/iso -w /iso docker.io/cachyos/cachyos:latest bash -c \ + 'pacman-key --init && pacman-key --populate && pacman -Syu --noconfirm --needed archiso mkinitcpio-archiso git squashfs-tools grub sudo && { ./buildiso.sh -p desktop -w || ./buildiso.sh -p desktop -c -w; }' \ + > $HOME/projects/iso-build.log 2>&1" +``` + +Output: `out/desktop/*.iso`. Each flag fixes a failure seen before: + +- `--network=host`: the default network has no DNS here (every mirror + "Resolving timed out"). +- `--pids-limit=-1`: otherwise the last ~9 packages alphabetically fail with + `GPGME error: Inappropriate ioctl for device` / "missing required signature". +- `pacman-key --init/--populate`: the image's keyring isn't initialised. +- The retry with `-c` keeps the work dir and cache for a flaky pass. + +Don't stop a running build to try something else without checking its log +first (`grep -ac GPGME ~/projects/iso-build.log`). The repo's CI recipe +(`archlinux:base-devel`, `.github/workflows/build.yml`) works too but pulls +from one slow mirror. + +## Testing Steamify's install-time mode in the VM + +`scripts/vminstallsim.sh [--fresh]` (VM up via vmreset.sh `--fremont`, branch +rsynced to `~/projects/steamify-cachyos`): creates `isotest` (never logged +in), runs `/mnt/steamify.sh --defaults` for it without any session, visibly. +Every component should print OK and `exit: 0`. Use `--fresh` after changes: +an earlier run's single user mode edits the skel layout, and the theme then +(rightly) refuses. + +First desktop login as that user: + +1. Point the first-login script at the test copy (it runs the newest + release otherwise): copy `/mnt` to `/opt/steamify-test` (`chmod -R a+rX`), + `sed -i 's#^curl .*#bash /opt/steamify-test/steamify.sh --first-login#'` + `/home/isotest/.local/share/steamify/bin/first-login`. +2. Gamescope doesn't run in the VM: `Session=plasma.desktop` in + `/etc/sddm.conf.d/zz-steamos-autologin.conf`, remove + `/etc/plasmalogin.conf.d/00-test-autologin.conf`, reboot. +3. Expect: Steam Deck wallpaper (Vapor layout), `primaryActions=3` in + isotest's `plasma-org.kde.plasma.desktop-appletsrc`, the autostart entry + gone, `steamify-ui` running next to `cachyos-hello`. +4. Screenshot: QMP `screendump` gives "no surface" with virgl; use + `sudo -u isotest env XDG_RUNTIME_DIR=/run/user/1001 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1001/bus WAYLAND_DISPLAY=wayland-0 spectacle -b -n -f -o /tmp/shot.png`. + +## Testing the ISO itself + +Install the built ISO in a **new** VM disk (never over the ssh-ready one), +with `--fremont`, through Calamares, then check +`/var/log/steamify-install.log` in the installed system. In the chroot +`uname -r` is the live kernel: module loads and checks against the running +kernel may fail even when DKMS built for the installed kernels. Real +hardware (Steam Machine, USB stick) is the final test: gamescope, LEDs, CEC, +power-off. diff --git a/CHANGELOG.md b/CHANGELOG.md index 20e7b81..54dda15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes, per version and per commit. Versions follow [Semantic Versioning](https://semver.org/) and were numbered from the start of the history. +## 0.3.0 - 2026-09-27 + +The Steam Machine ISO and Steamify's install-time mode. + +- **feat: steam-machine-iso skill (ISO build in podman on the Steam Machine, installer simulation, first-login test) and scripts/vminstallsim.sh** + ## 0.2.0 - 2026-09-24 Watchable test runs and the lessons from testing cachyos-gamescope-boot 0.7.0 diff --git a/scripts/vminstallsim.sh b/scripts/vminstallsim.sh new file mode 100755 index 0000000..016ecfe --- /dev/null +++ b/scripts/vminstallsim.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Simulate the Steam Machine ISO's installer step in the test VM: a new user +# who never logged in (no session bus, user systemd or plasmashell) gets +# `steamify.sh --defaults` from /mnt, visibly in a Konsole on the VM's +# desktop. Prints the per-component result lines. +# scripts/vminstallsim.sh [--fresh] --fresh: delete and recreate the user first +# Env: VM_USER / VM_PORT / VM_HOST, SIM_USER (isotest), GUEST_UID (1000). +set -euo pipefail +. "$(dirname "$0")/common.sh" +fresh=""; [[ "${1:-}" == --fresh ]] && fresh=1 +{ printf 'u=%q fresh=%q uid=%q\n' "${SIM_USER:-isotest}" "$fresh" "${GUEST_UID:-1000}"; cat << 'REMOTE' +mountpoint -q /mnt || sudo mount -t 9p -o trans=virtio,version=9p2000.L repo /mnt +[ -n "$fresh" ] && sudo userdel -r "$u" 2>/dev/null +cat > /tmp/install-sim.sh << SIM +#!/bin/bash +id $u >/dev/null 2>&1 || { sudo useradd -m -G wheel -s /bin/bash $u; echo "$u:$u" | sudo chpasswd; } +echo "$u ALL=(ALL) NOPASSWD: ALL" | sudo tee /etc/sudoers.d/10-steamify-install-sim >/dev/null +sudo -u $u env -i HOME=/home/$u USER=$u LOGNAME=$u PATH=/usr/local/bin:/usr/bin TERM=xterm \ + bash -c 'cd ~ && /mnt/steamify.sh --defaults < /dev/null' 2>&1 | tee /tmp/install-sim.log +echo "exit: \${PIPESTATUS[0]}" | tee -a /tmp/install-sim.log +sudo rm -f /etc/sudoers.d/10-steamify-install-sim +touch /tmp/install-sim.done +SIM +chmod +x /tmp/install-sim.sh; rm -f /tmp/install-sim.done +XDG_RUNTIME_DIR=/run/user/$uid DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$uid/bus \ + systemd-run --user -q konsole --hold -e /tmp/install-sim.sh +while [ ! -f /tmp/install-sim.done ]; do sleep 3; done +sed 's/\x1b\[[0-9;]*m//g' /tmp/install-sim.log | grep -E '^Turning|^\[(WARN|ERROR|OK)\]|^exit' +REMOTE +} | vm_ssh bash -s 2>&1