Skip to content

Commit 5c945f9

Browse files
authored
Allow secret set to read secrets from stdin (#108)
Signed-off-by: Juan Antonio Osorio <ozz@stacklok.com>
1 parent 644b96d commit 5c945f9

File tree

1 file changed

+48
-11
lines changed

1 file changed

+48
-11
lines changed

cmd/thv/secret.go

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ package main
22

33
import (
44
"fmt"
5+
"io"
56
"os"
7+
"strings"
68
"syscall"
79

810
"github.com/spf13/cobra"
@@ -33,8 +35,22 @@ func newSecretSetCommand() *cobra.Command {
3335
return &cobra.Command{
3436
Use: "set <name>",
3537
Short: "Set a secret",
36-
Long: "Set a secret with the given name. The secret value will be read from the terminal.",
37-
Args: cobra.ExactArgs(1),
38+
Long: `Set a secret with the given name.
39+
40+
Input Methods:
41+
- Piped Input: If data is piped to the command, the secret value will be read from stdin.
42+
Examples:
43+
echo "my-secret-value" | thv secret set my-secret
44+
cat secret-file.txt | thv secret set my-secret
45+
46+
- Interactive Input: If no data is piped, you will be prompted to enter the secret value securely
47+
(input will be hidden).
48+
Example:
49+
thv secret set my-secret
50+
Enter secret value (input will be hidden): _
51+
52+
The secret will be stored securely using the configured secrets provider.`,
53+
Args: cobra.ExactArgs(1),
3854
Run: func(cmd *cobra.Command, args []string) {
3955
name := args[0]
4056

@@ -44,17 +60,38 @@ func newSecretSetCommand() *cobra.Command {
4460
return
4561
}
4662

47-
// Prompt for the secret value
48-
fmt.Print("Enter secret value (input will be hidden): ")
49-
valueBytes, err := term.ReadPassword(int(syscall.Stdin))
50-
fmt.Println("") // Add a newline after the hidden input
51-
52-
if err != nil {
53-
fmt.Fprintf(os.Stderr, "Error reading secret from terminal: %v\n", err)
54-
return
63+
var value string
64+
var err error
65+
66+
// Check if data is being piped to stdin
67+
stat, _ := os.Stdin.Stat()
68+
isPiped := (stat.Mode() & os.ModeCharDevice) == 0
69+
70+
if isPiped {
71+
// Read from stdin (piped input)
72+
var valueBytes []byte
73+
valueBytes, err = io.ReadAll(os.Stdin)
74+
if err != nil {
75+
fmt.Fprintf(os.Stderr, "Error reading secret from stdin: %v\n", err)
76+
return
77+
}
78+
value = string(valueBytes)
79+
// Trim trailing newline if present
80+
value = strings.TrimSuffix(value, "\n")
81+
} else {
82+
// Interactive mode - prompt for the secret value
83+
fmt.Print("Enter secret value (input will be hidden): ")
84+
var valueBytes []byte
85+
valueBytes, err = term.ReadPassword(int(syscall.Stdin))
86+
fmt.Println("") // Add a newline after the hidden input
87+
88+
if err != nil {
89+
fmt.Fprintf(os.Stderr, "Error reading secret from terminal: %v\n", err)
90+
return
91+
}
92+
value = string(valueBytes)
5593
}
5694

57-
value := string(valueBytes)
5895
if value == "" {
5996
fmt.Println("Validation Error: Secret value cannot be empty")
6097
return

0 commit comments

Comments
 (0)