mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-07-28 23:28:21 +00:00
fix(github): prevent null pointer dereferencing when using AllowMergeableBypassApply with no required checks on branch protection (#3672)
* Implement test for allow mergeable bypass apply with no branch protection checks * Report true combined status if no branch protection required status checks * Remove warning on feature flag utilization
This commit is contained in:
@@ -564,11 +564,6 @@ This is useful when you have many projects and want to keep the pull request cle
|
||||
```
|
||||
Feature flag to enable ability to use `mergeable` mode with required apply status check.
|
||||
|
||||
::: warning NOTE
|
||||
If there aren't any required checks set in the Github branch protection settings then this will cause atlantis to fail.
|
||||
See issue https://github.com/runatlantis/atlantis/issues/2663.
|
||||
:::
|
||||
|
||||
### `--gitlab-hostname`
|
||||
```bash
|
||||
atlantis server --gitlab-hostname="my.gitlab.enterprise.com"
|
||||
|
||||
@@ -418,6 +418,10 @@ func (g *GithubClient) GetCombinedStatusMinusApply(repo models.Repo, pull *githu
|
||||
return false, errors.Wrap(err, "getting required status checks")
|
||||
}
|
||||
|
||||
if required.RequiredStatusChecks == nil {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
//check check suite/check run api
|
||||
checksuites, _, err := g.client.Checks.ListCheckSuitesForRef(context.Background(), *pull.Head.Repo.Owner.Login, repo.Name, *pull.Head.Ref, nil)
|
||||
if err != nil {
|
||||
|
||||
@@ -737,6 +737,114 @@ func TestGithubClient_PullIsMergeableWithAllowMergeableBypassApply(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGithubClient_PullIsMergeableWithAllowMergeableBypassApplyButWithNoBranchProtectionChecks(t *testing.T) {
|
||||
vcsStatusName := "atlantis"
|
||||
cases := []struct {
|
||||
state string
|
||||
reviewDecision string
|
||||
expMergeable bool
|
||||
}{
|
||||
{
|
||||
"blocked",
|
||||
`"REVIEW_REQUIRED"`,
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
// Use a real GitHub json response and edit the mergeable_state field.
|
||||
jsBytes, err := os.ReadFile("testdata/github-pull-request.json")
|
||||
Ok(t, err)
|
||||
prJSON := string(jsBytes)
|
||||
|
||||
// Status Check Response
|
||||
jsBytes, err = os.ReadFile("testdata/github-commit-status-full.json")
|
||||
Ok(t, err)
|
||||
commitJSON := string(jsBytes)
|
||||
|
||||
// Branch protection Response
|
||||
jsBytes, err = os.ReadFile("testdata/github-branch-protection-no-required-checks.json")
|
||||
Ok(t, err)
|
||||
branchProtectionJSON := string(jsBytes)
|
||||
|
||||
// List check suites Response
|
||||
jsBytes, err = os.ReadFile("testdata/github-commit-check-suites-completed.json")
|
||||
Ok(t, err)
|
||||
checkSuites := string(jsBytes)
|
||||
|
||||
// List check runs in a check suite
|
||||
jsBytes, err = os.ReadFile("testdata/github-commit-check-suites-check-runs-completed.json")
|
||||
Ok(t, err)
|
||||
checkRuns := string(jsBytes)
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.state, func(t *testing.T) {
|
||||
response := strings.Replace(prJSON,
|
||||
`"mergeable_state": "clean"`,
|
||||
fmt.Sprintf(`"mergeable_state": "%s"`, c.state),
|
||||
1,
|
||||
)
|
||||
|
||||
// reviewDecision Response
|
||||
reviewDecision := fmt.Sprintf(`{
|
||||
"data": {
|
||||
"repository": {
|
||||
"pullRequest": {
|
||||
"reviewDecision": %s
|
||||
}
|
||||
}
|
||||
}
|
||||
}`, c.reviewDecision)
|
||||
|
||||
testServer := httptest.NewTLSServer(
|
||||
http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.RequestURI {
|
||||
case "/api/v3/repos/octocat/Hello-World/pulls/1":
|
||||
w.Write([]byte(response)) // nolint: errcheck
|
||||
return
|
||||
case "/api/v3/repos/octocat/Hello-World/pulls/1/reviews?per_page=300":
|
||||
w.Write([]byte("[]")) // nolint: errcheck
|
||||
return
|
||||
case "/api/v3/repos/octocat/Hello-World/commits/new-topic/status":
|
||||
w.Write([]byte(commitJSON)) // nolint: errcheck
|
||||
case "/api/graphql":
|
||||
w.Write([]byte(reviewDecision)) // nolint: errcheck
|
||||
case "/api/v3/repos/octocat/Hello-World/branches/main/protection":
|
||||
w.Write([]byte(branchProtectionJSON)) // nolint: errcheck
|
||||
case "/api/v3/repos/octocat/Hello-World/commits/new-topic/check-suites":
|
||||
w.Write([]byte(checkSuites)) // nolint: errcheck
|
||||
case "/api/v3/repos/octocat/Hello-World/check-suites/1234567890/check-runs":
|
||||
w.Write([]byte(checkRuns)) // nolint: errcheck
|
||||
default:
|
||||
t.Errorf("got unexpected request at %q", r.RequestURI)
|
||||
http.Error(w, "not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
}))
|
||||
testServerURL, err := url.Parse(testServer.URL)
|
||||
Ok(t, err)
|
||||
client, err := vcs.NewGithubClient(testServerURL.Host, &vcs.GithubUserCredentials{"user", "pass"}, vcs.GithubConfig{AllowMergeableBypassApply: true}, logging.NewNoopLogger(t))
|
||||
Ok(t, err)
|
||||
defer disableSSLVerification()()
|
||||
|
||||
actMergeable, err := client.PullIsMergeable(models.Repo{
|
||||
FullName: "octocat/Hello-World",
|
||||
Owner: "octocat",
|
||||
Name: "Hello-World",
|
||||
CloneURL: "",
|
||||
SanitizedCloneURL: "",
|
||||
VCSHost: models.VCSHost{
|
||||
Type: models.Github,
|
||||
Hostname: "github.com",
|
||||
},
|
||||
}, models.PullRequest{
|
||||
Num: 1,
|
||||
}, vcsStatusName)
|
||||
Ok(t, err)
|
||||
Equals(t, c.expMergeable, actMergeable)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGithubClient_MergePullHandlesError(t *testing.T) {
|
||||
cases := []struct {
|
||||
code int
|
||||
|
||||
10
server/events/vcs/testdata/github-branch-protection-no-required-checks.json
vendored
Normal file
10
server/events/vcs/testdata/github-branch-protection-no-required-checks.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"url": "https://api.github.com/repos/octocat/repo/branches/master/protection",
|
||||
"required_pull_request_reviews": {
|
||||
"url": "https://api.github.com/repos/octocat/repo/branches/master/protection/required_pull_request_reviews",
|
||||
"dismiss_stale_reviews": false,
|
||||
"require_code_owner_reviews": false,
|
||||
"require_last_push_approval": false,
|
||||
"required_approving_review_count": 1
|
||||
}
|
||||
}
|
||||
95
server/events/vcs/testdata/github-commit-check-suites-check-runs-completed.json
vendored
Normal file
95
server/events/vcs/testdata/github-commit-check-suites-check-runs-completed.json
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
{
|
||||
"total_count": 1,
|
||||
"check_runs": [
|
||||
{
|
||||
"id": 4,
|
||||
"head_sha": "ce587453ced02b1526dfb4cb910479d431683101",
|
||||
"node_id": "MDg6Q2hlY2tSdW40",
|
||||
"external_id": "",
|
||||
"url": "https://api.github.com/repos/github/hello-world/check-runs/4",
|
||||
"html_url": "https://github.com/github/hello-world/runs/4",
|
||||
"details_url": "https://example.com",
|
||||
"status": "completed",
|
||||
"conclusion": "success",
|
||||
"started_at": "2018-05-04T01:14:52Z",
|
||||
"completed_at": "2018-05-04T01:14:52Z",
|
||||
"output": {
|
||||
"title": "Mighty Readme report",
|
||||
"summary": "There are 0 failures, 2 warnings, and 1 notice.",
|
||||
"text": "You may have some misspelled words on lines 2 and 4. You also may want to add a section in your README about how to install your app.",
|
||||
"annotations_count": 2,
|
||||
"annotations_url": "https://api.github.com/repos/github/hello-world/check-runs/4/annotations"
|
||||
},
|
||||
"name": "mighty_readme",
|
||||
"check_suite": {
|
||||
"id": 5
|
||||
},
|
||||
"app": {
|
||||
"id": 1,
|
||||
"slug": "octoapp",
|
||||
"node_id": "MDExOkludGVncmF0aW9uMQ==",
|
||||
"owner": {
|
||||
"login": "github",
|
||||
"id": 1,
|
||||
"node_id": "MDEyOk9yZ2FuaXphdGlvbjE=",
|
||||
"url": "https://api.github.com/orgs/github",
|
||||
"repos_url": "https://api.github.com/orgs/github/repos",
|
||||
"events_url": "https://api.github.com/orgs/github/events",
|
||||
"avatar_url": "https://github.com/images/error/octocat_happy.gif",
|
||||
"gravatar_id": "",
|
||||
"html_url": "https://github.com/octocat",
|
||||
"followers_url": "https://api.github.com/users/octocat/followers",
|
||||
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/octocat/orgs",
|
||||
"received_events_url": "https://api.github.com/users/octocat/received_events",
|
||||
"type": "User",
|
||||
"site_admin": true
|
||||
},
|
||||
"name": "Octocat App",
|
||||
"description": "",
|
||||
"external_url": "https://example.com",
|
||||
"html_url": "https://github.com/apps/octoapp",
|
||||
"created_at": "2017-07-08T16:18:44-04:00",
|
||||
"updated_at": "2017-07-08T16:18:44-04:00",
|
||||
"permissions": {
|
||||
"metadata": "read",
|
||||
"contents": "read",
|
||||
"issues": "write",
|
||||
"single_file": "write"
|
||||
},
|
||||
"events": [
|
||||
"push",
|
||||
"pull_request"
|
||||
]
|
||||
},
|
||||
"pull_requests": [
|
||||
{
|
||||
"url": "https://api.github.com/repos/github/hello-world/pulls/1",
|
||||
"id": 1934,
|
||||
"number": 3956,
|
||||
"head": {
|
||||
"ref": "say-hello",
|
||||
"sha": "3dca65fa3e8d4b3da3f3d056c59aee1c50f41390",
|
||||
"repo": {
|
||||
"id": 526,
|
||||
"url": "https://api.github.com/repos/github/hello-world",
|
||||
"name": "hello-world"
|
||||
}
|
||||
},
|
||||
"base": {
|
||||
"ref": "master",
|
||||
"sha": "e7fdf7640066d71ad16a86fbcbb9c6a10a18af4f",
|
||||
"repo": {
|
||||
"id": 526,
|
||||
"url": "https://api.github.com/repos/github/hello-world",
|
||||
"name": "hello-world"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
169
server/events/vcs/testdata/github-commit-check-suites-completed.json
vendored
Normal file
169
server/events/vcs/testdata/github-commit-check-suites-completed.json
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
{
|
||||
"total_count": 1,
|
||||
"check_suites": [
|
||||
{
|
||||
"id": 1234567890,
|
||||
"node_id": "CS_kwDOHE7PYM8AAAAB2iIZfQ",
|
||||
"head_branch": "atlantis-patch-2",
|
||||
"head_sha": "4273e07c528292222f119a040079093bf1f11232",
|
||||
"status": "completed",
|
||||
"conclusion": null,
|
||||
"url": "https://api.github.com/repos/octocat/Hello-World/check-suites/1234567890",
|
||||
"before": "0000000000000000000000000000000000000000",
|
||||
"after": "4273e07c528292222f119a040079093bf1f11232",
|
||||
"pull_requests": [
|
||||
{
|
||||
"url": "https://api.github.com/repos/octocat/Hello-World/pulls/1",
|
||||
"id": 1035065545,
|
||||
"number": 1,
|
||||
"head": {
|
||||
"ref": "atlantis-patch-2",
|
||||
"sha": "4273e07c528292222f119a040079093bf1f11232",
|
||||
"repo": {
|
||||
"id": 474926944,
|
||||
"url": "https://api.github.com/repos/octocat/Hello-World",
|
||||
"name": "Hello-World"
|
||||
}
|
||||
},
|
||||
"base": {
|
||||
"ref": "main",
|
||||
"sha": "6f5744874b33ceb6a5c91edc91085991dbd1f61a",
|
||||
"repo": {
|
||||
"id": 474926944,
|
||||
"url": "https://api.github.com/repos/octocat/Hello-World",
|
||||
"name": "Hello-World"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"app": {
|
||||
"id": 184783,
|
||||
"slug": "atlantis",
|
||||
"node_id": "A_kwHOBbMkBs4AAtHP",
|
||||
"owner": {
|
||||
"login": "octocat",
|
||||
"id": 95626246,
|
||||
"node_id": "O_kgDOBbMkBg",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95626246?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/octocat",
|
||||
"html_url": "https://github.com/octocat",
|
||||
"followers_url": "https://api.github.com/users/octocat/followers",
|
||||
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/octocat/orgs",
|
||||
"repos_url": "https://api.github.com/users/octocat/repos",
|
||||
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/octocat/received_events",
|
||||
"type": "Organization",
|
||||
"site_admin": false
|
||||
},
|
||||
"name": "atlantis",
|
||||
"description": "",
|
||||
"external_url": "https://atlantis.localhost/",
|
||||
"html_url": "https://github.com/apps/atlantis",
|
||||
"created_at": "2022-03-29T08:51:26Z",
|
||||
"updated_at": "2022-07-01T11:35:37Z",
|
||||
"permissions": {
|
||||
"administration": "read",
|
||||
"checks": "write",
|
||||
"contents": "write",
|
||||
"issues": "write",
|
||||
"metadata": "read",
|
||||
"pull_requests": "write",
|
||||
"statuses": "write"
|
||||
},
|
||||
"events": []
|
||||
},
|
||||
"created_at": "2022-08-24T07:06:21Z",
|
||||
"updated_at": "2022-08-24T07:06:21Z",
|
||||
"rerequestable": true,
|
||||
"runs_rerequestable": true,
|
||||
"latest_check_runs_count": 0,
|
||||
"check_runs_url": "https://api.github.com/repos/octocat/Hello-World/check-suites/1234567890/check-runs",
|
||||
"head_commit": {
|
||||
"id": "4273e07c528292222f119a040079093bf1f11232",
|
||||
"tree_id": "56781332464aabdfae51b7f37f72ffc6ce8ce54e",
|
||||
"message": "test atlantis",
|
||||
"timestamp": "2022-08-24T07:06:21Z",
|
||||
"author": {
|
||||
"name": "octocat",
|
||||
"email": "octocat@noreply.github.com"
|
||||
},
|
||||
"committer": {
|
||||
"name": "GitHub",
|
||||
"email": "noreply@github.com"
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"id": 474926944,
|
||||
"node_id": "R_kgDOHE7PYA",
|
||||
"name": "Hello-World",
|
||||
"full_name": "octocat/Hello-World",
|
||||
"private": true,
|
||||
"owner": {
|
||||
"login": "octocat",
|
||||
"id": 95626246,
|
||||
"node_id": "O_kgDOBbMkBg",
|
||||
"avatar_url": "https://avatars.githubusercontent.com/u/95626246?v=4",
|
||||
"gravatar_id": "",
|
||||
"url": "https://api.github.com/users/octocat",
|
||||
"html_url": "https://github.com/octocat",
|
||||
"followers_url": "https://api.github.com/users/octocat/followers",
|
||||
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
|
||||
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
|
||||
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
|
||||
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
|
||||
"organizations_url": "https://api.github.com/users/octocat/orgs",
|
||||
"repos_url": "https://api.github.com/users/octocat/repos",
|
||||
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
|
||||
"received_events_url": "https://api.github.com/users/octocat/received_events",
|
||||
"type": "Organization",
|
||||
"site_admin": false
|
||||
},
|
||||
"html_url": "https://github.com/octocat/Hello-World",
|
||||
"description": null,
|
||||
"fork": false,
|
||||
"url": "https://api.github.com/repos/octocat/Hello-World",
|
||||
"forks_url": "https://api.github.com/repos/octocat/Hello-World/forks",
|
||||
"keys_url": "https://api.github.com/repos/octocat/Hello-World/keys{/key_id}",
|
||||
"collaborators_url": "https://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}",
|
||||
"teams_url": "https://api.github.com/repos/octocat/Hello-World/teams",
|
||||
"hooks_url": "https://api.github.com/repos/octocat/Hello-World/hooks",
|
||||
"issue_events_url": "https://api.github.com/repos/octocat/Hello-World/issues/events{/number}",
|
||||
"events_url": "https://api.github.com/repos/octocat/Hello-World/events",
|
||||
"assignees_url": "https://api.github.com/repos/octocat/Hello-World/assignees{/user}",
|
||||
"branches_url": "https://api.github.com/repos/octocat/Hello-World/branches{/branch}",
|
||||
"tags_url": "https://api.github.com/repos/octocat/Hello-World/tags",
|
||||
"blobs_url": "https://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}",
|
||||
"git_tags_url": "https://api.github.com/repos/octocat/Hello-World/git/tags{/sha}",
|
||||
"git_refs_url": "https://api.github.com/repos/octocat/Hello-World/git/refs{/sha}",
|
||||
"trees_url": "https://api.github.com/repos/octocat/Hello-World/git/trees{/sha}",
|
||||
"statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/{sha}",
|
||||
"languages_url": "https://api.github.com/repos/octocat/Hello-World/languages",
|
||||
"stargazers_url": "https://api.github.com/repos/octocat/Hello-World/stargazers",
|
||||
"contributors_url": "https://api.github.com/repos/octocat/Hello-World/contributors",
|
||||
"subscribers_url": "https://api.github.com/repos/octocat/Hello-World/subscribers",
|
||||
"subscription_url": "https://api.github.com/repos/octocat/Hello-World/subscription",
|
||||
"commits_url": "https://api.github.com/repos/octocat/Hello-World/commits{/sha}",
|
||||
"git_commits_url": "https://api.github.com/repos/octocat/Hello-World/git/commits{/sha}",
|
||||
"comments_url": "https://api.github.com/repos/octocat/Hello-World/comments{/number}",
|
||||
"issue_comment_url": "https://api.github.com/repos/octocat/Hello-World/issues/comments{/number}",
|
||||
"contents_url": "https://api.github.com/repos/octocat/Hello-World/contents/{+path}",
|
||||
"compare_url": "https://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}",
|
||||
"merges_url": "https://api.github.com/repos/octocat/Hello-World/merges",
|
||||
"archive_url": "https://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}",
|
||||
"downloads_url": "https://api.github.com/repos/octocat/Hello-World/downloads",
|
||||
"issues_url": "https://api.github.com/repos/octocat/Hello-World/issues{/number}",
|
||||
"pulls_url": "https://api.github.com/repos/octocat/Hello-World/pulls{/number}",
|
||||
"milestones_url": "https://api.github.com/repos/octocat/Hello-World/milestones{/number}",
|
||||
"notifications_url": "https://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}",
|
||||
"labels_url": "https://api.github.com/repos/octocat/Hello-World/labels{/name}",
|
||||
"releases_url": "https://api.github.com/repos/octocat/Hello-World/releases{/id}",
|
||||
"deployments_url": "https://api.github.com/repos/octocat/Hello-World/deployments"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user