From c233b1bfbcc42f5557840abc6f6486de5a313590 Mon Sep 17 00:00:00 2001 From: Oier Bravo Urtasun Date: Wed, 10 Jun 2026 21:20:54 +0200 Subject: [PATCH] docs(drasl): record admin bootstrap + config-key/CORS/NMSR gotchas MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Capture what this session learned the hard way, in plan/03-drasl.md and CLAUDE.md: - Correct admin key is DefaultAdmins (not DefaultAdminUsernames); wrong/unknown keys are silently ignored by drasl (logged as "unknown config option"). - CORSAllowOrigins must be top-level, before any [Section], or it's ignored. - First-admin bootstrap under invite mode is a chicken-egg → temp-flip RequireInvite=false, register, revert. - NMSR needs the auth. host-gateway pin + https mojank endpoints or avatars render the default skin (cross-ref plan/19-routes.md). - Fix the stale example config and mark the admin-bootstrap task done. Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 4 +++- plan/03-drasl.md | 30 ++++++++++++++++++++++++++++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 88fe0dd..147eb19 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -156,7 +156,9 @@ Full design settled across WS1–WS6; all tasks unchecked, ready to execute. names, no categories/links; feeds the "50+" stat tile. - [ ] Server-side perf mods (C2ME, etc.). - [ ] **Verify NeoForge version** against current stable before first deploy. -- [ ] **Bootstrap Drasl admin** account. +- [x] **Bootstrap Drasl admin** account (`admin`, 2026-06-10). Key is + `DefaultAdmins` (not `DefaultAdminUsernames`); first admin needs an invite-flip. + See `plan/03-drasl.md` gotchas. ## Reference URLs diff --git a/plan/03-drasl.md b/plan/03-drasl.md index bb2eb1e..2ea9602 100644 --- a/plan/03-drasl.md +++ b/plan/03-drasl.md @@ -19,10 +19,13 @@ Config is **TOML only** (no env var support). So `config.toml` is rendered from BaseURL = "https://auth.${BASE_DOMAIN}" # public scheme is HTTPS (nginx TLS) Domain = "auth.${BASE_DOMAIN}" ListenAddress = "0.0.0.0:25585" # internal; Caddy proxies -DefaultAdminUsernames = ["admin"] +DefaultAdmins = ["admin"] # NOT DefaultAdminUsernames (see gotchas) AllowPasswordLogin = true +# Top-level — NOT under any [Section] (see gotchas). +CORSAllowOrigins = ["https://${BASE_DOMAIN}"] + [ApplicationOwner] # ... @@ -38,6 +41,28 @@ AllowPasswordLogin = true `http://auth.ulicraft.net/authlib-injector`. Must match on server and client. Network alias makes this identical inside/outside the stack. - **`Domain` affects skins** — if wrong, authlib clients may not see skins. +- **Config keys are validated loosely — wrong keys are silently ignored** (drasl + logs `Warning: unknown config option ` and moves on). Two that bit us: + - Admin list key is **`DefaultAdmins`** (top-level), NOT `DefaultAdminUsernames` + (that key never existed → no admin → admin-only routes like `GET /players` + return 403). + - **`CORSAllowOrigins` must be top-level**, before any `[Section]`. Placed after + a table header it parses as `.CORSAllowOrigins`, is ignored, and the + API serves no CORS headers → landing register/account browser calls blocked. + - `RateLimit.Burst` is valid in drasl master but warns on `unmojang/drasl:latest` + (image lags) — harmless. +- **First-admin bootstrap with invite mode on is a chicken-egg.** `DefaultAdmins` + only promotes the account at startup reconciliation, and `POST /drasl/api/v2/users` + is invite-gated (admins do NOT bypass the *register* endpoint). To create the + first admin: temporarily set `RequireInvite = false` in the rendered config, + `docker compose restart drasl`, `POST /users` to register `admin`, then revert + + restart (always trap-revert). API recap: `POST /login {username,password}` → + `{apiToken}`; admin-only `GET /players` with `Authorization: Bearer `. +- **NMSR avatars need https + a host-gateway pin** (see `plan/19-routes.md`). + Drasl's profile embeds **https** skin URLs (BaseURL is https). NMSR reaches + those via `extra_hosts: auth.${BASE_DOMAIN}:host-gateway` (host nginx :443, real + LE cert) with https mojank endpoints. Without it the skin fetch Connect-fails to + caddy:443 and every avatar renders the DEFAULT skin. ## Tasks @@ -47,6 +72,7 @@ AllowPasswordLogin = true - [ ] Wire `render-config.sh` → `drasl/config/config.toml` (gitignored) - [ ] Remove drasl host port from compose (internal only) - [ ] Update compose: drasl on `mcnet`, no `25585:25585` publish -- [ ] Bootstrap admin account on first run; create guest accounts +- [x] Bootstrap admin account (`admin`, done 2026-06-10 via invite-flip; creds in + cochi `.env` for the mc-status roster). Create guest accounts as needed. - [ ] Verify authlib endpoint responds through Caddy - [ ] Future: re-add `[[RegistrationOIDC]]` Keycloak block + secret file