From 5b2b75a41d301731fb9b67ee2583c83df69b99a3 Mon Sep 17 00:00:00 2001 From: Adam <19240940+ak2k@users.noreply.github.com> Date: Tue, 24 Mar 2026 23:06:57 -0400 Subject: [PATCH 1/4] litestream: 0.3.14 -> 0.5.9 Notable changes: - Built-in S3 distributed leasing via conditional writes - LTX-based transaction log format replacing WAL streaming - VFS write mode for tighter SQLite integration - IPC control, continuous restore, NATS/WebDAV replicas - Server-side encryption (SSE-C, SSE-KMS) The deprecated `replicas` config key is still accepted, so existing NixOS module configurations continue to work. Drop fix-cve-2024-41254.patch (included upstream via HostKey field on SFTP ReplicaClient). https://github.com/benbjohnson/litestream/releases --- nixos/tests/litestream.nix | 1 + .../li/litestream/fix-cve-2024-41254.patch | 64 ------------------- pkgs/by-name/li/litestream/package.nix | 8 +-- 3 files changed, 4 insertions(+), 69 deletions(-) delete mode 100644 pkgs/by-name/li/litestream/fix-cve-2024-41254.patch diff --git a/nixos/tests/litestream.nix b/nixos/tests/litestream.nix index f5a1668c30f2..b610c334ec01 100644 --- a/nixos/tests/litestream.nix +++ b/nixos/tests/litestream.nix @@ -59,6 +59,7 @@ security = { admin_user = "admin"; admin_password = "admin"; + secret_key = "SW2YcwTIb9zpOOhoPsMm"; }; server = { diff --git a/pkgs/by-name/li/litestream/fix-cve-2024-41254.patch b/pkgs/by-name/li/litestream/fix-cve-2024-41254.patch deleted file mode 100644 index 8fd06b712a24..000000000000 --- a/pkgs/by-name/li/litestream/fix-cve-2024-41254.patch +++ /dev/null @@ -1,64 +0,0 @@ -diff --git a/cmd/litestream/main.go b/cmd/litestream/main.go -index 1234567..abcdefg 100644 ---- a/cmd/litestream/main.go -+++ b/cmd/litestream/main.go -@@ -362,6 +362,7 @@ type ReplicaConfig struct { - Host string `yaml:"host"` - User string `yaml:"user"` - Password string `yaml:"password"` - KeyPath string `yaml:"key-path"` -+ HostKeyPath string `yaml:"host-key-path"` - - // Encryption identities and recipients -@@ -664,6 +665,7 @@ func NewReplicaFromConfig(c *ReplicaConfig, dbc *DBConfig) (_ litestream.Replic - client.Password = password - client.Path = path - client.KeyPath = c.KeyPath -+ client.HostKeyPath = c.HostKeyPath - return client, nil - } - -diff --git a/sftp/replica_client.go b/sftp/replica_client.go -index 30d8fa87..8b651e97 100644 ---- a/sftp/replica_client.go -+++ b/sftp/replica_client.go -@@ -41,6 +41,7 @@ type ReplicaClient struct { - Password string - Path string - KeyPath string -+ HostKeyPath string - DialTimeout time.Duration - } - -@@ -71,14 +72,28 @@ func (c *ReplicaClient) Init(ctx context.Context) (_ *sftp.Client, err error) { - - // Build SSH configuration & auth methods - config := &ssh.ClientConfig{ -- User: c.User, -- HostKeyCallback: ssh.InsecureIgnoreHostKey(), -- BannerCallback: ssh.BannerDisplayStderr(), -+ User: c.User, -+ BannerCallback: ssh.BannerDisplayStderr(), - } - if c.Password != "" { - config.Auth = append(config.Auth, ssh.Password(c.Password)) - } - -+ if c.HostKeyPath == "" { -+ config.HostKeyCallback = ssh.InsecureIgnoreHostKey() -+ } else { -+ buf, err := os.ReadFile(c.HostKeyPath) -+ if err != nil { -+ return nil, fmt.Errorf("cannot read sftp host key path: %w", err) -+ } -+ -+ key, _, _, _, err := ssh.ParseAuthorizedKey(buf) -+ if err != nil { -+ return nil, fmt.Errorf("cannot parse sftp host key path: path=%s len=%d err=%w", c.HostKeyPath, len(buf), err) -+ } -+ config.HostKeyCallback = ssh.FixedHostKey(key) -+ } -+ - if c.KeyPath != "" { - buf, err := os.ReadFile(c.KeyPath) - if err != nil { \ No newline at end of file diff --git a/pkgs/by-name/li/litestream/package.nix b/pkgs/by-name/li/litestream/package.nix index f5d68da741a8..c5c359a6f2d9 100644 --- a/pkgs/by-name/li/litestream/package.nix +++ b/pkgs/by-name/li/litestream/package.nix @@ -6,13 +6,13 @@ }: buildGoModule (finalAttrs: { pname = "litestream"; - version = "0.3.14"; + version = "0.5.9"; src = fetchFromGitHub { owner = "benbjohnson"; repo = "litestream"; rev = "v${finalAttrs.version}"; - sha256 = "sha256-rTPw1BnZPtcWzhwR9mCzoE4LXdlaFfRCIDMHlN/SRzk="; + hash = "sha256-GYYg1XyLhRBaUCY6RL8xLuaPL7k8KI2WjiGI8k86AW4="; }; ldflags = [ @@ -21,9 +21,7 @@ buildGoModule (finalAttrs: { "-X main.Version=${finalAttrs.version}" ]; - vendorHash = "sha256-sYIY3Z3VrCqbjEbQtEY7q6Jljg8jMoa2qWEB/IkDjzM="; - - patches = [ ./fix-cve-2024-41254.patch ]; + vendorHash = "sha256-e2fsgK/fZNIos5W/Gc3u72uzoT2igs6BgzYtz1PyI10="; passthru.tests = { inherit (nixosTests) litestream; }; From 7ccf46d9e4f37170f908f4fb01ac7d247ea3e6a3 Mon Sep 17 00:00:00 2001 From: Adam <19240940+ak2k@users.noreply.github.com> Date: Wed, 25 Mar 2026 07:35:56 -0400 Subject: [PATCH 2/4] nixos/tests/litestream: fix for v0.5.x Litestream 0.5.x writes to the database (_litestream_seq table), requiring group-write permissions on the data directory. Update the test to use tmpfiles for permissions, pre-create the DB in WAL mode, enable the IPC socket for deterministic sync, and verify backup content via restore + dump. --- nixos/tests/litestream.nix | 116 ++++++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 48 deletions(-) diff --git a/nixos/tests/litestream.nix b/nixos/tests/litestream.nix index b610c334ec01..6161742b539e 100644 --- a/nixos/tests/litestream.nix +++ b/nixos/tests/litestream.nix @@ -1,4 +1,8 @@ -{ pkgs, ... }: +{ pkgs, lib, ... }: +let + dbPath = "/var/lib/grafana/data/grafana.db"; + socketPath = "/run/litestream/litestream.sock"; +in { name = "litestream"; meta = with pkgs.lib.maintainers; { @@ -11,38 +15,45 @@ services.litestream = { enable = true; settings = { + socket = { + enabled = true; + path = "${socketPath}"; + }; dbs = [ { - path = "/var/lib/grafana/data/grafana.db"; + path = dbPath; replicas = [ { url = "sftp://foo:bar@127.0.0.1:22/home/foo/grafana"; + auto-recover = true; } ]; } ]; }; }; - systemd.services.grafana.serviceConfig.ExecStartPost = - "+" - + pkgs.writeShellScript "grant-grafana-permissions" '' - timeout=10 - - while [ ! -f /var/lib/grafana/data/grafana.db ]; - do - if [ "$timeout" == 0 ]; then - echo "ERROR: Timeout while waiting for /var/lib/grafana/data/grafana.db." - exit 1 - fi - - sleep 1 - - ((timeout--)) - done - - find /var/lib/grafana -type d -exec chmod -v 775 {} \; - find /var/lib/grafana -type f -exec chmod -v 660 {} \; - ''; + # Litestream 0.5.x writes to the database (_litestream_seq table), + # so grafana's data directory must be group-writable. + systemd.tmpfiles.rules = [ + "d /var/lib/grafana 0750 grafana grafana -" + "d /var/lib/grafana/data 2770 grafana grafana -" + ]; + systemd.services.grafana.serviceConfig = { + ExecStartPre = lib.mkAfter "+${pkgs.sqlite}/bin/sqlite3 ${dbPath} 'PRAGMA journal_mode=WAL;'"; + UMask = lib.mkForce "0007"; + }; + systemd.services.litestream = { + after = [ + "grafana.service" + "sshd.service" + ]; + requires = [ "grafana.service" ]; + wants = [ "sshd.service" ]; + serviceConfig = { + RuntimeDirectory = "litestream"; + ExecStartPre = "+/bin/sh -c 'chmod g+rw ${dbPath}*'"; + }; + }; services.openssh = { enable = true; allowSFTP = true; @@ -69,7 +80,7 @@ database = { type = "sqlite3"; - path = "/var/lib/grafana/data/grafana.db"; + path = dbPath; wal = true; }; }; @@ -79,35 +90,44 @@ password = "bar"; }; users.users.litestream.extraGroups = [ "grafana" ]; + environment.systemPackages = [ pkgs.sqlite ]; }; testScript = '' start_all() - machine.wait_until_succeeds("test -d /home/foo/grafana") machine.wait_for_open_port(3000) - machine.succeed(""" - curl -sSfN -X PUT -H "Content-Type: application/json" -d '{ - "oldPassword": "admin", - "newPassword": "newpass", - "confirmNew": "newpass" - }' http://admin:admin@127.0.0.1:3000/api/user/password - """) - # https://litestream.io/guides/systemd/#simulating-a-disaster - machine.systemctl("stop litestream.service") - machine.succeed( - "rm -f /var/lib/grafana/data/grafana.db " - "/var/lib/grafana/data/grafana.db-shm " - "/var/lib/grafana/data/grafana.db-wal" - ) - machine.succeed( - "litestream restore /var/lib/grafana/data/grafana.db " - "&& chown grafana:grafana /var/lib/grafana/data/grafana.db " - "&& chmod 660 /var/lib/grafana/data/grafana.db" - ) - machine.systemctl("restart grafana.service") - machine.wait_for_open_port(3000) - machine.succeed( - "curl -sSfN -u admin:newpass http://127.0.0.1:3000/api/org/users | grep admin\@localhost" - ) + with subtest("Verify litestream replicates changes"): + machine.succeed(""" + curl -sSfN -X PUT --json '{ + "name": "LitestreamTest", + "login": "admin", + "email": "admin@localhost" + }' http://admin:admin@127.0.0.1:3000/api/user + """) + machine.succeed("litestream sync -wait -socket ${socketPath} ${dbPath}") + machine.succeed( + "litestream restore -o /tmp/restored.db ${dbPath} && " + "sqlite3 /tmp/restored.db '.dump' | grep -q LitestreamTest" + ) + + with subtest("Simulate disaster recovery"): + # https://litestream.io/guides/systemd/#simulating-a-disaster + machine.systemctl("stop litestream.service grafana.service") + machine.succeed( + "rm -f ${dbPath} " + "${dbPath}-shm " + "${dbPath}-wal" + ) + machine.succeed( + "litestream restore ${dbPath} " + "&& chown grafana:grafana ${dbPath} " + "&& chmod 660 ${dbPath}" + ) + machine.systemctl("restart grafana.service litestream.service") + machine.wait_for_open_port(3000) + machine.wait_for_unit("litestream.service") + machine.succeed( + "curl -sSfN -u admin:admin http://127.0.0.1:3000/api/user | grep LitestreamTest" + ) ''; } From 04d02756781d79598e339807f4a1d372e3500bac Mon Sep 17 00:00:00 2001 From: ak2k <19240940+ak2k@users.noreply.github.com> Date: Wed, 25 Mar 2026 18:14:13 -0400 Subject: [PATCH 3/4] litestream: 0.5.9 -> 0.5.10 Fix NixOS VM test failure caused by a WAL change detection bug (shm mxFrame) introduced in v0.5.9 and reverted in v0.5.10. --- pkgs/by-name/li/litestream/package.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/by-name/li/litestream/package.nix b/pkgs/by-name/li/litestream/package.nix index c5c359a6f2d9..fad210501e68 100644 --- a/pkgs/by-name/li/litestream/package.nix +++ b/pkgs/by-name/li/litestream/package.nix @@ -6,13 +6,13 @@ }: buildGoModule (finalAttrs: { pname = "litestream"; - version = "0.5.9"; + version = "0.5.10"; src = fetchFromGitHub { owner = "benbjohnson"; repo = "litestream"; rev = "v${finalAttrs.version}"; - hash = "sha256-GYYg1XyLhRBaUCY6RL8xLuaPL7k8KI2WjiGI8k86AW4="; + hash = "sha256-xp1Ic7sF3yzpR4FgMOfx/uRp/jv/qzTgSlItOIrl2pI="; }; ldflags = [ From 352d41c5d9af8a62c282bfd00fe14bd2ad9e1f16 Mon Sep 17 00:00:00 2001 From: Adam <19240940+ak2k@users.noreply.github.com> Date: Mon, 6 Apr 2026 14:46:15 -0400 Subject: [PATCH 4/4] nixos/tests/litestream: use tmpfiles.settings, drop redundant interpolation --- nixos/tests/litestream.nix | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/nixos/tests/litestream.nix b/nixos/tests/litestream.nix index 6161742b539e..f879226e6f56 100644 --- a/nixos/tests/litestream.nix +++ b/nixos/tests/litestream.nix @@ -17,7 +17,7 @@ in settings = { socket = { enabled = true; - path = "${socketPath}"; + path = socketPath; }; dbs = [ { @@ -34,10 +34,18 @@ in }; # Litestream 0.5.x writes to the database (_litestream_seq table), # so grafana's data directory must be group-writable. - systemd.tmpfiles.rules = [ - "d /var/lib/grafana 0750 grafana grafana -" - "d /var/lib/grafana/data 2770 grafana grafana -" - ]; + systemd.tmpfiles.settings."10-litestream" = { + "/var/lib/grafana".d = { + mode = "0750"; + user = "grafana"; + group = "grafana"; + }; + "/var/lib/grafana/data".d = { + mode = "2770"; + user = "grafana"; + group = "grafana"; + }; + }; systemd.services.grafana.serviceConfig = { ExecStartPre = lib.mkAfter "+${pkgs.sqlite}/bin/sqlite3 ${dbPath} 'PRAGMA journal_mode=WAL;'"; UMask = lib.mkForce "0007";