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 df511a22aa
Signed by: dln
SSH key fingerprint: SHA256:dQy1Xj3UiqJYpKR5ggQ2bxgz4jCH8IF+k3AB8o0kmdI
26 changed files with 2609 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",

112
flake.nix
View file

@ -2,90 +2,50 @@
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 { };
};
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;
}

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"
'';
}