test(host): harden gateway and acceptance validation
This commit is contained in:
@@ -217,6 +217,89 @@ func TestSub2APIHostAdapterChecksGatewayAccess(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSub2APIHostAdapterSeparatesAccountModelsFromGatewayModels(t *testing.T) {
|
||||
server := newSub2APIStubServer(t, sub2APIStubConfig{
|
||||
requireAPIKey: true,
|
||||
version: "0.1.126",
|
||||
accountModels: []map[string]any{{"id": "deepseek-account-only", "display_name": "DeepSeek Account Only", "type": "chat"}},
|
||||
gatewayModels: []map[string]any{{"id": "deepseek-gateway-only"}},
|
||||
gatewayExpectedKey: "managed-user-key",
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
client, err := sub2api.NewClient(server.URL, sub2api.WithAPIKey("api-key"))
|
||||
if err != nil {
|
||||
t.Fatalf("NewClient() error = %v", err)
|
||||
}
|
||||
|
||||
accountModels, err := client.GetAccountModels(context.Background(), "account_1")
|
||||
if err != nil {
|
||||
t.Fatalf("GetAccountModels() error = %v", err)
|
||||
}
|
||||
if len(accountModels) != 1 || accountModels[0].ID != "deepseek-account-only" {
|
||||
t.Fatalf("GetAccountModels() = %+v, want admin account models only", accountModels)
|
||||
}
|
||||
|
||||
gatewayResult, err := client.CheckGatewayAccess(context.Background(), sub2api.GatewayAccessCheckRequest{
|
||||
APIKey: "managed-user-key",
|
||||
ExpectedModel: "deepseek-gateway-only",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CheckGatewayAccess() error = %v", err)
|
||||
}
|
||||
if !gatewayResult.OK || !gatewayResult.HasExpectedModel {
|
||||
t.Fatalf("CheckGatewayAccess() = %+v, want gateway models only", gatewayResult)
|
||||
}
|
||||
if len(gatewayResult.Models) != 1 || gatewayResult.Models[0] != "deepseek-gateway-only" {
|
||||
t.Fatalf("gateway models = %+v, want gateway-only model list", gatewayResult.Models)
|
||||
}
|
||||
if gatewayResult.Models[0] == accountModels[0].ID {
|
||||
t.Fatalf("gateway models = %+v unexpectedly matched account models %+v", gatewayResult.Models, accountModels)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSub2APIHostAdapterGatewayProbeDoesNotReuseAdminCredential(t *testing.T) {
|
||||
server := newSub2APIStubServer(t, sub2APIStubConfig{
|
||||
requireAPIKey: true,
|
||||
version: "0.1.126",
|
||||
gatewayExpectedKey: "managed-user-key",
|
||||
})
|
||||
defer server.Close()
|
||||
|
||||
client, err := sub2api.NewClient(server.URL, sub2api.WithAPIKey("api-key"))
|
||||
if err != nil {
|
||||
t.Fatalf("NewClient() error = %v", err)
|
||||
}
|
||||
|
||||
result, err := client.CheckGatewayAccess(context.Background(), sub2api.GatewayAccessCheckRequest{
|
||||
APIKey: "managed-user-key",
|
||||
ExpectedModel: "deepseek-chat",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CheckGatewayAccess() error = %v", err)
|
||||
}
|
||||
if !result.OK {
|
||||
t.Fatalf("CheckGatewayAccess() = %+v, want OK=true with managed user key", result)
|
||||
}
|
||||
|
||||
wrongKeyResult, err := client.CheckGatewayAccess(context.Background(), sub2api.GatewayAccessCheckRequest{
|
||||
APIKey: "api-key",
|
||||
ExpectedModel: "deepseek-chat",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CheckGatewayAccess() with admin key error = %v", err)
|
||||
}
|
||||
if wrongKeyResult.OK {
|
||||
t.Fatalf("CheckGatewayAccess() with admin key = %+v, want OK=false", wrongKeyResult)
|
||||
}
|
||||
if wrongKeyResult.StatusCode != http.StatusUnauthorized {
|
||||
t.Fatalf("StatusCode = %d, want %d", wrongKeyResult.StatusCode, http.StatusUnauthorized)
|
||||
}
|
||||
if wrongKeyResult.HasExpectedModel {
|
||||
t.Fatalf("CheckGatewayAccess() with admin key = %+v, want HasExpectedModel=false", wrongKeyResult)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSub2APIHostAdapterDeletesManagedResources(t *testing.T) {
|
||||
server := newSub2APIStubServer(t, sub2APIStubConfig{
|
||||
requireAPIKey: true,
|
||||
@@ -277,13 +360,35 @@ func TestSub2APIHostAdapterListManagedResources(t *testing.T) {
|
||||
}
|
||||
|
||||
type sub2APIStubConfig struct {
|
||||
requireAPIKey bool
|
||||
version string
|
||||
requireAPIKey bool
|
||||
version string
|
||||
accountModels []map[string]any
|
||||
gatewayModels []map[string]any
|
||||
gatewayExpectedKey string
|
||||
}
|
||||
|
||||
func newSub2APIStubServer(t *testing.T, cfg sub2APIStubConfig) *httptest.Server {
|
||||
t.Helper()
|
||||
|
||||
accountModels := cfg.accountModels
|
||||
if len(accountModels) == 0 {
|
||||
accountModels = []map[string]any{
|
||||
{"id": "deepseek-chat", "display_name": "DeepSeek Chat", "type": "chat"},
|
||||
{"id": "deepseek-reasoner", "display_name": "DeepSeek Reasoner", "type": "reasoning"},
|
||||
}
|
||||
}
|
||||
gatewayModels := cfg.gatewayModels
|
||||
if len(gatewayModels) == 0 {
|
||||
gatewayModels = []map[string]any{
|
||||
{"id": "deepseek-chat"},
|
||||
{"id": "deepseek-reasoner"},
|
||||
}
|
||||
}
|
||||
gatewayExpectedKey := cfg.gatewayExpectedKey
|
||||
if gatewayExpectedKey == "" {
|
||||
gatewayExpectedKey = "user-api-key"
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/api/v1/admin/system/version", func(w http.ResponseWriter, r *http.Request) {
|
||||
if !mustStubAuth(t, w, r, cfg.requireAPIKey) {
|
||||
@@ -458,10 +563,7 @@ func newSub2APIStubServer(t *testing.T, cfg sub2APIStubConfig) *httptest.Server
|
||||
}
|
||||
writeJSON(t, w, http.StatusOK, map[string]any{
|
||||
"data": map[string]any{
|
||||
"items": []map[string]any{
|
||||
{"id": "deepseek-chat", "display_name": "DeepSeek Chat", "type": "chat"},
|
||||
{"id": "deepseek-reasoner", "display_name": "DeepSeek Reasoner", "type": "reasoning"},
|
||||
},
|
||||
"items": accountModels,
|
||||
},
|
||||
})
|
||||
default:
|
||||
@@ -489,16 +591,13 @@ func newSub2APIStubServer(t *testing.T, cfg sub2APIStubConfig) *httptest.Server
|
||||
})
|
||||
})
|
||||
mux.HandleFunc("/v1/models", func(w http.ResponseWriter, r *http.Request) {
|
||||
if got := r.Header.Get("x-api-key"); got != "user-api-key" {
|
||||
if got := r.Header.Get("x-api-key"); got != gatewayExpectedKey {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
_, _ = w.Write([]byte(`{"error":"unauthorized"}`))
|
||||
return
|
||||
}
|
||||
writeJSON(t, w, http.StatusOK, map[string]any{
|
||||
"data": []map[string]any{
|
||||
{"id": "deepseek-chat"},
|
||||
{"id": "deepseek-reasoner"},
|
||||
},
|
||||
"data": gatewayModels,
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user