Subject: [bug#75959] [PATCH v8] services: syncthing: Add support for config file generation.

From: Leo Famulari <[email-masked]>
Date: Fri, 14 Feb 2025 03:09:46 -0500

On Tue, Feb 11, 2025 at 12:31:23AM -0500, Zacchaeus Scheffer wrote:
> Subject: [PATCH v8] services: syncthing: Add support for config file
>  generation.
> 
> * gnu/services/syncthing.scm: (syncthing-config-file,
> syncthing-folder, syncthing-device, syncthing-folder-device): New
> records;  (syncthing-service-type): Add special-files-service-type
> extension for the config file; (syncthing-files-service): Add service
> to create config file.
> * gnu/home/services/syncthing.scm: (home-syncthing-service-type):
> Extend home-files-services-type and re-exported more things from
> gnu/services/syncthing.scm.
> * doc/guix.texi: (syncthing-service-type): Document changes.

Great! I read through the documentation and made numerous stylistic
edits, and also added some references, links, and markup. See the
attached diff. I did not change the structure of the docs. Please let me
know what you think.

> +      (start #~(lambda _
> +                 ;; if we are managing the config, and it's not a home
> +                 ;; service, then exepect the config file at
> +                 ;; /var/lib/syncthing-<user>.  This makes sure the ownership
> +                 ;; is correct
> +                 (unless (or #$(not config-file) #$home-service?)
> +                   (system* "chown" #$user (string-append "/var/lib/syncthing-" #$user))
> +                   (system* "chmod" "700" (string-append "/var/lib/syncthing-" #$user)))

Please use the Guile procedures chown and chmod here, rather than
shelling out. Also, I think the folder's group should be set as well
using the chown procedure; right now it remains owned by root. There are
examples in 'gnu/services'.

https://www.gnu.org/software/guile/manual/html_node/File-System.html#index-chmod
https://www.gnu.org/software/guile/manual/html_node/File-System.html#index-chown

> +                 (make-forkexec-constructor
> +                  (append (list (string-append #$syncthing "/bin/syncthing")
> +                                "--no-browser"
> +                                "--no-restart"

It will be helpful to add brief Scheme code comments explaining what
these options do.
diff --git a/doc/guix.texi b/doc/guix.texi
index cf7c6e276a..112056e8ca 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -22739,7 +22739,7 @@ Networking Services
 The @code{(gnu services syncthing)} module provides the following services:
 @cindex syncthing
 
-You might want a syncthing daemon if you have files between two or more
+You might want a Syncthing daemon if you have files between two or more
 computers and want to sync them in real time, safely protected from
 prying eyes.
 
@@ -22785,41 +22785,43 @@ Networking Services
 This assumes that the specified group exists.
 
 @item @code{home} (default: @var{#f})
-Sets the @code{HOME} variable for the syncthing daemon.  The default is
+Sets the @code{HOME} variable for the Syncthing daemon.  The default is
 @file{$HOME} of the specified Syncthing @code{user}.
 
 @item @code{config-file} (default: @var{#f})
-Either a file-like object that resolves to a Syncthing configuration xml
+Either a file-like object that resolves to a Syncthing configuration XML
 file, or a @code{syncthing-config-file} record (see below).  If set to
 @code{#f}, Guix will not try to generate a config file, and Syncthing
-will generate a default one which will not be touched on reconfigure.
-Specifying this in a system service moves Syncthing's common
-configuration and data directory (@code{--home} in
+will generate a default configuration which will not be touched on
+reconfigure.  Specifying this in a system service moves Syncthing's
+common configuration and data directory (@code{--home} in
 @uref{https://docs.syncthing.net/users/syncthing.html}) to
-@file{/var/lib/syncthnig-<user>}.
+@file{/var/lib/syncthing-<user>}.
 
 @end table
 @end deftp
 
-In the below, only details specific to Guix, or related to how your
-device will connect to unrelated devices (relays, nameservers), are
-presented.  Otherwise, you should consult
+This section documents a subset of the Syncthing configuration
+options—specifically those related to Guix or those affecting how your
+computer will connect to other computers over the network (such as
+Syncthing relays or discovery servers).  The configuration is fully
+documented in the upstream
 @uref{https://docs.syncthing.net/users/config.html, Syncthing config
-documentation}; camelCase there is converted to kebab-case here.  If you
-are migrating to a Guix-powered Syncthing config file from a
-GUI-configured one, you can see what changes were introduced by
-@code{diff}ing them.  Note that you will need to add whitespace with
-4-space indentation to the one generated by Guix.  This can be done
-(requires @code{libxml2}) like so:
+documentation}. camelCase there is converted to kebab-case here.  If you
+are migrating from a Syncthing-managed configuration to one managed by
+Guix, you can check what changes were introduced by @code{diff}ing the
+respective @file{config.xml} files.  Note that you will need to add
+whitespace with 4-space indentation to the file generated by Guix, using
+the @code{xmllint} program from the @code{libxml2} package like so:
 
 @example
 XMLLINT_INDENT="    " xmllint --format /path/to/new/config.xml | diff /path/to/old/config.xml -
 @end example
 
-When generating a config file through Guix, you can still modify
-Syncthing from the GUI or through @code{introducer} and
-@code{autoAcceptFolders} mechanisms, but such changes will be reset on
-reconfigure.
+When generating a configuration file through Guix, you can still
+temporarily modify Syncthing from the GUI or through @code{introducer}
+and @code{autoAcceptFolders} mechanisms, but such changes will be reset
+on reconfigure.
 
 @deftp {Data Type} syncthing-config-file
 Data type representing the configuration file read by the Syncthing
@@ -22837,13 +22839,13 @@ Networking Services
 (initially) sharing any folders (such as a device with
 autoAcceptFolders).  In such instances, you should specify those devices
 here.  If multiple versions of the same device (as determined by
-comparing device id) are discovered, the one in this list is
+comparing device ID) are discovered, the one in this list is
 prioritized.  Otherwise, the first instance in the first folder is used.
 
 @item @code{gui-enabled} (default: @var{"true"})
 By default, any user on the computer can access the GUI and make changes
 to Syncthing.  If you leave this enabled, you should probably set
-gui-user and gui-password (see below).
+@code{gui-user} and @code{gui-password} (see below).
 
 @item @code{gui-tls} (default: @var{"false"})
 @item @code{gui-debugging} (default: @var{"false"})
@@ -22854,8 +22856,8 @@ Networking Services
 A bcrypt hash of the GUI password.  Remember that this will be globally
 exposed in @file{/gnu/store}.
 @item @code{gui-apikey} (default: @var{#f})
-You must specify this to use the Syncthing REST interface.  Also exposed
-in @file{/gnu/store}.
+You must specify this to use the Syncthing REST interface.  This key is
+kept in @file{/gnu/store} and is accessible to all users of the system.
 
 @item @code{gui-theme} (default: @var{"default"})
 @item @code{ldap-enabled} (default: @var{#f})
@@ -22882,9 +22884,11 @@ Networking Services
 @item @code{max-recv-kbps} (default: @var{"0"})
 @item @code{reconnection-interval-s} (default: @var{"60"})
 @item @code{relays-enabled} (default: @var{"true"})
-This option allows your Syncthing instance to coordinate with a global
-network of relays to enable syncing between devices when all other
-methods fail.
+This option allows your Syncthing instance to use a global network of
+@uref{https://docs.syncthing.net/users/relaying.html, relays} to enable
+syncing between devices when all other methods fail.  As always,
+Syncthing traffic is encrypted in transport and the relays are unable to
+decrypt it.
 
 @item @code{relay-reconnect-interval-m} (default: @var{"10"})
 @item @code{start-browser} (default: @var{"true"})
@@ -22893,9 +22897,10 @@ Networking Services
 @item @code{nat-renewal-minutes} (default: @var{"30"})
 @item @code{nat-timeout-seconds} (default: @var{"10"})
 @item @code{ur-accepted} (default: @var{"0"})
-ur* options control usage reporting.  Set to -1 to disable, or positive
-to enable.  The default (0) has reporting disabled, but you will be
-asked to decide in the GUI.
+Options whose names begin with `ur-' control usage reporting.  Set to -1
+to disable, or to a positive value to enable.  The default (0) disables
+reporting, but causes a usage reporting consent prompt to be displayed
+in the Syncthing GUI.
 
 @item @code{ur-seen} (default: @var{"0"})
 @item @code{ur-unique-id} (default: @var{""})
@@ -22938,23 +22943,24 @@ Networking Services
 @item @code{default-folder} (default: @var{(syncthing-folder (label ""))})
 @item @code{default-device} (default: @var{(syncthing-device (id ""))})
 @item @code{default-ignores} (default: @var{"")})
-The default-* above do not affect folders and devices added by the Guix
-interface.  They will, however, affect folders and devices that are
-added through the GUI, by an @code{introducer}, or a device with
+Options whose names begin with `default-' above do not affect folders
+and devices added through the Guix configuration interface.  They will,
+however, affect folders and devices that are added through the Syncthing
+GUI, by an @code{introducer}, or a device with
 @code{auto-accept-folders}.
 @end table
 @end deftp
 
 @deftp {Data Type} syncthing-folder
-Data type representing a folder to be synced.
+Data type representing a folder to be synchronized.
 
 @table @asis
 @item @code{id} (default: @var{#f})
-This id cannot match the id of any other folder on this device.  If left
+This ID cannot match the ID of any other folder on this device.  If left
 unspecified, it will default to the label (see below).
 
 @item @code{label}
-Human readable label for the folder.
+A human readable label for the folder.
 
 @item @code{path}
 The path at which to store this folder.
@@ -23013,24 +23019,27 @@ Networking Services
 @end deftp
 
 @deftp {Data Type} syncthing-device
-Data type representing a device to sync with.
+Data type representing a device to synchronize folders with.
 
 @table @asis
 @item @code{id}
-A long hash tied to the keys generated by Syncthing on the first launch.
-You can obtain this from the Syncthing GUI or by inspecting an existing
-Syncthing configuration file.
+A long hash representing the keys generated by Syncthing on the first
+launch.  You can obtain this from the Syncthing GUI or by inspecting an
+existing Syncthing configuration file.
 
 @item @code{name} (default: @var{""})
-Human readable device name for viewing in the GUI or in scheme.
+A human readable device name for viewing in the GUI or in Scheme.
 
 @item @code{compression} (default: @var{"metadata"})
 @item @code{introducer} (default: @var{"false"})
 @item @code{skip-introduction-removals} (default: @var{"false"})
 @item @code{introduced-by} (default: @var{""})
 @item @code{addresses} (default: @var{'("dynamic")})
-List of addresses at which to search for this device.  The special value
-``dynamic'' will have syncthing use several means to find the device.
+List of addresses at which to search for this device.  When the special
+value ``dynamic'' is included, Syncthing will search for the device
+locally as well as via the Syncthing project's
+@uref{https://docs.syncthing.net/users/security.html#global-discovery,
+global discovery} servers.
 
 @item @code{paused} (default: @var{"false"})
 @item @code{auto-accept-folders} (default: @var{"false"})
@@ -23045,32 +23054,37 @@ Networking Services
 @end deftp
 
 @deftp {Data Type} syncthing-folder-device
-There are two pieces of configuration specific to the relationship
-between a specific folder and a specific device.  First, syncthing needs
-to know if the remote device should be able to see the files given to
-it.  Second, syncthing needs to know from where that device originates.
-See
+This data type offers two folder-specific device options.  First, it
+offers @code{introduced-by}, which is a record of Syncthing
+@uref{https://docs.syncthing.net/users/introducer.html, introductions}.
+Second, it offers @code{encryption-password}, by which you can set the
+password used to encrypt data that is synced with
+@uref{https://docs.syncthing.net/users/untrusted.html, untrusted
+devices}.
+
+@code{syncthing-folder-device} corresponds to the
 @uref{https://docs.syncthing.net/users/config.html#config-option-folder.device,
-the Syncthing Documentation on this}.  If you leave these default, then
-you can just specify @code{syncthing-device}s instead of
-@code{syncthing-folder-device}s in a @code{syncthing-folder}'s
-@code{devices} field.
+`device'} option in the upstream `folder' element.
+
+If you don't need to use these options, then you can just specify
+@code{syncthing-device}s instead of @code{syncthing-folder-device}s in a
+@code{syncthing-folder}'s @code{devices} field.
 
 @table @asis
 @item @code{device}
-device should be a @code{syncthing-device} for which this configuration
-applies.
+The @code{syncthing-device} for which this configuration applies.
 
 @item @code{introduced-by} (default: @var{""})
 @item @code{encryption-password} (default: @var{""})
 Beware: specifying this field will include this password as plain text
-(not encrypted) and globally visible in @file{/gnu/store/}.  If
+(not encrypted) and globally visible in @file{/gnu/store/}.  If the
 encryption-password is non-empty, then it will be used as a password to
-encrypt file chunks as they are synced to that device.  For more info on
-syncing to devices you don't totally trust, see
-@uref{https://docs.syncthing.net/users/untrusted.html, Syncthing
-Documentation on Untrusted Devices}.  Note that file transfers are
-always end-to-end encrypted, regardless of this setting.
+encrypt file chunks as they are synchronized to untrusted devices.  For
+more information on syncing to devices you don't totally trust, see
+Syncthing's documentation on
+@uref{https://docs.syncthing.net/users/untrusted.html, Untrusted
+(Encrypted) Devices}.  Note that data transfer is always encrypted while
+in transport ("end-to-end encryption"), regardless of this setting.
 
 @end table
 @end deftp