Commit Graph

7 Commits

Author SHA1 Message Date
Super User
a63aa4e2b7 feat(settings): cross-app language preference
gscMy /settings now hosts a single Language picker.

- Persisted in admin.users.locale (keyed by gscSID). Per the
  gsc-identity-boundaries decision, locale is one of the explicitly
  allowed app-local preference columns.
- Cross-app effect via NEXT_LOCALE cookie set with
  Domain=.gosec.internal — every sibling host on *.gosec.internal
  picks it up on the next request (no relogin, no DB read).
- Server action prisma.user.upsert + cookies().set; client form
  reloads after save so next-intl re-resolves immediately.

This deliberately collapses the previous kitchen-sink AccountSettings
page (which depended on the broken gscUserId/getUserEffectiveSettings
path) — full settings UI will return when the database/users.ts
redesign in Phase-2 lands.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 14:53:35 +02:00
Super User
9b0a1847c2 deploy: gscMy v0.1.5 (picks up kit withLocale no-op)
Same locale-prefix 404 fix as gscAdmin: kit AdminShell no longer
prepends /{locale} to internal URLs, since gscMy's app tree has no
[locale] segment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 14:32:41 +02:00
Super User
afe775c1b0 ui(chrome): render sidebar item labels via legacy 'name'
The kit's AdminShell resolves DbMenuItem.translationKey via
next-intl. gscMy's i18n config has a getMessageFallback that
returns the key verbatim when no translation exists, so passing
the legacy human-readable name ("Dashboard", "Profile", …) as
the translationKey makes the sidebar render correctly without
needing new translations.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 14:18:30 +02:00
Super User
ccf601c178 fix(pam): key grants by gscSID, not NextAuth user.id
The kit's session.user.id is a NextAuth UUID — opaque, per-session
plumbing. The canonical cross-service identity is the FreeIPA uid
exposed as `gscSid` in the kit session. Grants written by gscMy
must use that key so gscAdmin's authz lookup (which uses the
same gscSID-as-key convention) hits them.

- All /api/pam/* routes now require `user.gscSid` instead of `user.id`
- authz.hasRole/requireRole/hasAnyRole take `{gscSid,roles}` shape
- whoami debug endpoint now shows gscSid for verification
- New helper src/lib/session-helpers.ts:getGscsid() for callers

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 14:08:10 +02:00
Super User
cb85c1de7a debug(pam): add /api/pam/whoami to inspect session roles
Temporary endpoint to verify what `realm_access.roles` Keycloak puts
into the access token vs. what NextAuth lands in session.user.roles.
Remove once the eligibility plumbing is confirmed working.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 13:58:00 +02:00
Super User
af8c4fd0da fix(auth): add undici instrumentation for Squid proxy
Without it, NextAuth's Keycloak issuer-discovery fetch goes direct
and Calico default-deny drops it → /access-denied?error=Configuration.
EnvHttpProxyAgent reads HTTP(S)_PROXY at startup.

Mirrors gscAdmin/src/instrumentation.ts. + undici ^6.25.0.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 13:47:59 +02:00
Super User
be1c4fe5f9 chore: bootstrap gscMy on @gsc/web-kit + PAM/JIT request flow
Initial commit for gscMy carved out as its own repo (was tracked
loosely under the monorepo's web/ which is gitignored).

What this contains:
- Auth: next-auth v5 via @gsc/web-kit createAuth (Keycloak only,
  identity sourced from claims, no admin.users writes)
- Chrome: @gsc/web-kit AdminShell — replaces the legacy MyShell.
  Sidebar JSON config carried over and mapped to DbMenuItem.
- Middleware: createAuthMiddleware. Public: /access-denied,
  /auth/keycloak, /signed-out, /api/health, /api/pam/approve.
- RP-initiated signout at /api/auth/signout → Keycloak end_session →
  /signed-out (mirrors gscAdmin).
- Phosphor-iconned access-denied + signed-out landing pages.

PAM/JIT request flow (ported from gscAdmin's pre-strip git history):
- /access page (Active + Eligible tables, request modal with
  duration slider + justification + optional MFA)
- API: /api/pam/{eligible, active, audit, request, approve/:token,
  revoke/:id}
- src/lib/{authz, pam, pam-mail, pam-mfa}.ts — same files as
  gscAdmin had before the strip. PAM tables (admin.privilege_*)
  are shared with gscAdmin; gscMy uses the same Prisma model defs.
- Top-bar widget shows active grants with countdown + revoke.

Build/Deploy: Dockerfile (monorepo-root context), k8s manifests for
my.gosec.internal, self-signed TLS placeholder, DNS A record.
Keycloak gsc-my client extended to include my.gosec.internal/* in
redirect_uris + web_origins.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 13:46:13 +02:00