v1.0.0:4 — remove default admin@local credentials; require StartOS action to bootstrap

Security: shipping admin@local / workout123 as a default that the
operator was supposed-to-rotate-but-might-not is the kind of footgun
that turns into "default-credential exposure" headlines. Eliminated.

prisma/seed.ts now ONLY seeds the InstanceSettings singleton — no
admin user, no UserPreferences, no exercises in the build-time
fallback DB. The image still ships with prisma/exercises.seed.json
(curated 164-exercise library) but those rows aren't inserted until
an admin is created via the StartOS Action.

The change-admin-credentials Action now does INSERT-or-UPDATE in one
shot. CREATE mode (no admin exists) inserts the User row, inserts
UserPreferences with sensible defaults, and runs
ensureExerciseLibrary.cjs for the new admin so they don't have to
wait for the next service start to see the curated library. UPDATE
mode (admin exists) keeps the v1.0.0:1-3 rotation behavior. The
mode is auto-detected by counting `WHERE isAdmin = 1`.

The login page is now a server component that reads the admin count
upfront. Zero admins -> renders a "needs setup" panel pointing at
the StartOS Action ("Services -> Proof of Work -> Actions -> Set
admin credentials"). Otherwise renders the existing LoginForm
(extracted to LoginForm.tsx). Eliminates the
"I tried admin@local/workout123 and it failed, what's wrong"
fresh-installer confusion.

Backward compatible for upgrades from v1.0.0:1-3:
  - /data already has an admin user; the no-admin detection never
    triggers; login behaves identically to before.
  - The Action's UPDATE mode still works for rotation.

Version graph: v1.0.0:4 promoted to current; v1.0.0:1, :2, :3 all
listed as `other` for in-place upgrade paths.

README updated to call out the explicit no-default-account design
and how to bootstrap an admin in local dev (Prisma Studio, since
the StartOS action isn't available off-StartOS).
This commit is contained in:
Keysat
2026-05-09 19:13:49 -05:00
parent a64fee4873
commit 5f7b3b6b7a
8 changed files with 405 additions and 266 deletions
+42
View File
@@ -0,0 +1,42 @@
import { IMPOSSIBLE, VersionInfo } from '@start9labs/start-sdk'
/**
* v1.0.0:4 — eliminates the default-admin footgun.
*
* v1.0.0:1-3 shipped with `admin@local` / `workout123` baked into the
* empty-schema fallback DB. Operators were SUPPOSED to rotate via
* Settings or the StartOS Action immediately after install, but
* "supposed to" is the kind of language that puts default credentials
* into HaveIBeenPwned headlines.
*
* From v1.0.0:4 forward:
* - `prisma/seed.ts` only seeds the InstanceSettings singleton.
* No default admin, no UserPreferences, no curated exercises in
* the build-time fallback DB.
* - The StartOS Action `change-admin-credentials` (label: "Set
* admin credentials") now runs in CREATE mode when no admin
* exists — inserts the User row, inserts UserPreferences, and
* triggers ensureExerciseLibrary for the brand-new admin all in
* one shot. Operators run it once on install, then again only
* if they want to rotate.
* - The login page detects zero-admin state and shows a "needs
* setup" panel pointing at the StartOS Action. No more
* "I tried admin@local/workout123 and it failed, what's wrong"
* confusion for fresh installers.
*
* Backward compatible for upgrades from v1.0.0:1-3:
* - Your /data already has an admin user; the no-admin detection
* never triggers; login behaves identically to before.
* - The StartOS Action still works for rotation (UPDATE mode).
*/
export const v_1_0_0_4 = VersionInfo.of({
version: '1.0.0:4',
releaseNotes: {
en_US:
'Security: removes the default admin@local / workout123 credentials from fresh installs. The image now ships with no users; the operator must run the StartOS Action "Set admin credentials" to bootstrap the first admin before anyone can log in. Existing installs are unaffected — your admin row stays as-is and the action keeps working for rotation.',
},
migrations: {
up: async () => {},
down: IMPOSSIBLE,
},
})