mirror of
https://github.com/kuhyx/utils.git
synced 2026-11-11 13:47:43 +01:00
Three changes from kuhy's follow-up: - An explicit standing instruction that when vmbox breaks the next session FIXES it -- not works around it, not reports it as a limitation, not quietly falls back to testing on the host. Bugs found by real use are the return on having built this. - Guidance to attach to an existing sandbox or create one as appropriate, rather than tearing down and rebuilding per command (`vm reset` is ~2s). - A build-speed job with measurements rather than guesses: the last build pulled 197 packages / 396 MiB over the internet and spent 45s waiting on cloud-init, while the host's 114 GB pacman cache already holds every one of the packages checked. Exposing that cache read-only is the obvious first move; trimming base-devel and shortening the cloud-init wait follow. The smoke gate stays regardless -- a faster build that fails open would be a bad trade. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdyMBGCrGVGDWtJ9xe48f3
169 lines
8.5 KiB
Markdown
169 lines
8.5 KiB
Markdown
# Next session: make vmbox the default place scripts get tested
|
|
|
|
Paste everything below into a fresh Claude session.
|
|
|
|
---
|
|
|
|
`~/utils/vmbox` is a working disposable-Arch-VM sandbox (built and verified
|
|
2026-08-22, pushed to `github.com/kuhyx/utils`). Read `~/utils/vmbox/README.md`
|
|
first — it documents the design and the traps.
|
|
|
|
Three jobs this session, in order.
|
|
|
|
## Job 1: harden it by using it for real
|
|
|
|
vmbox has only ever been driven by one session, against a handful of scripts.
|
|
`testsAndMisc/linux_configuration` is ~1090 files, ~170 of which need root.
|
|
**Expect it to break.** That is the point of this job: find the breakages by
|
|
running real work through it, and fix them.
|
|
|
|
**Standing instruction for the whole session: when vmbox breaks, FIX IT.**
|
|
Do not work around it, do not report it as a limitation and move on, do not
|
|
switch to testing on the host instead. A bug found here is the whole return on
|
|
building the thing. Fix, commit, push, carry on with the list.
|
|
|
|
Reuse a sandbox when one is already up and suitable (`vm list`, then
|
|
`vm run <name> ...` — it starts the VM if stopped); create a fresh one when
|
|
you need a clean system or a different pinned clock. Do not tear down and
|
|
rebuild a sandbox for every command: `vm reset` is ~2s and is usually what you
|
|
actually want.
|
|
|
|
Work through this list, fixing vmbox whenever it gets in the way:
|
|
|
|
1. The 8 Arch-only tests the repo's CI already names in
|
|
`.github/workflows/shell-tests.yml` (`arch-tests` job) — `test_hosts_*`,
|
|
`test_makepkg_*`, `test_pacman_wrapper_security.sh`,
|
|
`test_security_hardening.sh`, `test_shutdown_timer_monitor.sh`. These are
|
|
the ones its comments say "cannot run on an Ubuntu runner". Run them in a
|
|
sandbox and report which pass.
|
|
2. `test_security_hardening.sh` specifically: on a bare guest it reports its
|
|
host checks as *skipped*. Install the real system first
|
|
(`install_core_system.sh`), then re-run it, so those checks become real.
|
|
3. `setup_night_lockdown.sh` — writes `/etc/systemd/system` units and an
|
|
i2c module config. The i2c RGB part is hardware and will not work; confirm
|
|
everything else does.
|
|
4. `boot_recovery/install.sh` — pacman hooks + mkinitcpio. Highest blast
|
|
radius of anything in the repo, and the best argument for the sandbox.
|
|
5. The hosts guard (`periodic_background/hosts/install.sh`) — rewrites
|
|
`/etc/hosts` and makes it immutable with `chattr +i`. Verify the immutable
|
|
flag really lands in the guest, then that `vm reset` clears it.
|
|
|
|
For each: `vm share` what it needs, clone into the guest, run it, report what
|
|
happened. When vmbox itself is the thing that broke, fix vmbox and commit.
|
|
|
|
### Known-good invocation shape
|
|
|
|
```bash
|
|
vm share ~/testsAndMisc # bind mount, NOT a symlink (9p won't follow one)
|
|
vm share ~/utils # guard-lib lives here; several scripts need guardctl
|
|
vm new t1 --rtc 2026-08-22T20:55:00 # pin the clock: shutdown scripts gate on 21:00-05:00
|
|
vm run t1 'git clone --no-hardlinks -q /mnt/hostrepo/testsAndMisc ~/tam'
|
|
vm run t1 'echo y | sudo bash ~/tam/path/to/script.sh enable' # many prompt; stdin is closed
|
|
vm reset t1 # ~2s back to pristine
|
|
```
|
|
|
|
### Traps already paid for — do not rediscover these
|
|
|
|
- **A guest that boots but refuses ssh is almost never a network problem.**
|
|
Run `systemctl list-jobs` on the guest via `vm ssh` or the serial console. A
|
|
unit that is enabled, has satisfied dependencies, and neither starts nor
|
|
fails is QUEUED behind something. That cost most of a session.
|
|
- **Never grep a `bash -x` trace for the failure** — you find where your
|
|
pattern matched, not where execution stopped. Read the tail.
|
|
- **`pkill -f <pattern>`** kills the Bash-tool shell when the pattern appears
|
|
in the command running it (exit 144). Use `pgrep -f | xargs -r kill`.
|
|
- Full list: `~/.claude/projects/-home-kuhy/memory/reference-vmbox-guest-image-traps.md`
|
|
and `reference-qemu-shutdown-verification.md`.
|
|
|
|
### Rebuilding the image
|
|
|
|
`vm build --force` takes ~10 min. It ends with a smoke test that boots a real
|
|
sandbox and refuses to ship an unreachable image. **Do not debug the image by
|
|
rebuilding per hypothesis** — boot an overlay off the current base, fix it live
|
|
over the serial console (root autologin is on ttyS0 and ttyS1), confirm the
|
|
fix, and only then bake it into `guest/provision.sh` and rebuild once.
|
|
|
|
## Job 2: make it the default, once Job 1 says it is trustworthy
|
|
|
|
kuhy's ask: *"claude should ALWAYS defer to using this sandbox when testing
|
|
stuff, ESPECIALLY when testing scripts."*
|
|
|
|
**Do Job 2 only after Job 1.** A rule that routes work into a tool that
|
|
breaks is worse than no rule. If Job 1 leaves vmbox flaky, say so and stop.
|
|
|
|
The rule belongs in `~/.claude/CLAUDE.md`. Points to settle with kuhy before
|
|
writing it — these are real forks, not rhetorical:
|
|
|
|
- **What triggers it.** "Any script" is too broad: it would send a one-line
|
|
`python_pkg` unit test through a VM boot. A sharper line is anything that
|
|
needs root, writes outside `$HOME`, touches systemd/pacman/`/etc`, or could
|
|
power the machine off.
|
|
- **What it replaces.** Today's `CLAUDE.md` development workflow says "run the
|
|
actual script to verify it does what it is supposed to do". Does the sandbox
|
|
become the *first* run, or an extra step before the host run? Note the
|
|
standing `feedback-verify-real-deployment-path` memory: testing somewhere
|
|
that is not the real deploy target has burned kuhy before, so a sandbox pass
|
|
must NOT be presented as proof the host is fine.
|
|
- **The escape hatch.** Anything hardware-bound (adb/phone, GPU, i2c, the
|
|
Huion tablet) cannot run in a VM. The rule needs a stated exception, or it
|
|
will be violated on the first phone task and quietly stop being followed.
|
|
- **Where it lives.** `CLAUDE.md` is always-on context, so keep it to a few
|
|
lines and link out. Per `token-spend.instructions.md`, a long rule there is
|
|
a permanent per-turn tax.
|
|
|
|
Draft it, get kuhy's sign-off on those four points, then write it.
|
|
|
|
## Job 3: make `vm build` faster than ~10 minutes
|
|
|
|
Measured on the last real build, so this is a known target rather than a
|
|
guess:
|
|
|
|
- 45s waiting for cloud-init on the guest's first boot.
|
|
- **197 packages, 396 MiB downloaded over the internet** (1273 MiB installed).
|
|
- The host's own pacman cache is **114 GB** and already contains every one of
|
|
`xorg-server i3-wm base-devel git strace jq kcov bats rsync xterm dmenu
|
|
shellcheck` — verified. The build is re-downloading packages that are
|
|
already on this machine.
|
|
|
|
Ideas, cheapest first — measure before and after, do not assume:
|
|
|
|
1. **Expose the host pacman cache to the build VM read-only** (`-virtfs` the
|
|
way `vm share` already does) and point the guest's pacman at it
|
|
(`CacheDir`, or bind `/var/cache/pacman/pkg`). Should remove most of the
|
|
396 MiB. Careful: the guest must not WRITE to the host cache, and a stale
|
|
cached package can be older than the guest's mirror expects — `-Syu` first,
|
|
or accept `--needed` semantics.
|
|
2. **Trim the package list.** `base-devel` is a large group; check whether the
|
|
target tests actually need all of it. `kcov` is only needed for the shell
|
|
coverage jail.
|
|
3. **Cut the cloud-init wait.** The build boot spends 45s on datasource
|
|
probing that the sealed image then disables anyway; a kernel arg or an
|
|
earlier `cloud-init.disabled` may shorten it.
|
|
4. **Cache the provisioned disk.** If provisioning inputs are unchanged
|
|
(`guest/provision.sh` hash + package list), a rebuild could reuse the last
|
|
provisioned image instead of redoing it. Only worth it if 1-3 are not
|
|
enough.
|
|
|
|
Note the build already ends with a smoke test that boots a real sandbox; keep
|
|
that. Making the build fast by making it fail open would be a bad trade.
|
|
|
|
## Definition of done
|
|
|
|
- The 5 items in Job 1 have been run in a sandbox, with results reported per
|
|
item (pass / fail / not-applicable-in-a-VM, with reasons).
|
|
- Every vmbox bug found is fixed, committed, and pushed.
|
|
- `bats ~/utils/vmbox/tests/test_vmbox.bats`, shellcheck and ruff all clean.
|
|
- Either the CLAUDE.md rule is written and agreed, or there is a clear
|
|
statement of what still makes vmbox untrustworthy.
|
|
- `vm build --force` is measurably faster than the ~10 min baseline, with the
|
|
before/after numbers stated.
|
|
|
|
## State as of handoff
|
|
|
|
Verified working: the shutdown verdict (5 outcomes, all measured against real
|
|
guests), destructive demo 7/7, reset ~2s, VM-to-VM ping (0% loss), screenshots,
|
|
pinned clock, repo share + clone, base-corruption guard, build smoke gate.
|
|
|
|
Unverified / not attempted: everything in Job 1 above; anything hardware-bound;
|
|
concurrent sandboxes beyond two.
|