diff options
-rw-r--r-- | flake.nix | 120 |
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; [ |