From 4680882f804aad8f516f2794a9f44a26ba262015 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Mon, 9 Mar 2026 11:53:18 -0600 Subject: [PATCH 1/3] restore execute permissions on tool binaries: GitHub Actions artifact upload/download strips file permissions, causing containerd, runc, nerdctl, and CNI plugin binaries to lose their execute bit. This results in 'Permission denied' errors when systemd tries to start containerd.service inside the booted ISO. Signed-off-by: Jacob Weinstock --- .github/workflows/ci.yml | 7 +++++++ mkosi.finalize | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a5a0f55..6b7071f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -245,6 +245,13 @@ jobs: name: tools-${{ matrix.arch }} path: mkosi.output/tools/${{ matrix.arch }} + - name: Restore tool binary permissions + run: | + # GitHub Actions artifact upload/download strips execute permissions. + # Restore +x on all tool binaries so they work inside the initramfs. + chmod +x mkosi.output/tools/${{ matrix.arch }}/usr/local/bin/* + chmod +x mkosi.output/tools/${{ matrix.arch }}/opt/cni/bin/* + - name: Refresh apt cache run: sudo apt-get update diff --git a/mkosi.finalize b/mkosi.finalize index fc1d5f6..1057bcd 100755 --- a/mkosi.finalize +++ b/mkosi.finalize @@ -36,6 +36,18 @@ if [[ -f "$BUILDROOT/init" ]]; then echo " /init made executable" fi +# Ensure tool binaries are executable. +# GitHub Actions artifact upload/download and some archive tools strip +# the execute bit. Re-apply +x to every tool directory so containerd, +# runc, nerdctl, and CNI plugins can actually run. +for dir in usr/local/bin opt/cni/bin; do + target="$BUILDROOT/$dir" + if [[ -d "$target" ]]; then + find "$target" -type f -exec chmod +x {} + + echo " +x restored on $dir/*" + fi +done + # --------------------------------------------------------------------------- # Trim kernel modules not needed for provisioning. # The kernel is built with a broad defconfig (modules as =m) so the full set From f6c4dd86e61ff6dba20578c2c8579c0351a7414e Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Mon, 9 Mar 2026 12:08:18 -0600 Subject: [PATCH 2/3] move iso-staging under iso/ directory: Reduces top-level clutter in mkosi.output/ by nesting the staging directory inside iso/{ver}/{arch}/staging instead of maintaining a separate iso-staging/ tree. Signed-off-by: Jacob Weinstock --- captain/cli/_commands.py | 4 +--- captain/cli/_stages.py | 1 - captain/config.py | 2 +- captain/iso.py | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/captain/cli/_commands.py b/captain/cli/_commands.py index 4e2679e..2789757 100644 --- a/captain/cli/_commands.py +++ b/captain/cli/_commands.py @@ -123,7 +123,6 @@ def _clean_version(cfg: Config, clog: StageLogger) -> None: mkosi_output / "kernel" / kver / cfg.arch, mkosi_output / "initramfs" / kver / cfg.arch, mkosi_output / "iso" / kver / cfg.arch, - mkosi_output / "iso-staging" / kver / cfg.arch, ] has_docker = shutil.which("docker") is not None @@ -195,13 +194,12 @@ def _clean_all(cfg: Config, clog: StageLogger) -> None: " /work/mkosi.output/kernel" " /work/mkosi.output/tools" " /work/mkosi.output/iso" - " /work/mkosi.output/iso-staging" " /work/mkosi.cache", ], ) else: # No Docker available — remove directly (may need sudo for root-owned mkosi files) - for pattern in ("image*", "initramfs", "kernel", "tools", "iso", "iso-staging"): + for pattern in ("image*", "initramfs", "kernel", "tools", "iso"): for p in mkosi_output.glob(pattern): if p.is_dir(): shutil.rmtree(p, ignore_errors=True) diff --git a/captain/cli/_stages.py b/captain/cli/_stages.py index 326e606..4e359c2 100644 --- a/captain/cli/_stages.py +++ b/captain/cli/_stages.py @@ -188,7 +188,6 @@ def _build_iso_stage(cfg: Config) -> None: isolog, [ "/work/mkosi.output/iso", - "/work/mkosi.output/iso-staging", "/work/out", ], ) diff --git a/captain/config.py b/captain/config.py index 65434d0..90cd118 100644 --- a/captain/config.py +++ b/captain/config.py @@ -198,4 +198,4 @@ def iso_output(self) -> Path: @property def iso_staging(self) -> Path: """Per-version, per-arch staging directory for assembling the ISO filesystem.""" - return self.project_dir / "mkosi.output" / "iso-staging" / self.kernel_version / self.arch + return self.iso_output / "staging" diff --git a/captain/iso.py b/captain/iso.py index 4876482..8275b32 100644 --- a/captain/iso.py +++ b/captain/iso.py @@ -65,7 +65,7 @@ def build(cfg: Config) -> None: The ISO layout is:: - iso-staging/{arch}/ + iso/{version}/{arch}/staging/ ├── boot/ │ ├── grub/ │ │ └── grub.cfg From 5b856ed0e92d23c8b5e7c9e37b8fcb3709cbbbee Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Mon, 9 Mar 2026 12:30:04 -0600 Subject: [PATCH 3/3] Fix for cache hit warnings in GitHub Signed-off-by: Jacob Weinstock --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6b7071f..7f7ac28 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -148,7 +148,7 @@ jobs: run: sudo chown -R "$(id -u):$(id -g)" mkosi.output/ - name: Save kernel cache - if: github.ref == 'refs/heads/main' + if: github.ref == 'refs/heads/main' && steps.kernel-cache.outputs.cache-hit != 'true' uses: actions/cache/save@v4 with: path: | @@ -198,7 +198,7 @@ jobs: run: ./build.py tools - name: Save tools cache - if: github.ref == 'refs/heads/main' + if: github.ref == 'refs/heads/main' && steps.tools-cache.outputs.cache-hit != 'true' uses: actions/cache/save@v4 with: path: |