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.nix279
1 files changed, 12 insertions, 267 deletions
diff --git a/flake.nix b/flake.nix
index 5eae2da..d437310 100644
--- a/flake.nix
+++ b/flake.nix
@@ -18,285 +18,30 @@
     supportedSystems = ["aarch64-linux" "x86_64-linux"];
     forAllSystems = f: flake-utils.lib.eachSystem supportedSystems f;
   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;
-            defaultText = "<kittybox package from the upstream 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.";
-          };
-          backendUri = mkOption {
-            type = types.str;
-            default = "file:///var/lib/kittybox/data";
-            example = "redis://192.168.1.200:6379";
-            description = ''
-              Set the backend used for storing data. Available backends are:
-               - file:// - static folder backend (recommended)
-               - redis:// - Redis backend
-
-              Make sure that if you are using the file backend, the state
-              directory is accessible by Kittybox. By default, the unit config
-              uses DynamicUser=true, which prevents the unit from accessing
-              data outside of its directory. It is recommended to use a
-              bind-mount to /var/lib/private/kittybox if you require the state
-              directory to reside elsewhere.
-            '';
-          };
-          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.";
-          };
-          mediaEndpoint = mkOption {
-            type = types.nullOr types.str;
-            default = null;
-            description = "The URL of a media endpoint to announce when asked by a Micropub client. Strongly recommended if you plan to upload images.";
-          };
-          microsubServer = mkOption {
-            type = types.nullOr types.str;
-            default = null;
-            example = "https://aperture.p3k.io/microsub/69420";
-            description = ''
-              The URL of your Microsub server, which saves feeds for you
-              and allows you to browse Web content from one place. Try
-              https://aperture.p3k.io/ if you don't have one yet!
-            '';
-          };
-          webmentionEndpoint = mkOption {
-            type = types.nullOr types.str;
-            default = null;
-            example = "https://webmention.io/example.com/webmention";
-            description = ''
-              The URL of your webmention endpoint, which allows you to
-              receive notifications about your site's content being featured
-              or interacted with elsewhere on the IndieWeb.
-
-              By default Kittybox expects the Webmention endpoint to post
-              updates using an internal token. kittybox-webmention is an
-              endpoint capable of that.
-            '';
-          };
-          internalTokenFile = mkOption {
-            type = types.nullOr types.str;
-            default = null;
-            example = "/run/secrets/kittybox-shared-secret";
-            description = "A shared secret that will, when passed, allow unlimited editing access to database. Keep it safe.";
-          };
-          cookieSecretFile = mkOption {
-            type = types.str;
-            default = "/var/lib/kittybox/cookie_secret_key";
-            example = "/run/secrets/kittybox-cookie-secret";
-            description = "A secret file to encrypt cookies with the contents of. Should be at least 32 bytes in length. A random persistent file will be generated if this variable is left untouched.";
-          };
-        };
-      };
-      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.backendUri cfg.tokenEndpoint
-            cfg.authorizationEndpoint
-            cfg.internalTokenFile
-            cfg.bind cfg.port
-            cfg.cookieSecretFile
-          ];
-
-          environment = {
-            SERVE_AT = "${cfg.bind}:${builtins.toString cfg.port}";
-            AUTHORIZATION_ENDPOINT = cfg.authorizationEndpoint;
-            TOKEN_ENDPOINT = cfg.tokenEndpoint;
-            MEDIA_ENDPOINT = cfg.mediaEndpoint;
-            MICROSUB_ENDPOINT = cfg.microsubServer;
-            WEBMENTION_ENDPOINT = cfg.webmentionEndpoint;
-            #REDIS_URI = if (cfg.redisUri == null) then "redis://127.0.0.1:6379/" else cfg.redisUri;
-            BACKEND_URI = cfg.backendUri;
-            RUST_LOG = "${cfg.logLevel}";
-            COOKIE_SECRET_FILE = "${cfg.cookieSecretFile}";
-          };
-
-          script = ''
-            ${lib.optionalString (cfg.internalTokenFile != null) ''
-              if [[ -f ${cfg.internalTokenFile} ]]; then
-                export KITTYBOX_INTERNAL_TOKEN=$(${pkgs.coreutils}/bin/cat ${cfg.internalTokenFile})
-              fi
-            ''}
-            if [[ ${cfg.cookieSecretFile} == /var/lib/kittybox/cookie_secret_key && ! -f /var/lib/kittybox/cookie_secret_key ]]; then
-                cat /dev/urandom | tr -Cd '[:alnum:]' | head -c 128 > /var/lib/kittybox/cookie_secret_key
-            fi
-            exec ${cfg.package}/bin/kittybox
-          '';
-
-          serviceConfig = {
-            DynamicUser = true;
-            StateDirectory = "kittybox";
-          };
-        };
-      };
-    };
+    nixosModules.default = import ./configuration.nix self;
   } // forAllSystems (system: let
     pkgs = nixpkgs.legacyPackages.${system};
