forked from baron/baron-sso
feat(user): support fixed UUID registration and enhance bulk import results
- Added support for fixed UUIDs during bulk registration (Search-first + ExternalID mapping) - Implemented idempotency and visibility restoration for soft-deleted users - Enhanced bulk upload UI to show 'New/Updated/Unchanged' status and modified fields - Added logic to reclaim identifiers (login_id) from colliding records - Added frontend E2E and backend unit tests for UUID integrity and conflict handling - Fixed i18n, formatting, and mock tests to satisfy code-check - Applied 'go fix' for 'omitzero' tags and general Go standards
This commit is contained in:
@@ -88,7 +88,7 @@ func (m *devMockKratosAdmin) GetIdentity(ctx context.Context, identityID string)
|
||||
return nil, args.Error(1)
|
||||
}
|
||||
|
||||
func (m *devMockKratosAdmin) UpdateIdentity(ctx context.Context, identityID string, traits map[string]interface{}, state string) (*service.KratosIdentity, error) {
|
||||
func (m *devMockKratosAdmin) UpdateIdentity(ctx context.Context, identityID string, traits map[string]any, state string) (*service.KratosIdentity, error) {
|
||||
args := m.Called(ctx, identityID, traits, state)
|
||||
if identity, ok := args.Get(0).(*service.KratosIdentity); ok {
|
||||
return identity, args.Error(1)
|
||||
@@ -292,9 +292,9 @@ func TestGetCurrentProfile_PreservesExistingAuditUserContext(t *testing.T) {
|
||||
func TestListClients_Success(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.URL.Path == "/clients" {
|
||||
return httpJSONAny(r, http.StatusOK, []map[string]interface{}{
|
||||
{"client_id": "client-1", "client_name": "App One", "metadata": map[string]interface{}{"status": "active"}},
|
||||
{"client_id": "client-2", "client_name": "App Two", "metadata": map[string]interface{}{"status": "inactive"}},
|
||||
return httpJSONAny(r, http.StatusOK, []map[string]any{
|
||||
{"client_id": "client-1", "client_name": "App One", "metadata": map[string]any{"status": "active"}},
|
||||
{"client_id": "client-2", "client_name": "App Two", "metadata": map[string]any{"status": "inactive"}},
|
||||
}), nil
|
||||
}
|
||||
return httpJSONAny(r, http.StatusNotFound, nil), nil
|
||||
@@ -326,9 +326,9 @@ func TestListClients_Success(t *testing.T) {
|
||||
func TestListClients_UserSeesOnlyClientsAllowedByReBAC(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.URL.Path == "/clients" {
|
||||
return httpJSONAny(r, http.StatusOK, []map[string]interface{}{
|
||||
{"client_id": "client-denied", "client_name": "Denied App", "metadata": map[string]interface{}{"tenant_id": "tenant-a", "status": "active"}},
|
||||
{"client_id": "client-allowed", "client_name": "Allowed App", "metadata": map[string]interface{}{"tenant_id": "tenant-b", "status": "active"}},
|
||||
return httpJSONAny(r, http.StatusOK, []map[string]any{
|
||||
{"client_id": "client-denied", "client_name": "Denied App", "metadata": map[string]any{"tenant_id": "tenant-a", "status": "active"}},
|
||||
{"client_id": "client-allowed", "client_name": "Allowed App", "metadata": map[string]any{"tenant_id": "tenant-b", "status": "active"}},
|
||||
}), nil
|
||||
}
|
||||
return httpJSONAny(r, http.StatusNotFound, nil), nil
|
||||
@@ -796,9 +796,9 @@ func TestUpdateClient_AuditDetailsIncludeGeneralSettingChanges(t *testing.T) {
|
||||
func TestListClients_ProtectedSystemClientHidden(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.URL.Path == "/clients" {
|
||||
return httpJSONAny(r, http.StatusOK, []map[string]interface{}{
|
||||
return httpJSONAny(r, http.StatusOK, []map[string]any{
|
||||
{"client_id": "oathkeeper-introspect", "client_name": "Internal Client"},
|
||||
{"client_id": "client-1", "client_name": "App One", "metadata": map[string]interface{}{"status": "active"}},
|
||||
{"client_id": "client-1", "client_name": "App One", "metadata": map[string]any{"status": "active"}},
|
||||
}), nil
|
||||
}
|
||||
return httpJSONAny(r, http.StatusNotFound, nil), nil
|
||||
@@ -834,12 +834,12 @@ func TestListClients_ProtectedSystemClientHidden(t *testing.T) {
|
||||
func TestListClients_ReservedSystemNameAliasHidden(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.URL.Path == "/clients" {
|
||||
return httpJSONAny(r, http.StatusOK, []map[string]interface{}{
|
||||
{"client_id": "adminfront", "client_name": "AdminFront", "metadata": map[string]interface{}{"status": "active"}},
|
||||
{"client_id": "4f2c9fd6-1111-2222-3333-444444444444", "client_name": "AdminFront", "metadata": map[string]interface{}{"status": "active"}},
|
||||
{"client_id": "devfront", "client_name": "DevFront", "metadata": map[string]interface{}{"status": "active"}},
|
||||
{"client_id": "7d2c9fd6-1111-2222-3333-444444444444", "client_name": "DevFront", "metadata": map[string]interface{}{"status": "active"}},
|
||||
{"client_id": "client-1", "client_name": "App One", "metadata": map[string]interface{}{"status": "active"}},
|
||||
return httpJSONAny(r, http.StatusOK, []map[string]any{
|
||||
{"client_id": "adminfront", "client_name": "AdminFront", "metadata": map[string]any{"status": "active"}},
|
||||
{"client_id": "4f2c9fd6-1111-2222-3333-444444444444", "client_name": "AdminFront", "metadata": map[string]any{"status": "active"}},
|
||||
{"client_id": "devfront", "client_name": "DevFront", "metadata": map[string]any{"status": "active"}},
|
||||
{"client_id": "7d2c9fd6-1111-2222-3333-444444444444", "client_name": "DevFront", "metadata": map[string]any{"status": "active"}},
|
||||
{"client_id": "client-1", "client_name": "App One", "metadata": map[string]any{"status": "active"}},
|
||||
}), nil
|
||||
}
|
||||
return httpJSONAny(r, http.StatusNotFound, nil), nil
|
||||
@@ -878,10 +878,10 @@ func TestListClients_ReservedSystemNameAliasHidden(t *testing.T) {
|
||||
func TestGetClient_ReservedSystemNameAliasHidden(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.URL.Path == "/clients/4f2c9fd6-1111-2222-3333-444444444444" {
|
||||
return httpJSONAny(r, http.StatusOK, map[string]interface{}{
|
||||
return httpJSONAny(r, http.StatusOK, map[string]any{
|
||||
"client_id": "4f2c9fd6-1111-2222-3333-444444444444",
|
||||
"client_name": "AdminFront",
|
||||
"metadata": map[string]interface{}{"status": "active"},
|
||||
"metadata": map[string]any{"status": "active"},
|
||||
}), nil
|
||||
}
|
||||
return httpJSONAny(r, http.StatusNotFound, nil), nil
|
||||
@@ -910,13 +910,13 @@ func TestGetClient_ReservedSystemNameAliasHidden(t *testing.T) {
|
||||
func TestUpdateClientStatus_Success(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method == http.MethodGet && r.URL.Path == "/clients/client-1" {
|
||||
return httpJSONAny(r, http.StatusOK, map[string]interface{}{
|
||||
"client_id": "client-1", "metadata": map[string]interface{}{"status": "active"},
|
||||
return httpJSONAny(r, http.StatusOK, map[string]any{
|
||||
"client_id": "client-1", "metadata": map[string]any{"status": "active"},
|
||||
}), nil
|
||||
}
|
||||
if r.Method == http.MethodPatch && r.URL.Path == "/clients/client-1" {
|
||||
return httpJSONAny(r, http.StatusOK, map[string]interface{}{
|
||||
"client_id": "client-1", "metadata": map[string]interface{}{"status": "inactive"},
|
||||
return httpJSONAny(r, http.StatusOK, map[string]any{
|
||||
"client_id": "client-1", "metadata": map[string]any{"status": "inactive"},
|
||||
}), nil
|
||||
}
|
||||
return httpJSONAny(r, http.StatusNotFound, nil), nil
|
||||
@@ -936,7 +936,7 @@ func TestUpdateClientStatus_Success(t *testing.T) {
|
||||
})
|
||||
app.Patch("/api/v1/dev/clients/:id/status", h.UpdateClientStatus)
|
||||
|
||||
body, _ := json.Marshal(map[string]interface{}{"status": "inactive"})
|
||||
body, _ := json.Marshal(map[string]any{"status": "inactive"})
|
||||
req := httptest.NewRequest(http.MethodPatch, "/api/v1/dev/clients/client-1/status", bytes.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
resp, _ := app.Test(req, -1)
|
||||
@@ -950,20 +950,20 @@ func TestUpdateClientStatus_Success(t *testing.T) {
|
||||
func TestUpdateClientStatus_UserAllowedByStatusPermission(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method == http.MethodGet && r.URL.Path == "/clients/client-1" {
|
||||
return httpJSONAny(r, http.StatusOK, map[string]interface{}{
|
||||
return httpJSONAny(r, http.StatusOK, map[string]any{
|
||||
"client_id": "client-1",
|
||||
"client_name": "App One",
|
||||
"metadata": map[string]interface{}{
|
||||
"metadata": map[string]any{
|
||||
"tenant_id": "tenant-1",
|
||||
"status": "active",
|
||||
},
|
||||
}), nil
|
||||
}
|
||||
if r.Method == http.MethodPatch && r.URL.Path == "/clients/client-1" {
|
||||
return httpJSONAny(r, http.StatusOK, map[string]interface{}{
|
||||
return httpJSONAny(r, http.StatusOK, map[string]any{
|
||||
"client_id": "client-1",
|
||||
"client_name": "App One",
|
||||
"metadata": map[string]interface{}{
|
||||
"metadata": map[string]any{
|
||||
"tenant_id": "tenant-1",
|
||||
"status": "inactive",
|
||||
},
|
||||
@@ -995,7 +995,7 @@ func TestUpdateClientStatus_UserAllowedByStatusPermission(t *testing.T) {
|
||||
})
|
||||
app.Patch("/api/v1/dev/clients/:id/status", h.UpdateClientStatus)
|
||||
|
||||
body, _ := json.Marshal(map[string]interface{}{"status": "inactive"})
|
||||
body, _ := json.Marshal(map[string]any{"status": "inactive"})
|
||||
req := httptest.NewRequest(http.MethodPatch, "/api/v1/dev/clients/client-1/status", bytes.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
resp, _ := app.Test(req, -1)
|
||||
@@ -1010,20 +1010,20 @@ func TestUpdateClientStatus_UserAllowedByStatusPermission(t *testing.T) {
|
||||
func TestUpdateClientStatus_UserAllowedByEditConfigPermission(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method == http.MethodGet && r.URL.Path == "/clients/client-1" {
|
||||
return httpJSONAny(r, http.StatusOK, map[string]interface{}{
|
||||
return httpJSONAny(r, http.StatusOK, map[string]any{
|
||||
"client_id": "client-1",
|
||||
"client_name": "App One",
|
||||
"metadata": map[string]interface{}{
|
||||
"metadata": map[string]any{
|
||||
"tenant_id": "tenant-1",
|
||||
"status": "active",
|
||||
},
|
||||
}), nil
|
||||
}
|
||||
if r.Method == http.MethodPatch && r.URL.Path == "/clients/client-1" {
|
||||
return httpJSONAny(r, http.StatusOK, map[string]interface{}{
|
||||
return httpJSONAny(r, http.StatusOK, map[string]any{
|
||||
"client_id": "client-1",
|
||||
"client_name": "App One",
|
||||
"metadata": map[string]interface{}{
|
||||
"metadata": map[string]any{
|
||||
"tenant_id": "tenant-1",
|
||||
"status": "inactive",
|
||||
},
|
||||
@@ -1055,7 +1055,7 @@ func TestUpdateClientStatus_UserAllowedByEditConfigPermission(t *testing.T) {
|
||||
})
|
||||
app.Patch("/api/v1/dev/clients/:id/status", h.UpdateClientStatus)
|
||||
|
||||
body, _ := json.Marshal(map[string]interface{}{"status": "inactive"})
|
||||
body, _ := json.Marshal(map[string]any{"status": "inactive"})
|
||||
req := httptest.NewRequest(http.MethodPatch, "/api/v1/dev/clients/client-1/status", bytes.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
resp, _ := app.Test(req, -1)
|
||||
@@ -1070,7 +1070,7 @@ func TestUpdateClientStatus_UserAllowedByEditConfigPermission(t *testing.T) {
|
||||
func TestUpdateClientStatus_ProtectedSystemClientForbidden(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method == http.MethodGet && r.URL.Path == "/clients/oathkeeper-introspect" {
|
||||
return httpJSONAny(r, http.StatusOK, map[string]interface{}{
|
||||
return httpJSONAny(r, http.StatusOK, map[string]any{
|
||||
"client_id": "oathkeeper-introspect",
|
||||
}), nil
|
||||
}
|
||||
@@ -1091,7 +1091,7 @@ func TestUpdateClientStatus_ProtectedSystemClientForbidden(t *testing.T) {
|
||||
})
|
||||
app.Patch("/api/v1/dev/clients/:id/status", h.UpdateClientStatus)
|
||||
|
||||
body, _ := json.Marshal(map[string]interface{}{"status": "inactive"})
|
||||
body, _ := json.Marshal(map[string]any{"status": "inactive"})
|
||||
req := httptest.NewRequest(http.MethodPatch, "/api/v1/dev/clients/oathkeeper-introspect/status", bytes.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
resp, _ := app.Test(req, -1)
|
||||
@@ -1102,7 +1102,7 @@ func TestUpdateClientStatus_ProtectedSystemClientForbidden(t *testing.T) {
|
||||
func TestDeleteClient_Success(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method == http.MethodGet && r.URL.Path == "/clients/client-1" {
|
||||
return httpJSONAny(r, http.StatusOK, map[string]interface{}{"client_id": "client-1"}), nil
|
||||
return httpJSONAny(r, http.StatusOK, map[string]any{"client_id": "client-1"}), nil
|
||||
}
|
||||
if r.Method == http.MethodDelete && r.URL.Path == "/clients/client-1" {
|
||||
return &http.Response{StatusCode: http.StatusNoContent, Body: http.NoBody}, nil
|
||||
@@ -1142,7 +1142,7 @@ func TestDeleteClient_Success(t *testing.T) {
|
||||
func TestDeleteClient_ProtectedSystemClientForbidden(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method == http.MethodGet && r.URL.Path == "/clients/oathkeeper-introspect" {
|
||||
return httpJSONAny(r, http.StatusOK, map[string]interface{}{"client_id": "oathkeeper-introspect"}), nil
|
||||
return httpJSONAny(r, http.StatusOK, map[string]any{"client_id": "oathkeeper-introspect"}), nil
|
||||
}
|
||||
return httpJSONAny(r, http.StatusNotFound, nil), nil
|
||||
})
|
||||
@@ -1172,7 +1172,7 @@ func TestDeleteClient_ProtectedSystemClientForbidden(t *testing.T) {
|
||||
func TestGetClient_ProtectedSystemClientHidden(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method == http.MethodGet && r.URL.Path == "/clients/oathkeeper-introspect" {
|
||||
return httpJSONAny(r, http.StatusOK, map[string]interface{}{
|
||||
return httpJSONAny(r, http.StatusOK, map[string]any{
|
||||
"client_id": "oathkeeper-introspect",
|
||||
"client_name": "Internal Client",
|
||||
}), nil
|
||||
@@ -1203,10 +1203,10 @@ func TestGetClient_ProtectedSystemClientHidden(t *testing.T) {
|
||||
func TestGetClient_RPAdminAllowedByKetoViewPermission(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method == http.MethodGet && r.URL.Path == "/clients/client-1" {
|
||||
return httpJSONAny(r, http.StatusOK, map[string]interface{}{
|
||||
return httpJSONAny(r, http.StatusOK, map[string]any{
|
||||
"client_id": "client-1",
|
||||
"client_name": "App One",
|
||||
"metadata": map[string]interface{}{
|
||||
"metadata": map[string]any{
|
||||
"tenant_id": "tenant-b",
|
||||
"status": "active",
|
||||
},
|
||||
@@ -1248,11 +1248,11 @@ func TestGetClient_RPAdminAllowedByKetoViewPermission(t *testing.T) {
|
||||
func TestGetClient_RedactsSecretWithoutViewSecretPermission(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method == http.MethodGet && r.URL.Path == "/clients/client-1" {
|
||||
return httpJSONAny(r, http.StatusOK, map[string]interface{}{
|
||||
return httpJSONAny(r, http.StatusOK, map[string]any{
|
||||
"client_id": "client-1",
|
||||
"client_name": "App One",
|
||||
"client_secret": "stored-secret",
|
||||
"metadata": map[string]interface{}{
|
||||
"metadata": map[string]any{
|
||||
"tenant_id": "tenant-1",
|
||||
"status": "active",
|
||||
},
|
||||
@@ -1297,11 +1297,11 @@ func TestGetClient_RedactsSecretWithoutViewSecretPermission(t *testing.T) {
|
||||
func TestGetClient_UserAllowedToViewSecretByPermission(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method == http.MethodGet && r.URL.Path == "/clients/client-1" {
|
||||
return httpJSONAny(r, http.StatusOK, map[string]interface{}{
|
||||
return httpJSONAny(r, http.StatusOK, map[string]any{
|
||||
"client_id": "client-1",
|
||||
"client_name": "App One",
|
||||
"client_secret": "stored-secret",
|
||||
"metadata": map[string]interface{}{
|
||||
"metadata": map[string]any{
|
||||
"tenant_id": "tenant-1",
|
||||
"status": "active",
|
||||
},
|
||||
@@ -1346,10 +1346,10 @@ func TestGetClient_UserAllowedToViewSecretByPermission(t *testing.T) {
|
||||
func TestRotateClientSecret_Success(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method == http.MethodGet && r.URL.Path == "/clients/client-1" {
|
||||
return httpJSONAny(r, http.StatusOK, map[string]interface{}{"client_id": "client-1"}), nil
|
||||
return httpJSONAny(r, http.StatusOK, map[string]any{"client_id": "client-1"}), nil
|
||||
}
|
||||
if r.Method == http.MethodPut && r.URL.Path == "/clients/client-1" {
|
||||
var body map[string]interface{}
|
||||
var body map[string]any
|
||||
json.NewDecoder(r.Body).Decode(&body)
|
||||
return httpJSONAny(r, http.StatusOK, body), nil
|
||||
}
|
||||
@@ -1390,7 +1390,7 @@ func TestRotateClientSecret_Success(t *testing.T) {
|
||||
func TestCreateClient_RPAdminAllowedByTenantGrantPermission(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method == http.MethodPost && r.URL.Path == "/clients" {
|
||||
var body map[string]interface{}
|
||||
var body map[string]any
|
||||
_ = json.NewDecoder(r.Body).Decode(&body)
|
||||
body["client_secret"] = "generated-secret"
|
||||
return httpJSONAny(r, http.StatusCreated, body), nil
|
||||
@@ -1443,7 +1443,7 @@ func TestCreateClient_RPAdminAllowedByTenantGrantPermission(t *testing.T) {
|
||||
func TestCreateClient_ApprovedDeveloperCanCreatePrivateClient(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.Method == http.MethodPost && r.URL.Path == "/clients" {
|
||||
var body map[string]interface{}
|
||||
var body map[string]any
|
||||
_ = json.NewDecoder(r.Body).Decode(&body)
|
||||
body["client_secret"] = "generated-secret"
|
||||
return httpJSONAny(r, http.StatusCreated, body), nil
|
||||
@@ -1625,11 +1625,11 @@ func TestRevokeDeveloperGrantRelation_DeletesRequiredTenantRelations(t *testing.
|
||||
func TestGetStats_Success(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.URL.Path == "/clients" {
|
||||
return httpJSONAny(r, http.StatusOK, []map[string]interface{}{
|
||||
{"client_id": "c1", "metadata": map[string]interface{}{"tenant_id": "t1"}},
|
||||
{"client_id": "c2", "metadata": map[string]interface{}{"tenant_id": "t1"}},
|
||||
{"client_id": "oathkeeper-introspect", "metadata": map[string]interface{}{"tenant_id": "t1"}},
|
||||
{"client_id": "c3", "metadata": map[string]interface{}{"tenant_id": "t2"}},
|
||||
return httpJSONAny(r, http.StatusOK, []map[string]any{
|
||||
{"client_id": "c1", "metadata": map[string]any{"tenant_id": "t1"}},
|
||||
{"client_id": "c2", "metadata": map[string]any{"tenant_id": "t1"}},
|
||||
{"client_id": "oathkeeper-introspect", "metadata": map[string]any{"tenant_id": "t1"}},
|
||||
{"client_id": "c3", "metadata": map[string]any{"tenant_id": "t2"}},
|
||||
}), nil
|
||||
}
|
||||
return httpJSONAny(r, http.StatusNotFound, nil), nil
|
||||
@@ -1693,9 +1693,9 @@ func TestGetStats_UserScopesAuditMetricsToVisibleClients(t *testing.T) {
|
||||
now := time.Now()
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.URL.Path == "/clients" {
|
||||
return httpJSONAny(r, http.StatusOK, []map[string]interface{}{
|
||||
{"client_id": "client-owned", "metadata": map[string]interface{}{"tenant_id": "tenant-a"}},
|
||||
{"client_id": "client-other", "metadata": map[string]interface{}{"tenant_id": "tenant-a"}},
|
||||
return httpJSONAny(r, http.StatusOK, []map[string]any{
|
||||
{"client_id": "client-owned", "metadata": map[string]any{"tenant_id": "tenant-a"}},
|
||||
{"client_id": "client-other", "metadata": map[string]any{"tenant_id": "tenant-a"}},
|
||||
}), nil
|
||||
}
|
||||
return httpJSONAny(r, http.StatusNotFound, nil), nil
|
||||
@@ -1785,9 +1785,9 @@ func TestGetStats_UserScopesAuditMetricsToVisibleClients(t *testing.T) {
|
||||
func TestGetRPUsageDaily_UserScopesItemsToVisibleClients(t *testing.T) {
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.URL.Path == "/clients" {
|
||||
return httpJSONAny(r, http.StatusOK, []map[string]interface{}{
|
||||
{"client_id": "client-owned", "client_name": "Owned App", "metadata": map[string]interface{}{"tenant_id": "tenant-a"}},
|
||||
{"client_id": "client-other", "client_name": "Other App", "metadata": map[string]interface{}{"tenant_id": "tenant-a"}},
|
||||
return httpJSONAny(r, http.StatusOK, []map[string]any{
|
||||
{"client_id": "client-owned", "client_name": "Owned App", "metadata": map[string]any{"tenant_id": "tenant-a"}},
|
||||
{"client_id": "client-other", "client_name": "Other App", "metadata": map[string]any{"tenant_id": "tenant-a"}},
|
||||
}), nil
|
||||
}
|
||||
return httpJSONAny(r, http.StatusNotFound, nil), nil
|
||||
@@ -1997,7 +1997,7 @@ func TestCreateClient_DefaultsSkipConsentToTrue(t *testing.T) {
|
||||
|
||||
func TestNormalizeClientAutoLoginMetadata(t *testing.T) {
|
||||
t.Run("keeps supported flag and URL", func(t *testing.T) {
|
||||
metadata, err := normalizeClientAutoLoginMetadata(map[string]interface{}{
|
||||
metadata, err := normalizeClientAutoLoginMetadata(map[string]any{
|
||||
"auto_login_supported": true,
|
||||
"auto_login_url": "https://rp.example.com/login?auto=1",
|
||||
})
|
||||
@@ -2007,14 +2007,14 @@ func TestNormalizeClientAutoLoginMetadata(t *testing.T) {
|
||||
})
|
||||
|
||||
t.Run("requires URL when supported", func(t *testing.T) {
|
||||
_, err := normalizeClientAutoLoginMetadata(map[string]interface{}{
|
||||
_, err := normalizeClientAutoLoginMetadata(map[string]any{
|
||||
"auto_login_supported": true,
|
||||
})
|
||||
assert.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("removes URL when unsupported", func(t *testing.T) {
|
||||
metadata, err := normalizeClientAutoLoginMetadata(map[string]interface{}{
|
||||
metadata, err := normalizeClientAutoLoginMetadata(map[string]any{
|
||||
"auto_login_supported": false,
|
||||
"auto_login_url": "https://rp.example.com/login?auto=1",
|
||||
})
|
||||
@@ -2293,9 +2293,9 @@ func TestCreateClient_NormalizesIDTokenClaimsMetadata(t *testing.T) {
|
||||
resp, _ := app.Test(req, -1)
|
||||
assert.Equal(t, http.StatusCreated, resp.StatusCode)
|
||||
|
||||
claims, ok := captured.Metadata[domain.MetadataIDTokenClaims].([]interface{})
|
||||
claims, ok := captured.Metadata[domain.MetadataIDTokenClaims].([]any)
|
||||
if assert.True(t, ok) && assert.Len(t, claims, 2) {
|
||||
first, ok := claims[0].(map[string]interface{})
|
||||
first, ok := claims[0].(map[string]any)
|
||||
if assert.True(t, ok) {
|
||||
assert.Equal(t, "top_level", first["namespace"])
|
||||
assert.Equal(t, "locale", first["key"])
|
||||
@@ -2305,7 +2305,7 @@ func TestCreateClient_NormalizesIDTokenClaimsMetadata(t *testing.T) {
|
||||
assert.False(t, hasID)
|
||||
}
|
||||
|
||||
second, ok := claims[1].(map[string]interface{})
|
||||
second, ok := claims[1].(map[string]any)
|
||||
if assert.True(t, ok) {
|
||||
assert.Equal(t, "rp_claims", second["namespace"])
|
||||
assert.Equal(t, "tier", second["key"])
|
||||
@@ -2464,7 +2464,7 @@ func TestUpdateClient_AllowsExplicitSkipConsentFalse(t *testing.T) {
|
||||
Scope: "openid profile",
|
||||
TokenEndpointAuthMethod: "none",
|
||||
SkipConsent: ¤tSkipConsent,
|
||||
Metadata: map[string]interface{}{"status": "active"},
|
||||
Metadata: map[string]any{"status": "active"},
|
||||
}), nil
|
||||
}
|
||||
if r.Method == http.MethodPut && r.URL.Path == "/clients/client-1" {
|
||||
@@ -2620,7 +2620,7 @@ func TestUpdateClient_RevokesExistingConsentsWhenTenantPolicyChanges(t *testing.
|
||||
ResponseTypes: []string{"code"},
|
||||
Scope: "openid tenant profile email",
|
||||
TokenEndpointAuthMethod: "none",
|
||||
Metadata: map[string]interface{}{
|
||||
Metadata: map[string]any{
|
||||
"tenant_access_restricted": true,
|
||||
"allowed_tenants": []string{"tenant-a"},
|
||||
},
|
||||
@@ -2704,7 +2704,7 @@ func TestUpdateClient_DoesNotRevokeConsentsWhenTenantPolicyUnchanged(t *testing.
|
||||
ResponseTypes: []string{"code"},
|
||||
Scope: "openid tenant profile email",
|
||||
TokenEndpointAuthMethod: "none",
|
||||
Metadata: map[string]interface{}{
|
||||
Metadata: map[string]any{
|
||||
"tenant_access_restricted": true,
|
||||
"allowed_tenants": []string{"tenant-a"},
|
||||
},
|
||||
@@ -2991,9 +2991,9 @@ func TestListAuditLogs_UserAllowedByRPAuditPermission(t *testing.T) {
|
||||
}
|
||||
transport := roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.URL.Path == "/clients" {
|
||||
return httpJSONAny(r, http.StatusOK, []map[string]interface{}{
|
||||
{"client_id": "client-allowed", "client_name": "Allowed App", "metadata": map[string]interface{}{"tenant_id": "tenant-a"}},
|
||||
{"client_id": "client-denied", "client_name": "Denied App", "metadata": map[string]interface{}{"tenant_id": "tenant-b"}},
|
||||
return httpJSONAny(r, http.StatusOK, []map[string]any{
|
||||
{"client_id": "client-allowed", "client_name": "Allowed App", "metadata": map[string]any{"tenant_id": "tenant-a"}},
|
||||
{"client_id": "client-denied", "client_name": "Denied App", "metadata": map[string]any{"tenant_id": "tenant-b"}},
|
||||
}), nil
|
||||
}
|
||||
return httpJSONAny(r, http.StatusNotFound, nil), nil
|
||||
@@ -3124,7 +3124,7 @@ func TestListClientRelations_RPAdminAllowedByViewRelationshipsPermission(t *test
|
||||
mockKratos := new(devMockKratosAdmin)
|
||||
mockKratos.On("GetIdentity", mock.Anything, "user-2").Return(&service.KratosIdentity{
|
||||
ID: "user-2",
|
||||
Traits: map[string]interface{}{
|
||||
Traits: map[string]any{
|
||||
"name": "김용연",
|
||||
"email": "kyy@example.com",
|
||||
"id": "kyy01",
|
||||
@@ -3195,7 +3195,7 @@ func TestListClientRelations_DedupesDuplicateRelations(t *testing.T) {
|
||||
mockKratos := new(devMockKratosAdmin)
|
||||
mockKratos.On("GetIdentity", mock.Anything, "user-1").Return(&service.KratosIdentity{
|
||||
ID: "user-1",
|
||||
Traits: map[string]interface{}{
|
||||
Traits: map[string]any{
|
||||
"name": "Tester",
|
||||
"email": "tester@example.com",
|
||||
},
|
||||
@@ -3371,7 +3371,7 @@ func TestSearchUsers_RPAdminSearchByNameOrEmailWithinTenantScope(t *testing.T) {
|
||||
mockKratos.On("ListIdentities", mock.Anything).Return([]service.KratosIdentity{
|
||||
{
|
||||
ID: "user-1",
|
||||
Traits: map[string]interface{}{
|
||||
Traits: map[string]any{
|
||||
"name": "Alice Kim",
|
||||
"email": "alice@example.com",
|
||||
"id": "alice01",
|
||||
@@ -3380,7 +3380,7 @@ func TestSearchUsers_RPAdminSearchByNameOrEmailWithinTenantScope(t *testing.T) {
|
||||
},
|
||||
{
|
||||
ID: "user-2",
|
||||
Traits: map[string]interface{}{
|
||||
Traits: map[string]any{
|
||||
"name": "Bob Lee",
|
||||
"email": "bob@example.com",
|
||||
"id": "bob01",
|
||||
@@ -3451,7 +3451,7 @@ func TestSearchUsers_UserAllowedByRPAdminRelation(t *testing.T) {
|
||||
mockKratos.On("ListIdentities", mock.Anything).Return([]service.KratosIdentity{
|
||||
{
|
||||
ID: "target-user",
|
||||
Traits: map[string]interface{}{
|
||||
Traits: map[string]any{
|
||||
"name": "김용연",
|
||||
"email": "kyy@example.com",
|
||||
"id": "kyy01",
|
||||
|
||||
Reference in New Issue
Block a user