mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-11 08:38:24 +00:00
Merge a2b2d4954c into e16d79d635
This commit is contained in:
commit
cd9ac46505
3 changed files with 92 additions and 0 deletions
|
|
@ -51,6 +51,7 @@ longer signal it.
|
|||
|
||||
### Fixed
|
||||
|
||||
- **key**: Updates no longer resend unchanged `allowed_passthrough_routes`, avoiding an Enterprise-only 403 on OSS proxies when passthrough metadata is managed outside Terraform
|
||||
- **model**: `additional_drop_params` in `litellm_model.additional_litellm_params` is now sent to the proxy as the deployment's `additional_drop_params` list, the same list a `model_list` entry takes. Before, the provider never sent the list and instead deleted every key it named from `litellm_params`, so a `store` or `vertex_location` listed there was lost and requests still carried the parameters (#38349). The value must be a JSON list of parameter names such as `jsonencode(["store"])`, which `terraform plan` now checks, and `null` entries are skipped as before. When the configuration sets the list, refresh reads the stored list back from the proxy, so a list changed outside Terraform shows up as drift. On a model an older provider created, the proxy has no stored list, so the first plan after upgrading shows the list and every listed key the configuration sets as changes, since that apply writes them. A write-only secret such as `model_api_key_wo` is never shown in a plan
|
||||
- **user**: `litellm_user` updates no longer send `blocked`, which `/user/update` writes into the user table where no such column exists, so every update failed with a 400 (`Could not find field at upsertOneLiteLLM_UserTable.create.blocked`). Create still sends `blocked`, including `false`, so a `default_internal_user_params.blocked` on the proxy cannot block the auto-created key. Changing `blocked` after creation has no effect, since the proxy has no user-level block; use `litellm_key_block` instead
|
||||
- **model**: `litellm_model` refresh now reads the `{"data": [...]}` envelope `/model/info` returns, so `model_info` fields changed outside Terraform show up as drift instead of silently keeping the previous state
|
||||
|
|
|
|||
|
|
@ -372,6 +372,9 @@ func resourceKeyUpdate(ctx context.Context, d *schema.ResourceData, m interface{
|
|||
if allowedRoutesNotConfigured(d) {
|
||||
key.AllowedRoutes = nil
|
||||
}
|
||||
if !d.HasChange("allowed_passthrough_routes") {
|
||||
key.AllowedPassthroughRoutes = nil
|
||||
}
|
||||
if !d.HasChange("duration") {
|
||||
key.Duration = ""
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package litellm
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
|
@ -965,6 +966,93 @@ func applyKeyUpdate(t *testing.T, client *Client, stateAttrs map[string]string,
|
|||
return newState
|
||||
}
|
||||
|
||||
func TestKeyUpdateOmitsUnchangedPassthroughRoutes(t *testing.T) {
|
||||
for _, field := range []string{"models", "allowed_routes"} {
|
||||
t.Run(field, func(t *testing.T) {
|
||||
const route = "/direct/openai/v1/batches"
|
||||
proxy := &fakeKeyProxy{metadata: map[string]interface{}{
|
||||
"allowed_passthrough_routes": []string{route},
|
||||
"server_side": "preserved",
|
||||
}}
|
||||
handler := proxy.handler()
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if r.URL.Path == "/key/update" {
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
http.Error(w, "invalid test request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
var payload map[string]interface{}
|
||||
if err := json.Unmarshal(body, &payload); err != nil {
|
||||
t.Error(err)
|
||||
http.Error(w, "invalid test request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
if _, present := payload["allowed_passthrough_routes"]; present {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
w.Write([]byte(`{"error":"Enterprise required: allowed_passthrough_routes"}`))
|
||||
return
|
||||
}
|
||||
r.Body = io.NopCloser(bytes.NewReader(body))
|
||||
}
|
||||
handler(w, r)
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
applyKeyUpdate(t, NewClient(srv.URL, "test-key", true),
|
||||
map[string]string{
|
||||
"key_alias": "alias-1",
|
||||
"allowed_passthrough_routes.#": "1",
|
||||
"allowed_passthrough_routes.0": route,
|
||||
"blocked": "true",
|
||||
field + ".#": "1",
|
||||
field + ".0": "previous",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"key_alias": "alias-1",
|
||||
"allowed_passthrough_routes": []interface{}{route},
|
||||
"blocked": true,
|
||||
field: []interface{}{"replacement"},
|
||||
},
|
||||
)
|
||||
if len(proxy.updates) != 1 {
|
||||
t.Fatalf("expected one update, got %d", len(proxy.updates))
|
||||
}
|
||||
if got := proxy.updates[0][field]; !reflect.DeepEqual(got, []interface{}{"replacement"}) {
|
||||
t.Errorf("%s = %v, want [replacement]", field, got)
|
||||
}
|
||||
if proxy.updates[0]["blocked"] != true {
|
||||
t.Error("update must preserve the operator's block")
|
||||
}
|
||||
if proxy.metadata["server_side"] != "preserved" ||
|
||||
!reflect.DeepEqual(proxy.metadata["allowed_passthrough_routes"], []string{route}) {
|
||||
t.Errorf("server metadata changed: %v", proxy.metadata)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyUpdateSendsChangedPassthroughRoutes(t *testing.T) {
|
||||
proxy := &fakeKeyProxy{metadata: map[string]interface{}{}}
|
||||
srv := httptest.NewServer(proxy.handler())
|
||||
defer srv.Close()
|
||||
applyKeyUpdate(t, NewClient(srv.URL, "test-key", true),
|
||||
map[string]string{
|
||||
"key_alias": "alias-1",
|
||||
"allowed_passthrough_routes.#": "1",
|
||||
"allowed_passthrough_routes.0": "/previous",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"key_alias": "alias-1",
|
||||
"allowed_passthrough_routes": []interface{}{"/replacement"},
|
||||
},
|
||||
)
|
||||
if got := proxy.updates[0]["allowed_passthrough_routes"]; !reflect.DeepEqual(got, []interface{}{"/replacement"}) {
|
||||
t.Errorf("changed passthrough routes = %v, want [/replacement]", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeyUpdateWithoutMetadataChangePreservesServerMetadata(t *testing.T) {
|
||||
proxy := &fakeKeyProxy{metadata: map[string]interface{}{"a": "1", "server_side": "x", "model_rpm_limit": map[string]interface{}{"gpt-4o-mini": float64(5)}}}
|
||||
srv := httptest.NewServer(proxy.handler())
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue