@@ -65,48 +65,64 @@ runs:
6565 major=$(podman --version | awk '{print $NF}' | cut -d. -f1)
6666 if [ "${major:-0}" -ge 5 ]; then
6767 for d in /usr/local/bin /usr/local/sbin /usr/bin /usr/sbin /bin /sbin; do
68- [ -x "$d/podman" ] && echo "already at $d/podman" && exit 0
68+ # Found, not exited: the probes at the bottom gate a shipped
69+ # podman the same as a repaired one, because a shipped one
70+ # drifts too.
71+ [ -x "$d/podman" ] && echo "already at $d/podman" && podman_ok=1 && break
72+ done
73+ if [ -z "$podman_ok" ]; then
74+ sudo ln -s "$(command -v podman)" /usr/bin/podman
75+ echo "linked $(command -v podman) -> /usr/bin/podman"
76+ fi
77+ else
78+ # Presence is not the whole gate. The install's own build mounts
79+ # its working container with lowerdirs from the additional image
80+ # store, and podman 4.9.3 cannot make that mount: the first COPY
81+ # dies with "no such file or directory" whatever the sync
82+ # unpacked first. Measured on 2026-09-04, where every job that
83+ # drew apt's 4.9.3 at /usr/bin died there while the same commits
84+ # on 5.8.4 installed and booted. So an old podman is repaired
85+ # with a new one rather than accepted, into /usr/local/bin, which
86+ # TOOL_DIRS orders ahead of /usr/bin and sudo's secure_path reads
87+ # first as well. Homebrew is preinstalled on these images and
88+ # bottles podman for linux, so the repair pours rather than
89+ # builds; a runner without it fails here, naming the absence,
90+ # instead of twenty minutes later at the COPY.
91+ [ -x /home/linuxbrew/.linuxbrew/bin/brew ] \
92+ || { echo "podman $major is too old for the install's build and there is no Homebrew to repair with" >&2; exit 1; }
93+ eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
94+ HOMEBREW_NO_AUTO_UPDATE=1 brew install podman
95+ sudo ln -sf "$(command -v podman)" /usr/local/bin/podman
96+ echo "podman version now: $(podman --version)"
97+ # The poured podman brings matching helpers, but linking podman
98+ # alone left the repair running the apt ones: podman resolves
99+ # crun and pasta from fixed path lists that read /usr/bin before
100+ # anywhere brew pours, and sudo's PATH never reaches the brew
101+ # prefix either. The apt crun 0.17 rejected the OCI spec the new
102+ # podman writes ("crun: unknown version specified") and the apt
103+ # pasta rejected its --map-guest-addr ("pasta failed with exit
104+ # code 1"), both measured 2026-09-04, each wall costing a run.
105+ # So the repair replaces the old helpers where the lists look
106+ # first, like the podman above. conmon is shadowed the same way
107+ # but the apt one starts containers fine, so it is left alone.
108+ for helper in crun pasta; do
109+ [ -x "$(command -v "$helper")" ] \
110+ || { echo "brew poured podman but no $helper came with it" >&2; exit 1; }
111+ sudo ln -sf "$(command -v "$helper")" "/usr/bin/$helper"
112+ echo "$helper now at: $(readlink "/usr/bin/$helper")"
69113 done
70- sudo ln -s "$(command -v podman)" /usr/bin/podman
71- echo "linked $(command -v podman) -> /usr/bin/podman"
72- exit 0
73114 fi
74- # Presence is not the whole gate. The install's own build mounts
75- # its working container with lowerdirs from the additional image
76- # store, and podman 4.9.3 cannot make that mount: the first COPY
77- # dies with "no such file or directory" whatever the sync
78- # unpacked first. Measured on 2026-09-04, where every job that
79- # drew apt's 4.9.3 at /usr/bin died there while the same commits
80- # on 5.8.4 installed and booted. So an old podman is repaired
81- # with a new one rather than accepted, into /usr/local/bin, which
82- # TOOL_DIRS orders ahead of /usr/bin and sudo's secure_path reads
83- # first as well. Homebrew is preinstalled on these images and
84- # bottles podman for linux, so the repair pours rather than
85- # builds; a runner without it fails here, naming the absence,
86- # instead of twenty minutes later at the COPY.
87- [ -x /home/linuxbrew/.linuxbrew/bin/brew ] \
88- || { echo "podman $major is too old for the install's build and there is no Homebrew to repair with" >&2; exit 1; }
89- eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"
90- HOMEBREW_NO_AUTO_UPDATE=1 brew install podman
91- sudo ln -sf "$(command -v podman)" /usr/local/bin/podman
92- echo "podman version now: $(podman --version)"
93- # The poured podman brings matching helpers, but linking podman
94- # alone left the repair running the apt ones: podman resolves
95- # crun and pasta from fixed path lists that read /usr/bin before
96- # anywhere brew pours, and sudo's PATH never reaches the brew
97- # prefix either. The apt crun 0.17 rejected the OCI spec the new
98- # podman writes ("crun: unknown version specified") and the apt
99- # pasta rejected its --map-guest-addr ("pasta failed with exit
100- # code 1"), both measured 2026-09-04, each wall costing a run.
101- # So the repair replaces the old helpers where the lists look
102- # first, like the podman above. conmon is shadowed the same way
103- # but the apt one starts containers fine, so it is left alone.
104- for helper in crun pasta; do
105- [ -x "$(command -v "$helper")" ] \
106- || { echo "brew poured podman but no $helper came with it" >&2; exit 1; }
107- sudo ln -sf "$(command -v "$helper")" "/usr/bin/$helper"
108- echo "$helper now at: $(readlink "/usr/bin/$helper")"
109- done
115+ # Rootless podman re-executes itself inside a fresh user namespace
116+ # before it does anything else, and a 2026-09-04 runner image
117+ # denied that exec ("failed to reexec: Permission denied") where
118+ # the morning's image allowed it: the kernel gained AppArmor's
119+ # unprivileged-userns restriction, under which an unprofiled
120+ # binary can enter a userns but not exec inside one. Rootless
121+ # containers cannot exist without unprivileged user namespaces,
122+ # so the restriction is cleared rather than worked around. The
123+ # old value is printed either way, to name the next drift.
124+ echo "apparmor_restrict_unprivileged_userns: $(cat /proc/sys/kernel/apparmor_restrict_unprivileged_userns 2>/dev/null || echo 'no such knob on this kernel')"
125+ sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0 >/dev/null 2>&1 || true
110126 # A new podman that cannot run as root would fail the install
111127 # twenty minutes in at the same COPY. Running a container as root
112128 # here costs seconds, exercises the store, the runtime and the
0 commit comments