-    packages = {
-      kittybox = { stdenv, lib, runCommandNoCC, openssl, zlib, pkg-config, protobuf, naersk-lib, lld, mold }:
-      naersk-lib.buildPackage {
-        pname = "kittybox";
-        version = "0.1.0";
-
-        src = runCommandNoCC "kittybox-src" {} ''
-          mkdir -p $out
-          cp -r ${./Cargo.toml} $out/Cargo.toml
-          cp -r ${./Cargo.lock} $out/Cargo.lock
-          cp -r ${./src} $out/src
-          cp -r ${./templates} $out/templates
-          cp -r ${./util} $out/util
-          cp -r ${./fonts} $out/fonts
-        '';
-
-        checkInputs = [ openssl.dev zlib ];
-        nativeBuildInputs = [ pkg-config protobuf ];
-        nativeCheckInputs = [ pkg-config ];
-
-        doCheck = stdenv.hostPlatform == stdenv.targetPlatform;
-
-        meta = with lib.meta; {
-          maintainers = with lib.maintainers; [ vikanezrimaya ];
-          platforms = supportedSystems;
-          mainProgram = "kittybox";
-        };
-      };
+    naersk-lib = naersk.lib.${system}.override {
+      inherit (pkgs) rustc cargo;
     };
   in {
-    packages = let
-      naersk-lib = naersk.lib.${system}.override {
-        inherit (pkgs) rustc cargo;
-      };
-    in {
-      kittybox = pkgs.callPackage packages.kittybox { inherit naersk-lib; };
+    packages = {
+      kittybox = pkgs.callPackage ./kittybox.nix { inherit naersk-lib; };
+      default = self.packages.${system}.kittybox;
     };
-    defaultPackage = self.packages.${system}.kittybox;
 
     checks = {
       kittybox = self.packages.${system}.kittybox;
       distributed-test = pkgs.nixosTest (import ./distributed-test.nix self);
-      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";
-              logLevel = "info,kittybox=debug,retainer::cache=warn,h2=warn,rustls=warn";
-            };
-
-            environment.systemPackages = with pkgs; [
-              curl
-            ];
-          };
-        };
-
-        testScript = ''
-          with subtest("Verify that Kittybox started correctly..."):
-              kittybox.wait_for_open_port(8080)
-              kittybox.succeed("curl --silent http://localhost:8080/micropub")
-
-          with subtest("Onboarding should correctly work..."):
-              kittybox.copy_from_host("${./onboarding.json}", "/root/onboarding.json")
-              kittybox.succeed("curl -vvv http://localhost:8080/onboarding -d@/root/onboarding.json -H 'Content-Type: application/json'")
-              # Testing for a known string is the easiest way to determine that the onboarding worked
-              kittybox.succeed("curl --silent http://localhost:8080/ | grep 'vestige of the past long gone'")
-        '';
-      }));
-      dockerContainer = pkgs.dockerTools.buildImage {
-        name = "kittybox";
-        tag = self.rev or "development";
-        created = let
-          date = self.lastModifiedDate;
-        in builtins.concatStringsSep "" [
-          (builtins.substring 0 4 date)
-          "-"
-          (builtins.substring 4 2 date)
-          "-"
-          (builtins.substring 6 2 date)
-          "T"
-          (builtins.substring 8 2 date)
-          ":"
-          (builtins.substring 10 2 date)
-          ":"
-          (builtins.substring 12 2 date)
-          "Z"
-        ];
-
-        runAsRoot = ''
-          #!${pkgs.runtimeShell}
-          ${pkgs.dockerTools.shadowSetup}
-          groupadd -r kittybox
-          useradd -r -g kittybox kittybox
-          mkdir -p /data
-          chown kittybox:kittybox /data
-        '';
-
-        config = {
-          Cmd = [ "${self.packages.${system}.kittybox}/bin/kittybox" ];
-          Env = [
-            "SERVE_AT=0.0.0.0:8080"
-            "BACKEND_URI=file:///data"
-            "RUST_LOG=info"
-          ];
-          WorkingDir = "/data";
-          Volumes = { "/data" = {}; };
-          User = "kittybox";
-          ExposedPorts = { "8080" = {}; };
-        };
+      nixos-test = pkgs.nixosTest (import ./smoke-test.nix self);
+      dockerContainer = pkgs.callPackage ./docker.nix {
+        inherit (self.packages.${system}) kittybox;
+        rev = self.rev or "development";
+        inherit (self) lastModifiedDate;
       };
     };
 
-    devShell = pkgs.mkShell {
+    devShells.default = pkgs.mkShell {
       name = "rust-dev-shell";
 
       nativeBuildInputs = with pkgs; [