diff --git a/github/AuthorizationOrganization.py b/github/AuthorizationOrganization.py new file mode 100644 index 0000000000..1b35c867c6 --- /dev/null +++ b/github/AuthorizationOrganization.py @@ -0,0 +1,126 @@ +# -*- coding: utf-8 -*- + +############################ Copyrights and license ############################ +# # +# Copyright 2020 Alexandre Delisle # +# # +# This file is part of PyGithub. # +# http://pygithub.readthedocs.io/ # +# # +# PyGithub is free software: you can redistribute it and/or modify it under # +# the terms of the GNU Lesser General Public License as published by the Free # +# Software Foundation, either version 3 of the License, or (at your option) # +# any later version. # +# # +# PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY # +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # +# details. # +# # +# You should have received a copy of the GNU Lesser General Public License # +# along with PyGithub. If not, see . # +# # +################################################################################ + +import github.GithubObject + + +class AuthorizationOrganization(github.GithubObject.NonCompletableGithubObject): + """ + This class represents a credential id. + """ + + def __repr__(self): + return self.get__repr__( + { + "login": self.login, + "credential_id": self.credential_id, + "credential_type": self.credential_type, + "credential_authorized_at": self.credential_authorized_at, + "credential_accessed_at": self.credential_accessed_at, + "token_last_eight": self.token_last_eight, + "scopes": self.scopes, + } + ) + + @property + def login(self): + """ + :type: string + """ + return self._login.value + + @property + def credential_id(self): + """ + :type: string + """ + return self._credential_id.value + + @property + def credential_type(self): + """ + :type: string + """ + return self._credential_type.value + + @property + def credential_authorized_at(self): + """ + :type: string + """ + return self._credential_authorized_at.value + + @property + def credential_accessed_at(self): + """ + :type: string + """ + return self._credential_accessed_at.value + + @property + def token_last_eight(self): + """ + :type: string + """ + return self._token_last_eight.value + + @property + def scopes(self): + """ + :type: list + """ + return self._scopes.value + + def _initAttributes(self): + self._login = github.GithubObject.NotSet + self._credential_id = github.GithubObject.NotSet + self._credential_type = github.GithubObject.NotSet + self._credential_authorized_at = github.GithubObject.NotSet + self._credential_accessed_at = github.GithubObject.NotSet + self._token_last_eight = github.GithubObject.NotSet + self._scopes = github.GithubObject.NotSet + + def _useAttributes(self, attributes): + if "login" in attributes: # pragma no branch + self._login = self._makeStringAttribute(attributes["login"]) + if "credential_id" in attributes: # pragma no branch + self._credential_id = self._makeIntAttribute(attributes["credential_id"]) + if "credential_type" in attributes: # pragma no branch + self._credential_type = self._makeStringAttribute( + attributes["credential_type"] + ) + if "credential_authorized_at" in attributes: # pragma no branch + self._credential_authorized_at = self._makeDatetimeAttribute( + attributes["credential_authorized_at"] + ) + if "credential_accessed_at" in attributes: # pragma no branch + self._credential_accessed_at = self._makeDatetimeAttribute( + attributes["credential_accessed_at"] + ) + if "token_last_eight" in attributes: # pragma no branch + self._token_last_eight = self._makeStringAttribute( + attributes["token_last_eight"] + ) + if "scopes" in attributes: # pragma no branch + self._scopes = self._makeListOfStringsAttribute(attributes["scopes"]) diff --git a/github/AuthorizationOrganization.pyi b/github/AuthorizationOrganization.pyi new file mode 100644 index 0000000000..61a94cb1db --- /dev/null +++ b/github/AuthorizationOrganization.pyi @@ -0,0 +1,22 @@ +from typing import Dict +from typing import List +from datetime import datetime +from github.GithubObject import CompletableGithubObject + +class AuthorizationOrganization(CompletableGithubObject): + def _initAttributes(self) -> None: ... + def _useAttributes(self, attributes: Dict[str, str]) -> None: ... + @property + def login(self) -> str: ... + @property + def credential_id(self) -> int: ... + @property + def credential_type(self) -> str: ... + @property + def credential_authorized_at(self) -> datetime: ... + @property + def credential_accessed_at(self) -> datetime: ... + @property + def token_last_eight(self) -> str: ... + @property + def scopes(self) -> List[str]: ... diff --git a/github/Organization.py b/github/Organization.py index 9bb2003b6e..fc7efaa43f 100644 --- a/github/Organization.py +++ b/github/Organization.py @@ -43,6 +43,7 @@ import datetime +import github.AuthorizationOrganization import github.Event import github.GithubObject import github.NamedUser @@ -1156,6 +1157,33 @@ def get_migrations(self): headers={"Accept": Consts.mediaTypeMigrationPreview}, ) + def get_credential_authorizations(self): + """ + :calls: `GET /orgs/:org/credential-authorizations `_ + :rtype: list + """ + headers, data = self._requester.requestJsonAndCheck( + "GET", self.url + "/credential-authorizations" + ) + return [ + github.AuthorizationOrganization.AuthorizationOrganization( + self._requester, headers, x, completed=True + ) + for x in data + ] + + def remove_credential_authorization(self, credential_id): + """ + :calls: `DELETE /orgs/:org/credential-authorizations/:credential_id `_ + :param credential_id: int + :rtype: bool + """ + assert isinstance(credential_id, int), credential_id + status, headers, data = self._requester.requestJson( + "DELETE", self.url + "/credential-authorizations/" + str(credential_id) + ) + return status == 204 + def _initAttributes(self): self._default_repository_permission = github.GithubObject.NotSet self._has_organization_projects = github.GithubObject.NotSet diff --git a/github/Organization.pyi b/github/Organization.pyi index 06533e393d..d28ac6dde4 100644 --- a/github/Organization.pyi +++ b/github/Organization.pyi @@ -204,3 +204,7 @@ class Organization(CompletableGithubObject): def updated_at(self) -> datetime: ... @property def url(self) -> str: ... + def remove_credential_authorization( + self, + credential_id: Union[int, _NotSetType] = ..., + ) -> None: ... diff --git a/tests/Organization1655.py b/tests/Organization1655.py new file mode 100644 index 0000000000..f16436c054 --- /dev/null +++ b/tests/Organization1655.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- + +############################ Copyrights and license ############################ +# # +# Copyright 2020 Alexandre Delisle # +# # +# This file is part of PyGithub. # +# http://pygithub.readthedocs.io/ # +# # +# PyGithub is free software: you can redistribute it and/or modify it under # +# the terms of the GNU Lesser General Public License as published by the Free # +# Software Foundation, either version 3 of the License, or (at your option) # +# any later version. # +# # +# PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY # +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # +# details. # +# # +# You should have received a copy of the GNU Lesser General Public License # +# along with PyGithub. If not, see . # +# # +################################################################################ + +import datetime + +from . import Framework + + +class OrganizationAuthorization(Framework.TestCase): + subset = { + "login": "AlexandreODelisle", + "credential_id": 5077768, + "credential_type": "personal access token", + "token_last_eight": "14ab3430", + "scopes": ["repo"], + "credential_authorized_at": datetime.datetime.strptime( + "2020-09-23 00:38:34", "%Y-%m-%d %H:%M:%S" + ), # Will need to be updated if test re-ran ( delete ) + "credential_accessed_at": None, # Will need to be updated if test re-ran ( delete ) + } + + def setUp(self): + super().setUp() + self.org = self.g.get_organization("Learn-Think-Do") + + def testAttributes(self): + credentials_list = self.org.get_credential_authorizations() + print(credentials_list) + filtered_credentials_list = list( + filter( + lambda x: x.login == self.subset["login"] + and x.credential_id == self.subset["credential_id"], + credentials_list, + ) + ) + + AuthCred = filtered_credentials_list[0] + self.assertEqual(AuthCred.login, self.subset["login"]) + self.assertEqual(AuthCred.credential_type, self.subset["credential_type"]) + self.assertEqual(AuthCred.credential_id, self.subset["credential_id"]) + self.assertEqual(AuthCred.token_last_eight, self.subset["token_last_eight"]) + self.assertEqual(AuthCred.scopes, self.subset["scopes"]) + self.assertEqual( + AuthCred.credential_authorized_at, self.subset["credential_authorized_at"] + ) + self.assertEqual( + AuthCred.credential_accessed_at, self.subset["credential_accessed_at"] + ) + self.assertEqual( + repr(AuthCred), + 'AuthorizationOrganization(token_last_eight="14ab3430", scopes=[\'repo\'], login="AlexandreODelisle", credential_type="personal access token", credential_id=5077768, credential_authorized_at=2020-09-23 00:38:34, credential_accessed_at=None)' + "", + ) + + def testGetCredentialsAuth(self): + credentials_list = self.org.get_credential_authorizations() + if "credential_authorized_at" in self.subset.keys(): + self.subset.pop( + "credential_authorized_at" + ) # because _rawData return a Str for datetime + + self.assertTrue( + any([self.subset.items() <= x._rawData.items() for x in credentials_list]) + ) + + def testRemoveCredentialAuth(self): + credentials_list = self.org.get_credential_authorizations() + if "credential_authorized_at" in self.subset.keys(): + self.subset.pop( + "credential_authorized_at" + ) # because _rawData return a Str for datetime + + self.assertTrue( + any([self.subset.items() <= x._rawData.items() for x in credentials_list]) + ) + self.assertTrue( + self.org.remove_credential_authorization( + credential_id=self.subset["credential_id"] + ) + ) + credentials_list = self.org.get_credential_authorizations() + self.assertFalse( + any([self.subset.items() <= x._rawData.items() for x in credentials_list]) + ) diff --git a/tests/ReplayData/OrganizationAuthorization.setUp.txt b/tests/ReplayData/OrganizationAuthorization.setUp.txt new file mode 100644 index 0000000000..c02f07f2ef --- /dev/null +++ b/tests/ReplayData/OrganizationAuthorization.setUp.txt @@ -0,0 +1,11 @@ +https +GET +api.github.com +None +/orgs/Learn-Think-Do +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} +None +200 +[('Server', 'GitHub.com'), ('Date', 'Wed, 23 Sep 2020 00:41:21 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Transfer-Encoding', 'chunked'), ('Status', '200 OK'), ('Cache-Control', 'private, max-age=60, s-maxage=60'), ('Vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding, Accept, X-Requested-With'), ('ETag', 'W/"27936ca8d4ebf08ca87c7b75aaa2bd2250d4460d9d6ccbdd53802a291ed3b6e2"'), ('Last-Modified', 'Mon, 21 Sep 2020 17:04:51 GMT'), ('X-OAuth-Scopes', 'admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages'), ('X-Accepted-OAuth-Scopes', 'admin:org, read:org, repo, user, write:org'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4895'), ('X-RateLimit-Reset', '1600823195'), ('X-RateLimit-Used', '105'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '1; mode=block'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Content-Encoding', 'gzip'), ('X-GitHub-Request-Id', 'BF9C:43BD:4886279:AFE4D62:5F6A99B1')] +{"login":"Learn-Think-Do","id":71595780,"node_id":"MDEyOk9yZ2FuaXphdGlvbjcxNTk1Nzgw","url":"https://api.github.com/orgs/Learn-Think-Do","repos_url":"https://api.github.com/orgs/Learn-Think-Do/repos","events_url":"https://api.github.com/orgs/Learn-Think-Do/events","hooks_url":"https://api.github.com/orgs/Learn-Think-Do/hooks","issues_url":"https://api.github.com/orgs/Learn-Think-Do/issues","members_url":"https://api.github.com/orgs/Learn-Think-Do/members{/member}","public_members_url":"https://api.github.com/orgs/Learn-Think-Do/public_members{/member}","avatar_url":"https://avatars3.githubusercontent.com/u/71595780?v=4","description":null,"is_verified":false,"has_organization_projects":true,"has_repository_projects":true,"public_repos":0,"public_gists":0,"followers":0,"following":0,"html_url":"https://github.com/Learn-Think-Do","created_at":"2020-09-20T13:23:24Z","updated_at":"2020-09-21T17:04:51Z","type":"Organization","total_private_repos":0,"owned_private_repos":0,"private_gists":0,"disk_usage":0,"collaborators":0,"billing_email":"alexandredelisle@adelisle.com","default_repository_permission":"read","members_can_create_repositories":true,"two_factor_requirement_enabled":false,"members_can_create_pages":true,"plan":{"name":"enterprise","space":976562499,"private_repos":999999,"filled_seats":1,"seats":50}} + diff --git a/tests/ReplayData/OrganizationAuthorization.testAttributes.txt b/tests/ReplayData/OrganizationAuthorization.testAttributes.txt new file mode 100644 index 0000000000..a34a1d17be --- /dev/null +++ b/tests/ReplayData/OrganizationAuthorization.testAttributes.txt @@ -0,0 +1,11 @@ +https +GET +api.github.com +None +/orgs/Learn-Think-Do/credential-authorizations +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} +None +200 +[('Server', 'GitHub.com'), ('Date', 'Wed, 23 Sep 2020 00:41:20 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Transfer-Encoding', 'chunked'), ('Status', '200 OK'), ('Cache-Control', 'private, max-age=60, s-maxage=60'), ('Vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding, Accept, X-Requested-With'), ('ETag', 'W/"e8b28b0bc634bece926a24d96466711f277572a1fd1d927dec0b42353dcec2bc"'), ('X-OAuth-Scopes', 'admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages'), ('X-Accepted-OAuth-Scopes', 'read:org'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4898'), ('X-RateLimit-Reset', '1600823195'), ('X-RateLimit-Used', '102'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '1; mode=block'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Content-Encoding', 'gzip'), ('X-GitHub-Request-Id', 'BF96:371D:4BD0E9D:AE3764E:5F6A99B0')] +[{"login":"AlexandreODelisle","credential_id":5016098,"credential_type":"personal access token","credential_authorized_at":"2020-09-20T23:50:41Z","credential_accessed_at":"2020-09-20T23:52:12Z","token_last_eight":"a397af52","scopes":["admin:enterprise","admin:gpg_key","admin:org","admin:org_hook","admin:public_key","admin:repo_hook","delete:packages","delete_repo","gist","notifications","read:packages","repo","user","workflow","write:discussion","write:packages"]},{"login":"AlexandreODelisle","credential_id":5077768,"credential_type":"personal access token","credential_authorized_at":"2020-09-23T00:38:34Z","credential_accessed_at":null,"token_last_eight":"14ab3430","scopes":["repo"]}] + diff --git a/tests/ReplayData/OrganizationAuthorization.testGetCredentialsAuth.txt b/tests/ReplayData/OrganizationAuthorization.testGetCredentialsAuth.txt new file mode 100644 index 0000000000..8151229dfa --- /dev/null +++ b/tests/ReplayData/OrganizationAuthorization.testGetCredentialsAuth.txt @@ -0,0 +1,11 @@ +https +GET +api.github.com +None +/orgs/Learn-Think-Do/credential-authorizations +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} +None +200 +[('Server', 'GitHub.com'), ('Date', 'Wed, 23 Sep 2020 00:41:20 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Transfer-Encoding', 'chunked'), ('Status', '200 OK'), ('Cache-Control', 'private, max-age=60, s-maxage=60'), ('Vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding, Accept, X-Requested-With'), ('ETag', 'W/"e8b28b0bc634bece926a24d96466711f277572a1fd1d927dec0b42353dcec2bc"'), ('X-OAuth-Scopes', 'admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages'), ('X-Accepted-OAuth-Scopes', 'read:org'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4896'), ('X-RateLimit-Reset', '1600823195'), ('X-RateLimit-Used', '104'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '1; mode=block'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Content-Encoding', 'gzip'), ('X-GitHub-Request-Id', 'BF9A:3E2A:81E3D74:DFD78A6:5F6A99B0')] +[{"login":"AlexandreODelisle","credential_id":5016098,"credential_type":"personal access token","credential_authorized_at":"2020-09-20T23:50:41Z","credential_accessed_at":"2020-09-20T23:52:12Z","token_last_eight":"a397af52","scopes":["admin:enterprise","admin:gpg_key","admin:org","admin:org_hook","admin:public_key","admin:repo_hook","delete:packages","delete_repo","gist","notifications","read:packages","repo","user","workflow","write:discussion","write:packages"]},{"login":"AlexandreODelisle","credential_id":5077768,"credential_type":"personal access token","credential_authorized_at":"2020-09-23T00:38:34Z","credential_accessed_at":null,"token_last_eight":"14ab3430","scopes":["repo"]}] + diff --git a/tests/ReplayData/OrganizationAuthorization.testRemoveCredentialAuth.txt b/tests/ReplayData/OrganizationAuthorization.testRemoveCredentialAuth.txt new file mode 100644 index 0000000000..4972a61a48 --- /dev/null +++ b/tests/ReplayData/OrganizationAuthorization.testRemoveCredentialAuth.txt @@ -0,0 +1,33 @@ +https +GET +api.github.com +None +/orgs/Learn-Think-Do/credential-authorizations +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} +None +200 +[('Server', 'GitHub.com'), ('Date', 'Wed, 23 Sep 2020 00:41:21 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Transfer-Encoding', 'chunked'), ('Status', '200 OK'), ('Cache-Control', 'private, max-age=60, s-maxage=60'), ('Vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding, Accept, X-Requested-With'), ('ETag', 'W/"e8b28b0bc634bece926a24d96466711f277572a1fd1d927dec0b42353dcec2bc"'), ('X-OAuth-Scopes', 'admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages'), ('X-Accepted-OAuth-Scopes', 'read:org'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4894'), ('X-RateLimit-Reset', '1600823195'), ('X-RateLimit-Used', '106'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '1; mode=block'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Content-Encoding', 'gzip'), ('X-GitHub-Request-Id', 'BF9E:695F:49F18C3:A74DA1C:5F6A99B1')] +[{"login":"AlexandreODelisle","credential_id":5016098,"credential_type":"personal access token","credential_authorized_at":"2020-09-20T23:50:41Z","credential_accessed_at":"2020-09-20T23:52:12Z","token_last_eight":"a397af52","scopes":["admin:enterprise","admin:gpg_key","admin:org","admin:org_hook","admin:public_key","admin:repo_hook","delete:packages","delete_repo","gist","notifications","read:packages","repo","user","workflow","write:discussion","write:packages"]},{"login":"AlexandreODelisle","credential_id":5077768,"credential_type":"personal access token","credential_authorized_at":"2020-09-23T00:38:34Z","credential_accessed_at":null,"token_last_eight":"14ab3430","scopes":["repo"]}] + +https +DELETE +api.github.com +None +/orgs/Learn-Think-Do/credential-authorizations/5077768 +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} +None +204 +[('Server', 'GitHub.com'), ('Date', 'Wed, 23 Sep 2020 00:41:21 GMT'), ('Status', '204 No Content'), ('X-OAuth-Scopes', 'admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages'), ('X-Accepted-OAuth-Scopes', 'admin:org'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4893'), ('X-RateLimit-Reset', '1600823195'), ('X-RateLimit-Used', '107'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '1; mode=block'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Vary', 'Accept-Encoding, Accept, X-Requested-With'), ('X-GitHub-Request-Id', 'BFA0:7D31:2364D20:5E37F6A:5F6A99B1')] + + +https +GET +api.github.com +None +/orgs/Learn-Think-Do/credential-authorizations +{'Authorization': 'Basic login_and_password_removed', 'User-Agent': 'PyGithub/Python'} +None +200 +[('Server', 'GitHub.com'), ('Date', 'Wed, 23 Sep 2020 00:41:22 GMT'), ('Content-Type', 'application/json; charset=utf-8'), ('Transfer-Encoding', 'chunked'), ('Status', '200 OK'), ('Cache-Control', 'private, max-age=60, s-maxage=60'), ('Vary', 'Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding, Accept, X-Requested-With'), ('ETag', 'W/"b76c1fb7ba4cd5d44f31a985c256fa9ee2512b7d6b4936e93f01484e78ab8881"'), ('X-OAuth-Scopes', 'admin:enterprise, admin:gpg_key, admin:org, admin:org_hook, admin:public_key, admin:repo_hook, delete:packages, delete_repo, gist, notifications, read:packages, repo, user, workflow, write:discussion, write:packages'), ('X-Accepted-OAuth-Scopes', 'read:org'), ('X-GitHub-Media-Type', 'github.v3; format=json'), ('X-RateLimit-Limit', '5000'), ('X-RateLimit-Remaining', '4892'), ('X-RateLimit-Reset', '1600823195'), ('X-RateLimit-Used', '108'), ('Access-Control-Expose-Headers', 'ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, Deprecation, Sunset'), ('Access-Control-Allow-Origin', '*'), ('Strict-Transport-Security', 'max-age=31536000; includeSubdomains; preload'), ('X-Frame-Options', 'deny'), ('X-Content-Type-Options', 'nosniff'), ('X-XSS-Protection', '1; mode=block'), ('Referrer-Policy', 'origin-when-cross-origin, strict-origin-when-cross-origin'), ('Content-Security-Policy', "default-src 'none'"), ('Content-Encoding', 'gzip'), ('X-GitHub-Request-Id', 'BFA2:7853:89FBEC5:E8929C0:5F6A99B2')] +[{"login":"AlexandreODelisle","credential_id":5016098,"credential_type":"personal access token","credential_authorized_at":"2020-09-20T23:50:41Z","credential_accessed_at":"2020-09-20T23:52:12Z","token_last_eight":"a397af52","scopes":["admin:enterprise","admin:gpg_key","admin:org","admin:org_hook","admin:public_key","admin:repo_hook","delete:packages","delete_repo","gist","notifications","read:packages","repo","user","workflow","write:discussion","write:packages"]}] +