Start here
Disposable VM
Guest prerequisites, lifecycle, source sync, and troubleshooting with the QEMU helper.
60c72c2bView original On this page
All psh builds, automated tests, listeners, and root/session checks must run in
this guest. The host only downloads images, starts QEMU, and transfers source.
No host packages, host network configuration, host accounts, or /etc files are
changed. QEMU uses user networking; its sole forwarded port listens on
127.0.0.1:22222 and reaches guest SSH. psh ports are never forwarded.
Host prerequisites: Bash, QEMU (qemu-system-x86_64, qemu-img), mkisofs,
curl, sha256sum, OpenSSH client/keygen, and tar. KVM is used if accessible;
otherwise QEMU uses software emulation. First setup downloads the official
Ubuntu 24.04 cloud image over HTTPS and checks its SHA256SUMS entry. The guest
installs build-essential, libssl-dev, pkg-config, Python 3, OpenSSL, iproute2,
and util-linux using cloud-init.
tools/vm/vm.sh start
tools/vm/vm.sh wait
tools/vm/vm.sh sync
tools/vm/vm.sh run 'make && make test'
tools/vm/vm.sh ssh 'uname -a; id'
tools/vm/vm.sh stop
tests/integration/run.py checks real key authentication, host pins, account
privileges and environment, exit codes, stdout/stderr, binary streams, and PTY
dimensions. Its UDP proxy exercises packet loss, reordering, and live changes
of client source IP and port entirely on guest loopback. The proxy uses
127.0.0.1 and 127.0.0.2, with no address or route configuration. Its smoke test is
available as tools/vm/vm.sh run 'python3 tests/integration/test_udp_proxy.py'.
The suite also checks encrypted local key prompts and terminal restoration after
interruptions, host trust/forget commands, connection-slot recycling, cookie
address binding, and session revocation or preservation during configuration reloads.
Encrypted identities are unlocked through a controlling terminal and used for
real remote authentication. Other checks exercise live terminal resizing,
remote signal forwarding, and the client’s SIGUSR1 socket-rebind hook.
The test guard requires the guest marker, PSH_TEST_VM=1, and successful QEMU
virtualization detection before creating any listeners or accounts.
run starts in /work/psh and sets PSH_TEST_VM=1. sync sends a source tarball
over SSH; there is no writable shared host filesystem in the guest. It overlays
existing guest files so incremental builds remain possible. Root build/ is
excluded so host artifacts cannot replace guest binaries or dependencies. SSH uses a fresh,
local public key, disables password login, and stores known hosts under
tools/vm/.state/. The guest’s root login is deliberate: integration tests can
exercise account switching without touching the host. The private key is for
this disposable guest only and is excluded from version control.
Serial output is in tools/vm/.state/serial.log. Image, writable overlay,
cloud-init seed, local SSH credentials, PID, and serial output stay under the
ignored .state/ directory. Set PSH_VM_STATE, PSH_VM_PORT, PSH_VM_MEMORY,
or PSH_VM_CPUS to override defaults. PSH_VM_WAIT controls the SSH startup
timeout in seconds (default 600).
PSH_VM_STATE accepts absolute paths or paths relative to the caller’s working
directory, including spaces and shell or glob metacharacters. The helper resolves
the source root and state directory to physical paths. sync always excludes
tools/vm/.state, .git, and build at the source root, and also excludes the resolved
state directory when it lies inside the source root. An outside state directory
adds no source exclusions. Sync fails before SSH or archiving if the state
directory is the source root or one of its ancestors. This prevents VM disks and
SSH credentials from entering the source archive without silently omitting the
whole source tree. State paths reached through symlinks follow the same physical
path rules; source symlinks are archived as links without following their targets.
Exclusions match literal paths, so a state name containing *, ?, or [] does
not exclude similarly named source files.
make test-vm-sync runs a guest-only regression with inert source/state fixtures
and a fake SSH receiver; it never archives the live VM’s state.
Build and test logs can stay in guest /work/results. To save a review copy on
the host without running any tests there:
tools/vm/vm.sh ssh 'cat /work/results/final-test.log' > tools/vm/.state/final-test.log
The PID check verifies both the QEMU executable and this guest’s disk argument,
so a stale PID file cannot make stop signal an unrelated host process.
To start fresh, stop the VM, remove .state/guest.qcow2 and .state/seed.iso,
then start it again. Keep the downloaded base image to avoid another download.