From 5e5431f1aaa7af8d58afc08f48a91a855adaf7bc Mon Sep 17 00:00:00 2001 From: "Alex M. Lowe" Date: Thu, 23 Jul 2026 14:46:10 -0400 Subject: [PATCH 01/14] fix(pack): fix GRUB EFI stub and classic boot test setup - Fix GRUB EFI stub generation in grubutil.py to avoid hardware serial overrides in UEFI mode, which conflict with OVMF and cause QEMU to hang. - Update tests/spread/boot/classic/imagecraft.yaml to configure recordfail timeout, serial terminal, and manual boot-sentinel service symlinking. - Update tests/spread/boot/classic/task.yaml to include a QEMU timeout and check output log for sentinel output. --- imagecraft/pack/grubutil.py | 76 ++++++++++++++++++++--- tests/spread/boot/classic/imagecraft.yaml | 13 ++-- tests/spread/boot/classic/task.yaml | 5 +- 3 files changed, 79 insertions(+), 15 deletions(-) diff --git a/imagecraft/pack/grubutil.py b/imagecraft/pack/grubutil.py index 7faace24..aa2b7fd6 100644 --- a/imagecraft/pack/grubutil.py +++ b/imagecraft/pack/grubutil.py @@ -14,6 +14,7 @@ """GRUB utils.""" +import shutil import subprocess from pathlib import Path @@ -41,6 +42,13 @@ _GRUB_BIOS_TARGET = "i386-pc" _GRUB_BIOS_ARCHS = {DebianArchitecture.AMD64, DebianArchitecture.I386} +# Maps grub EFI target → (grub binary name under /EFI//, fallback sibling name) +_EFI_TARGET_TO_FILENAMES: dict[str, tuple[str, str]] = { + "x86_64-efi": ("grubx64.efi", "grubx64.efi"), + "arm64-efi": ("grubaa64.efi", "grubaa64.efi"), + "arm-efi": ("grubarm.efi", "grubarm.efi"), +} + def _grub_install(grub_target: str, loop_dev: str) -> None: """Install grub in the image. @@ -65,6 +73,9 @@ def _grub_install(grub_target: str, loop_dev: str) -> None: f"--target={grub_target}", "--uefi-secure-boot", "--no-nvram", + # Ubuntu's signed grub binary has /EFI/ubuntu compiled in as its + # $prefix, so the config and modules must live there. + "--bootloader-id=ubuntu", ] update_grub_command = [ @@ -116,6 +127,56 @@ def _grub_install(grub_target: str, loop_dev: str) -> None: except FileNotFoundError as err: raise errors.GRUBInstallError("Missing tool to install grub") from err + _populate_uefi_fallback(grub_target) + + +def _extract_root_uuid(grub_cfg_src: Path) -> str: + """Extract rootfs UUID from a search.fs_uuid line in a GRUB config file.""" + for line in grub_cfg_src.read_text(encoding="utf-8").splitlines(): + if line.startswith("search.fs_uuid "): + parts = line.split() + if len(parts) > 1: + return parts[1] + return "" + + +def _populate_uefi_fallback(grub_target: str) -> None: + """Populate UEFI fallback path with grub + config next to BOOT*.EFI. + + We intentionally keep BOOT*.EFI as shim and provide grubx64.efi/grub.cfg + in the same directory, which is the location shim looks at first. + """ + if grub_target not in _EFI_TARGET_TO_FILENAMES: + return + + grub_fname, fallback_grub_fname = _EFI_TARGET_TO_FILENAMES[grub_target] + efi_dir = Path("/boot/efi/EFI") + grub_src = efi_dir / "ubuntu" / grub_fname + grub_cfg_src = efi_dir / "ubuntu" / "grub.cfg" + boot_grub = efi_dir / "BOOT" / fallback_grub_fname + boot_cfg = efi_dir / "BOOT" / "grub.cfg" + + if not (grub_src.exists() and grub_cfg_src.exists()): + return + + boot_grub.parent.mkdir(parents=True, exist_ok=True) + shutil.copy2(grub_src, boot_grub) + root_uuid = _extract_root_uuid(grub_cfg_src) + if root_uuid: + # In this path grub may start in command mode; `normal` enters + # menu mode and evaluates /boot/grub/grub.cfg from the rootfs. + stub = "\n".join( + [ + f"search.fs_uuid {root_uuid} root", + "set prefix=($root)'/boot/grub'", + "normal", + ] + ) + boot_cfg.write_text(stub + "\n", encoding="utf-8") + grub_cfg_src.write_text(stub + "\n", encoding="utf-8") + else: + shutil.copy2(grub_cfg_src, boot_cfg) + def setup_grub( image: Image, workdir: Path, arch: str, filesystem_mount: FilesystemMount @@ -161,16 +222,15 @@ def setup_grub( with image.attach_loopdev() as loop_dev: mounts: list[Mount] = [ *_image_mounts(loop_dev, image.volume.structure, filesystem_mount), + # Use a recursive bind of the host's /dev so that loop devices + # created by losetup (e.g. /dev/loop5) are visible inside the + # chroot. A fresh devtmpfs would not contain them, causing + # grub-install to fail silently when it cannot access the disk. Mount( - fstype="devtmpfs", - src="devtmpfs-build", + fstype=None, + src="/dev", relative_mountpoint="/dev", - ), - Mount( - fstype="devpts", - src="devpts-build", - relative_mountpoint="/dev/pts", - options=["-o", "nodev,nosuid"], + options=["--rbind"], ), Mount(fstype="proc", src="proc-build", relative_mountpoint="proc"), Mount(fstype="sysfs", src="sysfs-build", relative_mountpoint="/sys"), diff --git a/tests/spread/boot/classic/imagecraft.yaml b/tests/spread/boot/classic/imagecraft.yaml index 1c6d050f..c328f56c 100644 --- a/tests/spread/boot/classic/imagecraft.yaml +++ b/tests/spread/boot/classic/imagecraft.yaml @@ -68,7 +68,12 @@ parts: override-overlay: | cat << 'EOF' > /etc/default/grub GRUB_TIMEOUT=1 - GRUB_TIMEOUT_STYLE=hidden + GRUB_RECORDFAIL_TIMEOUT=1 + GRUB_TIMEOUT_STYLE=menu + GRUB_TERMINAL="console serial" + GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1" + GRUB_CMDLINE_LINUX_DEFAULT="" + GRUB_CMDLINE_LINUX="console=ttyS0,115200n8 console=tty1" EOF sentinel-service: @@ -84,18 +89,18 @@ parts: cat << EOF > /etc/systemd/system/boot-sentinel.service [Unit] Description=Boot sentinel - After=multi-user.target [Service] Type=oneshot - ExecStart=/bin/bash -c 'echo HELLO FROM IMAGECRAFT > $SERIAL_CONSOLE' + ExecStart=/bin/bash -c 'echo HELLO FROM IMAGECRAFT > /var/lib/boot-sentinel.txt; echo HELLO FROM IMAGECRAFT > $SERIAL_CONSOLE || true' ExecStartPost=/sbin/poweroff [Install] WantedBy=multi-user.target EOF - systemctl enable boot-sentinel.service + mkdir -p /etc/systemd/system/multi-user.target.wants + ln -sf /etc/systemd/system/boot-sentinel.service /etc/systemd/system/multi-user.target.wants/boot-sentinel.service volumes: pc: diff --git a/tests/spread/boot/classic/task.yaml b/tests/spread/boot/classic/task.yaml index 5147b24f..ea9fe70f 100644 --- a/tests/spread/boot/classic/task.yaml +++ b/tests/spread/boot/classic/task.yaml @@ -31,10 +31,9 @@ execute: | echo "Unsupported arch: $ARCH" exit 1 fi - cp "$UEFI_VARS" /tmp/uefi_vars.fd - $QEMU_BIN \ + timeout 180 $QEMU_BIN \ $QEMU_ARGS \ -accel kvm -accel tcg,thread=multi \ -smp "$(nproc)" \ @@ -42,7 +41,7 @@ execute: | -m 1G \ -drive if=pflash,format=raw,readonly=on,file=$UEFI_CODE \ -drive if=pflash,format=raw,file=/tmp/uefi_vars.fd \ - -drive file=pc.img,format=raw,index=0,if=virtio 2>&1 | tee output.log || true + -drive file=pc.img,format=raw,index=0,if=ide 2>&1 | tee output.log || true MATCH "HELLO FROM IMAGECRAFT" output.log From 9eb3d6341529f43b5be8d96525cc142ba55cdcf4 Mon Sep 17 00:00:00 2001 From: "Alex M. Lowe" Date: Thu, 23 Jul 2026 18:33:31 -0400 Subject: [PATCH 02/14] fix(test): use virtio drive interface and cache=unsafe in classic boot spread test --- tests/spread/boot/classic/task.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/spread/boot/classic/task.yaml b/tests/spread/boot/classic/task.yaml index ea9fe70f..8f4530a5 100644 --- a/tests/spread/boot/classic/task.yaml +++ b/tests/spread/boot/classic/task.yaml @@ -33,7 +33,7 @@ execute: | fi cp "$UEFI_VARS" /tmp/uefi_vars.fd - timeout 180 $QEMU_BIN \ + $QEMU_BIN \ $QEMU_ARGS \ -accel kvm -accel tcg,thread=multi \ -smp "$(nproc)" \ @@ -41,7 +41,7 @@ execute: | -m 1G \ -drive if=pflash,format=raw,readonly=on,file=$UEFI_CODE \ -drive if=pflash,format=raw,file=/tmp/uefi_vars.fd \ - -drive file=pc.img,format=raw,index=0,if=ide 2>&1 | tee output.log || true + -drive file=pc.img,format=raw,index=0,if=virtio,cache=unsafe 2>&1 | tee output.log || true MATCH "HELLO FROM IMAGECRAFT" output.log From 8d09ed5e96a45d0091a0220b3a7113fcb9ff39ba Mon Sep 17 00:00:00 2001 From: "Alex M. Lowe" Date: Thu, 23 Jul 2026 20:42:43 -0400 Subject: [PATCH 03/14] fix(pack): use configfile in UEFI grub stub to chainload rootfs grub.cfg --- imagecraft/pack/grubutil.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imagecraft/pack/grubutil.py b/imagecraft/pack/grubutil.py index aa2b7fd6..03f732f9 100644 --- a/imagecraft/pack/grubutil.py +++ b/imagecraft/pack/grubutil.py @@ -169,7 +169,7 @@ def _populate_uefi_fallback(grub_target: str) -> None: [ f"search.fs_uuid {root_uuid} root", "set prefix=($root)'/boot/grub'", - "normal", + "configfile $prefix/grub.cfg", ] ) boot_cfg.write_text(stub + "\n", encoding="utf-8") From dc9d36a018f45becfed6543a6d48d3503d52ad93 Mon Sep 17 00:00:00 2001 From: "Alex M. Lowe" Date: Thu, 23 Jul 2026 21:10:44 -0400 Subject: [PATCH 04/14] fix(pack): robustly extract UUID using regex for grub config stub --- imagecraft/pack/grubutil.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/imagecraft/pack/grubutil.py b/imagecraft/pack/grubutil.py index 03f732f9..322363a7 100644 --- a/imagecraft/pack/grubutil.py +++ b/imagecraft/pack/grubutil.py @@ -14,6 +14,7 @@ """GRUB utils.""" +import re import shutil import subprocess from pathlib import Path @@ -33,6 +34,10 @@ from imagecraft.pack.image import Image from imagecraft.subprocesses import run +_UUID_REGEX = re.compile( + r"[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}" +) + _ARCH_TO_GRUB_EFI_TARGET: dict[str, str] = { DebianArchitecture.AMD64: "x86_64-efi", DebianArchitecture.ARM64: "arm64-efi", @@ -131,12 +136,11 @@ def _grub_install(grub_target: str, loop_dev: str) -> None: def _extract_root_uuid(grub_cfg_src: Path) -> str: - """Extract rootfs UUID from a search.fs_uuid line in a GRUB config file.""" - for line in grub_cfg_src.read_text(encoding="utf-8").splitlines(): - if line.startswith("search.fs_uuid "): - parts = line.split() - if len(parts) > 1: - return parts[1] + """Extract rootfs UUID from a GRUB config file.""" + text = grub_cfg_src.read_text(encoding="utf-8") + match = _UUID_REGEX.search(text) + if match: + return match.group(0) return "" From 13cd60f078db323aac5143510061a518fe3ed85d Mon Sep 17 00:00:00 2001 From: "Alex M. Lowe" Date: Thu, 23 Jul 2026 21:23:34 -0400 Subject: [PATCH 05/14] fix(pack): copy GRUB EFI modules to EFI partition and insmod part_gpt and ext2 in EFI stub --- imagecraft/pack/grubutil.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/imagecraft/pack/grubutil.py b/imagecraft/pack/grubutil.py index 322363a7..23087a04 100644 --- a/imagecraft/pack/grubutil.py +++ b/imagecraft/pack/grubutil.py @@ -165,12 +165,23 @@ def _populate_uefi_fallback(grub_target: str) -> None: boot_grub.parent.mkdir(parents=True, exist_ok=True) shutil.copy2(grub_src, boot_grub) + + # Copy modules to EFI partition so GRUB can load ext2/part_gpt drivers + modules_src = Path("/boot/grub") / grub_target + if modules_src.exists(): + boot_modules = efi_dir / "BOOT" / grub_target + ubuntu_modules = efi_dir / "ubuntu" / grub_target + if not boot_modules.exists(): + shutil.copytree(modules_src, boot_modules, dirs_exist_ok=True) + if not ubuntu_modules.exists(): + shutil.copytree(modules_src, ubuntu_modules, dirs_exist_ok=True) + root_uuid = _extract_root_uuid(grub_cfg_src) if root_uuid: - # In this path grub may start in command mode; `normal` enters - # menu mode and evaluates /boot/grub/grub.cfg from the rootfs. stub = "\n".join( [ + "insmod part_gpt", + "insmod ext2", f"search.fs_uuid {root_uuid} root", "set prefix=($root)'/boot/grub'", "configfile $prefix/grub.cfg", From a5d63cad386a3257a16eb547f0519a3c63577fa1 Mon Sep 17 00:00:00 2001 From: "Alex M. Lowe" Date: Thu, 23 Jul 2026 21:37:43 -0400 Subject: [PATCH 06/14] fix(test): wrap QEMU in script PTY to provide TTY interface for GRUB EFI --- tests/spread/boot/classic/task.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/spread/boot/classic/task.yaml b/tests/spread/boot/classic/task.yaml index 8f4530a5..3c72e16c 100644 --- a/tests/spread/boot/classic/task.yaml +++ b/tests/spread/boot/classic/task.yaml @@ -33,15 +33,15 @@ execute: | fi cp "$UEFI_VARS" /tmp/uefi_vars.fd - $QEMU_BIN \ + script -q -c "$QEMU_BIN \ $QEMU_ARGS \ -accel kvm -accel tcg,thread=multi \ - -smp "$(nproc)" \ + -smp \"\$(nproc)\" \ -nographic \ -m 1G \ -drive if=pflash,format=raw,readonly=on,file=$UEFI_CODE \ -drive if=pflash,format=raw,file=/tmp/uefi_vars.fd \ - -drive file=pc.img,format=raw,index=0,if=virtio,cache=unsafe 2>&1 | tee output.log || true + -drive file=pc.img,format=raw,index=0,if=virtio,cache=unsafe" output.log || true MATCH "HELLO FROM IMAGECRAFT" output.log From a60723ff5024c8941971a8f1c87f04370c53786b Mon Sep 17 00:00:00 2001 From: "Alex M. Lowe" Date: Thu, 23 Jul 2026 21:54:37 -0400 Subject: [PATCH 07/14] fix(test): set GRUB_TIMEOUT=0 to immediately boot without waiting for serial keypress --- tests/spread/boot/classic/imagecraft.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/spread/boot/classic/imagecraft.yaml b/tests/spread/boot/classic/imagecraft.yaml index c328f56c..3c0afe4c 100644 --- a/tests/spread/boot/classic/imagecraft.yaml +++ b/tests/spread/boot/classic/imagecraft.yaml @@ -67,9 +67,9 @@ parts: after: [rootfs] override-overlay: | cat << 'EOF' > /etc/default/grub - GRUB_TIMEOUT=1 - GRUB_RECORDFAIL_TIMEOUT=1 - GRUB_TIMEOUT_STYLE=menu + GRUB_TIMEOUT=0 + GRUB_RECORDFAIL_TIMEOUT=0 + GRUB_TIMEOUT_STYLE=hidden GRUB_TERMINAL="console serial" GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1" GRUB_CMDLINE_LINUX_DEFAULT="" From 0c879c93e5e43553e81bb80f6201edbfb0a65286 Mon Sep 17 00:00:00 2001 From: "Alex M. Lowe" Date: Mon, 10 Aug 2026 12:12:41 -0400 Subject: [PATCH 08/14] Fix GRUB utility issues and update documentation --- .agents/rules/core-directive.instructions.md | 1 + .../rules/documentation-rtd.instructions.md | 1 + .agents/rules/documentation.instructions.md | 1 + .agents/rules/instructions.instructions.md | 1 + .../python-code-commenting.instructions.md | 1 + .../rules/starcraft-docs-meta.instructions.md | 1 + .../starcraft-docs-style.instructions.md | 1 + .agents/skills/documentation-build | 1 + .agents/skills/documentation-diataxis | 1 + .agents/skills/documentation-review | 1 + .agents/skills/documentation-structure | 1 + .agents/skills/documentation-style | 1 + .agents/skills/documentation-verify | 1 + .kdev4/imagecraft.kdev4 | 2 + .workshop/dev.yaml | 48 ++ .workshop/imagecraft-setup/hooks/check-health | 20 + .workshop/imagecraft-setup/hooks/setup-base | 7 + .../imagecraft-setup/hooks/setup-project | 8 + .workshop/imagecraft-setup/sdk.yaml | 1 + TODO.md | 172 ++++++ contributors.html | 566 ++++++++++++++++++ docs/release-notes/imagecraft-0-2-0.rst | 120 ++++ imagecraft.kdev4 | 4 + imagecraft/pack/grubutil.py | 14 +- tests/unit/pack/test_grubutil.py | 42 +- 25 files changed, 1011 insertions(+), 6 deletions(-) create mode 120000 .agents/rules/core-directive.instructions.md create mode 120000 .agents/rules/documentation-rtd.instructions.md create mode 120000 .agents/rules/documentation.instructions.md create mode 120000 .agents/rules/instructions.instructions.md create mode 120000 .agents/rules/python-code-commenting.instructions.md create mode 120000 .agents/rules/starcraft-docs-meta.instructions.md create mode 120000 .agents/rules/starcraft-docs-style.instructions.md create mode 120000 .agents/skills/documentation-build create mode 120000 .agents/skills/documentation-diataxis create mode 120000 .agents/skills/documentation-review create mode 120000 .agents/skills/documentation-structure create mode 120000 .agents/skills/documentation-style create mode 120000 .agents/skills/documentation-verify create mode 100644 .kdev4/imagecraft.kdev4 create mode 100644 .workshop/dev.yaml create mode 100755 .workshop/imagecraft-setup/hooks/check-health create mode 100755 .workshop/imagecraft-setup/hooks/setup-base create mode 100755 .workshop/imagecraft-setup/hooks/setup-project create mode 100644 .workshop/imagecraft-setup/sdk.yaml create mode 100644 TODO.md create mode 100644 contributors.html create mode 100644 docs/release-notes/imagecraft-0-2-0.rst create mode 100644 imagecraft.kdev4 diff --git a/.agents/rules/core-directive.instructions.md b/.agents/rules/core-directive.instructions.md new file mode 120000 index 00000000..d9a21c7e --- /dev/null +++ b/.agents/rules/core-directive.instructions.md @@ -0,0 +1 @@ +/home/lengau/Work/Code/imagecraft/.github/instructions/core-directive.instructions.md \ No newline at end of file diff --git a/.agents/rules/documentation-rtd.instructions.md b/.agents/rules/documentation-rtd.instructions.md new file mode 120000 index 00000000..7633c7b9 --- /dev/null +++ b/.agents/rules/documentation-rtd.instructions.md @@ -0,0 +1 @@ +/home/lengau/Work/Code/imagecraft/.github/instructions/documentation-rtd.instructions.md \ No newline at end of file diff --git a/.agents/rules/documentation.instructions.md b/.agents/rules/documentation.instructions.md new file mode 120000 index 00000000..d98fe64c --- /dev/null +++ b/.agents/rules/documentation.instructions.md @@ -0,0 +1 @@ +/home/lengau/Work/Code/imagecraft/.github/instructions/documentation.instructions.md \ No newline at end of file diff --git a/.agents/rules/instructions.instructions.md b/.agents/rules/instructions.instructions.md new file mode 120000 index 00000000..bb84cb59 --- /dev/null +++ b/.agents/rules/instructions.instructions.md @@ -0,0 +1 @@ +/home/lengau/Work/Code/imagecraft/.github/instructions/instructions.instructions.md \ No newline at end of file diff --git a/.agents/rules/python-code-commenting.instructions.md b/.agents/rules/python-code-commenting.instructions.md new file mode 120000 index 00000000..214bc0bb --- /dev/null +++ b/.agents/rules/python-code-commenting.instructions.md @@ -0,0 +1 @@ +/home/lengau/Work/Code/imagecraft/.github/instructions/python-code-commenting.instructions.md \ No newline at end of file diff --git a/.agents/rules/starcraft-docs-meta.instructions.md b/.agents/rules/starcraft-docs-meta.instructions.md new file mode 120000 index 00000000..46172e41 --- /dev/null +++ b/.agents/rules/starcraft-docs-meta.instructions.md @@ -0,0 +1 @@ +/home/lengau/Work/Code/imagecraft/.github/instructions/starcraft-docs-meta.instructions.md \ No newline at end of file diff --git a/.agents/rules/starcraft-docs-style.instructions.md b/.agents/rules/starcraft-docs-style.instructions.md new file mode 120000 index 00000000..1bccb3e3 --- /dev/null +++ b/.agents/rules/starcraft-docs-style.instructions.md @@ -0,0 +1 @@ +/home/lengau/Work/Code/imagecraft/.github/instructions/starcraft-docs-style.instructions.md \ No newline at end of file diff --git a/.agents/skills/documentation-build b/.agents/skills/documentation-build new file mode 120000 index 00000000..6647c542 --- /dev/null +++ b/.agents/skills/documentation-build @@ -0,0 +1 @@ +/home/lengau/Work/Code/imagecraft/.github/skills/documentation-build \ No newline at end of file diff --git a/.agents/skills/documentation-diataxis b/.agents/skills/documentation-diataxis new file mode 120000 index 00000000..996d46d6 --- /dev/null +++ b/.agents/skills/documentation-diataxis @@ -0,0 +1 @@ +/home/lengau/Work/Code/imagecraft/.github/skills/documentation-diataxis \ No newline at end of file diff --git a/.agents/skills/documentation-review b/.agents/skills/documentation-review new file mode 120000 index 00000000..c6b9fa61 --- /dev/null +++ b/.agents/skills/documentation-review @@ -0,0 +1 @@ +/home/lengau/Work/Code/imagecraft/.github/skills/documentation-review \ No newline at end of file diff --git a/.agents/skills/documentation-structure b/.agents/skills/documentation-structure new file mode 120000 index 00000000..145f2e8b --- /dev/null +++ b/.agents/skills/documentation-structure @@ -0,0 +1 @@ +/home/lengau/Work/Code/imagecraft/.github/skills/documentation-structure \ No newline at end of file diff --git a/.agents/skills/documentation-style b/.agents/skills/documentation-style new file mode 120000 index 00000000..6373ad45 --- /dev/null +++ b/.agents/skills/documentation-style @@ -0,0 +1 @@ +/home/lengau/Work/Code/imagecraft/.github/skills/documentation-style \ No newline at end of file diff --git a/.agents/skills/documentation-verify b/.agents/skills/documentation-verify new file mode 120000 index 00000000..5e5e1e06 --- /dev/null +++ b/.agents/skills/documentation-verify @@ -0,0 +1 @@ +/home/lengau/Work/Code/imagecraft/.github/skills/documentation-verify \ No newline at end of file diff --git a/.kdev4/imagecraft.kdev4 b/.kdev4/imagecraft.kdev4 new file mode 100644 index 00000000..2ffd5cd5 --- /dev/null +++ b/.kdev4/imagecraft.kdev4 @@ -0,0 +1,2 @@ +[Project] +VersionControlSupport=kdevgit diff --git a/.workshop/dev.yaml b/.workshop/dev.yaml new file mode 100644 index 00000000..0f3f534e --- /dev/null +++ b/.workshop/dev.yaml @@ -0,0 +1,48 @@ +name: dev +base: ubuntu@24.04 +sdks: + - name: uv + - name: copilot + - name: node + channel: 24/stable + - name: rust + - name: project-imagecraft-setup +actions: + setup: make setup + test: make test + test-fast: make test-fast + test-slow: make test-slow + lint: make lint + format: make format + pack: make pack + pack-snap: make pack-snap + install-craft-stack-branch: | + if [ "$#" -gt 1 ]; then + echo 'usage: workshop run dev -- install-craft-stack-branch [branch]' + exit 2 + fi + branch="${1:-main}" + for package in craft-application craft-parts craft-providers; do + uv pip install --python .venv/bin/python --upgrade "$package @ git+https://github.com/canonical/$package.git@$branch" + done + install-craft-application-branch: | + if [ "$#" -gt 1 ]; then + echo 'usage: workshop run dev -- install-craft-application-branch [branch]' + exit 2 + fi + branch="${1:-main}" + uv pip install --python .venv/bin/python --upgrade "craft-application @ git+https://github.com/canonical/craft-application.git@$branch" + install-craft-parts-branch: | + if [ "$#" -gt 1 ]; then + echo 'usage: workshop run dev -- install-craft-parts-branch [branch]' + exit 2 + fi + branch="${1:-main}" + uv pip install --python .venv/bin/python --upgrade "craft-parts @ git+https://github.com/canonical/craft-parts.git@$branch" + install-craft-providers-branch: | + if [ "$#" -gt 1 ]; then + echo 'usage: workshop run dev -- install-craft-providers-branch [branch]' + exit 2 + fi + branch="${1:-main}" + uv pip install --python .venv/bin/python --upgrade "craft-providers @ git+https://github.com/canonical/craft-providers.git@$branch" diff --git a/.workshop/imagecraft-setup/hooks/check-health b/.workshop/imagecraft-setup/hooks/check-health new file mode 100755 index 00000000..3056c00a --- /dev/null +++ b/.workshop/imagecraft-setup/hooks/check-health @@ -0,0 +1,20 @@ +#!/usr/bin/env bash +set -euo pipefail + +missing=() +for tool in uv ruff codespell shellcheck ty; do + if ! command -v "$tool" >/dev/null 2>&1; then + missing+=("$tool") + fi +done + +if [ ! -x /project/.venv/bin/python ]; then + missing+=(".venv/bin/python") +fi + +if [ "${#missing[@]}" -gt 0 ]; then + workshopctl set-health error "missing setup tools: ${missing[*]}" + exit 1 +fi + +workshopctl set-health okay diff --git a/.workshop/imagecraft-setup/hooks/setup-base b/.workshop/imagecraft-setup/hooks/setup-base new file mode 100755 index 00000000..187d4c34 --- /dev/null +++ b/.workshop/imagecraft-setup/hooks/setup-base @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -euo pipefail + +if ! command -v shellcheck >/dev/null 2>&1; then + apt-get update + DEBIAN_FRONTEND=noninteractive apt-get install -y shellcheck +fi diff --git a/.workshop/imagecraft-setup/hooks/setup-project b/.workshop/imagecraft-setup/hooks/setup-project new file mode 100755 index 00000000..f35d504f --- /dev/null +++ b/.workshop/imagecraft-setup/hooks/setup-project @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail + +cd /project +make setup +uv tool install --force ruff +uv tool install --force codespell +uv tool install --force ty diff --git a/.workshop/imagecraft-setup/sdk.yaml b/.workshop/imagecraft-setup/sdk.yaml new file mode 100644 index 00000000..623eacd3 --- /dev/null +++ b/.workshop/imagecraft-setup/sdk.yaml @@ -0,0 +1 @@ +name: imagecraft-setup diff --git a/TODO.md b/TODO.md new file mode 100644 index 00000000..fe452c86 --- /dev/null +++ b/TODO.md @@ -0,0 +1,172 @@ +# TODO: Replicating `grub-install` using `grub-mkimage` & Manual GRUB Deployment (EFI Devices) + +This document outlines all technical steps, module dependencies, file operations, and platform-specific logic required to replace high-level `grub-install` invocations in `imagecraft` with `grub-mkimage` and direct file/sector installation for **Ubuntu** image builds on **EFI-capable devices** across supported architectures (`amd64`, `arm64`, `armhf`, and `riscv64`). + +--- + +## 1. Overview & Context + +Currently, `imagecraft` invokes `grub-install` inside a chroot environment (see [`imagecraft/pack/grubutil.py`](file:///home/lengau/Work/Code/imagecraft/imagecraft/pack/grubutil.py#L45-L118)). + +Replacing `grub-install` with `grub-mkimage` and direct asset deployment tailored for EFI devices offers several advantages: + +- Bypasses the need for full chroot mount setups (`/dev`, `/proc`, `/sys`, `/run`). +- Enables cross-architecture bootloader generation directly on the host. +- Provides fine-grained control over embedded modules and configuration stubs. + +--- + +## 2. Shared / Prerequisites Stage: GRUB Asset Deployment + +Before generating boot executables or embedding core images, GRUB runtime assets must be placed on the target root/boot filesystem. + +- [ ] **Create Directory Structure** + - Path: `/boot/grub//` + - `amd64` $\rightarrow$ `/boot/grub/x86_64-efi/` (or `/boot/grub/i386-pc/` for BIOS fallback) + - `arm64` $\rightarrow$ `/boot/grub/arm64-efi/` + - `armhf` $\rightarrow$ `/boot/grub/arm-efi/` + - `riscv64` $\rightarrow$ `/boot/grub/riscv64-efi/` + - Path: `/boot/grub/fonts/` + - Path: `/boot/grub/locale/` + +- [ ] **Copy GRUB Modules (`*.mod`)** + - Source: `/usr/lib/grub//*.mod` + - Destination: `/boot/grub//` + - Purpose: Dynamic module loading during system boot. + +- [ ] **Copy GRUB Metadata & Lookup Lists (`*.lst`)** + - Source files: + - `moddep.lst` (Module dependency map) + - `fs.lst` (Supported filesystems list) + - `partmap.lst` (Supported partition schemes list) + - `parttool.lst`, `command.lst`, `terminal.lst`, `crypto.lst`, `video.lst` + - Destination: `/boot/grub//` + +- [ ] **Copy Fonts & Locales** + - Copy font file (`unicode.pf2`) from `/usr/share/grub/` to `/boot/grub/fonts/`. + - Copy translation catalogs (`*.mo`) from `/usr/share/locale/*/LC_MESSAGES/grub.mo` to `/boot/grub/locale//`. + +--- + +## 3. Ubuntu UEFI Deployment Tasks (`amd64`, `arm64`, `armhf`, `riscv64`) + +In Ubuntu, the vendor boot directory on the EFI System Partition (ESP) is fixed to `/boot/efi/EFI/ubuntu/`. + +### 3.1 Unsigned / Standard UEFI (via `grub-mkimage`) + +- [ ] **Build Standalone EFI Binary with `grub-mkimage`** + - **amd64 (`x86_64-efi`)**: + ```bash + grub-mkimage \ + -d /usr/lib/grub/x86_64-efi \ + -o /tmp/grubx64.efi \ + -O x86_64-efi \ + -p /boot/grub \ + part_gpt part_msdos fat ext2 btrfs xfs normal search search_fs_uuid search_label search_fs_file boot linux configfile echo loadenv test efi_gop gfxterm font + ``` + - **arm64 (`arm64-efi`)**: + ```bash + grub-mkimage \ + -d /usr/lib/grub/arm64-efi \ + -o /tmp/grubaa64.efi \ + -O arm64-efi \ + -p /boot/grub \ + part_gpt part_msdos fat ext2 btrfs xfs normal search search_fs_uuid search_label search_fs_file boot linux configfile echo loadenv test efi_gop gfxterm font devicetree acpi + ``` + - **armhf (`arm-efi`)**: + ```bash + grub-mkimage \ + -d /usr/lib/grub/arm-efi \ + -o /tmp/grubarm.efi \ + -O arm-efi \ + -p /boot/grub \ + part_gpt part_msdos fat ext2 btrfs xfs normal search search_fs_uuid search_label search_fs_file boot linux configfile echo loadenv test efi_gop gfxterm font devicetree + ``` + - **riscv64 (`riscv64-efi`)**: + ```bash + grub-mkimage \ + -d /usr/lib/grub/riscv64-efi \ + -o /tmp/grubriscv64.efi \ + -O riscv64-efi \ + -p /boot/grub \ + part_gpt part_msdos fat ext2 btrfs xfs normal search search_fs_uuid search_label search_fs_file boot linux configfile echo loadenv test efi_gop gfxterm font devicetree + ``` + +- [ ] **Deploy EFI Binary to EFI System Partition (ESP)** + - **amd64 Target Paths**: + - Vendor path: `/boot/efi/EFI/ubuntu/grubx64.efi` + - Fallback / Removable path: `/boot/efi/EFI/BOOT/BOOTX64.EFI` + - **arm64 Target Paths**: + - Vendor path: `/boot/efi/EFI/ubuntu/grubaa64.efi` + - Fallback / Removable path: `/boot/efi/EFI/BOOT/BOOTAA64.EFI` + - **armhf Target Paths**: + - Vendor path: `/boot/efi/EFI/ubuntu/grubarm.efi` + - Fallback / Removable path: `/boot/efi/EFI/BOOT/BOOTARM.EFI` + - **riscv64 Target Paths**: + - Vendor path: `/boot/efi/EFI/ubuntu/grubriscv64.efi` + - Fallback / Removable path: `/boot/efi/EFI/BOOT/BOOTRISCV64.EFI` + +--- + +### 3.2 Secure Boot UEFI (Pre-Signed Canonical Shim + Signed GRUB) + +- [ ] **Copy Pre-Signed Binaries from Ubuntu Packages** + - Do **not** use `grub-mkimage` (custom-built binaries will fail Secure Boot signature verification). + - **amd64 Signed Binaries** (from `shim-signed` & `grub-efi-amd64-signed`): + - Source: `/usr/lib/shim/shimx64.efi.signed` $\rightarrow$ `/boot/efi/EFI/ubuntu/shimx64.efi` (and `/boot/efi/EFI/BOOT/BOOTX64.EFI`) + - Source: `/usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed` $\rightarrow$ `/boot/efi/EFI/ubuntu/grubx64.efi` + - Support files: `/usr/lib/shim/mmx64.efi` & `/usr/lib/shim/fbx64.efi` $\rightarrow$ `/boot/efi/EFI/ubuntu/` + - **arm64 Signed Binaries** (from `shim-signed` & `grub-efi-arm64-signed`): + - Source: `/usr/lib/shim/shimaa64.efi.signed` $\rightarrow$ `/boot/efi/EFI/ubuntu/shimaa64.efi` (and `/boot/efi/EFI/BOOT/BOOTAA64.EFI`) + - Source: `/usr/lib/grub/arm64-efi-signed/grubaa64.efi.signed` $\rightarrow$ `/boot/efi/EFI/ubuntu/grubaa64.efi` + - Support files: `/usr/lib/shim/mmaa64.efi` & `/usr/lib/shim/fbaa64.efi` $\rightarrow$ `/boot/efi/EFI/ubuntu/` + - **armhf and riscv64**: + - _N/A_: Secure Boot is **not supported** for `armhf` or `riscv64` in Ubuntu. Builds always use unsigned binaries generated via `grub-mkimage`. + +- [ ] **Generate Ubuntu ESP Early Load Stub (`/boot/efi/EFI/ubuntu/grub.cfg`)** + - Place Ubuntu's standard 3-line loader config on the ESP alongside the GRUB binary: + ```grub + search.fs_uuid root hd0,gpt2 + set prefix=($root)'/boot/grub' + configfile $prefix/grub.cfg + ``` + +--- + +## 4. Legacy BIOS / MBR (`i386-pc`) Deployment Tasks (amd64 Legacy Devices) + +- [ ] **Build `core.img` via `grub-mkimage`** + - Command template: + ```bash + grub-mkimage \ + -d /usr/lib/grub/i386-pc \ + -o /boot/grub/i386-pc/core.img \ + -O i386-pc \ + -p /boot/grub \ + biosdisk part_msdos part_gpt ext2 fat normal search search_fs_uuid boot linux configfile + ``` + +- [ ] **Copy Stage 1 Boot Sector (`boot.img`)** + - Source: `/usr/lib/grub/i386-pc/boot.img` + - Destination: `/boot/grub/i386-pc/boot.img` + +- [ ] **Install Boot Sector & Sector-Patch `core.img` using `grub-bios-setup`** + - Execute `grub-bios-setup` directly against the loop device without chroot: + ```bash + grub-bios-setup \ + --directory=/mountpoint/boot/grub/i386-pc \ + --device-map=/tmp/device.map \ + /dev/loopX + ``` + - _Note_: Ensure the loop device is attached with partition scanning enabled (`losetup -P`). + +--- + +## 5. Configuration & Cleanup Tasks + +- [ ] **Generate Main Config (`/boot/grub/grub.cfg`)** + - Run `update-grub` / `grub-mkconfig` or generate Ubuntu's standard `grub.cfg` template with kernel command-line arguments and initrd options. + +- [ ] **Refactor `imagecraft/pack/grubutil.py`** + - Remove chroot dependency for GRUB installation on EFI targets. + - Implement architecture dispatcher routing `amd64` (`x86_64-efi`), `arm64` (`arm64-efi`), `armhf` (`arm-efi`), and `riscv64` (`riscv64-efi`) to their respective EFI bootloader binary generation and asset deployment strategies. diff --git a/contributors.html b/contributors.html new file mode 100644 index 00000000..fb87c6f3 --- /dev/null +++ b/contributors.html @@ -0,0 +1,566 @@ + + + + + +Commits, Changes, and Contributors + + + + + +

