package settings import ( "context" "encoding/json" "os" "path/filepath" "reflect" "strings" "testing" ) func TestFixtureIsConsumedByGo(t *testing.T) { data, err := os.ReadFile("../../../contracts/settings/runtime-v1.json") if err != nil { t.Fatal(err) } var fixture struct { Version int `json:"version"` FileName string `json:"fileName"` AllowedKeys []string `json:"allowedKeys"` SecretKeys []string `json:"secretKeys"` } if err := json.Unmarshal(data, &fixture); err != nil { t.Fatal(err) } if fixture.Version != 1 || fixture.FileName != ".env.local" || len(fixture.AllowedKeys) != 25 || len(fixture.SecretKeys) != 8 { t.Fatalf("fixture = %#v", fixture) } } func TestServiceSavePreservesSecretsAndUnrelatedEnvLines(t *testing.T) { path := filepath.Join(t.TempDir(), ".env.local") original := "# operator note\nDATABASE_URL=postgres://untouched\nZHINIAN_AUTH_SESSION_SECRET=keep-me\nZHINIAN_BILLING_CONTACT=old # prior\nCUSTOM_QUOTED=\"a b\"\n" if err := os.WriteFile(path, []byte(original), 0o600); err != nil { t.Fatal(err) } environment := map[string]string{"EVOLINK_BASE_URL": "https://runtime.example"} var applied map[string]string service := New(path, environment, func(_ context.Context, updates map[string]string) error { applied = clone(updates); return nil }) value, err := service.Save(context.Background(), map[string]any{ "ZHINIAN_AUTH_SESSION_SECRET": " ", "ZHINIAN_BILLING_CONTACT": " ", "EVOLINK_BASE_URL": " https://new.example/v1 ", "DATABASE_URL": "postgres://attack", "ALI_OSS_BUCKET": 42, }) if err != nil { t.Fatal(err) } text, err := os.ReadFile(path) if err != nil { t.Fatal(err) } got := string(text) for _, expected := range []string{"# operator note", "DATABASE_URL=postgres://untouched", "ZHINIAN_AUTH_SESSION_SECRET=keep-me", "ZHINIAN_BILLING_CONTACT=", "CUSTOM_QUOTED=\"a b\"", "EVOLINK_BASE_URL=https://new.example/v1"} { if !strings.Contains(got, expected) { t.Fatalf("file missing %q:\n%s", expected, got) } } if strings.Contains(got, "postgres://attack") || strings.Contains(got, "ALI_OSS_BUCKET=42") { t.Fatalf("unexpected unapproved update:\n%s", got) } if !reflect.DeepEqual(applied, map[string]string{"ZHINIAN_BILLING_CONTACT": "", "EVOLINK_BASE_URL": "https://new.example/v1"}) { t.Fatalf("applied = %#v", applied) } if payload := value.(Payload); !payload.RestartRequired { t.Fatal("provider setting update must declare restartRequired") } assertSecretProjection(t, value, "ZHINIAN_AUTH_SESSION_SECRET", true) } func TestServiceGetUsesInjectedEnvironmentWithoutMutatingProcess(t *testing.T) { path := filepath.Join(t.TempDir(), ".env.local") if err := os.WriteFile(path, []byte("EVOLINK_BASE_URL=file-value\nSEEDANCE_API_KEY=file-secret\n"), 0o600); err != nil { t.Fatal(err) } const sentinel = "settings-service-must-not-write-this" old, present := os.LookupEnv(sentinel) t.Cleanup(func() { if present { _ = os.Setenv(sentinel, old) } else { _ = os.Unsetenv(sentinel) } }) _ = os.Unsetenv(sentinel) service := New(path, map[string]string{"EVOLINK_BASE_URL": "runtime-value", "SEEDANCE_API_KEY": "runtime-secret"}, nil) value, err := service.Get(context.Background()) if err != nil { t.Fatal(err) } if _, exists := os.LookupEnv(sentinel); exists { t.Fatal("process environment mutated") } if got := fieldValue(t, value, "EVOLINK_BASE_URL"); got != "runtime-value" { t.Fatalf("value = %q", got) } assertSecretProjection(t, value, "SEEDANCE_API_KEY", true) } func TestServiceSynchronizesBillingAccountWithoutRequiringRestart(t *testing.T) { writer := &billingWriterStub{} service := New(filepath.Join(t.TempDir(), ".env.local"), nil, nil).WithBillingAccountWriter(writer) value, err := service.Save(context.Background(), map[string]any{ "ZHINIAN_BILLING_ACCOUNT_NAME": " Acme ", "ZHINIAN_BILLING_ACCOUNT_BANK": " Bank ", "ZHINIAN_BILLING_ACCOUNT_NUMBER": " 123 ", "ZHINIAN_BILLING_CONTACT": " Ops ", }) if err != nil { t.Fatal(err) } if writer.value != (BillingAccount{AccountName: "Acme", BankName: "Bank", AccountNumber: "123", Contact: "Ops"}) { t.Fatalf("billing account=%#v", writer.value) } if value.(Payload).RestartRequired { t.Fatal("billing account update should be applied immediately") } } func TestServicePartialBillingUpdatePreservesPersistedSiblingFields(t *testing.T) { path := filepath.Join(t.TempDir(), ".env.local") if err := os.WriteFile(path, []byte("ZHINIAN_BILLING_ACCOUNT_NAME=Acme\nZHINIAN_BILLING_ACCOUNT_BANK=Legacy Bank\nZHINIAN_BILLING_ACCOUNT_NUMBER=123\nZHINIAN_BILLING_CONTACT=Old Ops\n"), 0o600); err != nil { t.Fatal(err) } writer := &billingWriterStub{} service := New(path, nil, nil).WithBillingAccountWriter(writer) if _, err := service.Save(context.Background(), map[string]any{"ZHINIAN_BILLING_CONTACT": "New Ops"}); err != nil { t.Fatal(err) } want := BillingAccount{AccountName: "Acme", BankName: "Legacy Bank", AccountNumber: "123", Contact: "New Ops"} if writer.value != want { t.Fatalf("billing account=%#v want %#v", writer.value, want) } } type billingWriterStub struct{ value BillingAccount } func (writer *billingWriterStub) SaveBillingAccount(_ context.Context, value BillingAccount) error { writer.value = value return nil } func fieldValue(t *testing.T, value any, key string) string { t.Helper() payload := value.(Payload) for _, group := range payload.Groups { for _, field := range group.Fields { if field.Key == key { return field.Value } } } t.Fatalf("field %s not found", key) return "" } func assertSecretProjection(t *testing.T, value any, key string, configured bool) { t.Helper() payload := value.(Payload) for _, group := range payload.Groups { for _, field := range group.Fields { if field.Key == key { if field.Value != "" || field.Configured != configured { t.Fatalf("field = %#v", field) } return } } } t.Fatalf("field %s not found", key) } func clone(input map[string]string) map[string]string { output := map[string]string{} for key, value := range input { output[key] = value } return output }