forked from toolshed/abra
		
	
		
			
				
	
	
		
			654 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			654 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package app
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"os"
 | 
						|
	"sort"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
 | 
						|
	"coopcloud.tech/abra/cli/internal"
 | 
						|
	appPkg "coopcloud.tech/abra/pkg/app"
 | 
						|
	"coopcloud.tech/abra/pkg/autocomplete"
 | 
						|
	"coopcloud.tech/abra/pkg/client"
 | 
						|
	"coopcloud.tech/abra/pkg/formatter"
 | 
						|
	"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"
 | 
						|
)
 | 
						|
 | 
						|
// translators: `abra app secret generate` aliases. use a comma separated list of aliases with
 | 
						|
// no spaces in between
 | 
						|
var appSecretGenerateAliases = i18n.G("g")
 | 
						|
 | 
						|
var AppSecretGenerateCommand = &cobra.Command{
 | 
						|
	// translators: `app secret generate` command
 | 
						|
	Use:     i18n.G("generate <domain> [[secret] [version] | --all] [flags]"),
 | 
						|
	Aliases: strings.Split(appSecretGenerateAliases, ","),
 | 
						|
	// translators: Short description for `app secret generate` command
 | 
						|
	Short: i18n.G("Generate secrets"),
 | 
						|
	Args:  cobra.RangeArgs(1, 3),
 | 
						|
	ValidArgsFunction: func(
 | 
						|
		cmd *cobra.Command,
 | 
						|
		args []string,
 | 
						|
		toComplete string,
 | 
						|
	) ([]string, cobra.ShellCompDirective) {
 | 
						|
		switch l := len(args); l {
 | 
						|
		case 0:
 | 
						|
			return autocomplete.AppNameComplete()
 | 
						|
		case 1:
 | 
						|
			app, err := appPkg.Get(args[0])
 | 
						|
			if err != nil {
 | 
						|
				return []string{i18n.G("autocomplete failed: %s", err)}, cobra.ShellCompDirectiveError
 | 
						|
			}
 | 
						|
			return autocomplete.SecretComplete(app.Recipe.Name)
 | 
						|
		default:
 | 
						|
			return nil, cobra.ShellCompDirectiveDefault
 | 
						|
		}
 | 
						|
	},
 | 
						|
	Run: func(cmd *cobra.Command, args []string) {
 | 
						|
		app := internal.ValidateApp(args)
 | 
						|
 | 
						|
		if err := app.Recipe.Ensure(internal.GetEnsureContext()); err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		if len(args) <= 2 && !generateAllSecrets {
 | 
						|
			log.Fatal(i18n.G("missing arguments [secret]/[version] or '--all'"))
 | 
						|
		}
 | 
						|
 | 
						|
		if len(args) > 2 && generateAllSecrets {
 | 
						|
			log.Fatal(i18n.G("cannot use '[secret] [version]' and '--all' together"))
 | 
						|
		}
 | 
						|
 | 
						|
		composeFiles, err := app.Recipe.GetComposeFiles(app.Env)
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		secrets, err := secret.ReadSecretsConfig(app.Path, composeFiles, app.StackName())
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		if !generateAllSecrets {
 | 
						|
			secretName := args[1]
 | 
						|
			secretVersion := args[2]
 | 
						|
			s, ok := secrets[secretName]
 | 
						|
			if !ok {
 | 
						|
				log.Fatal(i18n.G("%s doesn't exist in the env config?", secretName))
 | 
						|
			}
 | 
						|
			s.Version = secretVersion
 | 
						|
			secrets = map[string]secret.Secret{
 | 
						|
				secretName: s,
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		cl, err := client.New(app.Server)
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		secretVals, err := secret.GenerateSecrets(cl, secrets, app.Server)
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		if storeInPass {
 | 
						|
			for name, data := range secretVals {
 | 
						|
				if err := secret.PassInsertSecret(data, name, app.Name, app.Server); err != nil {
 | 
						|
					log.Fatal(err)
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if len(secretVals) == 0 {
 | 
						|
			log.Warn(i18n.G("no secrets generated"))
 | 
						|
			os.Exit(1)
 | 
						|
		}
 | 
						|
 | 
						|
		headers := []string{i18n.G("NAME"), i18n.G("VALUE")}
 | 
						|
		table, err := formatter.CreateTable()
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		table.Headers(headers...)
 | 
						|
 | 
						|
		var rows [][]string
 | 
						|
		for name, val := range secretVals {
 | 
						|
			row := []string{name, val}
 | 
						|
			rows = append(rows, row)
 | 
						|
			table.Row(row...)
 | 
						|
		}
 | 
						|
 | 
						|
		if internal.MachineReadable {
 | 
						|
			out, err := formatter.ToJSON(headers, rows)
 | 
						|
			if err != nil {
 | 
						|
				log.Fatal(i18n.G("unable to render to JSON: %s", err))
 | 
						|
			}
 | 
						|
			fmt.Println(out)
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		if err := formatter.PrintTable(table); err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		log.Warn(i18n.G(
 | 
						|
			"generated secrets %s shown again, please take note of them %s",
 | 
						|
			formatter.BoldStyle.Render(i18n.G("NOT")),
 | 
						|
			formatter.BoldStyle.Render(i18n.G("NOW")),
 | 
						|
		))
 | 
						|
	},
 | 
						|
}
 | 
						|
 | 
						|
// translators: `abra app secret insert` aliases. use a comma separated list of aliases with
 | 
						|
// no spaces in between
 | 
						|
var appSecretInsertAliases = i18n.G("i")
 | 
						|
 | 
						|
var AppSecretInsertCommand = &cobra.Command{
 | 
						|
	// translators: `app secret insert` command
 | 
						|
	Use:     i18n.G("insert <domain> <secret> <version> [<data>] [flags]"),
 | 
						|
	Aliases: strings.Split(appSecretInsertAliases, ","),
 | 
						|
	// translators: Short description for `app secret insert` command
 | 
						|
	Short: i18n.G("Insert secret"),
 | 
						|
	Long: i18n.G(`This command inserts a secret into an app environment.
 | 
						|
 | 
						|
Arbitrary secret insertion is not supported. Secrets that are inserted must
 | 
						|
match those configured in the recipe beforehand.
 | 
						|
 | 
						|
This can be useful when you want to manually generate secrets for an app
 | 
						|
environment. Typically, you can let Abra generate them for you on app creation
 | 
						|
(see "abra app new --secrets/-S" for more).`),
 | 
						|
	Example: i18n.G(`  # insert regular secret
 | 
						|
  abra app secret insert 1312.net my_secret v1 mySuperSecret
 | 
						|
 | 
						|
  # insert secret as file
 | 
						|
  abra app secret insert 1312.net my_secret v1 secret.txt -f
 | 
						|
 | 
						|
  # insert secret from stdin
 | 
						|
  echo "mmySuperSecret" | abra app secret insert 1312.net my_secret v1`),
 | 
						|
	Args: cobra.MinimumNArgs(3),
 | 
						|
	ValidArgsFunction: func(
 | 
						|
		cmd *cobra.Command,
 | 
						|
		args []string,
 | 
						|
		toComplete string,
 | 
						|
	) ([]string, cobra.ShellCompDirective) {
 | 
						|
		switch l := len(args); l {
 | 
						|
		case 0:
 | 
						|
			return autocomplete.AppNameComplete()
 | 
						|
		case 1:
 | 
						|
			app, err := appPkg.Get(args[0])
 | 
						|
			if err != nil {
 | 
						|
				return []string{i18n.G("autocomplete failed: %s", err)}, cobra.ShellCompDirectiveError
 | 
						|
			}
 | 
						|
			return autocomplete.SecretComplete(app.Recipe.Name)
 | 
						|
		default:
 | 
						|
			return nil, cobra.ShellCompDirectiveDefault
 | 
						|
		}
 | 
						|
	},
 | 
						|
	Run: func(cmd *cobra.Command, args []string) {
 | 
						|
		app := internal.ValidateApp(args)
 | 
						|
 | 
						|
		if err := app.Recipe.Ensure(internal.GetEnsureContext()); err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		cl, err := client.New(app.Server)
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		name := args[1]
 | 
						|
		version := args[2]
 | 
						|
		data, err := readSecretData(args)
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		composeFiles, err := app.Recipe.GetComposeFiles(app.Env)
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		secrets, err := secret.ReadSecretsConfig(app.Path, composeFiles, app.StackName())
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		var isRecipeSecret bool
 | 
						|
		for secretName := range secrets {
 | 
						|
			if secretName == name {
 | 
						|
				isRecipeSecret = true
 | 
						|
			}
 | 
						|
		}
 | 
						|
		if !isRecipeSecret {
 | 
						|
			log.Fatal(i18n.G("no secret %s available for recipe %s?", name, app.Recipe.Name))
 | 
						|
		}
 | 
						|
 | 
						|
		if insertFromFile {
 | 
						|
			raw, err := os.ReadFile(data)
 | 
						|
			if err != nil {
 | 
						|
				log.Fatal(i18n.G("reading secret from file: %s", err))
 | 
						|
			}
 | 
						|
			data = string(raw)
 | 
						|
		}
 | 
						|
 | 
						|
		if trimInput {
 | 
						|
			data = strings.TrimSpace(data)
 | 
						|
		}
 | 
						|
 | 
						|
		secretName := fmt.Sprintf("%s_%s_%s", app.StackName(), name, version)
 | 
						|
		if err := client.StoreSecret(cl, secretName, data); err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		log.Info(i18n.G("%s successfully stored on server", secretName))
 | 
						|
 | 
						|
		if storeInPass {
 | 
						|
			if err := secret.PassInsertSecret(data, name, app.Name, app.Server); err != nil {
 | 
						|
				log.Fatal(err)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	},
 | 
						|
}
 | 
						|
 | 
						|
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 {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	log.Info(i18n.G("deleted %s successfully from server", secretName))
 | 
						|
 | 
						|
	if removeFromPass {
 | 
						|
		if err := secret.PassRmSecret(parsed, app.StackName(), app.Server); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		log.Info(i18n.G("deleted %s successfully from local pass store", secretName))
 | 
						|
	}
 | 
						|
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// translators: `abra app secret remove` aliases. use a comma separated list of aliases with
 | 
						|
// no spaces in between
 | 
						|
var appSecretRemoveAliases = i18n.G("rm")
 | 
						|
 | 
						|
var AppSecretRmCommand = &cobra.Command{
 | 
						|
	// translators: `app secret remove` command
 | 
						|
	Use:     i18n.G("remove <domain> [[secret] | --all] [flags]"),
 | 
						|
	Aliases: strings.Split(appSecretRemoveAliases, ","),
 | 
						|
	// translators: Short description for `app secret remove` command
 | 
						|
	Short: i18n.G("Remove a secret"),
 | 
						|
	Long: i18n.G(`This command removes a secret from an app environment.
 | 
						|
 | 
						|
Arbitrary secret removal is not supported. Secrets that are removed must
 | 
						|
match those configured in the recipe beforehand.`),
 | 
						|
	Example: i18n.G("  abra app secret rm 1312.net oauth_key"),
 | 
						|
	Args:    cobra.RangeArgs(1, 2),
 | 
						|
	ValidArgsFunction: func(
 | 
						|
		cmd *cobra.Command,
 | 
						|
		args []string,
 | 
						|
		toComplete string,
 | 
						|
	) ([]string, cobra.ShellCompDirective) {
 | 
						|
		switch l := len(args); l {
 | 
						|
		case 0:
 | 
						|
			return autocomplete.AppNameComplete()
 | 
						|
		case 1:
 | 
						|
			if !rmAllSecrets {
 | 
						|
				app, err := appPkg.Get(args[0])
 | 
						|
				if err != nil {
 | 
						|
					return []string{i18n.G("autocomplete failed: %s", err)}, cobra.ShellCompDirectiveError
 | 
						|
				}
 | 
						|
				return autocomplete.SecretComplete(app.Recipe.Name)
 | 
						|
			}
 | 
						|
			return nil, cobra.ShellCompDirectiveDefault
 | 
						|
		default:
 | 
						|
			return nil, cobra.ShellCompDirectiveError
 | 
						|
		}
 | 
						|
	},
 | 
						|
	Run: func(cmd *cobra.Command, args []string) {
 | 
						|
		app := internal.ValidateApp(args)
 | 
						|
 | 
						|
		if err := app.Recipe.Ensure(internal.GetEnsureContext()); err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		composeFiles, err := app.Recipe.GetComposeFiles(app.Env)
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		secrets, err := secret.ReadSecretsConfig(app.Path, composeFiles, app.StackName())
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		if len(args) == 2 && rmAllSecrets {
 | 
						|
			log.Fatal(i18n.G("cannot use [secret] and --all/-a together"))
 | 
						|
		}
 | 
						|
 | 
						|
		if len(args) != 2 && !rmAllSecrets {
 | 
						|
			log.Fatal(i18n.G("no secret(s) specified?"))
 | 
						|
		}
 | 
						|
 | 
						|
		cl, err := client.New(app.Server)
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		filters, err := app.Filters(false, false)
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		secretList, err := cl.SecretList(context.Background(), types.SecretListOptions{Filters: filters})
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		remoteSecretNames := make(map[string]bool)
 | 
						|
		for _, cont := range secretList {
 | 
						|
			remoteSecretNames[cont.Spec.Annotations.Name] = true
 | 
						|
		}
 | 
						|
 | 
						|
		var secretToRm string
 | 
						|
		if len(args) == 2 {
 | 
						|
			secretToRm = args[1]
 | 
						|
		}
 | 
						|
 | 
						|
		match := false
 | 
						|
		for secretName, val := range secrets {
 | 
						|
			secretRemoteName := fmt.Sprintf("%s_%s_%s", app.StackName(), secretName, val.Version)
 | 
						|
			if _, ok := remoteSecretNames[secretRemoteName]; ok {
 | 
						|
				if secretToRm != "" {
 | 
						|
					if secretName == secretToRm {
 | 
						|
						if err := secretRm(cl, app, secretRemoteName, secretName); err != nil {
 | 
						|
							log.Fatal(err)
 | 
						|
						}
 | 
						|
 | 
						|
						return
 | 
						|
					}
 | 
						|
				} else {
 | 
						|
					match = true
 | 
						|
 | 
						|
					if err := secretRm(cl, app, secretRemoteName, secretName); err != nil {
 | 
						|
						log.Fatal(err)
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if !match && secretToRm != "" {
 | 
						|
			log.Fatal(i18n.G("%s doesn't exist on server?", secretToRm))
 | 
						|
		}
 | 
						|
 | 
						|
		if !match {
 | 
						|
			log.Fatal(i18n.G("no secrets to remove?"))
 | 
						|
		}
 | 
						|
	},
 | 
						|
}
 | 
						|
 | 
						|
// translators: `abra app secret ls` aliases. use a comma separated list of aliases with
 | 
						|
// no spaces in between
 | 
						|
var appSecretLsAliases = i18n.G("ls")
 | 
						|
 | 
						|
var AppSecretLsCommand = &cobra.Command{
 | 
						|
	// translators: `app secret list` command
 | 
						|
	Use:     i18n.G("list <domain>"),
 | 
						|
	Aliases: strings.Split(appSecretLsAliases, ","),
 | 
						|
	// translators: Short description for `app secret list` command
 | 
						|
	Short: i18n.G("List all secrets"),
 | 
						|
	Args:  cobra.MinimumNArgs(1),
 | 
						|
	ValidArgsFunction: func(
 | 
						|
		cmd *cobra.Command,
 | 
						|
		args []string,
 | 
						|
		toComplete string,
 | 
						|
	) ([]string, cobra.ShellCompDirective) {
 | 
						|
		return autocomplete.AppNameComplete()
 | 
						|
	},
 | 
						|
	Run: func(cmd *cobra.Command, args []string) {
 | 
						|
		app := internal.ValidateApp(args)
 | 
						|
 | 
						|
		if err := app.Recipe.Ensure(internal.GetEnsureContext()); err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		cl, err := client.New(app.Server)
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		headers := []string{i18n.G("NAME"), i18n.G("VERSION"), i18n.G("GENERATED NAME"), i18n.G("CREATED ON SERVER")}
 | 
						|
		table, err := formatter.CreateTable()
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		table.Headers(headers...)
 | 
						|
 | 
						|
		secStats, err := secret.PollSecretsStatus(cl, app)
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
 | 
						|
		// Sort secrets to ensure reproducible output
 | 
						|
		sort.Slice(secStats, func(i, j int) bool {
 | 
						|
			return secStats[i].LocalName < secStats[j].LocalName
 | 
						|
		})
 | 
						|
		var rows [][]string
 | 
						|
		for _, secStat := range secStats {
 | 
						|
			row := []string{
 | 
						|
				secStat.LocalName,
 | 
						|
				secStat.Version,
 | 
						|
				secStat.RemoteName,
 | 
						|
				strconv.FormatBool(secStat.CreatedOnRemote),
 | 
						|
			}
 | 
						|
 | 
						|
			rows = append(rows, row)
 | 
						|
			table.Row(row...)
 | 
						|
		}
 | 
						|
 | 
						|
		if len(rows) > 0 {
 | 
						|
			if internal.MachineReadable {
 | 
						|
				out, err := formatter.ToJSON(headers, rows)
 | 
						|
				if err != nil {
 | 
						|
					log.Fatal(i18n.G("unable to render to JSON: %s", err))
 | 
						|
				}
 | 
						|
				fmt.Println(out)
 | 
						|
				return
 | 
						|
			}
 | 
						|
 | 
						|
			if err := formatter.PrintTable(table); err != nil {
 | 
						|
				log.Fatal(err)
 | 
						|
			}
 | 
						|
 | 
						|
			return
 | 
						|
		}
 | 
						|
 | 
						|
		log.Warn(i18n.G("no secrets stored for %s", app.Name))
 | 
						|
	},
 | 
						|
}
 | 
						|
 | 
						|
var AppSecretCommand = &cobra.Command{
 | 
						|
	// translators: `app secret` command group
 | 
						|
	Use:     i18n.G("secret [cmd] [args] [flags]"),
 | 
						|
	Aliases: []string{i18n.G("s")},
 | 
						|
	// translators: Short description for `app secret` command group
 | 
						|
	Short: i18n.G("Manage app secrets"),
 | 
						|
}
 | 
						|
 | 
						|
var (
 | 
						|
	storeInPass        bool
 | 
						|
	insertFromFile     bool
 | 
						|
	trimInput          bool
 | 
						|
	rmAllSecrets       bool
 | 
						|
	generateAllSecrets bool
 | 
						|
	removeFromPass     bool
 | 
						|
)
 | 
						|
 | 
						|
func init() {
 | 
						|
	AppSecretGenerateCommand.Flags().BoolVarP(
 | 
						|
		&internal.MachineReadable,
 | 
						|
		i18n.G("machine"),
 | 
						|
		i18n.G("m"),
 | 
						|
		false,
 | 
						|
		i18n.G("print machine-readable output"),
 | 
						|
	)
 | 
						|
 | 
						|
	AppSecretGenerateCommand.Flags().BoolVarP(
 | 
						|
		&storeInPass,
 | 
						|
		i18n.G("pass"),
 | 
						|
		i18n.G("p"),
 | 
						|
		false,
 | 
						|
		i18n.G("store generated secrets in a local pass store"),
 | 
						|
	)
 | 
						|
 | 
						|
	AppSecretGenerateCommand.Flags().BoolVarP(
 | 
						|
		&internal.Chaos,
 | 
						|
		i18n.G("chaos"),
 | 
						|
		i18n.G("C"),
 | 
						|
		false,
 | 
						|
		i18n.G("ignore uncommitted recipes changes"),
 | 
						|
	)
 | 
						|
 | 
						|
	AppSecretGenerateCommand.Flags().BoolVarP(
 | 
						|
		&generateAllSecrets,
 | 
						|
		i18n.G("all"),
 | 
						|
		i18n.G("a"),
 | 
						|
		false,
 | 
						|
		i18n.G("generate all secrets"),
 | 
						|
	)
 | 
						|
 | 
						|
	AppSecretInsertCommand.Flags().BoolVarP(
 | 
						|
		&storeInPass,
 | 
						|
		i18n.G("pass"),
 | 
						|
		i18n.G("p"),
 | 
						|
		false,
 | 
						|
		i18n.G("store generated secrets in a local pass store"),
 | 
						|
	)
 | 
						|
 | 
						|
	AppSecretInsertCommand.Flags().BoolVarP(
 | 
						|
		&insertFromFile,
 | 
						|
		i18n.G("file"),
 | 
						|
		i18n.G("f"),
 | 
						|
		false,
 | 
						|
		i18n.G("treat input as a file"),
 | 
						|
	)
 | 
						|
 | 
						|
	AppSecretInsertCommand.Flags().BoolVarP(
 | 
						|
		&trimInput,
 | 
						|
		i18n.G("trim"),
 | 
						|
		i18n.G("t"),
 | 
						|
		false,
 | 
						|
		i18n.G("trim input"),
 | 
						|
	)
 | 
						|
 | 
						|
	AppSecretInsertCommand.Flags().BoolVarP(
 | 
						|
		&internal.Chaos,
 | 
						|
		i18n.G("chaos"),
 | 
						|
		i18n.G("C"),
 | 
						|
		false,
 | 
						|
		i18n.G("ignore uncommitted recipes changes"),
 | 
						|
	)
 | 
						|
 | 
						|
	AppSecretRmCommand.Flags().BoolVarP(
 | 
						|
		&rmAllSecrets,
 | 
						|
		i18n.G("all"),
 | 
						|
		i18n.G("a"),
 | 
						|
		false,
 | 
						|
		i18n.G("remove all secrets"),
 | 
						|
	)
 | 
						|
 | 
						|
	AppSecretRmCommand.Flags().BoolVarP(
 | 
						|
		&removeFromPass,
 | 
						|
		i18n.G("pass"),
 | 
						|
		i18n.G("p"),
 | 
						|
		false,
 | 
						|
		i18n.G("remove generated secrets from a local pass store"),
 | 
						|
	)
 | 
						|
 | 
						|
	AppSecretRmCommand.Flags().BoolVarP(
 | 
						|
		&internal.Chaos,
 | 
						|
		i18n.G("chaos"),
 | 
						|
		i18n.G("C"),
 | 
						|
		false,
 | 
						|
		i18n.G("ignore uncommitted recipes changes"),
 | 
						|
	)
 | 
						|
 | 
						|
	AppSecretLsCommand.Flags().BoolVarP(
 | 
						|
		&internal.Chaos,
 | 
						|
		i18n.G("chaos"),
 | 
						|
		i18n.G("C"),
 | 
						|
		false,
 | 
						|
		i18n.G("ignore uncommitted recipes changes"),
 | 
						|
	)
 | 
						|
 | 
						|
	AppSecretLsCommand.Flags().BoolVarP(
 | 
						|
		&internal.MachineReadable,
 | 
						|
		i18n.G("machine"),
 | 
						|
		i18n.G("m"),
 | 
						|
		false,
 | 
						|
		i18n.G("print machine-readable output"),
 | 
						|
	)
 | 
						|
}
 |