diff --git a/terraform/provider/CHANGELOG.md b/terraform/provider/CHANGELOG.md index 3bd3c4d1d6c..8baa5f810f8 100644 --- a/terraform/provider/CHANGELOG.md +++ b/terraform/provider/CHANGELOG.md @@ -20,6 +20,7 @@ longer signal it. ### Fixed +- **key**: Honor caller-supplied write-only key values when creating `litellm_key` resources without overwriting token IDs during updates - **team**: Read now decodes the `team_info` envelope `/team/info` actually returns, so team attributes refresh from the proxy instead of always falling back to the prior state ### Changed diff --git a/terraform/provider/litellm/resource_key.go b/terraform/provider/litellm/resource_key.go index 5c80198cf6a..988e137a7d7 100644 --- a/terraform/provider/litellm/resource_key.go +++ b/terraform/provider/litellm/resource_key.go @@ -145,6 +145,12 @@ func resourceKeyCreate(ctx context.Context, d *schema.ResourceData, m interface{ key := &Key{} mapResourceDataToKey(d, key) + if rawConfig := d.GetRawConfig(); !rawConfig.IsNull() { + rawKey := rawConfig.GetAttr("key") + if rawKey.IsKnown() && !rawKey.IsNull() { + key.Key = rawKey.AsString() + } + } createdKey, err := c.CreateKey(key) if err != nil { diff --git a/terraform/provider/litellm/resource_key_test.go b/terraform/provider/litellm/resource_key_test.go new file mode 100644 index 00000000000..bf53244ca25 --- /dev/null +++ b/terraform/provider/litellm/resource_key_test.go @@ -0,0 +1,65 @@ +package litellm + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "testing" + + "github.com/hashicorp/go-cty/cty" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestResourceKeyCreateUsesConfiguredKey(t *testing.T) { + var payload Key + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/key/generate": + if err := json.NewDecoder(r.Body).Decode(&payload); err != nil { + t.Error(err) + } + case "/key/info": + default: + http.NotFound(w, r) + return + } + _ = json.NewEncoder(w).Encode(Key{Key: "sk-customer-managed", TokenID: "token-id"}) + })) + defer server.Close() + + d := resourceDataWithRawKey(t, "sk-customer-managed") + diags := resourceKeyCreate(context.Background(), d, NewClient(server.URL, "sk-master", false)) + + if diags.HasError() { + t.Fatalf("create returned diagnostics: %v", diags) + } + if payload.Key != "sk-customer-managed" { + t.Fatalf("configured key was dropped from create payload: got %q", payload.Key) + } +} + +func TestMapResourceDataToKeyPreservesUpdateTokenID(t *testing.T) { + d := resourceDataWithRawKey(t, "sk-customer-managed") + key := &Key{Key: "token-id"} + + mapResourceDataToKey(d, key) + + if key.Key != "token-id" { + t.Fatalf("update token ID was overwritten: got %q", key.Key) + } +} + +func resourceDataWithRawKey(t *testing.T, key string) *schema.ResourceData { + t.Helper() + d, err := schema.InternalMap(resourceKey().Schema).Data(nil, &terraform.InstanceDiff{ + RawConfig: cty.ObjectVal(map[string]cty.Value{ + "key": cty.StringVal(key), + }), + }) + if err != nil { + t.Fatal(err) + } + return d +}