mirror of
https://github.com/nix-community/home-manager.git
synced 2025-11-08 19:46:05 +01:00
ssh: remove top level options
This commit is contained in:
parent
59aabcd3db
commit
3882f88691
23 changed files with 370 additions and 226 deletions
|
|
@ -194,14 +194,14 @@ let
|
||||||
};
|
};
|
||||||
|
|
||||||
serverAliveInterval = mkOption {
|
serverAliveInterval = mkOption {
|
||||||
type = types.int;
|
type = types.nullOr types.int;
|
||||||
default = 0;
|
default = null;
|
||||||
description = "Set timeout in seconds after which response will be requested.";
|
description = "Set timeout in seconds after which response will be requested.";
|
||||||
};
|
};
|
||||||
|
|
||||||
serverAliveCountMax = mkOption {
|
serverAliveCountMax = mkOption {
|
||||||
type = types.ints.positive;
|
type = types.nullOr types.ints.positive;
|
||||||
default = 3;
|
default = null;
|
||||||
description = ''
|
description = ''
|
||||||
Sets the number of server alive messages which may be sent
|
Sets the number of server alive messages which may be sent
|
||||||
without SSH receiving any messages back from the server.
|
without SSH receiving any messages back from the server.
|
||||||
|
|
@ -345,6 +345,65 @@ let
|
||||||
default = { };
|
default = { };
|
||||||
description = "Extra configuration options for the host.";
|
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;
|
# config.host = mkDefault dagName;
|
||||||
|
|
@ -368,12 +427,24 @@ let
|
||||||
++ optional (cf.addressFamily != null) " AddressFamily ${cf.addressFamily}"
|
++ optional (cf.addressFamily != null) " AddressFamily ${cf.addressFamily}"
|
||||||
++ optional (cf.sendEnv != [ ]) " SendEnv ${unwords cf.sendEnv}"
|
++ optional (cf.sendEnv != [ ]) " SendEnv ${unwords cf.sendEnv}"
|
||||||
++ optional (cf.setEnv != { }) " SetEnv ${mkSetEnvStr cf.setEnv}"
|
++ optional (cf.setEnv != { }) " SetEnv ${mkSetEnvStr cf.setEnv}"
|
||||||
++ optional (cf.serverAliveInterval != 0) " ServerAliveInterval ${toString cf.serverAliveInterval}"
|
++ optional (
|
||||||
++ optional (cf.serverAliveCountMax != 3) " ServerAliveCountMax ${toString cf.serverAliveCountMax}"
|
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.compression != null) " Compression ${lib.hm.booleans.yesNo cf.compression}"
|
||||||
++ optional (!cf.checkHostIP) " CheckHostIP no"
|
++ optional (!cf.checkHostIP) " CheckHostIP no"
|
||||||
++ optional (cf.proxyCommand != null) " ProxyCommand ${cf.proxyCommand}"
|
++ optional (cf.proxyCommand != null) " ProxyCommand ${cf.proxyCommand}"
|
||||||
++ optional (cf.proxyJump != null) " ProxyJump ${cf.proxyJump}"
|
++ 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: " IdentityFile ${file}") cf.identityFile
|
||||||
++ map (file: " IdentityAgent ${file}") cf.identityAgent
|
++ map (file: " IdentityAgent ${file}") cf.identityAgent
|
||||||
++ map (file: " CertificateFile ${file}") cf.certificateFile
|
++ map (file: " CertificateFile ${file}") cf.certificateFile
|
||||||
|
|
@ -387,6 +458,35 @@ in
|
||||||
{
|
{
|
||||||
meta.maintainers = [ lib.maintainers.rycee ];
|
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 = {
|
options.programs.ssh = {
|
||||||
enable = lib.mkEnableOption "SSH client configuration";
|
enable = lib.mkEnableOption "SSH client configuration";
|
||||||
|
|
||||||
|
|
@ -396,101 +496,6 @@ in
|
||||||
extraDescription = "By default, the client provided by your system is used.";
|
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 {
|
extraConfig = mkOption {
|
||||||
type = types.lines;
|
type = types.lines;
|
||||||
default = "";
|
default = "";
|
||||||
|
|
@ -546,76 +551,108 @@ in
|
||||||
for more information.
|
for more information.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
enableDefaultConfig = mkOption {
|
||||||
assertions = [
|
type = types.bool;
|
||||||
{
|
default = true;
|
||||||
assertion =
|
example = false;
|
||||||
let
|
description = ''
|
||||||
# `builtins.any`/`lib.lists.any` does not return `true` if there are no elements.
|
Whether to enable or not the old default config values.
|
||||||
any' = pred: items: if items == [ ] then true else lib.any pred items;
|
This option will become deprecated in the future.
|
||||||
# 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}
|
|
||||||
'';
|
'';
|
||||||
|
};
|
||||||
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";
|
||||||
|
};
|
||||||
|
})
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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}
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
@ -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-includes = ./includes.nix;
|
||||||
ssh-match-blocks = ./match-blocks-attrs.nix;
|
ssh-match-blocks = ./match-blocks-attrs.nix;
|
||||||
ssh-match-blocks-match-and-hosts = ./match-blocks-match-and-hosts.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-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-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;
|
ssh-forwards-local-bind-path-with-port-asserts = ./forwards-local-bind-path-with-port-asserts.nix;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
14
tests/modules/programs/ssh/extra-config-no-default-host.nix
Normal file
14
tests/modules/programs/ssh/extra-config-no-default-host.nix
Normal file
|
|
@ -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.''
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
config = {
|
config = {
|
||||||
programs.ssh = {
|
programs.ssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
enableDefaultConfig = false;
|
||||||
matchBlocks = {
|
matchBlocks = {
|
||||||
dynamicBindPathWithPort = {
|
dynamicBindPathWithPort = {
|
||||||
dynamicForwards = [
|
dynamicForwards = [
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,5 @@ Host dynamicBindAddressWithPort
|
||||||
Host dynamicBindPathNoPort
|
Host dynamicBindPathNoPort
|
||||||
DynamicForward /run/user/1000/gnupg/S.gpg-agent.extra
|
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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
config = {
|
config = {
|
||||||
programs.ssh = {
|
programs.ssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
enableDefaultConfig = false;
|
||||||
matchBlocks = {
|
matchBlocks = {
|
||||||
dynamicBindPathNoPort = {
|
dynamicBindPathNoPort = {
|
||||||
dynamicForwards = [
|
dynamicForwards = [
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
config = {
|
config = {
|
||||||
programs.ssh = {
|
programs.ssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
enableDefaultConfig = false;
|
||||||
matchBlocks = {
|
matchBlocks = {
|
||||||
localBindPathWithPort = {
|
localBindPathWithPort = {
|
||||||
localForwards = [
|
localForwards = [
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
config = {
|
config = {
|
||||||
programs.ssh = {
|
programs.ssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
enableDefaultConfig = false;
|
||||||
matchBlocks = {
|
matchBlocks = {
|
||||||
localHostPathWithPort = {
|
localHostPathWithPort = {
|
||||||
localForwards = [
|
localForwards = [
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
config = {
|
config = {
|
||||||
programs.ssh = {
|
programs.ssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
enableDefaultConfig = false;
|
||||||
matchBlocks = {
|
matchBlocks = {
|
||||||
remoteBindPathWithPort = {
|
remoteBindPathWithPort = {
|
||||||
remoteForwards = [
|
remoteForwards = [
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
config = {
|
config = {
|
||||||
programs.ssh = {
|
programs.ssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
enableDefaultConfig = false;
|
||||||
matchBlocks = {
|
matchBlocks = {
|
||||||
remoteHostPathWithPort = {
|
remoteHostPathWithPort = {
|
||||||
remoteForwards = [
|
remoteForwards = [
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
config = {
|
config = {
|
||||||
programs.ssh = {
|
programs.ssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
enableDefaultConfig = false;
|
||||||
includes = [
|
includes = [
|
||||||
"config.d/*"
|
"config.d/*"
|
||||||
"other/dir"
|
"other/dir"
|
||||||
|
|
|
||||||
|
|
@ -16,16 +16,5 @@ Host xyz
|
||||||
Host ordered
|
Host ordered
|
||||||
Port 1
|
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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
config = {
|
config = {
|
||||||
programs.ssh = {
|
programs.ssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
enableDefaultConfig = false;
|
||||||
matchBlocks = {
|
matchBlocks = {
|
||||||
abc = {
|
abc = {
|
||||||
identityFile = null;
|
identityFile = null;
|
||||||
|
|
|
||||||
|
|
@ -5,16 +5,5 @@ Host abc
|
||||||
Match host xyz canonical
|
Match host xyz canonical
|
||||||
Port 2223
|
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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
config = {
|
config = {
|
||||||
programs.ssh = {
|
programs.ssh = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
enableDefaultConfig = false;
|
||||||
matchBlocks = {
|
matchBlocks = {
|
||||||
abc = {
|
abc = {
|
||||||
port = 2222;
|
port = 2222;
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,13 @@
|
||||||
|
|
||||||
Host *
|
Host *
|
||||||
ForwardAgent no
|
ForwardAgent no
|
||||||
AddKeysToAgent no
|
|
||||||
Compression no
|
|
||||||
ServerAliveInterval 0
|
ServerAliveInterval 0
|
||||||
ServerAliveCountMax 3
|
ServerAliveCountMax 3
|
||||||
|
Compression no
|
||||||
|
AddKeysToAgent no
|
||||||
HashKnownHosts no
|
HashKnownHosts no
|
||||||
UserKnownHostsFile ~/.ssh/known_hosts
|
UserKnownHostsFile ~/.ssh/known_hosts
|
||||||
ControlMaster no
|
ControlMaster no
|
||||||
ControlPath ~/.ssh/master-%r@%n:%p
|
ControlPath ~/.ssh/master-%r@%n:%p
|
||||||
ControlPersist no
|
ControlPersist no
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
24
tests/modules/programs/ssh/old-defaults-extra-config.nix
Normal file
24
tests/modules/programs/ssh/old-defaults-extra-config.nix
Normal file
|
|
@ -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}
|
||||||
|
'';
|
||||||
|
}
|
||||||
18
tests/modules/programs/ssh/old-defaults.nix
Normal file
18
tests/modules/programs/ssh/old-defaults.nix
Normal file
|
|
@ -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}
|
||||||
|
'';
|
||||||
|
}
|
||||||
14
tests/modules/programs/ssh/renamed-options-expected.conf
Normal file
14
tests/modules/programs/ssh/renamed-options-expected.conf
Normal file
|
|
@ -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
|
||||||
|
|
||||||
46
tests/modules/programs/ssh/renamed-options.nix
Normal file
46
tests/modules/programs/ssh/renamed-options.nix
Normal file
|
|
@ -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}
|
||||||
|
'';
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue