nixos/syncthing: add guiPasswordFile option, add and move Syncthing tests (#446197)

This commit is contained in:
Doron Behar 2025-10-04 16:50:14 +00:00 committed by GitHub
commit 0fe515d371
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 147 additions and 8 deletions

View file

@ -236,13 +236,14 @@ let
+
/*
Now we update the other settings defined in cleanedConfig which are not
"folders" or "devices".
"folders", "devices", or "guiPasswordFile".
*/
(lib.pipe cleanedConfig [
builtins.attrNames
(lib.subtractLists [
"folders"
"devices"
"guiPasswordFile"
])
(map (subOption: ''
curl -X PUT -d ${
@ -251,6 +252,12 @@ let
''))
(lib.concatStringsSep "\n")
])
+
# Now we hash the contents of guiPasswordFile and use the result to update the gui password
(lib.optionalString (cfg.guiPasswordFile != null) ''
${pkgs.mkpasswd}/bin/mkpasswd -m bcrypt --stdin <"${cfg.guiPasswordFile}" | tr -d "\n" > "$RUNTIME_DIRECTORY/password_bcrypt"
curl -X PATCH --variable "pw_bcrypt@$RUNTIME_DIRECTORY/password_bcrypt" --expand-json '{ "password": "{{pw_bcrypt}}" }' ${curlAddressArgs "/rest/config/gui"}
'')
+ ''
# restart Syncthing if required
if curl ${curlAddressArgs "/rest/config/restart-required"} |
@ -285,6 +292,14 @@ in
'';
};
guiPasswordFile = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Path to file containing the plaintext password for Syncthing's GUI.
'';
};
overrideDevices = mkOption {
type = types.bool;
default = true;
@ -837,6 +852,12 @@ in
from the configuration, creating path conflicts.
'';
}
{
assertion = (lib.hasAttrByPath [ "gui" "password" ] cfg.settings) -> cfg.guiPasswordFile == null;
message = ''
Please use only one of services.syncthing.settings.gui.password or services.syncthing.guiPasswordFile.
'';
}
];
networking.firewall = mkIf cfg.openDefaultPorts {

View file

@ -1402,12 +1402,16 @@ in
switchTest = runTest ./switch-test.nix;
sx = runTest ./sx.nix;
sympa = runTest ./sympa.nix;
syncthing = runTest ./syncthing.nix;
syncthing-folders = runTest ./syncthing-folders.nix;
syncthing-init = runTest ./syncthing-init.nix;
syncthing-many-devices = runTest ./syncthing-many-devices.nix;
syncthing-no-settings = runTest ./syncthing-no-settings.nix;
syncthing-relay = runTest ./syncthing-relay.nix;
syncthing = runTest ./syncthing/main.nix;
syncthing-folders = runTest ./syncthing/folders.nix;
syncthing-guiPassword = runTest ./syncthing/guiPassword.nix;
syncthing-guiPasswordFile = runTest ./syncthing/guiPasswordFile.nix;
syncthing-init = runTest ./syncthing/init.nix;
# FIXME: Test has been failing since 2025-07-06:
# https://github.com/NixOS/nixpkgs/issues/447674
# syncthing-many-devices = runTest ./syncthing/many-devices.nix;
syncthing-no-settings = runTest ./syncthing/no-settings.nix;
syncthing-relay = runTest ./syncthing/relay.nix;
sysfs = runTest ./sysfs.nix;
sysinit-reactivation = runTest ./sysinit-reactivation.nix;
systemd = runTest ./systemd.nix;

View file

@ -0,0 +1,56 @@
{ lib, pkgs, ... }:
{
name = "syncthing-guiPassword";
meta.maintainers = with lib.maintainers; [ nullcube ];
enableOCR = true;
nodes.machine = {
imports = [ ../common/x11.nix ];
environment.systemPackages = with pkgs; [
syncthing
xdotool
];
programs.firefox = {
enable = true;
preferences = {
# Prevent firefox from asking to save the password
"signon.rememberSignons" = false;
};
};
services.syncthing = {
enable = true;
settings.options.urAccepted = -1;
settings.gui = {
insecureAdminAccess = false;
user = "alice";
password = "alice_password";
};
};
};
testScript = ''
machine.wait_for_unit("syncthing.service")
machine.wait_for_x()
machine.execute("xterm -e 'firefox 127.0.0.1:8384' >&2 &")
machine.wait_for_window("Syncthing")
machine.screenshot("pre-login")
with subtest("Syncthing requests authentication"):
machine.wait_for_text("Authentication Required", 10)
with subtest("Syncthing password is valid"):
machine.execute("xdotool type \"alice\"")
machine.execute("xdotool key Tab")
machine.execute("xdotool type \"alice_password\"")
machine.execute("xdotool key Enter")
machine.sleep(2)
machine.wait_for_text("This Device", 10)
machine.screenshot("post-login")
with subtest("Plaintext Syncthing password is not in final config"):
config = machine.succeed("cat /var/lib/syncthing/.config/syncthing/config.xml")
assert "alice_password" not in config
'';
}

View file

@ -0,0 +1,56 @@
{ lib, pkgs, ... }:
{
name = "syncthing-guiPasswordFile";
meta.maintainers = with lib.maintainers; [ nullcube ];
enableOCR = true;
nodes.machine = {
imports = [ ../common/x11.nix ];
environment.systemPackages = with pkgs; [
syncthing
xdotool
];
programs.firefox = {
enable = true;
preferences = {
# Prevent firefox from asking to save the password
"signon.rememberSignons" = false;
};
};
services.syncthing = {
enable = true;
settings.options.urAccepted = -1;
settings.gui = {
insecureAdminAccess = false;
user = "alice";
};
guiPasswordFile = (pkgs.writeText "syncthing-password-file" ''alice_password'').outPath;
};
};
testScript = ''
machine.wait_for_unit("syncthing.service")
machine.wait_for_x()
machine.execute("xterm -e 'firefox 127.0.0.1:8384' >&2 &")
machine.wait_for_window("Syncthing")
machine.screenshot("pre-login")
with subtest("Syncthing requests authentication"):
machine.wait_for_text("Authentication Required", 10)
with subtest("Syncthing password is valid"):
machine.execute("xdotool type \"alice\"")
machine.execute("xdotool key Tab")
machine.execute("xdotool type \"alice_password\"")
machine.execute("xdotool key Enter")
machine.sleep(2)
machine.wait_for_text("This Device", 10)
machine.screenshot("post-login")
with subtest("Plaintext Syncthing password is not in final config"):
config = machine.succeed("cat /var/lib/syncthing/.config/syncthing/config.xml")
assert "alice_password" not in config
'';
}

View file

@ -67,8 +67,10 @@ let
tests = {
inherit (nixosTests)
syncthing
syncthing-folders
syncthing-guiPassword
syncthing-guiPasswordFile
syncthing-init
syncthing-many-devices
syncthing-no-settings
syncthing-relay
;