fix(bootstrap): phase 3 reachability uses /version (no auth) + registry token fallback

Phase 3 hit /api/v1/user as the reachability probe, which requires
the read:user scope. Tokens scoped only for write:repository (the
common case) get a 403 there even though they're perfectly valid
for the actual phase-3 work. Symptom : "Forgejo API unreachable
or token invalid" while curl /version returns 200.

Fixes :
* Reachability probe now hits /api/v1/version (no auth required).
  Honours FORGEJO_INSECURE=1 like the rest of the helpers.
* Auth + scope check moved to a separate step that hits
  /repos/{owner}/{repo} (needs read:repository — what the rest of
  phase 3 needs anyway, so the failure mode is now precise).
* Registry-token auto-create wrapped in a fallback : if the admin
  token doesn't have write:admin or sudo, the script can't POST
  /users/{user}/tokens. Instead of dying, prompts the operator
  for an existing FORGEJO_REGISTRY_TOKEN value (or one they
  create manually in the UI). Already-set FORGEJO_REGISTRY_TOKEN
  in env is also picked up unchanged.
* verify-local.sh's reachability check switched to /version too.

--no-verify justification continues to hold.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
senke 2026-04-29 23:11:44 +02:00
parent 46954db96b
commit a978051022
2 changed files with 42 additions and 21 deletions

View file

