about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--nix/modules/default.nix200
-rw-r--r--nix/modules/source-options.nix16
2 files changed, 216 insertions, 0 deletions
diff --git a/nix/modules/default.nix b/nix/modules/default.nix
new file mode 100644
index 0000000..6e2c86b
--- /dev/null
+++ b/nix/modules/default.nix
@@ -0,0 +1,200 @@
+{ config
+, lib
+, pkgs
+, ...
+}:
+
+let
+  cfg = config.services.searchix;
+
+  package = (import ../.. { inherit pkgs; }).searchix;
+
+  settingsFormat = pkgs.formats.toml { };
+
+  env = {
+    ENVIRONMENT = "production";
+    LISTEN_ADDRESS = cfg.listenAddress;
+    PORT = (toString cfg.port);
+    BASE_URL = cfg.baseUrl;
+    CONFIG_FILE = settingsFormat.generate "searchix-config.toml" cfg.settings;
+    LOG_LEVEL = cfg.logLevel;
+  };
+
+  defaultServiceConfig = {
+    User = cfg.user;
+    Group = cfg.group;
+    ReadWritePaths = [ cfg.homeDir ];
+    StateDirectory = mkIf (cfg.homeDir == "/var/lib/searchix") [ "searchix" ];
+    Restart = "on-failure";
+
+    CacheDirectory = "searchix";
+    CapabilityBoundingSet = "";
+    DeviceAllow = "";
+    LockPersonality = true;
+    MemoryDenyWriteExecute = true;
+    NoNewPrivileges = true;
+    PrivateDevices = true;
+    PrivateMounts = true;
+    PrivateTmp = true;
+    PrivateUsers = true;
+    ProtectClock = true;
+    ProtectHome = true;
+    ProtectHostname = true;
+    ProtectSystem = "strict";
+    ProtectControlGroups = true;
+    ProtectKernelLogs = true;
+    ProtectKernelModules = true;
+    ProtectKernelTunables = true;
+    RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
+    RestrictNamespaces = true;
+    RestrictRealtime = true;
+    RestrictSUIDSGID = true;
+    SystemCallArchitectures = "native";
+    SystemCallFilter = [ "@system-service" "~@privileged @setuid @keyring" ];
+    UMask = "0066";
+  };
+
+  inherit (lib) mkEnableOption mkOption mkIf optionalAttrs types;
+in
+{
+  options.services.searchix = {
+    enable = mkEnableOption "Searchix options search";
+
+    user = mkOption {
+      type = types.str;
+      default = "searchix";
+      description = "User account under which searchix runs.";
+    };
+
+    group = mkOption {
+      type = types.str;
+      default = "searchix";
+      description = "Group under which searchix runs.";
+    };
+
+    homeDir = mkOption {
+      type = types.path;
+      default = "/var/lib/searchix";
+      description = "Home directory for searchix user";
+    };
+
+    dates = mkOption {
+      type = types.singleLineStr;
+      default = "04:00";
+      example = "weekly";
+    };
+
+    port = mkOption {
+      type = types.port;
+      description = "Port for searchix to listen on";
+      default = 51313;
+    };
+
+    listenAddress = mkOption {
+      type = types.str;
+      description = "Listen on a specific IP address.";
+      default = "localhost";
+    };
+
+    baseUrl = mkOption {
+      type = types.str;
+      description = "The base URL that searchix will be served on.";
+      default = "http://localhost:3000";
+    };
+
+    sentryDsn = mkOption {
+      type = with types; nullOr str;
+      description = "Optionally enable sentry to track errors.";
+      default = null;
+    };
+
+    logLevel = mkOption {
+      type = with types; enum [ "error" "warn" "info" "debug" ];
+      description = "Only log messages with the given severity or above.";
+      default = "info";
+    };
+
+    importTimeout = mkOption {
+      type = types.str;
+      default = "30m";
+      description = ''
+        Maximum time to wait for all import jobs.
+        May need to be increased based on the number of sources.
+      '';
+    };
+
+    settings = mkOption {
+      type = types.submodule {
+        freeformType = settingsFormat.type;
+        options = {
+          data-path = mkOption {
+            type = types.str;
+            description = "Where to store search index and other data, can be relative to homeDir.";
+            default = "${cfg.homeDir}/data";
+          };
+          sources = mkOption {
+            type = with types; attrsOf (submodule (import ./source-options.nix { inherit cfg; }));
+            default = {
+              nixos.enable = true;
+              darwin.enable = false;
+              home-manager.enable = false;
+            };
+            description = "Declarative specification of options sources for searchix.";
+          };
+        };
+      };
+      default = { };
+      description = "Configuration for searchix (TODO: publish description).";
+    };
+  };
+
+  config = mkIf cfg.enable {
+    nixpkgs.overlays = [
+      (import "${(import ../sources.nix).gomod2nix}/overlay.nix")
+    ];
+
+    systemd.services.searchix-importer = {
+      description = "Searchix option importer";
+      unitConfig.Conflicts = [ "searchix-web" ];
+      path = with pkgs; [ nix ];
+      serviceConfig = defaultServiceConfig // {
+        ExecStart = "${package}/bin/import";
+        Type = "oneshot";
+      };
+      environment = env;
+      startAt = cfg.dates;
+    };
+
+    systemd.timers.searchix-importer = {
+      timerConfig = {
+        Persistent = true;
+        RandomizedDelaySec = 1800;
+      };
+    };
+
+    systemd.services.searchix-web = {
+      description = "Searchix Nix option search";
+      after = [ "searchix-importer.service" ];
+      wantedBy = [ "multi-user.target" ];
+      environment = env;
+      serviceConfig = defaultServiceConfig // {
+        ExecStart = "${package}/bin/serve";
+      } // lib.optionalAttrs (cfg.port < 1024) {
+        AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
+        CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
+      };
+    };
+
+    users.users = optionalAttrs (cfg.user == "searchix") {
+      searchix = {
+        group = cfg.group;
+        home = cfg.homeDir;
+        isSystemUser = true;
+      };
+    };
+
+    users.groups = optionalAttrs (cfg.group == "searchix") {
+      searchix = { };
+    };
+  };
+}
diff --git a/nix/modules/source-options.nix b/nix/modules/source-options.nix
new file mode 100644
index 0000000..4757c89
--- /dev/null
+++ b/nix/modules/source-options.nix
@@ -0,0 +1,16 @@
+{ cfg }:
+{ config, lib, name, ... }:
+let
+  inherit (lib) literalExpression mkOption mkEnableOption types;
+in
+{
+  options = {
+    key = mkOption {
+      type = types.strMatching "[a-z0-9_-]*";
+      default = name;
+      description = "URL-safe name for this source.";
+    };
+
+    enable = mkEnableOption "Whether to enable this source.";
+  };
+}