The forge mints its own API token with the admin account the vault delivers

The runtime beside the forge served 0 tools: GiteaClient.fromEnv required a token
(settings or MESH_GITEA_TOKEN), nobody had one to give — the mesh raised the forge —
and putting one in settings would store a secret in plaintext in the inventory. So
the fifteen tools registered nothing and the watcher logged "not watching".

What the mesh does deliver is the admin account: a login the manifest names and a
password the vault minted and the host unsealed into a file (ADR 0086). That is
enough to mint a token, so the module does (hq issue 100, the forge's tools):
POST /users/{admin}/tokens over basic auth, scoped to write:repository and
write:issue — the least the tools and the repo watcher need — kept at 0600 in the
module's own state (/var/lib/mesh/gitea/state, a new directory resource the runtime
mounts writable), read back on the next start, and minted afresh when the forge
answers 401 to it or the kept file is gone. A forge whose data came from the
predecessor has no mesh-admin: that is reported in plain words on every poll until
it clears, once per reason, not crash-looped. A configured token still wins and is
never minted over.

The mint happens on the first call, not at registration: a contributor is
synchronous, and a forge not yet answering must not keep the runtime from serving.
One source per kept file in a process, or the watcher and the tools would each
renew on a 401 and drop the other's token by name.
This commit is contained in:
2026-09-23 23:48:36 +02:00
parent 9f2c678355
commit ed094031fd
9 changed files with 625 additions and 28 deletions
+9 -1
View File
@@ -71,6 +71,12 @@
"path": "/var/lib/mesh/gitea",
"mode": "0700"
},
{
"id": "runtime-state",
"type": "directory",
"path": "/var/lib/mesh/gitea/state",
"mode": "0700"
},
{
"id": "state",
"type": "directory",
@@ -161,7 +167,8 @@
"/var/lib/mesh/gitea/broker:/run/secrets/broker:ro",
"/var/lib/mesh/gitea/config.json:/run/config/config.json:ro",
"/var/lib/gitea/grants:/var/lib/gitea/grants:ro",
"/var/lib/gitea/admin.secret:/run/secrets/admin:ro"
"/var/lib/gitea/admin.secret:/run/secrets/admin:ro",
"/var/lib/mesh/gitea/state:/run/state"
],
"env": {
"MESH_BROKER_FILE": "/run/secrets/broker",
@@ -169,6 +176,7 @@
"MESH_GITEA_CONFIG_FILE": "/run/config/config.json",
"MESH_GITEA_ADMIN_USER": "mesh-admin",
"MESH_GITEA_ADMIN_PASSWORD_FILE": "/run/secrets/admin",
"MESH_GITEA_STATE_DIR": "/run/state",
"MESH_RECEIVES": "/var/lib/gitea/grants/mesh.json"
},
"artifact": "runtime",