Commits, Changes, and Contributors

+

Summary

+ + + + + + + + + + + + + + + + + +
projectoldnew
imagecraft0.1.0c5b8dda
craft-application6.1.17.1.0
craft-archives2.2.02.2.0
craft-cli3.2.03.2.0
craft-grammar2.3.02.3.0
craft-parts2.28.02.35.0
craft-platforms0.10.00.10.0
craft-providers3.2.03.7.1
+

imagecraft (0.1.0 → c5b8dda)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
checkheaderPRauthorhash
build(docs): incorporate the latest Sphinx Starter Pack (#275)#275jahn-junior097e5f5
chore: reorder init template (#277)#277jahn-junior0b401fc
style: migrate from overrides library to typing.override (#273)#273Spilsed69e47e0
style: migrate from overrides library to typing.override (#273)#273Spilsed1ffde99
style: migrate from overrides library to typing.override (#273)#273Spilsedefa5479
chore: remove comment fences from GitHub templates (#281)#281medubelko2b37857
docs: add '(overlay)' to the `organize` key description (#278)#278jahn-junior8b961f1
docs: add 'Build an Ubuntu image' tutorial (#287)#287jahn-junior77e1c35
docs: resolve spellcheck errors (#290)#290jahn-junior3f56e9b
ci: fix failing tests (#291)#291smethnani6357854
docs: fix fstab part snippet (#294)#294jahn-juniorbdacaeb
docs: reorder 'imagecraft.yaml' reference (#293)#293jahn-junior314f01d
docs: fix bad link (#296)#296bepriaaf3bb9
docs: remove bounty instructions (#295)#295beprif605cf0
fix(ci): add cargo/rustc symlinks (#297)#297smethnani1f01eb5
feat(volumes): add some more GPT types (#286)#286lengau1547a40
feat: add mmdebstrap plugin (#289)#289smethnani92f26fe
feat: enable override-overlay (#299)#299smethnani6d283be
build(deps): constrain setuptools-scm due to cyclic dependency (#306)#306lengaufca3ff4
build: update requests to 2.33.0 (#308)#308smethnanicbca1c1
test(spread): switch to testing in destructive mode (#302)#302lengauf6aae5e
ci: pack snap using craft-actions (#307)#307lengau3f26a09
build(deps): resolve osvs (#313)#313smethnani10f3370
feat: enable writing to specific sectors of the image (#301)#301lengau9bb5d8a
build: bump cryptography to 46.0.7 (#318)#318smethnani8a390e6
docs: mmdebstrap plugin (#315)#315smethnani8ec3481
build(deps): unpin setuptools-scm (#309)#309beprib1e78bf
docs: add home page content (#317)#317jahn-junior178f32e
build(deps): bump pytest (#321)#321smethnanie1b9241
chore: add doc meta description to pr checklist (#319)#319medubelko8c361be
build(deps): update lxml (#331)#331smethnanieae7ded
ci: initial sync with canonical/copilot-collections (#327)#327mr-cal82bd946
chore: change type checking to use `ty` (#328)#328lengaufc21f39
feat: support 26.04 as a build-base (#322)#322bepribe019b2
feat: snap prepare-image plugins (#320)#320smethnani97670aa
feat(Project): add MBR and hybrid volume schemas (#329)#329lengau805f640
fix(lint): suppress ty (#335)#335smethnanic270f0a
fix(snap-prepare): make keys optional (#332)#332smethnani4fd1b56
docs: update home and landing pages (#339)#339jahn-junior8c865f0
build(deps): use a newer pygit2 on Python 3.14 (#336)#336lengau8f9833b
feat(Lifecycle)!: use craft-application's new plugin groups (#326)#326lengaufc8182b
feat: add support for MBR images (#338)#338lengau47fd939
docs: add uc-prepare plugin (#334)#334smethnanid352f96
fix: clear ty diagnostics for partition-number helpers (#341)#341mwhudson96c4d21
build(deps): bump urllib3 (#344)#344smethnani033c84e
docs: add snap-preseed plugin (#333)#333smethnani7c0a27a
build(deps): bump idna (#346)#346smethnani4bf75c9
feat(plugins): use @ channel separator (#345)#345smethnani3dfacf0
build(deps): bump starlette (#350)#350smethnani920399b
ci: add conditionals for docs-only checks (#352)#352medubelko0104193
fix(mmdebstrap_plugin): unmount lingering mounts (#351)#351smethnanid19c950
docs: incorporate tutorial feedback (#354)#354jahn-junior699cc9e
test: add overlay plugin integration test (#349)#349smethnani494e370
chore: fix indentation in init template (#353)#353jahn-juniord13f4f1
docs: how-to add package repositories (#355)#355smethnani21e65f4
build(deps): bump cryptography and starlette (#357)#357smethnania868324
ci: add code owners (#358)#358mr-cal1a4a25f
ci: add qemu spread suite (#356)#356smethnanibcb343c
docs: describe MBR and hybrid schemas (#359)#359lengau04f04c6
chore: fix linting (#369)#369smethnani5363d6d
docs: add 'Configure instances with cloud-init' (#367)#367jahn-junior9d46133
docs: fix project file for tutorial (#360)#360jahn-junior5f531a4
ci: use openstack for spread (#368)#368smethnani778d8dd
ci: add conditional to snap-builds job steps (#370)#370medubelkoa73afd4
docs: add 'Pre-install snaps' guide (#374)#374jahn-junior297872a
docs: configure for ubuntu.com proxy (#376)#376jahn-junior402d0b8
test: add core boot spread test (#375)#375smethnanic5b8dda
+

craft-application (6.1.1 → 7.1.0)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
checkheaderPRauthorhash
feat: add Ubuntu Pro argument and validation (#438)#438clay-lake825adcc
feat: enable requested ubuntu pro services (#504)#504clay-lakecae9272
fix(pro): fix _check_pro_requirement function to not ignore empty ProServices set (#563)#563clay-lake238304b
Merge branch 'main' into chore/merge-main-with-pro-sourcesn/aunknowneb5755c
fix lint errorsn/aunknown2768bb5
Merge pull request #582 from linostar/chore/merge-main-with-pro-sourcesn/abepri559ec1e
feat: more updates to support Pro Rocks in Rockcraft (#616)#616clay-lakee921232
feat: ensure pro validation does not run on devel basesn/aclay-lake0e804b8
feat: more descriptive text for InvalidUbuntuProBaseErrorn/aclay-laked65d652
fix: move project pro validation to project get methodn/aclay-lake9f98320
fix: remove base used for testing invalid pro basesn/aclay-lake8b853e9
refactor: minor changes for lintingn/aclay-lakea4ace66
docs: fix typo (#992)#992steinbro71490ec
feat(Provider): inject the base snap (#997)#997lengau41cee32
build(deps): bump craft-providers to 3.3.0n/amr-cal9eb4605
test: remove 24.10n/amr-calad9823b
fix(LifecycleService): pull local test files (#1013)#1013mr-calf4a4d28
docs: reference document for the Build Plan Service (#999)#999lengauebbd599
fix(Application): set the plugin group on load (#998)#998lengaub1d70a5
docs: add platform naming snippet (#1012)#1012lengau0ab97a3
docs: add reference document for the ConfigService (#1000)#1000lengau7f1efa4
docs: Reference document for the PackageService (#1002)#1002lengaufc91d41
docs: add 6.2.1 changelog (#1019)#1019lengauaaa9777
docs: Reference document for the Service Factory (#1001)#1001lengaufb2a80b
feat(services/linter): add a linter service (#907)#907HamdaanAliQuatila76bcaa
fix(docs): Unicode has a capital U (#1023)#1023lengau421a445
chore: merge branch 'main' into hotfix-merge/6.2.2n/alengau6005c8d
chore(merge): main into merge/mainn/amr-caleb8ad11
chore(merge): main into feature/pro-sources (#1031)#1031lengau39ed82a
fix(testing): error early if spread.yaml is invalid. (#1029)#1029lengau93c27ec
Merge branch 'main' into hotfix-merge/6.2.2n/alengaua869a9f
chore: merge 6.2.2 into main (#1026)#1026lengaua98e1c3
ci: temporarily disable external fetch service spread test (#1036)#1036lengau790ecaf
ci: run Python tests on arm64 (#1030)#1030lengau944c358
feat: allow building on other compatible architectures (#1027)#1027lengau15f4828
docs: remove bounty instructions (#1043)#1043bepria710d01
feat(ProviderService): don't inject snaps if the host and guest architectures differ (#1037)#1037lengau16bd7ac
chore: finalize Pro support (#1047)#1047mr-cal0455be5
chore: make Pro support opt-in (#1048)#1048mr-calbe206d1
chore(merge): feature/pro-sources into merge/pro-sourcesn/amr-cala66d92b
chore(merge): feature/pro-sources into main (#1050)#1050lengau8c1a7ae
docs(changelog): create changelog for 6.3.0 (#1046)#1046lengau01e7574
fix(deps): Make osv-scanner be quiet. (#1051)#1051lengaufe828e0
build(deps): bump cryptography (#1055)#1055bepridf46c84
fix(pro): fewer errors when checking pro context (#1054)#1054beprib78daa6
build(deps): bump cryptography (#1061)#1061bepri4b0e00a
feat(ProjectService): ban `/` in user-provided part names (#1067)#1067lengau3857782
feat: add a mechanism to add fetch-service secrets (#1066)#1066tigarmof9b01b4
docs: fix changelog entry for 6.4.0 (#1069)#1069mr-cal7b5be5b
build(deps): bump lxml (#1072)#1072smethnanie8c8a38
build(docs)!: add dependency starter pack 1.5 (#1070)#1070medubelko691eec7
fix: handle `--debug` for post-prime failures (#1073)#1073steinbro38fdb68
build(deps): bump idna, urllib3 (#1076)#1076mr-cal80a5847
chore!: remove managed commands (#1077)#1077mr-cale00540d
chore!: remove deprecated APIs (#1078)#1078mr-cal3334f13
docs: fix terminal directive (#1079)#1079jahn-junior28df6ac
fix(application): preserve non-successful return codes (#1068)#1068gcomneno58e0440
feat: expose pro_client_exists and get_pro_services as public methods (#1083)#1083smethnania742213
build: update lockfile (#1085)#1085mr-cal2a6a732
style: replace mypy and pyright with ty (#1084)#1084mr-cal345bd5d
docs: finalize 7.0 changelog (#1087)#1087mr-cale429672
ci: separate flaky tests into their own run (#1088)#1088lengau6d755f0
ci: silence the fast flaky tests (#1090)#1090lengau51736da
ci: update CODEOWNERS (#1095)#1095mr-cal01ee7b2
chore: fix linting (#1099)#1099smethnani4c674c2
build(deps): bump cryptography (#1098)#1098smethnani239b3af
docs: update intersphinx mappings (#1102)#1102lengau80ae974
ci: use openstack for spread (#1091)#1091smethnani826edb3
docs: finalize changelog for 7.0.1 (#1115)#1115tigarmob437eb2
test: enable pro spread tests (#1114)#1114smethnanib768195
feat: add conditional repacking support (#1111)#1111cmatsuoka1dfae60
+

craft-archives (2.2.0 → 2.2.0)

+

No commits

+ +

craft-cli (3.2.0 → 3.2.0)

+

No commits

+ +

craft-grammar (2.3.0 → 2.3.0)

+

No commits

+ +

craft-parts (2.28.0 → 2.35.0)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
checkheaderPRauthorhash
fix: backport uv fix to 2.7n/alengau25d2878
docs(changelog): release 2.7.1n/alengaucaf5e64
style(auto): autoformatn/alengauacf81a0
fix(jlink_plugin): use self.model_dump() (#1426)#1426smethnaniee97b68
test: enable gradle plugin test (#1428)#1428smethnani5244702
build: update urllib3 (#1430)#1430bepri1b60eff
fix(Makefile): remove duplicate install-rustup definition (#1429)#1429smethnani35ad44b
test(gradle_plugin): disable daemon in integration test (#1433)#1433smethnanic5bf8ed
feat(gradle_plugin): add gradle-use-daemon key (#1436)#1436smethnani63d14cf
feat(gradle_plugin): add self-contained attribute support (#1425)#1425smethnanief17116
fix(docs): move gradle-use-daemon to keys section (#1439)#1439smethnani6718d13
fix(docs): Unformatted link in ruby plugin (#1437) (#1440)#1440canon-cat50936fa
feat: add colcon plugin (#1434)#1434Guillaumebeuzeboca713bdd
feat: implement mid-step callbacks (#1441)#1441cmatsuoka6bda793
docs: Release 2.29.0 (#1442)#1442smethnani71291d5
fix(apt_cache): set all candidate versions before marking packages (#1446)#1446EddyPronkcf118b5
ci: fix go_use test (#1455)#1455smethnani1d8d4f8
feat(npm): add self-contained support (#1448)#1448smethnanib654a77
chore(codeowners): remove authors from changelog reviews (#1461)#1461beprif8ce283
test: add test-requires-root (#1463)#1463smethnanib83516a
style: fix linting issues for newer ruff (#1465)#1465lengaua58695e
ci: upgrade flask (#1471)#1471smethnani32c8a63
feat: add override-overlay (#1472)#1472smethnani43dc848
feat: add npm-use (#1462)#1462smethnanica2f22c
fix(git-source): only shallow fetch if a source-depth is provided (#1476)#1476beprif1e2c92
docs: add override-overlay (#1473)#1473smethnani1b2b7d5
fix(ruby): run `gem build` on gems in `build_dir`, not `src_dir` (#1477)#1477atandrewlee0764004
chore(merge): hotfix/2.28 into main (#1481)#1481mr-caldf271d6
docs: fix Ruby plugin docs examples (#1474)#1474steinbroe751706
feat(go-use): error early if go.mod is missing (#1478)#1478atandrewleee5af6aa
feat: allow copying apt sources from host to overlay (#1483)#1483tigarmobedb4c0
chore!: deinit sphinx-docs-starter-pack submodulen/amedubelkof304b45
build(docs)!: update canonical starter pack to 1.4.1n/amedubelko6b0b727
build(deps): update documentation dependenciesn/amedubelko67623b5
build(docs): add passthrough to docs Makefilen/amedubelkof623a5e
docs: update all content for compatibilityn/amedubelko5484f06
docs: add starter pack refresh to changelogn/amedubelkof5c1aa6
docs: update uv plugin reference (#1486)#1486beprif91f0d4
tests: make test_install_slice deterministic across locales (#1496)#1496gcomnenoa832c05
ci(osv-scanner): ignore integration tests (#1498)#1498mr-cal559a7da
build(deps): update core dependencies (#1500)#1500lengauab2a2ee
build(docs): update and clean docs dependencies (#1501)#1501lengau753f204
docs: finalize 2.30.0 (#1499)#1499mr-cala1d1c6b
docs: remove bounty instructions (#1506)#1506beprie2b87f6
fix(poetry): install export plugin on 25.04+ (#1510)#1510bepri6d30ef1
fix: 7z(ip) sources support (#1443) (#1515)#1515canon-catc3aec9c
chore(merge): 2.7.1 into merge/2.7.1n/amr-cal09836a8
chore(merge): 2.7.1 into main (#1520)#1520mr-cald4a0463
fix: handle use_host_sources on OverlayManager.run() (#1524)#1524tigarmodd05222
build(deps): bump pygments (#1529)#1529smethnani5ed85e1
test(cmake_plugin): update version requirement (#1528)#1528smethnani89e8a05
feat: added bazel plugin (#1491)#1491ethandcosta3ac5961
build(deps): update dependency mypy to ~=1.20.0 (#1536)#1536mr-cala053c22
fix(test): enable the java plugin tests on resolute (#1530)#1530beprida6b596
docs: clarify .NET plugin SDK provisioning (#1417)#1417mateusrodrigues58e9ca1
build(Makefile): check for cargo (#1537)#1537mr-calcb31017
feat: organize files from build (#1535)#1535cmatsuoka8e4daf5
docs: prepare 2.31.0 release (#1539)#1539cmatsuoka659aafa
feat(packages/deb): parse chisel manifests (#1538)#1538mr-cal49a8824
revert: feat: organize files from build (#1548)#1548cmatsuoka5628273
docs(changelog): finalize 2.33.0 (#1549)#1549mr-calf593297
docs: add example to dump plugin (#1547)#1547asanvaqfb57e5a
build(deps): bump pytest (#1550)#1550beprie5a6feb
docs: add -i option example to both python plugin versions (#1542)#1542asanvaq88bf5ef
build(deps): bump lxml (#1563)#1563smethnani3495de6
feat: add gradle-use plugin (#1559)#1559smethnanic293ca9
ci: use ubuntu-22.04-arm runners (#1568)#1568lengaua85b434
fix(organize): make organizing to the overlay idempotent (#1541)#1541lengaua117830
docs: rename plugins '* use' -> '*-use' (#1573)#1573medubelkoe848312
fix(organize): allow merging directories in overlay with metadata differences (#1586)#1586lengau0797420
feat(overlay): plugins can define overlay commands (#1567)#1567lengau73d6a98
fix(organize): reject sources outside install dir (#1562)#1562gcomneno32b95b4
docs: fix npm capitalisation (#1565)#1565medubelkocebc4af
ci: separate flaky tests into their own job (#1583)#1583lengauec6458a
docs: correct the 'organize' description (#1582)#1582jahn-juniora769db7
chore: add Copilot collections (#1576)#1576lengau792a0a2
docs: fix headings in 'Overlay step' explanation (#1453)#1453jahn-juniorb6d6d35
fix(state): track override-overlay changes (#1579)#1579gcomneno059b1c0
refactor: use pathlib internally (#1424)#1424EdmilsonRodriguescfdabaf
fix(sources): handle streaming request errors (#1533)#1533gcomnenobbc6f9f
fix(organize): make organize to overlay behavior consistent (#1602)#1602cmatsuoka139cbce
feat(organize): support build pseudo-partition source (#1598)#1598gcomnenocc02958
feat: allow applications to set build environment (#1608)#1608cmatsuoka0f7a4b1
docs: finalize 2.34.0 (#1614)#1614smethnanic2bd58d
build(deps): bump idna + urllib3 (#1615)#1615smethnanidd195de
feat: allow the plus sign in partition names (#1612)#1612cmatsuoka5d5b792
fix: migrate overlay files before running stage or prime (#1617)#1617tigarmo2d81a4b
feat(plugins): allow subclasses to set autoconf parameters (#1616)#1616cmatsuoka5d909cf
+

craft-platforms (0.10.0 → 0.10.0)

+

No commits

+ +

craft-providers (3.2.0 → 3.7.1)

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
checkheaderPRauthorhash
feat: acquire pro guest tokens in managed LXD instances (#647)#647unknown10895fd
feat: get Pro status in managed LXD instance (#652)#652unknown6425b68
feat: attach managed instance to pro subscription (#655)#655unknown2bd0ca6
feat: enable pro services on managed LXD instance (#656)#656unknownc511987
feat: install Ubuntu Pro Client in LXD instance (#664)#664unknown09caf83
feat: switch to new guest token endpoint (#673)#673unknown4b64127
Merge branch 'main' into feature/pro-sourcesn/aunknown0d6d855
chore: merge main branch with feature/pro-source branch (#704)#704lengauad55c78
feat: updates to complete feature set for RK042 - Support for Pro Rocks in Rockcraft. (#721)#721clay-lake2e6a559
fix(pro-sources): Inherit Host's `contract_url` (#776)#776clay-lakec46962d
docs: enable Google Analytics (#424)#424jahn-junior37bb2a8
docs: update code of conduct links (#427)#427lengau95945ac
ci: fix publish workflow (#430)#430lengaub42c04a
fix(tests): better typing for tests (#433)#433lengau2262e30
chore: add IDE configs to gitignore (#435)#435bepri5ef1053
feat(Makefile): add ty as an optional linter (#429)#429lengauc2390f0
fix(gitignore): only ignore a top-level parts dir (#441)#441lengau43fa30d
docs: make linkcheck more forgiving (#444)#444lengau9cbbaf5
docs: add `CONTRIBUTING.md` template (#448)#448jahn-juniorebfec44
build(docs): remove line length check from linter (#453)#453medubelkoec0cf32
chore: add documentation items to PR checklist (#463)#463jahn-junior93f3b47
fix(bases): ignore unknown Ubuntu versions in bases check. (#852)#852lengau2707796
chore(test): remove no-op deprecated behavior (#855)#855beprifb68c17
chore: update CODEOWNERS (#837)#837lengaua0967cc
ci: downgrade to macos 14 on most runners (#879)#879lengau262f731
build: bump urllib3 (#869)#869bepri122fd0b
ci: disable Linux ARM64 CI (#883)#883lengau27f833e
refactor: use pylxd to determine if an instance exists (#874)#874bepri48bd685
style: enable type checking with ty (#885)#885lengau28ccfe5
style: enable ty by default (#472)#472lengau7982765
build(docs): make `clean` target scrub `docs/reference/gen` (#477)#477lengau334adfe
build(deps): update canonical starter pack to 1.3.1n/amedubelkoc47c166
build(deps): remove dependency sphinx-toolboxn/amedubelko7ff4723
build(docs): add passthrough to docs Makefilen/amedubelkoe94f190
docs: fix spelling errorsn/amedubelkoa551c9d
feat(pro): use Ubuntu Pro guest attachment (#890)#890tigarmo31c4e58
docs: mandate conventional commits in PR titlesn/amedubelko602d1d0
build(docs): exclude reuse dir (#483)#483medubelko014764d
docs: remove scheduled feature deprecations from rn template (#484)#484medubelkod348aad
docs: add guidance for contribs to rn template (#485)#485medubelkob878f19
build(deps): bump pytest to 9.0n/amr-cale64feb1
style: ignore unused type commentsn/amr-calc1abc9e
fix: retry 'snap watch' (#899)#899mr-cale0f6bc7
build(docs): remove myst check (#488)#488medubelko64374bc
fix(build): use correct autobuild command (#491)#491medubelko22e9ce4
docs: ensure we never delete a "real" file (#492)#492bepri560adbf
build(deps): bump cryptography and urllib3 (#909)#909smethnani922e691
build(deps): remove unused docs dependencies (#490)#490medubelko43c54fa
build(docs): disable vale check (#489)#489medubelko136c2e2
fix(build): false lint errors (#493)#493medubelkob304e0a
style: fix ty error (#910)#910bepri30fc806
build(deps): restore sphinxcontrib-jquery>=4.1 (#494)#494medubelkoc1aab61
chore(merge): main into merge/mainn/amr-calcca0836
chore(merge): main into feature/pro-sources (#913)#913lengauf7edf3d
feat: list all vm instances (#903)#903Aeonoi9ae7664
chore: finalize Pro support (#916)#916mr-cal6545bdb
chore(merge): feature/pro-sources into merge/pro-sourcesn/amr-cal3232836
chore(merge): feature/pro-sources into main (#918)#918mr-calb56ff14
fix: get lsb_release when installing Pron/amr-cal6bb4d0f
docs: finalize 3.4.0n/amr-cal68f1ca3
feat(models): add SnapInfo model for snapd response (#908)#908PraaneshSelvaraje996996
ci: enable integration tests on arm64 (#921)#921lengau55b77b8
feat(LXD): add other-architecture option (#922)#922lengauccb946b
chore: remove comment fences from GitHub templates (#498)#498beprie810141
feat(lint): lint the Github actions with actionlint (#473)#473lengaue385e9d
fix: help formatting when running `make -f common.mk` (#501)#501medubelko0344506
feat: allow disabling eol source updates (#926)#926FinnRGae95427
docs: finalize 3.5.0 (#927)#927mr-caleef0712
build(docs): upgrade Starter Pack to 1.5 (#499)#499jahn-junior8c01792
docs: add 'about this documentation' (#502)#502medubelko80e67c9
build(deps): update dependency sphinx-sitemap to ==2.6.0 (#504)#504medubelko22b81ba
ci(osv-scanner): ignore integration tests (#505)#505mr-cale7954a7
fix(ci): collapse the docs checks in the workflow logs (#508)#508lengau0867e7e
docs: remove bounty instructions (#933)#933bepric399130
fix(multipass): list instances (#930)#930Aeonoi21f3af1
style: ty (#938)#938mr-cal44bcd1a
feat(Provider): add prune method (#925)#925Aeonoi9836260
build(deps): update cryptography, pygments, requests (#940)#940mr-caleb8549f
build(deps): bump pygments (#517)#517bepric9fecdf
docs: block intersphinx lookup for internal links (#519)#519medubelkoa38d79a
docs: format doc version as major.minor (#520)#520medubelko66911da
build(docs): fix double build with docs-lint (#513)#513medubelko1107517
docs: update Starter Pack variables (#523)#523jahn-junior25d7d15
build(deps): bump pytest (#524)#524smethnanie372177
chore: add doc meta description to pr checklist (#521)#521medubelkoa73333a
style(lint): ignore FBT001 and FBT002 in tests (#528)#528lengau829b31f
build: fix docs-install target (#525)#525mr-calb434201
docs: minor clean up and reorg (#529)#529medubelko50567fc
chore: use releases for resolute (#958)#958canon-cat37aa14d
docs: changelog entries for 3.6.0 (#959)#959tigarmo93a61b3
docs: remove bounty instructions (#530)#530beprif7ccae3
fix(ty): point to venv (#534)#534bepricf39b36
build(deps): update lockfile for OSVs (#963)#963lengauf2266ad
fix(lxd/remotes): use release images for plucky (#962)#962lengau92a8243
chore: add copilot-collections (#964)#964lengau742eeb4
feat(models): add SnapdResponse model for snapd Response (#939)#939PraaneshSelvaraj2702b5a
chore(types): enable explicit re-export checking (#966)#966gcomneno6bbb837
build(docs): update Sphinx Stack to 2.0 (#537)#537jahn-juniorfafd1fc
build(deps): bump lxml (#540)#540jahn-junior663c1b4
chore: update Copilot collections to v0.14.0 (#968)#968github-actions[bot]d5462c1
chore: merge the latest starbasen/alengau8fd197d
build(deps): add constraint for Starlette (#972)#972steinbro7ed9c81
chore: merge the latest Starbase (#973)#973lengauaa50a03
fix: raise MultipassError instead of looping forever on dotless version (#952)#952lengauc02b44a
ci: update code owners (#974)#974mr-cal1543896
feat: add support for Ubuntu 26.10 (Stonking) (#956)#956canon-catef04bef
fix: don't fail on unknown ubuntu bases (#980)#980mr-cal628f199
ci: temporarily disable macos smoke tests (#982)#982lengaua3af10b
fix: forward env to lxd instance with Pro methods (#981)#981smethnanib4761be
docs: finalize 3.7.1 (#984)#984smethnani74d275d
+

Contributors

+:literalref:`@Aeonoi <https://github.com/Aeonoi>`,
+:literalref:`@asanvaq <https://github.com/asanvaq>`,
+:literalref:`@atandrewlee <https://github.com/atandrewlee>`,
+:literalref:`@bepri <https://github.com/bepri>`,
+:literalref:`@canon-cat <https://github.com/canon-cat>`,
+:literalref:`@clay-lake <https://github.com/clay-lake>`,
+:literalref:`@cmatsuoka <https://github.com/cmatsuoka>`,
+:literalref:`@EddyPronk <https://github.com/EddyPronk>`,
+:literalref:`@EdmilsonRodrigues <https://github.com/EdmilsonRodrigues>`,
+:literalref:`@ethandcosta <https://github.com/ethandcosta>`,
+:literalref:`@FinnRG <https://github.com/FinnRG>`,
+:literalref:`@gcomneno <https://github.com/gcomneno>`,
+:literalref:`@github-actions[bot] <https://github.com/github-actions[bot]>`,
+:literalref:`@Guillaumebeuzeboc <https://github.com/Guillaumebeuzeboc>`,
+:literalref:`@HamdaanAliQuatil <https://github.com/HamdaanAliQuatil>`,
+:literalref:`@jahn-junior <https://github.com/jahn-junior>`,
+:literalref:`@lengau <https://github.com/lengau>`,
+:literalref:`@mateusrodrigues <https://github.com/mateusrodrigues>`,
+:literalref:`@medubelko <https://github.com/medubelko>`,
+:literalref:`@mr-cal <https://github.com/mr-cal>`,
+:literalref:`@mwhudson <https://github.com/mwhudson>`,
+:literalref:`@PraaneshSelvaraj <https://github.com/PraaneshSelvaraj>`,
+:literalref:`@smethnani <https://github.com/smethnani>`,
+:literalref:`@Spilsed <https://github.com/Spilsed>`,
+:literalref:`@steinbro <https://github.com/steinbro>`,
+:literalref:`@tigarmo <https://github.com/tigarmo>`,
+and :literalref:`@unknown <https://github.com/unknown>`
+ + + diff --git a/docs/release-notes/imagecraft-0-2-0.rst b/docs/release-notes/imagecraft-0-2-0.rst new file mode 100644 index 00000000..34fe46dc --- /dev/null +++ b/docs/release-notes/imagecraft-0-2-0.rst @@ -0,0 +1,120 @@ +.. meta:: + :description: Release notes for Imagecraft 0.2.0. + +.. _release-0.2.0: + +Imagecraft 0.2.0 release notes +============================== + +22 July 2026 + +Learn about the new features, changes, and fixes introduced in Imagecraft 0.2.0. + + +Requirements and compatibility +------------------------------ + +Imagecraft 0.2.0 requires Python 3.11 or higher. + + +What's new +---------- + +Imagecraft 0.2.0 brings the following features, integrations, and improvements. + + +Support for MBR and hybrid volume schemas +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Imagecraft now accepts ``mbr`` and ``mbr,gpt`` volume schemas. MBR images are now +supported on x86, and Imagecraft generates the GRUB assets needed for them. + + +Support for snap prepare-image plugins +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Imagecraft now includes ``snap-preseed`` and ``uc-prepare`` plugins for core and +classic images. These plugins make it easier to prepare images that need snap +content or Ubuntu Core setup steps. + + +Support for the mmdebstrap plugin +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Imagecraft now includes an ``mmdebstrap`` plugin for building Debian-derived root +filesystems. + + +Improved boot image generation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Imagecraft now uses ``grub-mkimage`` asset generation instead of mounting the target +root filesystem and running ``grub-install``. This makes boot asset generation more +reliable during packing. + + +Minor features +-------------- + +Imagecraft 0.2.0 brings the following minor changes. + + +Support for writing to specific sectors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Imagecraft now writes volume data to temporary image files during lifecycle commands, +which lets it place data in specific sectors of the final output image. + + +Support for the ``@`` channel separator +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``snap-preseed`` and ``uc-prepare`` plugins now accept ``@`` as the channel +separator, with optional surrounding whitespace. + + +Support for Ubuntu 26.04 as a build base +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Imagecraft now accepts ``ubuntu@26.04`` as a build base. + + +Improved overlay handling +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Imagecraft now enables ``override-overlay`` for image builds. + + +Backwards-incompatible changes +------------------------------ + +The following changes are incompatible with previous versions of Imagecraft. + + +Using the MINIMAL plugin group +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Imagecraft now extends craft-application's ``MINIMAL`` plugin group instead of the +``DEFAULT`` group. If you rely on custom plugin selection, review your setup against +the new plugin grouping behavior. + + +Fixed bugs and issues +--------------------- + +The following issues have been resolved in Imagecraft 0.2.0. + + +* ``snap-prepare`` now treats missing keys as optional instead of failing when they + are absent. +* ``mmdebstrap`` now unmounts lingering mounts after use. + + +Contributors +------------ + +We would like to express a big thank you to all the people who contributed to this +release. + +smethnani, JJ Coldiron, Alex Lowe, Imani Pelton, Michael DuBelko, Spilsed, Callahan +Kovacs, Alex M. Lowe, and Michael Hudson-Doyle. diff --git a/imagecraft.kdev4 b/imagecraft.kdev4 new file mode 100644 index 00000000..77fc269f --- /dev/null +++ b/imagecraft.kdev4 @@ -0,0 +1,4 @@ +[Project] +CreatedFrom= +Manager=KDevCustomBuildSystem +Name=imagecraft diff --git a/imagecraft/pack/grubutil.py b/imagecraft/pack/grubutil.py index 23087a04..7983665a 100644 --- a/imagecraft/pack/grubutil.py +++ b/imagecraft/pack/grubutil.py @@ -55,11 +55,12 @@ } -def _grub_install(grub_target: str, loop_dev: str) -> None: +def _grub_install(grub_target: str, loop_dev: str, mount_dir: Path) -> None: """Install grub in the image. :param grub_target: target platform to install grub for. :param loop_dev: loop device to install grub on + :param mount_dir: mount directory for the image """ check_grub_install = ["grub-install", "-V"] if grub_target == _GRUB_BIOS_TARGET: @@ -132,7 +133,7 @@ def _grub_install(grub_target: str, loop_dev: str) -> None: except FileNotFoundError as err: raise errors.GRUBInstallError("Missing tool to install grub") from err - _populate_uefi_fallback(grub_target) + _populate_uefi_fallback(grub_target, mount_dir) def _extract_root_uuid(grub_cfg_src: Path) -> str: @@ -144,7 +145,9 @@ def _extract_root_uuid(grub_cfg_src: Path) -> str: return "" -def _populate_uefi_fallback(grub_target: str) -> None: +def _populate_uefi_fallback( + grub_target: str, mount_dir: Path, efi_dir: Path = Path("/boot/efi/EFI") +) -> None: """Populate UEFI fallback path with grub + config next to BOOT*.EFI. We intentionally keep BOOT*.EFI as shim and provide grubx64.efi/grub.cfg @@ -154,11 +157,11 @@ def _populate_uefi_fallback(grub_target: str) -> None: return grub_fname, fallback_grub_fname = _EFI_TARGET_TO_FILENAMES[grub_target] - efi_dir = Path("/boot/efi/EFI") grub_src = efi_dir / "ubuntu" / grub_fname grub_cfg_src = efi_dir / "ubuntu" / "grub.cfg" boot_grub = efi_dir / "BOOT" / fallback_grub_fname boot_cfg = efi_dir / "BOOT" / "grub.cfg" + root_grub_cfg = mount_dir / "boot" / "grub" / "grub.cfg" if not (grub_src.exists() and grub_cfg_src.exists()): return @@ -176,7 +179,7 @@ def _populate_uefi_fallback(grub_target: str) -> None: if not ubuntu_modules.exists(): shutil.copytree(modules_src, ubuntu_modules, dirs_exist_ok=True) - root_uuid = _extract_root_uuid(grub_cfg_src) + root_uuid = _extract_root_uuid(root_grub_cfg) if root_grub_cfg.exists() else "" if root_uuid: stub = "\n".join( [ @@ -260,6 +263,7 @@ def setup_grub( target=_grub_install, grub_target=grub_target, loop_dev=loop_dev, + mount_dir=mount_dir, ) except errors.ChrootMountError as err: # Ignore mounting errors indicating the rootfs does not have diff --git a/tests/unit/pack/test_grubutil.py b/tests/unit/pack/test_grubutil.py index 125b3cee..cc8dc34f 100644 --- a/tests/unit/pack/test_grubutil.py +++ b/tests/unit/pack/test_grubutil.py @@ -31,7 +31,12 @@ MBRVolume, ) from imagecraft.pack.chroot import Mount -from imagecraft.pack.grubutil import _image_mounts, _part_num, setup_grub +from imagecraft.pack.grubutil import ( + _image_mounts, + _part_num, + _populate_uefi_fallback, + setup_grub, +) from imagecraft.pack.image import Image @@ -309,6 +314,41 @@ def test_setup_grub_mbr_bios(mocker, new_dir, arch): assert mock_chroot.return_value.execute.call_args.kwargs["grub_target"] == "i386-pc" +@pytest.mark.usefixtures("new_dir") +def test_populate_uefi_fallback_uses_root_grub_cfg(new_dir): + mount_dir = Path(new_dir, "mount") + efi_dir = Path(new_dir, "efi") + root_grub_cfg = mount_dir / "boot" / "grub" / "grub.cfg" + ubuntu_dir = efi_dir / "ubuntu" + + root_grub_cfg.parent.mkdir(parents=True, exist_ok=True) + ubuntu_dir.mkdir(parents=True, exist_ok=True) + (mount_dir / "boot" / "grub" / "x86_64-efi").mkdir(parents=True, exist_ok=True) + root_grub_cfg.write_text( + "search.fs_uuid 12345678-1234-1234-1234-123456789abc root\n", + encoding="utf-8", + ) + (ubuntu_dir / "grubx64.efi").write_text("grub-binary", encoding="utf-8") + (ubuntu_dir / "grub.cfg").write_text("normal\n", encoding="utf-8") + + _populate_uefi_fallback("x86_64-efi", mount_dir, efi_dir=efi_dir) + + expected_stub = ( + "insmod part_gpt\n" + "insmod ext2\n" + "search.fs_uuid 12345678-1234-1234-1234-123456789abc root\n" + "set prefix=($root)'/boot/grub'\n" + "configfile $prefix/grub.cfg\n" + ) + assert (efi_dir / "BOOT" / "grubx64.efi").read_text( + encoding="utf-8" + ) == "grub-binary" + assert (efi_dir / "ubuntu" / "grub.cfg").read_text( + encoding="utf-8" + ) == expected_stub + assert (efi_dir / "BOOT" / "grub.cfg").read_text(encoding="utf-8") == expected_stub + + @pytest.mark.parametrize( ("loop_dev", "volume", "filesystem_mount", "mounts"), [ From 8e7368e05409c2f1ff187400145efb94bb1295cd Mon Sep 17 00:00:00 2001 From: "Alex M. Lowe" Date: Mon, 10 Aug 2026 15:40:20 -0400 Subject: [PATCH 09/14] Fix spread tests for Ubuntu 25.10 EOL Add --ignore=unmaintained flag to imagecraft pack commands in tests that run on all systems, including Ubuntu 25.10 which is now EOL. This allows the tests to continue running without failures due to unmaintained base distributions. Affected tests: - tests/spread/pack/simple/task.yaml - tests/spread/pack/non-sequential-partitions/task.yaml - tests/spread/pack/sector-write/task.yaml Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/spread/pack/non-sequential-partitions/task.yaml | 2 +- tests/spread/pack/sector-write/task.yaml | 2 +- tests/spread/pack/simple/task.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/spread/pack/non-sequential-partitions/task.yaml b/tests/spread/pack/non-sequential-partitions/task.yaml index 5057c2ec..0f0fa6f4 100644 --- a/tests/spread/pack/non-sequential-partitions/task.yaml +++ b/tests/spread/pack/non-sequential-partitions/task.yaml @@ -1,7 +1,7 @@ summary: Pack an image with non-sequential partition numbers. execute: | - imagecraft pack --verbose + imagecraft pack --verbose --ignore=unmaintained test -f disk.img diff --git a/tests/spread/pack/sector-write/task.yaml b/tests/spread/pack/sector-write/task.yaml index 95fe8529..e80b8211 100644 --- a/tests/spread/pack/sector-write/task.yaml +++ b/tests/spread/pack/sector-write/task.yaml @@ -1,7 +1,7 @@ summary: Data written to sectors outside partitions via the loop device is preserved execute: | - imagecraft pack --verbose --destructive-mode + imagecraft pack --verbose --ignore=unmaintained --destructive-mode test -f disk.img # Verify that sector 100 is actually in the gap between the GPT partition diff --git a/tests/spread/pack/simple/task.yaml b/tests/spread/pack/simple/task.yaml index f324fde3..051690a3 100644 --- a/tests/spread/pack/simple/task.yaml +++ b/tests/spread/pack/simple/task.yaml @@ -5,7 +5,7 @@ prepare: | sed "s/__BUILD_BASE__/${ID}@${VERSION_ID}/" imagecraft-template.yaml > imagecraft.yaml execute: | - imagecraft pack --verbose + imagecraft pack --verbose --ignore=unmaintained test -f disk.img # Running in destructive mode until we can fix https://github.com/canonical/imagecraft/issues/253 From cd6ec422e3e6e7b3375b01f1c6a2b432bf53dda2 Mon Sep 17 00:00:00 2001 From: "Alex M. Lowe" Date: Mon, 10 Aug 2026 16:02:19 -0400 Subject: [PATCH 10/14] chore(deps): pin craft-providers to latest 3.7.x version Update craft-providers constraint from ~=3.0 to ~=3.7 to ensure we use the latest bug fixes and improvements in the 3.7.x series. This helps support newer Ubuntu versions like 26.04. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pyproject.toml | 2 +- uv.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index ec64de73..5d451f2e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,7 @@ dependencies = [ "craft-platforms~=0.6", "craft-application~=7.1", "craft-grammar~=2.3", - "craft-providers~=3.0", + "craft-providers~=3.7", "pydantic~=2.8", "pygit2>=1.13.0,<1.15.0; python_version=='3.12'", # pin pygit2 to versions compatible with libgit2-1.7 for core24 "pygit2>=1.19.0,<1.20.0; python_version=='3.14'", # Ubuntu 26.04 and core26 diff --git a/uv.lock b/uv.lock index 4b918c20..d3e89cea 100644 --- a/uv.lock +++ b/uv.lock @@ -815,7 +815,7 @@ requires-dist = [ { name = "craft-grammar", specifier = "~=2.3" }, { name = "craft-parts", specifier = "~=2.35.0" }, { name = "craft-platforms", specifier = "~=0.6" }, - { name = "craft-providers", specifier = "~=3.0" }, + { name = "craft-providers", specifier = "~=3.7" }, { name = "pydantic", specifier = "~=2.8" }, { name = "pygit2", marker = "python_full_version == '3.12.*'", specifier = ">=1.13.0,<1.15.0" }, { name = "pygit2", marker = "python_full_version == '3.14.*'", specifier = ">=1.19.0,<1.20.0" }, From 6fe69a9965d907593052159189ba09fad13ade46 Mon Sep 17 00:00:00 2001 From: "Alex M. Lowe" Date: Mon, 10 Aug 2026 22:04:47 +0000 Subject: [PATCH 11/14] chore(deps): temporarily use craft-application fix-1152 branch is_effective_base_eol() crashes with UnknownVersionError when build-base: devel is used with --ignore=unmaintained, since it lacks the same devel/unknown-base handling as its sibling methods check_base_is_supported()/base_eol_soon_date(). This broke tests/spread/pack/non-sequential-partitions and tests/spread/pack/sector-write on all systems. Point craft-application at the canonical/craft-application#1153 fix branch until it's merged and released, then switch back to a released craft-application~=7.1. Fixes canonical/craft-application#1152 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pyproject.toml | 4 +++- uv.lock | 10 +++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 5d451f2e..fd74acf8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,7 +9,9 @@ dependencies = [ "craft-parts~=2.35.0", "craft-cli~=3.0", "craft-platforms~=0.6", - "craft-application~=7.1", + # TODO: switch back to a released craft-application~=7.1 once + # https://github.com/canonical/craft-application/pull/1153 is merged and released. + "craft-application @ git+https://github.com/canonical/craft-application@work/fix-1152", "craft-grammar~=2.3", "craft-providers~=3.7", "pydantic~=2.8", diff --git a/uv.lock b/uv.lock index d3e89cea..04a0b9f1 100644 --- a/uv.lock +++ b/uv.lock @@ -434,8 +434,8 @@ toml = [ [[package]] name = "craft-application" -version = "7.1.0" -source = { registry = "https://pypi.org/simple" } +version = "7.1.0.post25+g1da0cb1" +source = { git = "https://github.com/canonical/craft-application?rev=work%2Ffix-1152#1da0cb12ad4b66c962d5e5c2143060c0e895d093" } dependencies = [ { name = "annotated-types" }, { name = "craft-archives" }, @@ -457,10 +457,6 @@ dependencies = [ { name = "snap-http" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/6b/c3/be96c01c1b92a7a7eb6cafa881ccd09a6b9e1db1355835fc98f001680cc3/craft_application-7.1.0.tar.gz", hash = "sha256:e0a3fb2080bf1dd6daf8b570262716f79a5f307a87d3ed2b986eaca50e07efed", size = 663202, upload-time = "2026-07-07T22:02:40.491Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/ce/169bdacdfbda0fe8a880d914be0794fc5379b7ec577546444f1572f4762d/craft_application-7.1.0-py3-none-any.whl", hash = "sha256:3319310644d1d935fd7e2fb285fa38bc87c490f3d4fb72fed934e6202164b7bc", size = 212571, upload-time = "2026-07-07T22:02:38.317Z" }, -] [[package]] name = "craft-archives" @@ -810,7 +806,7 @@ types = [ [package.metadata] requires-dist = [ - { name = "craft-application", specifier = "~=7.1" }, + { name = "craft-application", git = "https://github.com/canonical/craft-application?rev=work%2Ffix-1152" }, { name = "craft-cli", specifier = "~=3.0" }, { name = "craft-grammar", specifier = "~=2.3" }, { name = "craft-parts", specifier = "~=2.35.0" }, From 396f8732b6fde97fd96ca3318d73423ae2381b7a Mon Sep 17 00:00:00 2001 From: "Alex M. Lowe" Date: Mon, 10 Aug 2026 22:07:48 +0000 Subject: [PATCH 12/14] chore: remove accidentally committed local artifacts Commit 0c879c9 unintentionally included local editor/agent tooling config and scratch files that don't belong in the repository: - .agents/, .kdev4/, imagecraft.kdev4, .workshop/ (local IDE/agent config) - TODO.md and contributors.html (personal scratch notes / generated report, referencing a local file path) - docs/release-notes/imagecraft-0-2-0.rst (belongs to the separate 0.2.0 release-notes work, not this branch) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .agents/rules/core-directive.instructions.md | 1 - .../rules/documentation-rtd.instructions.md | 1 - .agents/rules/documentation.instructions.md | 1 - .agents/rules/instructions.instructions.md | 1 - .../python-code-commenting.instructions.md | 1 - .../rules/starcraft-docs-meta.instructions.md | 1 - .../starcraft-docs-style.instructions.md | 1 - .agents/skills/documentation-build | 1 - .agents/skills/documentation-diataxis | 1 - .agents/skills/documentation-review | 1 - .agents/skills/documentation-structure | 1 - .agents/skills/documentation-style | 1 - .agents/skills/documentation-verify | 1 - .kdev4/imagecraft.kdev4 | 2 - .workshop/dev.yaml | 48 -- .workshop/imagecraft-setup/hooks/check-health | 20 - .workshop/imagecraft-setup/hooks/setup-base | 7 - .../imagecraft-setup/hooks/setup-project | 8 - .workshop/imagecraft-setup/sdk.yaml | 1 - TODO.md | 172 ------ contributors.html | 566 ------------------ docs/release-notes/imagecraft-0-2-0.rst | 120 ---- imagecraft.kdev4 | 4 - 23 files changed, 961 deletions(-) delete mode 120000 .agents/rules/core-directive.instructions.md delete mode 120000 .agents/rules/documentation-rtd.instructions.md delete mode 120000 .agents/rules/documentation.instructions.md delete mode 120000 .agents/rules/instructions.instructions.md delete mode 120000 .agents/rules/python-code-commenting.instructions.md delete mode 120000 .agents/rules/starcraft-docs-meta.instructions.md delete mode 120000 .agents/rules/starcraft-docs-style.instructions.md delete mode 120000 .agents/skills/documentation-build delete mode 120000 .agents/skills/documentation-diataxis delete mode 120000 .agents/skills/documentation-review delete mode 120000 .agents/skills/documentation-structure delete mode 120000 .agents/skills/documentation-style delete mode 120000 .agents/skills/documentation-verify delete mode 100644 .kdev4/imagecraft.kdev4 delete mode 100644 .workshop/dev.yaml delete mode 100755 .workshop/imagecraft-setup/hooks/check-health delete mode 100755 .workshop/imagecraft-setup/hooks/setup-base delete mode 100755 .workshop/imagecraft-setup/hooks/setup-project delete mode 100644 .workshop/imagecraft-setup/sdk.yaml delete mode 100644 TODO.md delete mode 100644 contributors.html delete mode 100644 docs/release-notes/imagecraft-0-2-0.rst delete mode 100644 imagecraft.kdev4 diff --git a/.agents/rules/core-directive.instructions.md b/.agents/rules/core-directive.instructions.md deleted file mode 120000 index d9a21c7e..00000000 --- a/.agents/rules/core-directive.instructions.md +++ /dev/null @@ -1 +0,0 @@ -/home/lengau/Work/Code/imagecraft/.github/instructions/core-directive.instructions.md \ No newline at end of file diff --git a/.agents/rules/documentation-rtd.instructions.md b/.agents/rules/documentation-rtd.instructions.md deleted file mode 120000 index 7633c7b9..00000000 --- a/.agents/rules/documentation-rtd.instructions.md +++ /dev/null @@ -1 +0,0 @@ -/home/lengau/Work/Code/imagecraft/.github/instructions/documentation-rtd.instructions.md \ No newline at end of file diff --git a/.agents/rules/documentation.instructions.md b/.agents/rules/documentation.instructions.md deleted file mode 120000 index d98fe64c..00000000 --- a/.agents/rules/documentation.instructions.md +++ /dev/null @@ -1 +0,0 @@ -/home/lengau/Work/Code/imagecraft/.github/instructions/documentation.instructions.md \ No newline at end of file diff --git a/.agents/rules/instructions.instructions.md b/.agents/rules/instructions.instructions.md deleted file mode 120000 index bb84cb59..00000000 --- a/.agents/rules/instructions.instructions.md +++ /dev/null @@ -1 +0,0 @@ -/home/lengau/Work/Code/imagecraft/.github/instructions/instructions.instructions.md \ No newline at end of file diff --git a/.agents/rules/python-code-commenting.instructions.md b/.agents/rules/python-code-commenting.instructions.md deleted file mode 120000 index 214bc0bb..00000000 --- a/.agents/rules/python-code-commenting.instructions.md +++ /dev/null @@ -1 +0,0 @@ -/home/lengau/Work/Code/imagecraft/.github/instructions/python-code-commenting.instructions.md \ No newline at end of file diff --git a/.agents/rules/starcraft-docs-meta.instructions.md b/.agents/rules/starcraft-docs-meta.instructions.md deleted file mode 120000 index 46172e41..00000000 --- a/.agents/rules/starcraft-docs-meta.instructions.md +++ /dev/null @@ -1 +0,0 @@ -/home/lengau/Work/Code/imagecraft/.github/instructions/starcraft-docs-meta.instructions.md \ No newline at end of file diff --git a/.agents/rules/starcraft-docs-style.instructions.md b/.agents/rules/starcraft-docs-style.instructions.md deleted file mode 120000 index 1bccb3e3..00000000 --- a/.agents/rules/starcraft-docs-style.instructions.md +++ /dev/null @@ -1 +0,0 @@ -/home/lengau/Work/Code/imagecraft/.github/instructions/starcraft-docs-style.instructions.md \ No newline at end of file diff --git a/.agents/skills/documentation-build b/.agents/skills/documentation-build deleted file mode 120000 index 6647c542..00000000 --- a/.agents/skills/documentation-build +++ /dev/null @@ -1 +0,0 @@ -/home/lengau/Work/Code/imagecraft/.github/skills/documentation-build \ No newline at end of file diff --git a/.agents/skills/documentation-diataxis b/.agents/skills/documentation-diataxis deleted file mode 120000 index 996d46d6..00000000 --- a/.agents/skills/documentation-diataxis +++ /dev/null @@ -1 +0,0 @@ -/home/lengau/Work/Code/imagecraft/.github/skills/documentation-diataxis \ No newline at end of file diff --git a/.agents/skills/documentation-review b/.agents/skills/documentation-review deleted file mode 120000 index c6b9fa61..00000000 --- a/.agents/skills/documentation-review +++ /dev/null @@ -1 +0,0 @@ -/home/lengau/Work/Code/imagecraft/.github/skills/documentation-review \ No newline at end of file diff --git a/.agents/skills/documentation-structure b/.agents/skills/documentation-structure deleted file mode 120000 index 145f2e8b..00000000 --- a/.agents/skills/documentation-structure +++ /dev/null @@ -1 +0,0 @@ -/home/lengau/Work/Code/imagecraft/.github/skills/documentation-structure \ No newline at end of file diff --git a/.agents/skills/documentation-style b/.agents/skills/documentation-style deleted file mode 120000 index 6373ad45..00000000 --- a/.agents/skills/documentation-style +++ /dev/null @@ -1 +0,0 @@ -/home/lengau/Work/Code/imagecraft/.github/skills/documentation-style \ No newline at end of file diff --git a/.agents/skills/documentation-verify b/.agents/skills/documentation-verify deleted file mode 120000 index 5e5e1e06..00000000 --- a/.agents/skills/documentation-verify +++ /dev/null @@ -1 +0,0 @@ -/home/lengau/Work/Code/imagecraft/.github/skills/documentation-verify \ No newline at end of file diff --git a/.kdev4/imagecraft.kdev4 b/.kdev4/imagecraft.kdev4 deleted file mode 100644 index 2ffd5cd5..00000000 --- a/.kdev4/imagecraft.kdev4 +++ /dev/null @@ -1,2 +0,0 @@ -[Project] -VersionControlSupport=kdevgit diff --git a/.workshop/dev.yaml b/.workshop/dev.yaml deleted file mode 100644 index 0f3f534e..00000000 --- a/.workshop/dev.yaml +++ /dev/null @@ -1,48 +0,0 @@ -name: dev -base: ubuntu@24.04 -sdks: - - name: uv - - name: copilot - - name: node - channel: 24/stable - - name: rust - - name: project-imagecraft-setup -actions: - setup: make setup - test: make test - test-fast: make test-fast - test-slow: make test-slow - lint: make lint - format: make format - pack: make pack - pack-snap: make pack-snap - install-craft-stack-branch: | - if [ "$#" -gt 1 ]; then - echo 'usage: workshop run dev -- install-craft-stack-branch [branch]' - exit 2 - fi - branch="${1:-main}" - for package in craft-application craft-parts craft-providers; do - uv pip install --python .venv/bin/python --upgrade "$package @ git+https://github.com/canonical/$package.git@$branch" - done - install-craft-application-branch: | - if [ "$#" -gt 1 ]; then - echo 'usage: workshop run dev -- install-craft-application-branch [branch]' - exit 2 - fi - branch="${1:-main}" - uv pip install --python .venv/bin/python --upgrade "craft-application @ git+https://github.com/canonical/craft-application.git@$branch" - install-craft-parts-branch: | - if [ "$#" -gt 1 ]; then - echo 'usage: workshop run dev -- install-craft-parts-branch [branch]' - exit 2 - fi - branch="${1:-main}" - uv pip install --python .venv/bin/python --upgrade "craft-parts @ git+https://github.com/canonical/craft-parts.git@$branch" - install-craft-providers-branch: | - if [ "$#" -gt 1 ]; then - echo 'usage: workshop run dev -- install-craft-providers-branch [branch]' - exit 2 - fi - branch="${1:-main}" - uv pip install --python .venv/bin/python --upgrade "craft-providers @ git+https://github.com/canonical/craft-providers.git@$branch" diff --git a/.workshop/imagecraft-setup/hooks/check-health b/.workshop/imagecraft-setup/hooks/check-health deleted file mode 100755 index 3056c00a..00000000 --- a/.workshop/imagecraft-setup/hooks/check-health +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -missing=() -for tool in uv ruff codespell shellcheck ty; do - if ! command -v "$tool" >/dev/null 2>&1; then - missing+=("$tool") - fi -done - -if [ ! -x /project/.venv/bin/python ]; then - missing+=(".venv/bin/python") -fi - -if [ "${#missing[@]}" -gt 0 ]; then - workshopctl set-health error "missing setup tools: ${missing[*]}" - exit 1 -fi - -workshopctl set-health okay diff --git a/.workshop/imagecraft-setup/hooks/setup-base b/.workshop/imagecraft-setup/hooks/setup-base deleted file mode 100755 index 187d4c34..00000000 --- a/.workshop/imagecraft-setup/hooks/setup-base +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -if ! command -v shellcheck >/dev/null 2>&1; then - apt-get update - DEBIAN_FRONTEND=noninteractive apt-get install -y shellcheck -fi diff --git a/.workshop/imagecraft-setup/hooks/setup-project b/.workshop/imagecraft-setup/hooks/setup-project deleted file mode 100755 index f35d504f..00000000 --- a/.workshop/imagecraft-setup/hooks/setup-project +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -cd /project -make setup -uv tool install --force ruff -uv tool install --force codespell -uv tool install --force ty diff --git a/.workshop/imagecraft-setup/sdk.yaml b/.workshop/imagecraft-setup/sdk.yaml deleted file mode 100644 index 623eacd3..00000000 --- a/.workshop/imagecraft-setup/sdk.yaml +++ /dev/null @@ -1 +0,0 @@ -name: imagecraft-setup diff --git a/TODO.md b/TODO.md deleted file mode 100644 index fe452c86..00000000 --- a/TODO.md +++ /dev/null @@ -1,172 +0,0 @@ -# TODO: Replicating `grub-install` using `grub-mkimage` & Manual GRUB Deployment (EFI Devices) - -This document outlines all technical steps, module dependencies, file operations, and platform-specific logic required to replace high-level `grub-install` invocations in `imagecraft` with `grub-mkimage` and direct file/sector installation for **Ubuntu** image builds on **EFI-capable devices** across supported architectures (`amd64`, `arm64`, `armhf`, and `riscv64`). - ---- - -## 1. Overview & Context - -Currently, `imagecraft` invokes `grub-install` inside a chroot environment (see [`imagecraft/pack/grubutil.py`](file:///home/lengau/Work/Code/imagecraft/imagecraft/pack/grubutil.py#L45-L118)). - -Replacing `grub-install` with `grub-mkimage` and direct asset deployment tailored for EFI devices offers several advantages: - -- Bypasses the need for full chroot mount setups (`/dev`, `/proc`, `/sys`, `/run`). -- Enables cross-architecture bootloader generation directly on the host. -- Provides fine-grained control over embedded modules and configuration stubs. - ---- - -## 2. Shared / Prerequisites Stage: GRUB Asset Deployment - -Before generating boot executables or embedding core images, GRUB runtime assets must be placed on the target root/boot filesystem. - -- [ ] **Create Directory Structure** - - Path: `/boot/grub//` - - `amd64` $\rightarrow$ `/boot/grub/x86_64-efi/` (or `/boot/grub/i386-pc/` for BIOS fallback) - - `arm64` $\rightarrow$ `/boot/grub/arm64-efi/` - - `armhf` $\rightarrow$ `/boot/grub/arm-efi/` - - `riscv64` $\rightarrow$ `/boot/grub/riscv64-efi/` - - Path: `/boot/grub/fonts/` - - Path: `/boot/grub/locale/` - -- [ ] **Copy GRUB Modules (`*.mod`)** - - Source: `/usr/lib/grub//*.mod` - - Destination: `/boot/grub//` - - Purpose: Dynamic module loading during system boot. - -- [ ] **Copy GRUB Metadata & Lookup Lists (`*.lst`)** - - Source files: - - `moddep.lst` (Module dependency map) - - `fs.lst` (Supported filesystems list) - - `partmap.lst` (Supported partition schemes list) - - `parttool.lst`, `command.lst`, `terminal.lst`, `crypto.lst`, `video.lst` - - Destination: `/boot/grub//` - -- [ ] **Copy Fonts & Locales** - - Copy font file (`unicode.pf2`) from `/usr/share/grub/` to `/boot/grub/fonts/`. - - Copy translation catalogs (`*.mo`) from `/usr/share/locale/*/LC_MESSAGES/grub.mo` to `/boot/grub/locale//`. - ---- - -## 3. Ubuntu UEFI Deployment Tasks (`amd64`, `arm64`, `armhf`, `riscv64`) - -In Ubuntu, the vendor boot directory on the EFI System Partition (ESP) is fixed to `/boot/efi/EFI/ubuntu/`. - -### 3.1 Unsigned / Standard UEFI (via `grub-mkimage`) - -- [ ] **Build Standalone EFI Binary with `grub-mkimage`** - - **amd64 (`x86_64-efi`)**: - ```bash - grub-mkimage \ - -d /usr/lib/grub/x86_64-efi \ - -o /tmp/grubx64.efi \ - -O x86_64-efi \ - -p /boot/grub \ - part_gpt part_msdos fat ext2 btrfs xfs normal search search_fs_uuid search_label search_fs_file boot linux configfile echo loadenv test efi_gop gfxterm font - ``` - - **arm64 (`arm64-efi`)**: - ```bash - grub-mkimage \ - -d /usr/lib/grub/arm64-efi \ - -o /tmp/grubaa64.efi \ - -O arm64-efi \ - -p /boot/grub \ - part_gpt part_msdos fat ext2 btrfs xfs normal search search_fs_uuid search_label search_fs_file boot linux configfile echo loadenv test efi_gop gfxterm font devicetree acpi - ``` - - **armhf (`arm-efi`)**: - ```bash - grub-mkimage \ - -d /usr/lib/grub/arm-efi \ - -o /tmp/grubarm.efi \ - -O arm-efi \ - -p /boot/grub \ - part_gpt part_msdos fat ext2 btrfs xfs normal search search_fs_uuid search_label search_fs_file boot linux configfile echo loadenv test efi_gop gfxterm font devicetree - ``` - - **riscv64 (`riscv64-efi`)**: - ```bash - grub-mkimage \ - -d /usr/lib/grub/riscv64-efi \ - -o /tmp/grubriscv64.efi \ - -O riscv64-efi \ - -p /boot/grub \ - part_gpt part_msdos fat ext2 btrfs xfs normal search search_fs_uuid search_label search_fs_file boot linux configfile echo loadenv test efi_gop gfxterm font devicetree - ``` - -- [ ] **Deploy EFI Binary to EFI System Partition (ESP)** - - **amd64 Target Paths**: - - Vendor path: `/boot/efi/EFI/ubuntu/grubx64.efi` - - Fallback / Removable path: `/boot/efi/EFI/BOOT/BOOTX64.EFI` - - **arm64 Target Paths**: - - Vendor path: `/boot/efi/EFI/ubuntu/grubaa64.efi` - - Fallback / Removable path: `/boot/efi/EFI/BOOT/BOOTAA64.EFI` - - **armhf Target Paths**: - - Vendor path: `/boot/efi/EFI/ubuntu/grubarm.efi` - - Fallback / Removable path: `/boot/efi/EFI/BOOT/BOOTARM.EFI` - - **riscv64 Target Paths**: - - Vendor path: `/boot/efi/EFI/ubuntu/grubriscv64.efi` - - Fallback / Removable path: `/boot/efi/EFI/BOOT/BOOTRISCV64.EFI` - ---- - -### 3.2 Secure Boot UEFI (Pre-Signed Canonical Shim + Signed GRUB) - -- [ ] **Copy Pre-Signed Binaries from Ubuntu Packages** - - Do **not** use `grub-mkimage` (custom-built binaries will fail Secure Boot signature verification). - - **amd64 Signed Binaries** (from `shim-signed` & `grub-efi-amd64-signed`): - - Source: `/usr/lib/shim/shimx64.efi.signed` $\rightarrow$ `/boot/efi/EFI/ubuntu/shimx64.efi` (and `/boot/efi/EFI/BOOT/BOOTX64.EFI`) - - Source: `/usr/lib/grub/x86_64-efi-signed/grubx64.efi.signed` $\rightarrow$ `/boot/efi/EFI/ubuntu/grubx64.efi` - - Support files: `/usr/lib/shim/mmx64.efi` & `/usr/lib/shim/fbx64.efi` $\rightarrow$ `/boot/efi/EFI/ubuntu/` - - **arm64 Signed Binaries** (from `shim-signed` & `grub-efi-arm64-signed`): - - Source: `/usr/lib/shim/shimaa64.efi.signed` $\rightarrow$ `/boot/efi/EFI/ubuntu/shimaa64.efi` (and `/boot/efi/EFI/BOOT/BOOTAA64.EFI`) - - Source: `/usr/lib/grub/arm64-efi-signed/grubaa64.efi.signed` $\rightarrow$ `/boot/efi/EFI/ubuntu/grubaa64.efi` - - Support files: `/usr/lib/shim/mmaa64.efi` & `/usr/lib/shim/fbaa64.efi` $\rightarrow$ `/boot/efi/EFI/ubuntu/` - - **armhf and riscv64**: - - _N/A_: Secure Boot is **not supported** for `armhf` or `riscv64` in Ubuntu. Builds always use unsigned binaries generated via `grub-mkimage`. - -- [ ] **Generate Ubuntu ESP Early Load Stub (`/boot/efi/EFI/ubuntu/grub.cfg`)** - - Place Ubuntu's standard 3-line loader config on the ESP alongside the GRUB binary: - ```grub - search.fs_uuid root hd0,gpt2 - set prefix=($root)'/boot/grub' - configfile $prefix/grub.cfg - ``` - ---- - -## 4. Legacy BIOS / MBR (`i386-pc`) Deployment Tasks (amd64 Legacy Devices) - -- [ ] **Build `core.img` via `grub-mkimage`** - - Command template: - ```bash - grub-mkimage \ - -d /usr/lib/grub/i386-pc \ - -o /boot/grub/i386-pc/core.img \ - -O i386-pc \ - -p /boot/grub \ - biosdisk part_msdos part_gpt ext2 fat normal search search_fs_uuid boot linux configfile - ``` - -- [ ] **Copy Stage 1 Boot Sector (`boot.img`)** - - Source: `/usr/lib/grub/i386-pc/boot.img` - - Destination: `/boot/grub/i386-pc/boot.img` - -- [ ] **Install Boot Sector & Sector-Patch `core.img` using `grub-bios-setup`** - - Execute `grub-bios-setup` directly against the loop device without chroot: - ```bash - grub-bios-setup \ - --directory=/mountpoint/boot/grub/i386-pc \ - --device-map=/tmp/device.map \ - /dev/loopX - ``` - - _Note_: Ensure the loop device is attached with partition scanning enabled (`losetup -P`). - ---- - -## 5. Configuration & Cleanup Tasks - -- [ ] **Generate Main Config (`/boot/grub/grub.cfg`)** - - Run `update-grub` / `grub-mkconfig` or generate Ubuntu's standard `grub.cfg` template with kernel command-line arguments and initrd options. - -- [ ] **Refactor `imagecraft/pack/grubutil.py`** - - Remove chroot dependency for GRUB installation on EFI targets. - - Implement architecture dispatcher routing `amd64` (`x86_64-efi`), `arm64` (`arm64-efi`), `armhf` (`arm-efi`), and `riscv64` (`riscv64-efi`) to their respective EFI bootloader binary generation and asset deployment strategies. diff --git a/contributors.html b/contributors.html deleted file mode 100644 index fb87c6f3..00000000 --- a/contributors.html +++ /dev/null @@ -1,566 +0,0 @@ - - - - - -Commits, Changes, and Contributors - - - - - -

Commits, Changes, and Contributors

-

Summary

- - - - - - - - - - - - - - - - - -
projectoldnew
imagecraft0.1.0c5b8dda
craft-application6.1.17.1.0
craft-archives2.2.02.2.0
craft-cli3.2.03.2.0
craft-grammar2.3.02.3.0
craft-parts2.28.02.35.0
craft-platforms0.10.00.10.0
craft-providers3.2.03.7.1
-

imagecraft (0.1.0 → c5b8dda)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
checkheaderPRauthorhash
build(docs): incorporate the latest Sphinx Starter Pack (#275)#275jahn-junior097e5f5
chore: reorder init template (#277)#277jahn-junior0b401fc
style: migrate from overrides library to typing.override (#273)#273Spilsed69e47e0
style: migrate from overrides library to typing.override (#273)#273Spilsed1ffde99
style: migrate from overrides library to typing.override (#273)#273Spilsedefa5479
chore: remove comment fences from GitHub templates (#281)#281medubelko2b37857
docs: add '(overlay)' to the `organize` key description (#278)#278jahn-junior8b961f1
docs: add 'Build an Ubuntu image' tutorial (#287)#287jahn-junior77e1c35
docs: resolve spellcheck errors (#290)#290jahn-junior3f56e9b
ci: fix failing tests (#291)#291smethnani6357854
docs: fix fstab part snippet (#294)#294jahn-juniorbdacaeb
docs: reorder 'imagecraft.yaml' reference (#293)#293jahn-junior314f01d
docs: fix bad link (#296)#296bepriaaf3bb9
docs: remove bounty instructions (#295)#295beprif605cf0
fix(ci): add cargo/rustc symlinks (#297)#297smethnani1f01eb5
feat(volumes): add some more GPT types (#286)#286lengau1547a40
feat: add mmdebstrap plugin (#289)#289smethnani92f26fe
feat: enable override-overlay (#299)#299smethnani6d283be
build(deps): constrain setuptools-scm due to cyclic dependency (#306)#306lengaufca3ff4
build: update requests to 2.33.0 (#308)#308smethnanicbca1c1
test(spread): switch to testing in destructive mode (#302)#302lengauf6aae5e
ci: pack snap using craft-actions (#307)#307lengau3f26a09
build(deps): resolve osvs (#313)#313smethnani10f3370
feat: enable writing to specific sectors of the image (#301)#301lengau9bb5d8a
build: bump cryptography to 46.0.7 (#318)#318smethnani8a390e6
docs: mmdebstrap plugin (#315)#315smethnani8ec3481
build(deps): unpin setuptools-scm (#309)#309beprib1e78bf
docs: add home page content (#317)#317jahn-junior178f32e
build(deps): bump pytest (#321)#321smethnanie1b9241
chore: add doc meta description to pr checklist (#319)#319medubelko8c361be
build(deps): update lxml (#331)#331smethnanieae7ded
ci: initial sync with canonical/copilot-collections (#327)#327mr-cal82bd946
chore: change type checking to use `ty` (#328)#328lengaufc21f39
feat: support 26.04 as a build-base (#322)#322bepribe019b2
feat: snap prepare-image plugins (#320)#320smethnani97670aa
feat(Project): add MBR and hybrid volume schemas (#329)#329lengau805f640
fix(lint): suppress ty (#335)#335smethnanic270f0a
fix(snap-prepare): make keys optional (#332)#332smethnani4fd1b56
docs: update home and landing pages (#339)#339jahn-junior8c865f0
build(deps): use a newer pygit2 on Python 3.14 (#336)#336lengau8f9833b
feat(Lifecycle)!: use craft-application's new plugin groups (#326)#326lengaufc8182b
feat: add support for MBR images (#338)#338lengau47fd939
docs: add uc-prepare plugin (#334)#334smethnanid352f96
fix: clear ty diagnostics for partition-number helpers (#341)#341mwhudson96c4d21
build(deps): bump urllib3 (#344)#344smethnani033c84e
docs: add snap-preseed plugin (#333)#333smethnani7c0a27a
build(deps): bump idna (#346)#346smethnani4bf75c9
feat(plugins): use @ channel separator (#345)#345smethnani3dfacf0
build(deps): bump starlette (#350)#350smethnani920399b
ci: add conditionals for docs-only checks (#352)#352medubelko0104193
fix(mmdebstrap_plugin): unmount lingering mounts (#351)#351smethnanid19c950
docs: incorporate tutorial feedback (#354)#354jahn-junior699cc9e
test: add overlay plugin integration test (#349)#349smethnani494e370
chore: fix indentation in init template (#353)#353jahn-juniord13f4f1
docs: how-to add package repositories (#355)#355smethnani21e65f4
build(deps): bump cryptography and starlette (#357)#357smethnania868324
ci: add code owners (#358)#358mr-cal1a4a25f
ci: add qemu spread suite (#356)#356smethnanibcb343c
docs: describe MBR and hybrid schemas (#359)#359lengau04f04c6
chore: fix linting (#369)#369smethnani5363d6d
docs: add 'Configure instances with cloud-init' (#367)#367jahn-junior9d46133
docs: fix project file for tutorial (#360)#360jahn-junior5f531a4
ci: use openstack for spread (#368)#368smethnani778d8dd
ci: add conditional to snap-builds job steps (#370)#370medubelkoa73afd4
docs: add 'Pre-install snaps' guide (#374)#374jahn-junior297872a
docs: configure for ubuntu.com proxy (#376)#376jahn-junior402d0b8
test: add core boot spread test (#375)#375smethnanic5b8dda
-

craft-application (6.1.1 → 7.1.0)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
checkheaderPRauthorhash
feat: add Ubuntu Pro argument and validation (#438)#438clay-lake825adcc
feat: enable requested ubuntu pro services (#504)#504clay-lakecae9272
fix(pro): fix _check_pro_requirement function to not ignore empty ProServices set (#563)#563clay-lake238304b
Merge branch 'main' into chore/merge-main-with-pro-sourcesn/aunknowneb5755c
fix lint errorsn/aunknown2768bb5
Merge pull request #582 from linostar/chore/merge-main-with-pro-sourcesn/abepri559ec1e
feat: more updates to support Pro Rocks in Rockcraft (#616)#616clay-lakee921232
feat: ensure pro validation does not run on devel basesn/aclay-lake0e804b8
feat: more descriptive text for InvalidUbuntuProBaseErrorn/aclay-laked65d652
fix: move project pro validation to project get methodn/aclay-lake9f98320
fix: remove base used for testing invalid pro basesn/aclay-lake8b853e9
refactor: minor changes for lintingn/aclay-lakea4ace66
docs: fix typo (#992)#992steinbro71490ec
feat(Provider): inject the base snap (#997)#997lengau41cee32
build(deps): bump craft-providers to 3.3.0n/amr-cal9eb4605
test: remove 24.10n/amr-calad9823b
fix(LifecycleService): pull local test files (#1013)#1013mr-calf4a4d28
docs: reference document for the Build Plan Service (#999)#999lengauebbd599
fix(Application): set the plugin group on load (#998)#998lengaub1d70a5
docs: add platform naming snippet (#1012)#1012lengau0ab97a3
docs: add reference document for the ConfigService (#1000)#1000lengau7f1efa4
docs: Reference document for the PackageService (#1002)#1002lengaufc91d41
docs: add 6.2.1 changelog (#1019)#1019lengauaaa9777
docs: Reference document for the Service Factory (#1001)#1001lengaufb2a80b
feat(services/linter): add a linter service (#907)#907HamdaanAliQuatila76bcaa
fix(docs): Unicode has a capital U (#1023)#1023lengau421a445
chore: merge branch 'main' into hotfix-merge/6.2.2n/alengau6005c8d
chore(merge): main into merge/mainn/amr-caleb8ad11
chore(merge): main into feature/pro-sources (#1031)#1031lengau39ed82a
fix(testing): error early if spread.yaml is invalid. (#1029)#1029lengau93c27ec
Merge branch 'main' into hotfix-merge/6.2.2n/alengaua869a9f
chore: merge 6.2.2 into main (#1026)#1026lengaua98e1c3
ci: temporarily disable external fetch service spread test (#1036)#1036lengau790ecaf
ci: run Python tests on arm64 (#1030)#1030lengau944c358
feat: allow building on other compatible architectures (#1027)#1027lengau15f4828
docs: remove bounty instructions (#1043)#1043bepria710d01
feat(ProviderService): don't inject snaps if the host and guest architectures differ (#1037)#1037lengau16bd7ac
chore: finalize Pro support (#1047)#1047mr-cal0455be5
chore: make Pro support opt-in (#1048)#1048mr-calbe206d1
chore(merge): feature/pro-sources into merge/pro-sourcesn/amr-cala66d92b
chore(merge): feature/pro-sources into main (#1050)#1050lengau8c1a7ae
docs(changelog): create changelog for 6.3.0 (#1046)#1046lengau01e7574
fix(deps): Make osv-scanner be quiet. (#1051)#1051lengaufe828e0
build(deps): bump cryptography (#1055)#1055bepridf46c84
fix(pro): fewer errors when checking pro context (#1054)#1054beprib78daa6
build(deps): bump cryptography (#1061)#1061bepri4b0e00a
feat(ProjectService): ban `/` in user-provided part names (#1067)#1067lengau3857782
feat: add a mechanism to add fetch-service secrets (#1066)#1066tigarmof9b01b4
docs: fix changelog entry for 6.4.0 (#1069)#1069mr-cal7b5be5b
build(deps): bump lxml (#1072)#1072smethnanie8c8a38
build(docs)!: add dependency starter pack 1.5 (#1070)#1070medubelko691eec7
fix: handle `--debug` for post-prime failures (#1073)#1073steinbro38fdb68
build(deps): bump idna, urllib3 (#1076)#1076mr-cal80a5847
chore!: remove managed commands (#1077)#1077mr-cale00540d
chore!: remove deprecated APIs (#1078)#1078mr-cal3334f13
docs: fix terminal directive (#1079)#1079jahn-junior28df6ac
fix(application): preserve non-successful return codes (#1068)#1068gcomneno58e0440
feat: expose pro_client_exists and get_pro_services as public methods (#1083)#1083smethnania742213
build: update lockfile (#1085)#1085mr-cal2a6a732
style: replace mypy and pyright with ty (#1084)#1084mr-cal345bd5d
docs: finalize 7.0 changelog (#1087)#1087mr-cale429672
ci: separate flaky tests into their own run (#1088)#1088lengau6d755f0
ci: silence the fast flaky tests (#1090)#1090lengau51736da
ci: update CODEOWNERS (#1095)#1095mr-cal01ee7b2
chore: fix linting (#1099)#1099smethnani4c674c2
build(deps): bump cryptography (#1098)#1098smethnani239b3af
docs: update intersphinx mappings (#1102)#1102lengau80ae974
ci: use openstack for spread (#1091)#1091smethnani826edb3
docs: finalize changelog for 7.0.1 (#1115)#1115tigarmob437eb2
test: enable pro spread tests (#1114)#1114smethnanib768195
feat: add conditional repacking support (#1111)#1111cmatsuoka1dfae60
-

craft-archives (2.2.0 → 2.2.0)

-

No commits

- -

craft-cli (3.2.0 → 3.2.0)

-

No commits

- -

craft-grammar (2.3.0 → 2.3.0)

-

No commits

- -

craft-parts (2.28.0 → 2.35.0)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
checkheaderPRauthorhash
fix: backport uv fix to 2.7n/alengau25d2878
docs(changelog): release 2.7.1n/alengaucaf5e64
style(auto): autoformatn/alengauacf81a0
fix(jlink_plugin): use self.model_dump() (#1426)#1426smethnaniee97b68
test: enable gradle plugin test (#1428)#1428smethnani5244702
build: update urllib3 (#1430)#1430bepri1b60eff
fix(Makefile): remove duplicate install-rustup definition (#1429)#1429smethnani35ad44b
test(gradle_plugin): disable daemon in integration test (#1433)#1433smethnanic5bf8ed
feat(gradle_plugin): add gradle-use-daemon key (#1436)#1436smethnani63d14cf
feat(gradle_plugin): add self-contained attribute support (#1425)#1425smethnanief17116
fix(docs): move gradle-use-daemon to keys section (#1439)#1439smethnani6718d13
fix(docs): Unformatted link in ruby plugin (#1437) (#1440)#1440canon-cat50936fa
feat: add colcon plugin (#1434)#1434Guillaumebeuzeboca713bdd
feat: implement mid-step callbacks (#1441)#1441cmatsuoka6bda793
docs: Release 2.29.0 (#1442)#1442smethnani71291d5
fix(apt_cache): set all candidate versions before marking packages (#1446)#1446EddyPronkcf118b5
ci: fix go_use test (#1455)#1455smethnani1d8d4f8
feat(npm): add self-contained support (#1448)#1448smethnanib654a77
chore(codeowners): remove authors from changelog reviews (#1461)#1461beprif8ce283
test: add test-requires-root (#1463)#1463smethnanib83516a
style: fix linting issues for newer ruff (#1465)#1465lengaua58695e
ci: upgrade flask (#1471)#1471smethnani32c8a63
feat: add override-overlay (#1472)#1472smethnani43dc848
feat: add npm-use (#1462)#1462smethnanica2f22c
fix(git-source): only shallow fetch if a source-depth is provided (#1476)#1476beprif1e2c92
docs: add override-overlay (#1473)#1473smethnani1b2b7d5
fix(ruby): run `gem build` on gems in `build_dir`, not `src_dir` (#1477)#1477atandrewlee0764004
chore(merge): hotfix/2.28 into main (#1481)#1481mr-caldf271d6
docs: fix Ruby plugin docs examples (#1474)#1474steinbroe751706
feat(go-use): error early if go.mod is missing (#1478)#1478atandrewleee5af6aa
feat: allow copying apt sources from host to overlay (#1483)#1483tigarmobedb4c0
chore!: deinit sphinx-docs-starter-pack submodulen/amedubelkof304b45
build(docs)!: update canonical starter pack to 1.4.1n/amedubelko6b0b727
build(deps): update documentation dependenciesn/amedubelko67623b5
build(docs): add passthrough to docs Makefilen/amedubelkof623a5e
docs: update all content for compatibilityn/amedubelko5484f06
docs: add starter pack refresh to changelogn/amedubelkof5c1aa6
docs: update uv plugin reference (#1486)#1486beprif91f0d4
tests: make test_install_slice deterministic across locales (#1496)#1496gcomnenoa832c05
ci(osv-scanner): ignore integration tests (#1498)#1498mr-cal559a7da
build(deps): update core dependencies (#1500)#1500lengauab2a2ee
build(docs): update and clean docs dependencies (#1501)#1501lengau753f204
docs: finalize 2.30.0 (#1499)#1499mr-cala1d1c6b
docs: remove bounty instructions (#1506)#1506beprie2b87f6
fix(poetry): install export plugin on 25.04+ (#1510)#1510bepri6d30ef1
fix: 7z(ip) sources support (#1443) (#1515)#1515canon-catc3aec9c
chore(merge): 2.7.1 into merge/2.7.1n/amr-cal09836a8
chore(merge): 2.7.1 into main (#1520)#1520mr-cald4a0463
fix: handle use_host_sources on OverlayManager.run() (#1524)#1524tigarmodd05222
build(deps): bump pygments (#1529)#1529smethnani5ed85e1
test(cmake_plugin): update version requirement (#1528)#1528smethnani89e8a05
feat: added bazel plugin (#1491)#1491ethandcosta3ac5961
build(deps): update dependency mypy to ~=1.20.0 (#1536)#1536mr-cala053c22
fix(test): enable the java plugin tests on resolute (#1530)#1530beprida6b596
docs: clarify .NET plugin SDK provisioning (#1417)#1417mateusrodrigues58e9ca1
build(Makefile): check for cargo (#1537)#1537mr-calcb31017
feat: organize files from build (#1535)#1535cmatsuoka8e4daf5
docs: prepare 2.31.0 release (#1539)#1539cmatsuoka659aafa
feat(packages/deb): parse chisel manifests (#1538)#1538mr-cal49a8824
revert: feat: organize files from build (#1548)#1548cmatsuoka5628273
docs(changelog): finalize 2.33.0 (#1549)#1549mr-calf593297
docs: add example to dump plugin (#1547)#1547asanvaqfb57e5a
build(deps): bump pytest (#1550)#1550beprie5a6feb
docs: add -i option example to both python plugin versions (#1542)#1542asanvaq88bf5ef
build(deps): bump lxml (#1563)#1563smethnani3495de6
feat: add gradle-use plugin (#1559)#1559smethnanic293ca9
ci: use ubuntu-22.04-arm runners (#1568)#1568lengaua85b434
fix(organize): make organizing to the overlay idempotent (#1541)#1541lengaua117830
docs: rename plugins '* use' -> '*-use' (#1573)#1573medubelkoe848312
fix(organize): allow merging directories in overlay with metadata differences (#1586)#1586lengau0797420
feat(overlay): plugins can define overlay commands (#1567)#1567lengau73d6a98
fix(organize): reject sources outside install dir (#1562)#1562gcomneno32b95b4
docs: fix npm capitalisation (#1565)#1565medubelkocebc4af
ci: separate flaky tests into their own job (#1583)#1583lengauec6458a
docs: correct the 'organize' description (#1582)#1582jahn-juniora769db7
chore: add Copilot collections (#1576)#1576lengau792a0a2
docs: fix headings in 'Overlay step' explanation (#1453)#1453jahn-juniorb6d6d35
fix(state): track override-overlay changes (#1579)#1579gcomneno059b1c0
refactor: use pathlib internally (#1424)#1424EdmilsonRodriguescfdabaf
fix(sources): handle streaming request errors (#1533)#1533gcomnenobbc6f9f
fix(organize): make organize to overlay behavior consistent (#1602)#1602cmatsuoka139cbce
feat(organize): support build pseudo-partition source (#1598)#1598gcomnenocc02958
feat: allow applications to set build environment (#1608)#1608cmatsuoka0f7a4b1
docs: finalize 2.34.0 (#1614)#1614smethnanic2bd58d
build(deps): bump idna + urllib3 (#1615)#1615smethnanidd195de
feat: allow the plus sign in partition names (#1612)#1612cmatsuoka5d5b792
fix: migrate overlay files before running stage or prime (#1617)#1617tigarmo2d81a4b
feat(plugins): allow subclasses to set autoconf parameters (#1616)#1616cmatsuoka5d909cf
-

craft-platforms (0.10.0 → 0.10.0)

-

No commits

- -

craft-providers (3.2.0 → 3.7.1)

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
checkheaderPRauthorhash
feat: acquire pro guest tokens in managed LXD instances (#647)#647unknown10895fd
feat: get Pro status in managed LXD instance (#652)#652unknown6425b68
feat: attach managed instance to pro subscription (#655)#655unknown2bd0ca6
feat: enable pro services on managed LXD instance (#656)#656unknownc511987
feat: install Ubuntu Pro Client in LXD instance (#664)#664unknown09caf83
feat: switch to new guest token endpoint (#673)#673unknown4b64127
Merge branch 'main' into feature/pro-sourcesn/aunknown0d6d855
chore: merge main branch with feature/pro-source branch (#704)#704lengauad55c78
feat: updates to complete feature set for RK042 - Support for Pro Rocks in Rockcraft. (#721)#721clay-lake2e6a559
fix(pro-sources): Inherit Host's `contract_url` (#776)#776clay-lakec46962d
docs: enable Google Analytics (#424)#424jahn-junior37bb2a8
docs: update code of conduct links (#427)#427lengau95945ac
ci: fix publish workflow (#430)#430lengaub42c04a
fix(tests): better typing for tests (#433)#433lengau2262e30
chore: add IDE configs to gitignore (#435)#435bepri5ef1053
feat(Makefile): add ty as an optional linter (#429)#429lengauc2390f0
fix(gitignore): only ignore a top-level parts dir (#441)#441lengau43fa30d
docs: make linkcheck more forgiving (#444)#444lengau9cbbaf5
docs: add `CONTRIBUTING.md` template (#448)#448jahn-juniorebfec44
build(docs): remove line length check from linter (#453)#453medubelkoec0cf32
chore: add documentation items to PR checklist (#463)#463jahn-junior93f3b47
fix(bases): ignore unknown Ubuntu versions in bases check. (#852)#852lengau2707796
chore(test): remove no-op deprecated behavior (#855)#855beprifb68c17
chore: update CODEOWNERS (#837)#837lengaua0967cc
ci: downgrade to macos 14 on most runners (#879)#879lengau262f731
build: bump urllib3 (#869)#869bepri122fd0b
ci: disable Linux ARM64 CI (#883)#883lengau27f833e
refactor: use pylxd to determine if an instance exists (#874)#874bepri48bd685
style: enable type checking with ty (#885)#885lengau28ccfe5
style: enable ty by default (#472)#472lengau7982765
build(docs): make `clean` target scrub `docs/reference/gen` (#477)#477lengau334adfe
build(deps): update canonical starter pack to 1.3.1n/amedubelkoc47c166
build(deps): remove dependency sphinx-toolboxn/amedubelko7ff4723
build(docs): add passthrough to docs Makefilen/amedubelkoe94f190
docs: fix spelling errorsn/amedubelkoa551c9d
feat(pro): use Ubuntu Pro guest attachment (#890)#890tigarmo31c4e58
docs: mandate conventional commits in PR titlesn/amedubelko602d1d0
build(docs): exclude reuse dir (#483)#483medubelko014764d
docs: remove scheduled feature deprecations from rn template (#484)#484medubelkod348aad
docs: add guidance for contribs to rn template (#485)#485medubelkob878f19
build(deps): bump pytest to 9.0n/amr-cale64feb1
style: ignore unused type commentsn/amr-calc1abc9e
fix: retry 'snap watch' (#899)#899mr-cale0f6bc7
build(docs): remove myst check (#488)#488medubelko64374bc
fix(build): use correct autobuild command (#491)#491medubelko22e9ce4
docs: ensure we never delete a "real" file (#492)#492bepri560adbf
build(deps): bump cryptography and urllib3 (#909)#909smethnani922e691
build(deps): remove unused docs dependencies (#490)#490medubelko43c54fa
build(docs): disable vale check (#489)#489medubelko136c2e2
fix(build): false lint errors (#493)#493medubelkob304e0a
style: fix ty error (#910)#910bepri30fc806
build(deps): restore sphinxcontrib-jquery>=4.1 (#494)#494medubelkoc1aab61
chore(merge): main into merge/mainn/amr-calcca0836
chore(merge): main into feature/pro-sources (#913)#913lengauf7edf3d
feat: list all vm instances (#903)#903Aeonoi9ae7664
chore: finalize Pro support (#916)#916mr-cal6545bdb
chore(merge): feature/pro-sources into merge/pro-sourcesn/amr-cal3232836
chore(merge): feature/pro-sources into main (#918)#918mr-calb56ff14
fix: get lsb_release when installing Pron/amr-cal6bb4d0f
docs: finalize 3.4.0n/amr-cal68f1ca3
feat(models): add SnapInfo model for snapd response (#908)#908PraaneshSelvaraje996996
ci: enable integration tests on arm64 (#921)#921lengau55b77b8
feat(LXD): add other-architecture option (#922)#922lengauccb946b
chore: remove comment fences from GitHub templates (#498)#498beprie810141
feat(lint): lint the Github actions with actionlint (#473)#473lengaue385e9d
fix: help formatting when running `make -f common.mk` (#501)#501medubelko0344506
feat: allow disabling eol source updates (#926)#926FinnRGae95427
docs: finalize 3.5.0 (#927)#927mr-caleef0712
build(docs): upgrade Starter Pack to 1.5 (#499)#499jahn-junior8c01792
docs: add 'about this documentation' (#502)#502medubelko80e67c9
build(deps): update dependency sphinx-sitemap to ==2.6.0 (#504)#504medubelko22b81ba
ci(osv-scanner): ignore integration tests (#505)#505mr-cale7954a7
fix(ci): collapse the docs checks in the workflow logs (#508)#508lengau0867e7e
docs: remove bounty instructions (#933)#933bepric399130
fix(multipass): list instances (#930)#930Aeonoi21f3af1
style: ty (#938)#938mr-cal44bcd1a
feat(Provider): add prune method (#925)#925Aeonoi9836260
build(deps): update cryptography, pygments, requests (#940)#940mr-caleb8549f
build(deps): bump pygments (#517)#517bepric9fecdf
docs: block intersphinx lookup for internal links (#519)#519medubelkoa38d79a
docs: format doc version as major.minor (#520)#520medubelko66911da
build(docs): fix double build with docs-lint (#513)#513medubelko1107517
docs: update Starter Pack variables (#523)#523jahn-junior25d7d15
build(deps): bump pytest (#524)#524smethnanie372177
chore: add doc meta description to pr checklist (#521)#521medubelkoa73333a
style(lint): ignore FBT001 and FBT002 in tests (#528)#528lengau829b31f
build: fix docs-install target (#525)#525mr-calb434201
docs: minor clean up and reorg (#529)#529medubelko50567fc
chore: use releases for resolute (#958)#958canon-cat37aa14d
docs: changelog entries for 3.6.0 (#959)#959tigarmo93a61b3
docs: remove bounty instructions (#530)#530beprif7ccae3
fix(ty): point to venv (#534)#534bepricf39b36
build(deps): update lockfile for OSVs (#963)#963lengauf2266ad
fix(lxd/remotes): use release images for plucky (#962)#962lengau92a8243
chore: add copilot-collections (#964)#964lengau742eeb4
feat(models): add SnapdResponse model for snapd Response (#939)#939PraaneshSelvaraj2702b5a
chore(types): enable explicit re-export checking (#966)#966gcomneno6bbb837
build(docs): update Sphinx Stack to 2.0 (#537)#537jahn-juniorfafd1fc
build(deps): bump lxml (#540)#540jahn-junior663c1b4
chore: update Copilot collections to v0.14.0 (#968)#968github-actions[bot]d5462c1
chore: merge the latest starbasen/alengau8fd197d
build(deps): add constraint for Starlette (#972)#972steinbro7ed9c81
chore: merge the latest Starbase (#973)#973lengauaa50a03
fix: raise MultipassError instead of looping forever on dotless version (#952)#952lengauc02b44a
ci: update code owners (#974)#974mr-cal1543896
feat: add support for Ubuntu 26.10 (Stonking) (#956)#956canon-catef04bef
fix: don't fail on unknown ubuntu bases (#980)#980mr-cal628f199
ci: temporarily disable macos smoke tests (#982)#982lengaua3af10b
fix: forward env to lxd instance with Pro methods (#981)#981smethnanib4761be
docs: finalize 3.7.1 (#984)#984smethnani74d275d
-

Contributors

-:literalref:`@Aeonoi <https://github.com/Aeonoi>`,
-:literalref:`@asanvaq <https://github.com/asanvaq>`,
-:literalref:`@atandrewlee <https://github.com/atandrewlee>`,
-:literalref:`@bepri <https://github.com/bepri>`,
-:literalref:`@canon-cat <https://github.com/canon-cat>`,
-:literalref:`@clay-lake <https://github.com/clay-lake>`,
-:literalref:`@cmatsuoka <https://github.com/cmatsuoka>`,
-:literalref:`@EddyPronk <https://github.com/EddyPronk>`,
-:literalref:`@EdmilsonRodrigues <https://github.com/EdmilsonRodrigues>`,
-:literalref:`@ethandcosta <https://github.com/ethandcosta>`,
-:literalref:`@FinnRG <https://github.com/FinnRG>`,
-:literalref:`@gcomneno <https://github.com/gcomneno>`,
-:literalref:`@github-actions[bot] <https://github.com/github-actions[bot]>`,
-:literalref:`@Guillaumebeuzeboc <https://github.com/Guillaumebeuzeboc>`,
-:literalref:`@HamdaanAliQuatil <https://github.com/HamdaanAliQuatil>`,
-:literalref:`@jahn-junior <https://github.com/jahn-junior>`,
-:literalref:`@lengau <https://github.com/lengau>`,
-:literalref:`@mateusrodrigues <https://github.com/mateusrodrigues>`,
-:literalref:`@medubelko <https://github.com/medubelko>`,
-:literalref:`@mr-cal <https://github.com/mr-cal>`,
-:literalref:`@mwhudson <https://github.com/mwhudson>`,
-:literalref:`@PraaneshSelvaraj <https://github.com/PraaneshSelvaraj>`,
-:literalref:`@smethnani <https://github.com/smethnani>`,
-:literalref:`@Spilsed <https://github.com/Spilsed>`,
-:literalref:`@steinbro <https://github.com/steinbro>`,
-:literalref:`@tigarmo <https://github.com/tigarmo>`,
-and :literalref:`@unknown <https://github.com/unknown>`
- - - diff --git a/docs/release-notes/imagecraft-0-2-0.rst b/docs/release-notes/imagecraft-0-2-0.rst deleted file mode 100644 index 34fe46dc..00000000 --- a/docs/release-notes/imagecraft-0-2-0.rst +++ /dev/null @@ -1,120 +0,0 @@ -.. meta:: - :description: Release notes for Imagecraft 0.2.0. - -.. _release-0.2.0: - -Imagecraft 0.2.0 release notes -============================== - -22 July 2026 - -Learn about the new features, changes, and fixes introduced in Imagecraft 0.2.0. - - -Requirements and compatibility ------------------------------- - -Imagecraft 0.2.0 requires Python 3.11 or higher. - - -What's new ----------- - -Imagecraft 0.2.0 brings the following features, integrations, and improvements. - - -Support for MBR and hybrid volume schemas -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Imagecraft now accepts ``mbr`` and ``mbr,gpt`` volume schemas. MBR images are now -supported on x86, and Imagecraft generates the GRUB assets needed for them. - - -Support for snap prepare-image plugins -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Imagecraft now includes ``snap-preseed`` and ``uc-prepare`` plugins for core and -classic images. These plugins make it easier to prepare images that need snap -content or Ubuntu Core setup steps. - - -Support for the mmdebstrap plugin -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Imagecraft now includes an ``mmdebstrap`` plugin for building Debian-derived root -filesystems. - - -Improved boot image generation -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Imagecraft now uses ``grub-mkimage`` asset generation instead of mounting the target -root filesystem and running ``grub-install``. This makes boot asset generation more -reliable during packing. - - -Minor features --------------- - -Imagecraft 0.2.0 brings the following minor changes. - - -Support for writing to specific sectors -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Imagecraft now writes volume data to temporary image files during lifecycle commands, -which lets it place data in specific sectors of the final output image. - - -Support for the ``@`` channel separator -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The ``snap-preseed`` and ``uc-prepare`` plugins now accept ``@`` as the channel -separator, with optional surrounding whitespace. - - -Support for Ubuntu 26.04 as a build base -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Imagecraft now accepts ``ubuntu@26.04`` as a build base. - - -Improved overlay handling -~~~~~~~~~~~~~~~~~~~~~~~~~ - -Imagecraft now enables ``override-overlay`` for image builds. - - -Backwards-incompatible changes ------------------------------- - -The following changes are incompatible with previous versions of Imagecraft. - - -Using the MINIMAL plugin group -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Imagecraft now extends craft-application's ``MINIMAL`` plugin group instead of the -``DEFAULT`` group. If you rely on custom plugin selection, review your setup against -the new plugin grouping behavior. - - -Fixed bugs and issues ---------------------- - -The following issues have been resolved in Imagecraft 0.2.0. - - -* ``snap-prepare`` now treats missing keys as optional instead of failing when they - are absent. -* ``mmdebstrap`` now unmounts lingering mounts after use. - - -Contributors ------------- - -We would like to express a big thank you to all the people who contributed to this -release. - -smethnani, JJ Coldiron, Alex Lowe, Imani Pelton, Michael DuBelko, Spilsed, Callahan -Kovacs, Alex M. Lowe, and Michael Hudson-Doyle. diff --git a/imagecraft.kdev4 b/imagecraft.kdev4 deleted file mode 100644 index 77fc269f..00000000 --- a/imagecraft.kdev4 +++ /dev/null @@ -1,4 +0,0 @@ -[Project] -CreatedFrom= -Manager=KDevCustomBuildSystem -Name=imagecraft From f6ebb0b286ff5d0b686bc20cb918a6763bf8e29c Mon Sep 17 00:00:00 2001 From: "Alex M. Lowe" Date: Mon, 10 Aug 2026 22:18:10 +0000 Subject: [PATCH 13/14] test: update test_lifecycle_args for craft-application ignore_outdated change Pointing craft-application at the work/fix-1152 branch (based on current main) pulls in an unrelated upstream change: LifecycleManager's ignore_outdated now also includes ".spread-reuse.*" to avoid re-pulling sources when spread test files change. Update the expected call to match. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/unit/services/test_lifecycle.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/services/test_lifecycle.py b/tests/unit/services/test_lifecycle.py index 526c6c00..1f0eb029 100644 --- a/tests/unit/services/test_lifecycle.py +++ b/tests/unit/services/test_lifecycle.py @@ -49,7 +49,7 @@ def test_lifecycle_args( cache_dir=Path("cache"), work_dir=Path("work"), ignore_local_sources=[".craft"], - ignore_outdated=[".craft"], + ignore_outdated=[".craft", ".spread-reuse.*"], parallel_build_count=ANY, # Value will vary when tests run locally or in CI project_vars=ProjectVarInfo.unmarshal( { From 79e112319a54397a452891af12407da834e374eb Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Tue, 11 Aug 2026 17:15:02 +0000 Subject: [PATCH 14/14] chore(deps): use released craft-application 7.2, add QEMU timeout grace period - pyproject.toml/uv.lock: switch from the temporary git+work/fix-1152 pin back to a released craft-application~=7.2, which includes the is_effective_base_eol() devel-base fix from canonical/craft-application#1153 (merged and released in 7.2.0). - tests/spread/boot/classic/task.yaml: wrap the QEMU invocation in `timeout -k 10 180` so a hung boot is reliably SIGKILLed after a 10s grace period if it ignores SIGTERM, rather than potentially leaving a hung QEMU process behind (per PR #385 review feedback). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- pyproject.toml | 4 +--- tests/spread/boot/classic/task.yaml | 2 +- uv.lock | 10 +++++++--- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index fd74acf8..7e2502c8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,9 +9,7 @@ dependencies = [ "craft-parts~=2.35.0", "craft-cli~=3.0", "craft-platforms~=0.6", - # TODO: switch back to a released craft-application~=7.1 once - # https://github.com/canonical/craft-application/pull/1153 is merged and released. - "craft-application @ git+https://github.com/canonical/craft-application@work/fix-1152", + "craft-application~=7.2", "craft-grammar~=2.3", "craft-providers~=3.7", "pydantic~=2.8", diff --git a/tests/spread/boot/classic/task.yaml b/tests/spread/boot/classic/task.yaml index 3c72e16c..812e3f87 100644 --- a/tests/spread/boot/classic/task.yaml +++ b/tests/spread/boot/classic/task.yaml @@ -33,7 +33,7 @@ execute: | fi cp "$UEFI_VARS" /tmp/uefi_vars.fd - script -q -c "$QEMU_BIN \ + script -q -c "timeout -k 10 180 $QEMU_BIN \ $QEMU_ARGS \ -accel kvm -accel tcg,thread=multi \ -smp \"\$(nproc)\" \ diff --git a/uv.lock b/uv.lock index 04a0b9f1..cc3ad979 100644 --- a/uv.lock +++ b/uv.lock @@ -434,8 +434,8 @@ toml = [ [[package]] name = "craft-application" -version = "7.1.0.post25+g1da0cb1" -source = { git = "https://github.com/canonical/craft-application?rev=work%2Ffix-1152#1da0cb12ad4b66c962d5e5c2143060c0e895d093" } +version = "7.2.0" +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types" }, { name = "craft-archives" }, @@ -457,6 +457,10 @@ dependencies = [ { name = "snap-http" }, { name = "typing-extensions" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/e4/aa/592be376d6b4c066bb7bff882179478d07287c1fc65e81bdef32e0f1f514/craft_application-7.2.0.tar.gz", hash = "sha256:182646ef7febe78e1241b393f6cf2b21ec2a3dd00596d323f85c59c3bc705e11", size = 711407, upload-time = "2026-08-11T16:50:12.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/02/c8bb8ec7af9a9c1f7775fc5f8b4174b2ca045b7e5a2a5402fec0d7243792/craft_application-7.2.0-py3-none-any.whl", hash = "sha256:ca0e068f56137b1bb117a0ae92da84db0a9d59360f95106582c7881acb95ec61", size = 212573, upload-time = "2026-08-11T16:50:10.454Z" }, +] [[package]] name = "craft-archives" @@ -806,7 +810,7 @@ types = [ [package.metadata] requires-dist = [ - { name = "craft-application", git = "https://github.com/canonical/craft-application?rev=work%2Ffix-1152" }, + { name = "craft-application", specifier = "~=7.2" }, { name = "craft-cli", specifier = "~=3.0" }, { name = "craft-grammar", specifier = "~=2.3" }, { name = "craft-parts", specifier = "~=2.35.0" },