hive-c0re: one binding for /run/hyperhive's mode

The mode was declared twice in this file — the service unit's
RuntimeDirectoryMode and the socket unit's DirectoryMode — with only a
prose "must match" note tying them. Whichever unit activates first creates
the directory, so they cannot be allowed to disagree.

Both literals are in one file, so they become a `let`. Deleting a copy
beats checking it, and unlike rendering the mode into hive-priv it costs no
config knob for a value nobody should ever set.

hive-priv's tmpfiles.d entry for the same path is a third declaration that
cannot read this binding, and is left in step by hand. An earlier revision
of this branch added a CI check for exactly that pair; mara pointed out it
was keyed to one path rather than to the class, and looking for the general
case found two more paths declared by more than one mechanism — including
/run/hive-agent, where hive-gateway's tmpfiles rule and hive-priv's
generated one disagreed on the owner and the winner depended on systemd's
read order. That check is being reworked as a general one, tracked
separately, so nothing about it rides in here.

Verified: nix fmt (713 traversed, 5 formatted, 0 changed); the three
scripts/check-*.sh lints all exit 0 with the tree staged; .forgejo/ is now
byte-identical to main and the diff is this one file. checks.module-eval
reported 91 module properties hold on the previous revision of this branch
— the only nix change since is comment text inside the same let block,
which cannot affect evaluation.
This commit is contained in:
atlas 2026-09-11 19:09:02 +02:00 committed by mara
commit 47d53f5c23

View file

@ -13,6 +13,20 @@
let
cfg = config.services.hyperhive.c0re;
# `/run/hyperhive`'s mode. Held in one place because whichever of the two
# units below activates first creates the directory, so they cannot be
# allowed to disagree about what it should be. `0751` is traverse-only, no
# listing: `hive-admin` members reach `host.sock` without root, while the
# socket's own `0660 hive-admin` gates the connection and the per-agent
# subdirs keep their own perms.
#
# hive-priv writes a tmpfiles.d entry for this same path and cannot read
# this binding, so the two are kept in step by hand. Divergence is not
# cosmetic: tmpfiles then tries to fchmod a directory hive-priv has no
# write access to, the whole `--create` run fails, and a single WARN per
# sync is the only symptom.
runtimeDirMode = "0751";
baoDeploy = config.services.hyperhive.deploy.bao;
# Held in one place because the LoadCredential below and the `BAO_*`
# environment in ./environment.nix have to agree on when they exist: a
@ -313,12 +327,7 @@ in
Group = "hive-core";
SupplementaryGroups = [ "systemd-journal" ];
RuntimeDirectory = "hyperhive";
# 0751 (traverse-only, no listing) so `hive-admin` operators can reach
# the host admin socket (`SocketGroup = "hive-admin"`, 0660) without
# root. Others can traverse but not list; the socket + per-agent
# subdirs gate access by their own perms. Matches the socket unit's
# DirectoryMode.
RuntimeDirectoryMode = "0751";
RuntimeDirectoryMode = runtimeDirMode;
RuntimeDirectoryPreserve = "yes";
StateDirectory = "hyperhive";
StateDirectoryMode = "0750";
@ -416,12 +425,9 @@ in
# so it stays effectively root-only. See docs/trust-boundary/boundary.md.
SocketMode = "0660";
SocketGroup = "hive-admin";
# `0751` (traverse-only, no listing) so hive-admin can reach the socket
# path — the socket's own `0660 hive-admin` gates the connection, and
# the per-agent subdirs under here keep their own restrictive perms.
# Must match the service unit's RuntimeDirectoryMode. DirectoryMode is
# only consulted when the dir is absent at socket-unit activation.
DirectoryMode = "0751";
# Only consulted when the directory is absent at socket-unit
# activation — i.e. when this unit wins the race with the service.
DirectoryMode = runtimeDirMode;
};
};
};