bug: setup_forge has ~6 other anonymous curl checks for user/repo existence, all fail with 403 on locked-down forgejos #582

Closed
opened 2026-04-10 10:02:57 +00:00 by dev-bot · 0 comments
Collaborator

Description

lib/forge-setup.sh uses unauthenticated curl calls to check whether users and repos exist before creating them. Grep for curl -sf --max-time 5 in that file surfaces at least these unauthenticated calls:

line 141: curl -sf --max-time 5 "${forge_url}/api/v1/users/${admin_user}"
line 162: curl -sf --max-time 5 "${forge_url}/api/v1/users/${admin_user}"
line 193: curl -sf --max-time 5 "${forge_url}/api/v1/users/${human_user}"
line 214: curl -sf --max-time 5 "${forge_url}/api/v1/users/${human_user}"
line 251: curl -sf --max-time 5 "${forge_url}/api/v1/users/${human_user}"
line 434: curl -sf --max-time 5 "${forge_url}/api/v1/repos/${bot_user}/.profile"

On a forgejo with FORGEJO__service__REQUIRE_SIGNIN_VIEW=true (the stock disinto compose setup), all of these return HTTP 403 regardless of whether the user/repo actually exists. Init then treats the 403 as "does not exist" and tries to create the resource. In most cases the creation call uses basic auth or a token and succeeds or safely fails, but:

  1. Admin user check (line 141): returns 403 → init tries to create disinto-admin → forgejo CLI errors with Command error: CreateUser: user already exists [name: disinto-admin] → init aborts
  2. Bot .profile check (line 434): returns 403 → init tries to create each bot's .profile repo → some succeed, some silently fail, leading to inconsistent state between runs

Reproduction

  1. Running disinto factory with REQUIRE_SIGNIN_VIEW=true
  2. Run bin/disinto init <repo-url> --yes a second time (first time created users, so they now exist)
  3. Observe: init prints "Creating admin user: disinto-admin" followed by "Error: failed to create admin user 'disinto-admin': user already exists" and exits

Environment

  • Box: harb-dev-box
  • Disinto: main (post-v0.2.0 + later merges)
  • Forgejo: codeberg.org/forgejo/forgejo:11.0, REQUIRE_SIGNIN_VIEW=true

Fix

Add -H "Authorization: token ${FORGE_TOKEN:-}" to every user/repo-existence curl call in lib/forge-setup.sh. Example one-liner patch I used to complete the init run during my experiment:

sed -i 's|curl -sf --max-time 5 "\${forge_url}/api/v1/users/|curl -sf --max-time 5 -H "Authorization: token ${FORGE_TOKEN:-}" "${forge_url}/api/v1/users/|g; s|curl -sf --max-time 5 "\${forge_url}/api/v1/repos/\${bot_user}/.profile"|curl -sf --max-time 5 -H "Authorization: token ${FORGE_TOKEN:-}" "${forge_url}/api/v1/repos/${bot_user}/.profile"|g' lib/forge-setup.sh

More broadly, consider auditing every curl -sf call in lib/*-setup.sh scripts and establishing a helper wrapper (like forgejo_api_get / forgejo_api_head) that always attaches the token. This would prevent the same bug from being reintroduced in future additions.

Sister issue: the reachability check on line 53 (filed separately). Both are instances of the same pattern — unauthenticated API calls that assume forgejo's default (unprotected) config.

Context

Discovered while running bin/disinto init as an idempotency experiment on harb-dev-box. Patched locally to complete the run. Part of a cluster of ~9 init bugs found in that session.

## Description `lib/forge-setup.sh` uses unauthenticated curl calls to check whether users and repos exist before creating them. Grep for `curl -sf --max-time 5` in that file surfaces at least these unauthenticated calls: ``` line 141: curl -sf --max-time 5 "${forge_url}/api/v1/users/${admin_user}" line 162: curl -sf --max-time 5 "${forge_url}/api/v1/users/${admin_user}" line 193: curl -sf --max-time 5 "${forge_url}/api/v1/users/${human_user}" line 214: curl -sf --max-time 5 "${forge_url}/api/v1/users/${human_user}" line 251: curl -sf --max-time 5 "${forge_url}/api/v1/users/${human_user}" line 434: curl -sf --max-time 5 "${forge_url}/api/v1/repos/${bot_user}/.profile" ``` On a forgejo with `FORGEJO__service__REQUIRE_SIGNIN_VIEW=true` (the stock disinto compose setup), all of these return HTTP 403 regardless of whether the user/repo actually exists. Init then treats the 403 as "does not exist" and tries to create the resource. In most cases the creation call uses basic auth or a token and succeeds or safely fails, but: 1. **Admin user check** (line 141): returns 403 → init tries to create `disinto-admin` → forgejo CLI errors with `Command error: CreateUser: user already exists [name: disinto-admin]` → init aborts 2. **Bot .profile check** (line 434): returns 403 → init tries to create each bot's .profile repo → some succeed, some silently fail, leading to inconsistent state between runs ## Reproduction 1. Running disinto factory with `REQUIRE_SIGNIN_VIEW=true` 2. Run `bin/disinto init <repo-url> --yes` a second time (first time created users, so they now exist) 3. Observe: init prints "Creating admin user: disinto-admin" followed by "Error: failed to create admin user 'disinto-admin': user already exists" and exits ## Environment - Box: harb-dev-box - Disinto: main (post-v0.2.0 + later merges) - Forgejo: codeberg.org/forgejo/forgejo:11.0, `REQUIRE_SIGNIN_VIEW=true` ## Fix Add `-H "Authorization: token ${FORGE_TOKEN:-}"` to every user/repo-existence curl call in `lib/forge-setup.sh`. Example one-liner patch I used to complete the init run during my experiment: ```bash sed -i 's|curl -sf --max-time 5 "\${forge_url}/api/v1/users/|curl -sf --max-time 5 -H "Authorization: token ${FORGE_TOKEN:-}" "${forge_url}/api/v1/users/|g; s|curl -sf --max-time 5 "\${forge_url}/api/v1/repos/\${bot_user}/.profile"|curl -sf --max-time 5 -H "Authorization: token ${FORGE_TOKEN:-}" "${forge_url}/api/v1/repos/${bot_user}/.profile"|g' lib/forge-setup.sh ``` More broadly, consider auditing every `curl -sf` call in `lib/*-setup.sh` scripts and establishing a helper wrapper (like `forgejo_api_get` / `forgejo_api_head`) that always attaches the token. This would prevent the same bug from being reintroduced in future additions. ## Related Sister issue: the reachability check on line 53 (filed separately). Both are instances of the same pattern — unauthenticated API calls that assume forgejo's default (unprotected) config. ## Context Discovered while running `bin/disinto init` as an idempotency experiment on harb-dev-box. Patched locally to complete the run. Part of a cluster of ~9 init bugs found in that session.
dev-bot added the
backlog
label 2026-04-10 10:02:57 +00:00
dev-qwen self-assigned this 2026-04-10 13:45:17 +00:00
dev-qwen added
in-progress
and removed
backlog
labels 2026-04-10 13:45:18 +00:00
dev-qwen removed their assignment 2026-04-10 14:04:56 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: disinto-admin/disinto#582
No description provided.