fix(auth): upsert UI login user_id unprefixed (drop docker seeder workaround)
Root cause of the mismatch that prompted the one-shot cameleer-seed
docker service: UiAuthController stored users.user_id as the JWT
subject "user:admin" (JWT sub format). Every env-scoped controller
(Alert, AlertSilence, AlertRule, OutboundConnectionAdmin) already
strips the "user:" prefix on the read path — so the rest of the
system expects the DB key to be the bare username. With UiAuth
storing prefixed, fresh docker stacks hit
"alert_rules_created_by_fkey violation" on the first rule create.
Fix: inside login(), compute `userId = request.username()` and use
it everywhere the DB/RBAC layer is touched (isLocked, getPasswordHash,
record/clearFailedLogins, upsert, assignRoleToUser, addUserToGroup,
getSystemRoleNames). Keep `subject = "user:" + userId` — we still
sign JWTs with the namespaced subject so JwtAuthenticationFilter can
distinguish user vs agent tokens.
refresh() and me() follow the same rule via a stripSubjectPrefix()
helper (JWT subject in, bare DB key out).
With the write path aligned, the docker bridge is no longer needed:
- Deleted deploy/docker/postgres-init.sql
- Deleted cameleer-seed service from docker-compose.yml
Scope: UiAuthController only. UserAdminController + OidcAuthController
still prefix on upsert — that's the bug class the triage identified
as "Option A or B either way OK". Not changing them now because:
a) prod admins are provisioned unprefixed through some other path,
so those two files aren't the docker-only failure observed;
b) stripping them would need a data migration for any existing
prod users stored prefixed, which is out of scope for a cleanup
phase. Follow-up worth scheduling if we ever wire OIDC or admin-
created users into alerting FKs.
Verified: 33/33 alerting+outbound controller ITs pass (9 outbound,
10 rules, 9 silences, 5 alert inbox).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,41 +0,0 @@
|
||||
-- Dev-stack seed: pre-create the `admin` user row without the `user:` prefix.
|
||||
--
|
||||
-- Why: the UI login controller stores the local admin as `user_id='user:admin'`
|
||||
-- (JWT `sub` format), but the alerting + outbound controllers resolve the FK
|
||||
-- via `authentication.name` with the `user:` prefix stripped, i.e. `admin`.
|
||||
-- In k8s these controllers happily insert `admin` because production admins are
|
||||
-- provisioned through the admin API with unprefixed user_ids. In the local
|
||||
-- docker stack there's no such provisioning step, so the FK check fails with
|
||||
-- "alert_rules_created_by_fkey violation" on the first rule create.
|
||||
--
|
||||
-- Seeding a row with `user_id='admin'` here bridges the gap so E2E smokes,
|
||||
-- API probes, and manual dev sessions can create alerting rows straight away.
|
||||
-- Flyway owns the schema in tenant_default; this script only INSERTs idempotently
|
||||
-- and is gated on the schema existing.
|
||||
|
||||
DO $$
|
||||
DECLARE
|
||||
schema_exists bool;
|
||||
table_exists bool;
|
||||
BEGIN
|
||||
SELECT EXISTS(
|
||||
SELECT 1 FROM information_schema.schemata WHERE schema_name = 'tenant_default'
|
||||
) INTO schema_exists;
|
||||
IF NOT schema_exists THEN
|
||||
RAISE NOTICE 'tenant_default schema not yet migrated — skipping admin seed (Flyway will run on server start)';
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
SELECT EXISTS(
|
||||
SELECT 1 FROM information_schema.tables
|
||||
WHERE table_schema = 'tenant_default' AND table_name = 'users'
|
||||
) INTO table_exists;
|
||||
IF NOT table_exists THEN
|
||||
RAISE NOTICE 'tenant_default.users not yet migrated — skipping admin seed';
|
||||
RETURN;
|
||||
END IF;
|
||||
|
||||
INSERT INTO tenant_default.users (user_id, provider, email, display_name)
|
||||
VALUES ('admin', 'local', '', 'admin')
|
||||
ON CONFLICT (user_id) DO NOTHING;
|
||||
END $$;
|
||||
Reference in New Issue
Block a user