From daf9151b9a7520dc23c10dba4674252fa6e73990 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 7 Apr 2026 16:48:43 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20fix:=20Forgejo=20API=20tokens=20rejected?= =?UTF-8?q?=20for=20git=20HTTP=20push=20=E2=80=94=20agents=20must=20use=20?= =?UTF-8?q?password=20auth=20(#361)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Forgejo 11.x rejects API tokens for git HTTP push while accepting them for all other operations. Store bot passwords alongside tokens during init and use password auth for git operations consistently. - forge-setup.sh: persist bot passwords to .env (FORGE_PASS, etc.) - forge-push.sh: use FORGE_PASS instead of FORGE_TOKEN for git remote URL - entrypoint.sh: configure git credential helper with password auth - entrypoint-llama.sh: use FORGE_PASS for git clone (fallback to FORGE_TOKEN) Co-Authored-By: Claude Opus 4.6 (1M context) --- docker/agents/entrypoint-llama.sh | 3 ++- docker/agents/entrypoint.sh | 32 +++++++++++++++++++++++++++++++ lib/forge-push.sh | 13 ++++++++----- lib/forge-setup.sh | 26 ++++++++++++++++++++++++- 4 files changed, 67 insertions(+), 7 deletions(-) diff --git a/docker/agents/entrypoint-llama.sh b/docker/agents/entrypoint-llama.sh index c142aad..fa2c6ed 100755 --- a/docker/agents/entrypoint-llama.sh +++ b/docker/agents/entrypoint-llama.sh @@ -24,7 +24,8 @@ if [ ! -d "${PROJECT_REPO_ROOT}/.git" ]; then log "Cloning repo..." mkdir -p "$(dirname "$PROJECT_REPO_ROOT")" chown -R agent:agent /home/agent/repos 2>/dev/null || true - su -s /bin/bash agent -c "git clone http://dev-bot:${FORGE_TOKEN}@forgejo:3000/${FORGE_REPO:-disinto-admin/disinto}.git ${PROJECT_REPO_ROOT}" + # Use password auth for git HTTP — Forgejo 11.x rejects API tokens for push (#361) + su -s /bin/bash agent -c "git clone http://dev-bot:${FORGE_PASS:-${FORGE_TOKEN}}@forgejo:3000/${FORGE_REPO:-disinto-admin/disinto}.git ${PROJECT_REPO_ROOT}" log "Repo cloned" fi diff --git a/docker/agents/entrypoint.sh b/docker/agents/entrypoint.sh index 7f3cbac..9d336aa 100644 --- a/docker/agents/entrypoint.sh +++ b/docker/agents/entrypoint.sh @@ -100,6 +100,38 @@ fi install_project_crons +# Configure git credential helper for password-based HTTP auth. +# Forgejo 11.x rejects API tokens for git push (#361); password auth works. +# This ensures all git operations (clone, fetch, push) from worktrees use +# password auth without needing tokens embedded in remote URLs. +if [ -n "${FORGE_PASS:-}" ] && [ -n "${FORGE_URL:-}" ]; then + _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) + _bot_user=$(curl -sf -H "Authorization: token ${FORGE_TOKEN}" \ + "${FORGE_URL}/api/v1/user" 2>/dev/null | jq -r '.login // empty') || _bot_user="" + _bot_user="${_bot_user:-dev-bot}" + + # Write a static credential helper script (git credential protocol) + cat > /home/agent/.git-credentials-helper </dev/null +echo "protocol=${_forge_proto}" +echo "host=${_forge_host}" +echo "username=${_bot_user}" +echo "password=${FORGE_PASS}" +CREDEOF + chmod 755 /home/agent/.git-credentials-helper + chown agent:agent /home/agent/.git-credentials-helper + + su -s /bin/bash agent -c "git config --global credential.helper '/home/agent/.git-credentials-helper'" + log "Git credential helper configured for ${_bot_user}@${_forge_host} (password auth)" +fi + # Configure tea CLI login for forge operations (runs as agent user). # tea stores config in ~/.config/tea/ — persistent across container restarts # only if that directory is on a mounted volume. diff --git a/lib/forge-push.sh b/lib/forge-push.sh index dba6e42..1da61f7 100644 --- a/lib/forge-push.sh +++ b/lib/forge-push.sh @@ -6,7 +6,8 @@ # # Globals expected: # FORGE_URL - Forge instance URL (e.g. http://localhost:3000) -# FORGE_TOKEN - API token for Forge operations +# FORGE_TOKEN - API token for Forge operations (used for API verification) +# FORGE_PASS - Bot password for git HTTP push (#361: tokens rejected by Forgejo 11.x) # FACTORY_ROOT - Root of the disinto factory # PRIMARY_BRANCH - Primary branch name (e.g. main) # @@ -20,6 +21,7 @@ set -euo pipefail _assert_forge_push_globals() { local missing=() [ -z "${FORGE_URL:-}" ] && missing+=("FORGE_URL") + [ -z "${FORGE_PASS:-}" ] && missing+=("FORGE_PASS") [ -z "${FORGE_TOKEN:-}" ] && missing+=("FORGE_TOKEN") [ -z "${FACTORY_ROOT:-}" ] && missing+=("FACTORY_ROOT") [ -z "${PRIMARY_BRANCH:-}" ] && missing+=("PRIMARY_BRANCH") @@ -33,13 +35,14 @@ _assert_forge_push_globals() { push_to_forge() { local repo_root="$1" forge_url="$2" repo_slug="$3" - # Build authenticated remote URL: http://dev-bot:@host:port/org/repo.git - if [ -z "${FORGE_TOKEN:-}" ]; then - echo "Error: FORGE_TOKEN not set — cannot push to Forgejo" >&2 + # Build authenticated remote URL: http://dev-bot:@host:port/org/repo.git + # Forgejo 11.x rejects API tokens for git HTTP push (#361); password auth works. + if [ -z "${FORGE_PASS:-}" ]; then + echo "Error: FORGE_PASS not set — cannot push to Forgejo (see #361)" >&2 return 1 fi local auth_url - auth_url=$(printf '%s' "$forge_url" | sed "s|://|://dev-bot:${FORGE_TOKEN}@|") + auth_url=$(printf '%s' "$forge_url" | sed "s|://|://dev-bot:${FORGE_PASS}@|") local remote_url="${auth_url}/${repo_slug}.git" # Display URL without token local display_url="${forge_url}/${repo_slug}.git" diff --git a/lib/forge-setup.sh b/lib/forge-setup.sh index 7e75434..40909c0 100644 --- a/lib/forge-setup.sh +++ b/lib/forge-setup.sh @@ -294,8 +294,21 @@ setup_forge() { [predictor-bot]="FORGE_PREDICTOR_TOKEN" [architect-bot]="FORGE_ARCHITECT_TOKEN" ) + # Map: bot-username -> env-var-name for the password + # Forgejo 11.x API tokens don't work for git HTTP push (#361). + # Store passwords so agents can use password auth for git operations. + local -A bot_pass_vars=( + [dev-bot]="FORGE_PASS" + [review-bot]="FORGE_REVIEW_PASS" + [planner-bot]="FORGE_PLANNER_PASS" + [gardener-bot]="FORGE_GARDENER_PASS" + [vault-bot]="FORGE_VAULT_PASS" + [supervisor-bot]="FORGE_SUPERVISOR_PASS" + [predictor-bot]="FORGE_PREDICTOR_PASS" + [architect-bot]="FORGE_ARCHITECT_PASS" + ) - local bot_user bot_pass token token_var + local bot_user bot_pass token token_var pass_var for bot_user in dev-bot review-bot planner-bot gardener-bot vault-bot supervisor-bot predictor-bot architect-bot; do bot_pass="bot-$(head -c 16 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | head -c 20)" @@ -389,6 +402,17 @@ setup_forge() { export "${token_var}=${token}" echo " ${bot_user} token generated and saved (${token_var})" + # Store password in .env for git HTTP push (#361) + # Forgejo 11.x API tokens don't work for git push; password auth does. + pass_var="${bot_pass_vars[$bot_user]}" + if grep -q "^${pass_var}=" "$env_file" 2>/dev/null; then + sed -i "s|^${pass_var}=.*|${pass_var}=${bot_pass}|" "$env_file" + else + printf '%s=%s\n' "$pass_var" "$bot_pass" >> "$env_file" + fi + export "${pass_var}=${bot_pass}" + echo " ${bot_user} password saved (${pass_var})" + # Backwards-compat aliases for dev-bot and review-bot if [ "$bot_user" = "dev-bot" ]; then export CODEBERG_TOKEN="$token"