Skip to content

fix(docker): create the first admin declaratively on compose deploys#175

Open
shani-singh1 wants to merge 1 commit into
oblien:mainfrom
shani-singh1:fix/docker-first-admin-bootstrap
Open

fix(docker): create the first admin declaratively on compose deploys#175
shani-singh1 wants to merge 1 commit into
oblien:mainfrom
shani-singh1:fix/docker-first-admin-bootstrap

Conversation

@shani-singh1

Copy link
Copy Markdown

Problem

On a fresh Docker Compose deployment there's no supported way to create the first admin through the web flow. Public sign-up is disabled on self-hosted instances, and the loopback bootstrap shortcut in the sign-up guard never fires because the request reaches the API from a Docker-bridge IP (e.g. 172.18.x.x) rather than 127.0.0.1, so it always returns SIGNUP_DISABLED. openship up's interactive wizard has no Compose equivalent.

Fixes #138.

Approach

This follows the direction discussed in #138 (declarative credentials at start, endorsed by @Hydralerne) and reuses the exact mechanism the CLI already relies on — the internal-token-gated, one-shot POST /api/system/bootstrap-admin endpoint. Public sign-up is not touched.

An optional one-shot init-admin Compose service runs once the API is healthy and creates the first admin from credentials the operator declares in .env:

OPENSHIP_ADMIN_NAME=Admin
OPENSHIP_ADMIN_EMAIL=admin@example.com
OPENSHIP_ADMIN_PASSWORD=a-strong-password   # 8-128 chars

Properties:

  • Opt-in / no-op by default — if the admin vars are unset the service prints a hint and exits 0, so nothing changes for operators who create the admin another way. depends_on is one-directional; no other service waits on it.
  • No new public surface — it POSTs to the same invite-only bootstrap endpoint the CLI wizard uses, authenticated with the existing INTERNAL_TOKEN. It does not enable public registration.
  • Idempotentbootstrap-admin returns 409 once an admin exists, which the script treats as success, so re-running docker compose up never mutates an existing admin.

Changes

  • scripts/docker-init-admin.sh — the bootstrap script (POSIX sh; JSON body is escaped for embedded quotes/backslashes).
  • docker-compose.yml — the init-admin service (pinned curlimages/curl, mounts the script read-only, waits for api health, then exits).
  • .env.example — documents the optional OPENSHIP_ADMIN_* vars.
  • docs/installation.md — a "Create the first admin" note in the Docker section.

Testing

  • docker compose config renders cleanly; init-admin receives INTERNAL_TOKEN and OPENSHIP_API_URL.
  • sh -n / bash -n syntax-check pass.
  • Ran the script against a mock of the bootstrap-admin contract covering every branch: vars-unset skip, successful create (incl. a password with embedded " and \ to confirm JSON escaping), idempotent 409 re-run, 401 wrong-token, missing-INTERNAL_TOKEN abort, and unreachable-API. Success/skip paths exit 0; error paths exit non-zero without blocking the rest of the stack.

Notes for reviewers

  • The service is intentionally non-blocking for the rest of the stack (restart: "no", nothing depends on it), so an error state surfaces as an Exited (1) container without affecting the API/dashboard.
  • No application/TypeScript code changes — this only wires up an existing endpoint for the Compose path.

A fresh `docker compose up` had no supported way to create the first
administrator through the web flow: public sign-up is disabled, and the
loopback bootstrap shortcut never fires because the request reaches the
API from a Docker-bridge IP rather than 127.0.0.1 (issue oblien#138).

Add an optional one-shot `init-admin` service that calls the existing
internal-token-gated `POST /api/system/bootstrap-admin` endpoint — the
same path the CLI wizard uses — with credentials the operator declares
in `.env` (`OPENSHIP_ADMIN_NAME` / `_EMAIL` / `_PASSWORD`).

- No-op unless the admin vars are set, so nothing changes for operators
  who create the admin another way.
- Does not enable public sign-up; reuses the invite-only bootstrap path.
- Idempotent: bootstrap-admin returns 409 once an admin exists, which the
  script treats as success, so re-running compose never mutates an admin.

Closes oblien#138.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Fresh Docker deployment cannot create first admin (SIGNUP_DISABLED) because bootstrap request comes from Docker bridge instead of loopback

1 participant