|
|
|
@ -2,6 +2,7 @@ package app
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"os"
|
|
|
|
@ -17,6 +18,7 @@ import (
|
|
|
|
|
"coopcloud.tech/abra/pkg/i18n"
|
|
|
|
|
"coopcloud.tech/abra/pkg/log"
|
|
|
|
|
"coopcloud.tech/abra/pkg/secret"
|
|
|
|
|
"github.com/AlecAivazis/survey/v2"
|
|
|
|
|
"github.com/docker/docker/api/types"
|
|
|
|
|
dockerClient "github.com/docker/docker/client"
|
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
@ -143,7 +145,7 @@ var AppSecretGenerateCommand = &cobra.Command{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var AppSecretInsertCommand = &cobra.Command{
|
|
|
|
|
Use: i18n.G("insert <domain> <secret> <version> <data> [flags]"),
|
|
|
|
|
Use: i18n.G("insert <domain> <secret> <version> [<data>] [flags]"),
|
|
|
|
|
Aliases: []string{i18n.G("i")},
|
|
|
|
|
Short: i18n.G("Insert secret"),
|
|
|
|
|
Long: i18n.G(`This command inserts a secret into an app environment.
|
|
|
|
@ -195,29 +197,9 @@ environment. Typically, you can let Abra generate them for you on app creation
|
|
|
|
|
|
|
|
|
|
name := args[1]
|
|
|
|
|
version := args[2]
|
|
|
|
|
var data string
|
|
|
|
|
if len(args) == 4 {
|
|
|
|
|
data = args[3]
|
|
|
|
|
} else if len(args) == 3 {
|
|
|
|
|
if insertFromFile {
|
|
|
|
|
log.Fatal("can not insert from file and read from stdin")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fi, err := os.Stdin.Stat()
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
if fi.Mode()&os.ModeNamedPipe == 0 {
|
|
|
|
|
log.Fatal("need to provide secret data or stdin stream")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.Debug("reading secret data from stdin")
|
|
|
|
|
bytes, err := io.ReadAll(os.Stdin)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("reading data from stdin: %s", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data = string(bytes)
|
|
|
|
|
data, err := readSecretData(args)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
composeFiles, err := app.Recipe.GetComposeFiles(app.Env)
|
|
|
|
@ -240,7 +222,7 @@ environment. Typically, you can let Abra generate them for you on app creation
|
|
|
|
|
log.Fatal(i18n.G("no secret %s available for recipe %s?", name, app.Recipe.Name))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if insertFromFile && len(args) == 4 {
|
|
|
|
|
if insertFromFile {
|
|
|
|
|
raw, err := os.ReadFile(data)
|
|
|
|
|
if err != nil {
|
|
|
|
|
log.Fatal(i18n.G("reading secret from file: %s", err))
|
|
|
|
@ -267,6 +249,55 @@ environment. Typically, you can let Abra generate them for you on app creation
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func readSecretData(args []string) (string, error) {
|
|
|
|
|
if len(args) == 4 {
|
|
|
|
|
return args[3], nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(args) != 3 {
|
|
|
|
|
return "", errors.New(i18n.G("need 3 or 4 arguments"))
|
|
|
|
|
}
|
|
|
|
|
// First check if data is provided by stdin
|
|
|
|
|
fi, err := os.Stdin.Stat()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
if fi.Mode()&os.ModeNamedPipe != 0 {
|
|
|
|
|
// Can't insert from stdin and read from file
|
|
|
|
|
if insertFromFile {
|
|
|
|
|
return "", errors.New(i18n.G("can not insert from file and read from stdin"))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.Debug(i18n.G("reading secret data from stdin"))
|
|
|
|
|
bytes, err := io.ReadAll(os.Stdin)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", errors.New(i18n.G("reading data from stdin: %s", err))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return string(bytes), nil
|
|
|
|
|
}
|
|
|
|
|
if internal.NoInput {
|
|
|
|
|
return "", errors.New(i18n.G("must provide <data> argument if --no-input is passed"))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log.Debug(i18n.G("secret data not provided on command-line or stdin, prompting"))
|
|
|
|
|
var prompt survey.Prompt
|
|
|
|
|
if !insertFromFile {
|
|
|
|
|
prompt = &survey.Password{
|
|
|
|
|
Message: i18n.G("specify secret value"),
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
prompt = &survey.Input{
|
|
|
|
|
Message: i18n.G("specify secret file"),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
var data string
|
|
|
|
|
if err := survey.AskOne(prompt, &data); err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
}
|
|
|
|
|
return data, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// secretRm removes a secret.
|
|
|
|
|
func secretRm(cl *dockerClient.Client, app appPkg.App, secretName, parsed string) error {
|
|
|
|
|
if err := cl.SecretRemove(context.Background(), secretName); err != nil {
|
|
|
|
|