From 0e4566400bd477f92df358a76b7bd17d5a330ee7 Mon Sep 17 00:00:00 2001 From: Ben Ammann Date: Sun, 18 Sep 2022 20:05:22 +0200 Subject: [PATCH 1/5] wip: gcp credentials --- .git-secrets.json | 2 +- cmd/gcp_credentials.go | 53 ++++ cmd/get.go | 2 +- cmd/info.go | 6 +- cmd/scan.go | 8 +- cmd/set.go | 3 +- .../with-binary-example/.git-secrets.json | 9 +- go.mod | 19 +- go.sum | 246 ++++++++++++++++++ pkg/config/generic/repository.go | 2 +- pkg/config/generic/repository_context.go | 9 +- pkg/config/generic/repository_secret.go | 48 ++-- .../generic/repository_secret_encrypted.go | 35 +++ pkg/config/generic/repository_secret_gcp.go | 84 ++++++ pkg/config/generic/schema_v1.go | 85 +++++- pkg/config/generic/schema_v1_writer.go | 22 +- pkg/config/generic/schema_v1_writer_test.go | 18 +- pkg/config/global/global_config.go | 25 ++ pkg/config/writer/writer.go | 3 +- schema/def/v1.json | 58 ++++- 20 files changed, 659 insertions(+), 78 deletions(-) create mode 100644 cmd/gcp_credentials.go create mode 100644 pkg/config/generic/repository_secret_encrypted.go create mode 100644 pkg/config/generic/repository_secret_gcp.go diff --git a/.git-secrets.json b/.git-secrets.json index 53d75d7..bb11118 100644 --- a/.git-secrets.json +++ b/.git-secrets.json @@ -1,5 +1,5 @@ { - "$schema": "https://raw.githubusercontent.com/benammann/git-secrets/dev-beta/schema/def/v1.json", + "$schema": "schema/def/v1.json", "version": 1, "context": { "default": { diff --git a/cmd/gcp_credentials.go b/cmd/gcp_credentials.go new file mode 100644 index 0000000..edc2c68 --- /dev/null +++ b/cmd/gcp_credentials.go @@ -0,0 +1,53 @@ +package cmd + +import ( + "fmt" + "github.com/spf13/cobra" + "path/filepath" +) + +// setGcpCredentialsCmd represents the globalSecrets command +var setGcpCredentialsCmd = &cobra.Command{ + Use: "gcp-credentials", + Short: "Write a secret to the global configuration", + Example: ` +git secrets set global-secret : sets the global secret from terminal input +git secrets set global-secret --value $MY_SECRET_VALUE_STORED_IN_ENV: sets the global secret value from --value parameter (insecure) +`, + Aliases: []string{"global-secrets", "gs"}, + Args: cobra.ExactArgs(2), + Run: func(cmd *cobra.Command, args []string) { + + isForce, _ := cmd.Flags().GetBool(FlagForce) + secretKey := args[0] + pathToFile := args[1] + + absFilePath, errAbs := filepath.Abs(pathToFile) + cobra.CheckErr(errAbs) + + errWrite := globalCfg.SetGcpCredentials(secretKey, absFilePath, isForce) + if errWrite != nil { + cobra.CheckErr(fmt.Errorf("could not write config: %s", errWrite.Error())) + } + + fmt.Printf("%s written.\n", secretKey) + + }, +} + +func init() { + setCmd.AddCommand(setGcpCredentialsCmd) + + setGcpCredentialsCmd.Flags().Bool(FlagForce, false, "Force overwrite existing secret: You may loose your master password!") + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // getGlobalSecretsCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // getGlobalSecretsCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} + diff --git a/cmd/get.go b/cmd/get.go index 171593d..1a510d5 100644 --- a/cmd/get.go +++ b/cmd/get.go @@ -54,7 +54,7 @@ git secrets get secret -c prod if secretEntry == nil { cobra.CheckErr(fmt.Errorf("the secret %s does not exist on context %s", secretKey, selectedContext.Name)) } - decodedValue, errDecode := secretEntry.Decode() + decodedValue, errDecode := secretEntry.GetPlainValue() if errDecode != nil { cobra.CheckErr(fmt.Errorf("could not decode secret %s: %s", secretKey, errDecode.Error())) } diff --git a/cmd/info.go b/cmd/info.go index efe6ade..ceffcc6 100644 --- a/cmd/info.go +++ b/cmd/info.go @@ -70,11 +70,11 @@ git secrets info -d -c prod: Decodes all secrets from the prod context for _, secret := range projectCfg.GetCurrentSecrets() { - tableRow := []string{secret.Name, secret.OriginContext.Name} + tableRow := []string{secret.GetName(), secret.GetOriginContext().Name} if shouldDecode { - decodedValue, errDecode := secret.Decode() + decodedValue, errDecode := secret.GetPlainValue() if errDecode != nil { - fmt.Printf("Could not decode %s: %s\n", secret.Name, errDecode.Error()) + fmt.Printf("Could not decode %s: %s\n", secret.GetName(), errDecode.Error()) continue } tableRow = append(tableRow, decodedValue) diff --git a/cmd/scan.go b/cmd/scan.go index 2579f8f..69c6c45 100644 --- a/cmd/scan.go +++ b/cmd/scan.go @@ -15,7 +15,7 @@ import ( ) type DecodedSecret struct { - secret *config_generic.Secret + secret config_generic.Secret decodedValue string } @@ -48,9 +48,9 @@ var scanCmd = &cobra.Command{ for _, context := range projectCfg.GetContexts() { contextSecrets := projectCfg.GetSecretsByContext(context.Name) for _, secret := range contextSecrets { - decodedValue, errDecode := secret.Decode() + decodedValue, errDecode := secret.GetPlainValue() if errDecode != nil { - color.Yellow("Warning: could not decode secret %s from context %s, skipping this secret\n", secret.Name, secret.OriginContext.Name) + color.Yellow("Warning: could not decode secret %s from context %s, skipping this secret\n", secret.GetName(), secret.GetOriginContext().Name) continue } decodedSecrets = append(decodedSecrets, &DecodedSecret{secret: secret, decodedValue: decodedValue}) @@ -149,7 +149,7 @@ var scanCmd = &cobra.Command{ } for _, leakedSecret := range leakedSecrets { - fmt.Printf("%s:%s - secret %s from context %s is present\n", red(leakedSecret.fileName), yellow(leakedSecret.line), yellow(leakedSecret.secret.secret.Name), yellow(leakedSecret.secret.secret.OriginContext.Name)) + fmt.Printf("%s:%s - secret %s from context %s is present\n", red(leakedSecret.fileName), yellow(leakedSecret.line), yellow(leakedSecret.secret.secret.GetName()), yellow(leakedSecret.secret.secret.GetOriginContext().Name)) fmt.Printf("%s%d | %s\n\n", yellow("> "), leakedSecret.line, leakedSecret.lineContent) } diff --git a/cmd/set.go b/cmd/set.go index 92728c0..e10647f 100644 --- a/cmd/set.go +++ b/cmd/set.go @@ -67,7 +67,8 @@ git secrets set secret --value : INSECURE: Uses the valu cobra.CheckErr(errEncode) writer := projectCfg.GetConfigWriter() - errWrite := writer.SetSecret(projectCfg.GetCurrent().Name, secretKey, encodedValue, force) + + errWrite := writer.SetEncryptedSecret(projectCfg.GetCurrent().Name, secretKey, encodedValue, force) cobra.CheckErr(errWrite) fmt.Printf("The secret %s has been written\n", secretKey) diff --git a/examples/with-binary-example/.git-secrets.json b/examples/with-binary-example/.git-secrets.json index e6fad8b..ac271bb 100644 --- a/examples/with-binary-example/.git-secrets.json +++ b/examples/with-binary-example/.git-secrets.json @@ -1,5 +1,5 @@ { - "$schema": "https://raw.githubusercontent.com/benammann/git-secrets/dev-beta/schema/def/v1.json", + "$schema": "../../schema/def/v1.json", "version": 1, "context": { "default": { @@ -7,6 +7,13 @@ "fromName": "withbinaryexample" }, "secrets": { + "abs": { + "gcp": { + "projectId": "", + "secretName": "", + "version": "latest" + } + }, "databasePassword": "pkov/lbOBAV44/FyOFC4arIvkesn5a6pPRqPQKi8WcsKTBzkpZT1/HKGWTheH4MgLHab2h2DaKR1om6i" }, "configs": { diff --git a/go.mod b/go.mod index bb39239..ae17f0b 100644 --- a/go.mod +++ b/go.mod @@ -15,8 +15,17 @@ require ( ) require ( + cloud.google.com/go v0.102.0 // indirect + cloud.google.com/go/compute v1.7.0 // indirect + cloud.google.com/go/iam v0.3.0 // indirect + cloud.google.com/go/secretmanager v1.5.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/golang/protobuf v1.5.2 // indirect + github.com/google/go-cmp v0.5.8 // indirect + github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect + github.com/googleapis/gax-go/v2 v2.4.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect @@ -35,9 +44,17 @@ require ( github.com/subosito/gotenv v1.2.0 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect - golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect + go.opencensus.io v0.23.0 // indirect + golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect + golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb // indirect + golang.org/x/sys v0.0.0-20220624220833-87e55d714810 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/text v0.3.7 // indirect + google.golang.org/api v0.85.0 // indirect + google.golang.org/appengine v1.6.7 // indirect + google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa // indirect + google.golang.org/grpc v1.48.0 // indirect + google.golang.org/protobuf v1.28.1 // indirect gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect gopkg.in/ini.v1 v1.66.2 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index ba21546..a61b40d 100644 --- a/go.sum +++ b/go.sum @@ -17,24 +17,50 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk= cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY= +cloud.google.com/go v0.78.0/go.mod h1:QjdrLG0uq+YwhjoVOLsS1t7TW8fs36kLs4XO5R5ECHg= +cloud.google.com/go v0.79.0/go.mod h1:3bzgcEeQlzbuEAYu4mrWhKqWjmpprinYgKJLgKHnbb8= +cloud.google.com/go v0.81.0/go.mod h1:mk/AM35KwGk/Nm2YSeZbxXdrNK3KZOYHmLkOqC2V6E0= +cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAVY= +cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM= +cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY= +cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ= +cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI= +cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4= +cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc= +cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA= +cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= +cloud.google.com/go v0.102.0 h1:DAq3r8y4mDgyB/ZPJ9v/5VJNqjgJAxTn6ZYLlUywOu8= +cloud.google.com/go v0.102.0/go.mod h1:oWcCzKlqJ5zgHQt9YsaeTY9KzIvjyy0ArmiBUgpQ+nc= cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg= cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc= cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ= +cloud.google.com/go/compute v0.1.0/go.mod h1:GAesmwr110a34z04OlxYkATPBEfVhkymfTBXtfbBFow= +cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= +cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= +cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= +cloud.google.com/go/compute v1.6.1/go.mod h1:g85FgpzFvNULZ+S8AYq87axRKuf2Kh7deLqV/jJ3thU= +cloud.google.com/go/compute v1.7.0 h1:v/k9Eueb8aAJ0vZuxKMrgm6kPhCLZU9HxFU+AFDs9Uk= +cloud.google.com/go/compute v1.7.0/go.mod h1:435lt8av5oL9P3fv1OEzSbSUe+ybHXGMPQHHZWZxy9U= cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= +cloud.google.com/go/iam v0.3.0 h1:exkAomrVUuzx9kWFI1wm3KI0uoDeUFPB4kKGzx6x+Gc= +cloud.google.com/go/iam v0.3.0/go.mod h1:XzJPvDayI+9zsASAFO68Hk07u3z+f+JrT2xXNdp4bnY= cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA= cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU= +cloud.google.com/go/secretmanager v1.5.0 h1:XdbW+Fx5amsRzjHeFbDAQI2v2VUkSl3BWEgkQD6z8hY= +cloud.google.com/go/secretmanager v1.5.0/go.mod h1:5C9kM+RwSpkURNovKySkNvGQLUaOgyoR5W0RUx2SyHQ= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= +cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq6kuBTW58Y= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AlecAivazis/survey/v2 v2.3.4 h1:pchTU9rsLUSvWEl2Aq9Pv3k0IE2fkqtGxazskAMd9Ng= github.com/AlecAivazis/survey/v2 v2.3.4/go.mod h1:hrV6Y/kQCLhIZXGcriDCUBtB3wnN7156gMXJ3+b23xM= @@ -42,7 +68,11 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -50,6 +80,12 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= +github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= @@ -61,11 +97,16 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po= github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= +github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= +github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI= github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU= +github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -73,6 +114,8 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= +github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= @@ -80,6 +123,8 @@ github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.5.0/go.mod h1:CWnOUgYIOo4TcNZ0wHX3YZCqsaM1I1Jvs6v3mP3KVu8= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -94,6 +139,11 @@ github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvq github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= +github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= +github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -104,10 +154,17 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= +github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= @@ -118,11 +175,27 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= +github.com/googleapis/enterprise-certificate-proxy v0.1.0 h1:zO8WHNx/MYiAKJ3d5spxZXZE6KHmIQGQcAzwUzV7qQw= +github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0= +github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= +github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= +github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= +github.com/googleapis/gax-go/v2 v2.4.0 h1:dS9eYAjhrE2RjmzYw2XAPvcXfmcQLtFEQWn0CR82awk= +github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c= +github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= +github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= @@ -172,8 +245,10 @@ github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qR github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= @@ -211,12 +286,16 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= +go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M= +go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E= +go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= @@ -247,6 +326,7 @@ golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRu golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= +golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= @@ -257,6 +337,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -285,10 +366,25 @@ golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81R golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 h1:Yqz/iviulwKwAREEeUd3nbBFn0XuyJqkoft2IlrvOhc= +golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ= +golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -298,6 +394,18 @@ golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210220000619-9bb904979d93/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210313182246-cd4f82c27b84/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb h1:8tDJ3aechhddbdPAxpycgXHJRMLpk/Ab+aa4OgdN5/g= +golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -308,6 +416,8 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -341,13 +451,41 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810 h1:rHZQSjJdAI4Xf5Qzeh2bBc5YJIkPFVM6oDtMFYmgws0= +golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= @@ -358,6 +496,8 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -410,10 +550,18 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= +golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= @@ -433,12 +581,35 @@ google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz513 google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg= google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE= google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8= +google.golang.org/api v0.41.0/go.mod h1:RkxM5lITDfTzmyKFPt+wGrCJbVfniCr2ool8kTBzRTU= +google.golang.org/api v0.43.0/go.mod h1:nQsDGjRXMo4lvh5hP0TKqF244gqhGcr/YSIykhUk/94= +google.golang.org/api v0.47.0/go.mod h1:Wbvgpq1HddcWVtzsVLyfLp8lDg6AA241LmgIL59tHXo= +google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtukyy4= +google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw= +google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU= +google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k= +google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE= +google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI= +google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I= +google.golang.org/api v0.63.0/go.mod h1:gs4ij2ffTRXwuzzgJl/56BdwJaA194ijkfn++9tDuPo= +google.golang.org/api v0.67.0/go.mod h1:ShHKP8E60yPsKNw/w8w+VYaj9H6buA5UqDp8dhbQZ6g= +google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/SkfA= +google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= +google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= +google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= +google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw= +google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg= +google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o= +google.golang.org/api v0.85.0 h1:8rJoHuRxx+vCmZtAO/3k1dRLvYNVyTJtZ5oaFZvhgvc= +google.golang.org/api v0.85.0/go.mod h1:AqZf8Ep9uZ2pyTvgL+x0D3Zt0eoT9b5E8fmzfu6FO2g= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -463,6 +634,7 @@ google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= +google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= @@ -475,7 +647,54 @@ google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6D google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= +google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= +google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= +google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210608205507-b6d2f5bf0d7d/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= +google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24= +google.golang.org/genproto v0.0.0-20210713002101-d411969a0d9a/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210716133855-ce7ef5c701ea/go.mod h1:AxrInvYm1dci+enl5hChSFPOmmUF1+uAa/UsgNRWd7k= +google.golang.org/genproto v0.0.0-20210728212813-7823e685a01f/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w= +google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY= +google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20211221195035-429b39de9b1c/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220126215142-9970aeb2e350/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220207164111-0872dc986b00/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= +google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220304144024-325a89244dc8/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= +google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= +google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220421151946-72621c1f0bd3/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220429170224-98d788798c3e/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= +google.golang.org/genproto v0.0.0-20220505152158-f39f71e6c8f3/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220518221133-4f43b3371335/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4= +google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad h1:kqrS+lhvaMHCxul6sKQvKJ8nAAhlVItmZV822hYFH/U= +google.golang.org/genproto v0.0.0-20220617124728-180714bec0ad/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa h1:VWkrxnAx2C2hirAP+W5ADU7e/+93Yhk//ioKd2XFyDI= +google.golang.org/genproto v0.0.0-20220916172020-2692e8806bfa/go.mod h1:0Nb8Qy+Sk5eDzHnzlStwW3itdNaWoZA5XeSG+R3JHSo= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -489,9 +708,28 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU= +google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= +google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= +google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ= +google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8= +google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w= +google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk= +google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= @@ -502,6 +740,13 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= +google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= +google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= +google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw= +google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= +google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= @@ -510,6 +755,7 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI= gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/pkg/config/generic/repository.go b/pkg/config/generic/repository.go index cb1b705..5ffe9ca 100644 --- a/pkg/config/generic/repository.go +++ b/pkg/config/generic/repository.go @@ -32,7 +32,7 @@ type Repository struct { contexts []*Context // secrets holds all secrets of all contexts - secrets []*Secret + secrets []Secret // configs holds all configs of all contexts configs []*Config diff --git a/pkg/config/generic/repository_context.go b/pkg/config/generic/repository_context.go index 72ad720..d6236d4 100644 --- a/pkg/config/generic/repository_context.go +++ b/pkg/config/generic/repository_context.go @@ -4,15 +4,18 @@ import ( "encoding/base64" "fmt" config_const "github.com/benammann/git-secrets/pkg/config/const" + global_config "github.com/benammann/git-secrets/pkg/config/global" "github.com/benammann/git-secrets/pkg/encryption" ) type Context struct { Name string + GlobalConfig *global_config.GlobalConfigProvider SecretResolver encryption.SecretResolver - Encryption encryption.Engine - EncryptedSecrets map[string]string - Configs map[string]string + GcpCredentials string + Encryption encryption.Engine + Secrets map[string]Secret + Configs map[string]string } // AddContext adds a context and does some validations diff --git a/pkg/config/generic/repository_secret.go b/pkg/config/generic/repository_secret.go index c6282fb..856d6cb 100644 --- a/pkg/config/generic/repository_secret.go +++ b/pkg/config/generic/repository_secret.go @@ -6,25 +6,21 @@ import ( "sort" ) -type Secret struct { - - // Name describes the name of the secret - Name string - - // EncodedValue hold the encodedValue in base64 of the secret - EncodedValue string - - // OriginContext references the configured context to decode the secret - OriginContext *Context +type Secret interface { + GetName() string + GetOriginContext() *Context + GetPlainValue() (string, error) } // AddSecret adds a secret to the repository // also does some validations -func (c *Repository) AddSecret(secret *Secret) error { +func (c *Repository) AddSecret(secret Secret) error { + + secretName, secretContext := secret.GetName(), secret.GetOriginContext() // if not default secret we need to check if the given secret is also configured in the default context // because we are not allowed to define variables only in a child context - if secret.OriginContext.Name != config_const.DefaultContextName { + if secretContext.Name != config_const.DefaultContextName { // get all the default secrets defaultSecrets := c.GetSecretsByContext(config_const.DefaultContextName) @@ -32,7 +28,7 @@ func (c *Repository) AddSecret(secret *Secret) error { // check if it defined for _, defaultSecret := range defaultSecrets { - if defaultSecret.Name == secret.Name { + if defaultSecret.GetName() == secretName { defaultSecretFound = true break } @@ -40,7 +36,7 @@ func (c *Repository) AddSecret(secret *Secret) error { // return error if not defined if defaultSecretFound == false { - return fmt.Errorf("secret %s defined in context %s is not defined in the default context", secret.Name, secret.OriginContext.Name) + return fmt.Errorf("secret %s defined in context %s is not defined in the default context", secretName, secretContext.Name) } } @@ -50,16 +46,16 @@ func (c *Repository) AddSecret(secret *Secret) error { // sort the secrets alphabetically sort.SliceStable(c.secrets, func(i, j int) bool { - return c.secrets[i].Name < c.secrets[j].Name + return c.secrets[i].GetName() < c.secrets[j].GetName() }) return nil } // GetSecretsByContext returns all the secrets related to the current context -func (c *Repository) GetSecretsByContext(contextName string) (res []*Secret) { +func (c *Repository) GetSecretsByContext(contextName string) (res []Secret) { for _, secret := range c.secrets { - if secret.OriginContext.Name == contextName { + if secret.GetOriginContext().Name == contextName { res = append(res, secret) } } @@ -68,7 +64,7 @@ func (c *Repository) GetSecretsByContext(contextName string) (res []*Secret) { // GetCurrentSecrets merges the default secrets with the context secrets // the default secrets are overwritten by the context secrets -func (c *Repository) GetCurrentSecrets() (res []*Secret) { +func (c *Repository) GetCurrentSecrets() (res []Secret) { // get all default secrets defaultSecrets := c.GetSecretsByContext(config_const.DefaultContextName) @@ -84,7 +80,7 @@ func (c *Repository) GetCurrentSecrets() (res []*Secret) { found := false for _, contextSecret := range contextSecrets { - if defaultSecret.Name == contextSecret.Name { + if defaultSecret.GetName() == contextSecret.GetName() { found = true break } @@ -108,19 +104,15 @@ func (c *Repository) GetCurrentSecrets() (res []*Secret) { } // GetCurrentSecret takes the merged secrets from GetCurrentSecrets and returns the needed one -func (c *Repository) GetCurrentSecret(secretName string) *Secret { +func (c *Repository) GetCurrentSecret(secretName string) Secret { for _, secret := range c.GetCurrentSecrets() { - if secret.Name == secretName { + if secret.GetName() == secretName { return secret } } return nil } -func (s *Secret) Decode() (string, error) { - return s.OriginContext.DecodeValue(s.EncodedValue) -} - // GetSecretsMapDecoded decodes the secrets of the current context and puts them into a map[string]string func (c *Repository) GetSecretsMapDecoded() (SecretsMap, error) { @@ -129,11 +121,11 @@ func (c *Repository) GetSecretsMapDecoded() (SecretsMap, error) { // decode each secret for _, secret := range c.GetCurrentSecrets() { - decodedSecret, errDecode := secret.Decode() + decodedSecret, errDecode := secret.GetPlainValue() if errDecode != nil { - return nil, fmt.Errorf("could not decode secret %s: %s", secret.Name, errDecode.Error()) + return nil, fmt.Errorf("could not decode secret %s: %s", secret.GetName(), errDecode.Error()) } - secretsMap[secret.Name] = decodedSecret + secretsMap[secret.GetName()] = decodedSecret } return secretsMap, nil diff --git a/pkg/config/generic/repository_secret_encrypted.go b/pkg/config/generic/repository_secret_encrypted.go new file mode 100644 index 0000000..bbcf84e --- /dev/null +++ b/pkg/config/generic/repository_secret_encrypted.go @@ -0,0 +1,35 @@ +package config_generic + + +func NewEncryptedSecret(name string, encodedValue string, originContext *Context) *EncryptedSecret { + return &EncryptedSecret{ + Name: name, + EncodedValue: encodedValue, + OriginContext: originContext, + } +} + +type EncryptedSecret struct { + + // Name describes the name of the GcpSecret + Name string + + // EncodedValue hold the encodedValue in base64 of the GcpSecret + EncodedValue string + + // OriginContext references the configured context to decode the GcpSecret + OriginContext *Context +} + +func (s *EncryptedSecret) GetName() string { + return s.Name +} + +func (s *EncryptedSecret) GetOriginContext() *Context { + return s.OriginContext +} + +func (s *EncryptedSecret) GetPlainValue() (string, error) { + return s.OriginContext.DecodeValue(s.EncodedValue) +} + diff --git a/pkg/config/generic/repository_secret_gcp.go b/pkg/config/generic/repository_secret_gcp.go new file mode 100644 index 0000000..c0df903 --- /dev/null +++ b/pkg/config/generic/repository_secret_gcp.go @@ -0,0 +1,84 @@ +package config_generic + +import ( + secretmanager "cloud.google.com/go/secretmanager/apiv1" + "context" + "github.com/spf13/afero" + "golang.org/x/oauth2/google" + "google.golang.org/api/option" + secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1" + "log" +) + +func NewGcpSecret(name string, resourceId string, originContext *Context) *GcpSecret { + return &GcpSecret{ + Name: name, + ResourceId: resourceId, + OriginContext: originContext, + } +} + +type GcpSecret struct { + + // Name describes the name of the GcpSecret + Name string + + // ResourceId hold the encodedValue in base64 of the GcpSecret + ResourceId string + + // OriginContext references the configured context to decode the GcpSecret + OriginContext *Context +} + +func (s *GcpSecret) GetName() string { + return s.Name +} + +func (s *GcpSecret) GetOriginContext() *Context { + return s.OriginContext +} + +func (s *GcpSecret) GetPlainValue() (string, error) { + + file := s.OriginContext.GlobalConfig.GetGcpCredentialsFile(s.OriginContext.GcpCredentials) + credentials, errCredentials := initCredentialsFromFile(afero.NewOsFs(), file, "https://www.googleapis.com/auth/cloud-platform") + if errCredentials != nil { + return "", errCredentials + } + + // Create the client. + ctx := context.Background() + client, err := secretmanager.NewClient(ctx, option.WithCredentials(credentials)) + if err != nil { + log.Fatalf("failed to setup client: %v", err) + } + defer client.Close() + + res, err := client.AccessSecretVersion(ctx, &secretmanagerpb.AccessSecretVersionRequest{ + Name: s.ResourceId, + }) + + if err != nil { + return "", err + } + + return string(res.Payload.GetData()), nil +} + +func initCredentialsFromFile(fs afero.Fs, fileName string, scopes ...string) (*google.Credentials, error) { + + ctx := context.Background() + + data, err := afero.ReadFile(fs, fileName) + if err != nil { + log.Fatal(err) + } + + creds, err := google.CredentialsFromJSON(ctx, data, scopes...) + if err != nil { + log.Fatal(err) + } + + return creds, err + +} \ No newline at end of file diff --git a/pkg/config/generic/schema_v1.go b/pkg/config/generic/schema_v1.go index d899566..bfa64bf 100644 --- a/pkg/config/generic/schema_v1.go +++ b/pkg/config/generic/schema_v1.go @@ -11,8 +11,26 @@ import ( "github.com/xeipuuv/gojsonschema" "path/filepath" "sort" + "strings" ) +type SecretEntry interface { + string | SecretEntryTypes +} + +type SecretEntryTypes struct { + Encrypted *SecretEntryEncrypted `json:"encrypted,omitempty"` + Gcp *SecretEntryGcp `json:"gcp,omitempty"` +} + +type SecretEntryEncrypted struct { + Value string `json:"value"` +} + +type SecretEntryGcp struct { + ResourceId string `json:"resourceId"` +} + type V1Schema struct { Schema string `json:"$schema,omitempty"` Version int `json:"version"` @@ -27,10 +45,40 @@ type V1DecryptSecret struct { type V1ContextAwareSecrets struct { DecryptSecret *V1DecryptSecret `json:"decryptSecret,omitempty"` - Secrets map[string]string `json:"secrets,omitempty"` + GcpCredentials string `json:"gcpCredentials,omitempty"` + Secrets map[string]*SecretEntryTypes `json:"secrets,omitempty"` Configs map[string]string `json:"configs,omitempty"` } +func (se *SecretEntryTypes) UnmarshalJSON(data []byte) error { + stringVal := string(data) + if !strings.Contains(stringVal, "{") { + + var stringValOut string + if err := json.Unmarshal(data, &stringValOut); err != nil { + return err + } + + se.Encrypted = &SecretEntryEncrypted{ + Value: stringValOut, + } + + return nil + } + + type tmpSecretEntryTypes SecretEntryTypes + var res tmpSecretEntryTypes + + if err := json.Unmarshal(data, &res); err != nil { + return err + } + + se.Encrypted = res.Encrypted + se.Gcp = res.Gcp + + return nil +} + type V1Context map[string]*V1ContextAwareSecrets type V1RenderTargetFileEntry struct { @@ -88,7 +136,7 @@ func (s *V1Schema) validateSchemaV1() error { if contextValue.Secrets != nil { for secretKey, _ := range contextValue.Secrets { - if defaultContext.Secrets[secretKey] == "" { + if defaultContext.Secrets[secretKey] == nil { return fmt.Errorf("secret %s exists in context %s but not in default context", secretKey, contextKey) } } @@ -144,11 +192,26 @@ func ParseSchemaV1(jsonInput []byte, configFileUsed string, globalConfig *global // first, initialize all contexts for contextKey, contextValue := range Parsed.Context { + localContext := &Context{ - Name: contextKey, - EncryptedSecrets: contextValue.Secrets, - Configs: contextValue.Configs, + Name: contextKey, + Secrets: nil, + Configs: contextValue.Configs, + GlobalConfig: globalConfig, + } + + secretsOut := make(map[string]Secret) + + for secretKey, encryptedSecret := range contextValue.Secrets { + if encryptedSecret.Encrypted != nil { + secretsOut[secretKey] = NewEncryptedSecret(secretKey, encryptedSecret.Encrypted.Value, localContext) + } else if encryptedSecret.Gcp != nil { + secretsOut[secretKey] = NewGcpSecret(secretKey, encryptedSecret.Gcp.ResourceId, localContext) + } } + + localContext.Secrets = secretsOut + // reference the default context if localContext.Name == config_const.DefaultContextName { defaultContext = localContext @@ -164,6 +227,7 @@ func ParseSchemaV1(jsonInput []byte, configFileUsed string, globalConfig *global for _, context := range contexts { context.SecretResolver = getSecretResolverV1(Parsed.Context[context.Name].DecryptSecret, defaultContext, globalConfig, overwrittenSecrets) context.Encryption = encryption.NewAesEngine(context.SecretResolver) + context.GcpCredentials = Parsed.Context[context.Name].GcpCredentials } if Parsed.RenderFiles != nil { @@ -184,18 +248,15 @@ func ParseSchemaV1(jsonInput []byte, configFileUsed string, globalConfig *global } } - var secrets []*Secret + var secrets []Secret for _, context := range contexts { - for secretKey, encryptedSecret := range context.EncryptedSecrets { - secrets = append(secrets, &Secret{ - Name: secretKey, - OriginContext: context, - EncodedValue: encryptedSecret, - }) + for _, secret := range context.Secrets { + secrets = append(secrets, secret) } } + var configs []*Config for _, context := range contexts { for configKey, configValue := range context.Configs { diff --git a/pkg/config/generic/schema_v1_writer.go b/pkg/config/generic/schema_v1_writer.go index c9cdfe7..6f6fd85 100644 --- a/pkg/config/generic/schema_v1_writer.go +++ b/pkg/config/generic/schema_v1_writer.go @@ -22,30 +22,38 @@ func NewV1Writer(fs afero.Fs, schema V1Schema, configPath string) *V1Writer { } } -func (v *V1Writer) SetSecret(contextName string, secretName string, secretEncodedValue string, force bool) error { +func (v *V1Writer) SetEncryptedSecret(contextName string, secretName string, secretEncodedValue string, force bool) error { if v.schema.Context[contextName] == nil { return fmt.Errorf("the context %s does not exist", contextName) } if v.schema.Context[contextName].Secrets == nil { - v.schema.Context[contextName].Secrets = make(map[string]string) + v.schema.Context[contextName].Secrets = make(map[string]*SecretEntryTypes) } - if contextName != config_const.DefaultContextName && v.schema.Context[config_const.DefaultContextName].Secrets[secretName] == "" { + if contextName != config_const.DefaultContextName && v.schema.Context[config_const.DefaultContextName].Secrets[secretName] == nil { return fmt.Errorf("you need to define secret entry %s in the default context first", secretName) } - if v.schema.Context[contextName].Secrets[secretName] != "" && force == false { + if v.schema.Context[contextName].Secrets[secretName] != nil && force == false { return fmt.Errorf("the secret %s does already exist. Use --force to overwrite", secretName) } - v.schema.Context[contextName].Secrets[secretName] = secretEncodedValue + v.schema.Context[contextName].Secrets[secretName] = &SecretEntryTypes{ + Encrypted: &SecretEntryEncrypted{ + Value: secretEncodedValue, + }, + } return v.WriteConfig() } +func (v *V1Writer) SetGcpSecret(contextName string, secretName string, resourceId string, force bool) error { + return nil +} + func (v *V1Writer) SetConfig(contextName string, configName string, configValue string, force bool) error { if v.schema.Context[contextName] == nil { @@ -77,7 +85,7 @@ func (v *V1Writer) AddContext(contextName string) error { } v.schema.Context[contextName] = &V1ContextAwareSecrets{ - Secrets: make(map[string]string), + Secrets: make(map[string]*SecretEntryTypes), Configs: make(map[string]string), } @@ -123,7 +131,7 @@ func (v *V1Writer) WriteConfig() error { for contextName, context := range v.schema.Context { if context.Secrets == nil && contextName == config_const.DefaultContextName { - context.Secrets = make(map[string]string) + context.Secrets = make(map[string]*SecretEntryTypes) } } diff --git a/pkg/config/generic/schema_v1_writer_test.go b/pkg/config/generic/schema_v1_writer_test.go index 76776c1..8079e35 100644 --- a/pkg/config/generic/schema_v1_writer_test.go +++ b/pkg/config/generic/schema_v1_writer_test.go @@ -181,14 +181,14 @@ func TestV1Writer_SetSecret(t *testing.T) { t.Run("fail if context does not exists", func(t *testing.T) { writer, original, getSchema := NewWrappedV1Writer(t, TestFileRealWorld) assert.Nil(t, original.Context["missing"]) - assert.Error(t, writer.SetSecret("missing", "databaseHost", "", false)) + assert.Error(t, writer.SetEncryptedSecret("missing", "databaseHost", "", false)) assert.Nil(t, getSchema().Context["missing"]) }) t.Run("initialize secrets struct", func(t *testing.T) { writer, original, getSchema := NewWrappedV1Writer(t, TestFileConfigEntries) assert.Nil(t, original.Context["default"].Secrets) - assert.NoError(t, writer.SetSecret("default", "testKey", "", false)) + assert.NoError(t, writer.SetEncryptedSecret("default", "testKey", "", false)) assert.NotNil(t, getSchema().Context["default"].Secrets) assert.Equal(t, "", getSchema().Context["default"].Secrets["testKey"]) }) @@ -197,10 +197,10 @@ func TestV1Writer_SetSecret(t *testing.T) { writer, original, getSchema := NewWrappedV1Writer(t, TestFileRealWorld) assert.Equal(t, "prPy40oRzdeFelmL5xVhbadEWNV9puR3/aWTY+gTYXOrT2bksi5GS9lCTKi66A3ePYa0hbwMqXadlDZw", original.Context["default"].Secrets["databasePassword"]) - assert.Error(t, writer.SetSecret("default", "databasePassword", "", false)) + assert.Error(t, writer.SetEncryptedSecret("default", "databasePassword", "", false)) assert.Equal(t, "prPy40oRzdeFelmL5xVhbadEWNV9puR3/aWTY+gTYXOrT2bksi5GS9lCTKi66A3ePYa0hbwMqXadlDZw", original.Context["default"].Secrets["databasePassword"]) - assert.NoError(t, writer.SetSecret("default", "databasePassword", "", true)) + assert.NoError(t, writer.SetEncryptedSecret("default", "databasePassword", "", true)) assert.Equal(t, "", getSchema().Context["default"].Secrets["databasePassword"]) }) @@ -210,13 +210,13 @@ func TestV1Writer_SetSecret(t *testing.T) { assert.Equal(t, "", original.Context["default"].Secrets["databaseRootPassword"]) assert.Equal(t, "", original.Context["prod"].Secrets["databaseRootPassword"]) - assert.Error(t, writer.SetSecret("prod", "databaseRootPassword", "", false)) + assert.Error(t, writer.SetEncryptedSecret("prod", "databaseRootPassword", "", false)) assert.Equal(t, "", getSchema().Context["prod"].Secrets["databaseRootPassword"]) - assert.NoError(t, writer.SetSecret("default", "databaseRootPassword", "", false)) + assert.NoError(t, writer.SetEncryptedSecret("default", "databaseRootPassword", "", false)) assert.Equal(t, "", original.Context["default"].Secrets["databaseRootPassword"]) - assert.NoError(t, writer.SetSecret("prod", "databaseRootPassword", "", false)) + assert.NoError(t, writer.SetEncryptedSecret("prod", "databaseRootPassword", "", false)) assert.Equal(t, "", getSchema().Context["prod"].Secrets["databaseRootPassword"]) }) @@ -224,10 +224,10 @@ func TestV1Writer_SetSecret(t *testing.T) { t.Run("should write the secret entry", func(t *testing.T) { writer, original, getSchema := NewWrappedV1Writer(t, TestFileRealWorld) assert.Equal(t, "", original.Context["default"].Secrets["databaseRootPassword"]) - assert.NoError(t, writer.SetSecret("default", "databaseRootPassword", "", false)) + assert.NoError(t, writer.SetEncryptedSecret("default", "databaseRootPassword", "", false)) assert.Equal(t, "", getSchema().Context["default"].Secrets["databaseRootPassword"]) - assert.NoError(t, writer.SetSecret("prod", "databaseRootPassword", "", false)) + assert.NoError(t, writer.SetEncryptedSecret("prod", "databaseRootPassword", "", false)) assert.Equal(t, "", getSchema().Context["prod"].Secrets["databaseRootPassword"]) }) diff --git a/pkg/config/global/global_config.go b/pkg/config/global/global_config.go index d099ae3..dc31f7e 100644 --- a/pkg/config/global/global_config.go +++ b/pkg/config/global/global_config.go @@ -8,6 +8,7 @@ import ( ) const SecretKeyPrefix = "secrets" +const GcpCredentialsPrefix = "gcp.credentials" type GlobalConfigProvider struct { storageProvider StorageProvider @@ -23,6 +24,10 @@ func (g *GlobalConfigProvider) GetSecret(secretKey string) (value string) { return g.storageProvider.GetString(g.secretConfigKey(secretKey)) } +func (g *GlobalConfigProvider) GetGcpCredentialsFile(credentialsName string) string { + return g.storageProvider.GetString(g.gcpCredentialsKey(credentialsName)) +} + func (g *GlobalConfigProvider) SetSecret(secretKey string, secretValue string, force bool) error { errValidate := g.validateSecret(secretKey, secretValue) @@ -42,6 +47,22 @@ func (g *GlobalConfigProvider) SetSecret(secretKey string, secretValue string, f return g.storageProvider.WriteConfig() } +func (g *GlobalConfigProvider) SetGcpCredentials(credentialsName string, pathToFile string, force bool) error { + + + configKey := g.gcpCredentialsKey(credentialsName) + + exists := g.GetGcpCredentialsFile(credentialsName) != "" + if exists && force == false { + return fmt.Errorf("gcp credentials %s already exists. use --force to overwrite", configKey) + } + + g.storageProvider.Set(configKey, pathToFile) + + return g.storageProvider.WriteConfig() + +} + func (g *GlobalConfigProvider) GetSecretKeys() []string { var secretKeys []string for _, key := range g.storageProvider.AllKeys() { @@ -58,6 +79,10 @@ func (g *GlobalConfigProvider) secretConfigKey(secretKey string) string { return fmt.Sprintf("%s.%s", SecretKeyPrefix, strings.ToLower(secretKey)) } +func (g *GlobalConfigProvider) gcpCredentialsKey(credentialsName string) string { + return fmt.Sprintf("%s.%s", GcpCredentialsPrefix, strings.ToLower(credentialsName)) +} + func (g *GlobalConfigProvider) validateSecret(secretKey string, secretValue string) error { if !regexp.MustCompile(`^[A-Za-z1-9]+$`).MatchString(secretKey) { diff --git a/pkg/config/writer/writer.go b/pkg/config/writer/writer.go index 843c5df..a6d3636 100644 --- a/pkg/config/writer/writer.go +++ b/pkg/config/writer/writer.go @@ -1,7 +1,8 @@ package writer type ConfigWriter interface { - SetSecret(contextName string, secretName string, secretEncodedValue string, force bool) error + SetEncryptedSecret(contextName string, secretName string, secretEncodedValue string, force bool) error + SetGcpSecret(contextName string, secretName string, resourceId string, force bool) error SetConfig(contextName string, configName string, configValue string, force bool) error AddContext(contextName string) error AddFileToRender(targetName string, fileIn string, fileOut string) error diff --git a/schema/def/v1.json b/schema/def/v1.json index 1f90f54..eb97808 100644 --- a/schema/def/v1.json +++ b/schema/def/v1.json @@ -19,6 +19,9 @@ "description": "The default context, you can specify the context by using -c ", "type": "object", "properties": { + "gcpCredentials": { + "type": "string" + }, "decryptSecret": { "type": "object", "description": "How to decode the secrets, available: fromName or fromEnv\nYou can only use one\nYou can also overwrite the decodeSecret method in another context\nSo you can use another secret encoding for your production secrets to protect them from the developers for example", @@ -47,8 +50,33 @@ "description": "Specify your secrets here", "patternProperties": { ".*": { - "description": "Encode them via git-secrets encode and them copy them here\nAvailable in the template via {{.Secrets.secretName}}", - "type": "string" + "anyOf": [ + { + "type": "object", + "properties": { + "encrypted": { + "type": "object", + "properties": { + "value": { + "type": "string", + "required": ["value"] + } + } + }, + "gcp": { + "type": "object", + "properties": { + "resourceId": { + "type": "string" + } + } + } + } + }, + { + "type": "string" + } + ] } } }, @@ -73,6 +101,9 @@ "description": "This is a custom context, you can specify the context by using -c ", "type": "object", "properties": { + "gcpCredentials": { + "type": "string" + }, "decryptSecret": { "type": "object", "description": "How to decode the secrets, available: fromName or fromEnv\nYou can only use one\nYou can also overwrite the decodeSecret method in another context\nSo you can use another secret encoding for your production secrets to protect them from the developers for example", @@ -98,11 +129,28 @@ }, "secrets": { "type": "object", - "description": "Allows to overwrite secrets from the default context", + "description": "Specify your secrets here", "patternProperties": { ".*": { - "description": "This secret overwrites the secret from the default context", - "type": "string" + "anyOf": [ + { + "type": "object", + "properties": { + "encrypted": { + "type": "object", + "properties": { + "value": { + "type": "string", + "required": ["value"] + } + } + } + } + }, + { + "type": "string" + } + ] } } }, From 16bc73c51a599aeb3c35ffe6d77325cd9d2d86c5 Mon Sep 17 00:00:00 2001 From: Ben Ammann Date: Sun, 18 Sep 2022 20:08:20 +0200 Subject: [PATCH 2/5] gcp demo --- .git-secrets.json | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/.git-secrets.json b/.git-secrets.json index bb11118..56cfbd3 100644 --- a/.git-secrets.json +++ b/.git-secrets.json @@ -3,15 +3,31 @@ "version": 1, "context": { "default": { + "gcpCredentials": "private-cli", "decryptSecret": { "fromName": "gitsecretspublicnew" }, "secrets": { - "crToken": "sybpBnwiGQ+TmsIL00ordYwVMS44FLcN7gEsQ0uSNQNhH1WFE/qW/7CuMyYrHGo/AL+fJs/WAcayW5qHaq6cAw==" + "crToken": "sybpBnwiGQ+TmsIL00ordYwVMS44FLcN7gEsQ0uSNQNhH1WFE/qW/7CuMyYrHGo/AL+fJs/WAcayW5qHaq6cAw==", + "fromGcp": { + "gcp": { + "resourceId": "projects/806001934377/secrets/awesomeSecret/versions/2" + } + } }, "configs": { "crUser": "benammann" } + }, + "prod": { + "gcpCredentials": "private-cli", + "secrets": { + "fromGcp": { + "gcp": { + "resourceId": "projects/806001934377/secrets/awesomeSecret/versions/1" + } + } + } } } } \ No newline at end of file From 02f6af20b1dd0a44149bb390eddb4c479f2d5998 Mon Sep 17 00:00:00 2001 From: Ben Ammann Date: Fri, 21 Oct 2022 11:01:24 +0200 Subject: [PATCH 3/5] wip --- .env | 0 .env.dist | 1 + .git-secrets.json | 34 ++++- cmd/get.go | 2 +- cmd/info.go | 6 +- cmd/render.go | 4 +- cmd/root.go | 42 +++++- cmd/scan.go | 2 +- cmd/set.go | 75 +++++++++- pkg/config/generic/repository.go | 13 ++ pkg/config/generic/repository_secret.go | 8 +- .../generic/repository_secret_encrypted.go | 7 +- pkg/config/generic/repository_secret_gcp.go | 59 +++----- pkg/config/generic/schema_v1.go | 6 +- pkg/config/generic/schema_v1_writer.go | 31 +++- pkg/config/global/global_config.go | 34 +++++ pkg/gcp/gcp.go | 134 ++++++++++++++++++ pkg/render/render.go | 17 +-- pkg/render/render_test.go | 11 +- pkg/utility/utility_context.go | 22 +++ schema/def/v1.json | 8 ++ 21 files changed, 436 insertions(+), 80 deletions(-) create mode 100644 .env create mode 100644 .env.dist create mode 100644 pkg/gcp/gcp.go create mode 100644 pkg/utility/utility_context.go diff --git a/.env b/.env new file mode 100644 index 0000000..e69de29 diff --git a/.env.dist b/.env.dist new file mode 100644 index 0000000..e450201 --- /dev/null +++ b/.env.dist @@ -0,0 +1 @@ +MY_ENV={{.Secrets.fromGcp}} diff --git a/.git-secrets.json b/.git-secrets.json index 56cfbd3..7adade6 100644 --- a/.git-secrets.json +++ b/.git-secrets.json @@ -3,16 +3,30 @@ "version": 1, "context": { "default": { - "gcpCredentials": "private-cli", "decryptSecret": { "fromName": "gitsecretspublicnew" }, + "gcpCredentials": "private-cli", "secrets": { - "crToken": "sybpBnwiGQ+TmsIL00ordYwVMS44FLcN7gEsQ0uSNQNhH1WFE/qW/7CuMyYrHGo/AL+fJs/WAcayW5qHaq6cAw==", + "crToken": { + "encrypted": { + "value": "sybpBnwiGQ+TmsIL00ordYwVMS44FLcN7gEsQ0uSNQNhH1WFE/qW/7CuMyYrHGo/AL+fJs/WAcayW5qHaq6cAw==" + } + }, "fromGcp": { "gcp": { "resourceId": "projects/806001934377/secrets/awesomeSecret/versions/2" } + }, + "fromGcp1": { + "gcp": { + "resourceId": "projects/806001934377/secrets/awesomeSecret/versions/1" + } + }, + "fromGcp2": { + "gcp": { + "resourceId": "projects/806001934377/secrets/awesomeSecret/versions/2" + } } }, "configs": { @@ -20,8 +34,12 @@ } }, "prod": { - "gcpCredentials": "private-cli", "secrets": { + "crToken": { + "gcp": { + "resourceId": "projects/806001934377/secrets/awesomeSecret/versions/1" + } + }, "fromGcp": { "gcp": { "resourceId": "projects/806001934377/secrets/awesomeSecret/versions/1" @@ -29,5 +47,15 @@ } } } + }, + "renderFiles": { + "env": { + "files": [ + { + "fileIn": ".env.dist", + "fileOut": ".env" + } + ] + } } } \ No newline at end of file diff --git a/cmd/get.go b/cmd/get.go index 1a510d5..8c937c6 100644 --- a/cmd/get.go +++ b/cmd/get.go @@ -54,7 +54,7 @@ git secrets get secret -c prod if secretEntry == nil { cobra.CheckErr(fmt.Errorf("the secret %s does not exist on context %s", secretKey, selectedContext.Name)) } - decodedValue, errDecode := secretEntry.GetPlainValue() + decodedValue, errDecode := secretEntry.GetPlainValue(cmd.Context()) if errDecode != nil { cobra.CheckErr(fmt.Errorf("could not decode secret %s: %s", secretKey, errDecode.Error())) } diff --git a/cmd/info.go b/cmd/info.go index ceffcc6..5769dab 100644 --- a/cmd/info.go +++ b/cmd/info.go @@ -61,7 +61,7 @@ git secrets info -d -c prod: Decodes all secrets from the prod context shouldDecode, _ := cmd.Flags().GetBool(InfoCmdFlagDecode) - tableHeader := []string{"Secret Name", "Origin Context"} + tableHeader := []string{"Type", "Secret Name", "Origin Context"} if shouldDecode { tableHeader = append(tableHeader, "Decoded Value") } @@ -70,9 +70,9 @@ git secrets info -d -c prod: Decodes all secrets from the prod context for _, secret := range projectCfg.GetCurrentSecrets() { - tableRow := []string{secret.GetName(), secret.GetOriginContext().Name} + tableRow := []string{secret.GetType(), secret.GetName(), secret.GetOriginContext().Name} if shouldDecode { - decodedValue, errDecode := secret.GetPlainValue() + decodedValue, errDecode := secret.GetPlainValue(cmd.Context()) if errDecode != nil { fmt.Printf("Could not decode %s: %s\n", secret.GetName(), errDecode.Error()) continue diff --git a/cmd/render.go b/cmd/render.go index a5442ca..2587045 100644 --- a/cmd/render.go +++ b/cmd/render.go @@ -81,7 +81,7 @@ git secrets render --debug: Render and write the rendering target for _, fileToRender := range filesToRender { if isDryRun { - usedContext, fileContents, errRender := renderingEngine.RenderFile(fileToRender) + usedContext, fileContents, errRender := renderingEngine.RenderFile(cmd.Context(), fileToRender) if isDebug { fmt.Println(fileToRender.FileIn) if usedContext != nil { @@ -95,7 +95,7 @@ git secrets render --debug: Render and write the rendering target } fmt.Println(fileContents) } else { - usedContext, errWrite := renderingEngine.WriteFile(fileToRender) + usedContext, errWrite := renderingEngine.WriteFile(cmd.Context(), fileToRender) if isDebug && usedContext != nil { fmt.Println(fileToRender.FileIn) renderContextJson, _ := json.MarshalIndent(usedContext, "", " ") diff --git a/cmd/root.go b/cmd/root.go index f4570d9..4625ae3 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -1,16 +1,19 @@ package cmd import ( + "context" config_const "github.com/benammann/git-secrets/pkg/config/const" config_generic "github.com/benammann/git-secrets/pkg/config/generic" global_config "github.com/benammann/git-secrets/pkg/config/global" "github.com/benammann/git-secrets/pkg/render" + "github.com/benammann/git-secrets/pkg/utility" "github.com/spf13/afero" "github.com/spf13/cobra" + "github.com/spf13/viper" "os" "strings" - - "github.com/spf13/viper" + "sync" + "time" ) var fs = afero.NewOsFs() @@ -31,7 +34,10 @@ var contextName string var overwrittenSecrets []string +var waitGroupSize = 0 + const FlagValue = "value" +const FlagResourceId = "resourceId" const FlagForce = "force" const FlagDebug = "debug" const FlagDryRun = "dry-run" @@ -64,7 +70,37 @@ func Execute(buildVersion string, buildCommit string, buildDate string) { version = buildVersion commit = buildCommit date = buildDate - cobra.CheckErr(rootCmd.Execute()) + + ctx := utility.NewChannelContext() + addChannel, doneChannel := utility.GetContextChannels(ctx) + ctx, cancel := context.WithCancel(ctx) + + var waitGroup sync.WaitGroup + timeout, _ := context.WithTimeout(context.Background(), time.Second * 5) + + go func() { + for { + select { + case val := <-addChannel: + waitGroupSize = waitGroupSize + val + waitGroup.Add(val) + case <-doneChannel: + waitGroup.Done() + waitGroupSize-- + case <-timeout.Done(): + for waitGroupSize > 0 { + waitGroup.Done() + waitGroupSize-- + } + } + } + }() + + cobra.CheckErr(rootCmd.ExecuteContext(ctx)) + cancel() + + waitGroup.Wait() + } func init() { diff --git a/cmd/scan.go b/cmd/scan.go index 69c6c45..d9b0be5 100644 --- a/cmd/scan.go +++ b/cmd/scan.go @@ -48,7 +48,7 @@ var scanCmd = &cobra.Command{ for _, context := range projectCfg.GetContexts() { contextSecrets := projectCfg.GetSecretsByContext(context.Name) for _, secret := range contextSecrets { - decodedValue, errDecode := secret.GetPlainValue() + decodedValue, errDecode := secret.GetPlainValue(cmd.Context()) if errDecode != nil { color.Yellow("Warning: could not decode secret %s from context %s, skipping this secret\n", secret.GetName(), secret.GetOriginContext().Name) continue diff --git a/cmd/set.go b/cmd/set.go index e10647f..69360bd 100644 --- a/cmd/set.go +++ b/cmd/set.go @@ -1,8 +1,10 @@ package cmd import ( + "errors" "fmt" "github.com/AlecAivazis/survey/v2" + "github.com/benammann/git-secrets/pkg/gcp" "github.com/spf13/cobra" ) @@ -38,13 +40,21 @@ git secrets set config -c prod }, } -// setSecretCmd represents the setSecret command var setSecretCmd = &cobra.Command{ - Use: "secret", + Use: "secret", + Short: "Commands to write secrets to the config", + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, +} + +// setEncryptedSecretCmd represents the setSecret command +var setEncryptedSecretCmd = &cobra.Command{ + Use: "encrypted", Short: "Encode and write a secret to the config file", Example: ` -git secrets set secret : Encodes the secret using interactive ui and adds it to the git secrets file -git secrets set secret --value : INSECURE: Uses the value directly from the --value parameter +git secrets set secret encrypted : Encodes the secret using interactive ui and adds it to the git secrets file +git secrets set secret encrypted --value : INSECURE: Uses the value directly from the --value parameter `, Args: cobra.ExactArgs(1), PersistentPreRun: func(cmd *cobra.Command, args []string) { @@ -78,12 +88,65 @@ git secrets set secret --value : INSECURE: Uses the valu }, } +// setEncryptedSecretCmd represents the setSecret command +var setGcpSecretCommand = &cobra.Command{ + Use: "gcp", + Short: "Encode and write a secret to the config file", + Example: ` +git secrets set secret gcp : Resolves the available secrets from secret manager +git secrets set secret gcp --resourceId : Uses the resource url directly from the --resourceId parameter. +`, + Args: cobra.ExactArgs(1), + PersistentPreRun: func(cmd *cobra.Command, args []string) { + cobra.CheckErr(projectCfgError) + }, + RunE: func(cmd *cobra.Command, args []string) error { + + secretKey := args[0] + resourceId, _ := cmd.Flags().GetString(FlagResourceId) + force, _ := cmd.Flags().GetBool(FlagForce) + + if projectCfg.GetDefault().GcpCredentials == "" { + return fmt.Errorf("you need to configure gcp credentials first") + } + credentialsName, errCredentials := projectCfg.GetCurrentGCPCredentialsName() + cobra.CheckErr(errCredentials) + credentialsFileName := globalCfg.GetGcpCredentialsFile(credentialsName) + + if resourceId == "" { + gcpSecrets, errSecrets := gcp.ListSecrets(cmd.Context(), credentialsFileName) + cobra.CheckErr(errSecrets) + for _, secret := range gcpSecrets { + fmt.Println(secret.GetEtag()) + } + cobra.CheckErr(errors.New("selection not supported yet. use --resourceId ")) + } + + writer := projectCfg.GetConfigWriter() + + errWrite := writer.SetGcpSecret(projectCfg.GetCurrent().Name, secretKey, resourceId, force) + cobra.CheckErr(errWrite) + + fmt.Printf("The secret %s has been written\n", secretKey) + fmt.Printf("Resolve the decoded value: git secrets get secret %s\n", secretKey) + fmt.Printf("Use it in a template: MY_CONFIG_KEY={{.Secrets.%s}}\n", secretKey) + + return nil + + }, +} + func init() { - for _, cmd := range []*cobra.Command{setConfigCmd, setSecretCmd} { + for _, cmd := range []*cobra.Command{setConfigCmd, setEncryptedSecretCmd, setGcpSecretCommand} { cmd.Flags().Bool(FlagForce, false, "use --force to overwrite an existing value") } - setSecretCmd.Flags().String(FlagValue, "", "--value : This is insecure, use --value $ENV_VALUE to not write the secret value to the history file.") + setEncryptedSecretCmd.Flags().String(FlagValue, "", "--value : This is insecure, use --value $ENV_VALUE to not write the secret value to the history file.") + setGcpSecretCommand.Flags().String(FlagResourceId, "", "--resourceId : Uses the resource url directly from the --resourceId parameter.") rootCmd.AddCommand(setCmd) + + setSecretCmd.AddCommand(setEncryptedSecretCmd) + setSecretCmd.AddCommand(setGcpSecretCommand) + setCmd.AddCommand(setConfigCmd) setCmd.AddCommand(setSecretCmd) } diff --git a/pkg/config/generic/repository.go b/pkg/config/generic/repository.go index 5ffe9ca..25ee55a 100644 --- a/pkg/config/generic/repository.go +++ b/pkg/config/generic/repository.go @@ -1,6 +1,7 @@ package config_generic import ( + "fmt" config_const "github.com/benammann/git-secrets/pkg/config/const" "github.com/benammann/git-secrets/pkg/config/writer" ) @@ -58,3 +59,15 @@ func (c *Repository) IsDefault() bool { func (c *Repository) GetConfigWriter() writer.ConfigWriter { return c.configWriter } + +func (c *Repository) GetCurrentGCPCredentialsName() (string, error) { + defaultCtx := c.GetDefault() + currentCtx := c.GetCurrent() + if currentCtx.GcpCredentials == "" && defaultCtx.GcpCredentials == "" { + return "", fmt.Errorf("there are no gcp credentials configured") + } + if currentCtx.GcpCredentials != "" { + return currentCtx.GcpCredentials, nil + } + return defaultCtx.GcpCredentials, nil +} \ No newline at end of file diff --git a/pkg/config/generic/repository_secret.go b/pkg/config/generic/repository_secret.go index 856d6cb..6221538 100644 --- a/pkg/config/generic/repository_secret.go +++ b/pkg/config/generic/repository_secret.go @@ -1,15 +1,17 @@ package config_generic import ( + "context" "fmt" config_const "github.com/benammann/git-secrets/pkg/config/const" "sort" ) type Secret interface { + GetType() string GetName() string GetOriginContext() *Context - GetPlainValue() (string, error) + GetPlainValue(ctx context.Context) (string, error) } // AddSecret adds a secret to the repository @@ -114,14 +116,14 @@ func (c *Repository) GetCurrentSecret(secretName string) Secret { } // GetSecretsMapDecoded decodes the secrets of the current context and puts them into a map[string]string -func (c *Repository) GetSecretsMapDecoded() (SecretsMap, error) { +func (c *Repository) GetSecretsMapDecoded(ctx context.Context) (SecretsMap, error) { // create the secrets map secretsMap := make(SecretsMap) // decode each secret for _, secret := range c.GetCurrentSecrets() { - decodedSecret, errDecode := secret.GetPlainValue() + decodedSecret, errDecode := secret.GetPlainValue(ctx) if errDecode != nil { return nil, fmt.Errorf("could not decode secret %s: %s", secret.GetName(), errDecode.Error()) } diff --git a/pkg/config/generic/repository_secret_encrypted.go b/pkg/config/generic/repository_secret_encrypted.go index bbcf84e..0d178d9 100644 --- a/pkg/config/generic/repository_secret_encrypted.go +++ b/pkg/config/generic/repository_secret_encrypted.go @@ -1,5 +1,6 @@ package config_generic +import "context" func NewEncryptedSecret(name string, encodedValue string, originContext *Context) *EncryptedSecret { return &EncryptedSecret{ @@ -21,6 +22,10 @@ type EncryptedSecret struct { OriginContext *Context } +func (s *EncryptedSecret) GetType() string { + return "encrypted" +} + func (s *EncryptedSecret) GetName() string { return s.Name } @@ -29,7 +34,7 @@ func (s *EncryptedSecret) GetOriginContext() *Context { return s.OriginContext } -func (s *EncryptedSecret) GetPlainValue() (string, error) { +func (s *EncryptedSecret) GetPlainValue(ctx context.Context) (string, error) { return s.OriginContext.DecodeValue(s.EncodedValue) } diff --git a/pkg/config/generic/repository_secret_gcp.go b/pkg/config/generic/repository_secret_gcp.go index c0df903..e1e5d47 100644 --- a/pkg/config/generic/repository_secret_gcp.go +++ b/pkg/config/generic/repository_secret_gcp.go @@ -1,13 +1,8 @@ package config_generic import ( - secretmanager "cloud.google.com/go/secretmanager/apiv1" "context" - "github.com/spf13/afero" - "golang.org/x/oauth2/google" - "google.golang.org/api/option" - secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1" - "log" + "github.com/benammann/git-secrets/pkg/gcp" ) func NewGcpSecret(name string, resourceId string, originContext *Context) *GcpSecret { @@ -28,6 +23,14 @@ type GcpSecret struct { // OriginContext references the configured context to decode the GcpSecret OriginContext *Context + + // resolvedPayload holds the resolved secret payload and acts as in memory cache + resolvedPayload string + +} + +func (s *GcpSecret) GetType() string { + return "gcp" } func (s *GcpSecret) GetName() string { @@ -38,47 +41,19 @@ func (s *GcpSecret) GetOriginContext() *Context { return s.OriginContext } -func (s *GcpSecret) GetPlainValue() (string, error) { - - file := s.OriginContext.GlobalConfig.GetGcpCredentialsFile(s.OriginContext.GcpCredentials) - credentials, errCredentials := initCredentialsFromFile(afero.NewOsFs(), file, "https://www.googleapis.com/auth/cloud-platform") - if errCredentials != nil { - return "", errCredentials - } - - // Create the client. - ctx := context.Background() - client, err := secretmanager.NewClient(ctx, option.WithCredentials(credentials)) - if err != nil { - log.Fatalf("failed to setup client: %v", err) - } - defer client.Close() - - res, err := client.AccessSecretVersion(ctx, &secretmanagerpb.AccessSecretVersionRequest{ - Name: s.ResourceId, - }) +func (s *GcpSecret) GetPlainValue(ctx context.Context) (string, error) { - if err != nil { - return "", err + if s.resolvedPayload != "" { + return s.resolvedPayload, nil } - return string(res.Payload.GetData()), nil -} - -func initCredentialsFromFile(fs afero.Fs, fileName string, scopes ...string) (*google.Credentials, error) { - - ctx := context.Background() + file := s.OriginContext.GlobalConfig.GetGcpCredentialsFile(s.OriginContext.GcpCredentials) - data, err := afero.ReadFile(fs, fileName) - if err != nil { - log.Fatal(err) - } + resolvedSecret, errResolve := gcp.ResolveSecret(ctx, s.ResourceId, file) - creds, err := google.CredentialsFromJSON(ctx, data, scopes...) - if err != nil { - log.Fatal(err) + if errResolve == nil { + s.resolvedPayload = resolvedSecret } - - return creds, err + return resolvedSecret, errResolve } \ No newline at end of file diff --git a/pkg/config/generic/schema_v1.go b/pkg/config/generic/schema_v1.go index bfa64bf..ee2525f 100644 --- a/pkg/config/generic/schema_v1.go +++ b/pkg/config/generic/schema_v1.go @@ -227,7 +227,11 @@ func ParseSchemaV1(jsonInput []byte, configFileUsed string, globalConfig *global for _, context := range contexts { context.SecretResolver = getSecretResolverV1(Parsed.Context[context.Name].DecryptSecret, defaultContext, globalConfig, overwrittenSecrets) context.Encryption = encryption.NewAesEngine(context.SecretResolver) - context.GcpCredentials = Parsed.Context[context.Name].GcpCredentials + if gcpCredentials := Parsed.Context[context.Name].GcpCredentials; gcpCredentials != "" { + context.GcpCredentials = gcpCredentials + } else { + context.GcpCredentials = defaultContext.GcpCredentials + } } if Parsed.RenderFiles != nil { diff --git a/pkg/config/generic/schema_v1_writer.go b/pkg/config/generic/schema_v1_writer.go index 6f6fd85..29facf7 100644 --- a/pkg/config/generic/schema_v1_writer.go +++ b/pkg/config/generic/schema_v1_writer.go @@ -2,6 +2,7 @@ package config_generic import ( "encoding/json" + "errors" "fmt" config_const "github.com/benammann/git-secrets/pkg/config/const" "github.com/spf13/afero" @@ -51,7 +52,35 @@ func (v *V1Writer) SetEncryptedSecret(contextName string, secretName string, sec } func (v *V1Writer) SetGcpSecret(contextName string, secretName string, resourceId string, force bool) error { - return nil + + if v.schema.Context[config_const.DefaultContextName].GcpCredentials == "" { + return errors.New("you need to specify a gcp credentials first") + } + + if v.schema.Context[contextName] == nil { + return fmt.Errorf("the context %s does not exist", contextName) + } + + if v.schema.Context[contextName].Secrets == nil { + v.schema.Context[contextName].Secrets = make(map[string]*SecretEntryTypes) + } + + if contextName != config_const.DefaultContextName && v.schema.Context[config_const.DefaultContextName].Secrets[secretName] == nil { + return fmt.Errorf("you need to define secret entry %s in the default context first", secretName) + } + + if v.schema.Context[contextName].Secrets[secretName] != nil && force == false { + return fmt.Errorf("the secret %s does already exist. Use --force to overwrite", secretName) + } + + v.schema.Context[contextName].Secrets[secretName] = &SecretEntryTypes{ + Gcp: &SecretEntryGcp{ + ResourceId: resourceId, + }, + } + + return v.WriteConfig() + } func (v *V1Writer) SetConfig(contextName string, configName string, configValue string, force bool) error { diff --git a/pkg/config/global/global_config.go b/pkg/config/global/global_config.go index dc31f7e..6c9b002 100644 --- a/pkg/config/global/global_config.go +++ b/pkg/config/global/global_config.go @@ -2,6 +2,7 @@ package global_config import ( "fmt" + "github.com/AlecAivazis/survey/v2" "regexp" "sort" "strings" @@ -28,6 +29,27 @@ func (g *GlobalConfigProvider) GetGcpCredentialsFile(credentialsName string) str return g.storageProvider.GetString(g.gcpCredentialsKey(credentialsName)) } +func (g *GlobalConfigProvider) SelectGcpCredentialsFile() (string, error) { + availableKeys := g.GetGCPCredentialsKeys() + if len(availableKeys) < 1 { + return "", fmt.Errorf("you need to define at least one gcp credential first") + } + + var res string + prompt := &survey.Select{ + Message: "Which credentials to use:", + Options: availableKeys, + } + + errAsk := survey.AskOne(prompt, &res) + if errAsk != nil { + return "", errAsk + } + + return g.GetGcpCredentialsFile(res), nil + +} + func (g *GlobalConfigProvider) SetSecret(secretKey string, secretValue string, force bool) error { errValidate := g.validateSecret(secretKey, secretValue) @@ -75,6 +97,18 @@ func (g *GlobalConfigProvider) GetSecretKeys() []string { return secretKeys } +func (g *GlobalConfigProvider) GetGCPCredentialsKeys() []string { + var credentialsKeys []string + for _, key := range g.storageProvider.AllKeys() { + credentialsPrefix := fmt.Sprintf("%s.", GcpCredentialsPrefix) + if strings.HasPrefix(key, credentialsPrefix) { + credentialsKeys = append(credentialsKeys, strings.Replace(key, credentialsPrefix, "", 1)) + } + } + sort.Strings(credentialsKeys) + return credentialsKeys +} + func (g *GlobalConfigProvider) secretConfigKey(secretKey string) string { return fmt.Sprintf("%s.%s", SecretKeyPrefix, strings.ToLower(secretKey)) } diff --git a/pkg/gcp/gcp.go b/pkg/gcp/gcp.go new file mode 100644 index 0000000..51ea922 --- /dev/null +++ b/pkg/gcp/gcp.go @@ -0,0 +1,134 @@ +package gcp + +import ( + secretmanager "cloud.google.com/go/secretmanager/apiv1" + "context" + "fmt" + "github.com/benammann/git-secrets/pkg/utility" + "github.com/spf13/afero" + "golang.org/x/oauth2/google" + "google.golang.org/api/iterator" + "google.golang.org/api/option" + secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1" + "log" +) + +const scopeGoogleCloudPlatform = "https://www.googleapis.com/auth/cloud-platform" + +type ResourceId string +type CredentialsFile string + +var fs = afero.NewOsFs() +var smClients = make(map[CredentialsFile]*secretmanager.Client) +var resolvedSecrets = make(map[ResourceId]string) + +func getClient(ctx context.Context, gcpCredentialsFile CredentialsFile) (*secretmanager.Client, error) { + + credentials, errCredentials := initCredentialsFromFile(fs, gcpCredentialsFile, scopeGoogleCloudPlatform) + if errCredentials != nil { + return nil, errCredentials + } + + if smClients[gcpCredentialsFile] != nil{ + return smClients[gcpCredentialsFile], nil + } + + newClient, err := secretmanager.NewClient(ctx, option.WithCredentials(credentials)) + if err != nil { + log.Fatalf("failed to setup client: %v", err) + } + + smClients[gcpCredentialsFile] = newClient + + addChannel, doneChannel := utility.GetContextChannels(ctx) + + addChannel<-1 + + go func() { + select { + case <-ctx.Done(): + errClose := newClient.Close() + delete(smClients, gcpCredentialsFile) + doneChannel <-errClose==nil + } + }() + + return newClient, nil + +} + +func ListSecrets(ctx context.Context, gcpCredentialsFile string) ([]*secretmanagerpb.SecretVersion, error) { + + smClient, errClient := getClient(ctx, CredentialsFile(gcpCredentialsFile)) + if errClient != nil { + return nil, fmt.Errorf("could not initialize secret manager client for %s: %s", gcpCredentialsFile, errClient.Error()) + } + + it := smClient.ListSecretVersions(ctx, &secretmanagerpb.ListSecretVersionsRequest{ + Parent: "projects/806001934377/secrets/awesomeSecret", + }) + + var secretVersions []*secretmanagerpb.SecretVersion + + for { + resp, err := it.Next() + if err == iterator.Done { + break + } + if err != nil { + return nil, fmt.Errorf("could not fetch secret version: %s", err.Error()) + } + secretVersions = append(secretVersions, resp) + } + + if len(secretVersions) < 1 { + return nil, fmt.Errorf("could not fetch any secret versions from %s", gcpCredentialsFile) + } + + return secretVersions, nil + +} + +func ResolveSecret(ctx context.Context, resourceId string, gcpCredentialsFile string) (string, error) { + + cacheKey := ResourceId(resourceId) + + if resolvedSecrets[cacheKey] != "" { + return resolvedSecrets[cacheKey], nil + } + + smClient, errClient := getClient(ctx, CredentialsFile(gcpCredentialsFile)) + if errClient != nil { + return "", fmt.Errorf("could not initialize secret manager client for %s: %s", gcpCredentialsFile, errClient.Error()) + } + + res, errResolve := smClient.AccessSecretVersion(ctx, &secretmanagerpb.AccessSecretVersionRequest{ + Name: resourceId, + }) + if errResolve != nil { + return "", fmt.Errorf("could not resolve secret %s: %s", resourceId, errResolve.Error()) + } + + resolvedSecrets[cacheKey] = string(res.Payload.GetData()) + + return resolvedSecrets[cacheKey], nil + +} + +func initCredentialsFromFile(fs afero.Fs, fileName CredentialsFile, scopes ...string) (*google.Credentials, error) { + + ctx := context.Background() + + data, err := afero.ReadFile(fs, string(fileName)) + if err != nil { + log.Fatal(err) + } + + creds, err := google.CredentialsFromJSON(ctx, data, scopes...) + if err != nil { + log.Fatal(err) + } + + return creds, err + +} \ No newline at end of file diff --git a/pkg/render/render.go b/pkg/render/render.go index e50bf41..abeda07 100644 --- a/pkg/render/render.go +++ b/pkg/render/render.go @@ -2,6 +2,7 @@ package render import ( "bytes" + "context" "fmt" config_generic "github.com/benammann/git-secrets/pkg/config/generic" "github.com/spf13/afero" @@ -37,10 +38,10 @@ func (e *RenderingEngine) createTemplate(fileIn string) (*template.Template, err } // CreateRenderingContext creates the context which is used in the templates -func (e *RenderingEngine) CreateRenderingContext(fileToRender *config_generic.FileToRender) (*RenderingContext, error) { +func (e *RenderingEngine) CreateRenderingContext(ctx context.Context, fileToRender *config_generic.FileToRender) (*RenderingContext, error) { // decode the secrets - secretsMap, errSecrets := e.repository.GetSecretsMapDecoded() + secretsMap, errSecrets := e.repository.GetSecretsMapDecoded(ctx) if errSecrets != nil { return nil, fmt.Errorf("could not create context secrets: %s", errSecrets.Error()) } @@ -58,10 +59,10 @@ func (e *RenderingEngine) CreateRenderingContext(fileToRender *config_generic.Fi } // RenderFile renders the file and returns the rendered contents as string -func (e *RenderingEngine) RenderFile(fileToRender *config_generic.FileToRender) (usedContext *RenderingContext, fileContents string, err error) { +func (e *RenderingEngine) RenderFile(ctx context.Context, fileToRender *config_generic.FileToRender) (usedContext *RenderingContext, fileContents string, err error) { var bytesOut bytes.Buffer - usedContext, errExecute := e.ExecuteTemplate(fileToRender, &bytesOut) + usedContext, errExecute := e.ExecuteTemplate(ctx, fileToRender, &bytesOut) if errExecute != nil { return nil, "", fmt.Errorf("could not execute template: %s", errExecute.Error()) } @@ -71,7 +72,7 @@ func (e *RenderingEngine) RenderFile(fileToRender *config_generic.FileToRender) } // WriteFile renders the file and writes it to its destination -func (e *RenderingEngine) WriteFile(fileToRender *config_generic.FileToRender) (usedContext *RenderingContext, err error) { +func (e *RenderingEngine) WriteFile(ctx context.Context, fileToRender *config_generic.FileToRender) (usedContext *RenderingContext, err error) { // open the file fsFileOut, errFsFile := e.fsOut.OpenFile(fileToRender.FileOut, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) @@ -83,7 +84,7 @@ func (e *RenderingEngine) WriteFile(fileToRender *config_generic.FileToRender) ( } // execute the template and link the file stream - usedContext, errExecute := e.ExecuteTemplate(fileToRender, fsFileOut) + usedContext, errExecute := e.ExecuteTemplate(ctx, fileToRender, fsFileOut) if errExecute != nil { return usedContext, fmt.Errorf("could not execute template: %s", errExecute.Error()) } @@ -93,10 +94,10 @@ func (e *RenderingEngine) WriteFile(fileToRender *config_generic.FileToRender) ( } // ExecuteTemplate executes the template and creates the rendering context -func (e *RenderingEngine) ExecuteTemplate(fileToRender *config_generic.FileToRender, writer io.Writer) (usedContext *RenderingContext, err error) { +func (e *RenderingEngine) ExecuteTemplate(ctx context.Context, fileToRender *config_generic.FileToRender, writer io.Writer) (usedContext *RenderingContext, err error) { // create the rendering context - usedContext, err = e.CreateRenderingContext(fileToRender) + usedContext, err = e.CreateRenderingContext(ctx, fileToRender) if err != nil { return nil, fmt.Errorf("could not create rendering context: %s", err.Error()) } diff --git a/pkg/render/render_test.go b/pkg/render/render_test.go index 5aff655..e572fde 100644 --- a/pkg/render/render_test.go +++ b/pkg/render/render_test.go @@ -7,6 +7,7 @@ import ( "fmt" config_generic "github.com/benammann/git-secrets/pkg/config/generic" global_config "github.com/benammann/git-secrets/pkg/config/global" + "github.com/benammann/git-secrets/pkg/utility" "github.com/spf13/afero" "github.com/stretchr/testify/assert" "testing" @@ -72,10 +73,10 @@ func TestRenderingEngine_CreateRenderingContext(t *testing.T) { } dbPassword := repo.GetCurrentSecret("databasePassword") - dbPasswordVal, errDecode := dbPassword.Decode() + dbPasswordVal, errDecode := dbPassword.GetPlainValue(utility.NewChannelContext()) assert.NoError(t, errDecode) - ctx, err := engine.CreateRenderingContext(file) + ctx, err := engine.CreateRenderingContext(utility.NewChannelContext(), file) assert.NoError(t, err) assert.Equal(t, "default", ctx.ContextName) assert.Equal(t, dbPasswordVal, ctx.Secrets["databasePassword"]) @@ -89,7 +90,7 @@ func TestRenderingEngine_ExecuteTemplate(t *testing.T) { } var bytesOut bytes.Buffer - usedContext, errExecute := engine.ExecuteTemplate(fileToRender, &bytesOut) + usedContext, errExecute := engine.ExecuteTemplate(utility.NewChannelContext(), fileToRender, &bytesOut) assert.NoError(t, errExecute) assert.NotNil(t, usedContext) @@ -115,7 +116,7 @@ func TestRenderingEngine_RenderFile(t *testing.T) { fileToRender := &config_generic.FileToRender{ FileIn: "test_fs/templates/render-context.json", } - _, fileContents, err := engine.RenderFile(fileToRender) + _, fileContents, err := engine.RenderFile(utility.NewChannelContext(), fileToRender) assert.NoError(t, err) assert.NotEqual(t, "", fileContents) } @@ -127,7 +128,7 @@ func TestRenderingEngine_WriteFile(t *testing.T) { FileOut: "render-context.json", } engine.fsOut = afero.NewMemMapFs() - _, err := engine.WriteFile(fileToRender) + _, err := engine.WriteFile(utility.NewChannelContext(), fileToRender) assert.NoError(t, err) fileExists, errExists := afero.Exists(engine.fsOut, fileToRender.FileOut) diff --git a/pkg/utility/utility_context.go b/pkg/utility/utility_context.go new file mode 100644 index 0000000..d651e76 --- /dev/null +++ b/pkg/utility/utility_context.go @@ -0,0 +1,22 @@ +package utility + +import "context" + +type AddChannel chan int +type DoneChannel chan bool + +const ( + ContextKeyAddChannel = "AddChannel" + ContextKeyDoneChannel = "DoneChannel" +) + +func NewChannelContext() context.Context { + ctx := context.Background() + ctx = context.WithValue(ctx, ContextKeyAddChannel, make(AddChannel)) + ctx = context.WithValue(ctx, ContextKeyDoneChannel, make(DoneChannel)) + return ctx +} + +func GetContextChannels(ctx context.Context) (AddChannel, DoneChannel) { + return ctx.Value(ContextKeyAddChannel).(AddChannel), ctx.Value(ContextKeyDoneChannel).(DoneChannel) +} \ No newline at end of file diff --git a/schema/def/v1.json b/schema/def/v1.json index eb97808..40a5777 100644 --- a/schema/def/v1.json +++ b/schema/def/v1.json @@ -144,6 +144,14 @@ "required": ["value"] } } + }, + "gcp": { + "type": "object", + "properties": { + "resourceId": { + "type": "string" + } + } } } }, From ab58f5d592ab21f961a78570cf9a4ece3033c787 Mon Sep 17 00:00:00 2001 From: Ben Ammann Date: Mon, 24 Oct 2022 20:56:38 +0200 Subject: [PATCH 4/5] gcp poc --- .env | 0 .env.dist | 1 - .git-secrets.json | 32 +----- .gitignore | 1 + Makefile | 2 +- cmd/auth.go | 57 +++++++++++ cmd/info.go | 4 +- cmd/set.go | 32 +++--- go.mod | 7 +- go.sum | 9 ++ pkg/config/generic/repository.go | 13 --- pkg/config/generic/repository_context.go | 1 - pkg/config/generic/repository_secret_gcp.go | 4 +- pkg/config/generic/schema_v1.go | 6 -- pkg/config/generic/schema_v1_writer.go | 5 - pkg/gcp/auth/gcp_auth.go | 75 ++++++++++++++ pkg/gcp/gcp.go | 105 +------------------- pkg/gcp/gcp_ask_projects.go | 68 +++++++++++++ pkg/gcp/gcp_ask_secret_version.go | 85 ++++++++++++++++ pkg/gcp/gcp_ask_secrets.go | 83 ++++++++++++++++ schema/def/v1.json | 6 -- 21 files changed, 411 insertions(+), 185 deletions(-) delete mode 100644 .env delete mode 100644 .env.dist create mode 100644 cmd/auth.go create mode 100644 pkg/gcp/auth/gcp_auth.go create mode 100644 pkg/gcp/gcp_ask_projects.go create mode 100644 pkg/gcp/gcp_ask_secret_version.go create mode 100644 pkg/gcp/gcp_ask_secrets.go diff --git a/.env b/.env deleted file mode 100644 index e69de29..0000000 diff --git a/.env.dist b/.env.dist deleted file mode 100644 index e450201..0000000 --- a/.env.dist +++ /dev/null @@ -1 +0,0 @@ -MY_ENV={{.Secrets.fromGcp}} diff --git a/.git-secrets.json b/.git-secrets.json index 7adade6..415e4ee 100644 --- a/.git-secrets.json +++ b/.git-secrets.json @@ -6,46 +6,16 @@ "decryptSecret": { "fromName": "gitsecretspublicnew" }, - "gcpCredentials": "private-cli", "secrets": { "crToken": { - "encrypted": { - "value": "sybpBnwiGQ+TmsIL00ordYwVMS44FLcN7gEsQ0uSNQNhH1WFE/qW/7CuMyYrHGo/AL+fJs/WAcayW5qHaq6cAw==" - } - }, - "fromGcp": { - "gcp": { - "resourceId": "projects/806001934377/secrets/awesomeSecret/versions/2" - } - }, - "fromGcp1": { "gcp": { - "resourceId": "projects/806001934377/secrets/awesomeSecret/versions/1" - } - }, - "fromGcp2": { - "gcp": { - "resourceId": "projects/806001934377/secrets/awesomeSecret/versions/2" + "resourceId": "projects/806001934377/secrets/git-secrets-dockerhub-ci-token/versions/1" } } }, "configs": { "crUser": "benammann" } - }, - "prod": { - "secrets": { - "crToken": { - "gcp": { - "resourceId": "projects/806001934377/secrets/awesomeSecret/versions/1" - } - }, - "fromGcp": { - "gcp": { - "resourceId": "projects/806001934377/secrets/awesomeSecret/versions/1" - } - } - } } }, "renderFiles": { diff --git a/.gitignore b/.gitignore index 1fd1f96..d5cf4b9 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ dist/ node_modules .temp .cache +bin \ No newline at end of file diff --git a/Makefile b/Makefile index cb03ae9..b610733 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,2 @@ watch: - CompileDaemon + CompileDaemon --build "go build -o bin/git-secrets ." diff --git a/cmd/auth.go b/cmd/auth.go new file mode 100644 index 0000000..0ca21bf --- /dev/null +++ b/cmd/auth.go @@ -0,0 +1,57 @@ +/* +Copyright © 2022 NAME HERE + +*/ +package cmd + +import ( + "fmt" + gcp_auth "github.com/benammann/git-secrets/pkg/gcp/auth" + "github.com/spf13/cobra" +) + + +var authCmd = &cobra.Command{ + Use: "auth", + Short: "Authentication commands for remote secret managers", + Run: func(cmd *cobra.Command, args []string) { + cmd.Help() + }, +} + +var authGcpCmd = &cobra.Command{ + Use: "gcp", + Short: "Authenticate against GoogleCloud using gcloud-cli", + RunE: func(cmd *cobra.Command, args []string) error { + + force, _ := cmd.Flags().GetBool(FlagForce) + + isAuthenticated, errAuth := gcp_auth.IsAuthenticated() + cobra.CheckErr(errAuth) + + if isAuthenticated && force == false { + fmt.Println("you are already authenticated. Use --force if you still want to continue") + return nil + } + + cobra.CheckErr(gcp_auth.Authenticate()) + return nil + }, +} + +func init() { + rootCmd.AddCommand(authCmd) + + authCmd.AddCommand(authGcpCmd) + authGcpCmd.Flags().Bool(FlagForce, false, "Use --force to ignore existing gcp authentication") + + // Here you will define your flags and configuration settings. + + // Cobra supports Persistent Flags which will work for this command + // and all subcommands, e.g.: + // authCmd.PersistentFlags().String("foo", "", "A help for foo") + + // Cobra supports local flags which will only run when this command + // is called directly, e.g.: + // authCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} diff --git a/cmd/info.go b/cmd/info.go index 5769dab..2bdeefc 100644 --- a/cmd/info.go +++ b/cmd/info.go @@ -61,7 +61,7 @@ git secrets info -d -c prod: Decodes all secrets from the prod context shouldDecode, _ := cmd.Flags().GetBool(InfoCmdFlagDecode) - tableHeader := []string{"Type", "Secret Name", "Origin Context"} + tableHeader := []string{"Secret Name", "Origin Context", "Type"} if shouldDecode { tableHeader = append(tableHeader, "Decoded Value") } @@ -70,7 +70,7 @@ git secrets info -d -c prod: Decodes all secrets from the prod context for _, secret := range projectCfg.GetCurrentSecrets() { - tableRow := []string{secret.GetType(), secret.GetName(), secret.GetOriginContext().Name} + tableRow := []string{secret.GetName(), secret.GetOriginContext().Name, secret.GetType()} if shouldDecode { decodedValue, errDecode := secret.GetPlainValue(cmd.Context()) if errDecode != nil { diff --git a/cmd/set.go b/cmd/set.go index 69360bd..c831476 100644 --- a/cmd/set.go +++ b/cmd/set.go @@ -1,7 +1,6 @@ package cmd import ( - "errors" "fmt" "github.com/AlecAivazis/survey/v2" "github.com/benammann/git-secrets/pkg/gcp" @@ -106,20 +105,27 @@ git secrets set secret gcp --resourceId : Uses the resou resourceId, _ := cmd.Flags().GetString(FlagResourceId) force, _ := cmd.Flags().GetBool(FlagForce) - if projectCfg.GetDefault().GcpCredentials == "" { - return fmt.Errorf("you need to configure gcp credentials first") - } - credentialsName, errCredentials := projectCfg.GetCurrentGCPCredentialsName() - cobra.CheckErr(errCredentials) - credentialsFileName := globalCfg.GetGcpCredentialsFile(credentialsName) - if resourceId == "" { - gcpSecrets, errSecrets := gcp.ListSecrets(cmd.Context(), credentialsFileName) + + projectsList, errProjects := gcp.ListProjects(cmd.Context()) + cobra.CheckErr(errProjects) + project, errAsk := projectsList.AskProject() + cobra.CheckErr(errAsk) + + gcpSecrets, errSecrets := gcp.ListSecrets(cmd.Context(), project) cobra.CheckErr(errSecrets) - for _, secret := range gcpSecrets { - fmt.Println(secret.GetEtag()) - } - cobra.CheckErr(errors.New("selection not supported yet. use --resourceId ")) + + secret, errAsk := gcpSecrets.AskSecret() + cobra.CheckErr(errAsk) + + secretVersions, errVersions := gcp.ListSecretVersions(cmd.Context(), project, secret) + cobra.CheckErr(errVersions) + + version, errAsk := secretVersions.AskSecretVersion() + cobra.CheckErr(errAsk) + + resourceId = version.Name + } writer := projectCfg.GetConfigWriter() diff --git a/go.mod b/go.mod index ae17f0b..eab2645 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/benammann/git-secrets go 1.19 require ( - github.com/spf13/cobra v1.4.0 + github.com/spf13/cobra v1.6.0 github.com/spf13/viper v1.10.1 ) @@ -24,10 +24,11 @@ require ( github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/go-cmp v0.5.8 // indirect + github.com/google/uuid v1.1.2 // indirect github.com/googleapis/enterprise-certificate-proxy v0.1.0 // indirect github.com/googleapis/gax-go/v2 v2.4.0 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kr/pretty v0.2.0 // indirect github.com/magiconair/properties v1.8.5 // indirect @@ -62,7 +63,7 @@ require ( ) require ( - github.com/AlecAivazis/survey/v2 v2.3.4 + github.com/AlecAivazis/survey/v2 v2.3.6 github.com/onsi/gomega v1.19.0 // indirect github.com/spf13/afero v1.9.2 github.com/tcnksm/go-gitconfig v0.1.2 diff --git a/go.sum b/go.sum index a61b40d..a124faa 100644 --- a/go.sum +++ b/go.sum @@ -64,6 +64,8 @@ cloud.google.com/go/storage v1.22.1/go.mod h1:S8N1cAStu7BOeFfE8KAQzmyyLkK8p/vmRq dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/AlecAivazis/survey/v2 v2.3.4 h1:pchTU9rsLUSvWEl2Aq9Pv3k0IE2fkqtGxazskAMd9Ng= github.com/AlecAivazis/survey/v2 v2.3.4/go.mod h1:hrV6Y/kQCLhIZXGcriDCUBtB3wnN7156gMXJ3+b23xM= +github.com/AlecAivazis/survey/v2 v2.3.6 h1:NvTuVHISgTHEHeBFqt6BHOe4Ny/NwGZr7w+F8S9ziyw= +github.com/AlecAivazis/survey/v2 v2.3.6/go.mod h1:4AuI9b7RjAR+G7v9+C4YSlX/YL3K3cWNXgWXOhllqvI= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= @@ -87,6 +89,7 @@ github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWH github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -181,6 +184,7 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8= github.com/googleapis/enterprise-certificate-proxy v0.1.0 h1:zO8WHNx/MYiAKJ3d5spxZXZE6KHmIQGQcAzwUzV7qQw= @@ -206,6 +210,8 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= +github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= @@ -255,6 +261,8 @@ github.com/spf13/cast v1.4.1 h1:s0hze+J0196ZfEMTs80N7UlFt0BDuQ7Q+JDnHiMWKdA= github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q= github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g= +github.com/spf13/cobra v1.6.0 h1:42a0n6jwCot1pUmomAp4T7DeMD+20LFv4Q54pxLf2LI= +github.com/spf13/cobra v1.6.0/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= @@ -478,6 +486,7 @@ golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220422013727-9388b58f7150/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/pkg/config/generic/repository.go b/pkg/config/generic/repository.go index 25ee55a..f1ea710 100644 --- a/pkg/config/generic/repository.go +++ b/pkg/config/generic/repository.go @@ -1,7 +1,6 @@ package config_generic import ( - "fmt" config_const "github.com/benammann/git-secrets/pkg/config/const" "github.com/benammann/git-secrets/pkg/config/writer" ) @@ -58,16 +57,4 @@ func (c *Repository) IsDefault() bool { // GetConfigWriter returns the current config writer func (c *Repository) GetConfigWriter() writer.ConfigWriter { return c.configWriter -} - -func (c *Repository) GetCurrentGCPCredentialsName() (string, error) { - defaultCtx := c.GetDefault() - currentCtx := c.GetCurrent() - if currentCtx.GcpCredentials == "" && defaultCtx.GcpCredentials == "" { - return "", fmt.Errorf("there are no gcp credentials configured") - } - if currentCtx.GcpCredentials != "" { - return currentCtx.GcpCredentials, nil - } - return defaultCtx.GcpCredentials, nil } \ No newline at end of file diff --git a/pkg/config/generic/repository_context.go b/pkg/config/generic/repository_context.go index d6236d4..85d1793 100644 --- a/pkg/config/generic/repository_context.go +++ b/pkg/config/generic/repository_context.go @@ -12,7 +12,6 @@ type Context struct { Name string GlobalConfig *global_config.GlobalConfigProvider SecretResolver encryption.SecretResolver - GcpCredentials string Encryption encryption.Engine Secrets map[string]Secret Configs map[string]string diff --git a/pkg/config/generic/repository_secret_gcp.go b/pkg/config/generic/repository_secret_gcp.go index e1e5d47..dce7621 100644 --- a/pkg/config/generic/repository_secret_gcp.go +++ b/pkg/config/generic/repository_secret_gcp.go @@ -47,9 +47,7 @@ func (s *GcpSecret) GetPlainValue(ctx context.Context) (string, error) { return s.resolvedPayload, nil } - file := s.OriginContext.GlobalConfig.GetGcpCredentialsFile(s.OriginContext.GcpCredentials) - - resolvedSecret, errResolve := gcp.ResolveSecret(ctx, s.ResourceId, file) + resolvedSecret, errResolve := gcp.ResolveSecret(ctx, s.ResourceId) if errResolve == nil { s.resolvedPayload = resolvedSecret diff --git a/pkg/config/generic/schema_v1.go b/pkg/config/generic/schema_v1.go index ee2525f..ecf94c9 100644 --- a/pkg/config/generic/schema_v1.go +++ b/pkg/config/generic/schema_v1.go @@ -45,7 +45,6 @@ type V1DecryptSecret struct { type V1ContextAwareSecrets struct { DecryptSecret *V1DecryptSecret `json:"decryptSecret,omitempty"` - GcpCredentials string `json:"gcpCredentials,omitempty"` Secrets map[string]*SecretEntryTypes `json:"secrets,omitempty"` Configs map[string]string `json:"configs,omitempty"` } @@ -227,11 +226,6 @@ func ParseSchemaV1(jsonInput []byte, configFileUsed string, globalConfig *global for _, context := range contexts { context.SecretResolver = getSecretResolverV1(Parsed.Context[context.Name].DecryptSecret, defaultContext, globalConfig, overwrittenSecrets) context.Encryption = encryption.NewAesEngine(context.SecretResolver) - if gcpCredentials := Parsed.Context[context.Name].GcpCredentials; gcpCredentials != "" { - context.GcpCredentials = gcpCredentials - } else { - context.GcpCredentials = defaultContext.GcpCredentials - } } if Parsed.RenderFiles != nil { diff --git a/pkg/config/generic/schema_v1_writer.go b/pkg/config/generic/schema_v1_writer.go index 29facf7..4de63c1 100644 --- a/pkg/config/generic/schema_v1_writer.go +++ b/pkg/config/generic/schema_v1_writer.go @@ -2,7 +2,6 @@ package config_generic import ( "encoding/json" - "errors" "fmt" config_const "github.com/benammann/git-secrets/pkg/config/const" "github.com/spf13/afero" @@ -53,10 +52,6 @@ func (v *V1Writer) SetEncryptedSecret(contextName string, secretName string, sec func (v *V1Writer) SetGcpSecret(contextName string, secretName string, resourceId string, force bool) error { - if v.schema.Context[config_const.DefaultContextName].GcpCredentials == "" { - return errors.New("you need to specify a gcp credentials first") - } - if v.schema.Context[contextName] == nil { return fmt.Errorf("the context %s does not exist", contextName) } diff --git a/pkg/gcp/auth/gcp_auth.go b/pkg/gcp/auth/gcp_auth.go new file mode 100644 index 0000000..31586f7 --- /dev/null +++ b/pkg/gcp/auth/gcp_auth.go @@ -0,0 +1,75 @@ +package gcp_auth + +import ( + "bytes" + "fmt" + "os" + "os/exec" + "path/filepath" + "runtime" + "strings" +) + +var defaultCredentialsPath string + +// Authenticate checks if user has credentials to use Google SDK and if not authenticates through a gcloud shell out +func Authenticate() error { + if !hasServiceAccount() { + err := createDefaultCredentials() + if err != nil { + return err + } + } + return nil +} + +func IsAuthenticated() (bool, error) { + credentials, errCred := hasDefaultCredentials() + if errCred != nil { + return false, fmt.Errorf("hasDefaultCredentials check failed: %w", errCred) + } + return credentials, nil +} + +// hasDefaultCredentials checks the default credentials used by google SDK, which by default are stored in ~/.config/gcloud/application_default_credentials.json +func hasDefaultCredentials() (bool, error) { + homeDir, err := os.UserHomeDir() + if err != nil { + return false, fmt.Errorf("retrieving homedir failed: %w", err) + } + defaultCredentialsPath = filepath.Join(homeDir, ".config", "gcloud", "application_default_credentials.json") + if _, err := os.Stat(defaultCredentialsPath); os.IsNotExist(err) { + return false, nil + } + return true, nil +} + +// hasServiceAccount checks if service account credentials are used (use case for ci usage) +func hasServiceAccount() bool { + if _, exists := os.LookupEnv("GOOGLE_APPLICATION_CREDENTIALS"); exists { + return true + } + return false +} + +// createDefaultCredentials redirects to browser to retrieve the default application credentials +func createDefaultCredentials() error { + command := "gcloud auth application-default login" + cmd := exec.Command("bash", "-c", command) + + // Windows usually does not ship bash, and execution in a subshell is not needed + if runtime.GOOS == "windows" { + commandParts := strings.Split(command, " ") + cmd = exec.Command(commandParts[0], commandParts[1:]...) + } + + var stderr bytes.Buffer + cmd.Stderr = &stderr + err := cmd.Run() + stdErr := stderr.String() + if err != nil { + return fmt.Errorf("'gcloud auth application-default login' failed: '%s'. "+ + "Please make sure gcloud is installed and if you are not having a bash shell, excecute 'gcloud auth application-default login' in another shell", stdErr) + } + return nil +} diff --git a/pkg/gcp/gcp.go b/pkg/gcp/gcp.go index 51ea922..2c2c758 100644 --- a/pkg/gcp/gcp.go +++ b/pkg/gcp/gcp.go @@ -4,92 +4,15 @@ import ( secretmanager "cloud.google.com/go/secretmanager/apiv1" "context" "fmt" - "github.com/benammann/git-secrets/pkg/utility" - "github.com/spf13/afero" - "golang.org/x/oauth2/google" - "google.golang.org/api/iterator" - "google.golang.org/api/option" secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1" "log" ) -const scopeGoogleCloudPlatform = "https://www.googleapis.com/auth/cloud-platform" - type ResourceId string -type CredentialsFile string -var fs = afero.NewOsFs() -var smClients = make(map[CredentialsFile]*secretmanager.Client) var resolvedSecrets = make(map[ResourceId]string) -func getClient(ctx context.Context, gcpCredentialsFile CredentialsFile) (*secretmanager.Client, error) { - - credentials, errCredentials := initCredentialsFromFile(fs, gcpCredentialsFile, scopeGoogleCloudPlatform) - if errCredentials != nil { - return nil, errCredentials - } - - if smClients[gcpCredentialsFile] != nil{ - return smClients[gcpCredentialsFile], nil - } - - newClient, err := secretmanager.NewClient(ctx, option.WithCredentials(credentials)) - if err != nil { - log.Fatalf("failed to setup client: %v", err) - } - - smClients[gcpCredentialsFile] = newClient - - addChannel, doneChannel := utility.GetContextChannels(ctx) - - addChannel<-1 - - go func() { - select { - case <-ctx.Done(): - errClose := newClient.Close() - delete(smClients, gcpCredentialsFile) - doneChannel <-errClose==nil - } - }() - - return newClient, nil - -} - -func ListSecrets(ctx context.Context, gcpCredentialsFile string) ([]*secretmanagerpb.SecretVersion, error) { - - smClient, errClient := getClient(ctx, CredentialsFile(gcpCredentialsFile)) - if errClient != nil { - return nil, fmt.Errorf("could not initialize secret manager client for %s: %s", gcpCredentialsFile, errClient.Error()) - } - - it := smClient.ListSecretVersions(ctx, &secretmanagerpb.ListSecretVersionsRequest{ - Parent: "projects/806001934377/secrets/awesomeSecret", - }) - - var secretVersions []*secretmanagerpb.SecretVersion - - for { - resp, err := it.Next() - if err == iterator.Done { - break - } - if err != nil { - return nil, fmt.Errorf("could not fetch secret version: %s", err.Error()) - } - secretVersions = append(secretVersions, resp) - } - - if len(secretVersions) < 1 { - return nil, fmt.Errorf("could not fetch any secret versions from %s", gcpCredentialsFile) - } - - return secretVersions, nil - -} - -func ResolveSecret(ctx context.Context, resourceId string, gcpCredentialsFile string) (string, error) { +func ResolveSecret(ctx context.Context, resourceId string) (string, error) { cacheKey := ResourceId(resourceId) @@ -97,12 +20,12 @@ func ResolveSecret(ctx context.Context, resourceId string, gcpCredentialsFile st return resolvedSecrets[cacheKey], nil } - smClient, errClient := getClient(ctx, CredentialsFile(gcpCredentialsFile)) - if errClient != nil { - return "", fmt.Errorf("could not initialize secret manager client for %s: %s", gcpCredentialsFile, errClient.Error()) + client, err := secretmanager.NewClient(ctx) + if err != nil { + log.Fatalf("failed to setup client: %v", err) } - res, errResolve := smClient.AccessSecretVersion(ctx, &secretmanagerpb.AccessSecretVersionRequest{ + res, errResolve := client.AccessSecretVersion(ctx, &secretmanagerpb.AccessSecretVersionRequest{ Name: resourceId, }) if errResolve != nil { @@ -113,22 +36,4 @@ func ResolveSecret(ctx context.Context, resourceId string, gcpCredentialsFile st return resolvedSecrets[cacheKey], nil -} - -func initCredentialsFromFile(fs afero.Fs, fileName CredentialsFile, scopes ...string) (*google.Credentials, error) { - - ctx := context.Background() - - data, err := afero.ReadFile(fs, string(fileName)) - if err != nil { - log.Fatal(err) - } - - creds, err := google.CredentialsFromJSON(ctx, data, scopes...) - if err != nil { - log.Fatal(err) - } - - return creds, err - } \ No newline at end of file diff --git a/pkg/gcp/gcp_ask_projects.go b/pkg/gcp/gcp_ask_projects.go new file mode 100644 index 0000000..c656679 --- /dev/null +++ b/pkg/gcp/gcp_ask_projects.go @@ -0,0 +1,68 @@ +package gcp + +import ( + "context" + "fmt" + "github.com/AlecAivazis/survey/v2" + "google.golang.org/api/cloudresourcemanager/v1" +) + +func ListProjects(ctx context.Context) (*ProjectsList, error) { + crm, errCrm := cloudresourcemanager.NewService(ctx) + if errCrm != nil { + return nil, fmt.Errorf("could not init cloudresourcemanager: %s", errCrm.Error()) + } + projects, errListProjects := crm.Projects.List().Do() + if errListProjects != nil { + return nil, fmt.Errorf("could not list gcp projects via cloudresourcemanager: %s", errCrm.Error()) + } + + return NewProjectsList(projects.Projects), nil +} + +type ProjectsList struct { + projects []*cloudresourcemanager.Project +} + +func NewProjectsList(projects []*cloudresourcemanager.Project) *ProjectsList { + return &ProjectsList{ + projects: projects, + } +} + +func (l *ProjectsList) GetProjects() []*cloudresourcemanager.Project { + return l.projects +} + +func (l *ProjectsList) GetProjectById(id string) *cloudresourcemanager.Project { + for _, project := range l.projects { + if project.ProjectId == id { + return project + } + } + return nil +} + +func (l *ProjectsList) ProjectIds() (ids []string) { + for _, project := range l.projects { + ids = append(ids, project.ProjectId) + } + return ids +} + +func (l *ProjectsList) AskProject() (*cloudresourcemanager.Project, error) { + projectId := "" + prompt := &survey.Select{ + Message: "GCP Project:", + Options: l.ProjectIds(), + Description: func(value string, index int) string { + project := l.GetProjectById(value) + if project != nil { + return project.Name + } + return "" + }, + } + errAsk := survey.AskOne(prompt, &projectId) + return l.GetProjectById(projectId), errAsk +} \ No newline at end of file diff --git a/pkg/gcp/gcp_ask_secret_version.go b/pkg/gcp/gcp_ask_secret_version.go new file mode 100644 index 0000000..61359d8 --- /dev/null +++ b/pkg/gcp/gcp_ask_secret_version.go @@ -0,0 +1,85 @@ +package gcp + +import ( + secretmanager "cloud.google.com/go/secretmanager/apiv1" + "context" + "fmt" + "github.com/AlecAivazis/survey/v2" + "google.golang.org/api/cloudresourcemanager/v1" + "google.golang.org/api/iterator" + secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1" + "log" +) + +type SecretsVersionList struct { + parentProject *cloudresourcemanager.Project + parentSecret *secretmanagerpb.Secret + versions []*secretmanagerpb.SecretVersion +} + + +func ListSecretVersions(ctx context.Context, parentProject *cloudresourcemanager.Project, parentSecret *secretmanagerpb.Secret) (*SecretsVersionList, error) { + + client, err := secretmanager.NewClient(ctx) + if err != nil { + log.Fatalf("failed to setup client: %v", err) + } + + projectsList := client.ListSecretVersions(ctx, &secretmanagerpb.ListSecretVersionsRequest{ + Parent: parentSecret.Name, + }) + + var versions []*secretmanagerpb.SecretVersion + + for { + resp, err := projectsList.Next() + if err == iterator.Done { + break + } + if err != nil { + return nil, fmt.Errorf("could not fetch secret versions: %s", err.Error()) + } + versions = append(versions, resp) + } + + if len(versions) < 1 { + return nil, fmt.Errorf("there are no versions configured in %s", parentProject.Name) + } + + return NewSecretVersionList(parentProject, parentSecret, versions), nil + +} + +func NewSecretVersionList(parentProject *cloudresourcemanager.Project, parentSecret *secretmanagerpb.Secret, versions []*secretmanagerpb.SecretVersion) *SecretsVersionList { + return &SecretsVersionList{ + parentProject: parentProject, + parentSecret: parentSecret, + versions: versions, + } +} + +func (l *SecretsVersionList) GetVersionByName(name string) *secretmanagerpb.SecretVersion { + for _, version := range l.versions { + if version.Name == name { + return version + } + } + return nil +} + +func (l *SecretsVersionList) VersionNames() (names []string) { + for _, version := range l.versions { + names = append(names, version.Name) + } + return names +} + +func (l *SecretsVersionList) AskSecretVersion() (*secretmanagerpb.SecretVersion, error) { + secretName := "" + prompt := &survey.Select{ + Message: "Secret Version:", + Options: l.VersionNames(), + } + errAsk := survey.AskOne(prompt, &secretName) + return l.GetVersionByName(secretName), errAsk +} \ No newline at end of file diff --git a/pkg/gcp/gcp_ask_secrets.go b/pkg/gcp/gcp_ask_secrets.go new file mode 100644 index 0000000..f350066 --- /dev/null +++ b/pkg/gcp/gcp_ask_secrets.go @@ -0,0 +1,83 @@ +package gcp + +import ( + secretmanager "cloud.google.com/go/secretmanager/apiv1" + "context" + "fmt" + "github.com/AlecAivazis/survey/v2" + "google.golang.org/api/cloudresourcemanager/v1" + "google.golang.org/api/iterator" + secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1" + "log" +) + +type SecretsList struct { + parentProject *cloudresourcemanager.Project + secrets []*secretmanagerpb.Secret +} + + +func ListSecrets(ctx context.Context, parentProject *cloudresourcemanager.Project) (*SecretsList, error) { + + client, err := secretmanager.NewClient(ctx) + if err != nil { + log.Fatalf("failed to setup client: %v", err) + } + + projectsList := client.ListSecrets(ctx, &secretmanagerpb.ListSecretsRequest{ + Parent: fmt.Sprintf("projects/%d", parentProject.ProjectNumber), + }) + + var secrets []*secretmanagerpb.Secret + + for { + resp, err := projectsList.Next() + if err == iterator.Done { + break + } + if err != nil { + return nil, fmt.Errorf("could not fetch secret version: %s", err.Error()) + } + secrets = append(secrets, resp) + } + + if len(secrets) < 1 { + return nil, fmt.Errorf("there are no secrets configured in %s", parentProject.Name) + } + + return NewSecretsList(parentProject, secrets), nil + +} + +func NewSecretsList(parentProject *cloudresourcemanager.Project, secrets []*secretmanagerpb.Secret) *SecretsList { + return &SecretsList{ + parentProject: parentProject, + secrets: secrets, + } +} + +func (l *SecretsList) GetSecretByName(name string) *secretmanagerpb.Secret { + for _, secret := range l.secrets { + if secret.Name == name { + return secret + } + } + return nil +} + +func (l *SecretsList) SecretNames() (names []string) { + for _, secret := range l.secrets { + names = append(names, secret.Name) + } + return names +} + +func (l *SecretsList) AskSecret() (*secretmanagerpb.Secret, error) { + secretName := "" + prompt := &survey.Select{ + Message: "Secret Name:", + Options: l.SecretNames(), + } + errAsk := survey.AskOne(prompt, &secretName) + return l.GetSecretByName(secretName), errAsk +} \ No newline at end of file diff --git a/schema/def/v1.json b/schema/def/v1.json index 40a5777..b73706d 100644 --- a/schema/def/v1.json +++ b/schema/def/v1.json @@ -19,9 +19,6 @@ "description": "The default context, you can specify the context by using -c ", "type": "object", "properties": { - "gcpCredentials": { - "type": "string" - }, "decryptSecret": { "type": "object", "description": "How to decode the secrets, available: fromName or fromEnv\nYou can only use one\nYou can also overwrite the decodeSecret method in another context\nSo you can use another secret encoding for your production secrets to protect them from the developers for example", @@ -101,9 +98,6 @@ "description": "This is a custom context, you can specify the context by using -c ", "type": "object", "properties": { - "gcpCredentials": { - "type": "string" - }, "decryptSecret": { "type": "object", "description": "How to decode the secrets, available: fromName or fromEnv\nYou can only use one\nYou can also overwrite the decodeSecret method in another context\nSo you can use another secret encoding for your production secrets to protect them from the developers for example", From fae12f53031ac0c7b34c8d5893f3af223f3b9164 Mon Sep 17 00:00:00 2001 From: Ben Ammann Date: Fri, 23 Dec 2022 16:12:18 +0100 Subject: [PATCH 5/5] build artifact on push --- .github/workflows/goreleaser-dev.yml | 31 ++++++++++++++++++++++++++++ Makefile | 3 +++ 2 files changed, 34 insertions(+) create mode 100644 .github/workflows/goreleaser-dev.yml diff --git a/.github/workflows/goreleaser-dev.yml b/.github/workflows/goreleaser-dev.yml new file mode 100644 index 0000000..1afe4b5 --- /dev/null +++ b/.github/workflows/goreleaser-dev.yml @@ -0,0 +1,31 @@ +name: Release brew package + +on: + push: + +permissions: + contents: write + +jobs: + goreleaser: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Fetch all tags + run: git fetch --force --tags + - name: Set up Go + uses: actions/setup-go@v2 + with: + go-version: 1.19 + - name: Run GoReleaser + uses: goreleaser/goreleaser-action@v4 + with: + distribution: goreleaser + version: latest + args: release --rm-dist + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + HOMEBREW_TAP_GITHUB_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }} \ No newline at end of file diff --git a/Makefile b/Makefile index b610733..8554054 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,5 @@ watch: CompileDaemon --build "go build -o bin/git-secrets ." + +tests: + go test ./... \ No newline at end of file