- Added internal/vault/client.go for creating a Vault client with configuration settings. - Introduced internal/vault/errors.go to classify Vault API errors for better UI handling. - Created internal/vault/kv.go to manage KV secrets, including listing, reading, writing, and deleting operations. - Implemented internal/vault/mounts.go to list and describe secret engine mounts. - Developed internal/vault/service.go to provide a unified entry point for Vault operations. - Added internal/vault/kv_test.go for comprehensive testing of KV operations. - Introduced internal/ui/toast.go for transient notifications in the UI. - Added renovate.json for dependency management and updates.
101 lines
2.6 KiB
Go
101 lines
2.6 KiB
Go
package auth
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
// EnvAuthParamPrefix + strings.ToUpper(Field.Name) is consulted by Prefill
|
|
// alongside each Field's own EnvFallback list, so any field can be
|
|
// overridden from the environment even if the method author didn't think
|
|
// to name a specific var for it.
|
|
const EnvAuthParamPrefix = "VAULT_TUI_AUTH_"
|
|
|
|
// PrefillSource is everything Prefill draws from, ordered highest priority
|
|
// first: CLIArgs > env fallback / VAULT_TUI_AUTH_* > ConfigArgs > Field.Default.
|
|
type PrefillSource struct {
|
|
CLIArgs map[string]string // `vault-tui login -method=x role=eng`
|
|
ConfigArgs map[string]string // profile.auth.params
|
|
LookupEnv func(string) (string, bool)
|
|
}
|
|
|
|
func (s PrefillSource) lookupEnv(key string) (string, bool) {
|
|
if s.LookupEnv != nil {
|
|
return s.LookupEnv(key)
|
|
}
|
|
return os.LookupEnv(key)
|
|
}
|
|
|
|
// Prefill resolves each of m's fields' initial value from src, in
|
|
// precedence order: CLIArgs > Field.EnvFallback > VAULT_TUI_AUTH_<NAME> >
|
|
// ConfigArgs > Field.Default.
|
|
func Prefill(m Method, src PrefillSource) Credentials {
|
|
out := Credentials{}
|
|
for _, f := range m.Fields() {
|
|
key := f.ConfigKey
|
|
if key == "" {
|
|
key = f.Name
|
|
}
|
|
|
|
if v, ok := src.CLIArgs[f.Name]; ok && v != "" {
|
|
out[f.Name] = v
|
|
continue
|
|
}
|
|
found := false
|
|
for _, envKey := range f.EnvFallback {
|
|
if v, ok := src.lookupEnv(envKey); ok && v != "" {
|
|
out[f.Name] = v
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if found {
|
|
continue
|
|
}
|
|
if v, ok := src.lookupEnv(EnvAuthParamPrefix + strings.ToUpper(f.Name)); ok && v != "" {
|
|
out[f.Name] = v
|
|
continue
|
|
}
|
|
if v, ok := src.ConfigArgs[key]; ok && v != "" {
|
|
out[f.Name] = v
|
|
continue
|
|
}
|
|
if f.Default != "" {
|
|
out[f.Name] = f.Default
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// Missing returns the Required fields that are still empty after Prefill.
|
|
// The TUI renders a form for exactly these; a headless, TTY-attached CLI
|
|
// prompts for them; a headless, non-TTY CLI should treat a non-empty result
|
|
// as a hard error (never block on stdin).
|
|
func Missing(m Method, creds Credentials) []Field {
|
|
var out []Field
|
|
for _, f := range m.Fields() {
|
|
if f.Required && !creds.Has(f.Name) {
|
|
out = append(out, f)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// Validate runs every Field.Validate and checks Required, returning the
|
|
// first error encountered.
|
|
func Validate(m Method, creds Credentials) error {
|
|
for _, f := range m.Fields() {
|
|
v, ok := creds[f.Name]
|
|
if f.Required && (!ok || v == "") {
|
|
return fmt.Errorf("missing required field %q", f.Name)
|
|
}
|
|
if ok && f.Validate != nil {
|
|
if err := f.Validate(v); err != nil {
|
|
return fmt.Errorf("field %q: %w", f.Name, err)
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|