fix: dispatcher admin check fails — is_admin not visible to non-admin tokens #152

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

Problem

The dispatcher checks if the PR merger is admin via GET /api/v1/users/{username} and reads .is_admin. But Forgejo only exposes is_admin: true when the requesting user is also a site admin. The dispatcher uses FORGE_TOKEN (dev-bot, not admin), so is_admin always appears false for everyone.

Current workaround: FORGE_ADMIN_USERS env var with a static list of admin usernames. But this is fragile — it must be kept in sync manually.

Fix

Two changes:

  1. bin/disinto generate_compose: add FORGE_ADMIN_USERS to the edge service environment, populated from the human user created during init. Format: FORGE_ADMIN_USERS: "disinto-admin,johba" (comma-separated).

  2. docker/edge/dispatcher.sh: change is_user_admin() to use an admin token for the API check. The dispatcher already has access to vault secrets — add FORGE_ADMIN_TOKEN (the disinto-admin token) to the edge environment and use it for admin verification:

is_user_admin() {
  local username="$1"
  local admin_token="${FORGE_ADMIN_TOKEN:-${FORGE_TOKEN}}"
  local is_admin
  is_admin=$(curl -sf -H "Authorization: token ${admin_token}" \
    "${FORGE_URL}/api/v1/users/${username}" | jq -r '.is_admin // false')
  [[ "$is_admin" == "true" ]]
}

Either approach works. The static list is simpler; the admin token is more correct.

Affected files

  • bin/disinto generate_compose (add FORGE_ADMIN_USERS to edge env)
  • docker/edge/dispatcher.sh (use admin token or static list)

Acceptance criteria

  • Dispatcher correctly identifies admin users who merge vault PRs
  • No false negatives (admin user not recognized)
  • Config survives disinto init regeneration
  • CI green
## Problem The dispatcher checks if the PR merger is admin via `GET /api/v1/users/{username}` and reads `.is_admin`. But Forgejo only exposes `is_admin: true` when the requesting user is also a site admin. The dispatcher uses `FORGE_TOKEN` (dev-bot, not admin), so `is_admin` always appears `false` for everyone. Current workaround: `FORGE_ADMIN_USERS` env var with a static list of admin usernames. But this is fragile — it must be kept in sync manually. ## Fix Two changes: 1. **`bin/disinto` generate_compose**: add `FORGE_ADMIN_USERS` to the edge service environment, populated from the human user created during init. Format: `FORGE_ADMIN_USERS: "disinto-admin,johba"` (comma-separated). 2. **`docker/edge/dispatcher.sh`**: change `is_user_admin()` to use an admin token for the API check. The dispatcher already has access to vault secrets — add `FORGE_ADMIN_TOKEN` (the disinto-admin token) to the edge environment and use it for admin verification: ```bash is_user_admin() { local username="$1" local admin_token="${FORGE_ADMIN_TOKEN:-${FORGE_TOKEN}}" local is_admin is_admin=$(curl -sf -H "Authorization: token ${admin_token}" \ "${FORGE_URL}/api/v1/users/${username}" | jq -r '.is_admin // false') [[ "$is_admin" == "true" ]] } ``` Either approach works. The static list is simpler; the admin token is more correct. ## Affected files - `bin/disinto` generate_compose (add FORGE_ADMIN_USERS to edge env) - `docker/edge/dispatcher.sh` (use admin token or static list) ## Acceptance criteria - [ ] Dispatcher correctly identifies admin users who merge vault PRs - [ ] No false negatives (admin user not recognized) - [ ] Config survives `disinto init` regeneration - [ ] CI green
dev-bot added the
backlog
label 2026-04-02 17:57:01 +00:00
dev-qwen self-assigned this 2026-04-02 17:59:46 +00:00
dev-qwen added
in-progress
and removed
backlog
labels 2026-04-02 17:59:46 +00:00
dev-qwen removed their assignment 2026-04-02 18:09:55 +00:00
dev-qwen removed the
in-progress
label 2026-04-02 18:09: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#152
No description provided.