mirror of
https://github.com/mudler/LocalAI.git
synced 2026-10-28 09:08:54 -04:00
* feat(proxy): accept direct upstream API keys Support direct credentials for models created in the UI. Keep env and file references as mutually exclusive alternatives. Use model env for frontend probes and omit credentials from structured config logs. Assisted-by: nib:gpt-6.1-sol Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * feat(distributed): isolate model environments in worker processes Forward complete model environment snapshots through backend installation. Restart worker children when overrides change or are removed, and include keyed snapshot identities in frontend install coalescing. Cover wire compatibility, routing, real worker children, and option copying; document rollout requirements and control-transport security. Assisted-by: nib:gpt-6.1-sol Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * fix(worker): serialize installs by model replica Different backend names can target the same process slot. Hold a slot lock through startup, readiness, and operation attachment so concurrent installs cannot reuse another configuration or an unready child. Assisted-by: nib:gpt-6.1-sol Signed-off-by: Ettore Di Giacinto <mudler@localai.io> * test(nodes): update endpoint stub for model env Keep the endpoint command stub aligned with the environment-aware install interface. Assert interface conformance so future changes fail at the stub declaration rather than at endpoint call sites. Assisted-by: nib:gpt-6.1-sol Signed-off-by: Ettore Di Giacinto <mudler@localai.io> --------- Signed-off-by: Ettore Di Giacinto <mudler@localai.io> Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
45 lines
1.6 KiB
Go
45 lines
1.6 KiB
Go
// SPDX-License-Identifier: MIT
|
|
package config
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
"gopkg.in/yaml.v3"
|
|
"log/slog"
|
|
)
|
|
|
|
var _ = Describe("Proxy credentials", func() {
|
|
It("preserves and resolves a direct admin credential", func() {
|
|
var p ProxyConfig
|
|
Expect(json.Unmarshal([]byte(`{"api_key":"fake-direct-key"}`), &p)).To(Succeed())
|
|
key, err := p.ResolveAPIKey(nil)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(key).To(Equal("fake-direct-key"))
|
|
encoded, err := json.Marshal(p)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(string(encoded)).To(ContainSubstring(`"api_key":"fake-direct-key"`))
|
|
})
|
|
It("rejects direct credentials combined with another source", func() {
|
|
var c ModelConfig
|
|
Expect(json.Unmarshal([]byte(`{"proxy":{"api_key":"fake-key","api_key_env":"OTHER"}}`), &c)).To(Succeed())
|
|
_, err := c.Validate()
|
|
Expect(err).To(HaveOccurred())
|
|
})
|
|
})
|
|
|
|
var _ = Describe("Proxy credential logging", func() {
|
|
It("keeps secrets out of structured config logs without changing storage", func() {
|
|
var output bytes.Buffer
|
|
logger := slog.New(slog.NewJSONHandler(&output, nil))
|
|
c := ModelConfig{Proxy: ProxyConfig{APIKey: "fake-direct-secret"}, Environment: map[string]string{"KEY": "fake-env-secret"}}
|
|
logger.Info("config", "config", c, "proxy", c.Proxy)
|
|
Expect(output.String()).NotTo(ContainSubstring("fake-direct-secret"))
|
|
Expect(output.String()).NotTo(ContainSubstring("fake-env-secret"))
|
|
data, err := yaml.Marshal(c)
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(string(data)).To(ContainSubstring("fake-direct-secret"))
|
|
})
|
|
})
|