Merge pull request 'fix: bug: setup_forge's admin_token is a local variable, not exported — setup_ops_repo falls back to dev-bot token and fails with 403 (#583)' (#617) from fix/issue-583 into main
All checks were successful
ci/woodpecker/push/ci Pipeline was successful

This commit is contained in:
dev-qwen 2026-04-10 14:14:35 +00:00
commit 6b858c9c43
3 changed files with 35 additions and 36 deletions

View file

@ -685,7 +685,7 @@ p.write_text(text)
# the calling user (e.g. johba) but the ops repo belongs to disinto-admin. # the calling user (e.g. johba) but the ops repo belongs to disinto-admin.
local ops_slug="disinto-admin/${project_name}-ops" local ops_slug="disinto-admin/${project_name}-ops"
local ops_root="/home/${USER}/${project_name}-ops" local ops_root="/home/${USER}/${project_name}-ops"
setup_ops_repo "$forge_url" "$ops_slug" "$ops_root" "$branch" setup_ops_repo "$forge_url" "$ops_slug" "$ops_root" "$branch" "${HUMAN_TOKEN:-}"
# Migrate ops repo to canonical structure (seed missing directories/files) # Migrate ops repo to canonical structure (seed missing directories/files)
# This brings pre-#407 deployments up to date with the canonical structure # This brings pre-#407 deployments up to date with the canonical structure

View file

@ -247,8 +247,7 @@ setup_forge() {
fi fi
# Get or create human user token # Get or create human user token
local human_token local human_token=""
if curl -sf --max-time 5 -H "Authorization: token ${admin_token}" "${forge_url}/api/v1/users/${human_user}" >/dev/null 2>&1; then
# Delete existing human token if present (token sha1 is only returned at creation time) # Delete existing human token if present (token sha1 is only returned at creation time)
local existing_human_token_id local existing_human_token_id
existing_human_token_id=$(curl -sf \ existing_human_token_id=$(curl -sf \
@ -279,7 +278,6 @@ setup_forge() {
export HUMAN_TOKEN="$human_token" export HUMAN_TOKEN="$human_token"
echo " Human token saved (HUMAN_TOKEN)" echo " Human token saved (HUMAN_TOKEN)"
fi fi
fi
# Create bot users and tokens # Create bot users and tokens
# Each agent gets its own Forgejo account for identity and audit trail (#747). # Each agent gets its own Forgejo account for identity and audit trail (#747).

View file

@ -5,10 +5,10 @@
# source "$(dirname "$0")/../lib/ops-setup.sh" # source "$(dirname "$0")/../lib/ops-setup.sh"
# #
# Required globals: FORGE_URL, FORGE_TOKEN, FACTORY_ROOT # Required globals: FORGE_URL, FORGE_TOKEN, FACTORY_ROOT
# Optional: admin_token (falls back to FORGE_TOKEN for admin operations) # Optional: HUMAN_TOKEN (falls back to FORGE_TOKEN for admin operations)
# #
# Functions: # Functions:
# setup_ops_repo <forge_url> <ops_slug> <ops_root> [primary_branch] # setup_ops_repo <forge_url> <ops_slug> <ops_root> [primary_branch] [admin_token]
# - Create ops repo on Forgejo if it doesn't exist # - Create ops repo on Forgejo if it doesn't exist
# - Configure bot collaborators with appropriate permissions # - Configure bot collaborators with appropriate permissions
# - Clone or initialize ops repo locally # - Clone or initialize ops repo locally
@ -26,6 +26,7 @@ set -euo pipefail
setup_ops_repo() { setup_ops_repo() {
local forge_url="$1" ops_slug="$2" ops_root="$3" primary_branch="${4:-main}" local forge_url="$1" ops_slug="$2" ops_root="$3" primary_branch="${4:-main}"
local admin_token="${5:-${HUMAN_TOKEN:-${FORGE_TOKEN}}}"
local org_name="${ops_slug%%/*}" local org_name="${ops_slug%%/*}"
local ops_name="${ops_slug##*/}" local ops_name="${ops_slug##*/}"
@ -55,12 +56,12 @@ setup_ops_repo() {
echo "Creating ops repo in namespace: ${org_name}" echo "Creating ops repo in namespace: ${org_name}"
# Create org if it doesn't exist # Create org if it doesn't exist
curl -sf -X POST \ curl -sf -X POST \
-H "Authorization: token ${admin_token:-${FORGE_TOKEN}}" \ -H "Authorization: token ${admin_token}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
"${forge_url}/api/v1/orgs" \ "${forge_url}/api/v1/orgs" \
-d "{\"username\":\"${org_name}\",\"visibility\":\"public\"}" >/dev/null 2>&1 || true -d "{\"username\":\"${org_name}\",\"visibility\":\"public\"}" >/dev/null 2>&1 || true
if curl -sf -X POST \ if curl -sf -X POST \
-H "Authorization: token ${admin_token:-${FORGE_TOKEN}}" \ -H "Authorization: token ${admin_token}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
"${forge_url}/api/v1/orgs/${org_name}/repos" \ "${forge_url}/api/v1/orgs/${org_name}/repos" \
-d "{\"name\":\"${ops_name}\",\"auto_init\":true,\"default_branch\":\"${primary_branch}\",\"description\":\"Operational data for ${org_name}/${ops_name%-ops}\"}" >/dev/null 2>&1; then -d "{\"name\":\"${ops_name}\",\"auto_init\":true,\"default_branch\":\"${primary_branch}\",\"description\":\"Operational data for ${org_name}/${ops_name%-ops}\"}" >/dev/null 2>&1; then
@ -70,7 +71,7 @@ setup_ops_repo() {
# Fallback: use admin API to create repo under the target namespace # Fallback: use admin API to create repo under the target namespace
http_code=$(curl -s -o /dev/null -w "%{http_code}" \ http_code=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST \ -X POST \
-H "Authorization: token ${admin_token:-${FORGE_TOKEN}}" \ -H "Authorization: token ${admin_token}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
"${forge_url}/api/v1/admin/users/${org_name}/repos" \ "${forge_url}/api/v1/admin/users/${org_name}/repos" \
-d "{\"name\":\"${ops_name}\",\"auto_init\":true,\"default_branch\":\"${primary_branch}\",\"description\":\"Operational data for ${org_name}/${ops_name%-ops}\"}" 2>/dev/null || echo "0") -d "{\"name\":\"${ops_name}\",\"auto_init\":true,\"default_branch\":\"${primary_branch}\",\"description\":\"Operational data for ${org_name}/${ops_name%-ops}\"}" 2>/dev/null || echo "0")
@ -104,7 +105,7 @@ setup_ops_repo() {
for bot_user in "${!bot_permissions[@]}"; do for bot_user in "${!bot_permissions[@]}"; do
bot_perm="${bot_permissions[$bot_user]}" bot_perm="${bot_permissions[$bot_user]}"
if curl -sf -X PUT \ if curl -sf -X PUT \
-H "Authorization: token ${admin_token:-${FORGE_TOKEN}}" \ -H "Authorization: token ${admin_token}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
"${forge_url}/api/v1/repos/${actual_ops_slug}/collaborators/${bot_user}" \ "${forge_url}/api/v1/repos/${actual_ops_slug}/collaborators/${bot_user}" \
-d "{\"permission\":\"${bot_perm}\"}" >/dev/null 2>&1; then -d "{\"permission\":\"${bot_perm}\"}" >/dev/null 2>&1; then
@ -116,7 +117,7 @@ setup_ops_repo() {
# Add disinto-admin as admin collaborator # Add disinto-admin as admin collaborator
if curl -sf -X PUT \ if curl -sf -X PUT \
-H "Authorization: token ${admin_token:-${FORGE_TOKEN}}" \ -H "Authorization: token ${admin_token}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
"${forge_url}/api/v1/repos/${actual_ops_slug}/collaborators/disinto-admin" \ "${forge_url}/api/v1/repos/${actual_ops_slug}/collaborators/disinto-admin" \
-d '{"permission":"admin"}' >/dev/null 2>&1; then -d '{"permission":"admin"}' >/dev/null 2>&1; then