From a5b92cc213637a5fccab7af67b3be71320206ce4 Mon Sep 17 00:00:00 2001 From: cethien Date: Mon, 16 Feb 2026 15:47:35 +0100 Subject: [PATCH] rclone: added sanitazion in systemd service name - replaces $ and spaces - escapes mount path --- modules/programs/rclone.nix | 10 +-- tests/integration/standalone/rclone/mount.nix | 62 +++++++++++++++++++ 2 files changed, 67 insertions(+), 5 deletions(-) diff --git a/modules/programs/rclone.nix b/modules/programs/rclone.nix index a660db89..8c9a6671 100644 --- a/modules/programs/rclone.nix +++ b/modules/programs/rclone.nix @@ -9,7 +9,7 @@ let cfg = config.programs.rclone; iniFormat = pkgs.formats.ini { }; - replaceSlashes = builtins.replaceStrings [ "/" ] [ "." ]; + replaceIllegalChars = builtins.replaceStrings [ "/" " " "$" ] [ "." "_" "" ]; isUsingSecretProvisioner = name: config ? "${name}" && config."${name}".secrets != { }; in @@ -361,7 +361,7 @@ in mount = value; in lib.optional mount.enable ( - lib.nameValuePair "rclone-mount:${replaceSlashes mount-path}@${remote-name}" { + lib.nameValuePair "rclone-mount:${replaceIllegalChars mount-path}@${remote-name}" { Unit = { Description = "Rclone FUSE daemon for ${remote-name}:${mount-path}"; }; @@ -374,13 +374,13 @@ in ] ++ lib.optional (mount.logLevel != null) "RCLONE_LOG_LEVEL=${mount.logLevel}"; - ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p ${mount.mountPoint}"; + ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p ${lib.escapeShellArg mount.mountPoint}"; ExecStart = lib.concatStringsSep " " [ (lib.getExe cfg.package) "mount" (lib.cli.toCommandLineShellGNU { } mount.options) - "${remote-name}:${mount-path}" - "${mount.mountPoint}" + (lib.escapeShellArg "${remote-name}:${mount-path}") + (lib.escapeShellArg mount.mountPoint) ]; Restart = "on-failure"; }; diff --git a/tests/integration/standalone/rclone/mount.nix b/tests/integration/standalone/rclone/mount.nix index ff9e662d..3b514340 100644 --- a/tests/integration/standalone/rclone/mount.nix +++ b/tests/integration/standalone/rclone/mount.nix @@ -11,6 +11,22 @@ let module = pkgs.writeText "mount-module" '' { pkgs, lib, ... }: { programs.rclone.remotes = { + alices-unclean-remote = { + config = { + type = "sftp"; + host = "remote"; + user = "alice"; + key_pem = "${keyPem}"; + known_hosts = "${sshKeys.snakeOilEd25519PublicKey}"; + }; + mounts = { + "/home/alice/invalid dirname$" = { + enable = true; + mountPoint = "/home/alice/valid-dirname"; + }; + }; + }; + alices-sftp-remote = { config = { type = "sftp"; @@ -157,5 +173,51 @@ in f"Failed to start {svc_name}" succeed_as_alice("ls /home/alice/even-more-files") + + with subtest("Sanitize service name"): + # https://rclone.org/commands/rclone_mount/#vfs-directory-cache + # Sending a SIGHUP evicts every dcache entry + def clear_vfs_dcache(): + svc_name = "rclone-mount:.home.alice.invalid_dirname@alices-unclean-remote.service" + succeed_as_alice(f"kill -s HUP $(systemctl --user show -p MainPID --value {svc_name})") + succeed_as_alice( + "sync", + "sleep 5", + box=remote + ) + + # remote -> machine + succeed_as_alice( + "mkdir /home/alice/invalid\\ dirname$", + "touch /home/alice/invalid\\ dirname$/test", + "echo started > /home/alice/invalid\\ dirname$/log", + box=remote + ) + + succeed_as_alice("ls /home/alice/valid-dirname/test") + + test_log = succeed_as_alice("cat /home/alice/valid-dirname/log") + expected = "started"; + assert expected in test_log, \ + f"Mounted file does not have expected contents. Expected {test_log} to contain \"{expected}\"" + + # machine -> remote + succeed_as_alice( + "touch /home/alice/valid-dirname/new-file", + "echo testing this works both ways! >> /home/alice/valid-dirname/log", + ) + + clear_vfs_dcache() + + succeed_as_alice("ls /home/alice/invalid\\ dirname$/new-file", box=remote) + + test_log = succeed_as_alice("cat /home/alice/invalid\\ dirname$/log", box=remote) + expected = "testing this works both ways!" + assert expected in test_log, \ + f"Mounted file does not have expected contents. Expected {test_log} to contain \"{expected}\"" + + expected = "started" + assert expected in test_log, \ + f"Mounted file does not have expected contents. Expected {test_log} to contain \"{expected}\"" ''; }