Changeset 0.22.7 (#149)
This commit is contained in:
@@ -200,12 +200,12 @@ func setupHarness(t *testing.T) *testHarness {
|
||||
settings := NewSettingsHandler(nil)
|
||||
protected.GET("/profile", settings.GetProfile)
|
||||
|
||||
// Presets
|
||||
presets := NewPersonaHandler(stores)
|
||||
protected.GET("/presets", presets.ListUserPersonas)
|
||||
protected.POST("/presets", presets.CreateUserPersona)
|
||||
protected.GET("/presets/:id/knowledge-bases", presets.GetPersonaKBs) // v0.17.0
|
||||
protected.PUT("/presets/:id/knowledge-bases", presets.SetPersonaKBs) // v0.17.0
|
||||
// Personas
|
||||
personas := NewPersonaHandler(stores)
|
||||
protected.GET("/personas", personas.ListUserPersonas)
|
||||
protected.POST("/personas", personas.CreateUserPersona)
|
||||
protected.GET("/personas/:id/knowledge-bases", personas.GetPersonaKBs) // v0.17.0
|
||||
protected.PUT("/personas/:id/knowledge-bases", personas.SetPersonaKBs) // v0.17.0
|
||||
|
||||
// Notes
|
||||
notes := NewNoteHandler(stores)
|
||||
@@ -283,10 +283,10 @@ func setupHarness(t *testing.T) *testHarness {
|
||||
admin.GET("/teams/:id", teams.GetTeam)
|
||||
admin.GET("/teams/:id/members", teams.ListMembers)
|
||||
admin.POST("/teams/:id/members", teams.AddMember)
|
||||
admin.GET("/presets", presets.ListAdminPersonas)
|
||||
admin.POST("/presets", presets.CreateAdminPersona)
|
||||
admin.GET("/presets/:id/knowledge-bases", presets.GetPersonaKBs) // v0.17.0
|
||||
admin.PUT("/presets/:id/knowledge-bases", presets.SetPersonaKBs) // v0.17.0
|
||||
admin.GET("/personas", personas.ListAdminPersonas)
|
||||
admin.POST("/personas", personas.CreateAdminPersona)
|
||||
admin.GET("/personas/:id/knowledge-bases", personas.GetPersonaKBs) // v0.17.0
|
||||
admin.PUT("/personas/:id/knowledge-bases", personas.SetPersonaKBs) // v0.17.0
|
||||
|
||||
// Admin groups (v0.16.0)
|
||||
groupAdm := NewGroupHandler(stores)
|
||||
@@ -802,14 +802,14 @@ func TestIntegration_TeamMemberManagement(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// ── 7. Presets (Policy Gated) ────────────────
|
||||
// ── 7. Personas (Policy Gated) ───────────────
|
||||
|
||||
func TestIntegration_PresetCreation_PolicyGated(t *testing.T) {
|
||||
func TestIntegration_PersonaCreation_PolicyGated(t *testing.T) {
|
||||
h := setupHarness(t)
|
||||
adminID, adminToken := h.createAdminUser("admin", "admin@test.com")
|
||||
_ = adminID
|
||||
|
||||
// Create a provider config (presets need a valid model reference)
|
||||
// Create a provider config (personas need a valid model reference)
|
||||
w := h.request("POST", "/api/v1/admin/configs", adminToken, map[string]interface{}{
|
||||
"name": "TestProvider", "provider": "openai",
|
||||
"endpoint": "https://api.openai.com/v1", "api_key": "sk-test",
|
||||
@@ -821,13 +821,13 @@ func TestIntegration_PresetCreation_PolicyGated(t *testing.T) {
|
||||
// Ensure allow_user_personas = false
|
||||
database.TestDB.Exec("INSERT INTO platform_policies (key, value) VALUES ('allow_user_personas', 'false') ON CONFLICT (key) DO UPDATE SET value = 'false'")
|
||||
|
||||
// Try to create a preset as admin (role=admin but policy says no)
|
||||
w = h.request("POST", "/api/v1/presets", adminToken, map[string]interface{}{
|
||||
"name": "My Preset", "base_model_id": "gpt-4o",
|
||||
// Try to create a persona as admin (role=admin but policy says no)
|
||||
w = h.request("POST", "/api/v1/personas", adminToken, map[string]interface{}{
|
||||
"name": "My Persona", "base_model_id": "gpt-4o",
|
||||
"provider_config_id": configID, "system_prompt": "You are helpful",
|
||||
})
|
||||
if w.Code != http.StatusForbidden {
|
||||
t.Fatalf("preset create with policy=false: want 403, got %d: %s", w.Code, w.Body.String())
|
||||
t.Fatalf("persona create with policy=false: want 403, got %d: %s", w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
// Enable the policy
|
||||
@@ -835,18 +835,18 @@ func TestIntegration_PresetCreation_PolicyGated(t *testing.T) {
|
||||
map[string]interface{}{"value": "true"})
|
||||
|
||||
// Now creation should succeed
|
||||
w = h.request("POST", "/api/v1/presets", adminToken, map[string]interface{}{
|
||||
"name": "My Preset", "base_model_id": "gpt-4o",
|
||||
w = h.request("POST", "/api/v1/personas", adminToken, map[string]interface{}{
|
||||
"name": "My Persona", "base_model_id": "gpt-4o",
|
||||
"provider_config_id": configID, "system_prompt": "You are helpful",
|
||||
})
|
||||
if w.Code != http.StatusCreated {
|
||||
t.Fatalf("preset create with policy=true: want 201, got %d: %s", w.Code, w.Body.String())
|
||||
t.Fatalf("persona create with policy=true: want 201, got %d: %s", w.Code, w.Body.String())
|
||||
}
|
||||
|
||||
// List presets
|
||||
w = h.request("GET", "/api/v1/presets", adminToken, nil)
|
||||
// List personas
|
||||
w = h.request("GET", "/api/v1/personas", adminToken, nil)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("list presets: want 200, got %d: %s", w.Code, w.Body.String())
|
||||
t.Fatalf("list personas: want 200, got %d: %s", w.Code, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1105,7 +1105,7 @@ func TestIntegration_AdminModelFetchEnableUserSees(t *testing.T) {
|
||||
t.Error("MISSING: model_id — required for composite ID")
|
||||
}
|
||||
|
||||
// source required for preset detection
|
||||
// source required for persona detection
|
||||
if m["source"] == nil || m["source"] == "" {
|
||||
t.Error("MISSING: source — frontend uses this to distinguish catalog vs persona")
|
||||
}
|
||||
@@ -2748,7 +2748,7 @@ func TestResourceGrants(t *testing.T) {
|
||||
decode(w, &group)
|
||||
|
||||
// Create a persona (admin)
|
||||
w = h.request("POST", "/api/v1/admin/presets", adminToken, map[string]interface{}{
|
||||
w = h.request("POST", "/api/v1/admin/personas", adminToken, map[string]interface{}{
|
||||
"name": "Test Bot",
|
||||
"base_model_id": "test-model",
|
||||
"scope": "global",
|
||||
@@ -2840,11 +2840,11 @@ func TestGroupBasedPersonaAccess(t *testing.T) {
|
||||
}
|
||||
|
||||
// ── User should NOT see team persona ──
|
||||
w = h.request("GET", "/api/v1/presets", userToken, nil)
|
||||
var presetsResp map[string]interface{}
|
||||
decode(w, &presetsResp)
|
||||
presets, _ := presetsResp["presets"].([]interface{})
|
||||
for _, p := range presets {
|
||||
w = h.request("GET", "/api/v1/personas", userToken, nil)
|
||||
var personasResp map[string]interface{}
|
||||
decode(w, &personasResp)
|
||||
personas, _ := personasResp["personas"].([]interface{})
|
||||
for _, p := range personas {
|
||||
pm := p.(map[string]interface{})
|
||||
if pm["id"] == personaID {
|
||||
t.Fatalf("user should NOT see team persona without group access")
|
||||
@@ -2872,14 +2872,14 @@ func TestGroupBasedPersonaAccess(t *testing.T) {
|
||||
}
|
||||
|
||||
// ── User should NOW see team persona via group grant ──
|
||||
w = h.request("GET", "/api/v1/presets", userToken, nil)
|
||||
w = h.request("GET", "/api/v1/personas", userToken, nil)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("list presets: want 200, got %d: %s", w.Code, w.Body.String())
|
||||
t.Fatalf("list personas: want 200, got %d: %s", w.Code, w.Body.String())
|
||||
}
|
||||
decode(w, &presetsResp)
|
||||
presets, _ = presetsResp["presets"].([]interface{})
|
||||
decode(w, &personasResp)
|
||||
personas, _ = personasResp["personas"].([]interface{})
|
||||
found := false
|
||||
for _, p := range presets {
|
||||
for _, p := range personas {
|
||||
pm := p.(map[string]interface{})
|
||||
if pm["id"] == personaID {
|
||||
found = true
|
||||
@@ -2887,16 +2887,16 @@ func TestGroupBasedPersonaAccess(t *testing.T) {
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatalf("user should see team persona after group grant, but didn't find it in %d presets (response: %s)", len(presets), w.Body.String())
|
||||
t.Fatalf("user should see team persona after group grant, but didn't find it in %d personas (response: %s)", len(personas), w.Body.String())
|
||||
}
|
||||
|
||||
// ── Remove user from group → should lose access ──
|
||||
w = h.request("DELETE", fmt.Sprintf("/api/v1/admin/groups/%s/members/%s", group.ID, userID), adminToken, nil)
|
||||
|
||||
w = h.request("GET", "/api/v1/presets", userToken, nil)
|
||||
decode(w, &presetsResp)
|
||||
presets, _ = presetsResp["presets"].([]interface{})
|
||||
for _, p := range presets {
|
||||
w = h.request("GET", "/api/v1/personas", userToken, nil)
|
||||
decode(w, &personasResp)
|
||||
personas, _ = personasResp["personas"].([]interface{})
|
||||
for _, p := range personas {
|
||||
pm := p.(map[string]interface{})
|
||||
if pm["id"] == personaID {
|
||||
t.Fatalf("user should NOT see persona after group removal")
|
||||
@@ -2915,7 +2915,7 @@ func TestIntegration_PersonaKB_Binding(t *testing.T) {
|
||||
_, adminToken := h.createAdminUser("admin", "admin@test.com")
|
||||
|
||||
// 1. Create a global persona via admin API
|
||||
w := h.request("POST", "/api/v1/admin/presets", adminToken, map[string]interface{}{
|
||||
w := h.request("POST", "/api/v1/admin/personas", adminToken, map[string]interface{}{
|
||||
"name": "KB Persona",
|
||||
"base_model_id": "test-model",
|
||||
"system_prompt": "You are a test persona.",
|
||||
@@ -2941,7 +2941,7 @@ func TestIntegration_PersonaKB_Binding(t *testing.T) {
|
||||
|
||||
// 3. Bind KB to persona
|
||||
w = h.request("PUT",
|
||||
fmt.Sprintf("/api/v1/admin/presets/%s/knowledge-bases", personaID),
|
||||
fmt.Sprintf("/api/v1/admin/personas/%s/knowledge-bases", personaID),
|
||||
adminToken, map[string]interface{}{
|
||||
"kb_ids": []string{kbID},
|
||||
"auto_search": map[string]bool{kbID: true},
|
||||
@@ -2952,7 +2952,7 @@ func TestIntegration_PersonaKB_Binding(t *testing.T) {
|
||||
|
||||
// 4. Read back bindings
|
||||
w = h.request("GET",
|
||||
fmt.Sprintf("/api/v1/admin/presets/%s/knowledge-bases", personaID),
|
||||
fmt.Sprintf("/api/v1/admin/personas/%s/knowledge-bases", personaID),
|
||||
adminToken, nil)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("get persona KBs: want 200, got %d: %s", w.Code, w.Body.String())
|
||||
@@ -2973,7 +2973,7 @@ func TestIntegration_PersonaKB_Binding(t *testing.T) {
|
||||
|
||||
// 5. Unbind — send empty list
|
||||
w = h.request("PUT",
|
||||
fmt.Sprintf("/api/v1/admin/presets/%s/knowledge-bases", personaID),
|
||||
fmt.Sprintf("/api/v1/admin/personas/%s/knowledge-bases", personaID),
|
||||
adminToken, map[string]interface{}{
|
||||
"kb_ids": []string{},
|
||||
})
|
||||
@@ -2983,7 +2983,7 @@ func TestIntegration_PersonaKB_Binding(t *testing.T) {
|
||||
|
||||
// 6. Verify empty
|
||||
w = h.request("GET",
|
||||
fmt.Sprintf("/api/v1/admin/presets/%s/knowledge-bases", personaID),
|
||||
fmt.Sprintf("/api/v1/admin/personas/%s/knowledge-bases", personaID),
|
||||
adminToken, nil)
|
||||
if w.Code != http.StatusOK {
|
||||
t.Fatalf("get empty persona KBs: want 200, got %d: %s", w.Code, w.Body.String())
|
||||
|
||||
Reference in New Issue
Block a user