remote_file kitten: fix dotfile rename and ssh-kitten cmdline truncation edge cases

This commit is contained in:
OBrutus 2026-08-12 17:45:35 +05:30
parent 25c3347d38
commit f9e242e308
2 changed files with 43 additions and 2 deletions

View file

@ -44,8 +44,11 @@ func parse_conn_data(raw string) (*SSHConnectionData, error) {
cmdline = append(cmdline, s)
}
}
// Python: sk_cmdline[:-2] always removes last 2, or returns empty if fewer items
if len(cmdline) >= 2 {
cmdline = cmdline[:len(cmdline)-2]
} else {
cmdline = cmdline[:0]
}
ans.SSHKittenCmdline = cmdline
return ans, nil
@ -96,10 +99,28 @@ func hostname_matches(from_hyperlink, actual string) bool {
return fl == al
}
// pythonSplitExt mirrors Python's os.path.splitext behavior for dotfiles.
// For a file like "/x/.bashrc" (basename ".bashrc"), Python returns ("/x/.bashrc", "").
// Go's filepath.Ext would return (".bashrc", "/x/"), losing the filename.
// Rule: if basename starts with '.' and has no other dots, treat extension as empty.
func pythonSplitExt(path string) (string, string) {
ext := filepath.Ext(path)
if ext == "" {
return path, ""
}
basename := filepath.Base(path)
// If basename starts with '.' and has exactly one dot (the leading dot),
// then this is a dotfile with no extension.
if strings.HasPrefix(basename, ".") && strings.Count(basename, ".") == 1 {
return path, ""
}
base := strings.TrimSuffix(path, ext)
return base, ext
}
func auto_rename_dest(dest string, exists func(string) bool) string {
q := dest
ext := filepath.Ext(dest)
base := strings.TrimSuffix(dest, ext)
base, ext := pythonSplitExt(dest)
for c := 1; exists(q); c++ {
q = fmt.Sprintf("%s-%d%s", base, c, ext)
}

View file

@ -75,3 +75,23 @@ func TestAutoRenameDest(t *testing.T) {
t.Fatalf("auto_rename_dest: %q", got)
}
}
func TestAutoRenameDotfile(t *testing.T) {
taken := map[string]bool{"/x/.bashrc": true}
got := auto_rename_dest("/x/.bashrc", func(p string) bool { return taken[p] })
if got != "/x/.bashrc-1" {
t.Fatalf("auto_rename_dest dotfile: got %q, want /x/.bashrc-1", got)
}
}
func TestParseConnDataSSHKittenEdge(t *testing.T) {
// ssh-kitten with exactly 1 cmdline item after sentinel should result in empty SSHKittenCmdline
raw := fmt.Sprintf(`["%s", "onlyitem"]`, is_ssh_kitten_sentinel)
c, err := parse_conn_data(raw)
if err != nil {
t.Fatal(err)
}
if !c.IsSSHKitten || c.Hostname != "onlyitem" || len(c.SSHKittenCmdline) != 0 {
t.Fatalf("ssh kitten edge case (single item): %+v, SSHKittenCmdline=%v", c, c.SSHKittenCmdline)
}
}