diff --git a/.git-secrets.json b/.git-secrets.json index 53d75d7..415e4ee 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": { @@ -7,11 +7,25 @@ "fromName": "gitsecretspublicnew" }, "secrets": { - "crToken": "sybpBnwiGQ+TmsIL00ordYwVMS44FLcN7gEsQ0uSNQNhH1WFE/qW/7CuMyYrHGo/AL+fJs/WAcayW5qHaq6cAw==" + "crToken": { + "gcp": { + "resourceId": "projects/806001934377/secrets/git-secrets-dockerhub-ci-token/versions/1" + } + } }, "configs": { "crUser": "benammann" } } + }, + "renderFiles": { + "env": { + "files": [ + { + "fileIn": ".env.dist", + "fileOut": ".env" + } + ] + } } } \ No newline at end of file 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/.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..8554054 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,5 @@ watch: - CompileDaemon + CompileDaemon --build "go build -o bin/git-secrets ." + +tests: + go test ./... \ No newline at end of file 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/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..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.Decode() + 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 efe6ade..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{"Secret Name", "Origin Context"} + tableHeader := []string{"Secret Name", "Origin Context", "Type"} if shouldDecode { tableHeader = append(tableHeader, "Decoded Value") } @@ -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, secret.GetType()} if shouldDecode { - decodedValue, errDecode := secret.Decode() + decodedValue, errDecode := secret.GetPlainValue(cmd.Context()) 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/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 2579f8f..d9b0be5 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(cmd.Context()) 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..c831476 100644 --- a/cmd/set.go +++ b/cmd/set.go @@ -3,6 +3,7 @@ package cmd import ( "fmt" "github.com/AlecAivazis/survey/v2" + "github.com/benammann/git-secrets/pkg/gcp" "github.com/spf13/cobra" ) @@ -38,13 +39,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) { @@ -67,7 +76,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) @@ -77,12 +87,72 @@ 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 resourceId == "" { + + 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) + + 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() + + 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/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..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 ) @@ -15,10 +15,20 @@ 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/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 @@ -35,9 +45,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 @@ -45,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 ba21546..a124faa 100644 --- a/go.sum +++ b/go.sum @@ -17,32 +17,64 @@ 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= +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= 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,7 +82,14 @@ 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/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= @@ -61,11 +100,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 +117,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 +126,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 +142,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 +157,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 +178,28 @@ 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 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= +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= @@ -133,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= @@ -172,14 +251,18 @@ 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= 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= @@ -211,12 +294,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 +334,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 +345,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 +374,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 +402,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 +424,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 +459,42 @@ 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-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= +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 +505,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 +559,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 +590,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 +643,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 +656,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 +717,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 +749,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 +764,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..f1ea710 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 @@ -57,4 +57,4 @@ func (c *Repository) IsDefault() bool { // GetConfigWriter returns the current config writer func (c *Repository) GetConfigWriter() writer.ConfigWriter { return c.configWriter -} +} \ No newline at end of file diff --git a/pkg/config/generic/repository_context.go b/pkg/config/generic/repository_context.go index 72ad720..85d1793 100644 --- a/pkg/config/generic/repository_context.go +++ b/pkg/config/generic/repository_context.go @@ -4,15 +4,17 @@ 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 + 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..6221538 100644 --- a/pkg/config/generic/repository_secret.go +++ b/pkg/config/generic/repository_secret.go @@ -1,30 +1,28 @@ package config_generic import ( + "context" "fmt" config_const "github.com/benammann/git-secrets/pkg/config/const" "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 { + GetType() string + GetName() string + GetOriginContext() *Context + GetPlainValue(ctx context.Context) (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 +30,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 +38,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 +48,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 +66,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 +82,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,32 +106,28 @@ 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) { +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.Decode() + decodedSecret, errDecode := secret.GetPlainValue(ctx) 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..0d178d9 --- /dev/null +++ b/pkg/config/generic/repository_secret_encrypted.go @@ -0,0 +1,40 @@ +package config_generic + +import "context" + +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) GetType() string { + return "encrypted" +} + +func (s *EncryptedSecret) GetName() string { + return s.Name +} + +func (s *EncryptedSecret) GetOriginContext() *Context { + return s.OriginContext +} + +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 new file mode 100644 index 0000000..dce7621 --- /dev/null +++ b/pkg/config/generic/repository_secret_gcp.go @@ -0,0 +1,57 @@ +package config_generic + +import ( + "context" + "github.com/benammann/git-secrets/pkg/gcp" +) + +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 + + // 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 { + return s.Name +} + +func (s *GcpSecret) GetOriginContext() *Context { + return s.OriginContext +} + +func (s *GcpSecret) GetPlainValue(ctx context.Context) (string, error) { + + if s.resolvedPayload != "" { + return s.resolvedPayload, nil + } + + resolvedSecret, errResolve := gcp.ResolveSecret(ctx, s.ResourceId) + + if errResolve == nil { + s.resolvedPayload = resolvedSecret + } + 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 d899566..ecf94c9 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,39 @@ type V1DecryptSecret struct { type V1ContextAwareSecrets struct { DecryptSecret *V1DecryptSecret `json:"decryptSecret,omitempty"` - Secrets map[string]string `json:"secrets,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 +135,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 +191,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 @@ -184,18 +246,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..4de63c1 100644 --- a/pkg/config/generic/schema_v1_writer.go +++ b/pkg/config/generic/schema_v1_writer.go @@ -22,25 +22,57 @@ 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 { + + 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() @@ -77,7 +109,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 +155,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..6c9b002 100644 --- a/pkg/config/global/global_config.go +++ b/pkg/config/global/global_config.go @@ -2,12 +2,14 @@ package global_config import ( "fmt" + "github.com/AlecAivazis/survey/v2" "regexp" "sort" "strings" ) const SecretKeyPrefix = "secrets" +const GcpCredentialsPrefix = "gcp.credentials" type GlobalConfigProvider struct { storageProvider StorageProvider @@ -23,6 +25,31 @@ 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) 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) @@ -42,6 +69,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() { @@ -54,10 +97,26 @@ 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)) } +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/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 new file mode 100644 index 0000000..2c2c758 --- /dev/null +++ b/pkg/gcp/gcp.go @@ -0,0 +1,39 @@ +package gcp + +import ( + secretmanager "cloud.google.com/go/secretmanager/apiv1" + "context" + "fmt" + secretmanagerpb "google.golang.org/genproto/googleapis/cloud/secretmanager/v1" + "log" +) + +type ResourceId string + +var resolvedSecrets = make(map[ResourceId]string) + +func ResolveSecret(ctx context.Context, resourceId string) (string, error) { + + cacheKey := ResourceId(resourceId) + + if resolvedSecrets[cacheKey] != "" { + return resolvedSecrets[cacheKey], nil + } + + client, err := secretmanager.NewClient(ctx) + if err != nil { + log.Fatalf("failed to setup client: %v", err) + } + + res, errResolve := client.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 + +} \ 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/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 1f90f54..b73706d 100644 --- a/schema/def/v1.json +++ b/schema/def/v1.json @@ -47,8 +47,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" + } + ] } } }, @@ -98,11 +123,36 @@ }, "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"] + } + } + }, + "gcp": { + "type": "object", + "properties": { + "resourceId": { + "type": "string" + } + } + } + } + }, + { + "type": "string" + } + ] } } },