Per-VM SSH aliases for external hosts a dev VM reaches with its own key #57

Closed
opened 2026-09-20 04:56:11 +01:00 by vnprc-agent · 3 comments
Contributor

Let a dev VM declare, in its own identity record, the few external hosts it reaches with its own key, and have the framework render those aliases beside its forge entry, so that a VM which lost a working alias when the hypervisor's address book stopped reaching it (allod/strategy#56) gets it back without the address book. Multi-repo home for that change; the public work is allod/archetypes#83.

Primary goals:

  • Per-VM aliases are per-VM data — devVMs.<vm>.sshHosts in the secrets identity, same entry shape as identity.sshHosts, projected onto devIdentities.<vm>.sshHosts with identityFile defaulting to that VM's own key and identitiesOnly to true. Empty by default, so nothing changes for a fork that declares none.
  • Refused at the source, not filtered downstream — the projection rejects an alias that names the forge host (the framework renders that block; a duplicate would win silently) or any machine of the deployment (VM-to-VM aliases stay on the hypervisor), compared case-insensitively because OpenSSH matches Host patterns that way; an alias that is not one literal token of letters, digits, dot, underscore and hyphen, because a space or a glob character renders a pattern that can capture the forge host and evade the name check; and an entry without a hostname.
  • Rendered by the same translation the hypervisor uses — the dev VM builder feeds identity.sshHosts through the existing field-name translation, beside the forge entry; a fork whose secrets predate the field gets an empty set.
  • Covered by the public template — a synthetic per-VM entry on the template's dev machine, so the framework check exercises the path against real composed data.

