Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added secrets input prompt for secrets put-secret command #413

Merged
merged 2 commits into from
May 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .codegen/service.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ var Cmd = &cobra.Command{
}

{{range .Methods}}

{{- $excludes := list "put-secret" -}}
{{if in $excludes .KebabName }}
{{continue}}
{{end}}
// start {{.KebabName}} command

{{if .Request}}var {{.CamelName}}Req {{.Service.Package.Name}}.{{.Request.PascalName}}
Expand Down
80 changes: 79 additions & 1 deletion cmd/workspace/secrets/overrides.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,88 @@
package secrets

import "github.com/databricks/cli/libs/cmdio"
import (
"github.com/databricks/cli/cmd/root"
"github.com/databricks/cli/libs/cmdio"
"github.com/databricks/cli/libs/flags"
"github.com/databricks/databricks-sdk-go/service/workspace"
"github.com/spf13/cobra"
)

func init() {
listScopesCmd.Annotations["template"] = cmdio.Heredoc(`
{{white "Scope"}} {{white "Backend Type"}}
{{range .}}{{.Name|green}} {{.BackendType}}
{{end}}`)

Cmd.AddCommand(putSecretCmd)
// TODO: short flags
putSecretCmd.Flags().Var(&putSecretJson, "json", `either inline JSON string or @path/to/file.json with request body`)

putSecretCmd.Flags().StringVar(&putSecretReq.BytesValue, "bytes-value", putSecretReq.BytesValue, `If specified, value will be stored as bytes.`)
putSecretCmd.Flags().StringVar(&putSecretReq.StringValue, "string-value", putSecretReq.StringValue, `If specified, note that the value will be stored in UTF-8 (MB4) form.`)
}

var putSecretReq workspace.PutSecret
var putSecretJson flags.JsonFlag

var putSecretCmd = &cobra.Command{
Use: "put-secret SCOPE KEY",
Short: `Add a secret.`,
Long: `Add a secret.

Inserts a secret under the provided scope with the given name. If a secret
already exists with the same name, this command overwrites the existing
secret's value. The server encrypts the secret using the secret scope's
encryption settings before storing it.

You must have WRITE or MANAGE permission on the secret scope. The secret
key must consist of alphanumeric characters, dashes, underscores, and periods,
and cannot exceed 128 characters. The maximum allowed secret value size is 128
KB. The maximum number of secrets in a given scope is 1000.

The input fields "string_value" or "bytes_value" specify the type of the
secret, which will determine the value returned when the secret value is
requested. Exactly one must be specified.

Throws RESOURCE_DOES_NOT_EXIST if no such secret scope exists. Throws
RESOURCE_LIMIT_EXCEEDED if maximum number of secrets in scope is exceeded.
Throws INVALID_PARAMETER_VALUE if the key name or value length is invalid.
Throws PERMISSION_DENIED if the user does not have permission to make this
API call.`,

Annotations: map[string]string{},
Args: func(cmd *cobra.Command, args []string) error {
check := cobra.ExactArgs(2)
if cmd.Flags().Changed("json") {
check = cobra.ExactArgs(0)
}
return check(cmd, args)
},
PreRunE: root.MustWorkspaceClient,
RunE: func(cmd *cobra.Command, args []string) (err error) {
ctx := cmd.Context()
w := root.WorkspaceClient(ctx)
if cmd.Flags().Changed("json") {
err = putSecretJson.Unmarshal(&putSecretReq)
if err != nil {
return err
}
} else {
putSecretReq.Scope = args[0]
putSecretReq.Key = args[1]

value, err := cmdio.Secret(ctx)
if err != nil {
return err
}

putSecretReq.StringValue = value
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any thought around string vs bytes here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per doc, difference is

If string_value, if specified, the value will be stored in UTF-8 (MB4) form.
If bytes_value, if specified, value will be stored as bytes.

Since we prompt customers to enter the key in terminal it's just natural to keep it as strings to avoid back and forth conversions

}

err = w.Secrets.PutSecret(ctx, putSecretReq)
if err != nil {
return err
}
return nil
},
}
70 changes: 0 additions & 70 deletions cmd/workspace/secrets/secrets.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions libs/cmdio/io.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,20 @@ func Select[V any](ctx context.Context, names map[string]V, label string) (id st
return c.Select(stringNames, label)
}

func (c *cmdIO) Secret() (value string, err error) {
prompt := (promptui.Prompt{
Label: "Enter your secrets value",
Mask: '*',
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this read from a pipe, e.g. echo foo | databricks secrets put-secret?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pietern , yes, it does read from pipe correctly


return prompt.Run()
}

func Secret(ctx context.Context) (value string, err error) {
c := fromContext(ctx)
return c.Secret()
}

func (c *cmdIO) Spinner(ctx context.Context) chan string {
var sp *spinner.Spinner
if c.interactive {
Expand Down