fix(terraform): honor configured key on create

Read the write-only key from raw config only during creation so it reaches LiteLLM without replacing the token ID used by updates.

Fixes BerriAI/terraform-provider-litellm#39
This commit is contained in:
Erik Bogado 2026-08-24 17:01:15 -03:00
parent ca0b951a43
commit cfcc051667
3 changed files with 72 additions and 0 deletions

View file

@ -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

View file

@ -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 {

View file

@ -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
}