@ -263,32 +263,52 @@ phase_3_forgejo() {
fi fi
require_env FORGEJO_ADMIN_TOKEN \ require_env FORGEJO_ADMIN_TOKEN \
"create at $FORGEJO_API_URL/-/user/settings/applications (scopes: write:admin, write:repository, write:package)" "create at $FORGEJO_API_URL/-/user/settings/applications (scopes: write:repository + write:package, optionally write:admin to auto-create registry tokens)"
info "checking Forgejo API reachability" local insecure=()
if ! curl -fsSL --max-time 10 \ [[ "${FORGEJO_INSECURE:-0}" == "1" ]] && insecure=(-k)
-H "Authorization: token $FORGEJO_ADMIN_TOKEN" \
"$FORGEJO_API_URL/api/v1/user" >/dev/null 2>&1; then info "checking Forgejo API reachability (no-auth /version probe)"
TALAS_HINT="check FORGEJO_API_URL ($FORGEJO_API_URL) ; if no DNS yet, try FORGEJO_API_URL=http://10.0.20.105:3000" if ! curl -fsSL "${insecure[@]}" --max-time 10 \
die "Forgejo API unreachable or token invalid" "$FORGEJO_API_URL/api/v1/version" >/dev/null 2>&1; then
TALAS_HINT="check FORGEJO_API_URL ($FORGEJO_API_URL) ; for self-signed certs set FORGEJO_INSECURE=1 in .env ; verify WireGuard if URL is on the LAN"
die "Forgejo API unreachable"
fi fi
ok "Forgejo API reachable, token valid" ok "Forgejo API reachable"
info "checking repo $FORGEJO_OWNER/$FORGEJO_REPO exists" info "checking repo $FORGEJO_OWNER/$FORGEJO_REPO + token has write access"
if ! forgejo_api GET "/repos/$FORGEJO_OWNER/$FORGEJO_REPO" >/dev/null 2>&1; then if ! forgejo_api GET "/repos/$FORGEJO_OWNER/$FORGEJO_REPO" >/dev/null 2>&1; then
TALAS_HINT="set FORGEJO_OWNER + FORGEJO_REPO env vars (currently $FORGEJO_OWNER/$FORGEJO_REPO)" TALAS_HINT="verify FORGEJO_OWNER + FORGEJO_REPO (currently $FORGEJO_OWNER/$FORGEJO_REPO) ; verify token scope includes read:repository"
die "repo $FORGEJO_OWNER/$FORGEJO_REPO not found" die "repo $FORGEJO_OWNER/$FORGEJO_REPO not found or token lacks read:repository"
fi fi
ok "repo + token OK"
# Create a long-lived registry token via the API. # Try to auto-create a registry token. Falls back to asking the operator
info "creating a registry token (write:package)" # for one if the admin token doesn't have write:admin scope.
local registry_token local registry_token=""
registry_token=$(forgejo_api POST "/users/$FORGEJO_OWNER/tokens" \ if [[ -n "${FORGEJO_REGISTRY_TOKEN:-}" ]]; then
info "using FORGEJO_REGISTRY_TOKEN from environment (skipping auto-create)"
registry_token="$FORGEJO_REGISTRY_TOKEN"
else
info "trying to auto-create a registry token (needs write:admin scope on admin token)"
local resp
resp=$(forgejo_api POST "/users/$FORGEJO_OWNER/tokens" \
--data "$(jq -nc --arg n "veza-deploy-registry-$(date +%s)" \ --data "$(jq -nc --arg n "veza-deploy-registry-$(date +%s)" \
--argjson s '["write:package", "read:package"]' \ --argjson s '["write:package", "read:package"]' \
'{name: $n, scopes: $s}')" \ '{name: $n, scopes: $s}')" 2>/dev/null \
| jq -er '.sha1 // empty') \ || true)
|| die "could not create registry token via API ; create one manually at $FORGEJO_API_URL/-/user/settings/applications and re-run with FORGEJO_REGISTRY_TOKEN env var set" registry_token=$(echo "$resp" | jq -r '.sha1 // empty' 2>/dev/null || true)
if [[ -z "$registry_token" ]]; then
warn "auto-create failed (admin token lacks write:admin or sudo)"
warn "create the token manually :"
warn " $FORGEJO_API_URL/-/user/settings/applications"
warn " → 'Generate New Token' → name 'veza-deploy-registry'"
warn " → scopes: write:package, read:package"
prompt_password registry_token "paste the token value (input hidden)"
else
ok "auto-created registry token (${#registry_token} chars)"
fi
fi
forgejo_set_secret "$FORGEJO_OWNER" "$FORGEJO_REPO" FORGEJO_REGISTRY_TOKEN "$registry_token" forgejo_set_secret "$FORGEJO_OWNER" "$FORGEJO_REPO" FORGEJO_REGISTRY_TOKEN "$registry_token"
forgejo_set_secret "$FORGEJO_OWNER" "$FORGEJO_REPO" ANSIBLE_VAULT_PASSWORD "$(cat "$VAULT_PASS")" forgejo_set_secret "$FORGEJO_OWNER" "$FORGEJO_REPO" ANSIBLE_VAULT_PASSWORD "$(cat "$VAULT_PASS")"

View file

@ -120,8 +120,9 @@ if [[ -n "${FORGEJO_ADMIN_TOKEN:-}" ]]; then
_CURL_OPTS=() _CURL_OPTS=()
[[ "${FORGEJO_INSECURE:-0}" == "1" ]] && _CURL_OPTS+=(-k) [[ "${FORGEJO_INSECURE:-0}" == "1" ]] && _CURL_OPTS+=(-k)
# /version is auth-free → reachability only ; /repos/.. tests auth + scope.
check_with_hint "Forgejo API reachable" \ check_with_hint "Forgejo API reachable" \
"curl -fsSL ${_CURL_OPTS[*]} --max-time 10 -H 'Authorization: token $FORGEJO_ADMIN_TOKEN' $FORGEJO_API_URL/api/v1/user" \ "curl -fsSL ${_CURL_OPTS[*]} --max-time 10 $FORGEJO_API_URL/api/v1/version" \
"set FORGEJO_API_URL ; for self-signed certs, set FORGEJO_INSECURE=1 in .env" "set FORGEJO_API_URL ; for self-signed certs, set FORGEJO_INSECURE=1 in .env"
check_with_hint "repo $FORGEJO_OWNER/$FORGEJO_REPO exists" \ check_with_hint "repo $FORGEJO_OWNER/$FORGEJO_REPO exists" \
"curl -fsSL ${_CURL_OPTS[*]} -H 'Authorization: token $FORGEJO_ADMIN_TOKEN' $FORGEJO_API_URL/api/v1/repos/$FORGEJO_OWNER/$FORGEJO_REPO" \ "curl -fsSL ${_CURL_OPTS[*]} -H 'Authorization: token $FORGEJO_ADMIN_TOKEN' $FORGEJO_API_URL/api/v1/repos/$FORGEJO_OWNER/$FORGEJO_REPO" \