about summary refs log tree commit diff
path: root/flake.nix
diff options
context:
space:
mode:
Diffstat (limited to 'flake.nix')
-rw-r--r--flake.nix120
1 files changed, 119 insertions, 1 deletions
diff --git a/flake.nix b/flake.nix
index 8041d7a..a24981e 100644
--- a/flake.nix
+++ b/flake.nix
@@ -20,7 +20,94 @@
   outputs = { self, nixpkgs, rust, flake-utils, naersk }: let
     supportedSystems = ["aarch64-linux" "x86_64-linux"];
     forAllSystems = f: flake-utils.lib.eachSystem supportedSystems f;
-  in forAllSystems (system: let
+  in {
+    nixosModule = { config, pkgs, lib, ... }: with lib; let
+      cfg = config.services.kittybox;
+    in {
+      options = {
+        services.kittybox = {
+          enable = mkOption {
+            type = types.bool;
+            default = false;
+            description = ''
+              Whether to enable Kittybox, the IndieWeb blogging solution.
+            '';
+          };
+          package = mkOption {
+            type = types.package;
+            default = self.packages.${config.nixpkgs.localSystem.system}.kittybox-micropub;
+            defaultText = "<kittybox_micropub package from the official flake>";
+            description = "Which Kittybox derivation to use.";
+          };
+
+          bind = mkOption {
+            type = types.nullOr types.str;
+            default = "127.0.0.1";
+            description = "The host for Kittybox to bind to.";
+            example = "192.168.1.100";
+          };
+          port = mkOption {
+            type = types.int;
+            default = 8080;
+            description = "The port for Kittybox to listen at.";
+            example = 16420;
+          };
+          logLevel = mkOption {
+            type = types.str;
+            default = "warn";
+            example = "info";
+            description = "Specify the server verbosity level. Uses RUST_LOG environment variable internally.";
+          };
+          redisUri = mkOption {
+            type = types.nullOr types.str;
+            default = null;
+            example = "redis://192.168.1.200:6379/";
+            description = "Set the Redis instance used as backing storage. If null, Redis will be configured on localhost. Use services.redis to change parameters.";
+          };
+          tokenEndpoint = mkOption {
+            type = types.str;
+            example = "https://tokens.indieauth.com/token";
+            description = "Token endpoint to use for authenticating Micropub requests. Use the example if you are unsure.";
+          };
+          authorizationEndpoint = mkOption {
+            type = types.str;
+            example = "https://indieauth.com/auth";
+            description = "Authorization endpoint to use to authenticate the user. You can use the default if you are unsure.";
+          };
+        };
+      };
+      config = lib.mkIf cfg.enable {
+        systemd.services.kittybox = {
+          description = "An IndieWeb-enabled blog engine";
+
+          wantedBy = [ "multi-user.target" ];
+          after = [ "network.target" ];
+
+          restartTriggers = [
+            cfg.package
+            cfg.redisUri cfg.tokenEndpoint
+            cfg.authorizationEndpoint
+            cfg.bind cfg.port
+          ];
+
+          environment = {
+            SERVE_AT = "${cfg.bind}:${builtins.toString cfg.port}";
+            AUTHORIZATION_ENDPOINT = cfg.authorizationEndpoint;
+            TOKEN_ENDPOINT = cfg.tokenEndpoint;
+            REDIS_URI = if (cfg.redisUri == null) then "redis://127.0.0.1:6379/" else cfg.redisUri;
+          };
+
+          serviceConfig = {
+            ExecStart = "${cfg.package}/bin/kittybox_micropub";
+            DynamicUser = true;
+          };
+        };
+        services.redis = lib.mkIf (cfg.redisUri == null) {
+          enable = true;
+        };
+      };
+    };
+  } // forAllSystems (system: let
     pkgs = import nixpkgs {
       localSystem.system = system;
       overlays = [ rust.overlay ];
@@ -55,6 +142,37 @@
     };
     defaultPackage = self.packages.${system}.kittybox-micropub;
 
+    checks = {
+      nixos-test = pkgs.nixosTest ({ lib }: {
+        name = "nixos-kittybox";
+
+        nodes = {
+          kittybox = { config, pkgs, lib, ... }: {
+            imports = [ self.nixosModule ];
+
+            services.kittybox = {
+              enable = true;
+              # It never actually contacts those endpoints anyway unless we use Micropub so it's fine!
+              # TODO: Once we have self-hosted software for those endpoints,
+              #       make an e2e test for common workflows (e.g. making a post)
+              tokenEndpoint = "https://example.com";
+              authorizationEndpoint = "https://example.com";
+            };
+
+            environment.systemPackages = with pkgs; [
+              curl
+            ];
+          };
+        };
+
+        testScript = ''
+          kittybox.start()
+          kittybox.wait_for_unit("default.target")
+          kittybox.succeed("curl --silent http://localhost:8080/micropub")
+        '';
+      });
+    };
+
     devShell = pkgs.mkShell {
       name = "rust-dev-shell";
       nativeBuildInputs = with pkgs; [