(chore) setup kmsvc-cli

This commit is contained in:
Story Crater Bot
2026-08-17 10:14:44 -07:00
commit d1c7f75cae
22 changed files with 1664 additions and 0 deletions
+112
View File
@@ -0,0 +1,112 @@
package cli
import (
"os"
"path/filepath"
"gopkg.in/yaml.v3"
)
// Config holds resolved CLI defaults. Precedence (highest to lowest):
// command-line flag > environment variable > ~/.kmsvc/config.yaml > built-in default.
type Config struct {
Server string
Token string
Output string
Insecure bool
ClientID string
ClientSecret string
TokenURL string
}
type fileConfig struct {
Server string `yaml:"server"`
Output string `yaml:"output"`
Insecure bool `yaml:"insecure"`
ClientID string `yaml:"clientId"`
ClientSecret string `yaml:"clientSecret"`
TokenURL string `yaml:"tokenUrl"`
}
// LoadConfig resolves defaults from ~/.kmsvc/config.yaml and environment
// variables (KMSVC_SERVER, KMSVC_TOKEN, KMSVC_OUTPUT, KMSVC_INSECURE,
// KMSVC_CLIENT_ID, KMSVC_CLIENT_SECRET, KMSVC_TOKEN_URL). ClientID/ClientSecret
// additionally fall back to AUTHENTIK_KAFAKA_CLIENT_ID/AUTHENTIK_KAFAKA_CLIENT_SECRET
// (the homelab's Authentik app credentials, typically exported into the shell
// via `vsource` from Vault) when the KMSVC_-prefixed vars aren't set, so this
// CLI doesn't need its own separately-exported copy. Flags are applied on top
// of this by the caller (root.go), so this function never reads flags.
func LoadConfig() Config {
cfg := Config{Output: "table"}
if path, err := configFilePath(); err == nil {
if fc, err := readFileConfig(path); err == nil {
if fc.Server != "" {
cfg.Server = fc.Server
}
if fc.Output != "" {
cfg.Output = fc.Output
}
cfg.Insecure = fc.Insecure
if fc.ClientID != "" {
cfg.ClientID = fc.ClientID
}
if fc.ClientSecret != "" {
cfg.ClientSecret = fc.ClientSecret
}
if fc.TokenURL != "" {
cfg.TokenURL = fc.TokenURL
}
}
}
if v := os.Getenv("KMSVC_SERVER"); v != "" {
cfg.Server = v
}
if v := os.Getenv("KMSVC_TOKEN"); v != "" {
cfg.Token = v
}
if v := os.Getenv("KMSVC_OUTPUT"); v != "" {
cfg.Output = v
}
if v := os.Getenv("KMSVC_INSECURE"); v != "" {
cfg.Insecure = v == "1" || v == "true"
}
if v := os.Getenv("AUTHENTIK_KAFAKA_CLIENT_ID"); v != "" {
cfg.ClientID = v
}
if v := os.Getenv("KMSVC_CLIENT_ID"); v != "" {
cfg.ClientID = v
}
if v := os.Getenv("AUTHENTIK_KAFAKA_CLIENT_SECRET"); v != "" {
cfg.ClientSecret = v
}
if v := os.Getenv("KMSVC_CLIENT_SECRET"); v != "" {
cfg.ClientSecret = v
}
if v := os.Getenv("KMSVC_TOKEN_URL"); v != "" {
cfg.TokenURL = v
}
return cfg
}
func configFilePath() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", err
}
return filepath.Join(home, ".kmsvc", "config.yaml"), nil
}
func readFileConfig(path string) (fileConfig, error) {
var fc fileConfig
data, err := os.ReadFile(path)
if err != nil {
return fc, err
}
if err := yaml.Unmarshal(data, &fc); err != nil {
return fc, err
}
return fc, nil
}