diff --git a/nixos/doc/manual/release-notes/rl-2505.section.md b/nixos/doc/manual/release-notes/rl-2505.section.md index 680d3ffb55be..23c055a0c08a 100644 --- a/nixos/doc/manual/release-notes/rl-2505.section.md +++ b/nixos/doc/manual/release-notes/rl-2505.section.md @@ -162,6 +162,8 @@ - [`yarr`](https://github.com/nkanaev/yarr), a small, web-based feed aggregator and RSS reader. Available as [services.yarr](#opt-services.yarr.enable). +- [OliveTin](https://www.olivetin.app/), gives safe and simple access to predefined shell commands from a web interface. Available as [services.olivetin](#opt-services.olivetin.enable). + - [Stash](https://github.com/stashapp/stash), An organizer for your adult videos/images, written in Go. Available as [services.stash](#opt-services.stash.enable). - [vsmartcard-vpcd](https://frankmorgner.github.io/vsmartcard/virtualsmartcard/README.html), a virtual smart card driver. Available as [services.vsmartcard-vpcd](#opt-services.vsmartcard-vpcd.enable). diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 4b487179231b..1cf9cdbfdfe6 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1604,6 +1604,7 @@ ./services/web-apps/mediagoblin.nix ./services/web-apps/open-web-calendar.nix ./services/web-apps/mobilizon.nix + ./services/web-apps/olivetin.nix ./services/web-apps/openwebrx.nix ./services/web-apps/outline.nix ./services/web-apps/pds.nix diff --git a/nixos/modules/services/web-apps/olivetin.nix b/nixos/modules/services/web-apps/olivetin.nix new file mode 100644 index 000000000000..5facc7eb7a56 --- /dev/null +++ b/nixos/modules/services/web-apps/olivetin.nix @@ -0,0 +1,152 @@ +{ + config, + pkgs, + lib, + ... +}: + +let + cfg = config.services.olivetin; + + settingsFormat = pkgs.formats.yaml { }; +in + +{ + meta.maintainers = with lib.maintainers; [ defelo ]; + + options.services.olivetin = { + enable = lib.mkEnableOption "OliveTin"; + + package = lib.mkPackageOption pkgs "olivetin" { }; + + user = lib.mkOption { + type = lib.types.str; + description = "The user account under which OliveTin runs."; + default = "olivetin"; + }; + + group = lib.mkOption { + type = lib.types.str; + description = "The group under which OliveTin runs."; + default = "olivetin"; + }; + + path = lib.mkOption { + type = + with lib.types; + listOf (oneOf [ + package + str + ]); + description = '' + Packages added to the service's {env}`PATH`. + ''; + defaultText = lib.literalExpression '' + with pkgs; [ bash ] + ''; + }; + + settings = lib.mkOption { + description = '' + Configuration of OliveTin. See for more information. + ''; + default = { }; + + type = lib.types.submodule { + freeformType = settingsFormat.type; + + options = { + ListenAddressSingleHTTPFrontend = lib.mkOption { + type = lib.types.str; + description = '' + The address to listen on for the internal "microproxy" frontend. + ''; + default = "127.0.0.1:8000"; + example = "0.0.0.0:8000"; + }; + }; + }; + }; + + extraConfigFiles = lib.mkOption { + type = lib.types.listOf lib.types.path; + default = [ ]; + example = [ "/run/secrets/olivetin.yaml" ]; + description = '' + Config files to merge into the settings defined in [](#opt-services.olivetin.settings). + This is useful to avoid putting secrets into the nix store. + See for more information. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + services.olivetin = { + path = with pkgs; [ bash ]; + }; + + systemd.services.olivetin = { + description = "OliveTin"; + + wantedBy = [ "multi-user.target" ]; + + wants = [ + "network-online.target" + "local-fs.target" + ]; + after = [ + "network-online.target" + "local-fs.target" + ]; + + inherit (cfg) path; + + preStart = '' + tmp="$(mktemp -d)" + trap 'rm -rf "$tmp"' EXIT + cd "$tmp" + + cp ${settingsFormat.generate "olivetin-config.yaml" cfg.settings} config.yaml + chmod +w config.yaml + for ((i=0; i < ${toString (lib.length cfg.extraConfigFiles)}; i++)); do + ${lib.getExe pkgs.yq} -yi ' + def merge($y): + . as $x | + if ($x | type == "object") and ($y | type == "object") then + $x + $y + with_entries(select(.key | in($y)) | .key as $key | .value |= merge($y[$key])) + elif ($x | type == "array") and ($y | type == "array") then + $x + $y + else + $y + end; + merge($f | fromjson) + ' config.yaml --rawfile f <(${lib.getExe pkgs.yq} -c . "$CREDENTIALS_DIRECTORY/config-$i.yaml") + done + chmod -w config.yaml + + mkdir -p /run/olivetin/config + mv config.yaml /run/olivetin/config/config.yaml + ''; + + serviceConfig = { + User = cfg.user; + Group = cfg.group; + RuntimeDirectory = "olivetin"; + Restart = "always"; + + LoadCredential = lib.imap0 (i: path: "config-${toString i}.yaml:${path}") cfg.extraConfigFiles; + + ExecStart = "${lib.getExe cfg.package} -configdir /run/olivetin/config"; + }; + }; + + users.users = lib.mkIf (cfg.user == "olivetin") { + olivetin = { + group = cfg.group; + isSystemUser = true; + }; + }; + + users.groups = lib.mkIf (cfg.group == "olivetin") { olivetin = { }; }; + }; +}