Carry the host user's credential files in nexusIdentity #17

Closed
opened 2026-09-10 15:12:30 +01:00 by vnprc-agent · 0 comments

Let a deployment name, through the identity contract, the two age files a host user's tools read — the human's forge API token and the site hosting rclone config — so the framework can place them instead of each deployment writing its own module. Part of allod/strategy#51.

Primary goals:

  • Two fields on nexusIdentity — userForgejoTokenFile and siteHostingConfigFile, both null in this template beside the existing forgeTokenFile = null (flake.nix:84-89). A deployment sets them to "${self}/secrets/<name>.age", the same spelling the dev-VM token fields use.
  • The shape is documented, not guessed — what each file decrypts to, who its recipients are, and what its credentials.nix record looks like, so a fork can produce a valid one without reading the consumer.
  • Older consumers keep evaluating — the framework reads these with or null, so this can land first and nothing downstream breaks in either order.

Current state and specifics

nexusIdentity today: username, hostname, forge coordinates, host SSH public keys, forgeTokenFile = null. The README's exported-outputs table describes it at README.md:56, and "How archetypes consumes it" at README.md:169-176 lists what the framework reads from it; both gain the two fields.

Shape to document:

Field Decrypts to Recipients Placed at
userForgejoTokenFile the raw Forgejo API token of the human account hypervisor host keys only /home/<user>/.config/git/forgejo-token, mode 0600
siteHostingConfigFile one complete rclone stanza: [shared], type = ftp, host, user, pass in rclone's obscured form, explicit_tls = true hypervisor host keys only /home/<user>/.config/rclone/rclone.conf, mode 0600

The rclone stanza is stored whole, not as a bare password, because rclone reads its config file and nothing else, and storing exactly what it reads means no activation step reshapes a secret. Obscuring is reversible by anyone with rclone, so the stanza is as sensitive as the password; that is why the recipient set is the host alone.

Each non-null file needs a credentials.nix entry with a consumer { type = "agenix"; repo = "secrets"; secret = "secrets/<name>.age"; } and a secrets.nix recipient line, as the existing entries show; credential-inventory refuses an age file with no record and a record with no file. The template itself commits nothing new: with both fields null there is no ciphertext to carry, synthetic or otherwise.

Scope

In: the two fields, the README rows and consumer notes, and a line in the layout section for the two paths.

Out: declaring the secrets (allod/archetypes#74), the deploy command's own docs (allod/nexus#44), and rotation tooling (allod/nexus#42).

Let a deployment name, through the identity contract, the two age files a host user's tools read — the human's forge API token and the site hosting rclone config — so the framework can place them instead of each deployment writing its own module. Part of allod/strategy#51. Primary goals: - **Two fields on `nexusIdentity`** — `userForgejoTokenFile` and `siteHostingConfigFile`, both `null` in this template beside the existing `forgeTokenFile = null` (`flake.nix:84-89`). A deployment sets them to `"${self}/secrets/<name>.age"`, the same spelling the dev-VM token fields use. - **The shape is documented, not guessed** — what each file decrypts to, who its recipients are, and what its `credentials.nix` record looks like, so a fork can produce a valid one without reading the consumer. - **Older consumers keep evaluating** — the framework reads these with `or null`, so this can land first and nothing downstream breaks in either order. ### Current state and specifics `nexusIdentity` today: username, hostname, forge coordinates, host SSH public keys, `forgeTokenFile = null`. The README's exported-outputs table describes it at `README.md:56`, and "How `archetypes` consumes it" at `README.md:169-176` lists what the framework reads from it; both gain the two fields. Shape to document: | Field | Decrypts to | Recipients | Placed at | | --- | --- | --- | --- | | `userForgejoTokenFile` | the raw Forgejo API token of the human account | hypervisor host keys only | `/home/<user>/.config/git/forgejo-token`, mode 0600 | | `siteHostingConfigFile` | one complete rclone stanza: `[shared]`, `type = ftp`, `host`, `user`, `pass` in rclone's obscured form, `explicit_tls = true` | hypervisor host keys only | `/home/<user>/.config/rclone/rclone.conf`, mode 0600 | The rclone stanza is stored whole, not as a bare password, because rclone reads its config file and nothing else, and storing exactly what it reads means no activation step reshapes a secret. Obscuring is reversible by anyone with rclone, so the stanza is as sensitive as the password; that is why the recipient set is the host alone. Each non-null file needs a `credentials.nix` entry with a consumer `{ type = "agenix"; repo = "secrets"; secret = "secrets/<name>.age"; }` and a `secrets.nix` recipient line, as the existing entries show; `credential-inventory` refuses an age file with no record and a record with no file. The template itself commits nothing new: with both fields null there is no ciphertext to carry, synthetic or otherwise. ### Scope In: the two fields, the README rows and consumer notes, and a line in the layout section for the two paths. Out: declaring the secrets (allod/archetypes#74), the deploy command's own docs (allod/nexus#44), and rotation tooling (allod/nexus#42).
vnprc closed this issue 2026-09-10 16:43:22 +01:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
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/secrets#17
No description provided.