-
Notifications
You must be signed in to change notification settings - Fork 3
Add opt-in confirmations for task mutations #155
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| "github.com/pterm/pterm" | ||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| const ( | ||
| confirmFlag = "confirm" | ||
| confirmAnnotation = "cone.conductorone.com/confirm" | ||
| ) | ||
|
|
||
| func supportsConfirmation(cmd *cobra.Command) *cobra.Command { | ||
| if cmd.Annotations == nil { | ||
| cmd.Annotations = make(map[string]string) | ||
| } | ||
| cmd.Annotations[confirmAnnotation] = "true" | ||
| return cmd | ||
| } | ||
|
|
||
| func confirmationSupported(cmd *cobra.Command) bool { | ||
| return cmd.Annotations[confirmAnnotation] == "true" | ||
| } | ||
|
|
||
| func confirmMutation(cmd *cobra.Command, action string) error { | ||
| enabled, _ := cmd.Flags().GetBool(confirmFlag) | ||
| if !enabled { | ||
| return nil | ||
| } | ||
|
|
||
| nonInteractive, _ := cmd.Flags().GetBool(nonInteractiveFlag) | ||
| if nonInteractive { | ||
| return fmt.Errorf("--confirm requires interactive mode") | ||
| } | ||
|
|
||
| confirmed, err := pterm.DefaultInteractiveConfirm.Show("Proceed with " + action + "?") | ||
| if err != nil { | ||
| return err | ||
| } | ||
| if !confirmed { | ||
| return fmt.Errorf("mutation cancelled") | ||
| } | ||
| return nil | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| package main | ||
|
|
||
| import ( | ||
| "strings" | ||
| "testing" | ||
|
|
||
| "github.com/spf13/cobra" | ||
| ) | ||
|
|
||
| func TestConfirmMutationRequiresInteractiveMode(t *testing.T) { | ||
| cmd := &cobra.Command{} | ||
| cmd.Flags().Bool(confirmFlag, false, "") | ||
| cmd.Flags().Bool(nonInteractiveFlag, false, "") | ||
| if err := cmd.ParseFlags([]string{"--confirm", "--non-interactive"}); err != nil { | ||
| t.Fatalf("ParseFlags: %v", err) | ||
| } | ||
|
|
||
| err := confirmMutation(cmd, "creating an access request") | ||
| if err == nil || !strings.Contains(err.Error(), "requires interactive mode") { | ||
| t.Fatalf("confirmMutation error = %v, want interactive-mode error", err) | ||
| } | ||
| } | ||
|
|
||
| func TestConfirmMutationIsOptIn(t *testing.T) { | ||
| if err := confirmMutation(&cobra.Command{}, "creating an access request"); err != nil { | ||
| t.Fatalf("confirmMutation without --confirm: %v", err) | ||
| } | ||
| } | ||
|
Comment on lines
+24
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Suggestion: This test passes vacuously. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -42,7 +42,14 @@ func runCli(ctx context.Context) int { | |
| Use: "cone", | ||
| Short: "Cone interacts with the ConductorOne API to manage access to entitlements.", | ||
| Version: version, | ||
| RunE: func(cmd *cobra.Command, _ []string) error { | ||
| return cmd.Help() | ||
| }, | ||
| PersistentPreRunE: func(cmd *cobra.Command, args []string) error { | ||
| confirm, _ := cmd.Flags().GetBool(confirmFlag) | ||
| if confirm && !confirmationSupported(cmd) { | ||
| return fmt.Errorf("--confirm is not supported by %q", cmd.CommandPath()) | ||
| } | ||
| cmd.SetContext(ctx) | ||
| return nil | ||
| }, | ||
|
|
@@ -58,6 +65,7 @@ func runCli(ctx context.Context) int { | |
| cliCmd.PersistentFlags().StringP("output", "o", "table", "Output format. Valid values: table, json, json-pretty, wide.") | ||
| cliCmd.PersistentFlags().Bool("debug", false, "Enable HTTP debug logging") | ||
| cliCmd.PersistentFlags().String("log-level", "", "Set log level (debug, info, warn, error)") | ||
| cliCmd.PersistentFlags().Bool(confirmFlag, false, "Prompt before supported task mutations") | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Suggestion: |
||
|
|
||
| err := initConfig(cliCmd) | ||
| if err != nil { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,7 +16,7 @@ func tasksCommentCmd() *cobra.Command { | |
| RunE: tasksCommentRun, | ||
| } | ||
|
|
||
| return cmd | ||
| return supportsConfirmation(cmd) | ||
| } | ||
|
|
||
| func tasksCommentRun(cmd *cobra.Command, args []string) error { | ||
|
|
@@ -29,10 +29,16 @@ func tasksCommentRun(cmd *cobra.Command, args []string) error { | |
| return err | ||
| } | ||
|
|
||
| taskId := args[0] | ||
| taskID := args[0] | ||
| comment := args[1] | ||
| if _, err := c.GetTask(ctx, taskID); err != nil { | ||
| return err | ||
| } | ||
|
Comment on lines
+34
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Suggestion: This |
||
| if err := confirmMutation(cmd, "commenting on task "+taskID); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| userResp, err := c.CommentOnTask(ctx, taskId, comment) | ||
| userResp, err := c.CommentOnTask(ctx, taskID, comment) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟠 Bug: Both flags are read straight off the
pflagset, bypassing viper. Everywhere else in this reponon-interactiveis read asv.GetBool(nonInteractiveFlag)(get_drop_task.go:136,190,449,form_fields.go:37), andgetSubViperForProfilebindscmd.Flags()so config-profile andCONE_*env values resolve. Two consequences:CONE_CONFIRM=true/confirm: truein a profile silently does nothing (the safety control fails open, no prompt), andCONE_NON_INTERACTIVE=truecombined with--confirmskips the guard and falls through topterm, which opens/dev/ttydirectly — so it blocks on a terminal prompt instead of returning the intended error.Suggest threading the
*viper.Viperthat all four call sites already have fromcmdContextinto this helper and usingv.GetBool(...)for both reads. Confidence: high.