Children

  • allod/archetypes#83 — framework: consume identity.sshHosts in the dev VM builder, refuse a forge-named alias there too, extend the ssh-settings check
  • allod/secrets — template: the projection in devIdentities, its refusals, and one synthetic entry on the template dev machine (part of the allod/archetypes#83 change)
  • deployments' private secrets: the same projection and their real entries (handoff; the deployment that raised this has it prepared and lands it with the deploy lock bump that takes the framework)

Landing order

Free. The framework reads the field with an empty default, so a secrets fork without it composes unchanged; a fork with the field and the old framework carries inert data. Aliases appear on a VM at the first rebuild after a deploy lock carries both.

Out of scope

Anything keyed to the hypervisor's key; identity.sshHosts and its consumers; renaming the address book's field names.

Let a dev VM declare, in its own identity record, the few external hosts it reaches with its own key, and have the framework render those aliases beside its forge entry, so that a VM which lost a working alias when the hypervisor's address book stopped reaching it (allod/strategy#56) gets it back without the address book. Multi-repo home for that change; the public work is allod/archetypes#83. Primary goals: - **Per-VM aliases are per-VM data** — `devVMs.<vm>.sshHosts` in the secrets identity, same entry shape as `identity.sshHosts`, projected onto `devIdentities.<vm>.sshHosts` with `identityFile` defaulting to that VM's own key and `identitiesOnly` to true. Empty by default, so nothing changes for a fork that declares none. - **Refused at the source, not filtered downstream** — the projection rejects an alias that names the forge host (the framework renders that block; a duplicate would win silently) or any machine of the deployment (VM-to-VM aliases stay on the hypervisor), compared case-insensitively because OpenSSH matches `Host` patterns that way; an alias that is not one literal token of letters, digits, dot, underscore and hyphen, because a space or a glob character renders a pattern that can capture the forge host and evade the name check; and an entry without a hostname. - **Rendered by the same translation the hypervisor uses** — the dev VM builder feeds `identity.sshHosts` through the existing field-name translation, beside the forge entry; a fork whose secrets predate the field gets an empty set. - **Covered by the public template** — a synthetic per-VM entry on the template's dev machine, so the framework check exercises the path against real composed data. ### Children - [ ] allod/archetypes#83 — framework: consume `identity.sshHosts` in the dev VM builder, refuse a forge-named alias there too, extend the `ssh-settings` check - [ ] allod/secrets — template: the projection in `devIdentities`, its refusals, and one synthetic entry on the template dev machine (part of the allod/archetypes#83 change) - [ ] deployments' private secrets: the same projection and their real entries (handoff; the deployment that raised this has it prepared and lands it with the deploy lock bump that takes the framework) ### Landing order Free. The framework reads the field with an empty default, so a secrets fork without it composes unchanged; a fork with the field and the old framework carries inert data. Aliases appear on a VM at the first rebuild after a deploy lock carries both. ### Out of scope Anything keyed to the hypervisor's key; `identity.sshHosts` and its consumers; renaming the address book's field names.
Author
Contributor

All children landed and the deployment's lock carries the framework, the template and its own per-VM data; the first alias appears on the deployment's VM at its next rebuild.

All children landed and the deployment's lock carries the framework, the template and its own per-VM data; the first alias appears on the deployment's VM at its next rebuild.
Author
Contributor

Reopened: my closing comment misread allod/archetypes#82 as the child implementation. allod/archetypes#83 has no PR yet; the secrets-side data of one deployment is merged and inert, as the landing-order section says it can be. Remaining: allod/archetypes#83 and the template change it carries.

Reopened: my closing comment misread allod/archetypes#82 as the child implementation. allod/archetypes#83 has no PR yet; the secrets-side data of one deployment is merged and inert, as the landing-order section says it can be. Remaining: allod/archetypes#83 and the template change it carries.
Member

The two public changes are open: allod/secrets#34 (the devVMs.<vm>.sshHosts projection, its refusals, the dev-ssh-hosts check and one template entry) and allod/archetypes#85 (the dev VM builder feeds the projected list through the shared translation, refuses a forge-named or non-literal alias itself, and the ssh-settings check covers the path). Measured on the public deploy template with both branches: allod-dev renders example-build-cache beside an unchanged forge block, both keyed to its own key; nexus and privacy-1 keep the same system derivations as the current lock.

Merge order: allod/secrets#34 first. Then allod/archetypes#85 takes one more commit bumping its own secrets lock, so its composed wiring assertion sees the template alias and pins the new import on the repo's own checks; after that it merges. Runtime order in a deploy lock stays free as the issue says.

Review found three boundary holes beyond the issue text, now closed on both layers: an extraOptions.header key or a newline in any string field could open a block that captures the forge entry; two aliases differing only by case both matched one host; and the framework's own fallback compared raw names, so a trailing space or a literal Host prefix slipped past. extraOptions keys are now restricted to bare directive names, letters and digits only, on both paths; a deployment address book entry with an unusual key would fail loudly at the lock bump.

The two public changes are open: allod/secrets#34 (the `devVMs.<vm>.sshHosts` projection, its refusals, the `dev-ssh-hosts` check and one template entry) and allod/archetypes#85 (the dev VM builder feeds the projected list through the shared translation, refuses a forge-named or non-literal alias itself, and the `ssh-settings` check covers the path). Measured on the public deploy template with both branches: `allod-dev` renders `example-build-cache` beside an unchanged forge block, both keyed to its own key; `nexus` and `privacy-1` keep the same system derivations as the current lock. Merge order: allod/secrets#34 first. Then allod/archetypes#85 takes one more commit bumping its own `secrets` lock, so its composed wiring assertion sees the template alias and pins the new import on the repo's own checks; after that it merges. Runtime order in a deploy lock stays free as the issue says. Review found three boundary holes beyond the issue text, now closed on both layers: an `extraOptions.header` key or a newline in any string field could open a block that captures the forge entry; two aliases differing only by case both matched one host; and the framework's own fallback compared raw names, so a trailing space or a literal `Host ` prefix slipped past. `extraOptions` keys are now restricted to bare directive names, letters and digits only, on both paths; a deployment address book entry with an unusual key would fail loudly at the lock bump.
vnprc closed this issue 2026-09-20 14:47:00 +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#57
No description provided.