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).
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.
DaanDeMeyer [Wed, 24 Dec 2025 08:35:39 +0000 (09:35 +0100)]
run: Remove hack to keep packed file descriptors intact
Now that we execute execvp() in the preexec function and therefore
skip python's close file descriptors logic, we don't need our hack
anymore to tell python the right file descriptors to close so let's
drop it.
DaanDeMeyer [Tue, 23 Dec 2025 16:17:01 +0000 (17:17 +0100)]
run: Call execvpe() from preexec function
Python does its own executable lookup in $PATH before executing the preexec function, and
hence before we have set up the sandbox which influences the lookup results. To get around
that, let's call execvpe() ourselves inside the preexec() function, and not give Python the
chance to do it itself. This ensures we can do the proper executable lookup after setting
up the sandbox. If we can't find the executable, do nothing, and let Python do its own
search logic so it can return a proper error, which we cannot do from the preexec function.
Note that by doing this we also skip Python closing all open file descriptors except the
ones specified by the user in pass_fds, but since Python opens all file descriptors with
O_CLOEXEC anyway, we'll assume we're good and don't need to close open file descriptors
explicitly.
DaanDeMeyer [Mon, 22 Dec 2025 19:33:08 +0000 (20:33 +0100)]
Configure pyright included files
Let's configure the files on which pyright should run to avoid long
startup times where it tries to check every single file in the workspace
directory.
Daan De Meyer [Mon, 22 Dec 2025 13:54:52 +0000 (14:54 +0100)]
qemu: Register with systemd-machined in user session
Now that machine registration works unprivileged
since systemd v259, let's switch to unconditionally
registering machines with the user session
systemd-machined instance.
This breaks compat but the previous implementation
arguably wasn't useful or used, since registration
would only be done when running as root or if the
Register= feature was explicitly enabled. And if
not running as root, you'd have to authenticate
every time when booting the image to register it
which is arguably too annoying that anyone actually
bothered with it.
As vmspawn doesn't yet support registering with the
user machined instance, we stop registering vmspawn
machines for now. https://github.com/systemd/systemd/pull/40185
will add support for user machined regisration to
vmspawn.
For nspawn we stick with system machined registration
for now.
Daan De Meyer [Fri, 19 Dec 2025 20:02:30 +0000 (21:02 +0100)]
Cache hwdb step
Running hwdb takes roughly a second and is
unlikely to ever rely on files added by extra
trees or such, so let's cache the step instead of
re-running it every single time.
distribution: do not default to release=VERSION_ID for openSUSE Tumbleweed
`config_default_release()` calls `detect_distribution()` to get the default
release if it's not set, which picks the value from os-release's `VERSION_ID`.
In openSUSE Tumbleweed this property has the snapshot number. Since
`mkosi-initrd` does not set `Release=` via config, mkosi thinks that it's Leap
and fails:
```
$ mkosi-initrd
‣ Validating certificates and keys
‣ Building main image
‣ Copying in sandbox trees…
‣ Installing openSUSE
Warning: Enforced setting: $releasever=20251217
Loading repository data...
Reading installed packages...
'Leap-release' not found in package names. Trying capabilities.
No provider of 'Leap-release' found.
‣ "zypper --installroot=/buildroot --cache-dir=/var/cache/zypp --non-interactive --no-refresh --releasever=20251217 --no-gpg-checks install --download in-advance --no-recommends --force-resolution filesystem Leap-release" returned non-zero exit code 104.
‣ "mkosi --force --directory= --format=cpio --output=initrd --output-directory=/tmp/tmpcvx9let7 --extra-tree=/usr/lib/modules/6.17.0-2-default:/usr/lib/modules/6.17.0-2-default --extra-tree=/usr/lib/firmware:/usr/lib/firmware '--remove-files=/usr/lib/firmware/*-ucode' --build-sources= --include=mkosi-initrd --kernel-modules=host --extra-tree=/usr/lib/modules/6.17.0-1-default/updates/hdaps.ko:/usr/lib/modules/6.17.0-1-default/updates/hdaps.ko --extra-tree=/usr/lib/modules/6.17.0-1-default/updates/thinkpad_ec.ko:/usr/lib/modules/6.17.0-1-default/updates/thinkpad_ec.ko --extra-tree=/usr/lib/modules/6.17.0-1-default/updates/tp_smapi.ko:/usr/lib/modules/6.17.0-1-default/updates/tp_smapi.ko --package-cache-dir=/var --cache-only=metadata --output-mode=600 --include /usr/lib/mkosi-initrd --include /etc/mkosi-initrd --sandbox-tree=/tmp/tmp0tjr7mwr --extra-tree=/etc/vconsole.conf:/etc/vconsole.conf" returned non-zero exit code 104.
```
Luca Boccassi [Wed, 17 Dec 2025 20:38:46 +0000 (20:38 +0000)]
mkosi-addon: drop Output=addon, addon.py already has a default
addon.py already passes mkosi-local.addon.efi by default if nothing
else is given, so it's not necessary to override it here. And it makes
it impossible to give custom names via Output= in your own config.
Yu Watanabe [Wed, 17 Dec 2025 16:44:42 +0000 (01:44 +0900)]
sandbox: return raw error code from the kernel and friends on failure
When a system error occurs, the libseccomp returns -ECANCELED and
hides the original error code. That makes harder to debug the failure.
Let's make libseccomp propagate the original error code.
Marc Herbert [Tue, 11 Nov 2025 00:12:49 +0000 (16:12 -0800)]
make_image: log systemd-repart *.conf files at the --debug level
As discussed in #3948, systemd-repart *.conf files have default values
which is convenient until this fails with some dreaded "disk full" error
- then it becomes very mysterious. To considerably speed up the
investigation about what exactly is full, show the configuration files
in use when using --debug.
Signed-off-by: Marc Herbert <marc.herbert@intel.com>
(cherry picked from commit 7040a6add12c8f8c1c8393d5e35c747ee2876472) Signed-off-by: Marc Herbert <marc.herbert@intel.com>
Daan De Meyer [Mon, 15 Dec 2025 20:24:15 +0000 (21:24 +0100)]
sandbox: Add better error reporting for overlayfs
Let's do some basic checks up front so we catch
trivial errors ourselves instead of having to
debug obscure errors we get back from the kernel
when calling mount().
Daan De Meyer [Fri, 12 Dec 2025 11:21:21 +0000 (12:21 +0100)]
kmod: Only add fully resolved fw path if it exists
The symlinks in /usr/lib/firmware might be
dangling and we shouldn't try to add the target of
a dangling symlink to the list of firmware as cpio
will error out later because it can't find the
file or directory.
Daan De Meyer [Wed, 10 Dec 2025 18:41:28 +0000 (19:41 +0100)]
Fix SplitArtifacts=repart-definitions for addons
is_extension_or_portable_image() includes addon images, which should
be skipped in copy_repart_definitions(), so list the formats individually
instead.
Daan De Meyer [Tue, 9 Dec 2025 22:11:25 +0000 (23:11 +0100)]
run: Set up sandbox with a preexec function
There's no need to initialize a new python interpreter every single
time we need a sandbox when we can use the one we already have by
setting up the sandbox with a preexec_fn. A preexec_fn executes before
execve(), so we can reuse the same python interpreter we're already
running in instead of having to spawn a new one.
If we're debugging the sandbox or running a setup command, we stick to
the old approach of invoking a separate python interpreter.
Daan De Meyer [Tue, 9 Dec 2025 21:54:03 +0000 (22:54 +0100)]
Move setup argument to run() instead of sandbox_cmd()
It's a bit up in the air whether this belongs in sandbox_cmd() or
spawn() but let's move it to spawn since it shouldn't be impossible
to have a setup command without having sandbox.
Daan De Meyer [Tue, 9 Dec 2025 21:30:04 +0000 (22:30 +0100)]
Use proper constants for ansi colors
I was playing around with mypyc again and it did not like class
attributes like the Style ones. While mypyc ended up not working for
other reasons, let's switch to something it is happy with which is just
regular constants named identically to how they're named in systemd. It's
arguably not uglier than the Style namespace class.
Daan De Meyer [Sun, 7 Dec 2025 19:04:51 +0000 (20:04 +0100)]
action: Use environment variables instead of inputs
Let's simplify and just use environment variables
instead of inputs. While we're at it, use
environment variables for everything since I don't
know which variables are broken in composite
actions and which are not (see linked github
actions bug).
Laurence Kiln [Fri, 5 Dec 2025 09:26:32 +0000 (11:26 +0200)]
Add python3-pefile to fedora tools conf
python3-pefile is a dep of `system-ukify` which `mkosi` depends on,
so it gets installed indirectly by `dnf install $(mkosi dependencies)`
runs. But mkosi depends on it directly, so make it an explicit dependency.