Avoid derived UDP host in SSH imports
ci / test (push) Canceled after 0s
ci / fuzz-smoke (push) Canceled after 0s
ci / macos-client (macos-aarch64, macos-14) (push) Canceled after 0s
ci / macos-client (macos-x86_64, macos-13) (push) Canceled after 0s
ci / windows-client (push) Canceled after 0s
ci / package-release (linux-x86_64, ubuntu-latest, , , ) (push) Canceled after 0s
ci / package-release (macos-aarch64, macos-14, , , ) (push) Canceled after 0s
ci / package-release (macos-x86_64, macos-13, , , ) (push) Canceled after 0s
ci / package-release (windows-aarch64, windows-latest, aarch64, windows, aarch64-pc-windows-msvc) (push) Canceled after 0s
ci / package-release (windows-x86_64, windows-latest, , , ) (push) Canceled after 0s
ci / remote-bench (push) Canceled after 0s
ci / publish-gitea-release (push) Canceled after 0s
ci / test (push) Canceled after 0s
ci / fuzz-smoke (push) Canceled after 0s
ci / macos-client (macos-aarch64, macos-14) (push) Canceled after 0s
ci / macos-client (macos-x86_64, macos-13) (push) Canceled after 0s
ci / windows-client (push) Canceled after 0s
ci / package-release (linux-x86_64, ubuntu-latest, , , ) (push) Canceled after 0s
ci / package-release (macos-aarch64, macos-14, , , ) (push) Canceled after 0s
ci / package-release (macos-x86_64, macos-13, , , ) (push) Canceled after 0s
ci / package-release (windows-aarch64, windows-latest, aarch64, windows, aarch64-pc-windows-msvc) (push) Canceled after 0s
ci / package-release (windows-x86_64, windows-latest, , , ) (push) Canceled after 0s
ci / remote-bench (push) Canceled after 0s
ci / publish-gitea-release (push) Canceled after 0s
This commit is contained in:
+77
-26
@@ -752,7 +752,11 @@ async fn run_setup_command(config: &dosh::config::ClientConfig, args: &Args) ->
|
|||||||
match entry.action {
|
match entry.action {
|
||||||
ImportAction::Added => println!(
|
ImportAction::Added => println!(
|
||||||
"[ok] host config: [{}] ssh={} ssh_config={} dosh_host={} port={}",
|
"[ok] host config: [{}] ssh={} ssh_config={} dosh_host={} port={}",
|
||||||
entry.alias, entry.ssh, entry.ssh_config, entry.dosh_host, entry.port
|
entry.alias,
|
||||||
|
entry.ssh,
|
||||||
|
entry.ssh_config,
|
||||||
|
imported_dosh_host_display(&entry),
|
||||||
|
entry.port
|
||||||
),
|
),
|
||||||
ImportAction::Skipped => println!("[ok] host config: [{}] already exists", entry.alias),
|
ImportAction::Skipped => println!("[ok] host config: [{}] already exists", entry.alias),
|
||||||
}
|
}
|
||||||
@@ -4858,7 +4862,7 @@ struct ImportedHost {
|
|||||||
alias: String,
|
alias: String,
|
||||||
ssh: String,
|
ssh: String,
|
||||||
ssh_config: String,
|
ssh_config: String,
|
||||||
dosh_host: String,
|
dosh_host: Option<String>,
|
||||||
port: u16,
|
port: u16,
|
||||||
action: ImportAction,
|
action: ImportAction,
|
||||||
}
|
}
|
||||||
@@ -4870,10 +4874,19 @@ fn run_import_ssh(config: &dosh::config::ClientConfig, aliases: &[String]) -> Re
|
|||||||
let imported = import_ssh_aliases(config, aliases)?;
|
let imported = import_ssh_aliases(config, aliases)?;
|
||||||
for entry in imported {
|
for entry in imported {
|
||||||
match entry.action {
|
match entry.action {
|
||||||
ImportAction::Added => eprintln!(
|
ImportAction::Added => {
|
||||||
|
if let Some(dosh_host) = &entry.dosh_host {
|
||||||
|
eprintln!(
|
||||||
"dosh import-ssh: added [{}] ssh={} ssh_config={} dosh_host={}",
|
"dosh import-ssh: added [{}] ssh={} ssh_config={} dosh_host={}",
|
||||||
entry.alias, entry.ssh, entry.ssh_config, entry.dosh_host
|
entry.alias, entry.ssh, entry.ssh_config, dosh_host
|
||||||
),
|
)
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"dosh import-ssh: added [{}] ssh={} ssh_config={} dosh_host=ssh",
|
||||||
|
entry.alias, entry.ssh, entry.ssh_config
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
ImportAction::Skipped => {
|
ImportAction::Skipped => {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"dosh import-ssh: [{}] already exists, skipping",
|
"dosh import-ssh: [{}] already exists, skipping",
|
||||||
@@ -4904,28 +4917,41 @@ fn import_ssh_aliases(
|
|||||||
}
|
}
|
||||||
let mut imported = Vec::new();
|
let mut imported = Vec::new();
|
||||||
for alias in aliases {
|
for alias in aliases {
|
||||||
let ssh_config = ssh_config(alias, None)
|
|
||||||
.with_context(|| format!("read SSH config for {alias} with ssh -G"))?;
|
|
||||||
let udp_host = ssh_config
|
|
||||||
.hostname
|
|
||||||
.clone()
|
|
||||||
.unwrap_or_else(|| ssh_destination_host(alias));
|
|
||||||
if raw_contains_host_table(&raw, alias) {
|
if raw_contains_host_table(&raw, alias) {
|
||||||
imported.push(ImportedHost {
|
imported.push(ImportedHost {
|
||||||
alias: alias.clone(),
|
alias: alias.clone(),
|
||||||
ssh: alias.clone(),
|
ssh: alias.clone(),
|
||||||
ssh_config: alias.clone(),
|
ssh_config: alias.clone(),
|
||||||
dosh_host: udp_host,
|
dosh_host: None,
|
||||||
port: config.dosh_port,
|
port: config.dosh_port,
|
||||||
action: ImportAction::Skipped,
|
action: ImportAction::Skipped,
|
||||||
});
|
});
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
let ssh_config = ssh_config(alias, None)
|
||||||
|
.with_context(|| format!("read SSH config for {alias} with ssh -G"))?;
|
||||||
|
let (block, entry) = imported_host_block(config, alias, &ssh_config);
|
||||||
raw.push('\n');
|
raw.push('\n');
|
||||||
|
raw.push_str(&block);
|
||||||
|
imported.push(entry);
|
||||||
|
}
|
||||||
|
if let Some(parent) = path.parent() {
|
||||||
|
fs::create_dir_all(parent)?;
|
||||||
|
}
|
||||||
|
fs::write(&path, raw).with_context(|| format!("write {}", path.display()))?;
|
||||||
|
Ok(imported)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn imported_host_block(
|
||||||
|
config: &dosh::config::ClientConfig,
|
||||||
|
alias: &str,
|
||||||
|
ssh_config: &SshConfig,
|
||||||
|
) -> (String, ImportedHost) {
|
||||||
|
let mut raw = String::new();
|
||||||
raw.push_str(&format!("[{}]\n", toml_bare_key_or_quoted(alias)));
|
raw.push_str(&format!("[{}]\n", toml_bare_key_or_quoted(alias)));
|
||||||
raw.push_str(&format!("ssh = {}\n", toml_string(alias)));
|
raw.push_str(&format!("ssh = {}\n", toml_string(alias)));
|
||||||
raw.push_str(&format!("ssh_config = {}\n", toml_string(alias)));
|
raw.push_str(&format!("ssh_config = {}\n", toml_string(alias)));
|
||||||
raw.push_str(&format!("dosh_host = {}\n", toml_string(&udp_host)));
|
raw.push_str("# dosh_host = \"server.example.com\"\n");
|
||||||
raw.push_str(&format!("port = {}\n", config.dosh_port));
|
raw.push_str(&format!("port = {}\n", config.dosh_port));
|
||||||
if let Some(user) = &ssh_config.user {
|
if let Some(user) = &ssh_config.user {
|
||||||
raw.push_str(&format!("user = {}\n", toml_string(user)));
|
raw.push_str(&format!("user = {}\n", toml_string(user)));
|
||||||
@@ -4936,20 +4962,21 @@ fn import_ssh_aliases(
|
|||||||
raw.push_str(&format!("ssh_port = {port}\n"));
|
raw.push_str(&format!("ssh_port = {port}\n"));
|
||||||
}
|
}
|
||||||
raw.push_str("predict = true\n");
|
raw.push_str("predict = true\n");
|
||||||
imported.push(ImportedHost {
|
(
|
||||||
alias: alias.clone(),
|
raw,
|
||||||
ssh: alias.clone(),
|
ImportedHost {
|
||||||
ssh_config: alias.clone(),
|
alias: alias.to_string(),
|
||||||
dosh_host: udp_host,
|
ssh: alias.to_string(),
|
||||||
|
ssh_config: alias.to_string(),
|
||||||
|
dosh_host: None,
|
||||||
port: config.dosh_port,
|
port: config.dosh_port,
|
||||||
action: ImportAction::Added,
|
action: ImportAction::Added,
|
||||||
});
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
if let Some(parent) = path.parent() {
|
|
||||||
fs::create_dir_all(parent)?;
|
fn imported_dosh_host_display(entry: &ImportedHost) -> &str {
|
||||||
}
|
entry.dosh_host.as_deref().unwrap_or("ssh")
|
||||||
fs::write(&path, raw).with_context(|| format!("write {}", path.display()))?;
|
|
||||||
Ok(imported)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn raw_contains_host_table(raw: &str, alias: &str) -> bool {
|
fn raw_contains_host_table(raw: &str, alias: &str) -> bool {
|
||||||
@@ -10616,8 +10643,8 @@ mod tests {
|
|||||||
TERMINAL_SNAPSHOT_RESET, UpdateOptions, UpdateRole, auth_allows, cache_key,
|
TERMINAL_SNAPSHOT_RESET, UpdateOptions, UpdateRole, auth_allows, cache_key,
|
||||||
cache_server_prefix, cleanup_stream_state, clear_cached_credentials,
|
cache_server_prefix, cleanup_stream_state, clear_cached_credentials,
|
||||||
effective_update_artifact_tag, ensure_tui_safe_status_overlay, expand_ssh_path_tokens,
|
effective_update_artifact_tag, ensure_tui_safe_status_overlay, expand_ssh_path_tokens,
|
||||||
first_resolved_addr, input_contains_focus_in, input_matches_escape, is_local_status_target,
|
first_resolved_addr, imported_host_block, input_contains_focus_in, input_matches_escape,
|
||||||
is_resume_response_for_client, latest_release_download_url,
|
is_local_status_target, is_resume_response_for_client, latest_release_download_url,
|
||||||
load_first_native_identity_with_prompt, local_symlink_target_is_dir,
|
load_first_native_identity_with_prompt, local_symlink_target_is_dir,
|
||||||
local_username_from_env, native_proxy_udp_warning, newest_client_trace_path_from,
|
local_username_from_env, native_proxy_udp_warning, newest_client_trace_path_from,
|
||||||
parse_dynamic_forward, parse_escape_key, parse_local_forward, parse_remote_forward,
|
parse_dynamic_forward, parse_escape_key, parse_local_forward, parse_remote_forward,
|
||||||
@@ -11155,6 +11182,30 @@ mod tests {
|
|||||||
assert_eq!(toml_bare_key_or_quoted("home box"), "\"home box\"");
|
assert_eq!(toml_bare_key_or_quoted("home box"), "\"home box\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn imported_ssh_host_block_does_not_bake_derived_udp_host() {
|
||||||
|
let config = ClientConfig {
|
||||||
|
dosh_port: 50000,
|
||||||
|
..ClientConfig::default()
|
||||||
|
};
|
||||||
|
let ssh_config = SshConfig {
|
||||||
|
hostname: Some("10.0.0.5".to_string()),
|
||||||
|
user: Some("deploy".to_string()),
|
||||||
|
port: Some(2222),
|
||||||
|
..SshConfig::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let (block, imported) = imported_host_block(&config, "prod", &ssh_config);
|
||||||
|
|
||||||
|
assert!(block.contains("[prod]\n"));
|
||||||
|
assert!(block.contains("ssh_config = \"prod\"\n"));
|
||||||
|
assert!(block.contains("# dosh_host = \"server.example.com\"\n"));
|
||||||
|
assert!(!block.contains("dosh_host = \"10.0.0.5\""));
|
||||||
|
assert!(block.contains("user = \"deploy\"\n"));
|
||||||
|
assert!(block.contains("ssh_port = 2222\n"));
|
||||||
|
assert_eq!(imported.dosh_host, None);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn strips_user_from_fallback_udp_host() {
|
fn strips_user_from_fallback_udp_host() {
|
||||||
assert_eq!(ssh_destination_host("alice@example.com"), "example.com");
|
assert_eq!(ssh_destination_host("alice@example.com"), "example.com");
|
||||||
|
|||||||
Reference in New Issue
Block a user