fix: fix: hire-an-agent fails — unbound user_pass, admin auth, silent repo creation failure, unauthenticated clone (#184)
All checks were successful
ci/woodpecker/push/ci Pipeline was successful
ci/woodpecker/pr/ci Pipeline was successful
ci/woodpecker/pr/smoke-init Pipeline was successful

This commit is contained in:
Agent 2026-04-03 12:26:20 +00:00
parent 3ca62fa96d
commit 0b0e8f8608

View file

@ -2634,38 +2634,54 @@ disinto_hire_an_agent() {
echo "Step 1: Creating user '${agent_name}' (if not exists)..."
local user_exists=false
local user_pass=""
local admin_pass=""
# Read admin password from .env for standalone runs (#184)
local env_file="${FACTORY_ROOT}/.env"
if [ -f "$env_file" ] && grep -q '^FORGE_ADMIN_PASS=' "$env_file" 2>/dev/null; then
admin_pass=$(grep '^FORGE_ADMIN_PASS=' "$env_file" | head -1 | cut -d= -f2-)
fi
# Get admin token early (needed for both user creation and password reset)
local admin_user="disinto-admin"
admin_pass="${admin_pass:-admin}"
local admin_token=""
admin_token=$(curl -sf -X POST \
-u "${admin_user}:${admin_pass}" \
-H "Content-Type: application/json" \
"${forge_url}/api/v1/users/${admin_user}/tokens" \
-d '{"name":"temp-token","scopes":["all"]}' 2>/dev/null \
| jq -r '.sha1 // empty') || admin_token=""
if [ -z "$admin_token" ]; then
admin_token=$(curl -sf \
-u "${admin_user}:${admin_pass}" \
"${forge_url}/api/v1/users/${admin_user}/tokens" 2>/dev/null \
| jq -r '.[0].sha1 // empty') || admin_token=""
fi
if [ -z "$admin_token" ]; then
echo " Warning: could not obtain admin token, trying FORGE_TOKEN..."
admin_token="${FORGE_TOKEN}"
fi
if curl -sf --max-time 5 "${forge_url}/api/v1/users/${agent_name}" >/dev/null 2>&1; then
user_exists=true
echo " User '${agent_name}' already exists"
else
# Create user using admin token
local admin_user="disinto-admin"
local admin_pass="${_FORGE_ADMIN_PASS:-admin}"
# Try to get admin token first
local admin_token
admin_token=$(curl -sf -X POST \
-u "${admin_user}:${admin_pass}" \
# Reset user password so we can get a token (#184)
user_pass="agent-$(head -c 16 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | head -c 20)"
if curl -sf -X PATCH \
-H "Authorization: token ${admin_token}" \
-H "Content-Type: application/json" \
"${forge_url}/api/v1/users/${admin_user}/tokens" \
-d '{"name":"temp-token","scopes":["all"]}' 2>/dev/null \
| jq -r '.sha1 // empty') || admin_token=""
if [ -z "$admin_token" ]; then
# Token might already exist — try listing
admin_token=$(curl -sf \
-u "${admin_user}:${admin_pass}" \
"${forge_url}/api/v1/users/${admin_user}/tokens" 2>/dev/null \
| jq -r '.[0].sha1 // empty') || admin_token=""
"${forge_url}/api/v1/admin/users/${agent_name}" \
-d "{\"password\":\"${user_pass}\"}" >/dev/null 2>&1; then
echo " Reset password for existing user '${agent_name}'"
else
echo " Warning: could not reset password for existing user" >&2
fi
if [ -z "$admin_token" ]; then
echo " Warning: could not obtain admin token, trying FORGE_TOKEN..."
admin_token="${FORGE_TOKEN}"
fi
else
# Create user using admin token (admin_token already obtained above)
# Create the user
local user_pass="agent-$(head -c 16 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | head -c 20)"
user_pass="agent-$(head -c 16 /dev/urandom | base64 | tr -dc 'a-zA-Z0-9' | head -c 20)"
if curl -sf -X POST \
-H "Authorization: token ${admin_token}" \
-H "Content-Type: application/json" \
@ -2695,24 +2711,21 @@ disinto_hire_an_agent() {
echo " Repo '${agent_name}/.profile' already exists"
else
# Get user token for creating repo
# Always try to get token using user_pass (set in Step 1 for new users, reset for existing)
local user_token=""
if [ "$user_exists" = true ]; then
# Try to get token for the new user
# Note: user_pass was set in Step 1; for existing users this will fail (unknown password)
user_token=$(curl -sf -X POST \
-u "${agent_name}:${user_pass}" \
-H "Content-Type: application/json" \
"${forge_url}/api/v1/users/${agent_name}/tokens" \
-d "{\"name\":\".profile-repo-token\",\"scopes\":[\"repository\"]}" 2>/dev/null \
| jq -r '.sha1 // empty') || user_token=""
user_token=$(curl -sf -X POST \
-u "${agent_name}:${user_pass}" \
-H "Content-Type: application/json" \
"${forge_url}/api/v1/users/${agent_name}/tokens" \
-d "{\"name\":\".profile-repo-token\",\"scopes\":[\"repository\"]}" 2>/dev/null \
| jq -r '.sha1 // empty') || user_token=""
if [ -z "$user_token" ]; then
# Try listing existing tokens
user_token=$(curl -sf \
-u "${agent_name}:${user_pass}" \
"${forge_url}/api/v1/users/${agent_name}/tokens" 2>/dev/null \
| jq -r '.[0].sha1 // empty') || user_token=""
fi
if [ -z "$user_token" ]; then
# Try listing existing tokens
user_token=$(curl -sf \
-u "${agent_name}:${user_pass}" \
"${forge_url}/api/v1/users/${agent_name}/tokens" 2>/dev/null \
| jq -r '.[0].sha1 // empty') || user_token=""
fi
# Fall back to admin token if user token not available
@ -2721,26 +2734,45 @@ disinto_hire_an_agent() {
user_token="${admin_token:-${FORGE_TOKEN}}"
fi
# Create the repo
if curl -sf -X POST \
-H "Authorization: token ${user_token}" \
-H "Content-Type: application/json" \
"${forge_url}/api/v1/user/repos" \
-d "{\"name\":\".profile\",\"description\":\"${agent_name}'s .profile repo\",\"private\":true,\"auto_init\":false}" >/dev/null 2>&1; then
echo " Created repo '${agent_name}/.profile'"
else
# Try with org path
if curl -sf -X POST \
# Create the repo using the user's namespace (user/repos with user_token creates in that user's namespace)
# or use admin API to create in specific user's namespace
local repo_created=false
local create_output
if [ -n "$user_token" ]; then
# Try creating as the agent user (user token creates in that user's namespace)
create_output=$(curl -sf -X POST \
-H "Authorization: token ${user_token}" \
-H "Content-Type: application/json" \
"${forge_url}/api/v1/orgs/${agent_name}/repos" \
-d "{\"name\":\".profile\",\"description\":\"${agent_name}'s .profile repo\",\"private\":true,\"auto_init\":false}" >/dev/null 2>&1; then
echo " Created repo '${agent_name}/.profile' (in org)"
else
echo " Error: failed to create repo '${agent_name}/.profile'" >&2
exit 1
"${forge_url}/api/v1/user/repos" \
-d "{\"name\":\".profile\",\"description\":\"${agent_name}'s .profile repo\",\"private\":true,\"auto_init\":false}" 2>&1) || true
if echo "$create_output" | grep -q '"id":\|[0-9]'; then
repo_created=true
echo " Created repo '${agent_name}/.profile'"
fi
fi
# If user token failed or wasn't available, use admin API to create in agent's namespace
if [ "$repo_created" = false ]; then
echo " Using admin API to create repo in ${agent_name}'s namespace"
create_output=$(curl -sf -X POST \
-H "Authorization: token ${user_token}" \
-H "Content-Type: application/json" \
"${forge_url}/api/v1/admin/users/${agent_name}/repos" \
-d "{\"name\":\".profile\",\"description\":\"${agent_name}'s .profile repo\",\"private\":true,\"auto_init\":false}" 2>&1) || true
if echo "$create_output" | grep -q '"id":\|[0-9]'; then
repo_created=true
echo " Created repo '${agent_name}/.profile' (via admin API)"
fi
fi
if [ "$repo_created" = false ]; then
echo " Error: failed to create repo '${agent_name}/.profile'" >&2
echo " Response: ${create_output}" >&2
exit 1
fi
fi
# Step 3: Clone repo and create initial commit
@ -2751,23 +2783,28 @@ disinto_hire_an_agent() {
rm -rf "$clone_dir"
mkdir -p "$clone_dir"
# Build clone URL (unauthenticated version for display)
# Build authenticated clone URL
# Use user_token if available, otherwise fall back to FORGE_TOKEN
local clone_token="${user_token:-${FORGE_TOKEN}}"
if [ -z "$clone_token" ]; then
echo " Error: no authentication token available for cloning" >&2
exit 1
fi
local clone_url="${forge_url}/${agent_name}/.profile.git"
local auth_url
auth_url=$(printf '%s' "$forge_url" | sed "s|://|://${agent_name}:${user_token:-${FORGE_TOKEN}}@|")
clone_url="${auth_url}/.profile.git"
auth_url=$(printf '%s' "$forge_url" | sed "s|://|://${agent_name}:${clone_token}@|")
auth_url="${auth_url}/.profile.git"
# Display unauthenticated URL (auth token only in actual git clone command)
echo " Cloning: ${forge_url}/${agent_name}/.profile.git"
if ! git clone --quiet "$clone_url" "$clone_dir" 2>/dev/null; then
# Try without auth (might work for public repos or with FORGE_TOKEN)
clone_url="${forge_url}/${agent_name}/.profile.git"
if ! git clone --quiet "$clone_url" "$clone_dir" 2>/dev/null; then
echo " Error: failed to clone repo" >&2
rm -rf "$clone_dir"
exit 1
fi
# Try authenticated clone first (required for private repos)
if ! git clone --quiet "$auth_url" "$clone_dir" 2>/dev/null; then
echo " Error: failed to clone repo with authentication" >&2
echo " Note: Ensure the user has a valid API token with repository access" >&2
rm -rf "$clone_dir"
exit 1
fi
# Configure git