Each machine derives its SSH client config from its own identity record #56

Closed
opened 2026-09-20 01:35:25 +01:00 by vnprc-agent · 2 comments
Contributor

Stop copying the hypervisor's SSH address book into every dev VM, and have the framework render a dev VM's forge host entry from that VM's own identity record, so that no SSH host block has two authors and no machine carries aliases it cannot use. This is the multi-repo home for that change; the framework work is allod/archetypes#54.

Primary goals:

  • One author per host block — the dev VM builder renders the forge entry from the identity fields it already receives (forgeHost, forgePort, sshKeyName). The profile copies and the lib.mkDefault tie-breaker that let two layers define one block go away.
  • Address book reaches the hypervisor only — identity.sshHosts is the hypervisor's SSH client configuration, keyed to a key only the hypervisor holds. Dev VMs stop receiving it, which closes the dead-alias and fleet-exposure defects by absence rather than by a per-entry filter.
  • Deprecation warnings die on the way — the hypervisor path emits programs.ssh.settings, translating the current sshHosts field names to upstream directive names in one place. Home Manager 26.05's matchBlocks warnings stop without renaming any data.
  • Data untouched — no sshHosts entry changes, and the nexus rotation scripts keep reading the same fields.

Children

  • allod/archetypes#54 — framework change and its check; supersedes the scope of allod/archetypes#79
  • allod/secrets — template sshHosts entries gain localForwards and extraOptions so the framework check exercises every field shape the translation claims (part of the allod/archetypes#54 change)
  • allod/profiles#8 — the SSH half becomes deleting the forge block from hosts/dev/allod-dev/home.nix; the neovim half is independent
  • deployments' private profiles delete their own copies of the forge block (handoff to each deployment; lands with the deploy lock bump that takes the archetypes change)

Held pull requests

allod/archetypes#80 and allod/profiles#9 implemented the warning fix by keeping both authors and porting the tie-breaker to the new option, which forces a strict landing order between the two repos. They stay open but unmerged. The translation and the ssh -G check from allod/archetypes#80 are harvested into the allod/archetypes#54 change, after which both are closed.

Landing order

The framework keeps lib.mkDefault on the rendered forge IdentityFile until every profile copy is gone, so the deploy lock may take the archetypes change and the profiles changes in either order. The trigger for the follow-up that drops it is a deploy lock in which no profile input still defines the forge block; after that, a stray copy is a type clash at evaluation, not a silent winner.

Out of scope

Renaming sshHosts field names to OpenSSH's directive names, which would make the hypervisor path a verbatim copy with no translation; a separate step across the secrets template, deployments' data, and the nexus scripts. A per-VM list of extra hosts a VM reaches with its own key, which would live in that VM's identity record beside sshKeyName when a deployment needs it. Deriving the address book's VM addresses from inventory, which is its own arc.

Stop copying the hypervisor's SSH address book into every dev VM, and have the framework render a dev VM's forge host entry from that VM's own identity record, so that no SSH host block has two authors and no machine carries aliases it cannot use. This is the multi-repo home for that change; the framework work is allod/archetypes#54. Primary goals: - **One author per host block** — the dev VM builder renders the forge entry from the identity fields it already receives (`forgeHost`, `forgePort`, `sshKeyName`). The profile copies and the `lib.mkDefault` tie-breaker that let two layers define one block go away. - **Address book reaches the hypervisor only** — `identity.sshHosts` is the hypervisor's SSH client configuration, keyed to a key only the hypervisor holds. Dev VMs stop receiving it, which closes the dead-alias and fleet-exposure defects by absence rather than by a per-entry filter. - **Deprecation warnings die on the way** — the hypervisor path emits `programs.ssh.settings`, translating the current `sshHosts` field names to upstream directive names in one place. Home Manager 26.05's `matchBlocks` warnings stop without renaming any data. - **Data untouched** — no `sshHosts` entry changes, and the nexus rotation scripts keep reading the same fields. ### Children - [ ] allod/archetypes#54 — framework change and its check; supersedes the scope of allod/archetypes#79 - [ ] allod/secrets — template `sshHosts` entries gain `localForwards` and `extraOptions` so the framework check exercises every field shape the translation claims (part of the allod/archetypes#54 change) - [ ] allod/profiles#8 — the SSH half becomes deleting the forge block from `hosts/dev/allod-dev/home.nix`; the neovim half is independent - [ ] deployments' private profiles delete their own copies of the forge block (handoff to each deployment; lands with the deploy lock bump that takes the archetypes change) ### Held pull requests allod/archetypes#80 and allod/profiles#9 implemented the warning fix by keeping both authors and porting the tie-breaker to the new option, which forces a strict landing order between the two repos. They stay open but unmerged. The translation and the `ssh -G` check from allod/archetypes#80 are harvested into the allod/archetypes#54 change, after which both are closed. ### Landing order The framework keeps `lib.mkDefault` on the rendered forge `IdentityFile` until every profile copy is gone, so the deploy lock may take the archetypes change and the profiles changes in either order. The trigger for the follow-up that drops it is a deploy lock in which no profile input still defines the forge block; after that, a stray copy is a type clash at evaluation, not a silent winner. ### Out of scope Renaming `sshHosts` field names to OpenSSH's directive names, which would make the hypervisor path a verbatim copy with no translation; a separate step across the secrets template, deployments' data, and the nexus scripts. A per-VM list of extra hosts a VM reaches with its own key, which would live in that VM's identity record beside `sshKeyName` when a deployment needs it. Deriving the address book's VM addresses from inventory, which is its own arc.
Member

The three public changes for this issue are open: allod/archetypes#81 (framework split, translation, ssh -G check; closes allod/archetypes#54), allod/secrets#33 (template localForwards and extraOptions entries) and allod/profiles#10 (forge block deleted, neovim provider flags). Each body carries its validation against the public deploy template. What remains for this issue is the per-deployment half: the private profile copies of the forge block, and the render of each deployment machine's ~/.ssh/config against allod/archetypes#81, which only the deployer can run.

One correction to the "Landing order" section. Evaluation is clean in either order, as written. Deployment order is not free: a deploy lock that takes the profile deletion while its archetypes pin still predates allod/archetypes#81 leaves that dev VM with the address book's forge block, keyed to the hypervisor's key it does not hold, until the archetypes pin catches up. Take the archetypes change first or together with the profile deletions. Nothing fails to evaluate in the wrong order, so this is a human check at the lock bump, not a canary.

One precision on "byte-identical". Measured on the public template with allod/secrets#33 in place: the hypervisor's rendered config is byte-identical for every entry without extraOptions; for an entry with extraOptions the same directives render in a different order inside the block (the legacy option appended them after the typed directives, the flat merge sorts them in). ssh -G resolves every host identically under both. A deployment measurement should compare ssh -G output per host, not bytes, for those entries.

Two facts a deployment's address book may hit at the lock bump, both loud evaluation errors naming the host: an extraOptions.SetEnv written as a string must become an attribute set (SetEnv = { ROLE = "backup"; }), because Home Manager's settings renderer takes only that form; and an extraOptions key that names a directive already set by a translated field, compared case-insensitively, is rejected rather than silently winning.

The three public changes for this issue are open: allod/archetypes#81 (framework split, translation, `ssh -G` check; closes allod/archetypes#54), allod/secrets#33 (template `localForwards` and `extraOptions` entries) and allod/profiles#10 (forge block deleted, neovim provider flags). Each body carries its validation against the public deploy template. What remains for this issue is the per-deployment half: the private profile copies of the forge block, and the render of each deployment machine's `~/.ssh/config` against allod/archetypes#81, which only the deployer can run. One correction to the "Landing order" section. Evaluation is clean in either order, as written. Deployment order is not free: a deploy lock that takes the profile deletion while its archetypes pin still predates allod/archetypes#81 leaves that dev VM with the address book's forge block, keyed to the hypervisor's key it does not hold, until the archetypes pin catches up. Take the archetypes change first or together with the profile deletions. Nothing fails to evaluate in the wrong order, so this is a human check at the lock bump, not a canary. One precision on "byte-identical". Measured on the public template with allod/secrets#33 in place: the hypervisor's rendered config is byte-identical for every entry without `extraOptions`; for an entry with `extraOptions` the same directives render in a different order inside the block (the legacy option appended them after the typed directives, the flat merge sorts them in). `ssh -G` resolves every host identically under both. A deployment measurement should compare `ssh -G` output per host, not bytes, for those entries. Two facts a deployment's address book may hit at the lock bump, both loud evaluation errors naming the host: an `extraOptions.SetEnv` written as a string must become an attribute set (`SetEnv = { ROLE = "backup"; }`), because Home Manager's settings renderer takes only that form; and an `extraOptions` key that names a directive already set by a translated field, compared case-insensitively, is rejected rather than silently winning.
Author
Contributor

Status. Every child has landed: allod/archetypes#54 (framework, c213a34), the allod/secrets template shapes (e21b088), allod/profiles#8 (fa37849), and the deployment's private profile copies, taken into its deploy lock together with the framework. allod/archetypes#80 and allod/profiles#9 are closed. Measured on a rebuilt dev VM: ~/.ssh/config holds one Host block, the forge, and git over SSH to the forge works with the VM's own key.

The landing-order trigger is met, so the follow-up that drops the transitional lib.mkDefault is filed as allod/archetypes#82; this issue closes with it. One residual outside this arc: a dev VM that reached an external host with its own key through an address-book alias no longer has that alias, which is the per-VM host list named under Out of scope, tracked by the deployment.

Status. Every child has landed: allod/archetypes#54 (framework, c213a34), the allod/secrets template shapes (e21b088), allod/profiles#8 (fa37849), and the deployment's private profile copies, taken into its deploy lock together with the framework. allod/archetypes#80 and allod/profiles#9 are closed. Measured on a rebuilt dev VM: `~/.ssh/config` holds one `Host` block, the forge, and git over SSH to the forge works with the VM's own key. The landing-order trigger is met, so the follow-up that drops the transitional `lib.mkDefault` is filed as allod/archetypes#82; this issue closes with it. One residual outside this arc: a dev VM that reached an external host with its own key through an address-book alias no longer has that alias, which is the per-VM host list named under Out of scope, tracked by the deployment.
vnprc closed this issue 2026-09-20 05:16:37 +01:00
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
allod/strategy#56
No description provided.