mirror of
https://github.com/lukaszraczylo/traefik-llmgateway.git
synced 2026-10-19 05:47:48 +00:00
feat: secret resolution (literal, env, file)
This commit is contained in:
+37
@@ -0,0 +1,37 @@
|
|||||||
|
package traefikllmgateway
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// resolveSecret resolves a config string value to its underlying secret. An
|
||||||
|
// empty value returns empty with no error. A "env:NAME" value returns
|
||||||
|
// os.Getenv(NAME), erroring if the variable is unset or empty. A
|
||||||
|
// "file:/path" value returns the file's contents with surrounding
|
||||||
|
// whitespace trimmed, erroring if the file cannot be read. Any other value
|
||||||
|
// is returned unchanged as a literal.
|
||||||
|
//
|
||||||
|
// Error messages never include a resolved secret value — only the env var
|
||||||
|
// name or file path, which are config, not secrets.
|
||||||
|
func resolveSecret(v string) (string, error) {
|
||||||
|
if v == "" {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
if name, ok := strings.CutPrefix(v, "env:"); ok {
|
||||||
|
val := os.Getenv(name)
|
||||||
|
if val == "" {
|
||||||
|
return "", fmt.Errorf("llmgateway: env var %q is unset or empty", name)
|
||||||
|
}
|
||||||
|
return val, nil
|
||||||
|
}
|
||||||
|
if path, ok := strings.CutPrefix(v, "file:"); ok {
|
||||||
|
b, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("llmgateway: cannot read secret file %q: %w", path, err)
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(string(b)), nil
|
||||||
|
}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package traefikllmgateway
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestResolveSecret(t *testing.T) {
|
||||||
|
t.Setenv("LLMGW_T", "from-env")
|
||||||
|
dir := t.TempDir()
|
||||||
|
fp := filepath.Join(dir, "k")
|
||||||
|
if err := os.WriteFile(fp, []byte("from-file\n"), 0o600); err != nil {
|
||||||
|
t.Fatalf("WriteFile: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cases := []struct {
|
||||||
|
in string
|
||||||
|
want string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{"plain", "plain", false},
|
||||||
|
{"env:LLMGW_T", "from-env", false},
|
||||||
|
{"env:LLMGW_MISSING", "", true},
|
||||||
|
{"file:" + fp, "from-file", false},
|
||||||
|
{"file:" + fp + ".nope", "", true},
|
||||||
|
{"", "", false},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
t.Run(c.in, func(t *testing.T) {
|
||||||
|
got, err := resolveSecret(c.in)
|
||||||
|
if (err != nil) != c.wantErr || got != c.want {
|
||||||
|
t.Errorf("resolveSecret(%q) = %q, %v; wantErr %v", c.in, got, err, c.wantErr)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user