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}
+ '';
+ };
+}