Skip to content

Commit

Permalink
removing client encryption, prompt for KMS by default, add task def o…
Browse files Browse the repository at this point in the history
…utputs
  • Loading branch information
kendavis2 committed Sep 16, 2019
1 parent cc3e83c commit 2ffd749
Show file tree
Hide file tree
Showing 22 changed files with 298 additions and 268 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,6 @@ cmd/tests/s3/infrastructure/*
infrastructure/s3demo/*
test-config/*

service


87 changes: 81 additions & 6 deletions cmd/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cmd

import (
"bytes"
"encoding/json"
"fmt"

"github.com/subosito/gotenv"
Expand Down Expand Up @@ -50,9 +51,10 @@ func updateUserOptions(file catalog.File, opt cfg.UserOptions) catalog.File {
}

type remoteComponents struct {
store contract.IStore
access contract.IVault
secrets contract.IVault
store contract.IStore
access contract.IVault
secrets contract.IVault
encryption contract.IVault
}

func getRemoteComponents(fileEntry *catalog.File, clog catalog.Catalog, uo cfg.UserOptions, io models.IO) (remoteComponents, error) {
Expand Down Expand Up @@ -128,14 +130,87 @@ func overrideFileSettings(fileEntry catalog.File, opt cfg.UserOptions) catalog.F
return fileEntry
}

func bufferExportScript(file []byte) bytes.Buffer {
func bufferExportScript(file []byte) (bytes.Buffer, error) {
reader := bytes.NewReader(file)
pairs := gotenv.Parse(reader)
var b bytes.Buffer

for key, value := range pairs {
b.WriteString(fmt.Sprintf("export %s='%s'\n", key, value))
_, err := b.WriteString(fmt.Sprintf("export %s='%s'\n", key, value))
if err != nil {
return b, err
}
}

return b
return b, nil
}

func toTaskDefSecretFormat(file []byte) (bytes.Buffer, error) {
reader := bytes.NewReader(file)
pairs := gotenv.Parse(reader)

var buff bytes.Buffer

secrets := []JsonFormat{}

for key, value := range pairs {
p := JsonFormat{
ValueFrom: value,
Name: key,
}

secrets = append(secrets, p)
}

b, err := json.MarshalIndent(secrets, "", " ")
if err != nil {
return buff, err
}

_, err = buff.Write(b)
if err != nil {
return buff, err
}

return buff, nil
}

type JsonFormat struct {
Name string `json:"name"`
ValueFrom string `json:"valueFrom"`
}

func toTaskDefEnvFormat(file []byte) (bytes.Buffer, error) {
reader := bytes.NewReader(file)
pairs := gotenv.Parse(reader)

var buff bytes.Buffer

env := []EnvFormat{}

for key, value := range pairs {
p := EnvFormat{
Value: value,
Name: key,
}

env = append(env, p)
}

b, err := json.MarshalIndent(env, "", " ")
if err != nil {
return buff, err
}

_, err = buff.Write(b)
if err != nil {
return buff, err
}

return buff, nil
}

type EnvFormat struct {
Name string `json:"name"`
Value string `json:"value"`
}
27 changes: 23 additions & 4 deletions cmd/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,15 +175,33 @@ func Pull(catalogPath string, opt cfg.UserOptions, io models.IO) (int, int, erro
//----------------------------------------------------
//- If user specifies, send export commands to stdout.
//----------------------------------------------------
if opt.ExportEnv {
if opt.ExportEnv || len(opt.ExportFormat) > 0 {

script := bytes.Buffer{}
msg := "\n%s sent to stdout.\n"

switch fileEntry.Type {
case "env":
script = bufferExportScript(fileWithSecrets)
msg = fmt.Sprintf(msg, "Export commands")
if opt.ExportFormat == "task-def-secrets" {
msg = fmt.Sprintf(msg, "AWS task definition secrets")
script, err = toTaskDefSecretFormat(fileWithSecrets)
if err != nil {
logger.L.Print(err)
}
} else if opt.ExportFormat == "task-def-env" {
msg = fmt.Sprintf(msg, "AWS task definition environment")
script, err = toTaskDefEnvFormat(fileWithSecrets)
if err != nil {
logger.L.Print(err)
}
} else {
msg = fmt.Sprintf(msg, "Terminal export commands")
script, err = bufferExportScript(fileWithSecrets)
if err != nil {
logger.L.Print(err)
}
}

case "json":
script.Write(fileWithSecrets)
msg = fmt.Sprintf(msg, "JSON")
Expand Down Expand Up @@ -254,8 +272,9 @@ func Pull(catalogPath string, opt cfg.UserOptions, io models.IO) (int, int, erro
func init() {
RootCmd.AddCommand(pullCmd)

pullCmd.Flags().BoolVarP(&uo.ExportEnv, "export", "e", false, "Set environment variables from files.")
pullCmd.Flags().BoolVarP(&uo.ExportEnv, "export", "e", false, "Append export command to environment variables and send to stdout.")
pullCmd.Flags().StringVarP(&uo.Tags, "tags", "t", "", "Specify a list of tags used to filter files.")
pullCmd.Flags().StringVarP(&uo.ExportFormat, "format", "g", "", "Format environment variables and send to stdout")
pullCmd.Flags().StringVarP(&uo.Version, "ver", "v", "", "Set a version to identify a file specific state.")
pullCmd.Flags().BoolVarP(&uo.InjectSecrets, "inject-secrets", "i", false, "Generate *.secrets file containing configuration including secrets.")
pullCmd.Flags().StringVarP(&uo.AlternateRestorePath, "alt", "a", "", "Set an alternate path to clone the file to during a restore.")
Expand Down
4 changes: 2 additions & 2 deletions cmd/purge.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func Purge(opt cfg.UserOptions, io models.IO) error {
}
}

if !prompt.Confirm(fmt.Sprintf("Files will be permanently deleted from remote storage!\n\n%s \nContinue?", fileList), true, io) {
if !prompt.Confirm(fmt.Sprintf("File data will be permanently deleted from remote storage! Local files and secrets stored in AWS Secrets Manager will not be affected.\n\n%s \nContinue?", fileList), prompt.Danger, io) {
color.New(color.Bold, color.FgRed).Fprint(ioStreams.UserOutput, "\nOperation Aborted!\n")
os.Exit(0)
}
Expand Down Expand Up @@ -141,7 +141,7 @@ func Purge(opt cfg.UserOptions, io models.IO) error {
//- Delete the file.
//----------------------------------------------------
if err = remoteComp.store.Purge(&fileEntry, none); err != nil {
display.Error(fmt.Sprintf("Failed to purge %s!", fileEntry.Path), io.UserOutput)
display.Error(fmt.Sprintf("Purge aborted for %s!", fileEntry.Path), io.UserOutput)
logger.L.Print(err)
fmt.Fprintln(io.UserOutput)
continue
Expand Down
2 changes: 1 addition & 1 deletion cmd/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ func Push(opt cfg.UserOptions, io models.IO) error {
continue
} else {
if !fileEntry.IsCurrent(lastModified, clog.Context) {
if !prompt.Confirm(fmt.Sprintf("Remote file '%s' was modified on %s. Overwrite?", filePath, lastModified.Format(time.RFC822)), false, io) {
if !prompt.Confirm(fmt.Sprintf("Remote file '%s' was modified on %s. Overwrite?", filePath, lastModified.Format(time.RFC822)), prompt.Warn, io) {
fmt.Fprintf(io.UserOutput, "Skipping %s\n", filePath)
errorOccurred = true
continue
Expand Down
2 changes: 1 addition & 1 deletion cmd/tests/s3/pull_s3_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func TestEnsureSecretsAreInjectedIntoFilesDuringPullRequest(t *testing.T) {

files := map[string]file{
expectedFile: file{
io: makeIO(testWriter, testWriter, fmt.Sprintf("%s-%s", Context, t.Name()), os.Getenv("AWS_S3_BUCKET"), os.Getenv("AWS_KMS_KEY_ID")),
io: makeIO(testWriter, testWriter, fmt.Sprintf("%s-%s", Context, t.Name()), os.Getenv("AWS_S3_BUCKET"), os.Getenv("AWS_STORE_KMS_KEY_ID")),
data: "DB=mongodb://{{dev/user::test-user}}:{{dev/password::shh...}}@ds111111.mlab.com:111111/app-dev\nAPI_KEY={{dev/key::test-api-key}}",
},
}
Expand Down
2 changes: 1 addition & 1 deletion components/catalog/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (

func create(io models.IO) Catalog {
opt := prompt.Options{
Description: "The project name categorizing the remotely stored files. This gives context to all files in this catalog.",
Description: "The project name categorizing the remotely stored files. This gives context to all files in this catalog. To avoid overriding existing data, ensure context is unique.",
DefaultValue: getContext(),
}
val := prompt.GetValFromUser("Context", opt, io)
Expand Down
2 changes: 1 addition & 1 deletion components/catalog/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func (f File) Missing(version string) bool {
}

// Name ...
func (f File) Name() string { return "" }
func (f File) Name() string { return "*.yml" }

// Description ...
func (f File) Description() string { return "" }
Expand Down
1 change: 1 addition & 0 deletions components/cfg/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type UserOptions struct {
Version string
AlternateRestorePath string
StoreCommand string
ExportFormat string
ModifySecrets bool
InjectSecrets bool
NoOverwrite bool
Expand Down
2 changes: 1 addition & 1 deletion components/display/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ import (

// Error ...
func Error(text string, w io.Writer) {
color.New(color.Bold, color.FgRed).Fprint(w, "ERROR: ")
color.New(color.Bold, color.FgRed).Fprint(w, "\nERROR: ")
fmt.Fprintln(w, text)
}
15 changes: 12 additions & 3 deletions components/prompt/confirm.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,22 @@ import (
"github.com/turnerlabs/cstore/components/models"
)

const (
Warn = "WARN"
Danger = "DANGER"
Normal = "NORMAL"
)

// Confirm ...
func Confirm(description string, critical bool, io models.IO) bool {
func Confirm(description, level string, io models.IO) bool {
var s string

if critical {
switch level {
case Warn:
fmt.Fprintf(io.UserOutput, "\n%s%s%s%s%s (y/N): ", yellowColor, bold, description, unbold, noColor)
case Danger:
fmt.Fprintf(io.UserOutput, "\n%s%s%s%s%s (y/N): ", redColor, bold, description, unbold, noColor)
} else {
default:
fmt.Fprintf(io.UserOutput, "\n%s (y/N): ", description)
}

Expand Down
7 changes: 4 additions & 3 deletions components/prompt/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ const (
bold = "\033[1m"
unbold = "\033[0m"

redColor = "\033[0;31m"
blueColor = "\033[0;34m"
noColor = "\033[0m"
redColor = "\033[0;31m"
yellowColor = "\033[0;33m"
blueColor = "\033[0;34m"
noColor = "\033[0m"
)

// Options ...
Expand Down
18 changes: 8 additions & 10 deletions components/setting/setting.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package setting

import (
"fmt"
"os"

"github.com/turnerlabs/cstore/components/contract"
"github.com/turnerlabs/cstore/components/models"
"github.com/turnerlabs/cstore/components/prompt"
Expand All @@ -16,10 +19,9 @@ type Setting struct {

Prompt bool
HideInput bool
Set bool
AutoSave bool

Vault contract.IVault
Stage contract.IVault
}

// Key ...
Expand All @@ -30,7 +32,6 @@ func (s Setting) Key(context string) string {
// Get ...
func (s Setting) Get(context string, io models.IO) (string, error) {
value, err := s.Vault.Get(context, s.Group, s.Prop)

if err != nil {
if err.Error() == contract.ErrSecretNotFound.Error() {
s.Prompt = true
Expand All @@ -48,23 +49,20 @@ func (s Setting) Get(context string, io models.IO) (string, error) {
HideInput: s.HideInput,
}

if len(opt.DefaultValue) == 0 {
if env := os.Getenv(formattedKey); len(env) > 0 {
opt.DefaultValue = env
} else if len(value) > 0 {
opt.DefaultValue = value
}

value = prompt.GetValFromUser(formattedKey, opt, io)

if len(value) > 0 && s.Set {
if s.AutoSave || prompt.Confirm(fmt.Sprintf("Save %s preference in %s?", formattedKey, s.Vault.Name()), prompt.Warn, io) {
if err := s.Vault.Set(context, s.Group, s.Prop, value); err != nil {
return value, err
}
}
}

if s.Stage != nil {
if err := s.Stage.Set(context, s.Group, s.Prop, value); err != nil {
return value, err
}
}

return value, nil
Expand Down
Loading

0 comments on commit 2ffd749

Please sign in to comment.