All checks were successful
Test / Create distribution (push) Successful in 34s
Test / Sandbox (push) Successful in 2m13s
Test / Hakurei (push) Successful in 3m10s
Test / Hpkg (push) Successful in 4m5s
Test / Sandbox (race detector) (push) Successful in 4m27s
Test / Hakurei (race detector) (push) Successful in 5m7s
Test / Flake checks (push) Successful in 1m28s
There is no reason to give the home directory special treatment, as this behaviour can be quite confusing. The home directory also does not necessarily require its own mount point, it could be provided by a parent or simply be ephemeral. Signed-off-by: Ophestra <cat@gensokyo.uk>
349 lines
12 KiB
Nix
349 lines
12 KiB
Nix
packages:
|
|
{
|
|
lib,
|
|
pkgs,
|
|
config,
|
|
...
|
|
}:
|
|
|
|
let
|
|
inherit (lib)
|
|
lists
|
|
attrsets
|
|
mkMerge
|
|
mkIf
|
|
mapAttrs
|
|
foldlAttrs
|
|
optional
|
|
optionals
|
|
;
|
|
|
|
cfg = config.environment.hakurei;
|
|
|
|
getsubuid = fid: aid: 1000000 + fid * 10000 + aid;
|
|
getsubname = fid: aid: "u${toString fid}_a${toString aid}";
|
|
getsubhome = fid: aid: "${cfg.stateDir}/u${toString fid}/a${toString aid}";
|
|
in
|
|
|
|
{
|
|
imports = [ (import ./options.nix packages) ];
|
|
|
|
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";
|
|
setgid = true;
|
|
group = "root";
|
|
};
|
|
|
|
environment.etc.hsurc = {
|
|
mode = "0400";
|
|
text = foldlAttrs (
|
|
acc: username: fid:
|
|
"${toString config.users.users.${username}.uid} ${toString fid}\n" + acc
|
|
) "" cfg.users;
|
|
};
|
|
|
|
home-manager =
|
|
let
|
|
privPackages = mapAttrs (username: fid: {
|
|
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 = {
|
|
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;
|
|
|
|
inherit id;
|
|
|
|
inherit (dbusConfig) session_bus system_bus;
|
|
direct_wayland = app.insecureWayland;
|
|
|
|
username = getsubname fid app.identity;
|
|
home = getsubhome fid app.identity;
|
|
|
|
inherit (cfg) shell;
|
|
inherit (app) identity groups enablements;
|
|
|
|
container = {
|
|
inherit (app)
|
|
wait_delay
|
|
devel
|
|
userns
|
|
device
|
|
tty
|
|
multiarch
|
|
env
|
|
;
|
|
map_real_uid = app.mapRealUid;
|
|
host_net = app.hostNet;
|
|
host_abstract = app.hostAbstract;
|
|
|
|
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 fid app.identity;
|
|
write = true;
|
|
ensure = true;
|
|
}
|
|
];
|
|
};
|
|
};
|
|
|
|
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 ${file}
|
|
'';
|
|
in
|
|
pkgs.writeShellScriptBin app.name ''
|
|
exec hakurei${if app.verbose then " -v" else ""} app ${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 = fid: aid: {
|
|
isSystemUser = true;
|
|
createHome = true;
|
|
description = "Hakurei subordinate user ${toString aid} (u${toString fid})";
|
|
group = getsubname fid aid;
|
|
home = getsubhome fid aid;
|
|
uid = getsubuid fid aid;
|
|
};
|
|
getgroup = fid: aid: { gid = getsubuid fid aid; };
|
|
in
|
|
{
|
|
users = mkMerge (
|
|
foldlAttrs (
|
|
acc: _: fid:
|
|
acc
|
|
++ foldlAttrs (
|
|
acc': _: app:
|
|
acc' ++ [ { ${getsubname fid app.identity} = getuser fid app.identity; } ]
|
|
) [ { ${getsubname fid 0} = getuser fid 0; } ] cfg.apps
|
|
) [ ] 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
|
|
) [ ] cfg.users
|
|
);
|
|
};
|
|
};
|
|
}
|