diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 7db9ff37d1d2..799c3d5d9791 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -245,6 +245,7 @@ in authelia = runTest ./authelia.nix; auto-cpufreq = runTest ./auto-cpufreq.nix; autobrr = runTest ./autobrr.nix; + autopush-rs = runTest ./autopush-rs.nix; autosuspend = runTest ./autosuspend.nix; avahi = runTest { imports = [ ./avahi.nix ]; diff --git a/nixos/tests/autopush-rs.nix b/nixos/tests/autopush-rs.nix new file mode 100644 index 000000000000..e1075bd3d17f --- /dev/null +++ b/nixos/tests/autopush-rs.nix @@ -0,0 +1,60 @@ +{ lib, ... }: +{ + _class = "nixosTest"; + name = "autopush-rs"; + + nodes = { + machine = + { pkgs, config, ... }: + { + environment.systemPackages = [ + pkgs.curl + ]; + + services.redis.servers.autopush-rs = { + enable = true; + port = 6000; + }; + system.services.autopush-autoconnect = { + imports = [ + pkgs.autopush-rs.services.autoconnect + ]; + autoconnect.settings = { + #do not use this key in production!!! + crypto_key = "[fZQX8jgdESUYFTYfWw3Dv5RRMuwYJPPaaPcbUgHM69Q=]"; + db_dsn = "redis://localhost:${toString config.services.redis.servers.autopush-rs.port}"; + port = 8000; + }; + }; + system.services.autopush-autoendpoint = { + imports = [ + pkgs.autopush-rs.services.autoendpoint + ]; + autoendpoint.settings = { + #do not use this key in production!!! + crypto_key = "[fZQX8jgdESUYFTYfWw3Dv5RRMuwYJPPaaPcbUgHM69Q=]"; + db_dsn = "redis://localhost:${toString config.services.redis.servers.autopush-rs.port}"; + port = 8080; + }; + }; + + networking.firewall.allowedTCPPorts = [ + 8080 + 8000 + ]; + }; + }; + + testScript = '' + start_all() + machine.wait_for_unit("multi-user.target") + machine.wait_for_unit("autopush-autoconnect.service") + machine.wait_for_unit("autopush-autoendpoint.service") + machine.wait_for_open_port(8080) + machine.wait_for_open_port(8000) + machine.succeed("curl -s -f http://localhost:8080/health") + machine.succeed("curl -s -f http://localhost:8000/health") + ''; + + meta.maintainers = with lib.maintainers; [ zimward ]; +} diff --git a/pkgs/by-name/au/autopush-rs/package.nix b/pkgs/by-name/au/autopush-rs/package.nix new file mode 100644 index 000000000000..08c946b5d6a4 --- /dev/null +++ b/pkgs/by-name/au/autopush-rs/package.nix @@ -0,0 +1,136 @@ +{ + lib, + pkgs, + nixosTests, + fetchFromGitHub, + rustPlatform, + stdenv, + pkg-config, + cmake, + openssl, + libffi, + grpc, + nix-update-script, + python3Packages, +}: +let + #script to generate the fernet key + fernetKey = + { + src, + version, + }: + python3Packages.buildPythonApplication { + pname = "fernet_key"; + inherit version src; + + __structuredAttrs = true; + + format = "other"; + + # this would run the upstream docker makefile + dontBuild = true; + + dependencies = [ python3Packages.cryptography ]; + + installPhase = '' + mkdir -p $out/bin + echo "#!/usr/bin/env python3" | \ + cat - $src/scripts/fernet_key.py > $out/bin/fernet_key + chmod +x $out/bin/fernet_key + ''; + + postFixup = '' + wrapPythonPrograms + ''; + }; +in +rustPlatform.buildRustPackage (finalAttrs: { + pname = "autopush"; + version = "1.81.3"; + + __structuredAttrs = true; + strictDeps = true; + + outputs = [ + "out" + "fernet" + ]; + + src = fetchFromGitHub { + owner = "mozilla-services"; + repo = "autopush-rs"; + tag = finalAttrs.version; + hash = "sha256-DP02mcEMoQoJqi5rw5eSuep0i7zeJ0LLYsakikt9hho="; + }; + + cargoHash = "sha256-LqmuUtFF30TO6iw7LPFB7yJGrzrhh7R0OKCWMhe/OjU="; + + nativeBuildInputs = [ + pkg-config + rustPlatform.bindgenHook + cmake + ]; + + buildInputs = [ + openssl + libffi + grpc + ]; + + # by default only google bigtable is supported as a db + buildNoDefaultFeatures = true; + buildFeatures = [ + "postgres" + "redis" + "reliable_report" + ]; + + env = { + #needed for bingen to find libc + BINDGEN_EXTRA_CLANG_ARGS = "-I${stdenv.cc.libc.dev}/include"; + CMAKE_POLICY_VERSION_MINIMUM = "3.5"; + }; + + #check build fails + doCheck = false; + + postInstall = '' + mkdir -p $fernet/bin + ln -s ${fernetKey { inherit (finalAttrs) src version; }}/bin/fernet_key $fernet/bin/fernet_key + ''; + + passthru = { + tests = nixosTests.autopush-rs; + services.autoconnect = { + imports = [ + (lib.modules.importApply ./service-autoconnect.nix { inherit pkgs; }) + ]; + package = finalAttrs.finalPackage.out; + }; + services.autoendpoint = { + imports = [ + (lib.modules.importApply ./service-autoendpoint.nix { inherit pkgs; }) + ]; + package = finalAttrs.finalPackage.out; + }; + + updateScript = nix-update-script { }; + }; + + meta = { + description = "Mozilla Push server and Push Endpoint"; + homepage = "https://mozilla-services.github.io/autopush-rs/index.html"; + changelog = "https://github.com/mozilla-services/autopush-rs/releases/tag/${finalAttrs.version}"; + license = lib.licenses.mpl20; + platforms = lib.platforms.linux; + maintainers = [ + lib.maintainers.zimward + ]; + # install the fernet_key script in devshells as users will only use it once most likely + outputsToInstall = [ + "out" + "fernet" + ]; + }; +}) diff --git a/pkgs/by-name/au/autopush-rs/service-autoconnect.nix b/pkgs/by-name/au/autopush-rs/service-autoconnect.nix new file mode 100644 index 000000000000..eca44eee4b87 --- /dev/null +++ b/pkgs/by-name/au/autopush-rs/service-autoconnect.nix @@ -0,0 +1,96 @@ +#v Non-module dependencies (`importApply`) +{ pkgs }: + +# Service module +{ + lib, + options, + config, + ... +}: +let + cfg = config.autoconnect; + tomlFmt = pkgs.formats.toml { }; +in +{ + _class = "service"; + options = { + package = lib.mkPackageOption pkgs "autopush-rs.out" { }; + autoconnect.settings = lib.mkOption { + type = lib.types.submodule { + freeformType = tomlFmt.type; + options = { + db_dsn = lib.mkOption { + description = "Endpoint of the database server."; + type = lib.types.str; + default = ""; + example = lib.literalExpression "redis+socket://${config.services.redis.servers.autopush-rs.unixSocket}"; + }; + }; + }; + default = { }; + description = ""; + }; + }; + config = + let + configFile = tomlFmt.generate "autoconnect.toml" cfg.settings; + in + { + process.argv = [ + "${config.package}/bin/autoconnect" + "-c" + (toString configFile) + ]; + } + // lib.optionalAttrs (options ? systemd) { + systemd.service = { + after = [ "network.target" ]; + wants = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Restart = "on-failure"; + + #hardening + MemoryDenyWriteExecute = true; + StateDirectoryMode = 0700; + UMask = 077; + DynamicUser = true; + PrivateUsers = true; + PrivateTmp = true; + PrivateDevices = true; + ProtectSystem = "full"; + ProtectHome = true; + NoNewPrivileges = true; + RuntimeDirectoryMode = 755; + ProtectHostname = true; + ProtectClock = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectKernelLogs = true; + ProtectControlGroups = true; + RestrictNamespaces = true; + LockPersonality = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + RemoveIPC = true; + SystemCallArchitectures = "native"; + + ProtectProc = "invisible"; + ProcSubset = "pid"; + + SystemCallFilter = [ + "~@clock" + "~@cpu-emulation" + "~@debug" + "~@module" + "~@mount" + "~@obsolete" + "~@raw-io" + "~@reboot" + "~@swap" + ]; + }; + }; + }; +} diff --git a/pkgs/by-name/au/autopush-rs/service-autoendpoint.nix b/pkgs/by-name/au/autopush-rs/service-autoendpoint.nix new file mode 100644 index 000000000000..d4c87dff54a7 --- /dev/null +++ b/pkgs/by-name/au/autopush-rs/service-autoendpoint.nix @@ -0,0 +1,98 @@ +# Non-module dependencies (`importApply`) +{ pkgs }: + +# Service module +{ + lib, + config, + options, + ... +}: +let + cfg = config.autoendpoint; + tomlFmt = pkgs.formats.toml { }; +in +{ + _class = "service"; + options = { + package = lib.mkPackageOption pkgs "autopush-rs.out" { }; + autoendpoint = { + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = tomlFmt.type; + options = { + db_dsn = lib.mkOption { + description = "Endpoint of the database server."; + type = lib.types.str; + default = ""; + example = lib.literalExpression "redis+socket://${config.services.redis.servers.autopush-rs.unixSocket}"; + }; + }; + }; + default = { }; + description = ""; + }; + }; + }; + config = + let + configFile = tomlFmt.generate "autoendpoint.toml" cfg.settings; + in + { + process.argv = [ + "${config.package}/bin/autoendpoint" + "-c" + (toString configFile) + ]; + } + // lib.optionalAttrs (options ? systemd) { + systemd.service = { + after = [ "network.target" ]; + wants = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Restart = "on-failure"; + + #hardening + MemoryDenyWriteExecute = true; + StateDirectoryMode = 0700; + UMask = 077; + DynamicUser = true; + PrivateUsers = true; + PrivateTmp = true; + PrivateDevices = true; + ProtectSystem = "full"; + ProtectHome = true; + NoNewPrivileges = true; + RuntimeDirectoryMode = 755; + ProtectHostname = true; + ProtectClock = true; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectKernelLogs = true; + ProtectControlGroups = true; + RestrictNamespaces = true; + LockPersonality = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + RemoveIPC = true; + SystemCallArchitectures = "native"; + + ProtectProc = "invisible"; + ProcSubset = "pid"; + + SystemCallFilter = [ + "~@clock" + "~@cpu-emulation" + "~@debug" + "~@module" + "~@mount" + "~@obsolete" + "~@raw-io" + "~@reboot" + "~@swap" + ]; + }; + }; + }; +}