fix: make credentials.json authoritative for Woodpecker, auto-sync to .env

- Woodpecker tokens from credentials.json now always override env vars,
  preventing stale .bashrc or env leakage from silently winning
- After loading, credentials are synced to ~/.woodpecker/<instance>.env
  so the wp CLI wrapper stays current automatically
- Sync only writes when values differ to avoid unnecessary disk I/O

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jason Woltje
2026-02-24 13:03:29 -06:00
parent 98b9bc3c93
commit 8de2f7439a

View File

@@ -5,8 +5,8 @@
# Usage: source ~/.config/mosaic/tools/_lib/credentials.sh
# load_credentials <service-name>
#
# Loads credentials from environment variables first, then falls back
# to ~/src/jarvis-brain/credentials.json (or MOSAIC_CREDENTIALS_FILE).
# credentials.json is the single source of truth.
# For Woodpecker, credentials are also synced to ~/.woodpecker/<instance>.env.
#
# Supported services:
# portainer, coolify, authentik, glpi, github,
@@ -33,6 +33,24 @@ _mosaic_read_cred() {
jq -r "$jq_path // empty" "$MOSAIC_CREDENTIALS_FILE"
}
# Sync Woodpecker credentials to ~/.woodpecker/<instance>.env
# Only writes when values differ to avoid unnecessary disk writes.
_mosaic_sync_woodpecker_env() {
local instance="$1" url="$2" token="$3"
local env_file="$HOME/.woodpecker/${instance}.env"
[[ -d "$HOME/.woodpecker" ]] || return 0
local expected
expected=$(printf '# %s Woodpecker CI\nexport WOODPECKER_SERVER="%s"\nexport WOODPECKER_TOKEN="%s"\n' \
"$instance" "$url" "$token")
if [[ -f "$env_file" ]]; then
local current_url current_token
current_url=$(grep -oP '(?<=WOODPECKER_SERVER=").*(?=")' "$env_file" 2>/dev/null || true)
current_token=$(grep -oP '(?<=WOODPECKER_TOKEN=").*(?=")' "$env_file" 2>/dev/null || true)
[[ "$current_url" == "$url" && "$current_token" == "$token" ]] && return 0
fi
printf '%s\n' "$expected" > "$env_file"
}
load_credentials() {
local service="$1"
@@ -108,12 +126,15 @@ EOF
;;
woodpecker-*)
local wp_instance="${service#woodpecker-}"
export WOODPECKER_URL="${WOODPECKER_URL:-$(_mosaic_read_cred ".woodpecker.${wp_instance}.url")}"
export WOODPECKER_TOKEN="${WOODPECKER_TOKEN:-$(_mosaic_read_cred ".woodpecker.${wp_instance}.token")}"
# credentials.json is authoritative — always read from it, ignore env
export WOODPECKER_URL="$(_mosaic_read_cred ".woodpecker.${wp_instance}.url")"
export WOODPECKER_TOKEN="$(_mosaic_read_cred ".woodpecker.${wp_instance}.token")"
export WOODPECKER_INSTANCE="$wp_instance"
WOODPECKER_URL="${WOODPECKER_URL%/}"
[[ -n "$WOODPECKER_URL" ]] || { echo "Error: woodpecker.${wp_instance}.url not found" >&2; return 1; }
[[ -n "$WOODPECKER_TOKEN" ]] || { echo "Error: woodpecker.${wp_instance}.token not found" >&2; return 1; }
# Sync to ~/.woodpecker/<instance>.env so the wp CLI wrapper stays current
_mosaic_sync_woodpecker_env "$wp_instance" "$WOODPECKER_URL" "$WOODPECKER_TOKEN"
;;
woodpecker)
# Resolve default instance, then load it