package store import ( "reflect" "testing" "github.com/easyai/easyai-ai-gateway/apps/api/internal/auth" ) func TestLayeredAccessDoesNotLetAPIKeyExpandBaseline(t *testing.T) { model := PlatformModel{ID: "model-1", PlatformID: "platform-1", BaseModelID: "base-1"} groupUser := &auth.User{GatewayUserID: "user-1", UserGroupID: "group-1", APIKeyID: "key-1"} baselineRules := []AccessRule{{ SubjectType: "user_group", SubjectID: "group-1", ResourceType: "platform_model", ResourceID: "model-1", Effect: "deny", }} keyRules := []AccessRule{{ SubjectType: "api_key", SubjectID: "key-1", ResourceType: "platform_model", ResourceID: "model-1", Effect: "allow", }} baseline := filterPlatformModelsByRuleSet([]PlatformModel{model}, baselineRules, baselineAccessRuleSubjects(groupUser), 0) actual := filterPlatformModelsByRuleSet(baseline, keyRules, apiKeyAccessRuleSubjects(groupUser), 0) if len(actual) != 0 { t.Fatalf("api key allow expanded denied baseline: %+v", actual) } } func TestAPIKeyAllowControlsOnlyMatchingKeys(t *testing.T) { model := PlatformModel{ID: "model-1", PlatformID: "platform-1"} rules := []AccessRule{{ SubjectType: "api_key", SubjectID: "key-a", ResourceType: "platform_model", ResourceID: "model-1", Effect: "allow", }} for _, test := range []struct { keyID string want int }{{"key-a", 1}, {"key-b", 0}} { user := &auth.User{APIKeyID: test.keyID} actual := filterPlatformModelsByRuleSet([]PlatformModel{model}, rules, apiKeyAccessRuleSubjects(user), 0) if len(actual) != test.want { t.Fatalf("key %s received %d models, want %d", test.keyID, len(actual), test.want) } } } func TestLayeredAccessDenyWinsAndNoRulesInherit(t *testing.T) { model := PlatformModel{ID: "model-1", PlatformID: "platform-1", ModelType: StringList{"text_generate"}} keyUser := &auth.User{APIKeyID: "key-a", APIKeyScopes: []string{"chat"}} keyUsers := map[string]*auth.User{"key-a": keyUser} if got := filterPlatformModelsByLayeredRuleSet(keyUser, []PlatformModel{model}, nil, nil, keyUsers); len(got) != 1 { t.Fatalf("key without rules did not inherit baseline: %+v", got) } rules := []AccessRule{ {SubjectType: "api_key", SubjectID: "key-a", ResourceType: "platform_model", ResourceID: "model-1", Effect: "allow"}, {SubjectType: "api_key", SubjectID: "key-a", ResourceType: "platform_model", ResourceID: "model-1", Effect: "deny"}, } if got := filterPlatformModelsByLayeredRuleSet(keyUser, []PlatformModel{model}, nil, rules, keyUsers); len(got) != 0 { t.Fatalf("matching deny did not override allow: %+v", got) } } func TestDirectUserIgnoresAPIKeyRules(t *testing.T) { model := PlatformModel{ID: "model-1", PlatformID: "platform-1", ModelType: StringList{"text_generate"}} rules := []AccessRule{{ SubjectType: "api_key", SubjectID: "key-a", ResourceType: "platform_model", ResourceID: "model-1", Effect: "allow", }} keyUsers := map[string]*auth.User{"key-a": {APIKeyID: "key-a", APIKeyScopes: []string{"chat"}}} if got := filterPlatformModelsByLayeredRuleSet(&auth.User{GatewayUserID: "user-1"}, []PlatformModel{model}, nil, rules, keyUsers); len(got) != 1 { t.Fatalf("direct user was constrained by API key exclusive rule: %+v", got) } } func TestIneffectiveAPIKeyRuleDoesNotControlAnotherKey(t *testing.T) { model := PlatformModel{ID: "model-1", PlatformID: "platform-1", ModelType: StringList{"text_generate"}} staleRule := AccessRule{SubjectType: "api_key", SubjectID: "key-a", ResourceType: "platform_model", ResourceID: "model-1", Effect: "allow"} groupDeny := AccessRule{SubjectType: "user_group", SubjectID: "group-a", ResourceType: "platform_model", ResourceID: "model-1", Effect: "deny"} keyUsers := map[string]*auth.User{ "key-a": {APIKeyID: "key-a", UserGroupID: "group-a", APIKeyScopes: []string{"chat"}}, } keyB := &auth.User{APIKeyID: "key-b", UserGroupID: "group-b", APIKeyScopes: []string{"chat"}} if got := filterPlatformModelsByLayeredRuleSet(keyB, []PlatformModel{model}, []AccessRule{groupDeny}, []AccessRule{staleRule}, keyUsers); len(got) != 1 { t.Fatalf("stale key-a rule blocked authorized key-b: %+v", got) } } func TestPlatformRuleOnlyControlsModelsItsKeyCanAccess(t *testing.T) { allowed := PlatformModel{ID: "allowed", PlatformID: "platform-1", ModelType: StringList{"image_generate"}} denied := PlatformModel{ID: "denied", PlatformID: "platform-1", ModelType: StringList{"text_generate"}} rule := AccessRule{SubjectType: "api_key", SubjectID: "key-a", ResourceType: "platform", ResourceID: "platform-1", Effect: "allow"} groupDeny := AccessRule{SubjectType: "user_group", SubjectID: "group-a", ResourceType: "platform_model", ResourceID: "denied", Effect: "deny"} ruleUser := &auth.User{APIKeyID: "key-a", UserGroupID: "group-a", APIKeyScopes: []string{"image"}} users := map[string]*auth.User{"key-a": ruleUser} if got := effectiveAPIKeyRulesForPlatformModel([]AccessRule{rule}, []AccessRule{groupDeny}, users, allowed); len(got) != 1 { t.Fatalf("platform rule should control the allowed image model: %+v", got) } if got := effectiveAPIKeyRulesForPlatformModel([]AccessRule{rule}, []AccessRule{groupDeny}, users, denied); len(got) != 0 { t.Fatalf("platform rule controlled a group-denied or scope-denied model: %+v", got) } } func TestFilterPlatformModelsByAPIKeyScopesPrunesCapabilities(t *testing.T) { models := []PlatformModel{{ ID: "model-1", ModelType: StringList{"text_generate", "image_generate"}, Capabilities: map[string]any{ "text_generate": map[string]any{"max_context_tokens": 128000}, "image_generate": map[string]any{"aspect_ratio_allowed": []any{"1:1"}}, "originalTypes": []any{"text_generate", "image_generate"}, "shared": true, }, }} actual := filterPlatformModelsByAPIKeyScopes(models, []string{"image"}) if len(actual) != 1 || !reflect.DeepEqual(actual[0].ModelType, StringList{"image_generate"}) { t.Fatalf("scope-filtered models = %+v", actual) } if _, exists := actual[0].Capabilities["text_generate"]; exists { t.Fatalf("text capability leaked into image scope: %+v", actual[0].Capabilities) } if _, exists := actual[0].Capabilities["image_generate"]; !exists { t.Fatalf("image capability was removed: %+v", actual[0].Capabilities) } if !reflect.DeepEqual(actual[0].Capabilities["originalTypes"], []string{"image_generate"}) { t.Fatalf("originalTypes not pruned: %+v", actual[0].Capabilities["originalTypes"]) } if actual[0].Capabilities["shared"] != true { t.Fatalf("shared capability metadata was removed: %+v", actual[0].Capabilities) } } func TestDiagnoseAPIKeyRulesExplainsEachInactiveLayer(t *testing.T) { rules := []AccessRule{ {ID: "gone", SubjectType: "api_key", SubjectID: "key-1", ResourceType: "platform_model", ResourceID: "gone", Effect: "allow", Status: "active"}, {ID: "revoked", SubjectType: "api_key", SubjectID: "key-1", ResourceType: "platform_model", ResourceID: "revoked", Effect: "allow", Status: "active"}, {ID: "scope", SubjectType: "api_key", SubjectID: "key-1", ResourceType: "platform_model", ResourceID: "scope", Effect: "deny", Status: "active"}, {ID: "effective", SubjectType: "api_key", SubjectID: "key-1", ResourceType: "platform_model", ResourceID: "effective", Effect: "allow", Status: "active"}, } all := []PlatformModel{{ID: "revoked"}, {ID: "scope"}, {ID: "effective"}} enabled := append([]PlatformModel(nil), all...) baseline := []PlatformModel{{ID: "scope"}, {ID: "effective"}} scoped := []PlatformModel{{ID: "effective"}} diagnostics := diagnoseAPIKeyRules("key-1", rules, all, enabled, baseline, scoped, nil) want := map[string]string{ "gone": "resource_unavailable", "revoked": "owner_access_revoked", "scope": "scope_not_allowed", "effective": "", } for _, diagnostic := range diagnostics { if diagnostic.Reason != want[diagnostic.RuleID] { t.Fatalf("diagnostic %s reason = %q, want %q", diagnostic.RuleID, diagnostic.Reason, want[diagnostic.RuleID]) } if diagnostic.Effective != (diagnostic.RuleID == "effective") { t.Fatalf("diagnostic %s effective = %v", diagnostic.RuleID, diagnostic.Effective) } } }