From 3bbabb4932e2a14c24e00175e59f8e0a69b0e4ee Mon Sep 17 00:00:00 2001 From: oddlama Date: Fri, 11 Oct 2024 03:03:16 +0200 Subject: [PATCH 1/2] actual-server: init at 24.12.0 Co-authored-by: PatrickDaG <58092422+PatrickDaG@users.noreply.github.com> --- pkgs/by-name/ac/actual-server/package.nix | 128 ++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 pkgs/by-name/ac/actual-server/package.nix diff --git a/pkgs/by-name/ac/actual-server/package.nix b/pkgs/by-name/ac/actual-server/package.nix new file mode 100644 index 0000000000000..1db6f742e03bf --- /dev/null +++ b/pkgs/by-name/ac/actual-server/package.nix @@ -0,0 +1,128 @@ +{ + lib, + stdenv, + stdenvNoCC, + fetchFromGitHub, + makeWrapper, + cacert, + gitMinimal, + nodejs_20, + yarn, + nixosTests, + nix-update-script, +}: +let + version = "24.12.0"; + src = fetchFromGitHub { + owner = "actualbudget"; + repo = "actual-server"; + tag = "v${version}"; + hash = "sha256-qCATfpYjDlR2LaalkF0/b5tD4HDE4aNDrLvTC4g0ctY="; + }; + + yarn_20 = yarn.override { nodejs = nodejs_20; }; + + # We cannot use fetchYarnDeps because that doesn't support yarn2/berry + # lockfiles (see https://github.com/NixOS/nixpkgs/issues/254369) + offlineCache = stdenvNoCC.mkDerivation { + name = "actual-server-${version}-offline-cache"; + inherit src; + + nativeBuildInputs = [ + cacert # needed for git + gitMinimal # needed to download git dependencies + yarn_20 + ]; + + SUPPORTED_ARCHITECTURES = builtins.toJSON { + os = [ + "darwin" + "linux" + ]; + cpu = [ + "arm" + "arm64" + "ia32" + "x64" + ]; + libc = [ + "glibc" + "musl" + ]; + }; + + buildPhase = '' + runHook preBuild + + export HOME=$(mktemp -d) + yarn config set enableTelemetry 0 + yarn config set cacheFolder $out + yarn config set --json supportedArchitectures "$SUPPORTED_ARCHITECTURES" + yarn + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out + cp -r ./node_modules $out/node_modules + + runHook postInstall + ''; + dontFixup = true; + + outputHashAlgo = "sha256"; + outputHashMode = "recursive"; + outputHash = + { + x86_64-linux = "sha256-Rz+iKw4JDWtZOrCjs9sbHVw/bErAEY4TfoG+QfGKY94="; + aarch64-linux = "sha256-JGpRoIQrEI6crczHD62ZQO08GshBbzJC0dONYD69K/I="; + aarch64-darwin = "sha256-v2qzKmtqBdU6igyHat+NyL/XTzWgq/CKlNpai/iFHyQ="; + x86_64-darwin = "sha256-0ksWLlF/a58KY/8NgOQ5aPOLoXzqDqO3lhkmFvT17Bk="; + } + .${stdenv.hostPlatform.system} or (throw "Unsupported system: ${stdenv.hostPlatform.system}"); + }; +in +stdenv.mkDerivation { + pname = "actual-server"; + inherit version src; + + nativeBuildInputs = [ + makeWrapper + yarn_20 + ]; + + installPhase = '' + runHook preInstall + + mkdir -p $out/{bin,lib,lib/actual} + cp -r ${offlineCache}/node_modules/ $out/lib/actual + cp -r ./ $out/lib/actual + + makeWrapper ${lib.getExe nodejs_20} "$out/bin/actual-server" \ + --add-flags "$out/lib/actual/app.js" \ + --set NODE_PATH "$out/node_modules" + + runHook postInstall + ''; + + passthru = { + inherit offlineCache; + tests = nixosTests.actual; + passthru.updateScript = nix-update-script { }; + }; + + meta = { + changelog = "https://actualbudget.org/docs/releases"; + description = "Super fast privacy-focused app for managing your finances"; + homepage = "https://actualbudget.org/"; + mainProgram = "actual-server"; + license = lib.licenses.mit; + maintainers = [ + lib.maintainers.oddlama + lib.maintainers.patrickdag + ]; + }; +} From 93af2d0523f4b9eb77e75208cdde4205110d2997 Mon Sep 17 00:00:00 2001 From: oddlama Date: Fri, 11 Oct 2024 03:06:31 +0200 Subject: [PATCH 2/2] nixos/actual: init module and tests Co-authored-by: PatrickDaG <58092422+PatrickDaG@users.noreply.github.com> --- .../manual/release-notes/rl-2505.section.md | 2 + nixos/modules/module-list.nix | 1 + nixos/modules/services/web-apps/actual.nix | 121 ++++++++++++++++++ nixos/tests/actual.nix | 18 +++ nixos/tests/all-tests.nix | 1 + 5 files changed, 143 insertions(+) create mode 100644 nixos/modules/services/web-apps/actual.nix create mode 100644 nixos/tests/actual.nix diff --git a/nixos/doc/manual/release-notes/rl-2505.section.md b/nixos/doc/manual/release-notes/rl-2505.section.md index bc9dde73c4a4e..7272f3ff8ecc6 100644 --- a/nixos/doc/manual/release-notes/rl-2505.section.md +++ b/nixos/doc/manual/release-notes/rl-2505.section.md @@ -38,6 +38,8 @@ - [nostr-rs-relay](https://git.sr.ht/~gheartsfield/nostr-rs-relay/), This is a nostr relay, written in Rust. Available as [services.nostr-rs-relay](options.html#opt-services.nostr-rs-relay.enable). +- [Actual Budget](https://actualbudget.org/), a local-first personal finance app. Available as [services.actual](#opt-services.actual.enable). + - [mqtt-exporter](https://github.com/kpetremann/mqtt-exporter/), a Prometheus exporter for exposing messages from MQTT. Available as [services.prometheus.exporters.mqtt](#opt-services.prometheus.exporters.mqtt.enable). - [Buffyboard](https://gitlab.postmarketos.org/postmarketOS/buffybox/-/tree/master/buffyboard), a framebuffer on-screen keyboard. Available as [services.buffyboard](option.html#opt-services.buffyboard). diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index d4db609bbd5eb..523cb4e190128 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1413,6 +1413,7 @@ ./services/video/wivrn.nix ./services/wayland/cage.nix ./services/wayland/hypridle.nix + ./services/web-apps/actual.nix ./services/web-apps/akkoma.nix ./services/web-apps/agorakit.nix ./services/web-apps/alps.nix diff --git a/nixos/modules/services/web-apps/actual.nix b/nixos/modules/services/web-apps/actual.nix new file mode 100644 index 0000000000000..af15471521f14 --- /dev/null +++ b/nixos/modules/services/web-apps/actual.nix @@ -0,0 +1,121 @@ +{ + lib, + pkgs, + config, + ... +}: +let + inherit (lib) + getExe + mkDefault + mkEnableOption + mkIf + mkOption + mkPackageOption + types + ; + + cfg = config.services.actual; + configFile = formatType.generate "config.json" cfg.settings; + dataDir = "/var/lib/actual"; + + formatType = pkgs.formats.json { }; +in +{ + options.services.actual = { + enable = mkEnableOption "actual, a privacy focused app for managing your finances"; + package = mkPackageOption pkgs "actual-server" { }; + + openFirewall = mkOption { + default = false; + type = types.bool; + description = "Whether to open the firewall for the specified port."; + }; + + settings = mkOption { + default = { }; + description = "Server settings, refer to [the documentation](https://actualbudget.org/docs/config/) for available options."; + type = types.submodule { + freeformType = formatType.type; + + options = { + hostname = mkOption { + type = types.str; + description = "The address to listen on"; + default = "::"; + }; + + port = mkOption { + type = types.port; + description = "The port to listen on"; + default = 3000; + }; + }; + + config = { + serverFiles = mkDefault "${dataDir}/server-files"; + userFiles = mkDefault "${dataDir}/user-files"; + dataDir = mkDefault dataDir; + }; + }; + }; + }; + + config = mkIf cfg.enable { + networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.settings.port ]; + + systemd.services.actual = { + description = "Actual server, a local-first personal finance app"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + environment.ACTUAL_CONFIG_PATH = configFile; + serviceConfig = { + ExecStart = getExe cfg.package; + DynamicUser = true; + User = "actual"; + Group = "actual"; + StateDirectory = "actual"; + WorkingDirectory = dataDir; + LimitNOFILE = "1048576"; + PrivateTmp = true; + PrivateDevices = true; + StateDirectoryMode = "0700"; + Restart = "always"; + + # Hardening + CapabilityBoundingSet = ""; + LockPersonality = true; + #MemoryDenyWriteExecute = true; # Leads to coredump because V8 does JIT + PrivateUsers = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProcSubset = "pid"; + ProtectSystem = "strict"; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_NETLINK" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "@pkey" + ]; + UMask = "0077"; + }; + }; + }; + + meta.maintainers = [ + lib.maintainers.oddlama + lib.maintainers.patrickdag + ]; +} diff --git a/nixos/tests/actual.nix b/nixos/tests/actual.nix new file mode 100644 index 0000000000000..b8ee303f81272 --- /dev/null +++ b/nixos/tests/actual.nix @@ -0,0 +1,18 @@ +import ./make-test-python.nix ( + { lib, ... }: + { + name = "actual"; + meta.maintainers = [ lib.maintainers.oddlama ]; + + nodes.machine = + { ... }: + { + services.actual.enable = true; + }; + + testScript = '' + machine.wait_for_open_port(3000) + machine.succeed("curl -fvvv -Ls http://localhost:3000/ | grep 'Actual'") + ''; + } +) diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index afb1730955eff..a9feb13f6d12a 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -107,6 +107,7 @@ in { aaaaxy = runTest ./aaaaxy.nix; acme = runTest ./acme.nix; acme-dns = handleTest ./acme-dns.nix {}; + actual = handleTest ./actual.nix {}; adguardhome = runTest ./adguardhome.nix; aesmd = runTestOn ["x86_64-linux"] ./aesmd.nix; agate = runTest ./web-servers/agate.nix;