1{ lib, pkgs, ... }:
2let
3 genNodeId =
4 name:
5 pkgs.runCommand "syncthing-test-certs-${name}" { } ''
6 mkdir -p $out
7 ${pkgs.syncthing}/bin/syncthing generate --home=$out
8 ${pkgs.libxml2}/bin/xmllint --xpath 'string(configuration/device/@id)' $out/config.xml > $out/id
9 '';
10 idA = genNodeId "a";
11 idB = genNodeId "b";
12 idC = genNodeId "c";
13 testPassword = "it's a secret";
14in
15{
16 name = "syncthing";
17 meta.maintainers = with pkgs.lib.maintainers; [ zarelit ];
18
19 nodes = {
20 a =
21 { config, ... }:
22 {
23 environment.etc.bar-encryption-password.text = testPassword;
24 services.syncthing = {
25 enable = true;
26 openDefaultPorts = true;
27 cert = "${idA}/cert.pem";
28 key = "${idA}/key.pem";
29 settings = {
30 devices.b.id = lib.fileContents "${idB}/id";
31 devices.c.id = lib.fileContents "${idC}/id";
32 folders.foo = {
33 path = "/var/lib/syncthing/foo";
34 devices = [ "b" ];
35 };
36 folders.bar = {
37 path = "/var/lib/syncthing/bar";
38 devices = [
39 {
40 name = "c";
41 encryptionPasswordFile = "/etc/${config.environment.etc.bar-encryption-password.target}";
42 }
43 ];
44 };
45 };
46 };
47 };
48 b =
49 { config, ... }:
50 {
51 environment.etc.bar-encryption-password.text = testPassword;
52 services.syncthing = {
53 enable = true;
54 openDefaultPorts = true;
55 cert = "${idB}/cert.pem";
56 key = "${idB}/key.pem";
57 settings = {
58 devices.a.id = lib.fileContents "${idA}/id";
59 devices.c.id = lib.fileContents "${idC}/id";
60 folders.foo = {
61 path = "/var/lib/syncthing/foo";
62 devices = [ "a" ];
63 };
64 folders.bar = {
65 path = "/var/lib/syncthing/bar";
66 devices = [
67 {
68 name = "c";
69 encryptionPasswordFile = "/etc/${config.environment.etc.bar-encryption-password.target}";
70 }
71 ];
72 };
73 };
74 };
75 };
76 c = {
77 services.syncthing = {
78 enable = true;
79 openDefaultPorts = true;
80 cert = "${idC}/cert.pem";
81 key = "${idC}/key.pem";
82 settings = {
83 devices.a.id = lib.fileContents "${idA}/id";
84 devices.b.id = lib.fileContents "${idB}/id";
85 folders.bar = {
86 path = "/var/lib/syncthing/bar";
87 devices = [
88 "a"
89 "b"
90 ];
91 type = "receiveencrypted";
92 };
93 };
94 };
95 };
96 };
97
98 testScript = ''
99 start_all()
100
101 a.wait_for_unit("syncthing.service")
102 b.wait_for_unit("syncthing.service")
103 c.wait_for_unit("syncthing.service")
104 a.wait_for_open_port(22000)
105 b.wait_for_open_port(22000)
106 c.wait_for_open_port(22000)
107
108 # Test foo
109
110 a.wait_for_file("/var/lib/syncthing/foo")
111 b.wait_for_file("/var/lib/syncthing/foo")
112
113 a.succeed("echo a2b > /var/lib/syncthing/foo/a2b")
114 b.succeed("echo b2a > /var/lib/syncthing/foo/b2a")
115
116 a.wait_for_file("/var/lib/syncthing/foo/b2a")
117 b.wait_for_file("/var/lib/syncthing/foo/a2b")
118
119 # Test bar
120
121 a.wait_for_file("/var/lib/syncthing/bar")
122 b.wait_for_file("/var/lib/syncthing/bar")
123 c.wait_for_file("/var/lib/syncthing/bar")
124
125 a.succeed("echo plaincontent > /var/lib/syncthing/bar/plainname")
126
127 # B should be able to decrypt, check that content of file matches
128 b.wait_for_file("/var/lib/syncthing/bar/plainname")
129 file_contents = b.succeed("cat /var/lib/syncthing/bar/plainname")
130 assert "plaincontent\n" == file_contents, f"Unexpected file contents: {file_contents=}"
131
132 # Bar on C is untrusted, check that content is not in cleartext
133 c.fail("grep -R plaincontent /var/lib/syncthing/bar")
134 '';
135}