nixos: guard home.uid with tryEval

Use tryEval when reading users.users.<name>.uid so configured NixOS
UIDs still propagate to home.uid while nix-darwin users without a
UID do not trigger a no-value-defined eval error.

Refs #8351
This commit is contained in:
Austin Horstman
2026-04-20 10:25:49 -05:00
parent 1072f064e2
commit 56b4526cfd
3 changed files with 124 additions and 1 deletions

View File

@@ -53,9 +53,16 @@ let
};
home = {
uid =
let
# `users.users.<name>.uid` may be declared but unset on
# nix-darwin, so probe it with `tryEval` instead of forcing a
# no-value-defined error during module evaluation.
userUid = builtins.tryEval config.users.users.${name}.uid;
in
mkIf (userUid.success && userUid.value != null) userUid.value;
username = config.users.users.${name}.name;
homeDirectory = config.users.users.${name}.home;
uid = mkIf (options.users.users.${name}.uid.isDefined or false) config.users.users.${name}.uid;
};
nix = {

View File

@@ -3,6 +3,7 @@
home-session-search-variables = ./session-search-variables.nix;
home-session-variables = ./session-variables.nix;
home-nixpkgs-release-check-pkgs = ./nixpkgs-release-check-pkgs.nix;
home-uid-from-nixos = ./uid-from-nixos.nix;
home-uid = ./uid.nix;
home-uid-null = ./uid-null.nix;
}

View File

@@ -0,0 +1,115 @@
{ lib, pkgs, ... }:
let
nixosLib = import /${pkgs.path}/nixos/lib { inherit lib; };
getHomeUid =
userConfig:
(nixosLib.evalTest {
hostPkgs = pkgs;
nodes.machine.imports = [
../../../nixos
{
users.users.alice = {
isNormalUser = true;
}
// userConfig;
home-manager.users.alice.home.stateVersion = "24.11";
}
];
}).config.nodes.machine.home-manager.users.alice.home.uid;
getCommonModuleHomeUidResult =
userConfig:
builtins.tryEval (
(lib.evalModules {
specialArgs = {
inherit pkgs;
_class = "darwin";
};
modules = [
../../../nixos/common.nix
(_: {
options.users.users = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule (
{ name, ... }:
{
options = {
name = lib.mkOption {
type = lib.types.str;
default = name;
};
home = lib.mkOption { type = lib.types.str; };
uid = lib.mkOption { type = lib.types.int; };
packages = lib.mkOption {
type = lib.types.listOf lib.types.package;
default = [ ];
};
};
}
)
);
default = { };
};
options.environment.pathsToLink = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
};
options.nix.enable = lib.mkOption {
type = lib.types.bool;
default = true;
};
options.nix.package = lib.mkOption {
type = lib.types.package;
default = pkgs.nix;
};
options.warnings = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
};
options.assertions = lib.mkOption {
type = lib.types.listOf (
lib.types.submodule (_: {
options.assertion = lib.mkOption { type = lib.types.bool; };
options.message = lib.mkOption { type = lib.types.str; };
})
);
default = [ ];
};
config.users.users.alice = {
home = "/Users/alice";
}
// userConfig;
config.home-manager.users.alice.home.stateVersion = "24.11";
})
];
}).config.home-manager.users.alice.home.uid
);
forwardedUid = builtins.toJSON (getHomeUid {
uid = 1000;
});
unsetUid = builtins.toJSON (getHomeUid { });
commonUnsetUidResult = getCommonModuleHomeUidResult { };
commonUnsetUidSuccess = builtins.toJSON commonUnsetUidResult.success;
commonUnsetUidValue = builtins.toJSON (
if commonUnsetUidResult.success then commonUnsetUidResult.value else "failed"
);
in
{
nmt.script = ''
test "${forwardedUid}" = '1000'
test "${unsetUid}" = 'null'
test "${commonUnsetUidSuccess}" = 'true'
test "${commonUnsetUidValue}" = 'null'
'';
}