WIP: Build image from scratch / without NixOS.
Some checks are pending
ci/woodpecker/pr/ci Pipeline is pending

An experiment to see if we can minimize the PatOS project even further,
and not have to adapt NixOS packages and config for our needs.
This commit is contained in:
Daniel Lundin 2025-02-13 09:28:16 +01:00
parent 4702e0dddb
commit 323f5daf2b
Signed by: dln
SSH key fingerprint: SHA256:dQy1Xj3UiqJYpKR5ggQ2bxgz4jCH8IF+k3AB8o0kmdI
27 changed files with 2861 additions and 1201 deletions

View file

@ -1 +1,3 @@
nix_direnv_manual_reload
use flake
dotenv_if_exists

34
flake.lock generated
View file

@ -1,5 +1,23 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1739020877,
@ -18,8 +36,24 @@
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
}
},
"root": "root",

113
flake.nix
View file

@ -2,90 +2,51 @@
description = "PatOS is a minimal, immutable Linux distribution specialized for the Patagia Platform.";
inputs = {
flake-utils.url = "github:numtide/flake-utils";
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs =
{ self, nixpkgs }:
let
releaseVersion = "0.0.1";
system = "x86_64-linux";
updateUrl = "https://images.dl.patagia.dev/patos/";
pkgs = import nixpkgs { inherit system; };
in
{
nixosModules.devel.imports = [
./modules/profiles/devel.nix
];
self,
flake-utils,
nixpkgs,
}:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = import nixpkgs { inherit system; };
in
{
packages = {
default = self.packages.${system}.image;
image = pkgs.writeShellScriptBin "image" ''
echo "make image here..."
'';
nixosModules.server.imports = [
./modules/profiles/server.nix
];
kernel = pkgs.callPackage ./kernel { };
systemd = pkgs.callPackage ./systemd { };
};
nixosModules.image.imports = [
./modules
./modules/profiles/base.nix
./modules/image
];
checks = {
simple-test = pkgs.runCommand "simple-test" { } ''
${self.packages.${system}.default}/bin/my-program
touch $out
'';
};
packages.${system} = {
devel =
(nixpkgs.lib.nixosSystem {
modules = [
(
{ ... }:
{
nixpkgs.hostPlatform = system;
system.stateVersion = "25.05";
}
)
{
system.image.updates.url = "${updateUrl}";
system.image.id = "patos";
system.image.version = releaseVersion;
image.compress = false;
}
self.nixosModules.image
self.nixosModules.devel
];
}).config.system.build.updatePackage;
formatter = pkgs.nixpkgs-fmt;
patos =
(nixpkgs.lib.nixosSystem {
modules = [
(
{ ... }:
{
nixpkgs.hostPlatform = system;
system.stateVersion = "25.05";
}
)
{
system.image.updates.url = "${updateUrl}";
system.image.id = "patos";
system.image.version = releaseVersion;
}
self.nixosModules.image
self.nixosModules.server
];
}).config.system.build.updatePackage;
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
erofs-utils
just
nixd
nixfmt-rfc-style
squashfs-tools-ng
];
};
qemu-uefi-tpm = pkgs.callPackage ./utils/qemu-uefi-tpm.nix { inherit pkgs; };
};
checks.${system} = {
podman = import ./tests/podman.nix { inherit pkgs self; };
system-update = import ./tests/system-update.nix { inherit pkgs self; };
};
devShells.${system}.default = pkgs.mkShell {
buildInputs = with pkgs; [
erofs-utils
just
self.packages.${system}.qemu-uefi-tpm
squashfs-tools-ng
];
};
};
}
);
}

16
kernel/default.nix Normal file
View file

@ -0,0 +1,16 @@
{ pkgs, ... }:
let
version = "6.13.2";
in
pkgs.linuxPackagesFor (
pkgs.linuxManualConfig {
version = "${version}-patos1";
modDirVersion = version;
src = pkgs.fetchurl {
url = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${version}.tar.xz";
hash = "sha256-zfYpgZBru+lwGutzxPn8yAegmEbCiHMWY9YnF+0a5wU=";
};
configfile = ./generic.config;
allowImportFromDerivation = true;
}
)

2521
kernel/generic.config Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,15 +0,0 @@
{ config, ... }:
{
boot = {
bootspec.enable = false;
initrd.kernelModules = config.boot.kernelModules;
kernel.enable = false; # No kernel or modules in the rootfs
modprobeConfig.enable = false;
};
system.build = {
inherit (config.boot.kernelPackages) kernel;
};
system.modulesTree = [ config.boot.kernelPackages.kernel ] ++ config.boot.extraModulePackages;
}

View file

@ -1,25 +0,0 @@
{ ... }:
{
nixpkgs.overlays = [
(final: prev: {
composefs = final.callPackage ../../pkgs/composefs.nix { inherit prev; };
qemu_tiny = final.callPackage ../../pkgs/qemu.nix { inherit prev; };
systemd = prev.systemd.overrideAttrs (oldAttrs: {
mesonFlags = oldAttrs.mesonFlags ++ [
"-Dsysupdated=enabled"
];
});
## minimal inherit from systemd pkg, need to explicitly disable sysupdated
systemdMinimal = prev.systemdMinimal.overrideAttrs (oldAttrs: {
mesonFlags = oldAttrs.mesonFlags ++ [
"-Dsysupdated=disabled"
];
});
})
];
}

