package token import ( "context" "strings" "git.morlana.online/f.weber/vault-tui/internal/config" ) // Source identifies which layer a resolved token came from. type Source uint8 const ( SourceNone Source = iota SourceFlag SourceEnv SourceConfig SourceStore ) func (s Source) String() string { switch s { case SourceFlag: return "flag" case SourceEnv: return "env" case SourceConfig: return "config" case SourceStore: return "store" default: return "none" } } // Resolved is the outcome of Resolve: the token plus enough provenance for // the status bar to explain itself (a common source of confusion for any // tool that shadows the Vault CLI's own ~/.vault-token). // // String/GoString are overridden so an accidental %v/%+v never leaks the // token value into a log line. type Resolved struct { Token string Source Source Origin string // e.g. "VAULT_TOKEN", "~/.vault-token", "/usr/local/bin/vault-token-helper" } func (r Resolved) String() string { if r.Token == "" { return "" } return "" } func (r Resolved) GoString() string { return r.String() } // Options is the input to Resolve. type Options struct { Flag string // --token Env string // VAULT_TOKEN, pre-read by the caller Profile *config.Profile Store Store // resolved by internal/cli from profile.token.storage Getenv func(string) (string, bool) } // Resolve applies the precedence: --token flag > VAULT_TOKEN env > // profile.token.value (discouraged) > the configured Store. func Resolve(ctx context.Context, o Options) (Resolved, error) { if v := strings.TrimSpace(o.Flag); v != "" { return Resolved{Token: v, Source: SourceFlag, Origin: "--token"}, nil } if v := strings.TrimSpace(o.Env); v != "" { return Resolved{Token: v, Source: SourceEnv, Origin: "VAULT_TOKEN"}, nil } if o.Profile != nil && o.Profile.Token.Value != "" { return Resolved{Token: o.Profile.Token.Value, Source: SourceConfig, Origin: "config token.value"}, nil } if o.Store != nil { tok, err := o.Store.Get(ctx) if err != nil { return Resolved{}, err } if tok != "" { return Resolved{Token: tok, Source: SourceStore, Origin: o.Store.Location()}, nil } } return Resolved{Source: SourceNone}, nil }