From 5eddf8d52369df321693c5f5131fdd138cd237a6 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 20 Aug 2025 11:03:44 -0600 Subject: [PATCH] Merge pull request #11536 from cli/copilot/fix-11535 Fix `gh repo delete --yes` safety issue when no repository argument provided --- pkg/cmd/repo/delete/delete.go | 12 ++++++++++++ pkg/cmd/repo/delete/delete_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/pkg/cmd/repo/delete/delete.go b/pkg/cmd/repo/delete/delete.go index 96cfe5e95..01495387e 100644 --- a/pkg/cmd/repo/delete/delete.go +++ b/pkg/cmd/repo/delete/delete.go @@ -43,6 +43,10 @@ func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Co Delete a GitHub repository. With no argument, deletes the current repository. Otherwise, deletes the specified repository. + + For safety, when no repository argument is provided, the %[1]s--yes%[1]s flag is ignored + and you will be prompted for confirmation. To delete the current repository non-interactively, + specify it explicitly (e.g., %[1]sgh repo delete owner/repo --yes%[1]s). Deletion requires authorization with the %[1]sdelete_repo%[1]s scope. To authorize, run %[1]sgh auth refresh -s delete_repo%[1]s @@ -53,6 +57,14 @@ func NewCmdDelete(f *cmdutil.Factory, runF func(*DeleteOptions) error) *cobra.Co opts.RepoArg = args[0] } + // Ignore --yes when no argument provided to prevent accidental deletion + if len(args) == 0 && opts.Confirmed { + if !opts.IO.CanPrompt() { + return cmdutil.FlagErrorf("cannot non-interactively delete current repository. Please specify a repository or run interactively") + } + opts.Confirmed = false + } + if !opts.IO.CanPrompt() && !opts.Confirmed { return cmdutil.FlagErrorf("--yes required when not running interactively") } diff --git a/pkg/cmd/repo/delete/delete_test.go b/pkg/cmd/repo/delete/delete_test.go index b52ac1de9..d5070d5aa 100644 --- a/pkg/cmd/repo/delete/delete_test.go +++ b/pkg/cmd/repo/delete/delete_test.go @@ -48,6 +48,30 @@ func TestNewCmdDelete(t *testing.T) { tty: true, output: DeleteOptions{}, }, + { + name: "yes flag ignored when no argument tty", + tty: true, + input: "--yes", + output: DeleteOptions{Confirmed: false}, // --yes should be ignored + }, + { + name: "yes flag error when no argument notty", + input: "--yes", + wantErr: true, + errMsg: "cannot non-interactively delete current repository. Please specify a repository or run interactively", + }, + { + name: "confirm flag error when no argument notty", + input: "--confirm", + wantErr: true, + errMsg: "cannot non-interactively delete current repository. Please specify a repository or run interactively", + }, + { + name: "confirm flag also ignored when no argument tty", + tty: true, + input: "--confirm", + output: DeleteOptions{Confirmed: false}, // --confirm should also be ignored + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {