2026-05-23 18:11:36 +00:00
|
|
|
package llm
|
|
|
|
|
|
2026-11-10 16:50:29 +00:00
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"os"
|
2026-11-10 20:29:59 +00:00
|
|
|
"strings"
|
2026-05-23 18:11:36 +00:00
|
|
|
|
2026-11-10 16:50:29 +00:00
|
|
|
"gitea.maximumdirect.net/eric/audita/v3/internal/core/redaction"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// ConfiguredSecrets obtains only values referenced by captured credential metadata.
|
|
|
|
|
// It never selects a credential or treats an absent value as an error.
|
|
|
|
|
func (r *Runtime) ConfiguredSecrets(ctx context.Context, additionalEnvNames ...string) []string {
|
|
|
|
|
if r == nil || r.Engine == nil {
|
2026-05-23 18:11:36 +00:00
|
|
|
return nil
|
|
|
|
|
}
|
2026-11-10 20:37:52 +00:00
|
|
|
r.credentialSourcesOnce.Do(func() {
|
|
|
|
|
r.credentialEnvNames = r.discoverCredentialEnvNames(context.WithoutCancel(ctx))
|
|
|
|
|
})
|
|
|
|
|
secrets := make([]string, 0, len(r.credentialEnvNames)+len(additionalEnvNames))
|
|
|
|
|
read := func(name string) {
|
|
|
|
|
if value := os.Getenv(name); value != "" {
|
|
|
|
|
secrets = append(secrets, value)
|
|
|
|
|
// PromptKit trims the value before sending it to the provider.
|
|
|
|
|
if trimmed := strings.TrimSpace(value); trimmed != "" && trimmed != value {
|
|
|
|
|
secrets = append(secrets, trimmed)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for name := range r.credentialEnvNames {
|
|
|
|
|
read(name)
|
|
|
|
|
}
|
|
|
|
|
if len(additionalEnvNames) > 0 {
|
|
|
|
|
seen := make(map[string]struct{}, len(additionalEnvNames))
|
|
|
|
|
for _, name := range additionalEnvNames {
|
|
|
|
|
if _, known := r.credentialEnvNames[name]; known {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if _, duplicate := seen[name]; name == "" || duplicate {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
seen[name] = struct{}{}
|
|
|
|
|
read(name)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return secrets
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *Runtime) discoverCredentialEnvNames(ctx context.Context) map[string]struct{} {
|
2026-11-10 16:50:29 +00:00
|
|
|
names := make(map[string]struct{})
|
|
|
|
|
add := func(name *string) {
|
|
|
|
|
if name != nil && *name != "" {
|
|
|
|
|
names[*name] = struct{}{}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ids, err := r.Engine.ListProfiles(ctx); err == nil {
|
|
|
|
|
for _, id := range ids {
|
|
|
|
|
if profile, err := r.Engine.InspectProfile(ctx, id); err == nil {
|
|
|
|
|
add(profile.APIKeyEnv)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ids, err := r.Engine.ListBackends(ctx); err == nil {
|
|
|
|
|
for _, id := range ids {
|
|
|
|
|
if backend, err := r.Engine.InspectBackend(ctx, id); err == nil {
|
|
|
|
|
add(backend.APIKeyEnv)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-11-10 20:37:52 +00:00
|
|
|
return names
|
2026-05-23 18:11:36 +00:00
|
|
|
}
|
2026-11-10 16:50:29 +00:00
|
|
|
|
|
|
|
|
func (r *Runtime) RedactError(ctx context.Context, err error, additionalEnvNames ...string) string {
|
|
|
|
|
if err == nil {
|
|
|
|
|
return ""
|
|
|
|
|
}
|
|
|
|
|
return redaction.New(r.ConfiguredSecrets(ctx, additionalEnvNames...)).String(err.Error())
|
|
|
|
|
}
|