fix(bastion): match OpenSSH username parsing for protocol-proxy hop

OpenSSH treats the last @ as user/host separator, so the SSH username must be hop@target@ip without duplicating hop_host. Legacy templates with {hop_host} are stripped automatically; connect logs now show bastion_ssh_cli for comparison with manual ssh.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-06-23 21:49:43 +08:00
parent 79ae5ff31c
commit 088e920f9d
7 changed files with 197 additions and 67 deletions

View file

@ -9,9 +9,11 @@ export type HopTargetAuthMode = "bastion_managed" | "manual";
export const HOP_VENDORS: HopVendor[] = ["zte", "huawei", "cisco", "linux", "bastion"];
export function bastionHopTemplate(): string {
return "{hop_user}@{target_user}@{target_ip}@{hop_host}";
return "{hop_user}@{target_user}@{target_ip}";
}
export const LEGACY_BASTION_HOP_TEMPLATE = "{hop_user}@{target_user}@{target_ip}@{hop_host}";
export function isBastionHopVendor(vendor: string): boolean {
return String(vendor || "").toLowerCase() === "bastion";
}

View file

@ -42,6 +42,11 @@ export function isAutoHopTemplate(
if (v === "huawei") return t === huaweiHopTemplate(protocol, vrf);
if (v === "cisco") return t === ciscoHopTemplate(protocol, vrf);
if (v === "linux") return t === "";
if (v === "bastion") return t === "{hop_user}@{target_user}@{target_ip}@{hop_host}";
if (v === "bastion") {
return (
t === "{hop_user}@{target_user}@{target_ip}"
|| t === "{hop_user}@{target_user}@{target_ip}@{hop_host}"
);
}
return t === zteHopTemplate(protocol, vrf);
}