feat(#903): expose hyperhive.user.uid + gid options for optional UID pinning

This commit is contained in:
atlas 2026-06-03 17:20:08 +02:00 committed by mara
commit 0d5f7e00b6

View file

@ -132,9 +132,42 @@ in
Constraints match `useradd`'s NAME_REGEX: lowercase / `_` start,
total length 31, no special characters. UID is auto-assigned
by NixOS; no `uid =` override surface (intentional pinning
across rebuilds isn't a concern when the home and state dirs
stay bind-mounted from the host).
by NixOS unless `hyperhive.user.uid` is explicitly set.
'';
};
options.hyperhive.user.uid = lib.mkOption {
type = lib.types.nullOr lib.types.int;
default = null;
example = 1100;
description = ''
Optional fixed UID for the per-agent unix user. `null` (default)
lets NixOS auto-assign from the normal-user range ( 1000),
which is the right default for most deployments the UID stays
stable across container rebuilds because each container only has
one normal user and the assignment is written into the container's
`/etc/passwd` at activation time.
Set an explicit value only when the host needs a predictable UID
for the agent's state files e.g. if an operator script
references files by numeric UID, or to keep ownership stable
across full container destroy + recreate on a fresh host.
Values must be in `[1000, 60000)`. Using UIDs < 1000 clashes with
system accounts and is rejected by NixOS.
'';
};
options.hyperhive.user.gid = lib.mkOption {
type = lib.types.nullOr lib.types.int;
default = null;
example = 1100;
description = ''
Optional fixed GID for the per-agent unix group. `null` (default)
lets NixOS auto-assign. When `uid` is set, setting `gid` to the
same value keeps uid == gid (the conventional Unix pattern for
per-user groups). Has no effect unless also setting
`hyperhive.user.uid`.
'';
};
@ -1063,14 +1096,35 @@ in
`..` path segments.
'';
}
{
assertion =
config.hyperhive.user.uid == null
|| (config.hyperhive.user.uid >= 1000 && config.hyperhive.user.uid < 60000);
message = ''
hyperhive.user.uid must be in [1000, 60000) values below
1000 clash with system accounts; values 60000 are reserved
by NixOS for dynamic allocation. Leave unset (null) to let
NixOS auto-assign.
'';
}
{
assertion =
config.hyperhive.user.gid == null
|| (config.hyperhive.user.gid >= 1000 && config.hyperhive.user.gid < 60000);
message = ''
hyperhive.user.gid must be in [1000, 60000) same range
constraint as hyperhive.user.uid.
'';
}
];
# Per-agent unix user. Runs the hive harness +
# co-process daemons under a non-root principal. UID auto-assigned by
# NixOS. The container activation script (hive-agent-user-migrate)
# chowns the bind-mounted state dir — including credential files
# written by hive-c0re before the container was built — to this user
# on every boot, so agent processes can always read their own tokens.
# NixOS unless `hyperhive.user.uid` is set. The container activation
# script (hive-agent-user-migrate) chowns the bind-mounted state dir
# — including credential files written by hive-c0re before the
# container was built — to this user on every boot, so agent
# processes can always read their own tokens.
users.users.${userName} = {
isNormalUser = true;
home = homeDir;
@ -1082,8 +1136,15 @@ in
# the system default for the root user too (see SHELL env
# var declaration below).
shell = pkgs.bashInteractive;
}
// lib.optionalAttrs (config.hyperhive.user.uid != null) {
uid = config.hyperhive.user.uid;
};
users.groups.${userName} = { };
users.groups.${userName} =
{ }
// lib.optionalAttrs (config.hyperhive.user.gid != null) {
gid = config.hyperhive.user.gid;
};
# `NOPASSWD: ALL` for the agent user. Lets claude's Bash tool
# keep working with anything that expected root (systemctl,