You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
image-builder: fail loudly for UKI bootc images with root on LVM or btrfs from a disk customization #24
Follow-up to cgwalters-forge/image-builder#1 and /pull/2. A UKI image has no root= karg, so the initrd finds / only via systemd-gpt-auto-generator and the DPS root partition type. btrfs and LVM root volumes from a blueprint disk customization get the generic Linux data type in pkg/disk (NewCustomPartitionTable), and LVM root isn't discoverable at all, so such images don't boot. Make it an error next to PR 2's checkUnifiedKernelCustomizations (or give btrfs the DPS root type in pkg/disk, and reject LVM/LUKS root for UKI).
Still valid and still open on upstream main; the fix is already written in fork PR 5 and only needs rebasing onto upstream main and promoting. Nothing in this run changes code.
What the code does today (osbuild/image-builder main at f43ddf4e, 21 Oct 2026)
#2719 (merged 28 Sep, the promoted fork PR 1) sets the DPS root type only on the / partition of the default table: bootc_imagetype.go#L938-L958. A disk customization builds a new table with NewCustomPartitionTable, where a plain / gets the DPS root type (partition_table.go#L1611-L1627) but a btrfs volume gets generic Linux data (#L1763-L1767) and an LVM VG gets the LVM type (#L1727-L1733), with / behind a layer gpt-auto cannot see. Upstream's own merged test records this: the disk-btrfs-root case in TestGenPartitionTableUnifiedKernel expects the generic type, with a comment saying so (bootc_image_test.go#L426-L443). The code also still carries the note XXX: not setting/defaults will fail to boot with btrfs/lvm (#L1048-L1056).
No check rejects these. #2730 (merged 7 Oct, supakeen) replaced fork PR 2's checkUnifiedKernelCustomizations with a supported-options list, and that list allows customizations.disk for UKI images (#L168), so a blueprint with a btrfs or LVM root passes validation and builds a disk the initrd cannot boot.
One more case than the issue names: when the container's default filesystem is btrfs, ensureBtrfs does give the partition the DPS root type (partition_table.go#L987) but puts / in a root subvolume; the org.osbuild.btrfs.subvol stage has no default-subvolume option (btrfs_subvol_stage.go) and a UKI has no rootflags=, so gpt-auto mounts the top level.
Reproducibility: confirmed by reading the code paths above and upstream's merged test; I did not boot an image this run. That such disks fail follows from how systemd-gpt-auto-generator finds /, and the boot test in fork PR 1 (emergency mode with the generic type, running system with the DPS type) showed gpt-auto is what finds it.
The fix already exists
cgwalters-forge/image-builder#5 (draft since 26 Sep, no review) adds checkUnifiedKernelRoot in its last commit 169b40c0: +84 lines in bootc_imagetype.go, +106 lines of tests (TestManifestUnifiedKernelRootLayout). It fails the manifest with a message saying what to change for LVM root, btrfs-subvolume root (both from a disk customization and from a btrfs default fs, pointing at --bootc-default-fs / --rootfs), a DOS table, and a non-DPS part_type; it allows LUKS directly on the DPS root partition (gpt-auto handles that), and skips layouts that come from the container. Its go test passed and manifest checksums were unchanged; it was not boot-tested. It is stacked on PR 2, but the commit itself only uses APIs on upstream main (disk.RootPartitionTypeGUID, ForEachMountable, the BootcDistro fields), so it cherry-picks onto main alone; the hook point manifestForDisk still calls genPartitionTable at #L317.
Why it has not moved: PR 5's /promote flow was homegit's bot-pr, which docs/homegit-freeze.md lists as dropped, and .github/agentic-job/dispatch.toml lists neither cgwalters-forge/image-builder nor osbuild/image-builder, so no run here can target it.
The issue says reject LUKS too; PR 5 allows LUKS directly on the root partition. gpt-auto supports that, so I would keep PR 5's behaviour unless upstream disagrees.
The alternative in the issue (give btrfs the DPS type) also needs a default subvolume or rootflags=, which means osbuild stage work; it is a possible later PR, not this one.
Precondition for the operator (one step)
Add cgwalters-forge/image-builder to repos in dispatch.toml, like the composefs-rs and bootc forks (staged PRs only, promoted upstream by hand). The fork has issues disabled, so the plan names PR 5 as its item; if dispatch refuses a pull request number for an implement run, enable issues on the fork, mirror this item there and edit item. Alternatively, cherry-pick 169b40c0 onto upstream main and open it on osbuild/image-builder by hand; it is self-contained.
Job plan
{
"schema": "agent-board/job-plan/v1",
"repo": "cgwalters-forge/image-builder",
"item": 5,
"kind": "implement",
"runner": "hosted",
"brief": "Follow-up to osbuild/image-builder#2719 for cgwalters-forge/tracker#24: make the manifest fail for bootc containers with a unified kernel (UKI) whose / the initrd cannot find. A UKI command line has no root=, so systemd-gpt-auto-generator finds / only by the DPS root partition type on a GPT partition; LVM roots, btrfs-subvolume roots (from customizations.disk, or from a btrfs default root fs, since the btrfs.subvol stage sets no default subvolume and there is no rootflags=), DOS tables and non-DPS part_type values build disks that drop to emergency mode. Today nothing rejects them: see the disk-btrfs-root case of TestGenPartitionTableUnifiedKernel and the 'XXX: not setting/defaults will fail to boot with btrfs/lvm' comment in pkg/distro/defs/bootc_imagetype.go.\n\nDo it as one PR on a branch from the fork's main, which must match osbuild/image-builder main (fetch upstream main if the fork is behind):\n1. Cherry-pick only the last commit of branch bot/bootc-uki-root-layout, 169b40c095d44c8cb1def576b9a0eafd18328d04 (fork PR 5: checkUnifiedKernelRoot plus TestManifestUnifiedKernelRootLayout). Do not take PR 5's other commits: upstream #2719 merged the DPS/XBOOTLDR ones and #2730 replaced PR 2's checkUnifiedKernelCustomizations with the supported-options list. Fix the conflict in bootc_imagetype.go by hand: hook the check right after genPartitionTable in manifestForDisk, and check whether the other genPartitionTable caller in the same file needs it too.\n2. Keep PR 5's behaviour: error for LVM root, btrfs-subvolume root (special message for a btrfs default fs naming --bootc-default-fs and --rootfs), non-GPT table and a non-DPS part_type; allow LUKS directly on the DPS root partition; skip layouts that come from the container (its partition table or disk.yaml customizations). Add a disk-lvm-root test case if the ported test lacks one, and update the now-stale comments: the XXX in genPartitionTableDiskCust and the genericRootType comment in TestGenPartitionTableUnifiedKernel.\n3. Tests: go test ./pkg/distro/defs/... ./pkg/disk/... ./pkg/manifestgen/... ./pkg/image/... ./cmd/image-builder/... (the cmd tests that fail on chcon in a rootless container also fail on main; say so). Run tools/gen-manifest-checksums.sh and confirm no checksum changes, since no test config has a UKI. No boot test is possible in this run; say so in the PR.\n4. PR description for upstream reviewers: what fails today and why (gpt-auto), the exact error texts, what is still allowed, and that it does not change any manifest. Reference osbuild/image-builder#2719 and #2337. Do not rebase after opening unless there is a conflict (supakeen asked this on #2719).\nOut of scope: giving btrfs the DPS type with a default subvolume or rootflags, which needs osbuild stage changes.\n\n**Note on secret-shaped strings.** Never write a literal secret-shaped string (`sk-ant-...`, `sk-...`, `ghp_...`, `github_pat_...`, AWS keys, private-key blocks) into code, tests, fixtures or docs. Where a test needs a key-shaped value, build it at run time from parts, or use an obviously fake value such as `test-key-not-secret`. Grep your diff for these patterns before you hand back.\n"
}
Activity
cgwalters-bot commentedon Oct 22, 2026
✅ dispatch ended well. Result: #24 (comment)
cgwalters-bot commentedon Oct 22, 2026
Still valid and still open on upstream main; the fix is already written in fork PR 5 and only needs rebasing onto upstream main and promoting. Nothing in this run changes code.
What the code does today (osbuild/image-builder main at f43ddf4e, 21 Oct 2026)
/partition of the default table: bootc_imagetype.go#L938-L958. A disk customization builds a new table withNewCustomPartitionTable, where a plain/gets the DPS root type (partition_table.go#L1611-L1627) but a btrfs volume gets generic Linux data (#L1763-L1767) and an LVM VG gets the LVM type (#L1727-L1733), with/behind a layer gpt-auto cannot see. Upstream's own merged test records this: thedisk-btrfs-rootcase inTestGenPartitionTableUnifiedKernelexpects the generic type, with a comment saying so (bootc_image_test.go#L426-L443). The code also still carries the noteXXX: not setting/defaults will fail to boot with btrfs/lvm(#L1048-L1056).checkUnifiedKernelCustomizationswith a supported-options list, and that list allowscustomizations.diskfor UKI images (#L168), so a blueprint with a btrfs or LVM root passes validation and builds a disk the initrd cannot boot.ensureBtrfsdoes give the partition the DPS root type (partition_table.go#L987) but puts/in arootsubvolume; theorg.osbuild.btrfs.subvolstage has no default-subvolume option (btrfs_subvol_stage.go) and a UKI has norootflags=, so gpt-auto mounts the top level.Reproducibility: confirmed by reading the code paths above and upstream's merged test; I did not boot an image this run. That such disks fail follows from how systemd-gpt-auto-generator finds
/, and the boot test in fork PR 1 (emergency mode with the generic type, running system with the DPS type) showed gpt-auto is what finds it.The fix already exists
cgwalters-forge/image-builder#5 (draft since 26 Sep, no review) adds
checkUnifiedKernelRootin its last commit 169b40c0: +84 lines inbootc_imagetype.go, +106 lines of tests (TestManifestUnifiedKernelRootLayout). It fails the manifest with a message saying what to change for LVM root, btrfs-subvolume root (both from a disk customization and from a btrfs default fs, pointing at--bootc-default-fs/--rootfs), a DOS table, and a non-DPSpart_type; it allows LUKS directly on the DPS root partition (gpt-auto handles that), and skips layouts that come from the container. Itsgo testpassed and manifest checksums were unchanged; it was not boot-tested. It is stacked on PR 2, but the commit itself only uses APIs on upstream main (disk.RootPartitionTypeGUID,ForEachMountable, theBootcDistrofields), so it cherry-picks onto main alone; the hook pointmanifestForDiskstill callsgenPartitionTableat #L317.Why it has not moved: PR 5's
/promoteflow was homegit'sbot-pr, which docs/homegit-freeze.md lists as dropped, and.github/agentic-job/dispatch.tomllists neithercgwalters-forge/image-buildernorosbuild/image-builder, so no run here can target it.Unclear
rootflags=, which means osbuild stage work; it is a possible later PR, not this one.Precondition for the operator (one step)
Add
cgwalters-forge/image-buildertoreposindispatch.toml, like the composefs-rs and bootc forks (staged PRs only, promoted upstream by hand). The fork has issues disabled, so the plan names PR 5 as its item; if dispatch refuses a pull request number for an implement run, enable issues on the fork, mirror this item there and edititem. Alternatively, cherry-pick 169b40c0 onto upstream main and open it on osbuild/image-builder by hand; it is self-contained.Job plan
Generated-by: https://github.com/cgwalters/#llms