mirror of
https://github.com/nix-community/home-manager.git
synced 2025-11-08 11:36:05 +01:00
Co-authored-by: Matthias Beyer <mail@beyermatthias.de> Co-authored-by: Austin Horstman <khaneliman12@gmail.com>
245 lines
7.1 KiB
Nix
245 lines
7.1 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
options,
|
|
...
|
|
}:
|
|
let
|
|
inherit (lib)
|
|
generators
|
|
getBin
|
|
getExe'
|
|
last
|
|
mapAttrsToList
|
|
mkDefault
|
|
mkEnableOption
|
|
mkIf
|
|
mkOption
|
|
mkMerge
|
|
mkPackageOption
|
|
splitString
|
|
;
|
|
|
|
inherit (lib.types)
|
|
attrsOf
|
|
nullOr
|
|
oneOf
|
|
package
|
|
path
|
|
str
|
|
;
|
|
|
|
cfg = config.services.radicle;
|
|
|
|
radicleHome = config.home.homeDirectory + "/.radicle";
|
|
|
|
gitPath = [ "PATH=${getBin pkgs.gitMinimal}/bin" ];
|
|
env = attrs: (mapAttrsToList (generators.mkKeyValueDefault { } "=") attrs) ++ gitPath;
|
|
in
|
|
{
|
|
options = {
|
|
services.radicle = {
|
|
node = {
|
|
enable = mkEnableOption "Radicle Node";
|
|
package = mkPackageOption pkgs "radicle-node" { };
|
|
args = mkOption {
|
|
type = str;
|
|
description = "Additional command line arguments to pass when executing `radicle-node`.";
|
|
default = "";
|
|
example = "--force";
|
|
};
|
|
environment = mkOption {
|
|
type = attrsOf (
|
|
nullOr (oneOf [
|
|
str
|
|
path
|
|
package
|
|
])
|
|
);
|
|
description = "Environment to set when executing `radicle-node`.";
|
|
default = { };
|
|
example = {
|
|
"RUST_BACKTRACE" = "full";
|
|
};
|
|
};
|
|
lazy = {
|
|
enable = mkEnableOption "a proxy service to lazily start and stop Radicle Node on demand";
|
|
exitIdleTime = mkOption {
|
|
type = str;
|
|
description = "The idle time after which no interaction with Radicle Node via the `rad` CLI should be stopped, in a format that {manpage}`systemd-socket-proxyd(8)` understands for its `--exit-idle-time` argument.";
|
|
default = "30min";
|
|
example = "1h";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.node.enable {
|
|
systemd.user = {
|
|
services = {
|
|
"radicle-node" =
|
|
let
|
|
keyFile = name: "${radicleHome}/keys/${name}";
|
|
keyPair = name: [
|
|
(keyFile name)
|
|
(keyFile (name + ".pub"))
|
|
];
|
|
radicleKeyPair = keyPair "radicle";
|
|
in
|
|
{
|
|
Unit = {
|
|
Description = "Radicle Node";
|
|
Documentation = [
|
|
"https://radicle.xyz/guides"
|
|
"man:radicle-node(1)"
|
|
];
|
|
StopWhenUnneeded = cfg.node.lazy.enable;
|
|
ConditionPathExists = radicleKeyPair;
|
|
};
|
|
Service = mkMerge ([
|
|
{
|
|
Slice = "session.slice";
|
|
ExecStart = "${getExe' cfg.node.package "radicle-node"} ${cfg.node.args}";
|
|
Environment = env cfg.node.environment;
|
|
KillMode = "process";
|
|
Restart = "no";
|
|
RestartSec = "2";
|
|
RestartSteps = "100";
|
|
RestartMaxDelaySec = "1min";
|
|
}
|
|
{
|
|
# Hardening
|
|
|
|
BindPaths = [
|
|
"${radicleHome}/storage"
|
|
"${radicleHome}/node"
|
|
"${radicleHome}/cobs"
|
|
];
|
|
|
|
BindReadOnlyPaths = [
|
|
"${radicleHome}/config.json"
|
|
"${radicleHome}/keys"
|
|
"-/etc/resolv.conf"
|
|
"/run/systemd"
|
|
];
|
|
|
|
RestrictAddressFamilies = [
|
|
"AF_UNIX"
|
|
"AF_INET"
|
|
"AF_INET6"
|
|
];
|
|
|
|
AmbientCapabilities = "";
|
|
CapabilityBoundingSet = "";
|
|
NoNewPrivileges = true;
|
|
|
|
DeviceAllow = ""; # ProtectClock= adds DeviceAllow=char-rtc r
|
|
KeyringMode = "private";
|
|
LockPersonality = true;
|
|
MemoryDenyWriteExecute = true;
|
|
PrivateDevices = true;
|
|
PrivateTmp = true;
|
|
PrivateUsers = "self";
|
|
|
|
ProcSubset = "pid";
|
|
ProtectClock = true;
|
|
ProtectHome = "tmpfs";
|
|
ProtectHostname = true;
|
|
ProtectKernelLogs = true;
|
|
ProtectProc = "invisible";
|
|
ProtectSystem = "strict";
|
|
|
|
RestrictNamespaces = true;
|
|
RestrictRealtime = true;
|
|
RestrictSUIDSGID = true;
|
|
|
|
RuntimeDirectoryMode = "0700";
|
|
|
|
SocketBindDeny = [ "any" ];
|
|
SocketBindAllow = map (
|
|
addr: "tcp:${last (splitString ":" addr)}"
|
|
) config.programs.radicle.settings.node.listen;
|
|
|
|
StateDirectoryMode = "0750";
|
|
UMask = "0067";
|
|
|
|
SystemCallArchitectures = "native";
|
|
SystemCallFilter = [
|
|
"@system-service"
|
|
"~@aio"
|
|
"~@chown"
|
|
"~@keyring"
|
|
"~@memlock"
|
|
"~@privileged"
|
|
"~@resources"
|
|
"~@setuid"
|
|
];
|
|
}
|
|
]);
|
|
};
|
|
"radicle-node-proxy" = mkIf cfg.node.lazy.enable {
|
|
Unit = {
|
|
Description = "Radicle Node Proxy";
|
|
BindsTo = [
|
|
"radicle-node-proxy.socket"
|
|
"radicle-node.service"
|
|
];
|
|
After = [
|
|
"radicle-node-proxy.socket"
|
|
"radicle-node.service"
|
|
];
|
|
Documentation = [ "man:systemd-socket-proxyd(8)" ];
|
|
};
|
|
Service = {
|
|
ExecSearchPath = "${pkgs.systemd}/lib/systemd";
|
|
ExecStart = "systemd-socket-proxyd --exit-idle-time=${cfg.node.lazy.exitIdleTime} %t/radicle-node/proxy.sock";
|
|
PrivateTmp = "yes";
|
|
PrivateNetwork = "yes";
|
|
RuntimeDirectory = "radicle";
|
|
RuntimeDirectoryPreserve = "yes";
|
|
};
|
|
};
|
|
};
|
|
sockets = mkIf cfg.node.lazy.enable {
|
|
"radicle-node-control" = {
|
|
Unit = {
|
|
Description = "Radicle Node Control Socket";
|
|
Documentation = [ "man:radicle-node(1)" ];
|
|
};
|
|
Socket = {
|
|
Service = "radicle-node-proxy.service";
|
|
ListenStream = "%t/radicle-node/control.sock";
|
|
RuntimeDirectory = "radicle-node";
|
|
RuntimeDirectoryPreserve = "yes";
|
|
};
|
|
Install.WantedBy = [ "sockets.target" ];
|
|
};
|
|
"radicle-node-proxy" = {
|
|
Unit = {
|
|
Description = "Radicle Node Proxy Socket";
|
|
Documentation = [ "man:systemd-socket-proxyd(8)" ];
|
|
};
|
|
Socket = {
|
|
Service = "radicle-node.service";
|
|
FileDescriptorName = "control";
|
|
ListenStream = "%t/radicle-node/proxy.sock";
|
|
RuntimeDirectory = "radicle-node";
|
|
RuntimeDirectoryPreserve = "yes";
|
|
};
|
|
Install.WantedBy = [ "sockets.target" ];
|
|
};
|
|
};
|
|
};
|
|
programs.radicle.enable = mkDefault true;
|
|
home.sessionVariables = mkIf cfg.node.lazy.enable {
|
|
RAD_SOCKET = "\${XDG_RUNTIME_DIR:-/run/user/$UID}/radicle-node/control.sock";
|
|
};
|
|
};
|
|
|
|
meta.maintainers = with lib.maintainers; [
|
|
lorenzleutgeb
|
|
matthiasbeyer
|
|
];
|
|
}
|