credential loader breaks under HOME-redirected profiles (Hermes profile homes) #699

Closed
opened 2026-07-09 21:44:43 +00:00 by jason.woltje · 0 comments
Owner

Problem

The shared credential loader (tools/_lib/credentials.sh) and two scripts with inline resolution (git/detect-platform.sh, health/stack-health.sh) resolve the default credentials file exclusively relative to $HOME. Under a HOME-redirected profile environment (e.g. a Hermes profile: HOME=/home/hermes/.hermes/profiles/<name>/home), the default resolves into the empty profile home and every Mosaic tool fails authentication unless the operator exports MOSAIC_CREDENTIALS_FILE per invocation.

Observed in production on the USC host (Edith profile): tea authenticated fine on both Gitea instances while every Mosaic wrapper failed, because the loader looked inside the profile home. Verified fix was a manual export MOSAIC_CREDENTIALS_FILE=... — which is exactly the per-invocation friction the loader is supposed to remove.

Fix

Add a host-level fallback candidate to the resolution chain, keeping explicit override supreme:

  1. $MOSAIC_CREDENTIALS_FILE (explicit — never second-guessed)
  2. $HOME/.config/mosaic/credentials.json
  3. /etc/mosaic/credentials.json (host-level fallback, one symlink per host)

Also export the resolved MOSAIC_CREDENTIALS_FILE so sourcing scripts and subprocesses inherit the resolution, and apply the same chain to the inline site in detect-platform.sh.

Operator-side (per affected host, one time): ln -s <canonical credentials.json> /etc/mosaic/credentials.json. Deliberately NOT hardcoding any operator-specific repo path in the framework loader (framework firewall).

## Problem The shared credential loader (`tools/_lib/credentials.sh`) and two scripts with inline resolution (`git/detect-platform.sh`, `health/stack-health.sh`) resolve the default credentials file exclusively relative to `$HOME`. Under a HOME-redirected profile environment (e.g. a Hermes profile: `HOME=/home/hermes/.hermes/profiles/<name>/home`), the default resolves into the empty profile home and every Mosaic tool fails authentication unless the operator exports `MOSAIC_CREDENTIALS_FILE` per invocation. Observed in production on the USC host (Edith profile): `tea` authenticated fine on both Gitea instances while every Mosaic wrapper failed, because the loader looked inside the profile home. Verified fix was a manual `export MOSAIC_CREDENTIALS_FILE=...` — which is exactly the per-invocation friction the loader is supposed to remove. ## Fix Add a host-level fallback candidate to the resolution chain, keeping explicit override supreme: 1. `$MOSAIC_CREDENTIALS_FILE` (explicit — never second-guessed) 2. `$HOME/.config/mosaic/credentials.json` 3. `/etc/mosaic/credentials.json` (host-level fallback, one symlink per host) Also export the resolved `MOSAIC_CREDENTIALS_FILE` so sourcing scripts and subprocesses inherit the resolution, and apply the same chain to the inline site in `detect-platform.sh`. Operator-side (per affected host, one time): `ln -s <canonical credentials.json> /etc/mosaic/credentials.json`. Deliberately NOT hardcoding any operator-specific repo path in the framework loader (framework firewall).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mosaicstack/stack#699