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 remote check to secret and variable commands #9083

Open
wants to merge 13 commits into
base: trunk
Choose a base branch
from

Conversation

wingleung
Copy link
Contributor

Fixes #4688

@wingleung wingleung marked this pull request as ready for review June 2, 2024 10:28
@wingleung wingleung requested a review from a team as a code owner June 2, 2024 10:28
@wingleung wingleung requested a review from andyfeller June 2, 2024 10:28
@cliAutomation cliAutomation added the external pull request originating outside of the CLI core team label Jun 2, 2024
@wingleung wingleung changed the title WIP add remote check to secret and variable commands add remote check to secret and variable commands Jun 3, 2024
@andyfeller
Copy link
Contributor

@wingleung : thank you yet again for your time and effort to improve the GitHub CLI and your patience with my slow follow up! 🙇

reviewing this right now, wanting to offer feedback today

Comment on lines 178 to 197

err = cmdutil.ValidateHasOnlyOneRemote(opts.HasRepoOverride, opts.Remotes)
if err != nil {
defaultRepo := cmdutil.DefaultRepo(opts.Remotes)

if defaultRepo != nil {
baseRepo = defaultRepo
} else if opts.Interactive {
selectedRepo, errSelectedRepo := cmdutil.PromptForRepo(baseRepo, opts.Remotes, opts.Prompter)

if errSelectedRepo != nil {
return errSelectedRepo
}

baseRepo = selectedRepo
} else {
return err
}
}

Copy link
Contributor

@andyfeller andyfeller Aug 16, 2024

Choose a reason for hiding this comment

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

Taking a step back from the code, is the following the logical order that repository should be identified?

  1. If a user specifies --owner this is an organization secret; otherwise it is a repository secret of some sort

  2. If a user specifies --repo this has the highest precedence because the user is explicitly telling us what to use

  3. Otherwise, we figure out the repo based on the remotes, dealing with various scenarios

    1. If there are multiple remotes but we cannot interact, error
    2. If there are multiple remotes and we can interact, prompt the user and maybe mention they can avoid this in the future with either using --repo ...
    3. If there is 1 remote, we use it

Copy link
Contributor

@andyfeller andyfeller Aug 19, 2024

Choose a reason for hiding this comment

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

Discussing with @williammartin

@wingleung : firstly, allow me to apologize for confusion on my part; Will has highlighted the fact that gh.resolved flag on the remote that provides the base repo is actually contributing to the challenge we're trying to undo here.

During our conversation, Will highlighted several things including:

  1. Remove the line about gh repo set-default as this is technically the problem we're running into
  2. This PR should explicitly call out in gh repo set-default that it IS NOT used for repository + repository environment
  3. In the remote prompt ordering, the upstream should be first as we know upset users will want to hit enter
  4. With these changes, we need to ensure it is called out in release notes and mention the community should follow up in this issue about interest in a configuration option
  5. Will also called out a larger problem regarding the inconsistent handling of repository defaults that might necessitate further changes

Copy link
Contributor Author

@wingleung wingleung Aug 21, 2024

Choose a reason for hiding this comment

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

  1. If a user specifies --owner this is an organization secret; otherwise it is a repository secret of some sort

I think you meant --org instead of --owner, if so ✅

  1. If a user specifies --repo this has the highest precedence because the user is explicitly telling us what to use

I think number 2 would be a secret or variable set with the --env flag, to set variables and secrets on a deployment environment level. which would be place between --org and --repo in terms of scope level

Copy link
Contributor Author

@wingleung wingleung Aug 21, 2024

Choose a reason for hiding this comment

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

During our conversation, Will highlighted several things including:

  1. Remove the line about gh repo set-default as this is technically the problem we're running into

OK, reverted the last commit, it will still select the default in the select prompt if there is a default but submitting is up to the user

  1. This PR should explicitly call out in gh repo set-default that it IS NOT used for repository + repository environment

Idd, it would do the exact opposite to what's in the docs, so the guidelines for gh repo set-default should change as well, added a proposal ### NOTE: gh does not use the default repository for managing repository and environment secrets or variables.. Let me know if you see any other places where we can add this note

  1. In the remote prompt ordering, the upstream should be first as we know upset users will want to hit enter

