nixos/redlib: format, add maintainer, add cfg.settings, use upstream systemd unit (#345715)

This commit is contained in:
Franz Pletz 2024-11-24 17:13:16 +01:00 committed by GitHub
commit d4b1fcdbe6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 114 additions and 58 deletions

View File

@ -1,18 +1,44 @@
{ config, lib, pkgs, ... }: {
config,
with lib; lib,
pkgs,
...
}:
let let
inherit (lib)
concatStringsSep
isBool
mapAttrs
mkEnableOption
mkIf
mkOption
mkPackageOption
mkRenamedOptionModule
types
;
cfg = config.services.redlib; cfg = config.services.redlib;
args = concatStringsSep " " ([ args = concatStringsSep " " ([
"--port ${toString cfg.port}" "--port ${toString cfg.port}"
"--address ${cfg.address}" "--address ${cfg.address}"
]); ]);
boolToString' = b: if b then "on" else "off";
in in
{ {
imports = [ imports = [
(mkRenamedOptionModule [ "services" "libreddit" ] [ "services" "redlib" ]) (mkRenamedOptionModule
[
"services"
"libreddit"
]
[
"services"
"redlib"
]
)
]; ];
options = { options = {
@ -24,7 +50,7 @@ in
address = mkOption { address = mkOption {
default = "0.0.0.0"; default = "0.0.0.0";
example = "127.0.0.1"; example = "127.0.0.1";
type = types.str; type = types.str;
description = "The address to listen on"; description = "The address to listen on";
}; };
@ -41,50 +67,60 @@ in
description = "Open ports in the firewall for the redlib web interface"; description = "Open ports in the firewall for the redlib web interface";
}; };
settings = lib.mkOption {
type = lib.types.submodule {
freeformType =
with types;
attrsOf (
nullOr (oneOf [
bool
int
str
])
);
options = { };
};
default = { };
description = ''
See [GitHub](https://github.com/redlib-org/redlib/tree/main?tab=readme-ov-file#configuration) for available settings.
'';
};
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
systemd.packages = [ cfg.package ];
systemd.services.redlib = { systemd.services.redlib = {
description = "Private front-end for Reddit"; wantedBy = [ "default.target" ];
wantedBy = [ "multi-user.target" ]; environment = mapAttrs (_: v: if isBool v then boolToString' v else toString v) cfg.settings;
after = [ "network.target" ]; serviceConfig =
serviceConfig = { {
DynamicUser = true; ExecStart = [
ExecStart = "${lib.getExe cfg.package} ${args}"; ""
AmbientCapabilities = lib.mkIf (cfg.port < 1024) [ "CAP_NET_BIND_SERVICE" ]; "${lib.getExe cfg.package} ${args}"
Restart = "on-failure"; ];
RestartSec = "2s"; }
# Hardening // (
CapabilityBoundingSet = if (cfg.port < 1024) then [ "CAP_NET_BIND_SERVICE" ] else [ "" ]; if (cfg.port < 1024) then
DeviceAllow = [ "" ]; {
LockPersonality = true; AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
MemoryDenyWriteExecute = true; CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
PrivateDevices = true; }
# A private user cannot have process capabilities on the host's user else
# namespace and thus CAP_NET_BIND_SERVICE has no effect. {
PrivateUsers = (cfg.port >= 1024); # A private user cannot have process capabilities on the host's user
ProcSubset = "pid"; # namespace and thus CAP_NET_BIND_SERVICE has no effect.
ProtectClock = true; PrivateUsers = true;
ProtectControlGroups = true; }
ProtectHome = true; );
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [ "@system-service" "~@privileged" "~@resources" ];
UMask = "0077";
};
}; };
networking.firewall = mkIf cfg.openFirewall { networking.firewall = mkIf cfg.openFirewall {
allowedTCPPorts = [ cfg.port ]; allowedTCPPorts = [ cfg.port ];
}; };
}; };
meta = {
maintainers = with lib.maintainers; [ Guanran928 ];
};
} }

View File

@ -1,20 +1,31 @@
import ./make-test-python.nix ({ lib, pkgs, ... }: { import ./make-test-python.nix (
name = "redlib"; { lib, pkgs, ... }:
meta.maintainers = with lib.maintainers; [ soispha ]; {
name = "redlib";
meta.maintainers = with lib.maintainers; [
soispha
Guanran928
];
nodes.machine = { nodes.machine = {
services.redlib = { services.redlib = {
package = pkgs.redlib; package = pkgs.redlib;
enable = true; enable = true;
# Test CAP_NET_BIND_SERVICE # Test CAP_NET_BIND_SERVICE
port = 80; port = 80;
settings = {
REDLIB_DEFAULT_USE_HLS = true;
};
};
}; };
};
testScript = '' testScript = ''
machine.wait_for_unit("redlib.service") machine.wait_for_unit("redlib.service")
machine.wait_for_open_port(80) machine.wait_for_open_port(80)
# Query a page that does not require Internet access # Query a page that does not require Internet access
machine.succeed("curl --fail http://localhost:80/settings") machine.succeed("curl --fail http://localhost:80/settings")
''; machine.succeed("curl --fail http://localhost:80/info | grep '<tr><td>Use HLS</td><td>on</td></tr>'")
}) '';
}
)

View File

@ -24,6 +24,12 @@ rustPlatform.buildRustPackage rec {
darwin.apple_sdk.frameworks.Security darwin.apple_sdk.frameworks.Security
]; ];
postInstall = ''
install -Dm644 contrib/redlib.service $out/lib/systemd/system/redlib.service
substituteInPlace $out/lib/systemd/system/redlib.service \
--replace-fail "/usr/bin/redlib" "$out/bin/redlib"
'';
checkFlags = [ checkFlags = [
# All these test try to connect to Reddit. # All these test try to connect to Reddit.
# utils.rs # utils.rs
@ -68,6 +74,9 @@ rustPlatform.buildRustPackage rec {
homepage = "https://github.com/redlib-org/redlib"; homepage = "https://github.com/redlib-org/redlib";
license = lib.licenses.agpl3Only; license = lib.licenses.agpl3Only;
mainProgram = "redlib"; mainProgram = "redlib";
maintainers = with lib.maintainers; [ soispha ]; maintainers = with lib.maintainers; [
soispha
Guanran928
];
}; };
} }