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

Add support for contexts requiring confirmation #1087

Merged
merged 3 commits into from
Dec 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
24 changes: 13 additions & 11 deletions cmd/cloud/clicontext/clicontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ import (
type ContextKeyServerURL struct{}

type CLIContext struct {
AuthData *auth.AuthorizationResponse `json:"auth_data"`
ClientID string `json:"client_id"`
OrgURL string `json:"org_url"`
ServerURL string `json:"server_url"`
Alias string `json:"alias"`
AuthData *auth.AuthorizationResponse `json:"auth_data"`
ClientID string `json:"client_id"`
OrgURL string `json:"org_url"`
ServerURL string `json:"server_url"`
Alias string `json:"alias"`
ConfirmationRequired bool `json:"confirmation_required"`
}

type Contexts struct {
Expand All @@ -33,13 +34,14 @@ func (c *Contexts) Current() *CLIContext {
return &context
}

func (c *Contexts) UpdateContext(contextName string, authData *auth.AuthorizationResponse, clientID, orgURL, alias, serverURL string) error {
func (c *Contexts) UpdateContext(contextName string, authData *auth.AuthorizationResponse, clientID, orgURL, alias, serverURL string, confirmationRequired bool) error {
c.Contexts[contextName] = CLIContext{
AuthData: authData,
ClientID: clientID,
OrgURL: orgURL,
Alias: alias,
ServerURL: serverURL,
AuthData: authData,
ClientID: clientID,
OrgURL: orgURL,
Alias: alias,
ServerURL: serverURL,
ConfirmationRequired: confirmationRequired,
}

return WriteContexts(c)
Expand Down
34 changes: 22 additions & 12 deletions cmd/cloud/contexts.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,17 @@ func newCmdContextGet() *cobra.Command {

type updateContextFlags struct {
createContextFlags
Context string
ClearAuth bool
Context string
ClearAuth bool
ConfirmationRequired bool
}

func (f *updateContextFlags) addFlags(command *cobra.Command) {
f.createContextFlags.addFlags(command)
command.Flags().StringVar(&f.Context, "context", "", "Name of the context to update")
command.MarkFlagRequired("context")
command.Flags().BoolVar(&f.ClearAuth, "clear-auth", false, "Turns off authentication for this context")
command.Flags().BoolVar(&f.ConfirmationRequired, "confirmation-required", false, "Require confirmation for commands run in this context")
}

func newCmdContextUpdate() *cobra.Command {
Expand All @@ -107,6 +109,7 @@ func newCmdContextUpdate() *cobra.Command {
Alias := flags.Alias
clearAuth := flags.ClearAuth
contextName := flags.Context
confirmationRequired := flags.ConfirmationRequired

contexts, err := clicontext.ReadContexts()
if err != nil {
Expand Down Expand Up @@ -135,6 +138,10 @@ func newCmdContextUpdate() *cobra.Command {
context.Alias = Alias
}

if confirmationRequired != context.ConfirmationRequired {
context.ConfirmationRequired = confirmationRequired
}

if !skipAuth && !clearAuth && clientID != "" && orgURL != "" {
login, err := auth.Login(command.Context(), orgURL, clientID)
if err != nil {
Expand Down Expand Up @@ -163,11 +170,12 @@ func newCmdContextUpdate() *cobra.Command {

type createContextFlags struct {
clusterFlags
ClientID string
OrgURL string
SkipAuth bool
Alias string
ServerURL string
ClientID string
OrgURL string
SkipAuth bool
Alias string
ServerURL string
ConfirmationRequired bool
}

func (f *createContextFlags) addFlags(command *cobra.Command) {
Expand All @@ -189,6 +197,7 @@ func newCmdContextCreate() *cobra.Command {
orgURL := flags.OrgURL
skipAuth := flags.SkipAuth
Alias := flags.Alias
confirmationRequired := flags.ConfirmationRequired
contextName := ""

if Alias != "" {
Expand Down Expand Up @@ -217,11 +226,12 @@ func newCmdContextCreate() *cobra.Command {
}

contexts.Contexts[contextName] = clicontext.CLIContext{
ClientID: clientID,
OrgURL: orgURL,
AuthData: authData,
Alias: Alias,
ServerURL: serverAddress,
ClientID: clientID,
OrgURL: orgURL,
AuthData: authData,
Alias: Alias,
ServerURL: serverAddress,
ConfirmationRequired: confirmationRequired,
}

contexts.CurrentContext = contextName
Expand Down
2 changes: 1 addition & 1 deletion cmd/cloud/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func newCmdLogin() *cobra.Command {

context.AuthData = &login

err = contexts.UpdateContext(contextName, context.AuthData, context.ClientID, context.OrgURL, context.Alias, context.ServerURL)
err = contexts.UpdateContext(contextName, context.AuthData, context.ClientID, context.OrgURL, context.Alias, context.ServerURL, context.ConfirmationRequired)
return err
},
}
Expand Down
28 changes: 27 additions & 1 deletion cmd/cloud/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
package main

import (
"bufio"
"context"
"fmt"
"os"
"strings"

Expand All @@ -25,6 +27,18 @@ func isCommandThatSkipsAuth(cmd *cobra.Command) bool {
return cmd.Use == "migrate" || cmd.Use == "server" || cmd.Use == "login" || cmd.Parent().Use == "contexts"
}

func askConfirmation(contextURL string) bool {
reader := bufio.NewReader(os.Stdin)
fmt.Printf("Commands against this context (URL: %s) require confirmation. Do you want to proceed? (Y/N): ", contextURL)
response, err := reader.ReadString('\n')
if err != nil {
logger.WithError(err).Fatal("Failed to read user input.")
return false
}
response = strings.TrimSpace(strings.ToLower(response))
return response == "y" || response == "yes"
}

// TODO: Add support for --context flag to all commands that can use a context different from current one
var rootCmd = &cobra.Command{
Use: "cloud",
Expand Down Expand Up @@ -63,11 +77,21 @@ var rootCmd = &cobra.Command{
}

// Update disk copy of context with new auth data if any
err = contexts.UpdateContext(contexts.CurrentContext, authData, currentContext.ClientID, currentContext.OrgURL, currentContext.Alias, currentContext.ServerURL)
err = contexts.UpdateContext(contexts.CurrentContext, authData, currentContext.ClientID, currentContext.OrgURL, currentContext.Alias, currentContext.ServerURL, currentContext.ConfirmationRequired)
if err != nil {
logger.WithError(err).Fatal("Failed to update context with new auth data.")
}
cmd.SetContext(context.WithValue(cmd.Context(), clicontext.ContextKeyServerURL{}, currentContext.ServerURL))

skipConfirmation, _ := cmd.Flags().GetBool("y")
if currentContext.ConfirmationRequired && !skipConfirmation {
if !askConfirmation(currentContext.ServerURL) {
logger.Fatal("Confirmation required to proceed.")
return
}
} else if strings.Contains(currentContext.ServerURL, "prod") {
logger.Warn("\"Prod\" detected in server URL. Consider requiring confirmation on this context. Proceed with caution.")
}
}
},
RunE: func(cmd *cobra.Command, args []string) error {
Expand All @@ -89,6 +113,8 @@ func init() {

_ = rootCmd.MarkFlagRequired("database")

rootCmd.PersistentFlags().BoolVarP(new(bool), "y", "y", false, "Skip confirmation prompts")

rootCmd.AddCommand(newCmdServer())
rootCmd.AddCommand(newCmdCluster())
rootCmd.AddCommand(newCmdInstallation())
Expand Down
Loading