We piggyback on Remotes which is doing sorting by itself using the Less function and the sort library from golang 👉

cli/context/remote.go

Lines 60 to 78 in 95a2f95

func remoteNameSortScore(name string) int {
switch strings.ToLower(name) {
case "upstream":
return 3
case "github":
return 2
case "origin":
return 1
default:
return 0
}
}
// https://golang.org/pkg/sort/#Interface
func (r Remotes) Len() int { return len(r) }
func (r Remotes) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
func (r Remotes) Less(i, j int) bool {
return remoteNameSortScore(r[i].Name) > remoteNameSortScore(r[j].Name)
}
so the order is always upstream first even though the default selected option might be the origin one. Or do you mean we should always select the first option which is the upstream option? That would be not be as intuitive because I would expect the origin to be the default option

  1. With these changes, we need to ensure it is called out in release notes and mention the community should follow up in this issue about interest in a configuration option

👍

  1. Will also called out a larger problem regarding the inconsistent handling of repository defaults that might necessitate further changes

I agree, I also mentioned something similar here 👉 #9083 (comment). problem is, it's not just a feature or a change to a command, it's refactoring with a higher level overview in mind. Is that something I can kickstart in https://github.com/cli/cli/discussions/categories/ideas? Or do you prefer to have this discussion internally first?

NOTE: gh does not use the default repository for managing repository and environment secrets or variables.
@andyfeller
Copy link
Contributor

Manual testing with forked repo

The following scenarios are exercising changes from the PR on a fork of a repo, which should require explicitly setting the repo because of multiple remotes.

  1. Building local gh for testing:

    andyfeller@Andys-MBP:cli/cli-trunk ‹add-remote-check-to-secret-and-variable›$ make
    go build -trimpath -ldflags "-X github.com/cli/cli/v2/internal/build.Date=2024-08-23 -X github.com/cli/cli/v2/internal/build.Version=v2.55.0-13-g97b10370 " -o bin/gh ./cmd/gh
  2. Creating upstream repo for testing

    andyfeller@Andys-MBP:cli/cli-trunk ‹add-remote-check-to-secret-and-variable›$ ./bin/gh repo create --add-readme --description "Upstream repo used in testing GitHub CLI secret and variable behaviors" --disable-issues --disable-wiki --public andyfeller/gh-testing-01 
    ✓ Created repository andyfeller/gh-testing-01 on GitHub
      https://github.com/andyfeller/gh-testing-01
  3. Creating downstream fork for testing

    andyfeller@Andys-MBP:cli/cli-trunk ‹add-remote-check-to-secret-and-variable›$ cd ~/Documents/workspace/tinyfists 
    andyfeller@Andys-MBP:workspace/tinyfists $ ~/Documents/workspace/cli/cli-trunk/bin/gh repo fork andyfeller/gh-testing-01 --org tinyfists --clone 
    ✓ Created fork tinyfists/gh-testing-01
    Cloning into 'gh-testing-01'...
    remote: Repository not found.
    fatal: repository 'https://github.com/tinyfists/gh-testing-01.git/' not found
    Cloning into 'gh-testing-01'...
    remote: Enumerating objects: 3, done.
    remote: Counting objects: 100% (3/3), done.
    remote: Compressing objects: 100% (2/2), done.
    remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
    Receiving objects: 100% (3/3), done.
    From https://github.com/andyfeller/gh-testing-01
     * [new branch]      main       -> upstream/main
    ✓ Cloned fork
    ! Repository andyfeller/gh-testing-01 set as the default repository. To learn more about the default repository, run: gh repo set-default --help
    andyfeller@Andys-MBP:workspace/tinyfists $ cd gh-testing-01 

