aboutsummaryrefslogtreecommitdiffstats
path: root/nix
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-06-12 01:54:21 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2026-06-12 01:54:21 +0200
commitbbdf38018b47328b5faa2cef635c37095045be72 (patch)
tree8983817d547551ae12508a8ae8731b622d990af4 /nix
parentfeat(server): Make user stuff stateless (diff)
downloadatuin-bbdf38018b47328b5faa2cef635c37095045be72.zip
feat(server): Really make users stateless (with tests)
This commit also remove another load of unneeded features.
Diffstat (limited to 'nix')
-rw-r--r--nix/module.nix144
-rw-r--r--nix/package.nix63
2 files changed, 207 insertions, 0 deletions
diff --git a/nix/module.nix b/nix/module.nix
new file mode 100644
index 00000000..da6fd02c
--- /dev/null
+++ b/nix/module.nix
@@ -0,0 +1,144 @@
+{
+ config,
+ pkgs,
+ lib,
+ ...
+}: let
+ inherit (lib) mkOption types mkIf;
+ cfg = config.services.turtle;
+in {
+ options = {
+ services.turtle = {
+ enable = lib.mkEnableOption "turtle server for shell history sync";
+
+ package = lib.mkPackageOption pkgs "turtle" {};
+
+ host = mkOption {
+ type = types.str;
+ default = "127.0.0.1";
+ description = "The host address the turtle server should listen on.";
+ };
+
+ port = mkOption {
+ type = types.port;
+ default = 8888;
+ description = "The port the turtle server should listen on.";
+ };
+
+ database = {
+ createLocally = mkOption {
+ type = types.bool;
+ default = true;
+ description = "Create the database and database user locally.";
+ };
+
+ uri = mkOption {
+ type = types.nullOr types.str;
+ default = "postgresql:///turtle?host=/run/postgresql";
+ example = "postgresql://turtle@localhost:5432/turtle";
+ description = ''
+ URI to the database.
+ Can be set to null in which case ATUIN_DB_URI should be set through an EnvironmentFile
+ '';
+ };
+ };
+
+ environmentFile = lib.mkOption {
+ type = lib.types.nullOr lib.types.externalPath;
+ default = null;
+ description = ''
+ Environment file, used to set any secret ATUIN_* environment variables, such as ATUIN_DB_URI containing a password.
+ See https://docs.atuin.sh/cli/self-hosting/server-setup/#configuration for available environment variables.
+ '';
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ assertions = [
+ {
+ assertion = cfg.database.createLocally -> config.services.postgresql.enable;
+ message = "Postgresql must be enabled to create a local database";
+ }
+ ];
+
+ services.postgresql = mkIf cfg.database.createLocally {
+ enable = true;
+ ensureUsers = [
+ {
+ name = "turtle";
+ ensureDBOwnership = true;
+ }
+ ];
+ ensureDatabases = ["turtle"];
+ };
+
+ systemd.services.turtle = {
+ description = "turtle server";
+ requires = lib.optionals cfg.database.createLocally ["postgresql.target"];
+ after =
+ [
+ "network-online.target"
+ ]
+ ++ lib.optionals cfg.database.createLocally ["postgresql.target"];
+ wants =
+ [
+ "network-online.target"
+ ]
+ ++ lib.optionals cfg.database.createLocally ["postgresql.target"];
+ wantedBy = ["multi-user.target"];
+
+ serviceConfig = {
+ ExecStart = "${lib.getExe' cfg.package "atuin"} server start";
+ EnvironmentFile = lib.mkIf (cfg.environmentFile != null) [cfg.environmentFile];
+ RuntimeDirectory = "turtle";
+ RuntimeDirectoryMode = "0700";
+ DynamicUser = true;
+
+ # Hardening
+ CapabilityBoundingSet = "";
+ LockPersonality = true;
+ NoNewPrivileges = true;
+ MemoryDenyWriteExecute = true;
+ PrivateDevices = true;
+ PrivateMounts = true;
+ PrivateTmp = true;
+ PrivateUsers = true;
+ ProcSubset = "pid";
+ ProtectClock = true;
+ ProtectControlGroups = true;
+ ProtectHome = true;
+ ProtectHostname = true;
+ ProtectKernelLogs = true;
+ ProtectKernelModules = true;
+ ProtectKernelTunables = true;
+ ProtectProc = "invisible";
+ ProtectSystem = "full";
+ RemoveIPC = true;
+ RestrictAddressFamilies = [
+ "AF_INET"
+ "AF_INET6"
+ # Required for connecting to database sockets,
+ "AF_UNIX"
+ ];
+ RestrictNamespaces = true;
+ RestrictRealtime = true;
+ RestrictSUIDSGID = true;
+ SystemCallArchitectures = "native";
+ SystemCallFilter = [
+ "@system-service"
+ "~@privileged"
+ ];
+ UMask = "0077";
+ };
+
+ environment =
+ {
+ ATUIN_HOST = cfg.host;
+ ATUIN_PORT = toString cfg.port;
+ ATUIN_CONFIG_DIR = "/run/turtle"; # required to start, but not used as configuration is via environment variables
+ }
+ // lib.optionalAttrs (cfg.database.uri != null) {ATUIN_DB_URI = cfg.database.uri;};
+ };
+ };
+}
diff --git a/nix/package.nix b/nix/package.nix
new file mode 100644
index 00000000..82a348b8
--- /dev/null
+++ b/nix/package.nix
@@ -0,0 +1,63 @@
+# Atuin package definition
+#
+# This file will be similar to the package definition in nixpkgs:
+# https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/at/atuin/package.nix
+#
+# Helpful documentation: https://github.com/NixOS/nixpkgs/blob/master/doc/languages-frameworks/rust.section.md
+{
+ lib,
+ stdenv,
+ installShellFiles,
+ rustPlatform,
+ libiconv,
+}:
+rustPlatform.buildRustPackage {
+ name = "turtle";
+
+ src = lib.cleanSourceWith {
+ src = lib.cleanSource ./..;
+ filter = name: type:
+ (type == "directory")
+ || (builtins.elem (builtins.baseNameOf name) [
+ "Cargo.toml"
+ "Cargo.lock"
+ "CONTRIBUTORS"
+
+ "atuin.bash"
+ "atuin.fish"
+ "atuin.nu"
+ "atuin.ps1"
+ "atuin.xsh"
+ "atuin.zsh"
+ ])
+ || (lib.strings.hasSuffix ".rs" (builtins.baseNameOf name))
+ || (lib.strings.hasSuffix ".proto" (builtins.baseNameOf name))
+ || (lib.strings.hasSuffix ".sql" (builtins.baseNameOf name));
+ };
+
+ cargoLock = {
+ lockFile = ../Cargo.lock;
+ # Allow dependencies to be fetched from git and avoid having to set the outputHashes manually
+ allowBuiltinFetchGit = true;
+ };
+
+ nativeBuildInputs = [installShellFiles];
+
+ buildInputs = lib.optionals stdenv.isDarwin [libiconv];
+
+ postInstall = ''
+ installShellCompletion --cmd atuin \
+ --bash <($out/bin/atuin gen-completions -s bash) \
+ --fish <($out/bin/atuin gen-completions -s fish) \
+ --zsh <($out/bin/atuin gen-completions -s zsh)
+ '';
+
+ doCheck = false;
+
+ meta = with lib; {
+ description = "Replacement for a shell history which records additional commands context with optional encrypted synchronization between machines";
+ homepage = "https://github.com/atuinsh/atuin";
+ license = licenses.mit;
+ mainProgram = "atuin";
+ };
+}