From e1b6080c168a5ccfdd5d39cb90c404de6f8b4e6f Mon Sep 17 00:00:00 2001 From: majiayu000 <1835304752@qq.com> Date: Mon, 30 Mar 2026 20:58:58 +0800 Subject: [PATCH 1/2] fix: allow non-ASCII characters in SSH host aliases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The userHostRe regexp only accepted ASCII letters and digits in the host portion, rejecting valid SSH config Host aliases that contain Chinese or other Unicode characters (e.g. "PROD-服务器"). Widen the character classes with \p{L} and \p{N} to accept Unicode letters and digits. Fixes #2937 Signed-off-by: majiayu000 <1835304752@qq.com> --- pkg/remote/connutil.go | 2 +- pkg/remote/connutil_test.go | 52 +++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 pkg/remote/connutil_test.go diff --git a/pkg/remote/connutil.go b/pkg/remote/connutil.go index 89d53f6ae4..98ce8d0961 100644 --- a/pkg/remote/connutil.go +++ b/pkg/remote/connutil.go @@ -26,7 +26,7 @@ import ( "golang.org/x/crypto/ssh" ) -var userHostRe = regexp.MustCompile(`^([a-zA-Z0-9][a-zA-Z0-9._@\\-]*@)?([a-zA-Z0-9][a-zA-Z0-9.-]*)(?::([0-9]+))?$`) +var userHostRe = regexp.MustCompile(`^([a-zA-Z0-9\p{L}\p{N}][a-zA-Z0-9._@\p{L}\p{N}\\-]*@)?([a-zA-Z0-9\p{L}\p{N}][a-zA-Z0-9.\p{L}\p{N}-]*)(?::([0-9]+))?$`) func ParseOpts(input string) (*SSHOpts, error) { m := userHostRe.FindStringSubmatch(input) diff --git a/pkg/remote/connutil_test.go b/pkg/remote/connutil_test.go new file mode 100644 index 0000000000..b8889f44f2 --- /dev/null +++ b/pkg/remote/connutil_test.go @@ -0,0 +1,52 @@ +// Copyright 2025, Command Line Inc. +// SPDX-License-Identifier: Apache-2.0 + +package remote + +import ( + "testing" +) + +func TestParseOpts(t *testing.T) { + tests := []struct { + name string + input string + wantUser string + wantHost string + wantPort string + wantErr bool + }{ + {"user@host:port", "user@myserver:22", "user", "myserver", "22", false}, + {"host only", "myserver", "", "myserver", "", false}, + {"chinese host alias", "PROD-服务器", "", "PROD-服务器", "", false}, + {"mixed ascii and chinese with user and port", "user@PROD-阿里云:22", "user", "PROD-阿里云", "22", false}, + {"unicode only host", "服务器", "", "服务器", "", false}, + {"japanese host", "サーバー", "", "サーバー", "", false}, + {"empty string", "", "", "", "", true}, + {"just colon", ":", "", "", "", true}, + {"just at", "@", "", "", "", true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + opts, err := ParseOpts(tt.input) + if tt.wantErr { + if err == nil { + t.Fatalf("expected error, got nil") + } + return + } + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if opts.SSHUser != tt.wantUser { + t.Errorf("user: got %q, want %q", opts.SSHUser, tt.wantUser) + } + if opts.SSHHost != tt.wantHost { + t.Errorf("host: got %q, want %q", opts.SSHHost, tt.wantHost) + } + if opts.SSHPort != tt.wantPort { + t.Errorf("port: got %q, want %q", opts.SSHPort, tt.wantPort) + } + }) + } +} From ac25dd30eecdeee80e4ed4ac3ade21cc19c8e266 Mon Sep 17 00:00:00 2001 From: majiayu000 <1835304752@qq.com> Date: Tue, 31 Mar 2026 11:48:53 +0800 Subject: [PATCH 2/2] test: add unicode username test case for ParseOpts Signed-off-by: majiayu000 <1835304752@qq.com> --- pkg/remote/connutil_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/pkg/remote/connutil_test.go b/pkg/remote/connutil_test.go index b8889f44f2..658a99acb1 100644 --- a/pkg/remote/connutil_test.go +++ b/pkg/remote/connutil_test.go @@ -20,6 +20,7 @@ func TestParseOpts(t *testing.T) { {"host only", "myserver", "", "myserver", "", false}, {"chinese host alias", "PROD-服务器", "", "PROD-服务器", "", false}, {"mixed ascii and chinese with user and port", "user@PROD-阿里云:22", "user", "PROD-阿里云", "22", false}, + {"unicode user and host", "用户@服务器:22", "用户", "服务器", "22", false}, {"unicode only host", "服务器", "", "服务器", "", false}, {"japanese host", "サーバー", "", "サーバー", "", false}, {"empty string", "", "", "", "", true},