gh secret set

  1. Confirming repo with multiple remotes forces user to choose

    andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh secret set TEST001 --body "wut"
    multiple remotes detected [upstream origin]. please specify which repo to use by providing the -R or --repo argument
  2. Confirming setting secret for upstream works

    andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh secret set TEST001 --body "wut" --repo tinyfists/gh-testing-01
    ✓ Set Actions secret TEST001 for tinyfists/gh-testing-01
  3. Confirming setting secret for downstream works

    andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh secret set TEST002 --body "wut" --repo andyfeller/gh-testing-01
    ✓ Set Actions secret TEST002 for andyfeller/gh-testing-01

gh secret list

  1. Confirming repo with multiple remotes forces user to choose

    andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh secret list                                                    
    multiple remotes detected [upstream origin]. please specify which repo to use by providing the -R or --repo argument
  2. Confirming listing secret for upstream works

    andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh secret list --repo tinyfists/gh-testing-01
    NAME     UPDATED               
    TEST001  less than a minute ago
  3. Confirming listing secret for upstream works

    andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh secret list --repo andyfeller/gh-testing-01
    NAME     UPDATED               
    TEST002  less than a minute ago

gh secret delete

  1. Confirming repo with multiple remotes forces user to choose

    andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh secret delete TEST001
    multiple remotes detected [upstream origin]. please specify which repo to use by providing the -R or --repo argument
  2. Confirming deleting non-existent secret for upstream works as expected

    andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh secret delete TEST001 --repo andyfeller/gh-testing-01
    failed to delete secret TEST001: HTTP 404 (https://api.github.com/repos/andyfeller/gh-testing-01/actions/secrets/TEST001)
  3. Confirming deleting secret for downstream works as expected

    andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh secret delete TEST001 --repo tinyfists/gh-testing-01
    ✓ Deleted Actions secret TEST001 from tinyfists/gh-testing-01
    andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ 

gh variable set

  1. Confirming repo with multiple remotes forces user to choose
andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh variable set FOO --body "bar"
multiple remotes detected [upstream origin]. please specify which repo to use by providing the -R or --repo argument
  1. Confirming setting variable for upstream works as expected
andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh variable set FOO --body "bar" --repo tinyfists/gh-testing-01 
✓ Created variable FOO for tinyfists/gh-testing-01
  1. Confirming setting variable for downstream works as expected
andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh variable set FOO --body "baz" --repo andyfeller/gh-testing-01
✓ Created variable FOO for andyfeller/gh-testing-01

gh variable list

  1. Confirming repo with multiple remotes forces user to choose
andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh variable list                                                
multiple remotes detected [upstream origin]. please specify which repo to use by providing the -R or --repo argument
  1. Confirming listing variables for upstream works as expected
andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh variable list --repo tinyfists/gh-testing-01
NAME  VALUE  UPDATED               
FOO   bar    less than a minute ago
  1. Confirming listing variables for downstream works as expected
andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh variable list --repo andyfeller/gh-testing-01
NAME  VALUE  UPDATED               
FOO   baz    less than a minute ago

gh variable delete

  1. Confirming repo with multiple remotes forces user to choose
andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh variable delete FOO   
multiple remotes detected [upstream origin]. please specify which repo to use by providing the -R or --repo argument
  1. Confirming deleting variable for downstream works as expected
andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh variable delete FOO --repo tinyfists/gh-testing-01
✓ Deleted variable FOO from tinyfists/gh-testing-01
andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh variable list --repo tinyfists/gh-testing-01     
no variables found
  1. Confirming upstream variable still exists
andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ ~/Documents/workspace/cli/cli-trunk/bin/gh variable list --repo andyfeller/gh-testing-01
NAME  VALUE  UPDATED             
FOO   baz    about 28 minutes ago

@andyfeller
Copy link
Contributor

Manual testing directly against upstream

Wanting to make sure we were just testing the multiple remotes scenario, this is me running through several of the commands to make sure no regressions.

andyfeller@Andys-MBP:tinyfists/gh-testing-01 ‹main›$ cd ../../andyfeller
andyfeller@Andys-MBP:workspace/andyfeller $ gh repo clone gh-testing-01
Cloning into 'gh-testing-01'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Receiving objects: 100% (3/3), done.
andyfeller@Andys-MBP:workspace/andyfeller $ cd gh-testing-01 
andyfeller@Andys-MBP:andyfeller/gh-testing-01 ‹main›$ gh variable list
NAME  VALUE  UPDATED         
FOO   baz    about 1 hour ago
andyfeller@Andys-MBP:andyfeller/gh-testing-01 ‹main›$ gh secret list
NAME     UPDATED         
TEST002  about 1 hour ago
andyfeller@Andys-MBP:andyfeller/gh-testing-01 ‹main›$ gh secret set TEST003 --body "on the catwalk"
✓ Set Actions secret TEST003 for andyfeller/gh-testing-01
andyfeller@Andys-MBP:andyfeller/gh-testing-01 ‹main›$ gh secret list                               
NAME     UPDATED               
TEST002  about 1 hour ago
TEST003  less than a minute ago
andyfeller@Andys-MBP:andyfeller/gh-testing-01 ‹main›$ gh variable set BAR --body "pipe"
✓ Created variable BAR for andyfeller/gh-testing-01
andyfeller@Andys-MBP:andyfeller/gh-testing-01 ‹main›$ gh variable list                             
NAME  VALUE  UPDATED               
BAR   pipe   less than a minute ago
FOO   baz    about 1 hour ago
andyfeller@Andys-MBP:andyfeller/gh-testing-01 ‹main›$ gh variable get BAR
pipe
andyfeller@Andys-MBP:andyfeller/gh-testing-01 ‹main›$ gh variable delete FOO
✓ Deleted variable FOO from andyfeller/gh-testing-01
andyfeller@Andys-MBP:andyfeller/gh-testing-01 ‹main›$ gh secret delete TEST002
✓ Deleted Actions secret TEST002 from andyfeller/gh-testing-01

Copy link
Contributor

@andyfeller andyfeller left a comment

Choose a reason for hiding this comment

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

Just want to take a moment and say thank you for the monumental lift here, @wingleung ❤️

From the automated tests here and the manual testing I commented on in the PR, I think this might be complete, so I'm giving my tentative :shipit: I'd like @williammartin to follow up when he's back on Wednesday next week solely because of how critical getting this right is. 🙇

Promise its in the home stretch; again thank you for your patience and closing a security concern in the GitHub CLI! ❤️

@wingleung
Copy link
Contributor Author

wingleung commented Aug 25, 2024

Just want to take a moment and say thank you for the monumental lift here, @wingleung ❤️

@andyfeller Pleasure was mine, especially because of the insights on high standards and the serene, collaborative environment we maintained throughout, love it 🙏

@andyfeller andyfeller self-requested a review September 18, 2024 12:27
Copy link
Member

@williammartin williammartin left a comment

Choose a reason for hiding this comment

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

I think there is some surprising behaviour in this PR as it is. In particular, I would expect the following three scenarios to prompt:

gh repo create my-org/my-repo
gh repo fork --org other-org my-org/my-repo
gh repo clone other-org/my-repo
cd my-repo
gh secret set VAL --body KEY
gh repo create my-org/my-repo
gh repo fork --org other-org my-org/my-repo
gh repo clone other-org/my-repo
cd my-repo
gh secret list
gh repo create my-org/my-repo
gh repo fork --org other-org my-org/my-repo
gh repo clone other-org/my-repo
cd my-repo
gh secret delete VAL

However, they do not right now, and I think this was alluded to here #9083 (comment)

Erroring and forcing users to provide a --repo flag in an interactive environment in some cases but not others seems inconsistent.

Additionally, I'm not convinced we should be modifying the variable set of commands. Breaking people's scripts for the sake of security is one thing, breaking them for consistent UX is another. Fortunately this should be easy to back out / and do later if we determine it is worthwhile.

We're going to discuss in our planning meeting later how to get this in. We feel bad that it's been languishing for so long (and I feel bad because Andy has been asking for my review for weeks 😬 ), so just hang in there @wingleung !

Acceptance Scripts

Based on #4688 (comment) I created a set of acceptance scripts over in 0c9b6ed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
external pull request originating outside of the CLI core team
Projects
Status: Needs review 🤔
Development

Successfully merging this pull request may close these issues.

Secret created in Upstream Repo instead of Current Repo
5 participants