ssh install tells a missing .ssh from one it cannot enter (closes #10)
check / check (push) Failing after 1s

The first sftp connection now lists ~/.ssh before it fetches
authorized_keys. The file reads as empty in just two cases: sftp reports
~/.ssh itself as not there, or the listing succeeds and the fetch then
reports the file as not there. A directory that is there but cannot be
entered, or a file that cannot be read, fails the run and writes nothing,
so a ~/.ssh whose mode shuts the user out is no longer read as a host
with no file and replaced by one holding the new key alone. The write
connection makes ~/.ssh and sets 0700 only when the read found none; an
existing directory keeps its mode.

Model: opus-4-8
This commit is contained in:
clawbot
2026-09-21 07:38:26 +00:00
parent 860e590114
commit f6663e4df2
4 changed files with 279 additions and 58 deletions
+55
View File
@@ -10,6 +10,7 @@ import "testing"
const (
echoed = `sftp> get .ssh/authorized_keys "/tmp/keyfunc/authorized_keys"
`
listed = "sftp> ls -1 .ssh\n"
warning = `Warning: Identity file /gone not accessible: ` +
"No such file or directory.\n"
)
@@ -76,3 +77,57 @@ func TestAbsenceIsReadOnlyFromWhatSFTPSaidAboutAuthorizedKeys(t *testing.T) {
})
}
}
// TestTheDirectoryIsReadAsAbsentOnlyFromTheListingSayingSo holds the
// wordings the OpenSSH client was seen to use when a listing fails: a
// directory it cannot find is reported one way, and one it cannot enter
// another, and only the first is read as a host with no .ssh yet.
func TestTheDirectoryIsReadAsAbsentOnlyFromTheListingSayingSo(t *testing.T) {
t.Parallel()
listings := map[string]struct {
said string
want bool
}{
"the directory is not there": {
said: listed + `Can't ls: "/home/someone/.ssh" not found` + "\n",
want: true,
},
"the directory is not there, named as it was asked for": {
said: listed + `Can't ls: ".ssh" not found` + "\n",
want: true,
},
"the directory is not there and an identity file is not either": {
said: warning + listed +
`Can't ls: "/home/someone/.ssh" not found` + "\n",
want: true,
},
"the directory is there and cannot be entered": {
said: listed +
`remote readdir("/home/someone/.ssh/"): Permission denied` + "\n",
want: false,
},
"some other directory is not there": {
said: listed + `Can't ls: "/home/someone/.config" not found` + "\n",
want: false,
},
"the connection did not come up": {
said: "ssh: connect to host example.com port 22: " +
"Connection refused\nConnection closed\n",
want: false,
},
}
for name, listing := range listings {
t.Run(name, func(t *testing.T) {
t.Parallel()
if directoryAbsent(listing.said) != listing.want {
t.Errorf(
"read as absent: %t, wanted %t, from:\n%s",
!listing.want, listing.want, listing.said,
)
}
})
}
}