diff --git a/04-ISSUES/172-the-ssh-client-block-matches-one-spelling-of-a-machine/00-report.md b/04-ISSUES/172-the-ssh-client-block-matches-one-spelling-of-a-machine/00-report.md new file mode 100644 index 0000000..fcb4b81 --- /dev/null +++ b/04-ISSUES/172-the-ssh-client-block-matches-one-spelling-of-a-machine/00-report.md @@ -0,0 +1,55 @@ +--- +status: located +opened: 2026-09-30 +located-in: + - the predecessor's terminal module (still generating the operator's ssh client blocks on every workstation) + - mesh-controller internal/catalogue (the ssh-client roster, tested and not yet a catalogue module) +fixed-by: +amended-design: +--- + +# 172 — The ssh client block for a machine matches one spelling of its name, and the other gets the wrong user + +## What was observed + +On a workstation, 2026-09-30, reported by the operator. `ssh home-server` logs in; `ssh +home-server.internal` is refused with `Permission denied (publickey)`. The operator expected the +opposite, if either: the full mesh name is the one the resolver serves. + +The name is not the fault. Both spellings resolve to the machine's private address — the mesh's roster +region in the hosts file carries `.internal ` on one line, and the resolver answers +anything under the node's name. What differs is the login: the generated client configuration has a +`Host home-server` block naming the account to log in as, and `home-server.internal` matches no block, +so ssh falls back to the operator's local username, which has no account on that machine. Spelled +`account@home-server.internal` it works. + +The file is the predecessor's. `~/.ssh/config.d/mesh` says in its own header that it is generated by +the predecessor's terminal module, which only ever wrote the bare name. The mesh's own ssh-client +roster — every other machine's Host block, written as a marked region of the operator's `~/.ssh/config` +with the account the mesh knows for that machine (to-be 29) — already matches both spellings, and a +controller test holds `Host marge marge.internal`. It is composed and tested in the controller and is +not a module in the catalogue, so no machine receives it; every workstation still runs the +predecessor's generator. + +## Why it matters beyond this instance + +**A name the mesh serves and a name a person can use are not the same set**, and the difference is +silent. The resolver, the hosts file and the certificate authority all treat `.internal` as the +machine's name; the one file that decides who you log in as does not know it. A person who learns the +mesh's name from `status` or from a certificate and types it is refused with an error that says +nothing about a missing Host block. + +**It is the migration story for the operator's own tooling, arriving as a symptom.** The mesh has the +right file and does not ship it. Until the ssh-client roster is a module and is assigned to the +workstations, the predecessor's generator keeps writing a file the mesh has already superseded, and +every such file is one the mesh cannot correct. + +## Open questions + +- Should the ssh-client roster become a catalogue module now, assigned to every workstation, and take + the predecessor's `config.d/mesh` out of the operator's `Include`? Its content is settled; what is + not is the takeover of a file in a person's home that another generator still writes. +- Should the block match a third spelling — the machine's public name, where it has one — or is that + a different key and a different account? +- What checks it? A controller test holds the two spellings; nothing checks that the file a workstation + actually has is the mesh's rather than the predecessor's.