Start here

Disposable VM

Guest prerequisites, lifecycle, source sync, and troubleshooting with the QEMU helper.

Source snapshot 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.

END OF DOCUMENT / psh/3All documentation