···4040 mountpoint -q /sys || mount -t sysfs sys /sys
4141 mountpoint -q /dev || mount -t devtmpfs dev /dev
4242 mountpoint -q /dev/pts || {
4343- mkdir -p /dev/pts
4343+ install -d /dev/pts
4444 mount -t devpts devpts /dev/pts
4545 }
4646 mountpoint -q /dev/shm || {
4747- mkdir -p /dev/shm
4747+ install -d /dev/shm
4848 mount -t tmpfs -o mode=1777 shm /dev/shm
4949 }
5050 mountpoint -q /run || mount -t tmpfs -o mode=0755 run /run
5151 mountpoint -q /tmp || mount -t tmpfs -o mode=1777 tmp /tmp
52525353+ # setup xdg runtime dir, podman eg. needs it
5454+ install -d -m 0700 -o spindle-workflow -g spindle-workflow /run/user/970
5555+5656+ # cgroup2 setup, normally we would do this with rc-service
5757+ # but minirootfs does not ship with those so we set it up ourselves.
5858+ mountpoint -q /sys/fs/cgroup || {
5959+ install -d /sys/fs/cgroup
6060+ mount -t cgroup2 -o nsdelegate cgroup2 /sys/fs/cgroup
6161+ chown -R spindle-workflow:spindle-workflow /sys/fs/cgroup 2>/dev/null || true
6262+ }
6363+5364 # the initramfs mdev leaves these 0660, which breaks non-root workflows
5465 chmod 666 /dev/null /dev/zero /dev/full /dev/random /dev/urandom /dev/tty /dev/ptmx 2>/dev/null
5566···6172 # /dev/vda is the squashfs root; the first spindle volume backs /workspace
6273 if [ -b /dev/vdb ]; then
6374 mount -t ext4 /dev/vdb /workspace
6464- mkdir -p /workspace/repo
6565- chown spindle-workflow:spindle-workflow /workspace /workspace/repo
7575+ install -d -o spindle-workflow -g spindle-workflow /workspace /workspace/repo
6676 fi
67776878 ip link set lo up
···207217 echo "spindle-workflow:x:970:" >> rootfs/etc/group
208218 echo "spindle-workflow:!::0:::::" >> rootfs/etc/shadow
209219 mkdir -p rootfs/workspace
220220+221221+ # subordinate id ranges so the workflow user can run rootless containers
222222+ # (podman/buildah): without these, user-namespace id mapping falls back to a
223223+ # single 970->0 map and any layer that chowns to another uid fails. the range
224224+ # is well clear of 970 and the 30000-block nixbld users.
225225+ echo "spindle-workflow:100000:65536" >> rootfs/etc/subuid
226226+ echo "spindle-workflow:100000:65536" >> rootfs/etc/subgid
210227211228 # setup nix build users for the daemon
212229 members=""
···814814 echo "success: alpine guest booted, ran as workflow user, wrote workspace, cloned + installed over the network, and substituted+ran a package from cache.nixos.org over HTTPS"
815815}
816816817817+test_alpine_podman() {
818818+ # install podman via apk and run a real container as the workflow user.
819819+ # rootless podman lives entirely in the writable workspace (storage + runroot
820820+ # under XDG dirs there), uses podman's default storage driver, and pulls over
821821+ # the guest network like the other alpine tests.
822822+ local out
823823+ out=$(run_vm --spec "$ALPINE_IMAGE_SPEC_JSON" --name "alpine-podman" --timeout "300s" --no-cache -- /bin/sh -lc '
824824+set -eu
825825+# no env setup here on purpose: shuttle seeds USER/LOGNAME/HOME/SHELL from the
826826+# workflow users passwd entry and provisions XDG_RUNTIME_DIR, so rootless podman
827827+# works out of the box. asserting those below doubles as a check on that.
828828+829829+# shadow-uidmap ships newuidmap/newgidmap which rootless podman uses to apply the
830830+# /etc/subuid + /etc/subgid ranges baked into the image.
831831+apk add podman shadow-uidmap
832832+echo "user=$(id -un) USER=$USER HOME=$HOME XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR"
833833+echo "newuidmap=$(command -v newuidmap)"
834834+echo "podman_version=$(podman --version)"
835835+836836+podman info >/dev/null
837837+echo "storage_driver=$(podman info --format "{{.Store.GraphDriverName}}")"
838838+839839+podman run --rm --network=host docker.io/library/alpine cat /etc/alpine-release | sed "s/^/container_release=/"
840840+podman run --rm --network=host docker.io/library/alpine echo container-ran-ok
841841+' sh) || return 1
842842+843843+ check_needles "$out" \
844844+ "user=spindle-workflow USER=spindle-workflow HOME=/workspace XDG_RUNTIME_DIR=/run/user/970" \
845845+ "newuidmap=/" "podman_version=" \
846846+ "storage_driver=" "container_release=[0-9]+\." "container-ran-ok" || return 1
847847+ echo "success: alpine guest installed podman via apk and pulled + ran a rootless container"
848848+}
849849+817850# asserts a store path's narinfo shows up in the local cache, retrying briefly
818851# since the post-build-hook enqueues uploads asynchronously.
819852cache_has_path() {
···914947TESTS=(
915948 test_alpine
916949 test_alpine_nix
950950+ test_alpine_podman
917951 test_realize
918952 test_build_upload
919953 test_ssh_store_upload