diff --git a/nixos/doc/manual/release-notes/rl-2411.section.md b/nixos/doc/manual/release-notes/rl-2411.section.md index b3b2af8d0778c4..ef23b74c88c311 100644 --- a/nixos/doc/manual/release-notes/rl-2411.section.md +++ b/nixos/doc/manual/release-notes/rl-2411.section.md @@ -360,6 +360,10 @@ - the `ankisyncd` package and its `services.ankisyncd` have been removed, use [`services.anki-sync-server`](#opt-services.anki-sync-server.enable) instead. +- The `octoprint` service has gained an `enableRaspberryPi` option, which will + be disabled for state versions following 25.05. Users running on Raspberry Pi + should enable the option to restore full functionality. + - `nodePackages.vscode-css-languageserver-bin`, `nodePackages.vscode-html-languageserver-bin`, and `nodePackages.vscode-json-languageserver-bin` were dropped due to an unmaintained upstream. The `vscode-langservers-extracted` package is a maintained drop-in replacement. diff --git a/nixos/modules/services/misc/octoprint.nix b/nixos/modules/services/misc/octoprint.nix index 1801b1f64021ea..31dbb6b3dde76a 100644 --- a/nixos/modules/services/misc/octoprint.nix +++ b/nixos/modules/services/misc/octoprint.nix @@ -4,21 +4,24 @@ pkgs, ... }: - let - cfg = config.services.octoprint; + inherit (lib) + literalExpression + mkDefault + mkEnableOption + mkOption + mkRenamedOptionModule + optional + types + versionOlder + ; - baseConfig = { - plugins.curalegacy.cura_engine = "${pkgs.curaengine_stable}/bin/CuraEngine"; - server.host = cfg.host; - server.port = cfg.port; - webcam.ffmpeg = "${pkgs.ffmpeg.bin}/bin/ffmpeg"; - }; + cfg = config.services.octoprint; - fullConfig = lib.recursiveUpdate cfg.extraConfig baseConfig; + formatType = pkgs.formats.json { }; - cfgUpdate = pkgs.writeText "octoprint-config.yaml" (builtins.toJSON fullConfig); + configFile = formatType.generate "octoprint-config.yaml" cfg.settings; pluginsEnv = package.python.withPackages (ps: [ ps.octoprint ] ++ (cfg.plugins ps)); @@ -74,18 +77,32 @@ in description = "State directory of the daemon."; }; - plugins = lib.mkOption { - type = lib.types.functionTo (lib.types.listOf lib.types.package); - default = plugins: [ ]; - defaultText = lib.literalExpression "plugins: []"; - example = lib.literalExpression "plugins: with plugins; [ themeify stlviewer ]"; + plugins = mkOption { + type = types.functionTo (types.listOf types.package); + default = _plugins: [ ]; + defaultText = literalExpression "plugins: []"; + example = literalExpression "plugins: with plugins; [ themeify stlviewer ]"; description = "Additional plugins to be used. Available plugins are passed through the plugins input."; }; - extraConfig = lib.mkOption { - type = lib.types.attrs; + settings = mkOption { default = { }; - description = "Extra options which are added to OctoPrint's YAML configuration file."; + description = '' + The octoprint settings, for definitions see the upstream [documentation](https://docs.octoprint.org). + Will override any existing settings. + ''; + type = types.submodule { + freeformType = formatType.type; + config = { + plugins.curalegacy.cura_engine = mkDefault "${pkgs.curaengine_stable}/bin/CuraEngine"; + server.host = cfg.host; + server.port = cfg.port; + webcam.ffmpeg = mkDefault "${pkgs.ffmpeg.bin}/bin/ffmpeg"; + }; + }; + }; + enableRaspberryPi = mkEnableOption "RaspberryPi specific hardware access rules" // { + default = versionOlder config.system.stateVersion "25.05"; }; }; @@ -93,6 +110,20 @@ in }; ##### implementation + imports = [ + (mkRenamedOptionModule + [ + "services" + "octoprint" + "extraConfig" + ] + [ + "services" + "octoprint" + "settings" + ] + ) + ]; config = lib.mkIf cfg.enable { @@ -107,12 +138,13 @@ in octoprint.gid = config.ids.gids.octoprint; }; - systemd.tmpfiles.rules = [ - "d '${cfg.stateDir}' - ${cfg.user} ${cfg.group} - -" - # this will allow octoprint access to raspberry specific hardware to check for throttling - # read-only will not work: "VCHI initialization failed" error - "a /dev/vchiq - - - - u:octoprint:rw" - ]; + systemd.tmpfiles.rules = + [ "d '${cfg.stateDir}' - ${cfg.user} ${cfg.group} - -" ] + ++ optional cfg.enableRaspberryPi + # this will allow octoprint access to raspberry specific hardware to check for throttling + # read-only will not work: "VCHI initialization failed" error + # FIXME: this should probably be a udev rule + "a /dev/vchiq - - - - u:octoprint:rw"; systemd.services.octoprint = { description = "OctoPrint, web interface for 3D printers"; @@ -122,10 +154,10 @@ in preStart = '' if [ -e "${cfg.stateDir}/config.yaml" ]; then - ${pkgs.yaml-merge}/bin/yaml-merge "${cfg.stateDir}/config.yaml" "${cfgUpdate}" > "${cfg.stateDir}/config.yaml.tmp" + ${pkgs.yaml-merge}/bin/yaml-merge "${cfg.stateDir}/config.yaml" "${configFile}" > "${cfg.stateDir}/config.yaml.tmp" mv "${cfg.stateDir}/config.yaml.tmp" "${cfg.stateDir}/config.yaml" else - cp "${cfgUpdate}" "${cfg.stateDir}/config.yaml" + cp "${configFile}" "${cfg.stateDir}/config.yaml" chmod 600 "${cfg.stateDir}/config.yaml" fi ''; @@ -135,6 +167,37 @@ in User = cfg.user; Group = cfg.group; SupplementaryGroups = [ "dialout" ]; + + # Hardening + CapabilityBoundingSet = ""; + LockPersonality = true; + MemoryDenyWriteExecute = true; + PrivateUsers = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProcSubset = "pid"; + ProtectSystem = "strict"; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_NETLINK" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "@pkey" + ]; + ReadWritePaths = [ cfg.stateDir ]; + UMask = "0077"; + }; }; diff --git a/nixos/tests/octoprint.nix b/nixos/tests/octoprint.nix index 15a2d677d4cf8b..968fef08144ea5 100644 --- a/nixos/tests/octoprint.nix +++ b/nixos/tests/octoprint.nix @@ -11,7 +11,7 @@ in environment.systemPackages = with pkgs; [ jq ]; services.octoprint = { enable = true; - extraConfig = { + settings = { server = { firstRun = false; };