diff --git a/modules/programs/ssh.nix b/modules/programs/ssh.nix index be154c94..899397f0 100644 --- a/modules/programs/ssh.nix +++ b/modules/programs/ssh.nix @@ -194,14 +194,14 @@ let }; serverAliveInterval = mkOption { - type = types.int; - default = 0; + type = types.nullOr types.int; + default = null; description = "Set timeout in seconds after which response will be requested."; }; serverAliveCountMax = mkOption { - type = types.ints.positive; - default = 3; + type = types.nullOr types.ints.positive; + default = null; description = '' Sets the number of server alive messages which may be sent without SSH receiving any messages back from the server. @@ -345,6 +345,65 @@ let default = { }; description = "Extra configuration options for the host."; }; + + addKeysToAgent = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + When enabled, a private key that is used during authentication will be + added to ssh-agent if it is running (with confirmation enabled if + set to 'confirm'). The argument must be 'no' (the default), 'yes', 'confirm' + (optionally followed by a time interval), 'ask' or a time interval (e.g. '1h'). + ''; + }; + + hashKnownHosts = mkOption { + type = types.nullOr types.bool; + default = null; + description = '' + Indicates that + {manpage}`ssh(1)` + should hash host names and addresses when they are added to + the known hosts file. + ''; + }; + + userKnownHostsFile = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + Specifies one or more files to use for the user host key + database, separated by whitespace. The default is + {file}`~/.ssh/known_hosts`. + ''; + }; + + controlMaster = mkOption { + default = null; + type = types.nullOr ( + types.enum [ + "yes" + "no" + "ask" + "auto" + "autoask" + ] + ); + description = "Configure sharing of multiple sessions over a single network connection."; + }; + + controlPath = mkOption { + type = types.nullOr types.str; + default = null; + description = "Specify path to the control socket used for connection sharing."; + }; + + controlPersist = mkOption { + type = types.nullOr types.str; + default = null; + example = "10m"; + description = "Whether control socket should remain open in the background."; + }; }; # config.host = mkDefault dagName; @@ -368,12 +427,24 @@ let ++ optional (cf.addressFamily != null) " AddressFamily ${cf.addressFamily}" ++ optional (cf.sendEnv != [ ]) " SendEnv ${unwords cf.sendEnv}" ++ optional (cf.setEnv != { }) " SetEnv ${mkSetEnvStr cf.setEnv}" - ++ optional (cf.serverAliveInterval != 0) " ServerAliveInterval ${toString cf.serverAliveInterval}" - ++ optional (cf.serverAliveCountMax != 3) " ServerAliveCountMax ${toString cf.serverAliveCountMax}" + ++ optional ( + cf.serverAliveInterval != null + ) " ServerAliveInterval ${toString cf.serverAliveInterval}" + ++ optional ( + cf.serverAliveCountMax != null + ) " ServerAliveCountMax ${toString cf.serverAliveCountMax}" ++ optional (cf.compression != null) " Compression ${lib.hm.booleans.yesNo cf.compression}" ++ optional (!cf.checkHostIP) " CheckHostIP no" ++ optional (cf.proxyCommand != null) " ProxyCommand ${cf.proxyCommand}" ++ optional (cf.proxyJump != null) " ProxyJump ${cf.proxyJump}" + ++ optional (cf.addKeysToAgent != null) " AddKeysToAgent ${cf.addKeysToAgent}" + ++ optional ( + cf.hashKnownHosts != null + ) " HashKnownHosts ${lib.hm.booleans.yesNo cf.hashKnownHosts}" + ++ optional (cf.userKnownHostsFile != null) " UserKnownHostsFile ${cf.userKnownHostsFile}" + ++ optional (cf.controlMaster != null) " ControlMaster ${cf.controlMaster}" + ++ optional (cf.controlPath != null) " ControlPath ${cf.controlPath}" + ++ optional (cf.controlPersist != null) " ControlPersist ${cf.controlPersist}" ++ map (file: " IdentityFile ${file}") cf.identityFile ++ map (file: " IdentityAgent ${file}") cf.identityAgent ++ map (file: " CertificateFile ${file}") cf.certificateFile @@ -387,6 +458,35 @@ in { meta.maintainers = [ lib.maintainers.rycee ]; + imports = + let + oldPrefix = [ + "programs" + "ssh" + ]; + newPrefix = [ + "programs" + "ssh" + "matchBlocks" + "*" + ]; + renamedOptions = [ + "forwardAgent" + "addKeysToAgent" + "compression" + "serverAliveInterval" + "serverAliveCountMax" + "hashKnownHosts" + "userKnownHostsFile" + "controlMaster" + "controlPath" + "controlPersist" + ]; + in + lib.hm.deprecations.mkSettingsRenamedOptionModules oldPrefix newPrefix { + transform = x: x; + } renamedOptions; + options.programs.ssh = { enable = lib.mkEnableOption "SSH client configuration"; @@ -396,101 +496,6 @@ in extraDescription = "By default, the client provided by your system is used."; }; - forwardAgent = mkOption { - default = false; - type = types.bool; - description = '' - Whether the connection to the authentication agent (if any) - will be forwarded to the remote machine. - ''; - }; - - addKeysToAgent = mkOption { - type = types.str; - default = "no"; - description = '' - When enabled, a private key that is used during authentication will be - added to ssh-agent if it is running (with confirmation enabled if - set to 'confirm'). The argument must be 'no' (the default), 'yes', 'confirm' - (optionally followed by a time interval), 'ask' or a time interval (e.g. '1h'). - ''; - }; - - compression = mkOption { - default = false; - type = types.bool; - description = "Specifies whether to use compression."; - }; - - serverAliveInterval = mkOption { - type = types.int; - default = 0; - description = '' - Set default timeout in seconds after which response will be requested. - ''; - }; - - serverAliveCountMax = mkOption { - type = types.ints.positive; - default = 3; - description = '' - Sets the default number of server alive messages which may be - sent without SSH receiving any messages back from the server. - ''; - }; - - hashKnownHosts = mkOption { - default = false; - type = types.bool; - description = '' - Indicates that - {manpage}`ssh(1)` - should hash host names and addresses when they are added to - the known hosts file. - ''; - }; - - userKnownHostsFile = mkOption { - type = types.str; - default = "~/.ssh/known_hosts"; - description = '' - Specifies one or more files to use for the user host key - database, separated by whitespace. The default is - {file}`~/.ssh/known_hosts`. - ''; - }; - - controlMaster = mkOption { - default = "no"; - type = types.enum [ - "yes" - "no" - "ask" - "auto" - "autoask" - ]; - description = '' - Configure sharing of multiple sessions over a single network connection. - ''; - }; - - controlPath = mkOption { - type = types.str; - default = "~/.ssh/master-%r@%n:%p"; - description = '' - Specify path to the control socket used for connection sharing. - ''; - }; - - controlPersist = mkOption { - type = types.str; - default = "no"; - example = "10m"; - description = '' - Whether control socket should remain open in the background. - ''; - }; - extraConfig = mkOption { type = types.lines; default = ""; @@ -546,76 +551,108 @@ in for more information. ''; }; - }; - config = lib.mkIf cfg.enable { - assertions = [ - { - assertion = - let - # `builtins.any`/`lib.lists.any` does not return `true` if there are no elements. - any' = pred: items: if items == [ ] then true else lib.any pred items; - # Check that if `entry.address` is defined, and is a path, that `entry.port` has not - # been defined. - noPathWithPort = entry: entry.address != null && isPath entry.address -> entry.port == null; - checkDynamic = block: any' noPathWithPort block.dynamicForwards; - checkBindAndHost = fwd: noPathWithPort fwd.bind && noPathWithPort fwd.host; - checkLocal = block: any' checkBindAndHost block.localForwards; - checkRemote = block: any' checkBindAndHost block.remoteForwards; - checkMatchBlock = - block: - lib.all (fn: fn block) [ - checkLocal - checkRemote - checkDynamic - ]; - in - any' checkMatchBlock (map (block: block.data) (builtins.attrValues cfg.matchBlocks)); - message = "Forwarded paths cannot have ports."; - } - ]; - - home.packages = optional (cfg.package != null) cfg.package; - - home.file.".ssh/config".text = - let - sortedMatchBlocks = lib.hm.dag.topoSort cfg.matchBlocks; - sortedMatchBlocksStr = builtins.toJSON sortedMatchBlocks; - matchBlocks = - if sortedMatchBlocks ? result then - sortedMatchBlocks.result - else - abort "Dependency cycle in SSH match blocks: ${sortedMatchBlocksStr}"; - in - '' - ${concatStringsSep "\n" ( - (mapAttrsToList (n: v: "${n} ${v}") cfg.extraOptionOverrides) - ++ (optional (cfg.includes != [ ]) '' - Include ${concatStringsSep " " cfg.includes} - '') - ++ (map (block: matchBlockStr block.name block.data) matchBlocks) - )} - - Host * - ForwardAgent ${lib.hm.booleans.yesNo cfg.forwardAgent} - AddKeysToAgent ${cfg.addKeysToAgent} - Compression ${lib.hm.booleans.yesNo cfg.compression} - ServerAliveInterval ${toString cfg.serverAliveInterval} - ServerAliveCountMax ${toString cfg.serverAliveCountMax} - HashKnownHosts ${lib.hm.booleans.yesNo cfg.hashKnownHosts} - UserKnownHostsFile ${cfg.userKnownHostsFile} - ControlMaster ${cfg.controlMaster} - ControlPath ${cfg.controlPath} - ControlPersist ${cfg.controlPersist} - - ${lib.replaceStrings [ "\n" ] [ "\n " ] cfg.extraConfig} + enableDefaultConfig = mkOption { + type = types.bool; + default = true; + example = false; + description = '' + Whether to enable or not the old default config values. + This option will become deprecated in the future. ''; - - warnings = - mapAttrsToList - (n: v: '' - The SSH config match block `programs.ssh.matchBlocks.${n}` sets both of the host and match options. - The match option takes precedence.'') - (lib.filterAttrs (n: v: v.data.host != null && v.data.match != null) cfg.matchBlocks); + }; }; + + config = lib.mkIf cfg.enable ( + lib.mkMerge [ + { + assertions = [ + { + assertion = + let + # `builtins.any`/`lib.lists.any` does not return `true` if there are no elements. + any' = pred: items: if items == [ ] then true else lib.any pred items; + # Check that if `entry.address` is defined, and is a path, that `entry.port` has not + # been defined. + noPathWithPort = entry: entry.address != null && isPath entry.address -> entry.port == null; + checkDynamic = block: any' noPathWithPort block.dynamicForwards; + checkBindAndHost = fwd: noPathWithPort fwd.bind && noPathWithPort fwd.host; + checkLocal = block: any' checkBindAndHost block.localForwards; + checkRemote = block: any' checkBindAndHost block.remoteForwards; + checkMatchBlock = + block: + lib.all (fn: fn block) [ + checkLocal + checkRemote + checkDynamic + ]; + in + any' checkMatchBlock (map (block: block.data) (builtins.attrValues cfg.matchBlocks)); + message = "Forwarded paths cannot have ports."; + } + { + assertion = (cfg.extraConfig != "") -> (cfg.matchBlocks ? "*"); + message = ''Cannot set `programs.ssh.extraConfig` if `programs.ssh.matchBlocks."*"` (default host config) is not declared.''; + } + ]; + + home.packages = optional (cfg.package != null) cfg.package; + + home.file.".ssh/config".text = + let + sortedMatchBlocks = lib.hm.dag.topoSort (lib.removeAttrs cfg.matchBlocks [ "*" ]); + sortedMatchBlocksStr = builtins.toJSON sortedMatchBlocks; + matchBlocks = + if sortedMatchBlocks ? result then + sortedMatchBlocks.result + else + abort "Dependency cycle in SSH match blocks: ${sortedMatchBlocksStr}"; + + defaultHostBlock = cfg.matchBlocks."*" or null; + in + '' + ${concatStringsSep "\n" ( + (mapAttrsToList (n: v: "${n} ${v}") cfg.extraOptionOverrides) + ++ (optional (cfg.includes != [ ]) '' + Include ${concatStringsSep " " cfg.includes} + '') + ++ (map (block: matchBlockStr block.name block.data) matchBlocks) + )} + + ${if (defaultHostBlock != null) then (matchBlockStr "*" defaultHostBlock.data) else ""} + ${lib.replaceStrings [ "\n" ] [ "\n " ] cfg.extraConfig} + ''; + + warnings = + mapAttrsToList + (n: v: '' + The SSH config match block `programs.ssh.matchBlocks.${n}` sets both of the host and match options. + The match option takes precedence.'') + (lib.filterAttrs (n: v: v.data.host != null && v.data.match != null) cfg.matchBlocks); + } + (lib.mkIf cfg.enableDefaultConfig { + warnings = [ + '' + `programs.ssh` default values will be removed in the future. + Consider setting `programs.ssh.enableDefaultConfig` to false, + and manually set the default values you want to keep at + `programs.ssh.matchBlocks."*"`. + '' + ]; + + programs.ssh.matchBlocks."*" = { + forwardAgent = lib.mkDefault false; + addKeysToAgent = lib.mkDefault "no"; + compression = lib.mkDefault false; + serverAliveInterval = lib.mkDefault 0; + serverAliveCountMax = lib.mkDefault 3; + hashKnownHosts = lib.mkDefault false; + userKnownHostsFile = lib.mkDefault "~/.ssh/known_hosts"; + controlMaster = lib.mkDefault "no"; + controlPath = lib.mkDefault "~/.ssh/master-%r@%n:%p"; + controlPersist = lib.mkDefault "no"; + }; + }) + ] + ); } diff --git a/tests/modules/programs/ssh/default-config.nix b/tests/modules/programs/ssh/default-config.nix deleted file mode 100644 index d4f0a6d4..00000000 --- a/tests/modules/programs/ssh/default-config.nix +++ /dev/null @@ -1,18 +0,0 @@ -{ config, lib, ... }: -{ - config = { - programs.ssh = { - enable = true; - }; - - home.file.assertions.text = builtins.toJSON ( - map (a: a.message) (lib.filter (a: !a.assertion) config.assertions) - ); - - nmt.script = '' - assertFileExists home-files/.ssh/config - assertFileContent home-files/.ssh/config ${./default-config-expected.conf} - assertFileContent home-files/assertions ${./no-assertions.json} - ''; - }; -} diff --git a/tests/modules/programs/ssh/default.nix b/tests/modules/programs/ssh/default.nix index 40e1845f..c5725f1f 100644 --- a/tests/modules/programs/ssh/default.nix +++ b/tests/modules/programs/ssh/default.nix @@ -1,9 +1,11 @@ { - ssh-defaults = ./default-config.nix; + ssh-old-defaults = ./old-defaults.nix; + ssh-old-defaults-extra-config = ./old-defaults-extra-config.nix; + ssh-extra-config-no-default-host = ./extra-config-no-default-host.nix; + ssh-renamed-options = ./renamed-options.nix; ssh-includes = ./includes.nix; ssh-match-blocks = ./match-blocks-attrs.nix; ssh-match-blocks-match-and-hosts = ./match-blocks-match-and-hosts.nix; - ssh-forwards-dynamic-valid-bind-no-asserts = ./forwards-dynamic-valid-bind-no-asserts.nix; ssh-forwards-dynamic-bind-path-with-port-asserts = ./forwards-dynamic-bind-path-with-port-asserts.nix; ssh-forwards-local-bind-path-with-port-asserts = ./forwards-local-bind-path-with-port-asserts.nix; diff --git a/tests/modules/programs/ssh/extra-config-no-default-host-expected.conf b/tests/modules/programs/ssh/extra-config-no-default-host-expected.conf new file mode 100644 index 00000000..e14c44e8 --- /dev/null +++ b/tests/modules/programs/ssh/extra-config-no-default-host-expected.conf @@ -0,0 +1,16 @@ + + +Host * + ForwardAgent no + ServerAliveInterval 0 + ServerAliveCountMax 3 + Compression no + AddKeysToAgent no + HashKnownHosts no + UserKnownHostsFile ~/.ssh/known_hosts + ControlMaster no + ControlPath ~/.ssh/master-%r@%n:%p + ControlPersist no + MyExtraOption no + AnotherOption 3 + diff --git a/tests/modules/programs/ssh/extra-config-no-default-host.nix b/tests/modules/programs/ssh/extra-config-no-default-host.nix new file mode 100644 index 00000000..3d6712e4 --- /dev/null +++ b/tests/modules/programs/ssh/extra-config-no-default-host.nix @@ -0,0 +1,14 @@ +{ + programs.ssh = { + enable = true; + enableDefaultConfig = false; + extraConfig = '' + MyExtraOption no + AnotherOption 3 + ''; + }; + + test.asserts.assertions.expected = [ + ''Cannot set `programs.ssh.extraConfig` if `programs.ssh.matchBlocks."*"` (default host config) is not declared.'' + ]; +} diff --git a/tests/modules/programs/ssh/forwards-dynamic-bind-path-with-port-asserts.nix b/tests/modules/programs/ssh/forwards-dynamic-bind-path-with-port-asserts.nix index 693a7aa4..64d3e8e3 100644 --- a/tests/modules/programs/ssh/forwards-dynamic-bind-path-with-port-asserts.nix +++ b/tests/modules/programs/ssh/forwards-dynamic-bind-path-with-port-asserts.nix @@ -2,6 +2,7 @@ config = { programs.ssh = { enable = true; + enableDefaultConfig = false; matchBlocks = { dynamicBindPathWithPort = { dynamicForwards = [ diff --git a/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts-expected.conf b/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts-expected.conf index 06720d4f..1c4c4f86 100644 --- a/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts-expected.conf +++ b/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts-expected.conf @@ -3,16 +3,5 @@ Host dynamicBindAddressWithPort Host dynamicBindPathNoPort DynamicForward /run/user/1000/gnupg/S.gpg-agent.extra -Host * - ForwardAgent no - AddKeysToAgent no - Compression no - ServerAliveInterval 0 - ServerAliveCountMax 3 - HashKnownHosts no - UserKnownHostsFile ~/.ssh/known_hosts - ControlMaster no - ControlPath ~/.ssh/master-%r@%n:%p - ControlPersist no diff --git a/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts.nix b/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts.nix index 7e9aec6a..909d27e8 100644 --- a/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts.nix +++ b/tests/modules/programs/ssh/forwards-dynamic-valid-bind-no-asserts.nix @@ -3,6 +3,7 @@ config = { programs.ssh = { enable = true; + enableDefaultConfig = false; matchBlocks = { dynamicBindPathNoPort = { dynamicForwards = [ diff --git a/tests/modules/programs/ssh/forwards-local-bind-path-with-port-asserts.nix b/tests/modules/programs/ssh/forwards-local-bind-path-with-port-asserts.nix index 9461517e..d435224f 100644 --- a/tests/modules/programs/ssh/forwards-local-bind-path-with-port-asserts.nix +++ b/tests/modules/programs/ssh/forwards-local-bind-path-with-port-asserts.nix @@ -2,6 +2,7 @@ config = { programs.ssh = { enable = true; + enableDefaultConfig = false; matchBlocks = { localBindPathWithPort = { localForwards = [ diff --git a/tests/modules/programs/ssh/forwards-local-host-path-with-port-asserts.nix b/tests/modules/programs/ssh/forwards-local-host-path-with-port-asserts.nix index db8dfe6f..283b5fcc 100644 --- a/tests/modules/programs/ssh/forwards-local-host-path-with-port-asserts.nix +++ b/tests/modules/programs/ssh/forwards-local-host-path-with-port-asserts.nix @@ -2,6 +2,7 @@ config = { programs.ssh = { enable = true; + enableDefaultConfig = false; matchBlocks = { localHostPathWithPort = { localForwards = [ diff --git a/tests/modules/programs/ssh/forwards-remote-bind-path-with-port-asserts.nix b/tests/modules/programs/ssh/forwards-remote-bind-path-with-port-asserts.nix index a581afa8..9720e346 100644 --- a/tests/modules/programs/ssh/forwards-remote-bind-path-with-port-asserts.nix +++ b/tests/modules/programs/ssh/forwards-remote-bind-path-with-port-asserts.nix @@ -2,6 +2,7 @@ config = { programs.ssh = { enable = true; + enableDefaultConfig = false; matchBlocks = { remoteBindPathWithPort = { remoteForwards = [ diff --git a/tests/modules/programs/ssh/forwards-remote-host-path-with-port-asserts.nix b/tests/modules/programs/ssh/forwards-remote-host-path-with-port-asserts.nix index 66f1b0b7..52fd409b 100644 --- a/tests/modules/programs/ssh/forwards-remote-host-path-with-port-asserts.nix +++ b/tests/modules/programs/ssh/forwards-remote-host-path-with-port-asserts.nix @@ -2,6 +2,7 @@ config = { programs.ssh = { enable = true; + enableDefaultConfig = false; matchBlocks = { remoteHostPathWithPort = { remoteForwards = [ diff --git a/tests/modules/programs/ssh/includes.nix b/tests/modules/programs/ssh/includes.nix index 8930a094..ff1f983d 100644 --- a/tests/modules/programs/ssh/includes.nix +++ b/tests/modules/programs/ssh/includes.nix @@ -7,6 +7,7 @@ config = { programs.ssh = { enable = true; + enableDefaultConfig = false; includes = [ "config.d/*" "other/dir" diff --git a/tests/modules/programs/ssh/match-blocks-attrs-expected.conf b/tests/modules/programs/ssh/match-blocks-attrs-expected.conf index 903dc571..edff6264 100644 --- a/tests/modules/programs/ssh/match-blocks-attrs-expected.conf +++ b/tests/modules/programs/ssh/match-blocks-attrs-expected.conf @@ -16,16 +16,5 @@ Host xyz Host ordered Port 1 -Host * - ForwardAgent no - AddKeysToAgent no - Compression no - ServerAliveInterval 0 - ServerAliveCountMax 3 - HashKnownHosts no - UserKnownHostsFile ~/.ssh/known_hosts - ControlMaster no - ControlPath ~/.ssh/master-%r@%n:%p - ControlPersist no diff --git a/tests/modules/programs/ssh/match-blocks-attrs.nix b/tests/modules/programs/ssh/match-blocks-attrs.nix index e12bd5d5..abd312ef 100644 --- a/tests/modules/programs/ssh/match-blocks-attrs.nix +++ b/tests/modules/programs/ssh/match-blocks-attrs.nix @@ -3,6 +3,7 @@ config = { programs.ssh = { enable = true; + enableDefaultConfig = false; matchBlocks = { abc = { identityFile = null; diff --git a/tests/modules/programs/ssh/match-blocks-match-and-hosts-expected.conf b/tests/modules/programs/ssh/match-blocks-match-and-hosts-expected.conf index 6e618318..b5f3dad8 100644 --- a/tests/modules/programs/ssh/match-blocks-match-and-hosts-expected.conf +++ b/tests/modules/programs/ssh/match-blocks-match-and-hosts-expected.conf @@ -5,16 +5,5 @@ Host abc Match host xyz canonical Port 2223 -Host * - ForwardAgent no - AddKeysToAgent no - Compression no - ServerAliveInterval 0 - ServerAliveCountMax 3 - HashKnownHosts no - UserKnownHostsFile ~/.ssh/known_hosts - ControlMaster no - ControlPath ~/.ssh/master-%r@%n:%p - ControlPersist no diff --git a/tests/modules/programs/ssh/match-blocks-match-and-hosts.nix b/tests/modules/programs/ssh/match-blocks-match-and-hosts.nix index 5cd70fb0..a68769d9 100644 --- a/tests/modules/programs/ssh/match-blocks-match-and-hosts.nix +++ b/tests/modules/programs/ssh/match-blocks-match-and-hosts.nix @@ -3,6 +3,7 @@ config = { programs.ssh = { enable = true; + enableDefaultConfig = false; matchBlocks = { abc = { port = 2222; diff --git a/tests/modules/programs/ssh/default-config-expected.conf b/tests/modules/programs/ssh/old-defaults-expected.conf similarity index 99% rename from tests/modules/programs/ssh/default-config-expected.conf rename to tests/modules/programs/ssh/old-defaults-expected.conf index d387017b..65290800 100644 --- a/tests/modules/programs/ssh/default-config-expected.conf +++ b/tests/modules/programs/ssh/old-defaults-expected.conf @@ -2,14 +2,13 @@ Host * ForwardAgent no - AddKeysToAgent no - Compression no ServerAliveInterval 0 ServerAliveCountMax 3 + Compression no + AddKeysToAgent no HashKnownHosts no UserKnownHostsFile ~/.ssh/known_hosts ControlMaster no ControlPath ~/.ssh/master-%r@%n:%p ControlPersist no - diff --git a/tests/modules/programs/ssh/old-defaults-extra-config-expected.conf b/tests/modules/programs/ssh/old-defaults-extra-config-expected.conf new file mode 100644 index 00000000..e14c44e8 --- /dev/null +++ b/tests/modules/programs/ssh/old-defaults-extra-config-expected.conf @@ -0,0 +1,16 @@ + + +Host * + ForwardAgent no + ServerAliveInterval 0 + ServerAliveCountMax 3 + Compression no + AddKeysToAgent no + HashKnownHosts no + UserKnownHostsFile ~/.ssh/known_hosts + ControlMaster no + ControlPath ~/.ssh/master-%r@%n:%p + ControlPersist no + MyExtraOption no + AnotherOption 3 + diff --git a/tests/modules/programs/ssh/old-defaults-extra-config.nix b/tests/modules/programs/ssh/old-defaults-extra-config.nix new file mode 100644 index 00000000..696b1cfc --- /dev/null +++ b/tests/modules/programs/ssh/old-defaults-extra-config.nix @@ -0,0 +1,24 @@ +{ + programs.ssh = { + enable = true; + extraConfig = '' + MyExtraOption no + AnotherOption 3 + ''; + }; + + test.asserts.warnings.expected = [ + '' + `programs.ssh` default values will be removed in the future. + Consider setting `programs.ssh.enableDefaultConfig` to false, + and manually set the default values you want to keep at + `programs.ssh.matchBlocks."*"`. + '' + ]; + + nmt.script = '' + assertFileExists home-files/.ssh/config + assertFileContent home-files/.ssh/config \ + ${./old-defaults-extra-config-expected.conf} + ''; +} diff --git a/tests/modules/programs/ssh/old-defaults.nix b/tests/modules/programs/ssh/old-defaults.nix new file mode 100644 index 00000000..f46b0cc0 --- /dev/null +++ b/tests/modules/programs/ssh/old-defaults.nix @@ -0,0 +1,18 @@ +{ + programs.ssh.enable = true; + + test.asserts.warnings.expected = [ + '' + `programs.ssh` default values will be removed in the future. + Consider setting `programs.ssh.enableDefaultConfig` to false, + and manually set the default values you want to keep at + `programs.ssh.matchBlocks."*"`. + '' + ]; + + nmt.script = '' + assertFileExists home-files/.ssh/config + assertFileContent home-files/.ssh/config \ + ${./old-defaults-expected.conf} + ''; +} diff --git a/tests/modules/programs/ssh/renamed-options-expected.conf b/tests/modules/programs/ssh/renamed-options-expected.conf new file mode 100644 index 00000000..e586953c --- /dev/null +++ b/tests/modules/programs/ssh/renamed-options-expected.conf @@ -0,0 +1,14 @@ + + +Host * + ForwardAgent yes + ServerAliveInterval 1 + ServerAliveCountMax 2 + Compression yes + AddKeysToAgent yes + HashKnownHosts yes + UserKnownHostsFile ~/.ssh/my_known_hosts + ControlMaster yes + ControlPath ~/.ssh/myfile-%r@%n:%p + ControlPersist 10m + diff --git a/tests/modules/programs/ssh/renamed-options.nix b/tests/modules/programs/ssh/renamed-options.nix new file mode 100644 index 00000000..b68710ab --- /dev/null +++ b/tests/modules/programs/ssh/renamed-options.nix @@ -0,0 +1,46 @@ +{ lib, options, ... }: + +{ + programs.ssh = { + enable = true; + enableDefaultConfig = false; + forwardAgent = true; + addKeysToAgent = "yes"; + compression = true; + serverAliveInterval = 1; + serverAliveCountMax = 2; + hashKnownHosts = true; + userKnownHostsFile = "~/.ssh/my_known_hosts"; + controlMaster = "yes"; + controlPath = "~/.ssh/myfile-%r@%n:%p"; + controlPersist = "10m"; + }; + + test.asserts.warnings.expected = + let + renamedOptions = [ + "controlPersist" + "controlPath" + "controlMaster" + "userKnownHostsFile" + "hashKnownHosts" + "serverAliveCountMax" + "serverAliveInterval" + "compression" + "addKeysToAgent" + "forwardAgent" + ]; + in + map ( + o: + "The option `programs.ssh.${o}' defined in ${ + lib.showFiles options.programs.ssh.${o}.files + } has been renamed to `programs.ssh.matchBlocks.*.${o}'." + ) renamedOptions; + + nmt.script = '' + assertFileExists home-files/.ssh/config + assertFileContent home-files/.ssh/config \ + ${./renamed-options-expected.conf} + ''; +}