2023-07-25 18:19:07 +00:00
package secrets
import (
"encoding/base64"
"fmt"
"io"
"os"
"github.com/databricks/cli/cmd/root"
"github.com/databricks/cli/libs/cmdio"
2024-10-11 14:39:53 +00:00
"github.com/databricks/cli/libs/diag"
2023-07-25 18:19:07 +00:00
"github.com/databricks/cli/libs/flags"
"github.com/databricks/databricks-sdk-go/service/workspace"
"github.com/spf13/cobra"
)
func newPutSecret ( ) * cobra . Command {
cmd := & cobra . Command { }
var putSecretReq workspace . PutSecret
var putSecretJson flags . JsonFlag
cmd . Flags ( ) . Var ( & putSecretJson , "json" , ` either inline JSON string or @path/to/file.json with request body ` )
cmd . Flags ( ) . StringVar ( & putSecretReq . BytesValue , "bytes-value" , putSecretReq . BytesValue , ` If specified, value will be stored as bytes. ` )
cmd . Flags ( ) . StringVar ( & putSecretReq . StringValue , "string-value" , putSecretReq . StringValue , ` If specified, note that the value will be stored in UTF-8 (MB4) form. ` )
cmd . Use = "put-secret SCOPE KEY"
cmd . Short = ` Add a secret. `
cmd . 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 arguments "string-value" or "bytes-value" specify the type of the secret ,
which will determine the value returned when the secret value is requested .
You can specify the secret value in one of three ways :
* Specify the value as a string using the -- string - value flag .
* Input the secret when prompted interactively ( single - line secrets ) .
* Pass the secret via standard input ( multi - line secrets ) .
`
cmd . Annotations = make ( map [ string ] string )
cmd . Args = func ( cmd * cobra . Command , args [ ] string ) error {
2024-03-12 14:12:34 +00:00
check := root . ExactArgs ( 2 )
2023-07-25 18:19:07 +00:00
if cmd . Flags ( ) . Changed ( "json" ) {
2024-03-12 14:12:34 +00:00
check = root . ExactArgs ( 0 )
2023-07-25 18:19:07 +00:00
}
return check ( cmd , args )
}
cmd . PreRunE = root . MustWorkspaceClient
cmd . RunE = func ( cmd * cobra . Command , args [ ] string ) ( err error ) {
ctx := cmd . Context ( )
2024-10-11 14:39:53 +00:00
var diags diag . Diagnostics
2023-07-25 18:19:07 +00:00
w := root . WorkspaceClient ( ctx )
bytesValueChanged := cmd . Flags ( ) . Changed ( "bytes-value" )
stringValueChanged := cmd . Flags ( ) . Changed ( "string-value" )
if bytesValueChanged && stringValueChanged {
return fmt . Errorf ( "cannot specify both --bytes-value and --string-value" )
}
if cmd . Flags ( ) . Changed ( "json" ) {
2024-10-11 14:39:53 +00:00
diags = putSecretJson . Unmarshal ( & putSecretReq )
if diags . HasError ( ) {
return diags . Error ( )
}
if len ( diags ) > 0 {
err := cmdio . RenderDiagnosticsToErrorOut ( ctx , diags )
if err != nil {
return err
}
2023-07-25 18:19:07 +00:00
}
} else {
putSecretReq . Scope = args [ 0 ]
putSecretReq . Key = args [ 1 ]
switch {
case bytesValueChanged :
// Bytes value set; encode as base64.
putSecretReq . BytesValue = base64 . StdEncoding . EncodeToString ( [ ] byte ( putSecretReq . BytesValue ) )
case stringValueChanged :
// String value set; nothing to do.
default :
// Neither is specified; read secret value from stdin.
bytes , err := promptSecret ( cmd )
if err != nil {
return err
}
putSecretReq . BytesValue = base64 . StdEncoding . EncodeToString ( bytes )
}
}
err = w . Secrets . PutSecret ( ctx , putSecretReq )
if err != nil {
return err
}
return nil
}
// Disable completions since they are not applicable.
// Potential future follow up to auto complete secret scopes for the first argument.
cmd . ValidArgsFunction = cobra . NoFileCompletions
return cmd
}
func promptSecret ( cmd * cobra . Command ) ( [ ] byte , error ) {
// If stdin is a TTY, prompt for the secret.
if ! cmdio . IsInTTY ( cmd . Context ( ) ) {
return io . ReadAll ( os . Stdin )
}
value , err := cmdio . Secret ( cmd . Context ( ) , "Please enter your secret value" )
if err != nil {
return nil , err
}
return [ ] byte ( value ) , nil
}