bug: setup_forge reachability check uses unauthenticated curl against /api/v1/version, fails on REQUIRE_SIGNIN_VIEW=true forgejos #581

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

Description

lib/forge-setup.sh line 53 (setup_forge) checks whether Forgejo is already running with an unauthenticated GET:

if curl -sf --max-time 5 "${forge_url}/api/v1/version" >/dev/null 2>&1; then
  echo "Forgejo:  ${forge_url} (already running)"
else
  echo "Forgejo not reachable at ${forge_url}"
  # ... tries to (re)start Forgejo via docker compose ...
fi

The stock disinto compose file sets FORGEJO__service__REQUIRE_SIGNIN_VIEW=true on the forgejo service — which makes every unauthenticated API call (including /api/v1/version) return HTTP 403. So curl -sf sees the 4xx and exits with code 22, and init thinks Forgejo is down.

Init then tries to (re)start Forgejo with docker compose up -d forgejo. On a running factory where forgejo is already up, this is harmless but misleading. On a box where the caller isn't in the docker group (e.g. running init as a non-root user without docker access), it fails with a permission error and init aborts entirely — unable to even check whether the already-running forgejo could be talked to.

Reproduction

  1. Start a disinto factory with the stock compose (or anything that sets REQUIRE_SIGNIN_VIEW=true):

    docker compose up -d forgejo
    
  2. Confirm forgejo is reachable but locked-down:

    curl -sf -o /dev/null -w 'HTTP %{http_code}\n' http://localhost:3000/
    # HTTP 200
    curl -s -w 'HTTP %{http_code}\n' http://localhost:3000/api/v1/version
    # HTTP 403
    # {"message":"Only signed in user is allowed to call APIs."}
    
  3. Run bin/disinto init — it will print "Forgejo not reachable" and attempt to restart the container.

Environment

  • Box: harb-dev-box (LXD container, Debian 12)
  • Disinto: main (post-v0.2.0, commit aeaef88 + later merges)
  • Forgejo: codeberg.org/forgejo/forgejo:11.0 with FORGEJO__service__REQUIRE_SIGNIN_VIEW=true

Fix

Add the FORGE_TOKEN to the reachability check:

if curl -sf --max-time 5 -H "Authorization: token ${FORGE_TOKEN:-}" "${forge_url}/api/v1/version" >/dev/null 2>&1; then

This works on both locked-down and open forgejos because Authorization: token with an empty token is accepted as "anonymous" by forgejo when sign-in is not required, and with a valid token when it is.

Alternative: hit an endpoint that is specifically designed to be public on forgejo (e.g. /api/healthz if it exists — need to verify in the forgejo image being used).

Context

Discovered while running bin/disinto init as an idempotency experiment on harb-dev-box to see if it would create the missing ops repo. This was the very first step that failed. Patched locally to complete the experiment — filing for a permanent fix. Part of a cluster of ~9 init bugs found during that experiment.

## Description `lib/forge-setup.sh` line 53 (setup_forge) checks whether Forgejo is already running with an unauthenticated GET: ```bash if curl -sf --max-time 5 "${forge_url}/api/v1/version" >/dev/null 2>&1; then echo "Forgejo: ${forge_url} (already running)" else echo "Forgejo not reachable at ${forge_url}" # ... tries to (re)start Forgejo via docker compose ... fi ``` The stock disinto compose file sets `FORGEJO__service__REQUIRE_SIGNIN_VIEW=true` on the forgejo service — which makes **every** unauthenticated API call (including `/api/v1/version`) return HTTP 403. So `curl -sf` sees the 4xx and exits with code 22, and init thinks Forgejo is down. Init then tries to (re)start Forgejo with `docker compose up -d forgejo`. On a running factory where forgejo is already up, this is harmless but misleading. On a box where the caller isn't in the docker group (e.g. running init as a non-root user without docker access), it fails with a permission error and init aborts entirely — unable to even check whether the already-running forgejo could be talked to. ## Reproduction 1. Start a disinto factory with the stock compose (or anything that sets `REQUIRE_SIGNIN_VIEW=true`): ```bash docker compose up -d forgejo ``` 2. Confirm forgejo is reachable but locked-down: ```bash curl -sf -o /dev/null -w 'HTTP %{http_code}\n' http://localhost:3000/ # HTTP 200 curl -s -w 'HTTP %{http_code}\n' http://localhost:3000/api/v1/version # HTTP 403 # {"message":"Only signed in user is allowed to call APIs."} ``` 3. Run `bin/disinto init` — it will print "Forgejo not reachable" and attempt to restart the container. ## Environment - Box: harb-dev-box (LXD container, Debian 12) - Disinto: main (post-v0.2.0, commit aeaef88 + later merges) - Forgejo: codeberg.org/forgejo/forgejo:11.0 with `FORGEJO__service__REQUIRE_SIGNIN_VIEW=true` ## Fix Add the FORGE_TOKEN to the reachability check: ```bash if curl -sf --max-time 5 -H "Authorization: token ${FORGE_TOKEN:-}" "${forge_url}/api/v1/version" >/dev/null 2>&1; then ``` This works on both locked-down and open forgejos because `Authorization: token ` with an empty token is accepted as "anonymous" by forgejo when sign-in is not required, and with a valid token when it is. Alternative: hit an endpoint that is specifically designed to be public on forgejo (e.g. `/api/healthz` if it exists — need to verify in the forgejo image being used). ## Context Discovered while running `bin/disinto init` as an idempotency experiment on harb-dev-box to see if it would create the missing ops repo. This was the very first step that failed. Patched locally to complete the experiment — filing for a permanent fix. Part of a cluster of ~9 init bugs found during that experiment.
dev-bot added the
backlog
label 2026-04-10 10:02:57 +00:00
dev-bot self-assigned this 2026-04-10 13:35:28 +00:00
dev-bot added
in-progress
and removed
backlog
labels 2026-04-10 13:35:29 +00:00
dev-bot removed their assignment 2026-04-10 13:41:58 +00:00
dev-bot removed the
in-progress
label 2026-04-10 13:41:59 +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#581
No description provided.