From b8ba5129d0a177c12c1bade3a768e48ba2705e49 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Mon, 13 Apr 2026 23:30:36 -0600 Subject: [PATCH 1/5] Improve Docker build reliability and add build idempotency: - Dockerfile: install dependencies into a persistent venv instead of priming the uv cache, so uv run reuses it rather than recreating one - docker.py: add --load to buildx build commands so images are available in the local Docker daemon - cli/_stages.py: skip initramfs build if output already exists (use --force to rebuild) - Add uv.lock for reproducible dependency resolution Signed-off-by: Jacob Weinstock --- Dockerfile | 17 ++++-- captain/cli/_stages.py | 7 +++ captain/docker.py | 4 +- uv.lock | 135 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 155 insertions(+), 8 deletions(-) create mode 100644 uv.lock diff --git a/Dockerfile b/Dockerfile index 6750a78..0ad0f83 100644 --- a/Dockerfile +++ b/Dockerfile @@ -74,12 +74,17 @@ RUN ln -sf ~/.local/bin/mkosi /usr/bin/mkosi # Verify mkosi is functional RUN mkosi --version -# Prime uv's cache with our pyproject.toml to speed up runtime -COPY pyproject.toml /tmp/pyproject.toml -COPY captain /tmp/captain -COPY build.py /tmp/build.py -WORKDIR /tmp -RUN uv --verbose run build.py --help +# Install project dependencies into a persistent venv so that +# `uv run` inside the container reuses it instead of recreating one. +COPY pyproject.toml /opt/captain/pyproject.toml +COPY captain /opt/captain/captain +COPY build.py /opt/captain/build.py +RUN uv venv /opt/captain-venv && \ + VIRTUAL_ENV=/opt/captain-venv uv pip install --project /opt/captain /opt/captain + +# Point uv at the pre-built venv for all future runs. +ENV VIRTUAL_ENV=/opt/captain-venv +ENV UV_PROJECT_ENVIRONMENT=/opt/captain-venv WORKDIR /work ENTRYPOINT ["mkosi"] diff --git a/captain/cli/_stages.py b/captain/cli/_stages.py index 358d299..d15284e 100644 --- a/captain/cli/_stages.py +++ b/captain/cli/_stages.py @@ -102,6 +102,13 @@ def _build_mkosi_stage(cfg: Config, extra_args: list[str]) -> None: log.info("MKOSI_MODE=skip — skipping image assembly") return + # --- idempotency -------------------------------------------------- + initramfs_image = cfg.initramfs_output / "image.cpio.zst" + force = "--force" in cfg.mkosi_args + if initramfs_image.is_file() and not force: + log.info("Initramfs already built: %s (use --force to rebuild)", initramfs_image) + return + mkosi_args = list(cfg.mkosi_args) + list(extra_args) # --- native ------------------------------------------------------- diff --git a/captain/docker.py b/captain/docker.py index cdf2ddb..0aaf921 100644 --- a/captain/docker.py +++ b/captain/docker.py @@ -59,7 +59,7 @@ def build_builder(cfg: Config) -> None: return log.info("Building Docker image '%s'...", cfg.builder_image) - cmd = ["docker", "buildx", "build"] + cmd = ["docker", "buildx", "build", "--load"] if cfg.no_cache: cmd.append("--no-cache") cmd.extend( @@ -88,7 +88,7 @@ def build_release_image(cfg: Config) -> None: return log.info("Building Docker image '%s'...", RELEASE_IMAGE) - cmd = ["docker", "buildx", "build", "-f", str(cfg.project_dir / "Dockerfile.release")] + cmd = ["docker", "buildx", "build", "--load", "-f", str(cfg.project_dir / "Dockerfile.release")] if cfg.no_cache: cmd.append("--no-cache") cmd.extend(["--progress=plain"]) diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..b436ceb --- /dev/null +++ b/uv.lock @@ -0,0 +1,135 @@ +version = 1 +revision = 3 +requires-python = ">=3.13" + +[[package]] +name = "captain" +version = "0.0.1" +source = { virtual = "." } +dependencies = [ + { name = "configargparse" }, + { name = "rich" }, +] + +[package.optional-dependencies] +dev = [ + { name = "pyright" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "configargparse", specifier = ">=1.7" }, + { name = "pyright", marker = "extra == 'dev'", specifier = ">=1.1" }, + { name = "rich", specifier = ">=14.3.3" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.9" }, +] +provides-extras = ["dev"] + +[[package]] +name = "configargparse" +version = "1.7.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/3f/0b/30328302903c55218ffc5199646d0e9d28348ff26c02ba77b2ffc58d294a/configargparse-1.7.5.tar.gz", hash = "sha256:e3f9a7bb6be34d66b2e3c4a2f58e3045f8dfae47b0dc039f87bcfaa0f193fb0f", size = 53548, upload-time = "2026-03-11T02:19:38.144Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/19/3ba5e1b0bcc7b91aeab6c258afd70e4907d220fed3972febe38feb40db30/configargparse-1.7.5-py3-none-any.whl", hash = "sha256:1e63fdffedf94da9cd435fc13a1cd24777e76879dd2343912c1f871d4ac8c592", size = 27692, upload-time = "2026-03-11T02:19:36.442Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "nodeenv" +version = "1.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/bf/d1bda4f6168e0b2e9e5958945e01910052158313224ada5ce1fb2e1113b8/nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb", size = 55611, upload-time = "2025-12-20T14:08:54.006Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, +] + +[[package]] +name = "pygments" +version = "2.20.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c3/b2/bc9c9196916376152d655522fdcebac55e66de6603a76a02bca1b6414f6c/pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f", size = 4955991, upload-time = "2026-03-29T13:29:33.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/7e/a72dd26f3b0f4f2bf1dd8923c85f7ceb43172af56d63c7383eb62b332364/pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176", size = 1231151, upload-time = "2026-03-29T13:29:30.038Z" }, +] + +[[package]] +name = "pyright" +version = "1.1.408" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nodeenv" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/b2/5db700e52554b8f025faa9c3c624c59f1f6c8841ba81ab97641b54322f16/pyright-1.1.408.tar.gz", hash = "sha256:f28f2321f96852fa50b5829ea492f6adb0e6954568d1caa3f3af3a5f555eb684", size = 4400578, upload-time = "2026-01-08T08:07:38.795Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/82/a2c93e32800940d9573fb28c346772a14778b84ba7524e691b324620ab89/pyright-1.1.408-py3-none-any.whl", hash = "sha256:090b32865f4fdb1e0e6cd82bf5618480d48eecd2eb2e70f960982a3d9a4c17c1", size = 6399144, upload-time = "2026-01-08T08:07:37.082Z" }, +] + +[[package]] +name = "rich" +version = "15.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" }, +] + +[[package]] +name = "ruff" +version = "0.15.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/d9/aa3f7d59a10ef6b14fe3431706f854dbf03c5976be614a9796d36326810c/ruff-0.15.10.tar.gz", hash = "sha256:d1f86e67ebfdef88e00faefa1552b5e510e1d35f3be7d423dc7e84e63788c94e", size = 4631728, upload-time = "2026-04-09T14:06:09.884Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/00/a1c2fdc9939b2c03691edbda290afcd297f1f389196172826b03d6b6a595/ruff-0.15.10-py3-none-linux_armv6l.whl", hash = "sha256:0744e31482f8f7d0d10a11fcbf897af272fefdfcb10f5af907b18c2813ff4d5f", size = 10563362, upload-time = "2026-04-09T14:06:21.189Z" }, + { url = "https://files.pythonhosted.org/packages/5c/15/006990029aea0bebe9d33c73c3e28c80c391ebdba408d1b08496f00d422d/ruff-0.15.10-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b1e7c16ea0ff5a53b7c2df52d947e685973049be1cdfe2b59a9c43601897b22e", size = 10951122, upload-time = "2026-04-09T14:06:02.236Z" }, + { url = "https://files.pythonhosted.org/packages/f2/c0/4ac978fe874d0618c7da647862afe697b281c2806f13ce904ad652fa87e4/ruff-0.15.10-py3-none-macosx_11_0_arm64.whl", hash = "sha256:93cc06a19e5155b4441dd72808fdf84290d84ad8a39ca3b0f994363ade4cebb1", size = 10314005, upload-time = "2026-04-09T14:06:00.026Z" }, + { url = "https://files.pythonhosted.org/packages/da/73/c209138a5c98c0d321266372fc4e33ad43d506d7e5dd817dd89b60a8548f/ruff-0.15.10-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:83e1dd04312997c99ea6965df66a14fb4f03ba978564574ffc68b0d61fd3989e", size = 10643450, upload-time = "2026-04-09T14:05:42.137Z" }, + { url = "https://files.pythonhosted.org/packages/ec/76/0deec355d8ec10709653635b1f90856735302cb8e149acfdf6f82a5feb70/ruff-0.15.10-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8154d43684e4333360fedd11aaa40b1b08a4e37d8ffa9d95fee6fa5b37b6fab1", size = 10379597, upload-time = "2026-04-09T14:05:49.984Z" }, + { url = "https://files.pythonhosted.org/packages/dc/be/86bba8fc8798c081e28a4b3bb6d143ccad3fd5f6f024f02002b8f08a9fa3/ruff-0.15.10-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ab88715f3a6deb6bde6c227f3a123410bec7b855c3ae331b4c006189e895cef", size = 11146645, upload-time = "2026-04-09T14:06:12.246Z" }, + { url = "https://files.pythonhosted.org/packages/a8/89/140025e65911b281c57be1d385ba1d932c2366ca88ae6663685aed8d4881/ruff-0.15.10-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a768ff5969b4f44c349d48edf4ab4f91eddb27fd9d77799598e130fb628aa158", size = 12030289, upload-time = "2026-04-09T14:06:04.776Z" }, + { url = "https://files.pythonhosted.org/packages/88/de/ddacca9545a5e01332567db01d44bd8cf725f2db3b3d61a80550b48308ea/ruff-0.15.10-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ee3ef42dab7078bda5ff6a1bcba8539e9857deb447132ad5566a038674540d0", size = 11496266, upload-time = "2026-04-09T14:05:55.485Z" }, + { url = "https://files.pythonhosted.org/packages/bc/bb/7ddb00a83760ff4a83c4e2fc231fd63937cc7317c10c82f583302e0f6586/ruff-0.15.10-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51cb8cc943e891ba99989dd92d61e29b1d231e14811db9be6440ecf25d5c1609", size = 11256418, upload-time = "2026-04-09T14:05:57.69Z" }, + { url = "https://files.pythonhosted.org/packages/dc/8d/55de0d35aacf6cd50b6ee91ee0f291672080021896543776f4170fc5c454/ruff-0.15.10-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:e59c9bdc056a320fb9ea1700a8d591718b8faf78af065484e801258d3a76bc3f", size = 11288416, upload-time = "2026-04-09T14:05:44.695Z" }, + { url = "https://files.pythonhosted.org/packages/68/cf/9438b1a27426ec46a80e0a718093c7f958ef72f43eb3111862949ead3cc1/ruff-0.15.10-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:136c00ca2f47b0018b073f28cb5c1506642a830ea941a60354b0e8bc8076b151", size = 10621053, upload-time = "2026-04-09T14:05:52.782Z" }, + { url = "https://files.pythonhosted.org/packages/4c/50/e29be6e2c135e9cd4cb15fbade49d6a2717e009dff3766dd080fcb82e251/ruff-0.15.10-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8b80a2f3c9c8a950d6237f2ca12b206bccff626139be9fa005f14feb881a1ae8", size = 10378302, upload-time = "2026-04-09T14:06:14.361Z" }, + { url = "https://files.pythonhosted.org/packages/18/2f/e0b36a6f99c51bb89f3a30239bc7bf97e87a37ae80aa2d6542d6e5150364/ruff-0.15.10-py3-none-musllinux_1_2_i686.whl", hash = "sha256:e3e53c588164dc025b671c9df2462429d60357ea91af7e92e9d56c565a9f1b07", size = 10850074, upload-time = "2026-04-09T14:06:16.581Z" }, + { url = "https://files.pythonhosted.org/packages/11/08/874da392558ce087a0f9b709dc6ec0d60cbc694c1c772dab8d5f31efe8cb/ruff-0.15.10-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b0c52744cf9f143a393e284125d2576140b68264a93c6716464e129a3e9adb48", size = 11358051, upload-time = "2026-04-09T14:06:18.948Z" }, + { url = "https://files.pythonhosted.org/packages/e4/46/602938f030adfa043e67112b73821024dc79f3ab4df5474c25fa4c1d2d14/ruff-0.15.10-py3-none-win32.whl", hash = "sha256:d4272e87e801e9a27a2e8df7b21011c909d9ddd82f4f3281d269b6ba19789ca5", size = 10588964, upload-time = "2026-04-09T14:06:07.14Z" }, + { url = "https://files.pythonhosted.org/packages/25/b6/261225b875d7a13b33a6d02508c39c28450b2041bb01d0f7f1a83d569512/ruff-0.15.10-py3-none-win_amd64.whl", hash = "sha256:28cb32d53203242d403d819fd6983152489b12e4a3ae44993543d6fe62ab42ed", size = 11745044, upload-time = "2026-04-09T14:05:39.473Z" }, + { url = "https://files.pythonhosted.org/packages/58/ed/dea90a65b7d9e69888890fb14c90d7f51bf0c1e82ad800aeb0160e4bacfd/ruff-0.15.10-py3-none-win_arm64.whl", hash = "sha256:601d1610a9e1f1c2165a4f561eeaa2e2ea1e97f3287c5aa258d3dab8b57c6188", size = 11035607, upload-time = "2026-04-09T14:05:47.593Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] From 3202bdf25b51c08456561358203f0e9351787523 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Tue, 26 May 2026 12:20:19 -0600 Subject: [PATCH 2/5] Fix rsyslog container log parsing: This get all Action container logs over to Tinkerbell via rsyslog properly. Signed-off-by: Jacob Weinstock --- mkosi.extra/etc/rsyslog.conf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mkosi.extra/etc/rsyslog.conf b/mkosi.extra/etc/rsyslog.conf index 09fa721..ab2d204 100644 --- a/mkosi.extra/etc/rsyslog.conf +++ b/mkosi.extra/etc/rsyslog.conf @@ -15,10 +15,10 @@ global( # want journal entries from specific units, not all daemon syslog output. module(load="imjournal") -# Tail containerd container log files (workflow action stdout/stderr). +# Tail nerdctl container log files (workflow action stdout/stderr). module(load="imfile") input(type="imfile" - File="/var/lib/containerd/io.containerd.grpc.v2.task/*/log" + File="/var/lib/nerdctl/*/containers/*/*/*-json.log" Tag="container" Severity="info" Facility="local0" @@ -38,7 +38,7 @@ if ($!_SYSTEMD_UNIT == "tink-agent.service" or $!_SYSTEMD_UNIT == "tink-agent-se # Forward container logs (from imfile). # Match "container:" specifically — NOT "containerd" (the daemon). -if ($syslogtag startswith "container:") then { +if ($syslogtag startswith "container") then { action(type="omfwd" target=`echo $SYSLOG_HOST` port=`echo $SYSLOG_PORT` From 5aff4d91d65511edadeecd174e415034d833ad98 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Tue, 26 May 2026 20:16:09 -0600 Subject: [PATCH 3/5] Fix arm64 initramfs builds in CI Signed-off-by: Jacob Weinstock --- mkosi.conf | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/mkosi.conf b/mkosi.conf index 10a5702..ceb619c 100644 --- a/mkosi.conf +++ b/mkosi.conf @@ -10,6 +10,12 @@ OutputDirectory=mkosi.output [Build] ToolsTree=yes +# grub-pc-bin is i386/amd64-only (BIOS GRUB). mkosi's default tools-tree +# package list pulls it in unconditionally, which breaks arm64 builds +# (no arm64 candidate exists). We build UEFI ISOs only; the amd64 ISO is +# assembled inside the builder container (Dockerfile) using grub-efi-*-bin, +# so dropping grub-pc-bin is safe on both architectures. +ToolsTreePackages=!grub-pc-bin Incremental=yes CacheDirectory=mkosi.cache From e18eb7b2dd71d144ca5434f155700c2167b988a6 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Tue, 26 May 2026 20:41:24 -0600 Subject: [PATCH 4/5] Pin mkosi past v26 for arm64 tools-tree: mkosi v26's default tools tree unconditionally pulls in grub-pc-bin, which has no arm64 candidate in current Debian trixie. The pre-existing `?exact-name(grub-pc-bin)` apt soft-fail pattern no longer soft-fails, so arm64 initramfs builds hard-error. Upstream fixed this in systemd/mkosi@1f811f05 by moving grub-pc-bin into an x86-only drop-in, but no release tag past v26 exists yet, so pin to the commit. Signed-off-by: Jacob Weinstock --- .github/workflows/ci.yml | 5 ++++- Dockerfile | 6 +++++- mkosi.conf | 6 ------ 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e0c6572..6c8bc82 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -258,7 +258,10 @@ jobs: run: sudo apt-get -o "Dpkg::Use-Pty=0" update - name: setup-mkosi - uses: systemd/mkosi@v26 + # Pinned post-v26 to pick up systemd/mkosi@1f811f05 ("tools: move grub-pc-bin + # to arch-specific drop-in"), which fixes arm64 builds failing on the + # default tools-tree pulling in grub-pc-bin (BIOS GRUB, x86-only). + uses: systemd/mkosi@1f811f0524be3096872e79161c8e6ab3e7c2bb1f - name: Install bubblewrap run: | diff --git a/Dockerfile b/Dockerfile index 0ad0f83..07061d5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,7 +3,11 @@ # Usage: docker build -t captainos-builder . && docker run --rm --privileged -v $(pwd):/work captainos-builder build FROM debian:trixie -ARG MKOSI_VERSION=v26 +# Pinned post-v26 to pick up systemd/mkosi@1f811f05 ("tools: move grub-pc-bin +# to arch-specific drop-in"), which fixes arm64 builds failing on the default +# tools-tree pulling in grub-pc-bin (BIOS GRUB, x86-only). Bump to a release +# tag once v27 lands. +ARG MKOSI_VERSION=1f811f0524be3096872e79161c8e6ab3e7c2bb1f # Avoid interactive prompts ENV DEBIAN_FRONTEND=noninteractive diff --git a/mkosi.conf b/mkosi.conf index ceb619c..10a5702 100644 --- a/mkosi.conf +++ b/mkosi.conf @@ -10,12 +10,6 @@ OutputDirectory=mkosi.output [Build] ToolsTree=yes -# grub-pc-bin is i386/amd64-only (BIOS GRUB). mkosi's default tools-tree -# package list pulls it in unconditionally, which breaks arm64 builds -# (no arm64 candidate exists). We build UEFI ISOs only; the amd64 ISO is -# assembled inside the builder container (Dockerfile) using grub-efi-*-bin, -# so dropping grub-pc-bin is safe on both architectures. -ToolsTreePackages=!grub-pc-bin Incremental=yes CacheDirectory=mkosi.cache From c0af77fa47c51bfe43395370beeff7d75b356f14 Mon Sep 17 00:00:00 2001 From: Jacob Weinstock Date: Tue, 26 May 2026 22:49:19 -0600 Subject: [PATCH 5/5] Bump GitHub Actions to current major versions: astral-sh/setup-uv v8 dropped floating major/minor tags as a supply-chain hardening measure, so the previous `@v7` reference will stop resolving. Pin to the exact `@v8.1.0` tag instead. Update all the other actions that have moved to Node 24 runtimes since the workflows were last touched. Signed-off-by: Jacob Weinstock --- .github/workflows/ci.yml | 56 +++++++++++++++++------------------ .github/workflows/release.yml | 4 +-- 2 files changed, 30 insertions(+), 30 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6c8bc82..522dfab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@v6 - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@v8.1.0 - name: Install lint tools run: make lint-install @@ -96,7 +96,7 @@ jobs: run: cat .github/config.env >> "$GITHUB_ENV" - name: Log in to GHCR - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} @@ -141,7 +141,7 @@ jobs: key: ${{ steps.kernel-cache-key.outputs.key }} - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@v8.1.0 - name: Build kernel run: uv run ./build.py kernel @@ -158,7 +158,7 @@ jobs: key: ${{ steps.kernel-cache-key.outputs.key }} - name: Upload kernel artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: kernel-${{ matrix.arch }} path: | @@ -194,7 +194,7 @@ jobs: key: tools-${{ matrix.arch }}-${{ hashFiles('captain/tools.py') }} - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@v8.1.0 - name: Download tools run: uv run ./build.py tools @@ -209,7 +209,7 @@ jobs: key: tools-${{ matrix.arch }}-${{ hashFiles('captain/tools.py') }} - name: Upload tools artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: tools-${{ matrix.arch }} path: | @@ -236,13 +236,13 @@ jobs: uses: actions/checkout@v6 - name: Download kernel artifacts - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v8 with: name: kernel-${{ matrix.arch }} path: mkosi.output/kernel/${{ env.KERNEL_VERSION }}/${{ matrix.arch }} - name: Download tools artifacts - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v8 with: name: tools-${{ matrix.arch }} path: mkosi.output/tools/${{ matrix.arch }} @@ -269,13 +269,13 @@ jobs: sudo apt-get -o "Dpkg::Use-Pty=0" install -y bubblewrap - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@v8.1.0 - name: Build initramfs run: uv run ./build.py initramfs - name: Upload initramfs artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: initramfs-${{ matrix.arch }} path: out/ @@ -309,7 +309,7 @@ jobs: run: cat .github/config.env >> "$GITHUB_ENV" - name: Log in to GHCR - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} @@ -342,13 +342,13 @@ jobs: docker push "${REMOTE}:${HASH}-${{ matrix.arch }}" - name: Download kernel artifacts - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v8 with: name: kernel-${{ matrix.arch }} path: mkosi.output/kernel/${{ env.KERNEL_VERSION }}/${{ matrix.arch }} - name: Download initramfs artifacts - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v8 with: name: initramfs-${{ matrix.arch }} path: out @@ -360,13 +360,13 @@ jobs: "mkosi.output/initramfs/${KERNEL_VERSION}/${{ matrix.arch }}/image.cpio.zst" - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@v8.1.0 - name: Build ISO run: uv run ./build.py iso - name: Upload ISO artifact - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: iso-${{ matrix.arch }} path: out/captainos-${{ env.KERNEL_VERSION }}-${{ matrix.output_arch }}.iso @@ -396,28 +396,28 @@ jobs: run: cat .github/config.env >> "$GITHUB_ENV" - name: Download kernel artifacts - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v8 with: name: kernel-${{ matrix.target }} path: mkosi.output/kernel/${{ env.KERNEL_VERSION }}/${{ matrix.target }} - name: Download initramfs artifacts - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v8 with: name: initramfs-${{ matrix.target }} path: out - name: Download ISO artifact - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v8 with: name: iso-${{ matrix.target }} path: out - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@v8.1.0 - name: Log in to GHCR - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} @@ -446,46 +446,46 @@ jobs: run: cat .github/config.env >> "$GITHUB_ENV" - name: Download kernel artifacts (amd64) - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v8 with: name: kernel-amd64 path: mkosi.output/kernel/${{ env.KERNEL_VERSION }}/amd64 - name: Download initramfs artifacts (amd64) - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v8 with: name: initramfs-amd64 path: out - name: Download ISO artifact (amd64) - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v8 with: name: iso-amd64 path: out - name: Download kernel artifacts (arm64) - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v8 with: name: kernel-arm64 path: mkosi.output/kernel/${{ env.KERNEL_VERSION }}/arm64 - name: Download initramfs artifacts (arm64) - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v8 with: name: initramfs-arm64 path: out - name: Download ISO artifact (arm64) - uses: actions/download-artifact@v6 + uses: actions/download-artifact@v8 with: name: iso-arm64 path: out - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@v8.1.0 - name: Log in to GHCR - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c478a8f..6e249c2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -18,7 +18,7 @@ jobs: fetch-depth: 0 - name: Log in to GHCR - uses: docker/login-action@v3 + uses: docker/login-action@v4 with: registry: ghcr.io username: ${{ github.actor }} @@ -28,7 +28,7 @@ jobs: run: cat .github/config.env >> "$GITHUB_ENV" - name: Install uv - uses: astral-sh/setup-uv@v7 + uses: astral-sh/setup-uv@v8.1.0 - name: Pull release artifacts (combined) env: