Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/remote/connutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
52 changes: 52 additions & 0 deletions pkg/remote/connutil_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
})
}
}