Daan De Meyer [Sat, 14 Feb 2026 21:37:43 +0000 (22:37 +0100)]
Look at all CacheOnly= settings to determine if we need to sync metadata
Instead of only looking at the CacheOnly= setting of the main image,
let's allow subimages to also configure it to instruct whether repository
metadata should be synced for that image or not.
Also, let's change the behavior of "auto". Currently, we don't sync
repository metadata as long as we have a cached image. The idea behind
this was to avoid weird problems when installing packages in postinst
scripts or such that would see newer repository metadata than the repository
metadata that the image was built with.
While this still holds, the problem with the current approach is that
for regular uses, the default initrd will always have a cache and as such,
even when the main image is out-of-date, we still won't sync repository metadata,
eventually resulting in the repository metadata being so out of date that
the packages can't be found in the mirrors anymore.
The latter is much more likely to happen than the former, so let's sync
repository metadata every time we have any image that does not have a cache.
The user now has the option to customize the behavior per image if they don't
like the default behavior.
Gregory Price [Fri, 23 Jan 2026 19:48:09 +0000 (14:48 -0500)]
config / qemu: add Console=headless
Add a headless option for Console so automation can run the qemu
instance in a background task. In the current modes, qemu just
exits on boot because the console has nothing to attach to.
vmspawn does not support headless for now, just die if this is set.
Turns out using python3.12 on CentOS causes more issues than
we thought it would, so let's revert the move to python 3.9.
Instead, we'll conditionally import Union in sandbox.py only on
python 3.9 and use the Union operator otherwise.
Daan De Meyer [Fri, 13 Feb 2026 20:34:48 +0000 (21:34 +0100)]
Rework sandbox globbing and exist checks
Using bash to glob in the sandbox is rather primitive. Let's do better
by taking advantage of the fact that we can run mkosi-sandbox without
executing another binary. We beef up fork_and_wait() to allow passing
in a sandbox and use a pipe to send the pickled result of the target
function back to the parent process so we can return it from
fork_and_wait(). This allows us to rewrite glob_in_sandbox() and
exists_in_sandbox() to be much simpler.
At the same time, make sure we show proper stacktraces when using
uncaught_exception_handler() after fork. To achieve this, we have to
make sure it logs all frames, including the parent's ones, as we have
to log the exception from the forked process as we can't pickle exceptions
and send them to the parent.
Additionally, try to populate the line cache as early as possible as
we might not be able to access source files after sandboxing ourselves.
While we're at it, we switch _preexec() over to using
uncaught_exception_handler() as well.
Clayton Craft [Sat, 14 Feb 2026 01:02:47 +0000 (17:02 -0800)]
tests: fix running pytest on undetected distro
63ae86e changed detect_distribution so that if it can't find the
distribution it now just returns the string instead of returning None.
This breaks conftest.py when trying to run tests on a distribution
that's not detected (e.g. when packaging mkosi for Alpine Linux)
Daan De Meyer [Fri, 13 Feb 2026 16:05:40 +0000 (17:05 +0100)]
Don't build default initrd for directory images by default
We switched this around a long time ago to accomodate virtiofsd qemu
boots as those needed an initrd without the image necessarily being
bootable. Given Fedora and Arch now allow for direct kernel boot with
virtiofsd without needing an initrd, let's switch back the default to
not building an initrd for directory images, so that the same config
can be used to build disk images for vm boot and directory images for
container boot without having to build the initrd when building directory
images.
Daan De Meyer [Fri, 13 Feb 2026 16:01:44 +0000 (17:01 +0100)]
Add Incremental=relaxed
In systemd, we have some test subimages that we want to build once
and keep intact instead of constantly rebuilding them. Let's add
Incremental=relaxed which will only remove the outputs from those
images if -ff is used and not a regular -f.
Daan De Meyer [Fri, 13 Feb 2026 15:56:03 +0000 (16:56 +0100)]
Only copy out initrds if we have any
Now that we don't build the default initrd on demand anymore, there's
nothing to copy out if no initrds are configured, so don't try to copy
anything out in that case.
Daan De Meyer [Fri, 13 Feb 2026 08:02:47 +0000 (09:02 +0100)]
config: Make sure we write finalized values into the history
Otherwise if we specify e.g. --package-directories= on the command
line it'll get written as None into the history and won't get parsed
properly by Config.from_partial_json().
Daan De Meyer [Fri, 13 Feb 2026 08:01:03 +0000 (09:01 +0100)]
config: Make sure we handle empty lists from history properly
If we get an empty list from the history, that means the empty string
was specified on the cli, and hence we should treat it as a reset (by
setting the xxx_was_none field in the dict same as we would when parsing
it from the cli).
Note that we only need to do this for list based settings as regular
values will just have their default value written into the history.
Daan De Meyer [Wed, 11 Feb 2026 19:39:33 +0000 (20:39 +0100)]
Bump minimum python version to 3.10
- CentOS Stream 9 has python 3.9 by default, but python 3.12 is packaged
- Ubuntu Jammy has python 3.10.
So we'll require CentOS Stream 9 users to install the python3.12
package to keep using mkosi, which shouldn't be a problem.
Bumping version allows us to switch to the Union operator among other
improvements. This commit gets rid of Union and Optional, we'll adopt
other 3.10 features later.
Kai Lüke [Fri, 23 Jan 2026 15:12:40 +0000 (16:12 +0100)]
Support resizing output image
When the final image does not contain the rootfs it must be grown before
being able to boot it. Since the exact size to grow is not easily known
to the user, it's best if the image is already grown to the right size.
Also, when flashing to disk it helps to have the image be the minimum
size needed because otherwise flashing on a too small disk succeeds but
boot will fail. With the right image size it's easier for the user to
know whether the disk is large enough.
Daan De Meyer [Thu, 5 Feb 2026 09:29:38 +0000 (10:29 +0100)]
fedora: Use N-1 key as well when querying rawhide GPG key
We now run into the opposite problem where distribution-gpg-keys is
updated before rawhide is updated, so query the N-1 key as well to
avoid issues in the other direction.
Luca Boccassi [Wed, 28 Jan 2026 22:43:21 +0000 (22:43 +0000)]
Add MakeScriptsExecutable= setting to optionally try to make scripts executable before bailing out
If it fails, it was going to die() anyway.
OBS sources defined inline (ie, not in a tarball) cannot have the mode preserved,
so it's not possible to have mkosi.build or so as a bare script
in an OBS project, one needs to tar it up and extract it again later,
which means it cannot be edited by the inline editor, which is very
convenient for small and trivial builds like an addon.
Daan De Meyer [Wed, 21 Jan 2026 09:05:24 +0000 (10:05 +0100)]
rpm: Set pkgverify_level to digest
This was changed to all in rpm 6.0.0, which means that rpm is checking
for signatures from dnf/zypper repos that have gpgcheck=0. dnf5 was updated
to deal with this but for some reason the fix isn't working in Arch and zypper
doesn't deal with this at all, so revert back to the previous level until
package managers can actually deal with this.
Daan De Meyer [Tue, 20 Jan 2026 18:25:35 +0000 (19:25 +0100)]
dnf: Give advanced users some control over plugins
Let's add some environment variables to control plugins for cases
where users have some dnf plugin they can't touch on their host system
which doesn't behave properly in mkosi-sandbox and which they can't
remove themselves.
Daan De Meyer [Sun, 18 Jan 2026 10:53:30 +0000 (11:53 +0100)]
Allow specifying "default" value for Initrds=
Also use it as the default value for Initrds= when we decide a default
initrd is needed. This allows both using the default initrd alongside
other initrds as well as disabling building the default initrd by assigning
the empty string to Initrds=.
Daan De Meyer [Thu, 15 Jan 2026 12:13:04 +0000 (13:13 +0100)]
opensuse: More GPG key handling fixes
- Pass GPG keys to rpm --import as paths inside the sandbox. This
makes sure that overrides from mkosi.sandbox are taken into account.
e.g. atm we pass mkosi.tools/usr/share/distribution-gpg-keys/... whereas
now we pass /usr/share/distribution-gpg-keys/...
- Make sure we figure out keys once when using zypper. zypper downloads
GPG keys (when fetching is enabled) when refreshing repositories. These
keys are stored in the rpm database in the temporary root we use when
syncing repository metadata. To make sure they are not lost, we extract
the keys using rpmkeys and store them in the keyring directory which we
use from then onwards. For all image builds we then simply import the
keys from the keyring directory.
Daan De Meyer [Wed, 14 Jan 2026 18:24:05 +0000 (19:24 +0100)]
opensuse: Import GPG keys downloaded by zypper as well
When syncing repository metadata, zypper will download keys if
--gpg-auto-import-keys is specified. When installing packages, we need
to make sure these keys are imported into the rpmdb as well.
DaanDeMeyer [Thu, 8 Jan 2026 17:06:16 +0000 (18:06 +0100)]
Make sure we pass the right context to finalize_default_initrd()
We mess around with the context object to make it for for use when
reading the subimages. But we need the full context again for parsing
the default initrd later on, so make a copy before we delete stuff and
pass that to finalize_default_initrd()
DaanDeMeyer [Tue, 6 Jan 2026 20:29:04 +0000 (21:29 +0100)]
Stop running auxiliary programs in systemd scopes
Similar to the same change made in systemd-vmspawn, let's stop running
virtiofsd, systemd-journal-remote and swtpm in scopes. Nobody ever makes
use of the features this provides and it simplifies our code quite a bit.
This also means we drop the UnitProperties setting, which was effectively
unused anyway.
This allows us to get rid of the --suspend setting in mkosi-sandbox, which
only really existed to allow waiting for systemd-run to finish its setup
before registering the machine. Because registering a machine means it needs
a cgroup, we allow systemd-machined to create the scope itself if needed.
DaanDeMeyer [Mon, 29 Dec 2025 18:54:01 +0000 (19:54 +0100)]
nixos: Use repository key fetching by default on nixos
nixos generally won't have any keys in the expected locations so let's
use repository key fetching by default if we're building from a nixos
host (or tools tree).
Maximilian Bosch [Mon, 29 Dec 2025 17:06:18 +0000 (18:06 +0100)]
mkosi/run: pass through LD_LIBRARY_PATH
The sandbox expects that the host has a `libseccomp.so` in its global
search-path (usually `/usr/lib`). However, that path doesn't exist on
NixOS. Another standard way of passing lookup paths to `dlopen()` is
using LD_LIBRARY_PATH which is now passed through to the sandbox.
Maximilian Bosch [Mon, 29 Dec 2025 17:04:21 +0000 (18:04 +0100)]
treewide: use `/usr/bin/env bash` instead of `/bin/bash` as shebang
E.g. NixOS doesn't have a `/bin/bash` and some of the scripts are seemingly
running inside the host's context. Hence, use the more cautious variant of
`/usr/bin/env bash` and just do it everywhere for consistency.
DaanDeMeyer [Sat, 27 Dec 2025 12:00:28 +0000 (13:00 +0100)]
docs: Update unprivileged user namespace docs
Let's not recommend fiddling around with apparmor profiles, but
instead recommend enabling unprivileged user namespaces unconditionally.
Users that care about security can figure out apparmor profiles on their own.
Also reorder and reword the REQUIREMENTS section in general.
DaanDeMeyer [Fri, 26 Dec 2025 09:55:24 +0000 (10:55 +0100)]
arch: Download archlinux-keyring with pacman
curl-ing the Arch Linux website fails quite often due to connection
issues. Let's try downloading the archlinux-keyring package with
Pacman so we go directly to a mirror and avoid hitting the Arch
Linux website.
DaanDeMeyer [Thu, 25 Dec 2025 20:41:11 +0000 (21:41 +0100)]
kmod: Reorder ko extension list
It's unsure whether python uses a hash based lookup for this or not,
so let's list the most commonly expected extensions first. Kernel
modules tend to be compressed these days, so those are the ones we
list first, with preference to zstd and xz.
DaanDeMeyer [Thu, 25 Dec 2025 19:48:47 +0000 (20:48 +0100)]
kmod: Stop retrieving dependency info of all modules
Instead of running modinfo once to retrieve the dependency information
of all modules, let's only retrieve the dependency information of the
modules that are to be included in the image and their transitive
dependencies. This means we have to run modinfo multiple times, but with
far fewer modules than before. This ends up being faster than retrieving
the dependency information of all modules, especially after the optimization
from e276dac87a530efac4376a5059b980f2d43460f5.
For the mkosi default image build on Arch Linux this reduces the time for
calculating the required kernel modules and firmware on my laptop from 5s
to 0.5s.
Robert Sturla [Thu, 25 Dec 2025 18:02:13 +0000 (18:02 +0000)]
compressor_command: Use gzip -n for reproducible output
The gzip format includes an MTIME field in its header that stores the
modification time of the original file. This causes compressed archives
to differ between builds even when the uncompressed content is identical.
Add the --no-name flag to gzip which suppresses storing the original
filename and timestamp, making gzip output reproducible.
Robert Sturla [Thu, 25 Dec 2025 18:00:22 +0000 (18:00 +0000)]
build_microcode_initrd: Normalize timestamps for reproducible builds
When building the microcode initrd, files are created in a temporary
directory with current timestamps. These timestamps are then embedded
in the CPIO archive, causing non-reproducible builds even when
SourceDateEpoch is set.
Fix this by normalizing the modification times of all files in the
microcode root directory to source_date_epoch before creating the
CPIO archive.
DaanDeMeyer [Wed, 24 Dec 2025 10:53:57 +0000 (11:53 +0100)]
Fix --debug-shell
While we're at it, let's save ourselves from having to reason about
Python's capture rules for nested functions by moving _preexec() out
of spawn() and passing in arguments via functools.partial().
DaanDeMeyer [Wed, 24 Dec 2025 10:35:32 +0000 (11:35 +0100)]
sandbox: Drop --proc
This is trivially replaced with --bind /proc $DST, so let's drop the
separate option. Maybe in the future we'll add --proc back but have it
actually mount a new procfs instance.