aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/nixos.nix
diff options
context:
space:
mode:
authorOphestra <cat@gensokyo.uk>2026-07-07 18:32:56 +0900
committerOphestra <cat@gensokyo.uk>2026-07-07 18:56:27 +0900
commit6d55ee536e902d059380f79e870d06547627cc7c (patch)
treeaacf3e3ec42525cf0e7a674aa948359fd0c21ae2 /test/nixos.nix
parentc8e8651694415d497b0800319b2ddda361b7651f (diff)
test: move nix files
These are too much clutter. Move them to test directory until the test suite replacement is upstreamed. Signed-off-by: Ophestra <cat@gensokyo.uk>
Diffstat (limited to 'test/nixos.nix')
-rw-r--r--test/nixos.nix407
1 files changed, 407 insertions, 0 deletions
diff --git a/test/nixos.nix b/test/nixos.nix
new file mode 100644
index 00000000..49bfffb6
--- /dev/null
+++ b/test/nixos.nix
@@ -0,0 +1,407 @@
+packages:
+{
+ lib,
+ pkgs,
+ config,
+ ...
+}:
+
+let
+ inherit (lib)
+ lists
+ attrsets
+ mkMerge
+ mkIf
+ mapAttrs
+ foldlAttrs
+ optional
+ optionals
+ ;
+
+ cfg = config.environment.hakurei;
+
+ # userid*userOffset + appStart + appid
+ getsubuid = userid: appid: userid * 100000 + 10000 + appid;
+ getsubname = userid: appid: "u${toString userid}_a${toString appid}";
+ getsubhome = userid: appid: "${cfg.stateDir}/u${toString userid}/a${toString appid}";
+
+ mountpoints = {
+ ${cfg.sharefs.name} = mkIf (cfg.sharefs.source != null) {
+ depends = [ cfg.sharefs.source ];
+ device = "sharefs";
+ fsType = "fuse.sharefs";
+ noCheck = true;
+ options = [
+ "rw"
+ "noexec"
+ "nosuid"
+ "nodev"
+ "noatime"
+ "allow_other"
+ "mkdir"
+ "source=${cfg.sharefs.source}"
+ "setuid=${toString config.users.users.${cfg.sharefs.user}.uid}"
+ "setgid=${toString config.users.groups.${cfg.sharefs.group}.gid}"
+ ];
+ };
+ };
+in
+
+{
+ imports = [ (import ./options.nix packages) ];
+
+ options = {
+ # Forward declare a dummy option for VM filesystems since the real one won't exist
+ # unless the VM module is actually imported.
+ virtualisation.fileSystems = lib.mkOption { };
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ (
+ let
+ conflictingApps = foldlAttrs (
+ acc: id: app:
+ (
+ acc
+ ++ foldlAttrs (
+ acc': id': app':
+ if id == id' || app.shareUid && app'.shareUid || app.identity != app'.identity then acc' else acc' ++ [ id ]
+ ) [ ] cfg.apps
+ )
+ ) [ ] cfg.apps;
+ in
+ {
+ assertion = (lists.length conflictingApps) == 0;
+ message = "the following hakurei apps have conflicting identities: " + (builtins.concatStringsSep ", " conflictingApps);
+ }
+ )
+ ];
+
+ security.wrappers.hsu = {
+ source = "${cfg.hsuPackage}/bin/hsu";
+ setuid = true;
+ owner = "root";
+ group = "root";
+ };
+
+ environment.etc.hsurc = {
+ mode = "0400";
+ text = foldlAttrs (
+ acc: username: fid:
+ "${toString config.users.users.${username}.uid} ${toString fid}\n" + acc
+ ) "" cfg.users;
+ };
+
+ environment.systemPackages = optional (cfg.sharefs.source != null) cfg.sharefs.package;
+ fileSystems = mountpoints;
+ virtualisation.fileSystems = mountpoints;
+
+ home-manager =
+ let
+ privPackages = mapAttrs (_: userid: {
+ home.packages = foldlAttrs (
+ acc: id: app:
+ [
+ (
+ let
+ extendDBusDefault = id: ext: {
+ filter = true;
+
+ talk = [ "org.freedesktop.Notifications" ] ++ ext.talk;
+ own = [
+ "${id}.*"
+ "org.mpris.MediaPlayer2.${id}.*"
+ ]
+ ++ ext.own;
+
+ inherit (ext) call broadcast;
+ };
+ dbusConfig =
+ let
+ default = {
+ talk = [ ];
+ own = [ ];
+ call = { };
+ broadcast = { };
+ };
+ in
+ {
+ session_bus = if app.dbus.session != null then (app.dbus.session (extendDBusDefault id)) else (extendDBusDefault id default);
+ system_bus = app.dbus.system;
+ };
+ command = if app.command == null then app.name else app.command;
+ script = if app.script == null then ("exec " + command + " $@") else app.script;
+ isGraphical = if app.gpu != null then app.gpu else app.enablements.wayland || app.enablements.x11;
+
+ conf = {
+ inherit id;
+ inherit (app) identity enablements;
+ inherit (dbusConfig) session_bus system_bus;
+ direct_wayland = app.insecureWayland;
+ sched_policy = app.schedPolicy;
+ sched_priority = app.schedPriority;
+ groups = app.groups ++ optional (cfg.sharefs.source != null) cfg.sharefs.group;
+
+ container = {
+ inherit (app)
+ wait_delay
+ devel
+ userns
+ device
+ tty
+ multiarch
+ env
+ ;
+ map_real_uid = app.mapRealUid;
+ host_net = app.hostNet;
+ host_abstract = app.hostAbstract;
+ share_runtime = app.shareRuntime;
+ share_tmpdir = app.shareTmpdir;
+
+ filesystem =
+ let
+ bind = src: {
+ type = "bind";
+ inherit src;
+ };
+ optBind = src: {
+ type = "bind";
+ inherit src;
+ optional = true;
+ };
+ optDevBind = src: {
+ type = "bind";
+ inherit src;
+ dev = true;
+ optional = true;
+ };
+ in
+ [
+ (bind "/bin")
+ (bind "/usr/bin")
+ (bind "/nix/store")
+ (optBind "/sys/block")
+ (optBind "/sys/bus")
+ (optBind "/sys/class")
+ (optBind "/sys/dev")
+ (optBind "/sys/devices")
+ ]
+ ++ optionals app.nix [
+ (bind "/nix/var")
+ ]
+ ++ optionals isGraphical [
+ (optDevBind "/dev/dri")
+ (optDevBind "/dev/nvidiactl")
+ (optDevBind "/dev/nvidia-modeset")
+ (optDevBind "/dev/nvidia-uvm")
+ (optDevBind "/dev/nvidia-uvm-tools")
+ (optDevBind "/dev/nvidia0")
+ ]
+ ++ optionals app.useCommonPaths cfg.commonPaths
+ ++ app.extraPaths
+ ++ [
+ {
+ type = "bind";
+ dst = "/etc/";
+ src = "/etc/";
+ special = true;
+ }
+ {
+ type = "link";
+ dst = "/run/current-system";
+ linkname = "/run/current-system";
+ dereference = true;
+ }
+ ]
+ ++ optionals (isGraphical && config.hardware.graphics.enable) (
+ [
+ {
+ type = "link";
+ dst = "/run/opengl-driver";
+ linkname = config.systemd.tmpfiles.settings.graphics-driver."/run/opengl-driver"."L+".argument;
+ }
+ ]
+ ++ optionals (app.multiarch && config.hardware.graphics.enable32Bit) [
+ {
+ type = "link";
+ dst = "/run/opengl-driver-32";
+ linkname = config.systemd.tmpfiles.settings.graphics-driver."/run/opengl-driver-32"."L+".argument;
+ }
+ ]
+ )
+ ++ [
+ {
+ type = "bind";
+ src = getsubhome userid app.identity;
+ write = true;
+ ensure = true;
+ }
+ ];
+
+ username = getsubname userid app.identity;
+ inherit (cfg) shell;
+ home = getsubhome userid app.identity;
+
+ path =
+ if app.path == null then
+ pkgs.writeScript "${app.name}-start" ''
+ #!${pkgs.zsh}${pkgs.zsh.shellPath}
+ ${script}
+ ''
+ else
+ app.path;
+ args = if app.args == null then [ "${app.name}-start" ] else app.args;
+ };
+ };
+
+ checkedConfig =
+ name: value:
+ let
+ file = pkgs.writeText name (builtins.toJSON value);
+ in
+ pkgs.runCommand "checked-${name}" { nativeBuildInputs = [ cfg.package ]; } ''
+ ln -vs ${file} "$out"
+ hakurei show --no-store ${file}
+ '';
+ in
+ pkgs.writeShellScriptBin app.name ''
+ exec hakurei${if app.verbose then " -v" else ""}${if app.insecureWayland then " --insecure" else ""} run ${checkedConfig "hakurei-app-${app.name}.json" conf} $@
+ ''
+ )
+ ]
+ ++ (
+ let
+ pkg = if app.share != null then app.share else pkgs.${app.name};
+ copy = source: "[ -d '${source}' ] && cp -Lrv '${source}' $out/share || true";
+ in
+ optional (app.enablements.wayland || app.enablements.x11) (
+ pkgs.runCommand "${app.name}-share" { } ''
+ mkdir -p $out/share
+ ${copy "${pkg}/share/applications"}
+ ${copy "${pkg}/share/pixmaps"}
+ ${copy "${pkg}/share/icons"}
+ ${copy "${pkg}/share/man"}
+
+ if test -d "$out/share/applications"; then
+ substituteInPlace $out/share/applications/* \
+ --replace-warn '${pkg}/bin/' "" \
+ --replace-warn '${pkg}/libexec/' ""
+ fi
+ ''
+ )
+ )
+ ++ acc
+ ) [ cfg.package ] cfg.apps;
+ }) cfg.users;
+ in
+ {
+ useUserPackages = false; # prevent users.users entries from being added
+
+ users =
+ mkMerge
+ (foldlAttrs
+ (
+ acc: _: fid:
+ foldlAttrs
+ (
+ acc: _: app:
+ (
+ let
+ key = getsubname fid app.identity;
+ in
+ {
+ usernames = acc.usernames // {
+ ${key} = true;
+ };
+ merge = acc.merge ++ [
+ {
+ ${key} = mkMerge (
+ [
+ app.extraConfig
+ { home.packages = app.packages; }
+ ]
+ ++ lib.optional (!attrsets.hasAttrByPath [ key ] acc.usernames) cfg.extraHomeConfig
+ );
+ }
+ ];
+ }
+ )
+ )
+ {
+ inherit (acc) usernames;
+ merge = acc.merge ++ [ { ${getsubname fid 0} = cfg.extraHomeConfig; } ];
+ }
+ cfg.apps
+ )
+ {
+ usernames = { };
+ merge = [ privPackages ];
+ }
+ cfg.users
+ ).merge;
+ };
+
+ users =
+ let
+ getuser = userid: appid: {
+ isSystemUser = true;
+ createHome = true;
+ description = "Hakurei subordinate user ${toString appid} (u${toString userid})";
+ group = getsubname userid appid;
+ home = getsubhome userid appid;
+ uid = getsubuid userid appid;
+ };
+ getgroup = userid: appid: { gid = getsubuid userid appid; };
+ in
+ {
+ users = mkMerge (
+ foldlAttrs
+ (
+ acc: username: fid:
+ acc
+ ++
+ foldlAttrs
+ (
+ acc': _: app:
+ acc' ++ [ { ${getsubname fid app.identity} = getuser fid app.identity; } ]
+ )
+ [
+ {
+ ${getsubname fid 0} = getuser fid 0;
+ ${username}.extraGroups = [ cfg.sharefs.group ];
+ }
+ ]
+ cfg.apps
+ )
+ (optional (cfg.sharefs.source != null) {
+ ${cfg.sharefs.user} = {
+ uid = lib.mkDefault 1023;
+ inherit (cfg.sharefs) group;
+ isSystemUser = true;
+ home = cfg.sharefs.source;
+ };
+ })
+ cfg.users
+ );
+
+ groups = mkMerge (
+ foldlAttrs
+ (
+ acc: _: fid:
+ acc
+ ++ foldlAttrs (
+ acc': _: app:
+ acc' ++ [ { ${getsubname fid app.identity} = getgroup fid app.identity; } ]
+ ) [ { ${getsubname fid 0} = getgroup fid 0; } ] cfg.apps
+ )
+ (optional (cfg.sharefs.source != null) {
+ ${cfg.sharefs.group} = {
+ gid = lib.mkDefault 1023;
+ };
+ })
+ cfg.users
+ );
+ };
+ };
+}