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

The first sftp session now lists .ssh before fetching authorized_keys. The file reads as empty only when sftp reports .ssh itself as missing, or the listing succeeded and the file is reported missing. A directory or file that is there but cannot be read fails the run and nothing is written, so no existing authorized_keys is replaced by content that was not built from what was read. An .ssh that already exists keeps its mode; the directory is made and set to 0700 only when none was found. The README describes the rule and states batch mode's limit: a key or an agent must authenticate.

Model: opus-4-8 (implementation); fable-5-1 (summary)
This commit was merged in pull request #27.
This commit is contained in:
2026-09-21 09:49:59 +02:00
parent e6ddf49acc
commit 3d90ac87f1
4 changed files with 279 additions and 58 deletions
+17 -15
View File
@@ -95,22 +95,24 @@ Adds the `pub` line to `~/.ssh/authorized_keys` on the host. No command is run
on the host: the file is fetched, changed here, and written back with the
system `sftp` client in batch mode.
The first connection fetches `~/.ssh/authorized_keys`. The file reads as empty
only when `sftp` reported that file as not being there — the one line naming
that path. The same wording anywhere else in the session does not count: `ssh`
writes `No such file or directory` about an `-i` it cannot find, on a session
that then authenticates through the agent. When `sftp` failed for any other
reason — the file is there and cannot be read, the connection did not come up —
the tool prints what `sftp` said and exits with status 1 without writing
anything, rather than put a file back holding the new key alone. What `sftp`
cannot tell apart is a missing file and one in a directory it cannot enter, so a
`~/.ssh` whose mode shuts the user out reads as a host with no file; the second
connection sets that mode to `0700` and writes, as on a host that has none. If
an identical line is already in the file, the tool prints
`already present` and connects no further. Otherwise the line is added (after a
newline, if the file did not end with one) and a second connection:
The first connection lists `~/.ssh` and then fetches
`~/.ssh/authorized_keys` from it. The file reads as empty in two cases only:
`sftp` reported `~/.ssh` itself as not being there, or the listing came up and
the file was not in it. Any other outcome of that connection fails the run — a
`~/.ssh` that is there but cannot be entered, an `authorized_keys` that is there
but cannot be read, or a connection that did not come up — and the tool prints
what `sftp` said and exits with status 1 without writing anything, rather than
put a file back holding the new key alone. The listing is what tells a missing
directory from one shut to the user, which `sftp` reports on a fetch the same
way; the wording of a missing file elsewhere does not count either, since `ssh`
writes `No such file or directory` about an `-i` it cannot find on a session
that then authenticates through the agent. If an identical line is already in
the file, the tool prints `already present` and connects no further. Otherwise
the line is added (after a newline, if the file did not end with one) and a
second connection:
- creates `~/.ssh` and sets it to mode `0700`;
- makes `~/.ssh` and sets it to mode `0700`, but only when the first connection
found none; a `~/.ssh` that was already there keeps the mode it had;
- uploads the new file as `~/.ssh/authorized_keys.keyfunc-<random>` and sets it
to mode `0600`;
- renames that file over `~/.ssh/authorized_keys`.