chore(session): harden chroot package installs (PATH + apt-get update)
- chroot_bash exports a Debian-safe PATH so /usr/sbin tools (update-initramfs, useradd, chpasswd, ...) resolve inside the chroot instead of failing with code 127. - install_packages runs apt-get update before install (a stock image ships stale lists whose superseded .deb URLs 404) and non-interactive apt-get install -y; pacman gains -Sy for the same index-refresh reason. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -161,11 +161,16 @@ class ImageSession:
|
|||||||
ui.warning("Failed.")
|
ui.warning("Failed.")
|
||||||
|
|
||||||
|
|
||||||
|
# The host PATH leaks into the chroot; force one that includes the sbin dirs
|
||||||
|
# where Debian keeps update-initramfs, useradd, chpasswd, ... (else code 127).
|
||||||
|
_CHROOT_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||||
|
|
||||||
|
|
||||||
def chroot_bash(root_mount_path: Path | str, script: str, error_msg: str | None = None) -> None:
|
def chroot_bash(root_mount_path: Path | str, script: str, error_msg: str | None = None) -> None:
|
||||||
"""Run a bash script inside the image via chroot."""
|
"""Run a bash script inside the image via chroot (with a Debian-safe PATH)."""
|
||||||
runner.run(
|
runner.run(
|
||||||
["chroot", str(root_mount_path), "/bin/bash"],
|
["chroot", str(root_mount_path), "/bin/bash"],
|
||||||
input_text=script,
|
input_text=f"export PATH={_CHROOT_PATH}\n{script}",
|
||||||
sudo=True,
|
sudo=True,
|
||||||
error_msg=error_msg,
|
error_msg=error_msg,
|
||||||
)
|
)
|
||||||
@@ -175,8 +180,13 @@ def install_packages(distribution: str, root_mount_path: Path, package_names: st
|
|||||||
"""Install packages inside the image with the distribution's package manager."""
|
"""Install packages inside the image with the distribution's package manager."""
|
||||||
ui.info(f"Installing {package_names}...")
|
ui.info(f"Installing {package_names}...")
|
||||||
if distribution in ("arch", "manjaro"):
|
if distribution in ("arch", "manjaro"):
|
||||||
chroot_bash(root_mount_path, f"pacman --noconfirm -S --needed {package_names}")
|
chroot_bash(root_mount_path, f"pacman --noconfirm -Sy --needed {package_names}")
|
||||||
elif distribution in ("moode", "retropie", "raspios"):
|
elif distribution in ("moode", "retropie", "raspios"):
|
||||||
chroot_bash(root_mount_path, f"yes | apt install {package_names}")
|
# apt-get update first: a stock image ships stale lists whose old .deb
|
||||||
|
# URLs 404 once the mirror has superseded them.
|
||||||
|
chroot_bash(
|
||||||
|
root_mount_path,
|
||||||
|
f"apt-get update\nDEBIAN_FRONTEND=noninteractive apt-get install -y {package_names}",
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise LimError("Package manager not supported.")
|
raise LimError("Package manager not supported.")
|
||||||
|
|||||||
@@ -101,7 +101,8 @@ class TestInstallPackages:
|
|||||||
for kind, cmd, input_text in fake_runner.calls
|
for kind, cmd, input_text in fake_runner.calls
|
||||||
if kind == "run" and cmd[0] == "chroot"
|
if kind == "run" and cmd[0] == "chroot"
|
||||||
]
|
]
|
||||||
assert chroot_calls == ["pacman --noconfirm -S --needed btrfs-progs"]
|
assert len(chroot_calls) == 1
|
||||||
|
assert "pacman --noconfirm -Sy --needed btrfs-progs" in chroot_calls[0]
|
||||||
|
|
||||||
def test_apt_for_retropie(self, tmp_path, fake_runner):
|
def test_apt_for_retropie(self, tmp_path, fake_runner):
|
||||||
install_packages("retropie", tmp_path, "btrfs-progs")
|
install_packages("retropie", tmp_path, "btrfs-progs")
|
||||||
@@ -110,7 +111,9 @@ class TestInstallPackages:
|
|||||||
for kind, cmd, input_text in fake_runner.calls
|
for kind, cmd, input_text in fake_runner.calls
|
||||||
if kind == "run" and cmd[0] == "chroot"
|
if kind == "run" and cmd[0] == "chroot"
|
||||||
]
|
]
|
||||||
assert chroot_calls == ["yes | apt install btrfs-progs"]
|
assert len(chroot_calls) == 1
|
||||||
|
assert "apt-get update" in chroot_calls[0]
|
||||||
|
assert "apt-get install -y btrfs-progs" in chroot_calls[0]
|
||||||
|
|
||||||
def test_unsupported_distribution_raises(self, tmp_path, fake_runner):
|
def test_unsupported_distribution_raises(self, tmp_path, fake_runner):
|
||||||
with pytest.raises(LimError):
|
with pytest.raises(LimError):
|
||||||
|
|||||||
@@ -189,7 +189,7 @@ class TestInitramfsToolsBackend:
|
|||||||
apt = [
|
apt = [
|
||||||
text
|
text
|
||||||
for _, _, text in fake_runner.calls
|
for _, _, text in fake_runner.calls
|
||||||
if text and "apt install" in text and "tor busybox" in text
|
if text and "apt-get install" in text and "tor busybox" in text
|
||||||
]
|
]
|
||||||
assert len(apt) == 1
|
assert len(apt) == 1
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user