View file

@ -1,6 +0,0 @@
{
imports = [
./config/minimal-modules.nix
./config/minimal-system.nix
];
}

View file

@ -1,196 +0,0 @@
{
config,
lib,
options,
pkgs,
...
}:
let
inherit (pkgs.stdenv.hostPlatform) efiArch;
initialPartitions = {
"10-root" = {
storePaths = [ config.system.build.toplevel ];
repartConfig = {
Type = "root";
Minimize = "best";
Format = "erofs";
MakeDirectories = "/home /root /etc /dev /sys /bin /var /proc /run /usr /usr/bin /srv /tmp /mnt /lib /boot";
Verity = "data";
VerityMatchKey = "root";
SplitName = "root";
};
};
"20-root-verity" = {
repartConfig = {
Type = "root-verity";
Minimize = "best";
Verity = "hash";
VerityMatchKey = "root";
SplitName = "verity";
};
};
};
# TODO: We don't need a combined image here - add dry-run flag to repart invocation
verityRepart = import (pkgs.path + "/nixos/lib/eval-config.nix") {
inherit lib pkgs;
system = null;
modules = [
(
{ modulesPath, ... }:
{
imports = [ (modulesPath + "/image/repart.nix") ];
image.repart = {
name = "verity";
split = true;
mkfsOptions = lib.mkIf config.image.compress {
erofs = [
"-zlz4hc,level=12"
"-Efragments,dedupe,ztailpacking"
];
};
partitions = initialPartitions;
};
}
)
];
};
rootPart = "${verityRepart.config.system.build.image}/${verityRepart.config.image.repart.imageFileBasename}.root.raw";
verityPart = "${verityRepart.config.system.build.image}/${verityRepart.config.image.repart.imageFileBasename}.verity.raw";
verityImgAttrs = builtins.fromJSON (
builtins.readFile "${verityRepart.config.system.build.image}/repart-output.json"
);
rootAttrs = builtins.elemAt verityImgAttrs 0;
verityAttrs = builtins.elemAt verityImgAttrs 1;
rootUuid = rootAttrs.uuid;
verityUuid = verityAttrs.uuid;
verityRootHash = rootAttrs.roothash;
finalPartitions = {
"10-esp" = {
contents = {
"/EFI/BOOT/BOOT${lib.toUpper efiArch}.EFI".source = "${pkgs.systemdUkify}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi";
"/EFI/Linux/${config.system.boot.loader.ukiFile}".source = "${config.system.build.uki}/${config.system.boot.loader.ukiFile}";
"/EFI/memtest86/memtest86.efi".source = "${pkgs.memtest86plus}/memtest.efi";
"/loader/entries/patos-factory-reset.conf".source = pkgs.writeText "patos-factory-reset.conf" ''
title Patos Factory Reset
efi /EFI/Linux/${config.system.boot.loader.ukiFile}
options ${toString config.boot.kernelParams} systemd.factory_reset=yes
sort-key z_factory_reset
'';
"/loader/entries/memtest86.conf".source = pkgs.writeText "memtest86.conf" ''
title Memtest86+
efi /EFI/memtest86/memtest86.efi
options console=ttyS0
sort-key z_memtest
'';
"/loader/loader.conf".source = pkgs.writeText "loader.conf" ''
timeout 2
'';
};
repartConfig = {
Type = "esp";
Format = "vfat";
SizeMinBytes = "96M";
SizeMaxBytes = "96M";
SplitName = "-";
};
};
"20-root-verity-a" = {
repartConfig = {
Type = "root-verity";
Label = "verity-${config.system.image.version}";
CopyBlocks = "${verityPart}";
SplitName = "-";
SizeMinBytes = "64M";
SizeMaxBytes = "64M";
UUID = "${verityUuid}";
ReadOnly = 1;
};
};
# TODO: Add signature partition for systemd-nspawn
"22-root-a" = {
repartConfig = {
Type = "root";
Label = "root-${config.system.image.version}";
CopyBlocks = "${rootPart}";
SplitName = "-";
UUID = "${rootUuid}";
ReadOnly = 1;
};
};
};
finalRepart = import (pkgs.path + "/nixos/lib/eval-config.nix") {
inherit lib pkgs;
system = null;
modules = [
(
{ modulesPath, ... }:
{
imports = [ (modulesPath + "/image/repart.nix") ];
image.repart = {
name = "${config.system.image.id}";
partitions = finalPartitions;
};
}
)
];
};
in
{
# This fields is immutable by default, but can be overridden.
options.system.nixos.codeName = lib.mkOption { readOnly = false; };
options.system.nixos.release = lib.mkOption { readOnly = false; };
# FIXME: Should be configured somehow
config.system.nixos = {
codeName = "Finn";
distroId = "patos";
distroName = "PatOS";
release = "2024-11";
variant_id = "server";
variantName = "Server";
vendorName = "PatOS";
};
options.image.compress = lib.mkEnableOption "image compression" // {
default = true;
};
config.system.build = {
inherit verityRootHash;
image =
(pkgs.linkFarm "image-release" [
{
name = "${config.system.image.id}_${config.system.image.version}.efi";
path = "${config.system.build.uki}/${config.system.boot.loader.ukiFile}";
}
{
name = "${config.system.image.id}_${config.system.image.version}_${verityUuid}.verity";
path = "${verityRepart.config.system.build.image}/${verityRepart.config.image.repart.imageFileBasename}.verity.raw";
}
{
name = "${config.system.image.id}_${config.system.image.version}_${rootUuid}.root";
path = "${verityRepart.config.system.build.image}/${verityRepart.config.image.repart.imageFileBasename}.root.raw";
}
{
name = "${config.system.image.id}_${config.system.image.version}.img";
path = "${finalRepart.config.system.build.image}/${finalRepart.config.image.repart.imageFileBasename}.raw";
}
])
// {
imageFile = "${config.system.image.id}_${config.system.image.version}.img";
};
};
}

