Skip to content

Commit 2c3f02e

Browse files
committed
Ensure NOT_FOUND error when querying private repos using insufficient scope
1 parent 2ca18e0 commit 2c3f02e

File tree

2 files changed

+49
-9
lines changed

2 files changed

+49
-9
lines changed

api/queries_repo.go

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -241,12 +241,23 @@ func FetchRepository(client *Client, repo ghrepo.Interface, fields []string) (*R
241241
}
242242

243243
var result struct {
244-
Repository Repository
244+
Repository *Repository
245245
}
246246
if err := client.GraphQL(repo.RepoHost(), query, variables, &result); err != nil {
247247
return nil, err
248248
}
249-
return InitRepoHostname(&result.Repository, repo.RepoHost()), nil
249+
// The GraphQL API should have returned an error in case of a missing repository, but this isn't
250+
// guaranteed to happen when an authentication token with insufficient permissions is being used.
251+
if result.Repository == nil {
252+
return nil, GraphQLErrorResponse{
253+
Errors: []GraphQLError{{
254+
Type: "NOT_FOUND",
255+
Message: fmt.Sprintf("Could not resolve to a Repository with the name '%s/%s'.", repo.RepoOwner(), repo.RepoName()),
256+
}},
257+
}
258+
}
259+
260+
return InitRepoHostname(result.Repository, repo.RepoHost()), nil
250261
}
251262

252263
func GitHubRepo(client *Client, repo ghrepo.Interface) (*Repository, error) {
@@ -280,16 +291,24 @@ func GitHubRepo(client *Client, repo ghrepo.Interface) (*Repository, error) {
280291
"name": repo.RepoName(),
281292
}
282293

283-
result := struct {
284-
Repository Repository
285-
}{}
286-
err := client.GraphQL(repo.RepoHost(), query, variables, &result)
287-
288-
if err != nil {
294+
var result struct {
295+
Repository *Repository
296+
}
297+
if err := client.GraphQL(repo.RepoHost(), query, variables, &result); err != nil {
289298
return nil, err
290299
}
300+
// The GraphQL API should have returned an error in case of a missing repository, but this isn't
301+
// guaranteed to happen when an authentication token with insufficient permissions is being used.
302+
if result.Repository == nil {
303+
return nil, GraphQLErrorResponse{
304+
Errors: []GraphQLError{{
305+
Type: "NOT_FOUND",
306+
Message: fmt.Sprintf("Could not resolve to a Repository with the name '%s/%s'.", repo.RepoOwner(), repo.RepoName()),
307+
}},
308+
}
309+
}
291310

292-
return InitRepoHostname(&result.Repository, repo.RepoHost()), nil
311+
return InitRepoHostname(result.Repository, repo.RepoHost()), nil
293312
}
294313

295314
func RepoDefaultBranch(client *Client, repo ghrepo.Interface) (string, error) {

api/queries_repo_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,27 @@ import (
1010
"github.com/cli/cli/v2/pkg/httpmock"
1111
)
1212

13+
func TestGitHubRepo_notFound(t *testing.T) {
14+
httpReg := &httpmock.Registry{}
15+
defer httpReg.Verify(t)
16+
17+
httpReg.Register(
18+
httpmock.GraphQL(`query RepositoryInfo\b`),
19+
httpmock.StringResponse(`{ "data": { "repository": null } }`))
20+
21+
client := NewClient(ReplaceTripper(httpReg))
22+
repo, err := GitHubRepo(client, ghrepo.New("OWNER", "REPO"))
23+
if err == nil {
24+
t.Fatal("GitHubRepo did not return an error")
25+
}
26+
if wants := "GraphQL error: Could not resolve to a Repository with the name 'OWNER/REPO'."; err.Error() != wants {
27+
t.Errorf("GitHubRepo error: want %q, got %q", wants, err.Error())
28+
}
29+
if repo != nil {
30+
t.Errorf("GitHubRepo: expected nil repo, got %v", repo)
31+
}
32+
}
33+
1334
func Test_RepoMetadata(t *testing.T) {
1435
http := &httpmock.Registry{}
1536
client := NewClient(ReplaceTripper(http))

0 commit comments

Comments
 (0)