fix: bug: credential helper race on every cold boot — configure_git_creds() silently falls back to wrong username when Forgejo is not yet ready (#741)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c4ca1e930d
commit
02915456ae
3 changed files with 60 additions and 12 deletions
|
|
@ -49,8 +49,10 @@ services:
|
|||
- ARCHITECT_INTERVAL=${ARCHITECT_INTERVAL:-21600}
|
||||
- PLANNER_INTERVAL=${PLANNER_INTERVAL:-43200}
|
||||
depends_on:
|
||||
- forgejo
|
||||
- woodpecker
|
||||
forgejo:
|
||||
condition: service_healthy
|
||||
woodpecker:
|
||||
condition: service_started
|
||||
networks:
|
||||
- disinto-net
|
||||
|
||||
|
|
@ -101,8 +103,10 @@ services:
|
|||
- POLL_INTERVAL=${POLL_INTERVAL:-300}
|
||||
- AGENT_ROLES=dev
|
||||
depends_on:
|
||||
- forgejo
|
||||
- woodpecker
|
||||
forgejo:
|
||||
condition: service_healthy
|
||||
woodpecker:
|
||||
condition: service_started
|
||||
networks:
|
||||
- disinto-net
|
||||
|
||||
|
|
@ -171,6 +175,12 @@ services:
|
|||
- FORGEJO__security__INSTALL_LOCK=true
|
||||
- FORGEJO__service__DISABLE_REGISTRATION=true
|
||||
- FORGEJO__webhook__ALLOWED_HOST_LIST=private
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-sf", "http://localhost:3000/api/v1/version"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 30
|
||||
start_period: 30s
|
||||
ports:
|
||||
- "3000:3000"
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ source "${DISINTO_BAKED}/lib/git-creds.sh"
|
|||
# Wrapper that calls the shared configure_git_creds with agent-specific paths,
|
||||
# then repairs any legacy baked-credential URLs in existing clones.
|
||||
_setup_git_creds() {
|
||||
configure_git_creds "/home/agent" "gosu agent"
|
||||
_GIT_CREDS_LOG_FN=log configure_git_creds "/home/agent" "gosu agent"
|
||||
if [ -n "${FORGE_PASS:-}" ] && [ -n "${FORGE_URL:-}" ]; then
|
||||
log "Git credential helper configured (password auth)"
|
||||
fi
|
||||
|
|
@ -61,16 +61,21 @@ _setup_git_creds() {
|
|||
# Configure git author identity for commits made by this container.
|
||||
# Derives identity from the resolved bot user (BOT_USER) to ensure commits
|
||||
# are visibly attributable to the correct bot in the forge timeline.
|
||||
# BOT_USER is normally set by configure_git_creds() (#741); this function
|
||||
# only falls back to its own API call if BOT_USER was not already resolved.
|
||||
configure_git_identity() {
|
||||
# Resolve BOT_USER from FORGE_TOKEN if not already set
|
||||
# Resolve BOT_USER from FORGE_TOKEN if not already set (configure_git_creds
|
||||
# exports BOT_USER on success, so this is a fallback for edge cases only).
|
||||
if [ -z "${BOT_USER:-}" ] && [ -n "${FORGE_TOKEN:-}" ]; then
|
||||
BOT_USER=$(curl -sf --max-time 10 \
|
||||
-H "Authorization: token ${FORGE_TOKEN}" \
|
||||
"${FORGE_URL:-http://localhost:3000}/api/v1/user" 2>/dev/null | jq -r '.login // empty') || true
|
||||
fi
|
||||
|
||||
# Default to dev-bot if resolution fails
|
||||
BOT_USER="${BOT_USER:-dev-bot}"
|
||||
if [ -z "${BOT_USER:-}" ]; then
|
||||
log "WARNING: Could not resolve bot username for git identity — commits will use fallback"
|
||||
BOT_USER="agent"
|
||||
fi
|
||||
|
||||
# Configure git identity for all repositories
|
||||
gosu agent git config --global user.name "${BOT_USER}"
|
||||
|
|
|
|||
|
|
@ -35,13 +35,35 @@ configure_git_creds() {
|
|||
forge_host=$(printf '%s' "$FORGE_URL" | sed 's|https\?://||; s|/.*||')
|
||||
forge_proto=$(printf '%s' "$FORGE_URL" | sed 's|://.*||')
|
||||
|
||||
# Determine the bot username from FORGE_TOKEN identity (or default to dev-bot)
|
||||
local log_fn="${_GIT_CREDS_LOG_FN:-echo}"
|
||||
|
||||
# Determine the bot username from FORGE_TOKEN identity with retry/backoff.
|
||||
# Never fall back to a hardcoded default — a wrong username paired with the
|
||||
# real password produces a cryptic 401 that's much harder to diagnose than
|
||||
# a missing credential helper (#741).
|
||||
local bot_user=""
|
||||
if [ -n "${FORGE_TOKEN:-}" ]; then
|
||||
bot_user=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \
|
||||
"${FORGE_URL}/api/v1/user" 2>/dev/null | jq -r '.login // empty') || bot_user=""
|
||||
local attempt
|
||||
for attempt in 1 2 3 4 5; do
|
||||
bot_user=$(curl -sf --max-time 5 -H "Authorization: token ${FORGE_TOKEN}" \
|
||||
"${FORGE_URL}/api/v1/user" 2>/dev/null | jq -r '.login // empty') || bot_user=""
|
||||
if [ -n "$bot_user" ]; then
|
||||
break
|
||||
fi
|
||||
$log_fn "WARNING: Forgejo not reachable (attempt ${attempt}/5) — retrying in ${attempt}s"
|
||||
sleep "$attempt"
|
||||
done
|
||||
fi
|
||||
bot_user="${bot_user:-dev-bot}"
|
||||
|
||||
if [ -z "$bot_user" ]; then
|
||||
$log_fn "ERROR: Could not determine bot username from FORGE_TOKEN after 5 attempts — credential helper NOT configured"
|
||||
$log_fn "ERROR: git push will fail until this is resolved. Restart the container after Forgejo is healthy."
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Export BOT_USER so downstream functions (e.g. configure_git_identity) can
|
||||
# reuse the resolved value without a redundant API call.
|
||||
export BOT_USER="$bot_user"
|
||||
|
||||
local helper_path="${home_dir}/.git-credentials-helper"
|
||||
|
||||
|
|
@ -77,6 +99,17 @@ CREDEOF
|
|||
else
|
||||
git config --global --add safe.directory '*'
|
||||
fi
|
||||
|
||||
# Verify the credential helper actually authenticates (#741).
|
||||
# A helper that was written with a valid username but a mismatched password
|
||||
# would silently 401 on every push — catch it now.
|
||||
if ! curl -sf --max-time 5 -u "${bot_user}:${FORGE_PASS}" \
|
||||
"${FORGE_URL}/api/v1/user" >/dev/null 2>&1; then
|
||||
$log_fn "ERROR: credential helper verification failed — ${bot_user}:FORGE_PASS rejected by Forgejo"
|
||||
rm -f "$helper_path"
|
||||
return 1
|
||||
fi
|
||||
$log_fn "Git credential helper verified: ${bot_user}@${forge_host}"
|
||||
}
|
||||
|
||||
# repair_baked_cred_urls [--as RUN_AS_CMD] DIR [DIR ...]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue