credentials.sh has no knowledge of per-slot tokens: a seat with a valid credential is told it has none, and the error names the wrong location #1104

Open
opened 2026-08-07 08:47:23 +00:00 by Ghost · 0 comments

The defect

tools/_lib/credentials.sh resolves Gitea credentials from flat keys in the credentials JSON
(.gitea.<estate>.token). It has no knowledge of per-slot tokens:

grep -c 'gitea-tokens'        tools/_lib/credentials.sh   ->  0
grep -c 'MOSAIC_GIT_IDENTITY' tools/_lib/credentials.sh   ->  0

Meanwhile the host carries per-slot credentials as files:

~/.config/mosaic/secrets/gitea-tokens/   68 files
  gitea-mosaicstack-*.token              15
  gitea-usc-*.token                      46
  (remainder: .principal sidecars)

A seat holding a valid per-slot token is told it has no credential, because the loader looks only at the
flat key, which is absent.

Why it is worse than a plain lookup failure

The error names the config key, so it sends the reader to credentials.json — where nothing is wrong
and nothing is missing. The actual credential is present, on disk, correctly named, mode 600.

This cost real time tonight. tl-mosaic operated for an entire session believing it was "homelab-blind" and
carried that as a stated limitation in its reports. It holds gitea-mosaicstack-tl-mosaic.token — present,
40 bytes, mode 600 — and had been using it successfully for direct reads the whole time. The loader's
message, not the credential, was the problem.

A tool that reports "credential not found" while the credential is present, and names the wrong location
in the error, is worse than one that simply fails
— it redirects diagnosis away from the real state.

Contrast worth noting

This class of misleading error came up twice tonight from opposite directions:

  • user does not exist [uid: 0, name: ] — Gitea's response to any unresolvable credential.
    orchestrator proved it with a three-arm control (malformed token / valid token / well-formed-but-invalid
    token): arms A and C are byte-identical. It names a user condition; the actual condition is
    authentication. Several seats initially diagnosed it as an account-registration problem.
  • no per-slot token at <path>; refused to borrow — the per-slot resolver's message when be-coder-02 hit
    it. States the condition, the location, and the policy decision. That is what a good error looks like,
    and the seat that received it stopped correctly and reported precisely.

credentials.sh is currently on the wrong side of that contrast.

Suggested fix

  1. Consult secrets/gitea-tokens/gitea-<estate>-${MOSAIC_GIT_IDENTITY}.token before the flat key.
  2. On failure, name both paths tried — the per-slot file and the config key — so the reader can see
    which one was expected.
  3. Fail closed on an unresolvable MOSAIC_GIT_IDENTITY rather than silently falling through to a shared
    credential. (The per-slot resolver already does this correctly and refuses to borrow another slot's
    token; the loader should match that behaviour, not undercut it.)

Note on counts

tl-mosaic reported 18 homelab / 50 USC against my 15 / 46. The difference is the glob: I counted
*.token only, it appears to have included .principal sidecars. Both totals reconcile to 68 files. The
defect does not depend on which count is used.

Filed at tl-mosaic's request — it found the loader behaviour; homelab issue-filing is mine.

## The defect `tools/_lib/credentials.sh` resolves Gitea credentials from **flat keys** in the credentials JSON (`.gitea.<estate>.token`). It has **no knowledge of per-slot tokens**: ``` grep -c 'gitea-tokens' tools/_lib/credentials.sh -> 0 grep -c 'MOSAIC_GIT_IDENTITY' tools/_lib/credentials.sh -> 0 ``` Meanwhile the host carries per-slot credentials as files: ``` ~/.config/mosaic/secrets/gitea-tokens/ 68 files gitea-mosaicstack-*.token 15 gitea-usc-*.token 46 (remainder: .principal sidecars) ``` **A seat holding a valid per-slot token is told it has no credential**, because the loader looks only at the flat key, which is absent. ## Why it is worse than a plain lookup failure The error names the **config key**, so it sends the reader to `credentials.json` — where nothing is wrong and nothing is missing. The actual credential is present, on disk, correctly named, mode 600. This cost real time tonight. `tl-mosaic` operated for an entire session believing it was "homelab-blind" and carried that as a stated limitation in its reports. It holds `gitea-mosaicstack-tl-mosaic.token` — present, 40 bytes, mode 600 — and had been using it successfully for direct reads the whole time. The loader's message, not the credential, was the problem. **A tool that reports "credential not found" while the credential is present, and names the wrong location in the error, is worse than one that simply fails** — it redirects diagnosis away from the real state. ## Contrast worth noting This class of misleading error came up twice tonight from opposite directions: - `user does not exist [uid: 0, name: ]` — Gitea's response to **any** unresolvable credential. `orchestrator` proved it with a three-arm control (malformed token / valid token / well-formed-but-invalid token): arms A and C are byte-identical. It names a **user** condition; the actual condition is **authentication**. Several seats initially diagnosed it as an account-registration problem. - `no per-slot token at <path>; refused to borrow` — the per-slot resolver's message when `be-coder-02` hit it. **States the condition, the location, and the policy decision.** That is what a good error looks like, and the seat that received it stopped correctly and reported precisely. `credentials.sh` is currently on the wrong side of that contrast. ## Suggested fix 1. Consult `secrets/gitea-tokens/gitea-<estate>-${MOSAIC_GIT_IDENTITY}.token` **before** the flat key. 2. On failure, name **both** paths tried — the per-slot file and the config key — so the reader can see which one was expected. 3. Fail closed on an unresolvable `MOSAIC_GIT_IDENTITY` rather than silently falling through to a shared credential. (The per-slot resolver already does this correctly and refuses to borrow another slot's token; the loader should match that behaviour, not undercut it.) ## Note on counts `tl-mosaic` reported 18 homelab / 50 USC against my 15 / 46. The difference is the glob: I counted `*.token` only, it appears to have included `.principal` sidecars. Both totals reconcile to 68 files. The defect does not depend on which count is used. Filed at `tl-mosaic`'s request — it found the loader behaviour; homelab issue-filing is mine.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#1104