fix(keycloak): org create must send a domain (KC 26 rejects domainless)
Onboarding provisioning failed at CreateOrgAndInvite with create org: 400 "You must provide at least one domain" — Keycloak 26 requires every organization to carry at least one domain, and the payload sent none. Membership is registry-authoritative (model B2), so we do not use Keycloak email-domain auto-join; a synthetic per-tenant domain <slug>.tenant.breakpilot.com satisfies the constraint, is unique (slug is unique in the registry), and never clashes with a real deliverable mail domain. Discovered live: with the service account now holding manage-realm the 403 is gone and this is the next real blocker to onboarding every customer's org on KC 26. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CNdLL9BdsWm7MCyui5ffPD
This commit is contained in:
co-authored by
Claude Fable 5
parent
84516e9b4f
commit
67264d57ed
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
@@ -24,6 +25,7 @@ type stubKC struct {
|
||||
emailCalls atomic.Int32
|
||||
healthCalls atomic.Int32
|
||||
syncCalls atomic.Int32
|
||||
lastOrgBody string
|
||||
|
||||
tokenFails atomic.Bool // when true, /token returns 401 once
|
||||
}
|
||||
@@ -53,6 +55,8 @@ func newStubKC(t *testing.T) *stubKC {
|
||||
mux.HandleFunc("/admin/realms/test-realm/organizations", func(w http.ResponseWriter, r *http.Request) {
|
||||
s.orgCalls.Add(1)
|
||||
if r.Method == http.MethodPost {
|
||||
body, _ := io.ReadAll(r.Body)
|
||||
s.lastOrgBody = string(body)
|
||||
w.Header().Set("Location", s.srv.URL+"/admin/realms/test-realm/organizations/org-xyz")
|
||||
w.WriteHeader(http.StatusCreated)
|
||||
return
|
||||
@@ -135,6 +139,12 @@ func TestHTTPAdapter_createOrgAndInvite(t *testing.T) {
|
||||
t.Errorf("call counts: org=%d user=%d member=%d email=%d",
|
||||
s.orgCalls.Load(), s.userCalls.Load(), s.memberCalls.Load(), s.emailCalls.Load())
|
||||
}
|
||||
// KC 26 rejects a domainless org; the adapter must send a synthetic
|
||||
// per-slug domain so onboarding actually provisions.
|
||||
if !strings.Contains(s.lastOrgBody, `"domains"`) ||
|
||||
!strings.Contains(s.lastOrgBody, "acme.tenant.breakpilot.com") {
|
||||
t.Errorf("org create body missing synthetic domain: %s", s.lastOrgBody)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHTTPAdapter_emailMissingAdminEmailRejected(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user