diff --git a/modules/misc/news.nix b/modules/misc/news.nix index a2f08db2..cc82598f 100644 --- a/modules/misc/news.nix +++ b/modules/misc/news.nix @@ -843,6 +843,15 @@ in export MOZ_ALLOW_DOWNGRADE=1 ''; } + + { + time = "2022-11-27T13:14:01+00:00"; + message = '' + 'programs.ssh.matchBlocks.*' now supports literal 'Match' blocks via + 'programs.ssh.matchBlocks.*.match' option as an alternative to plain + 'Host' blocks + ''; + } ]; }; } diff --git a/modules/programs/ssh.nix b/modules/programs/ssh.nix index 05d16a2c..f906d1bc 100644 --- a/modules/programs/ssh.nix +++ b/modules/programs/ssh.nix @@ -60,10 +60,37 @@ let matchBlockModule = types.submodule ({ dagName, ... }: { options = { host = mkOption { - type = types.str; + type = types.nullOr types.str; + default = null; example = "*.example.org"; description = '' - The host pattern used by this conditional block. + Host pattern used by this conditional block. + See + + ssh_config + 5 + + for Host block details. + This option is ignored if + + if defined. + ''; + }; + + match = mkOption { + type = types.nullOr types.str; + default = null; + example = "host canonical\nhost exec \"ping -c1 -q 192.168.17.1\""; + description = '' + Match block conditions used by this block. See + + ssh_config + 5 + + for Match block details. + This option takes precedence over + + if defined. ''; }; @@ -276,11 +303,16 @@ let }; }; - config.host = mkDefault dagName; +# config.host = mkDefault dagName; }); - matchBlockStr = cf: concatStringsSep "\n" ( - ["Host ${cf.host}"] + matchBlockStr = key: cf: concatStringsSep "\n" ( + let + hostOrDagName = if cf.host != null then cf.host else key; + matchHead = if cf.match != null + then "Match ${cf.match}" + else "Host ${hostOrDagName}"; + in [ "${matchHead}" ] ++ optional (cf.port != null) " Port ${toString cf.port}" ++ optional (cf.forwardAgent != null) " ForwardAgent ${lib.hm.booleans.yesNo cf.forwardAgent}" ++ optional cf.forwardX11 " ForwardX11 yes" @@ -492,7 +524,7 @@ in ++ (optional (cfg.includes != [ ]) '' Include ${concatStringsSep " " cfg.includes} '') - ++ (map (block: matchBlockStr block.data) matchBlocks) + ++ (map (block: matchBlockStr block.name block.data) matchBlocks) )} Host * @@ -508,5 +540,9 @@ in ${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.\nThe match option takes precedence.") + (filterAttrs (n: v: v.data.host != null && v.data.match != null) cfg.matchBlocks); }; } diff --git a/tests/modules/programs/ssh/default.nix b/tests/modules/programs/ssh/default.nix index b2f832c9..c5e17599 100644 --- a/tests/modules/programs/ssh/default.nix +++ b/tests/modules/programs/ssh/default.nix @@ -2,6 +2,7 @@ ssh-defaults = ./default-config.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; 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 new file mode 100644 index 00000000..d50343b9 --- /dev/null +++ b/tests/modules/programs/ssh/match-blocks-match-and-hosts-expected.conf @@ -0,0 +1,19 @@ +Host * !github.com + Port 516 +Host abc + Port 2222 +Match host xyz canonical + Port 2223 + +Host * + ForwardAgent 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 new file mode 100644 index 00000000..aa1e40d0 --- /dev/null +++ b/tests/modules/programs/ssh/match-blocks-match-and-hosts.nix @@ -0,0 +1,32 @@ +{ config, lib, pkgs, ... }: + +with lib; + +{ + config = { + programs.ssh = { + enable = true; + matchBlocks = { + abc = { port = 2222; }; + + xyz = { + match = "host xyz canonical"; + port = 2223; + }; + + "* !github.com" = { port = 516; }; + }; + }; + + home.file.assertions.text = builtins.toJSON + (map (a: a.message) (filter (a: !a.assertion) config.assertions)); + + nmt.script = '' + assertFileExists home-files/.ssh/config + assertFileContent \ + home-files/.ssh/config \ + ${./match-blocks-match-and-hosts-expected.conf} + assertFileContent home-files/assertions ${./no-assertions.json} + ''; + }; +}