openova/products/catalyst/bootstrap
e3mrah 8d2a947cfb
feat(handover): auto-seed owner UserAccess CR on chroot (D21) (#1564)
Closes the D21 gap on Sovereign DoD: /users page returned empty after
fresh handover because Keycloak `sovereign-admins` membership was
established but no UserAccess CR existed for the operator.

After `keycloak.EnsureUser` succeeds in `AuthHandover`, the helper
`EnsureOwnerUserAccess` upserts a cluster-scoped UserAccess CR shaped
like the canonical user_access.go `CreateUserAccess` write:

  apiVersion: access.openova.io/v1alpha1
  kind: UserAccess
  metadata:
    name: useraccess-owner-<sanitized-email>
    annotations:
      catalyst.openova.io/user-email: <email>   # rbac_matrix:309 hint
  spec:
    user:
      keycloakSubject: <email>
    sovereignRef: <fqdn-first-label>
    applications:
      - app: "*"
        role: admin                              # owner -> admin

The Composition (issue #322) reconciles the Claim into per-app
RoleBindings on the Sovereign so the operator surfaces in /users.

Best-effort + idempotent: AlreadyExists on the second handover is
folded to nil; any other error is logged at Warn and the handover
itself never fails. If the access.openova.io CRD has not rolled yet,
the next handover retries automatically.

Architect-first: mirrors `userAccessToUnstructured` shape and uses
existing `sovereignDynamicClient` + `rbacAssignSlug` seams. Tier
mapping follows the documented lossy `owner -> admin` rule in
`userAccessTierToRole` (CRD only accepts admin|editor|viewer).

Refs: docs/SOVEREIGN-MULTI-REGION-DOD.md D21

Co-authored-by: hatiyildiz <hatice.yildiz@openova.io>
2026-05-16 23:49:32 +04:00
..
api feat(handover): auto-seed owner UserAccess CR on chroot (D21) (#1564) 2026-05-16 23:49:32 +04:00
ui feat(wizard): default marketplaceEnabled=true for D27 zero-touch (#1555) 2026-05-16 22:24:09 +04:00