package cmd import ( "fmt" "io" "os" "strings" "github.com/spf13/cobra" "golang.org/x/term" ) // readSecretValue resolves the value for a secret/token flag from, in order: // 1. --body (inline; visible in shell history) // 2. --body-file (file path, or "-" for stdin) // 3. interactive TTY prompt (hidden) // 4. piped stdin // // Trailing whitespace (including the final newline common in heredocs and // `echo ... | fgj ...`) is trimmed. An empty resolved value is rejected so we // never silently write an empty secret. func readSecretValue(cmd *cobra.Command, label string) (string, error) { if v, _ := cmd.Flags().GetString("body"); v != "" { return strings.TrimRight(v, "\r\n"), nil } if path, _ := cmd.Flags().GetString("body-file"); path != "" { var raw []byte var err error if path == "-" { raw, err = io.ReadAll(ios.In) } else { raw, err = os.ReadFile(path) } if err != nil { return "", fmt.Errorf("failed to read secret from %q: %w", path, err) } value := strings.TrimRight(string(raw), "\r\n") if value == "" { return "", fmt.Errorf("secret value from %q is empty", path) } return value, nil } if ios.IsStdinTTY() { fmt.Fprintf(ios.ErrOut, "Value for %s: ", label) pw, err := term.ReadPassword(int(os.Stdin.Fd())) fmt.Fprintln(ios.ErrOut) if err != nil { return "", fmt.Errorf("failed to read secret: %w", err) } value := strings.TrimRight(string(pw), "\r\n") if value == "" { return "", fmt.Errorf("secret value is empty") } return value, nil } raw, err := io.ReadAll(ios.In) if err != nil { return "", fmt.Errorf("failed to read secret from stdin: %w", err) } value := strings.TrimRight(string(raw), "\r\n") if value == "" { return "", fmt.Errorf("secret value from stdin is empty") } return value, nil }