{"action":"created","comment":{"url":"https://api.github.com/repos/rancher/rancher/pulls/comments/188371061","pull_request_review_id":120336181,"id":188371061,"diff_hunk":"@@ -0,0 +1,550 @@\n+package azuread\n+\n+import (\n+\t\"bytes\"\n+\t\"encoding/json\"\n+\t\"fmt\"\n+\t\"io\"\n+\t\"io/ioutil\"\n+\t\"net/http\"\n+\t\"strings\"\n+\n+\t\"github.com/rancher/norman/httperror\"\n+\t\"github.com/rancher/types/apis/management.cattle.io/v3\"\n+\t\"github.com/rancher/types/apis/management.cattle.io/v3public\"\n+\t\"github.com/sirupsen/logrus\"\n+)\n+\n+const (\n+\tAzureURIChina          = \".chinacloudapi.cn\"\n+\tAzureURIGerman         = \".microsoftonline.de\"\n+\tAzureURIGlobal         = \".windows.net\"\n+\tAuthorityChina         = \"https://login\" + AzureURIChina + \"/common/oauth2/token\"\n+\tAuthorityGerman        = \"https://login\" + AzureURIGerman + \"/common/oauth2/token\"\n+\tAuthorityGlobal        = \"https://login\" + AzureURIGlobal + \"/common/oauth2/token\"\n+\tGraphAPIEndpointChina  = \"https://graph\" + AzureURIChina\n+\tGraphAPIEndpointGerman = \"https://graph\" + AzureURIGerman\n+\tGraphAPIEndpointGlobal = \"https://graph\" + AzureURIGlobal\n+\tGraphAPIVersion        = \"?api-version=1.6\"\n+\tBodyConstruct          = \"scope=openid&grant_type=password&resource=https%3A%2F%2F\"\n+)\n+\n+type Client struct {\n+\thttpClient *http.Client\n+}\n+\n+func (ac *Client) uriEndpointConstruction(config *v3.AzureADConfig) (string, string, string, error) {\n+\tvar authority, graphEndpoint, bodyconstruct string\n+\tdomain := config.Domain\n+\tif strings.Contains(domain, \"partner.onmschina.cn\") {\n+\t\tauthority = AuthorityChina\n+\t\tgraphEndpoint = GraphAPIEndpointChina\n+\t\tbodyconstruct = BodyConstruct + \"graph\" + AzureURIChina\n+\t} else if strings.Contains(domain, \"onmicrosoft.de\") {\n+\t\tauthority = AuthorityGerman\n+\t\tgraphEndpoint = GraphAPIEndpointGerman\n+\t\tbodyconstruct = BodyConstruct + \"graph\" + AzureURIGerman\n+\t} else if strings.Contains(domain, \"onmicrosoft.com\") {\n+\t\tauthority = AuthorityGlobal\n+\t\tgraphEndpoint = GraphAPIEndpointGlobal\n+\t\tbodyconstruct = BodyConstruct + \"graph\" + AzureURIGlobal\n+\t} else {\n+\t\treturn \"\", \"\", \"\", fmt.Errorf(\"Wrong Azure Domain %v is provided\", domain)\n+\t}\n+\treturn authority, graphEndpoint, bodyconstruct, nil\n+}\n+\n+func (ac *Client) getAccessToken(adCredential *v3public.BasicLogin, config *v3.AzureADConfig) (string, string, error) {\n+\tif ac.isConfigured(config) == false {\n+\t\tlogrus.Errorf(\"Azure Client is not configured\")\n+\t\treturn \"\", \"\", httperror.NewAPIError(httperror.ServerError, \"Azure Client is not configured\")\n+\t}\n+\n+\tusername := adCredential.Username\n+\tpassword := adCredential.Password\n+\tif username == \"\" || password == \"\" {\n+\t\treturn \"\", \"\", httperror.NewAPIError(httperror.MissingRequired, \"username or password not provided\")\n+\t}\n+\n+\tdomain := config.Domain\n+\tendsWith := strings.HasSuffix(\"username\", \"@\"+domain)\n+\tif domain != \"\" && endsWith == false {\n+\t\tusername = username + \"%40\" + domain //\"@\" is encoded to \"%40\"\n+\t}\n+\n+\tauthority, graphEndpoint, bodyconstruct, err := ac.uriEndpointConstruction(config)\n+\tif err != nil {\n+\t\tlogrus.Errorf(\"Wrong Azure Domain %v is provided\", domain)\n+\t\treturn \"\", \"\", fmt.Errorf(\"Wrong Azure Domain %v is provided\", domain)\n+\t}\n+\tbody := bytes.Buffer{}\n+\tbody.WriteString(bodyconstruct)\n+\tbody.WriteString(\"&client_id=\")\n+\tbody.WriteString(config.ClientID)\n+\tbody.WriteString(\"&client_secret=\")\n+\tbody.WriteString(config.ClientSecret) //clientsecret is a required field for China AzureAD\n+\tbody.WriteString(\"&username=\")\n+\tbody.WriteString(username)\n+\tbody.WriteString(\"&password=\")\n+\tbody.WriteString(password)\n+\n+\turl, err := ac.getURL(authority, graphEndpoint, \"TOKEN\", config, \"\")\n+\tif err != nil {\n+\t\tlogrus.Errorf(\"AzureAD GET url %v received error from Azure, err: %v\", url, err)\n+\t\treturn \"\", \"\", err\n+\t}\n+\n+\tresp, err := ac.postToAzureAD(url, body.String())\n+\tif err != nil {\n+\t\tlogrus.Errorf(\"AzureAD getAccessToken: GET url %v received error from Azure, err: %v\", url, err)\n+\t\treturn \"\", \"\", err\n+\t}\n+\tdefer resp.Body.Close()\n+\n+\t// Decode the response\n+\tvar respMap map[string]interface{}\n+\tb, err := ioutil.ReadAll(resp.Body)\n+\tif err != nil {\n+\t\tlogrus.Errorf(\"AzureAD getAccessToken: received error reading response body, err: %v\", err)\n+\t\treturn \"\", \"\", err\n+\t}\n+\n+\tif err := json.Unmarshal(b, &respMap); err != nil {\n+\t\tlogrus.Errorf(\"AzureAD getAccessToken: received error unmarshalling response body, err: %v\", err)\n+\t\treturn \"\", \"\", err\n+\t}\n+\n+\tif respMap[\"error\"] != nil {\n+\t\tdesc := respMap[\"error_description\"]\n+\t\tlogrus.Errorf(\"Received Error from AzureAD %v, description from AzureAD %v\", respMap[\"error\"], desc)\n+\t\treturn \"\", \"\", fmt.Errorf(\"Received Error from AzureAD %v, description from AzureAD %v\", respMap[\"error\"], desc)\n+\t}\n+\n+\taccessToken, ok := respMap[\"access_token\"].(string)\n+\tif !ok {\n+\t\treturn \"\", \"\", fmt.Errorf(\"Received Error reading accessToken from response %v\", respMap)\n+\t}\n+\n+\trefreshToken, ok := respMap[\"refresh_token\"].(string)\n+\tif !ok {\n+\t\treturn \"\", \"\", fmt.Errorf(\"Received Error reading refreshToken from response %v\", respMap)\n+\t}\n+\treturn accessToken, refreshToken, nil\n+}\n+\n+func (ac *Client) postToAzureAD(url string, body string) (*http.Response, error) {\n+\treq, err := http.NewRequest(\"POST\", url, strings.NewReader(body))\n+\tif err != nil {\n+\t\tlogrus.Error(err)\n+\t}\n+\treq.Header.Add(\"Accept\", \"application/json\")\n+\treq.Header.Add(\"Content-Type\", \"application/x-www-form-urlencoded\")\n+\n+\tresp, err := ac.httpClient.Do(req)\n+\tif err != nil {\n+\t\tlogrus.Errorf(\"Received error from azure: %v\", err)\n+\t\treturn resp, err\n+\t}\n+\t// Check the status code\n+\tswitch resp.StatusCode {\n+\tcase 200:\n+\tcase 201:\n+\tdefault:\n+\t\tvar body bytes.Buffer\n+\t\tio.Copy(&body, resp.Body)\n+\t\treturn resp, fmt.Errorf(\"Request failed, got status code: %d. Response: %s\",\n+\t\t\tresp.StatusCode, body.Bytes())\n+\t}\n+\treturn resp, nil\n+}\n+\n+func (ac *Client) getUser(azureAccessToken string, config *v3.AzureADConfig) (Account, error) {\n+\tif azureAccessToken == \"\" {\n+\t\treturn Account{}, httperror.NewAPIError(httperror.ServerError, \"No Azure Access token\")\n+\t}\n+\n+\tauthority, graphEndpoint, _, err := ac.uriEndpointConstruction(config)\n+\tif err != nil {\n+\t\tlogrus.Errorf(\"Wrong Azure Domain %v is provided\", config.Domain)\n+\t\treturn Account{}, fmt.Errorf(\"Wrong Azure Domain %v is provided\", config.Domain)\n+\t}\n+\turl, err := ac.getURL(authority, graphEndpoint, \"USER\", config, \"\")\n+\n+\tresp, newAccessToken, err := ac.getFromAzureAD(azureAccessToken, config, url)\n+\tif err != nil {\n+\t\tlogrus.Errorf(\"AzureAD getAzureADUser: GET url %v received error from Azure, err: %v\", url, err)\n+\t\treturn Account{}, err\n+\t}\n+\tif newAccessToken != \"\" {\n+\t\tresp, _, err = ac.getFromAzureAD(azureAccessToken, config, url)\n+\t\tif err != nil {\n+\t\t\tlogrus.Errorf(\"AzureAD getAccessToken: GET url %v received error from azure, err: %v\", url, err)\n+\t\t\treturn Account{}, err\n+\t\t}\n+\t}\n+\tdefer resp.Body.Close()\n+\tvar azureADAcct Account\n+\n+\tb, err := ioutil.ReadAll(resp.Body)\n+\tif err != nil {\n+\t\tlogrus.Errorf(\"AzureAD getAzureADUser: error reading response, err: %v\", err)\n+\t\treturn Account{}, err\n+\t}\n+\n+\tif err := json.Unmarshal(b, &azureADAcct); err != nil {\n+\t\tlogrus.Errorf(\"AzureAD getAzureADUser: error unmarshalling response, err: %v\", err)\n+\t\treturn Account{}, err\n+\t}\n+\n+\treturn azureADAcct, nil\n+}\n+\n+func (ac *Client) getGroup(azureAccessToken string, config *v3.AzureADConfig) ([]Account, error) {","path":"pkg/auth/providers/azuread/azuread_client.go","position":202,"original_position":202,"commit_id":"1b9b5446d8ab883060fba56743cfe50cf485125d","original_commit_id":"1b9b5446d8ab883060fba56743cfe50cf485125d","user":{"login":"cjellick","id":2473240,"avatar_url":"https://avatars1.githubusercontent.com/u/2473240?v=4","gravatar_id":"","url":"https://api.github.com/users/cjellick","html_url":"https://github.com/cjellick","followers_url":"https://api.github.com/users/cjellick/followers","following_url":"https://api.github.com/users/cjellick/following{/other_user}","gists_url":"https://api.github.com/users/cjellick/gists{/gist_id}","starred_url":"https://api.github.com/users/cjellick/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/cjellick/subscriptions","organizations_url":"https://api.github.com/users/cjellick/orgs","repos_url":"https://api.github.com/users/cjellick/repos","events_url":"https://api.github.com/users/cjellick/events{/privacy}","received_events_url":"https://api.github.com/users/cjellick/received_events","type":"User","site_admin":false},"body":"Nit: this function should be called getGroups (plural) since it returns more than one","created_at":"2018-05-15T17:27:55Z","updated_at":"2018-05-15T17:27:55Z","html_url":"https://github.com/rancher/rancher/pull/13386#discussion_r188371061","pull_request_url":"https://api.github.com/repos/rancher/rancher/pulls/13386","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/rancher/rancher/pulls/comments/188371061"},"html":{"href":"https://github.com/rancher/rancher/pull/13386#discussion_r188371061"},"pull_request":{"href":"https://api.github.com/repos/rancher/rancher/pulls/13386"}}},"pull_request":{"url":"https://api.github.com/repos/rancher/rancher/pulls/13386","id":186984259,"html_url":"https://github.com/rancher/rancher/pull/13386","diff_url":"https://github.com/rancher/rancher/pull/13386.diff","patch_url":"https://github.com/rancher/rancher/pull/13386.patch","issue_url":"https://api.github.com/repos/rancher/rancher/issues/13386","number":13386,"state":"open","locked":false,"title":"Azuread Support ","user":{"login":"carolynhu","id":29208297,"avatar_url":"https://avatars3.githubusercontent.com/u/29208297?v=4","gravatar_id":"","url":"https://api.github.com/users/carolynhu","html_url":"https://github.com/carolynhu","followers_url":"https://api.github.com/users/carolynhu/followers","following_url":"https://api.github.com/users/carolynhu/following{/other_user}","gists_url":"https://api.github.com/users/carolynhu/gists{/gist_id}","starred_url":"https://api.github.com/users/carolynhu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/carolynhu/subscriptions","organizations_url":"https://api.github.com/users/carolynhu/orgs","repos_url":"https://api.github.com/users/carolynhu/repos","events_url":"https://api.github.com/users/carolynhu/events{/privacy}","received_events_url":"https://api.github.com/users/carolynhu/received_events","type":"User","site_admin":false},"body":"","created_at":"2018-05-09T17:08:55Z","updated_at":"2018-05-15T17:27:55Z","closed_at":null,"merged_at":null,"merge_commit_sha":"ac4ba62afe712155ca765470f6bec0a3d4124a21","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/rancher/rancher/pulls/13386/commits","review_comments_url":"https://api.github.com/repos/rancher/rancher/pulls/13386/comments","review_comment_url":"https://api.github.com/repos/rancher/rancher/pulls/comments{/number}","comments_url":"https://api.github.com/repos/rancher/rancher/issues/13386/comments","statuses_url":"https://api.github.com/repos/rancher/rancher/statuses/1b9b5446d8ab883060fba56743cfe50cf485125d","head":{"label":"carolynhu:azuread","ref":"azuread","sha":"1b9b5446d8ab883060fba56743cfe50cf485125d","user":{"login":"carolynhu","id":29208297,"avatar_url":"https://avatars3.githubusercontent.com/u/29208297?v=4","gravatar_id":"","url":"https://api.github.com/users/carolynhu","html_url":"https://github.com/carolynhu","followers_url":"https://api.github.com/users/carolynhu/followers","following_url":"https://api.github.com/users/carolynhu/following{/other_user}","gists_url":"https://api.github.com/users/carolynhu/gists{/gist_id}","starred_url":"https://api.github.com/users/carolynhu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/carolynhu/subscriptions","organizations_url":"https://api.github.com/users/carolynhu/orgs","repos_url":"https://api.github.com/users/carolynhu/repos","events_url":"https://api.github.com/users/carolynhu/events{/privacy}","received_events_url":"https://api.github.com/users/carolynhu/received_events","type":"User","site_admin":false},"repo":{"id":95154486,"name":"rancher","full_name":"carolynhu/rancher","owner":{"login":"carolynhu","id":29208297,"avatar_url":"https://avatars3.githubusercontent.com/u/29208297?v=4","gravatar_id":"","url":"https://api.github.com/users/carolynhu","html_url":"https://github.com/carolynhu","followers_url":"https://api.github.com/users/carolynhu/followers","following_url":"https://api.github.com/users/carolynhu/following{/other_user}","gists_url":"https://api.github.com/users/carolynhu/gists{/gist_id}","starred_url":"https://api.github.com/users/carolynhu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/carolynhu/subscriptions","organizations_url":"https://api.github.com/users/carolynhu/orgs","repos_url":"https://api.github.com/users/carolynhu/repos","events_url":"https://api.github.com/users/carolynhu/events{/privacy}","received_events_url":"https://api.github.com/users/carolynhu/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/carolynhu/rancher","description":"Platform for operating Docker in production","fork":true,"url":"https://api.github.com/repos/carolynhu/rancher","forks_url":"https://api.github.com/repos/carolynhu/rancher/forks","keys_url":"https://api.github.com/repos/carolynhu/rancher/keys{/key_id}","collaborators_url":"https://api.github.com/repos/carolynhu/rancher/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/carolynhu/rancher/teams","hooks_url":"https://api.github.com/repos/carolynhu/rancher/hooks","issue_events_url":"https://api.github.com/repos/carolynhu/rancher/issues/events{/number}","events_url":"https://api.github.com/repos/carolynhu/rancher/events","assignees_url":"https://api.github.com/repos/carolynhu/rancher/assignees{/user}","branches_url":"https://api.github.com/repos/carolynhu/rancher/branches{/branch}","tags_url":"https://api.github.com/repos/carolynhu/rancher/tags","blobs_url":"https://api.github.com/repos/carolynhu/rancher/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/carolynhu/rancher/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/carolynhu/rancher/git/refs{/sha}","trees_url":"https://api.github.com/repos/carolynhu/rancher/git/trees{/sha}","statuses_url":"https://api.github.com/repos/carolynhu/rancher/statuses/{sha}","languages_url":"https://api.github.com/repos/carolynhu/rancher/languages","stargazers_url":"https://api.github.com/repos/carolynhu/rancher/stargazers","contributors_url":"https://api.github.com/repos/carolynhu/rancher/contributors","subscribers_url":"https://api.github.com/repos/carolynhu/rancher/subscribers","subscription_url":"https://api.github.com/repos/carolynhu/rancher/subscription","commits_url":"https://api.github.com/repos/carolynhu/rancher/commits{/sha}","git_commits_url":"https://api.github.com/repos/carolynhu/rancher/git/commits{/sha}","comments_url":"https://api.github.com/repos/carolynhu/rancher/comments{/number}","issue_comment_url":"https://api.github.com/repos/carolynhu/rancher/issues/comments{/number}","contents_url":"https://api.github.com/repos/carolynhu/rancher/contents/{+path}","compare_url":"https://api.github.com/repos/carolynhu/rancher/compare/{base}...{head}","merges_url":"https://api.github.com/repos/carolynhu/rancher/merges","archive_url":"https://api.github.com/repos/carolynhu/rancher/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/carolynhu/rancher/downloads","issues_url":"https://api.github.com/repos/carolynhu/rancher/issues{/number}","pulls_url":"https://api.github.com/repos/carolynhu/rancher/pulls{/number}","milestones_url":"https://api.github.com/repos/carolynhu/rancher/milestones{/number}","notifications_url":"https://api.github.com/repos/carolynhu/rancher/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/carolynhu/rancher/labels{/name}","releases_url":"https://api.github.com/repos/carolynhu/rancher/releases{/id}","deployments_url":"https://api.github.com/repos/carolynhu/rancher/deployments","created_at":"2017-06-22T20:37:22Z","updated_at":"2017-06-22T20:37:27Z","pushed_at":"2018-05-15T03:21:06Z","git_url":"git://github.com/carolynhu/rancher.git","ssh_url":"git@github.com:carolynhu/rancher.git","clone_url":"https://github.com/carolynhu/rancher.git","svn_url":"https://github.com/carolynhu/rancher","homepage":"http://rancher.com","size":32082,"stargazers_count":0,"watchers_count":0,"language":"Shell","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"other","name":"Other","spdx_id":null,"url":null},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"rancher:master","ref":"master","sha":"31613d627fda161417cc5dfead752f5d9ee11358","user":{"login":"rancher","id":9343010,"avatar_url":"https://avatars3.githubusercontent.com/u/9343010?v=4","gravatar_id":"","url":"https://api.github.com/users/rancher","html_url":"https://github.com/rancher","followers_url":"https://api.github.com/users/rancher/followers","following_url":"https://api.github.com/users/rancher/following{/other_user}","gists_url":"https://api.github.com/users/rancher/gists{/gist_id}","starred_url":"https://api.github.com/users/rancher/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rancher/subscriptions","organizations_url":"https://api.github.com/users/rancher/orgs","repos_url":"https://api.github.com/users/rancher/repos","events_url":"https://api.github.com/users/rancher/events{/privacy}","received_events_url":"https://api.github.com/users/rancher/received_events","type":"Organization","site_admin":false},"repo":{"id":26337322,"name":"rancher","full_name":"rancher/rancher","owner":{"login":"rancher","id":9343010,"avatar_url":"https://avatars3.githubusercontent.com/u/9343010?v=4","gravatar_id":"","url":"https://api.github.com/users/rancher","html_url":"https://github.com/rancher","followers_url":"https://api.github.com/users/rancher/followers","following_url":"https://api.github.com/users/rancher/following{/other_user}","gists_url":"https://api.github.com/users/rancher/gists{/gist_id}","starred_url":"https://api.github.com/users/rancher/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/rancher/subscriptions","organizations_url":"https://api.github.com/users/rancher/orgs","repos_url":"https://api.github.com/users/rancher/repos","events_url":"https://api.github.com/users/rancher/events{/privacy}","received_events_url":"https://api.github.com/users/rancher/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/rancher/rancher","description":"Complete container management platform","fork":false,"url":"https://api.github.com/repos/rancher/rancher","forks_url":"https://api.github.com/repos/rancher/rancher/forks","keys_url":"https://api.github.com/repos/rancher/rancher/keys{/key_id}","collaborators_url":"https://api.github.com/repos/rancher/rancher/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/rancher/rancher/teams","hooks_url":"https://api.github.com/repos/rancher/rancher/hooks","issue_events_url":"https://api.github.com/repos/rancher/rancher/issues/events{/number}","events_url":"https://api.github.com/repos/rancher/rancher/events","assignees_url":"https://api.github.com/repos/rancher/rancher/assignees{/user}","branches_url":"https://api.github.com/repos/rancher/rancher/branches{/branch}","tags_url":"https://api.github.com/repos/rancher/rancher/tags","blobs_url":"https://api.github.com/repos/rancher/rancher/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/rancher/rancher/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/rancher/rancher/git/refs{/sha}","trees_url":"https://api.github.com/repos/rancher/rancher/git/trees{/sha}","statuses_url":"https://api.github.com/repos/rancher/rancher/statuses/{sha}","languages_url":"https://api.github.com/repos/rancher/rancher/languages","stargazers_url":"https://api.github.com/repos/rancher/rancher/stargazers","contributors_url":"https://api.github.com/repos/rancher/rancher/contributors","subscribers_url":"https://api.github.com/repos/rancher/rancher/subscribers","subscription_url":"https://api.github.com/repos/rancher/rancher/subscription","commits_url":"https://api.github.com/repos/rancher/rancher/commits{/sha}","git_commits_url":"https://api.github.com/repos/rancher/rancher/git/commits{/sha}","comments_url":"https://api.github.com/repos/rancher/rancher/comments{/number}","issue_comment_url":"https://api.github.com/repos/rancher/rancher/issues/comments{/number}","contents_url":"https://api.github.com/repos/rancher/rancher/contents/{+path}","compare_url":"https://api.github.com/repos/rancher/rancher/compare/{base}...{head}","merges_url":"https://api.github.com/repos/rancher/rancher/merges","archive_url":"https://api.github.com/repos/rancher/rancher/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/rancher/rancher/downloads","issues_url":"https://api.github.com/repos/rancher/rancher/issues{/number}","pulls_url":"https://api.github.com/repos/rancher/rancher/pulls{/number}","milestones_url":"https://api.github.com/repos/rancher/rancher/milestones{/number}","notifications_url":"https://api.github.com/repos/rancher/rancher/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/rancher/rancher/labels{/name}","releases_url":"https://api.github.com/repos/rancher/rancher/releases{/id}","deployments_url":"https://api.github.com/repos/rancher/rancher/deployments","created_at":"2014-11-07T20:49:31Z","updated_at":"2018-05-15T16:10:12Z","pushed_at":"2018-05-15T16:46:47Z","git_url":"git://github.com/rancher/rancher.git","ssh_url":"git@github.com:rancher/rancher.git","clone_url":"https://github.com/rancher/rancher.git","svn_url":"https://github.com/rancher/rancher","homepage":"http://rancher.com","size":32604,"stargazers_count":8498,"watchers_count":8498,"language":"Go","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":845,"mirror_url":null,"archived":false,"open_issues_count":2007,"license":{"key":"apache-2.0","name":"Apache License 2.0","spdx_id":"Apache-2.0","url":"https://api.github.com/licenses/apache-2.0"},"forks":845,"open_issues":2007,"watchers":8498,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/rancher/rancher/pulls/13386"},"html":{"href":"https://github.com/rancher/rancher/pull/13386"},"issue":{"href":"https://api.github.com/repos/rancher/rancher/issues/13386"},"comments":{"href":"https://api.github.com/repos/rancher/rancher/issues/13386/comments"},"review_comments":{"href":"https://api.github.com/repos/rancher/rancher/pulls/13386/comments"},"review_comment":{"href":"https://api.github.com/repos/rancher/rancher/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/rancher/rancher/pulls/13386/commits"},"statuses":{"href":"https://api.github.com/repos/rancher/rancher/statuses/1b9b5446d8ab883060fba56743cfe50cf485125d"}},"author_association":"NONE"}}
{"actor":{"display_login":"cjellick"}}