View file

@ -1,137 +0,0 @@
{
config,
lib,
pkgs,
...
}:
{
imports = [
./updater.nix
./builder.nix
./veritysetup.nix
];
system.build.updatePackage = pkgs.runCommand "update-package" { } ''
mkdir "$out"
cd "$out"
cp "${config.system.build.image}"/* .
${pkgs.coreutils}/bin/sha256sum * > SHA256SUMS
'';
systemd.repart.partitions = {
"10-esp" = {
Type = "esp";
UUID = "c12a7328-f81f-11d2-ba4b-00a0c93ec93b"; # Well known
Format = "vfat";
SizeMinBytes = "96M";
SizeMaxBytes = "96M";
};
"20-root-verity-a" = {
Type = "root-verity";
SizeMinBytes = "64M";
SizeMaxBytes = "64M";
};
"22-root-a" = {
Type = "root";
SizeMinBytes = "512M";
SizeMaxBytes = "512M";
};
"30-root-verity-b" = {
Type = "root-verity";
SizeMinBytes = "64M";
SizeMaxBytes = "64M";
Label = "_empty";
ReadOnly = 1;
};
"32-root-b" = {
Type = "root";
SizeMinBytes = "512M";
SizeMaxBytes = "512M";
Label = "_empty";
ReadOnly = 1;
};
"40-var" = {
Type = "var";
UUID = "4d21b016-b534-45c2-a9fb-5c16e091fd2d"; # Well known
Format = "btrfs";
Label = "patos-state";
Minimize = "off";
FactoryReset = "yes";
Encrypt = "tpm2";
SizeMinBytes = "2G";
SplitName = "-";
};
};
boot.loader.grub.enable = false;
boot.loader.efi.canTouchEfiVariables = true;
boot.loader.systemd-boot.enable = true;
boot.uki.name = "patos";
boot.initrd = {
compressor = "zstd";
compressorArgs = [ "-8" ];
luks.forceLuksSupportInInitrd = true;
kernelModules = [
"dm_mod"
"dm_crypt"
] ++ config.boot.initrd.luks.cryptoModules;
supportedFilesystems = {
btrfs = true;
erofs = true;
};
systemd.enable = true;
systemd.repart.enable = true;
systemd.services.systemd-repart = {
after = lib.mkForce [ "sysroot.mount" ];
requires = [ "sysroot.mount" ];
serviceConfig.Environment = [
"SYSTEMD_REPART_MKFS_OPTIONS_BTRFS=--nodiscard"
];
};
};
system.etc.overlay.mutable = false;
users.mutableUsers = false;
boot.kernelParams = [
"rootfstype=erofs"
"rootflags=ro"
"roothash=${config.system.build.verityRootHash}"
];
fileSystems =
let
parts = config.systemd.repart.partitions;
in
{
"/var" = {
fsType = parts."40-var".Format;
device = "/dev/mapper/var";
encrypted = {
enable = true;
blkDev = "/dev/disk/by-partuuid/${parts."40-var".UUID}";
label = "var";
};
};
};
# Required to mount the efi partition
boot.kernelModules = [
"vfat"
"nls_cp437"
"nls_iso8859-1"
];
environment.etc."machine-id" = {
text = "";
mode = "0755";
};
# Refuse to boot on mount failure
systemd.targets."sysinit".requires = [ "local-fs.target" ];
}

View file

@ -1,89 +0,0 @@
{ config, lib, ... }:
{
options.system.image.updates = {
enable = lib.mkEnableOption "system updates via systemd-sysupdate" // {
default = config.system.image.updates.url != null;
};
url = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
};
};
config = lib.mkIf config.system.image.updates.enable {
assertions = [
{ assertion = config.system.image.updates.url != null; }
];
systemd.additionalUpstreamSystemUnits = [
"systemd-bless-boot.service"
"boot-complete.target"
"dbus-org.freedesktop.sysupdate1.service"
"systemd-sysupdated.service"
];
environment.etc."sysupdate.d/10-uki.transfer" = {
text = ''
[Source]
Path=${config.system.image.updates.url}
MatchPattern=${config.boot.uki.name}_@v.efi
Type=url-file
[Target]
InstancesMax=2
MatchPattern=${config.boot.uki.name}_@v+@l-@d.efi ${config.boot.uki.name}_@v+@l.efi ${config.boot.uki.name}_@v.efi
Mode=0444
Path=/EFI/Linux
PathRelativeTo=esp
TriesDone=0
TriesLeft=3
Type=regular-file
[Transfer]
Verify=no
'';
};
environment.etc."sysupdate.d/20-root.transfer" = {
text = ''
[Source]
Type=url-file
Path=${config.system.image.updates.url}
MatchPattern=${config.system.image.id}_@v_@u.verity
[Target]
Type=partition
Path=auto
MatchPattern=verity-@v
MatchPartitionType=root-verity
ReadOnly=1
[Transfer]
Verify=no
'';
};
environment.etc."sysupdate.d/22-root.transfer" = {
text = ''
[Source]
Type=url-file
Path=${config.system.image.updates.url}
MatchPattern=${config.system.image.id}_@v_@u.root
[Target]
Type=partition
Path=auto
MatchPattern=root-@v
MatchPartitionType=root
ReadOnly=1
[Transfer]
Verify=no
'';
};
};
}

View file

@ -1,39 +0,0 @@
{ config, lib, ... }:
{
options.boot.initrd.systemd.root = lib.mkOption {
type = lib.types.enum [
"fstab"
"gpt-auto"
""
];
};
config.boot.initrd = {
kernelModules = [
"dm_mod"
"dm_verity"
];
systemd = {
# Required to activate systemd-fstab-generator
root = "";
additionalUpstreamUnits = [
"veritysetup-pre.target"
"veritysetup.target"
"remote-veritysetup.target"
];
storePaths = [
"${config.boot.initrd.systemd.package}/lib/systemd/systemd-veritysetup"
"${config.boot.initrd.systemd.package}/lib/systemd/system-generators/systemd-veritysetup-generator"
];
};
};
}

View file

@ -1,97 +0,0 @@
{
config,
lib,
pkgs,
modulesPath,
...
}:
{
imports = [
(modulesPath + "/profiles/image-based-appliance.nix")
(modulesPath + "/profiles/perlless.nix")
(modulesPath + "/profiles/qemu-guest.nix")
];
# system.forbiddenDependenciesRegexes = lib.mkForce [ ];
nixpkgs.flake.setNixPath = false;
nixpkgs.flake.setFlakeRegistry = false;
boot.enableContainers = false;
boot.kernelModules = [
"zram"
"usb_storage"
"uas"
"sd_mod"
"r8169"
"ehci-hcd"
"ehci-pci"
"xhci-hcd"
"xhci-pci"
"xhci-pci-renesas"
"nvme"
"virtio_net"
"9p"
"9pnet_virtio"
];
system.etc.overlay.mutable = lib.mkDefault false;
systemd.watchdog = lib.mkDefault {
runtimeTime = "10s";
rebootTime = "30s";
};
zramSwap.enable = true;
# FIXME: fstrim should only be enabled for virtual machine images?
services.fstrim.enable = true;
users.allowNoPasswordLogin = true;
users.users.root.home = lib.mkForce "/";
security.sudo.enable = lib.mkDefault false;
security.polkit = {
enable = true;
extraConfig = ''
polkit.addRule(function(action, subject) {
if (subject.isInGroup("wheel")) {
return polkit.Result.YES;
}
});
'';
};
i18n.supportedLocales = [ "en_US.UTF-8/UTF-8" ];
# Console
systemd.enableEmergencyMode = false;
boot.consoleLogLevel = lib.mkDefault 1;
boot.kernelParams = [
"panic=1"
"boot.panic_on_fail"
# "nomodeset"
"console=ttyS0,115200n8"
"earlyprintk=ttyS0,115200n8"
"systemd.mask=systemd-vconsole-setup.service" # FIXME: Figure out why vconsole-setup fails when loading keymap
];
# This is vi country
programs.nano.enable = false;
programs.vim.enable = true;
programs.vim.defaultEditor = lib.mkDefault true;
# Temporary file
boot.tmp.useTmpfs = true;
# Logging
services.journald = {
storage = "volatile";
extraConfig = ''
SystemMaxUse=10M
'';
};
}

View file

@ -1,39 +0,0 @@
{
modulesPath,
...
}:
{
imports = [ ./server.nix ];
boot.kernel.sysctl = {
"net.ipv4.ip_unprivileged_port_start" = 0;
};
boot.kernelParams = [
"systemd.log_level=info"
"systemd.log_target=console"
"systemd.journald.forward_to_console"
];
users.users."admin" = {
isNormalUser = true;
linger = true;
extraGroups = [ "wheel" ];
home = "/var/home/admin";
};
environment.etc = {
subuid = {
text = "admin:100000:65536";
mode = "0644";
};
subgid = {
text = "admin:100000:65536";
mode = "0644";
};
};
services.getty.autologinUser = "admin";
}

View file

@ -1,65 +0,0 @@
{ lib, ... }:
{
# Use networkd
networking.useNetworkd = true;
systemd.network.wait-online.enable = true;
# Firewall
networking.firewall.enable = false;
networking.nftables.enable = lib.mkDefault true;
# DNS
services.resolved = {
fallbackDns = [ ]; # Disable fallback DNS. DNS will fail if resolvers are unconfigured
extraConfig = ''
DNSStubListener=no
'';
};
# Configuration
networking.hostName = "";
# Kernel
boot.kernel.sysctl = {
"net.core.default_qdisc" = "fq"; # FIXME: manage these with networkd?
"net.ipv4.tcp_congestion_control" = "bbr";
};
# Modules
boot.kernelModules = [
"ip_tables"
"x_tables"
"nf_tables"
"nft_ct"
"nft_log"
"nf_log_syslog"
"nft_fib"
"nft_fib_inet"
"nft_compat"
"nft_nat"
"nft_chain_nat"
"nft_masq"
"nfnetlink"
"xt_conntrack"
"nf_conntrack"
"nf_log_syslog"
"nf_nat"
"af_packet"
"bridge"
"veth"
"tcp_bbr"
"sch_fq_codel"
"ipt_rpfilter"
"ip6t_rpfilter"
"sch_fq"
"tun"
"tap"
"xt_MASQUERADE"
"xt_mark"
"xt_comment"
"xt_multiport"
"xt_addrtype"
];
}

View file

@ -1,18 +0,0 @@
{
modulesPath,
...
}:
{
imports = [
(modulesPath + "/profiles/minimal.nix")
./network.nix
./sysext.nix
];
boot.kernelParams = [
"quiet"
];
virtualisation.podman.enable = true;
}

View file

@ -1,23 +0,0 @@
{ ... }:
{
system.activationScripts.sysext = ''
mkdir -p /var/lib/confexts
mkdir -p /var/lib/extensions
mkdir -p /etc/systemd/extensions
'';
systemd.additionalUpstreamSystemUnits = [
"systemd-confext.service"
"systemd-sysext.service"
];
# systemd.services."systemd-confext" = {
# enable = true;
# wantedBy = [ "multi-user.target" ];
# };
# systemd.services."systemd-sysext.service" = {
# enable = true;
# wantedBy = [ "multi-user.target" ];
# };
}

View file

@ -1,5 +0,0 @@
{ prev, ... }:
prev.composefs.overrideAttrs (final: prev: {
doCheck = false;
})

View file

@ -1,12 +0,0 @@
{ stdenv, lib
, linux-firmware
, fwDirs
}: stdenv.mkDerivation {
pname = "linux-firmware-minimal";
version = linux-firmware.version;
buildCommand = lib.concatStringsSep "\n" (
[''mkdir -p "$out/lib/firmware"'']
++ (map (name: ''
cp -r "${linux-firmware}/lib/firmware/${name}" "$out/lib/firmware/${name}"
'') fwDirs));
}

View file

@ -1,30 +0,0 @@
{ prev, pkgs, ... }:
(prev.qemu_test.override {
enableDocs = false;
capstoneSupport = false;
guestAgentSupport = false;
tpmSupport = false;
libiscsiSupport = false;
usbredirSupport = false;
canokeySupport = false;
hostCpuTargets = [ "x86_64-softmmu" ];
}).overrideDerivation (old: {
postFixup = ''
rm -r "$out/share/icons"
cp "${pkgs.OVMF.fd + "/FV/OVMF.fd"}" "$out/share/qemu/"
'';
configureFlags = old.configureFlags ++ [
"--disable-tcg"
"--disable-tcg-interpreter"
"--disable-docs"
"--disable-install-blobs"
"--disable-slirp"
"--disable-virtfs"
"--disable-virtfs-proxy-helper"
"--disable-vhost-user-blk-server"
"--without-default-features"
"--enable-kvm"
"--disable-tools"
];
})

View file

@ -1,48 +0,0 @@
{ prev, ... }:
prev.systemd.override {
withAcl = false;
withAnalyze = false;
withApparmor = false;
withAudit = false;
withEfi = true;
withCompression = false;
withCoredump = false;
withCryptsetup = false;
withRepart = false;
withDocumentation = false;
withFido2 = false;
withFirstboot = false;
withHomed = false;
withHostnamed = false;
withHwdb = false;
withImportd = false;
withIptables = false;
withKmod = false;
withLibBPF = false;
withLibidn2 = false;
withLocaled = false;
withLogind = false;
withMachined = false;
withNetworkd = false;
withNss = false;
withOomd = false;
withPam = false;
withPasswordQuality = false;
withPCRE2 = false;
withPolkit = false;
withPortabled = false;
withQrencode = false;
withRemote = false;
withResolved = false;
withShellCompletions = false;
withSysusers = false;
withSysupdate = false;
withTimedated = false;
withTimesyncd = false;
withTpm2Tss = false;
withUkify = true;
withUserDb = false;
withUtmp = false;
withVmspawn = false;
}

251
systemd/default.nix Normal file
View file

@ -0,0 +1,251 @@
{
fetchFromGitHub,
lib,
pkgs,
stdenv,
...
}:
let
version = "257.3";
# Use the command below to update `releaseTimestamp` on every (major) version
# change. More details in the commentary at mesonFlags.
# command:
# $ curl -s https://api.github.com/repos/systemd/systemd/releases/latest | \
# jq '.created_at|strptime("%Y-%m-%dT%H:%M:%SZ")|mktime'
releaseTimestamp = "1734643670";
pname = "systemd";
in
stdenv.mkDerivation (finalAttrs: {
inherit version;
pname = pname;
src = fetchFromGitHub {
owner = "systemd";
repo = "systemd";
rev = "v${version}";
hash = "sha256-GvRn55grHWR6M+tA86RMzqinuXNpPZzRB4ApuGN/ZvU=";
};
nativeBuildInputs = with pkgs; [
pkg-config
makeBinaryWrapper
gperf
ninja
meson
glibcLocales
getent
m4
autoPatchelfHook
intltool
gettext
libxslt
docbook_xsl
docbook_xml_dtd_42
docbook_xml_dtd_45
bash
(buildPackages.python3Packages.python.withPackages (
ps: with ps; [
lxml
jinja2
ps.pyelftools
]
))
bpftools
buildPackages.llvmPackages.clang
buildPackages.llvmPackages.libllvm
];
autoPatchelfFlags = [ "--keep-libc" ];
hardeningDisable = [
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=111523
"trivialautovarinit"
# breaks clang -target bpf; should be fixed to filter target?
"zerocallusedregs"
"shadowstack"
];
buildInputs = with pkgs; [
libxcrypt
libcap
libuuid
linuxHeaders
bashInteractive # for patch shebangs
libgcrypt
libgpg-error
openssl
acl
libapparmor
audit
zlib
bzip2
lz4
xz
zstd
elfutils
kexec-tools
kmod
libidn2
libseccomp
libselinux
iptables
p11-kit
libfido2
pam
pcre2
libbpf
tpm2-tss
qrencode
libarchive
(lib.getDev curl)
(lib.getDev cryptsetup.dev)
(python3Packages.python.withPackages (ps: with ps; [ pefile ]))
(llvmPackages.compiler-rt.override {
doFakeLibgcc = true;
})
];
mesonBuildType = "release";
mesonFlags = [
# Options
# We bump this attribute on every (major) version change to ensure that we
# have known-good value for a timestamp that is in the (not so distant)
# past. This serves as a lower bound for valid system timestamps during
# startup. Systemd will reset the system timestamp if this date is +- 15
# years from the system time.
# See the systemd v250 release notes for further details:
# https://github.com/systemd/systemd/blob/60e930fc3e6eb8a36fbc184773119eb8d2f30364/NEWS#L258-L266
(lib.mesonOption "time-epoch" releaseTimestamp)
(lib.mesonOption "version-tag" version)
(lib.mesonOption "mode" "release")
(lib.mesonOption "tty-gid" "3") # tty in NixOS has gid 3
# SBAT
(lib.mesonOption "sbat-distro" "patos")
(lib.mesonOption "sbat-distro-summary" "PatOS")
(lib.mesonOption "sbat-distro-url" "https://patagia.io/")
(lib.mesonOption "sbat-distro-pkgname" pname)
(lib.mesonOption "sbat-distro-version" version)
# Users
(lib.mesonOption "system-uid-max" "999")
(lib.mesonOption "system-gid-max" "999")
# SysVinit
(lib.mesonOption "sysvinit-path" "")
(lib.mesonOption "sysvrcnd-path" "")
# SSH
# Disabled for now until someone makes this work.
(lib.mesonOption "sshconfdir" "no")
(lib.mesonOption "sshdconfdir" "no")
# Features
# Tests
(lib.mesonBool "tests" false)
(lib.mesonEnable "glib" false)
(lib.mesonEnable "dbus" false)
# Compression
(lib.mesonEnable "bzip2" true)
(lib.mesonEnable "lz4" true)
(lib.mesonEnable "xz" true)
(lib.mesonEnable "zstd" true)
(lib.mesonEnable "zlib" true)
# NSS
(lib.mesonEnable "nss-resolve" true)
(lib.mesonBool "nss-myhostname" true)
(lib.mesonBool "nss-systemd" true)
# Cryptsetup
(lib.mesonEnable "libcryptsetup" true)
(lib.mesonEnable "libcryptsetup-plugins" true)
(lib.mesonEnable "p11kit" true)
# FIDO2
(lib.mesonEnable "libfido2" true)
(lib.mesonEnable "openssl" true)
# Password Quality
(lib.mesonEnable "pwquality" false)
(lib.mesonEnable "passwdqc" false)
# Remote
(lib.mesonEnable "remote" false)
(lib.mesonEnable "microhttpd" false)
(lib.mesonEnable "pam" true)
(lib.mesonEnable "acl" true)
(lib.mesonEnable "audit" true)
(lib.mesonEnable "apparmor" true)
(lib.mesonEnable "gcrypt" true)
(lib.mesonEnable "importd" true)
(lib.mesonEnable "homed" true)
(lib.mesonEnable "polkit" true)
(lib.mesonEnable "elfutils" true)
(lib.mesonEnable "libcurl" true)
(lib.mesonEnable "libidn" false)
(lib.mesonEnable "libidn2" true)
(lib.mesonEnable "libiptc" true)
(lib.mesonEnable "repart" true)
(lib.mesonEnable "sysupdate" true)
(lib.mesonEnable "seccomp" true)
(lib.mesonEnable "selinux" true)
(lib.mesonEnable "tpm2" true)
(lib.mesonEnable "pcre2" true)
(lib.mesonEnable "bpf-framework" true)
(lib.mesonEnable "bootloader" true)
(lib.mesonEnable "ukify" true)
(lib.mesonEnable "kmod" true)
(lib.mesonEnable "qrencode" true)
(lib.mesonEnable "vmspawn" true)
(lib.mesonEnable "libarchive" true)
(lib.mesonEnable "xenctrl" false)
(lib.mesonEnable "gnutls" false)
(lib.mesonEnable "xkbcommon" false)
(lib.mesonEnable "man" true)
(lib.mesonBool "analyze" true)
(lib.mesonBool "logind" true)
(lib.mesonBool "localed" true)
(lib.mesonBool "hostnamed" true)
(lib.mesonBool "machined" true)
(lib.mesonBool "networkd" true)
(lib.mesonBool "oomd" true)
(lib.mesonBool "portabled" true)
(lib.mesonBool "hwdb" true)
(lib.mesonBool "timedated" true)
(lib.mesonBool "timesyncd" true)
(lib.mesonBool "userdb" true)
(lib.mesonBool "coredump" true)
(lib.mesonBool "firstboot" true)
(lib.mesonBool "resolve" true)
(lib.mesonBool "sysusers" true)
(lib.mesonBool "efi" true)
(lib.mesonBool "utmp" true)
(lib.mesonBool "log-trace" true)
(lib.mesonBool "kernel-install" true)
(lib.mesonBool "quotacheck" false)
(lib.mesonBool "ldconfig" false)
(lib.mesonBool "install-sysconfdir" false)
(lib.mesonBool "create-log-dirs" false)
(lib.mesonBool "smack" true)
(lib.mesonBool "b_pie" true)
(lib.mesonOption "bashcompletiondir" "no")
(lib.mesonOption "zshcompletiondir" "no")
];
})

View file

@ -1,155 +0,0 @@
{
self,
lib,
pkgs,
...
}:
with import (pkgs.path + "/nixos/lib/testing-python.nix") {
inherit pkgs;
inherit (pkgs.hostPlatform) system;
};
let
qemu-common = import (pkgs.path + "/nixos/lib/qemu-common.nix") { inherit lib pkgs; };
in
rec {
makeSystem =
extraConfig:
(import (pkgs.path + "/nixos/lib/eval-config.nix")) {
inherit pkgs lib;
system = null;
modules = [
{
nixpkgs.hostPlatform = pkgs.hostPlatform;
}
{
users.allowNoPasswordLogin = true;
system.stateVersion = lib.versions.majorMinor lib.version;
system.image.id = lib.mkDefault "test";
system.image.version = lib.mkDefault "1";
networking.hosts."10.0.2.1" = [ "server.test" ];
}
{
boot.kernelParams = [
"console=ttyS0,115200n8"
"systemd.journald.forward_to_console=1"
];
image.compress = false;
boot.uki.name = lib.mkForce "test";
boot.initrd.compressor = lib.mkForce "zstd";
boot.initrd.compressorArgs = lib.mkForce [ "-8" ];
}
(pkgs.path + "/nixos/modules/testing/test-instrumentation.nix")
self.nixosModules.devel
self.nixosModules.image
extraConfig
];
};
makeImage =
extraConfig:
let
system = makeSystem extraConfig;
in
"${system.config.system.build.image}/${system.config.system.build.image.imageFile}";
makeUpdatePackage =
extraConfig:
let
system = makeSystem extraConfig;
in
"${system.config.system.build.updatePackage}";
makeImageTest =
{
name,
image,
script,
httpRoot ? null,
}:
let
qemu = qemu-common.qemuBinary pkgs.qemu_test;
flags = [
"-m"
"512M"
"-drive"
"if=pflash,format=raw,unit=0,readonly=on,file=${pkgs.OVMF.firmware}"
"-drive"
"if=pflash,format=raw,unit=1,readonly=on,file=${pkgs.OVMF.variables}"
"-drive"
"if=virtio,file=${mutableImage}"
"-chardev"
"socket,id=chrtpm,path=${tpmFolder}/swtpm-sock"
"-tpmdev"
"emulator,id=tpm0,chardev=chrtpm"
"-device"
"tpm-tis,tpmdev=tpm0"
"-netdev"
(
"'user,id=net0"
+ (lib.optionalString (
httpRoot != null
) ",guestfwd=tcp:10.0.2.1:80-cmd:${pkgs.micro-httpd}/bin/micro_httpd ${httpRoot}")
+ "'"
)
"-device"
"virtio-net-pci,netdev=net0"
];
flagsStr = lib.concatStringsSep " " flags;
startCommand = "${qemu} ${flagsStr}";
mutableImage = "/tmp/linked-image.qcow2";
tpmFolder = "/tmp/emulated_tpm";
indentLines = str: lib.concatLines (map (s: " " + s) (lib.splitString "\n" str));
in
makeTest {
inherit name;
nodes = { };
testScript =
''
import os
import subprocess
subprocess.check_call(
[
"qemu-img",
"create",
"-f",
"qcow2",
"-F",
"raw",
"-b",
"${image}",
"${mutableImage}",
]
)
subprocess.check_call(["qemu-img", "resize", "${mutableImage}", "4G"])
os.mkdir("${tpmFolder}")
os.mkdir("${tpmFolder}/swtpm")
def start_tpm():
subprocess.Popen(
[
"${pkgs.swtpm}/bin/swtpm",
"socket",
"--tpmstate", "dir=${tpmFolder}/swtpm",
"--ctrl", "type=unixio,path=${tpmFolder}/swtpm-sock",
"--tpm2"
]
)
machine = create_machine("${startCommand}")
try:
''
+ indentLines script
+ ''
finally:
machine.shutdown()
'';
};
}

View file

@ -1,9 +0,0 @@
test:
{ pkgs, self }:
let nixos-lib = import (pkgs.path + "/nixos/lib") {};
in (nixos-lib.runTest {
hostPkgs = pkgs;
defaults.documentation.enable = false;
node.specialArgs = { inherit self; };
imports = [ test ];
}).config.result

View file

@ -1,22 +0,0 @@
{ pkgs, self }: let
lib = pkgs.lib;
test-common = import ./common.nix { inherit self lib pkgs; };
image = test-common.makeImage { };
in test-common.makeImageTest {
name = "podman";
inherit image;
script = ''
start_tpm()
machine.start()
machine.wait_for_unit("multi-user.target")
machine.wait_for_unit("network-online.target")
machine.succeed("tar cv --files-from /dev/null | su admin -l -c 'podman import - scratchimg'")
machine.succeed("su admin -l -c 'podman run --rm -v /nix/store:/nix/store -v /run/current-system/sw/bin:/bin scratchimg true'")
'';
}

View file

@ -1,45 +0,0 @@
{ pkgs, self }: let
lib = pkgs.lib;
test-common = import ./common.nix { inherit self lib pkgs; };
initialImage = test-common.makeImage {
system.image.version = "1";
system.image.updates.url = "http://server.test/";
# The default root-b is too small for uncompressed test images
systemd.repart.partitions."32-root-b" = {
SizeMinBytes = lib.mkForce "1G";
SizeMaxBytes = lib.mkForce "1G";
};
};
updatePackage = test-common.makeUpdatePackage {
system.image.version = "2";
system.image.updates.url = "http://server.test/";
};
in test-common.makeImageTest {
name = "system-update";
image = initialImage;
httpRoot = updatePackage;
script = ''
start_tpm()
machine.start()
machine.wait_for_unit("multi-user.target")
machine.wait_for_unit("network-online.target")
machine.succeed("/run/current-system/sw/lib/systemd/systemd-sysupdate update")
machine.shutdown()
start_tpm()
machine.start()
machine.wait_for_unit("multi-user.target")
machine.succeed('. /etc/os-release; [ "$IMAGE_VERSION" == "2" ]')
machine.wait_for_unit("systemd-bless-boot.service")
'';
}

View file

@ -1,50 +0,0 @@
{
config,
pkgs,
...
}:
pkgs.writeShellApplication {
name = "qemu-uefi-tpm";
runtimeInputs = with pkgs; [
qemu
swtpm
];
text =
let
tpmOVMF = pkgs.OVMF.override { tpmSupport = true; };
in
''
set -ex
state="/tmp/patos-qemu-$USER"
rm -rf "$state"
mkdir -m 700 "$state"
qemu-img create -f qcow2 -F raw -b "$(readlink -e "$1")" "$state/disk.qcow2" 10G
swtpm socket -d --tpmstate dir="$state" \
--ctrl type=unixio,path="$state/swtpm-sock" \
--tpm2 \
--log level=20
qemu-system-x86_64 \
-enable-kvm \
-machine q35,accel=kvm \
-cpu host \
-smp 8 \
-m 4G \
-display none \
-virtfs "local,path=/tmp,security_model=mapped,mount_tag=shared" \
-chardev "stdio,id=char0,mux=on,logfile=$state/console.log,signal=off" \
-serial chardev:char0 \
-mon chardev=char0 \
-drive "if=pflash,format=raw,unit=0,readonly=on,file=${tpmOVMF.firmware}" \
-drive "if=pflash,format=raw,unit=1,readonly=on,file=${tpmOVMF.variables}" \
-chardev socket,id=chrtpm,path="$state/swtpm-sock" \
-tpmdev emulator,id=tpm0,chardev=chrtpm \
-device tpm-tis,tpmdev=tpm0 \
-netdev id=net00,type=user,hostfwd=tcp::2222-:22 \
-device virtio-net-pci,netdev=net00 \
-drive "format=qcow2,file=$state/disk.qcow2"
'';
}