我正在编写一个Python应用程序,需要从组织克隆私有存储库。我已经注册了一个 GitHub 应用程序,我可以在文档中看到这需要一个安装访问令牌,但是如何获取其中一个令牌的每个步骤都让我陷入了一个兔子洞(循环引用)链接。
为此需要几个步骤:首先,您需要手动从 GitHub 获取一些信息,然后您的应用程序需要执行一些操作,将其身份验证密钥交换为可用于身份验证的临时代码一个
git clone
。
在编写函数来执行此操作之前,您需要三条信息,所有这些信息都可以从应用程序的设置中获取。到达那里
Settings > Developer Settings > GitHub Apps
Edit
,然后使用 2FA 进行身份验证您需要的三项信息是:
此内容位于
General
页面顶部的 About
部分。
如果您还没有安装该应用程序,您还需要将应用程序安装到组织中。完成此操作后,返回应用程序设置中的
Install App
页面,然后复制安装设置的链接。将其粘贴到编辑器中并从末尾获取数字。链接的格式应为 https://github.com/apps/{app_name}/installations/{installation_id}
;最后一个/
之后的部分是安装ID。
(如果您安装了多个应用程序,可能有一种方法可以通过编程方式获取此内容;我没有研究过这一点,因为我的用例不需要它。)
这就是您向 GitHub 证明您控制该应用程序的方式。返回应用程序设置中的
General
页面,然后向下滚动到 Private keys
部分。点击Generate a private key
按钮;这将立即生成一个 .pem
文件并将其下载到您的计算机。
请勿将其提交到您的存储库,除非您希望每个可以看到该存储库的人都能够像您一样向 GitHub 进行身份验证。
一旦掌握了这三件事,代码中需要的步骤是:
执行前三个步骤的代码可能如下所示:
from datetime import datetime
import jwt
import requests
def get_installation_access_token(
pem_filename: str, app_id: str, installation_id: str
) -> str:
"""
Obtain and return a GitHub installation access token.
Arguments:
pem_filename: Filename of a PEM file generated by GitHub to
authenticate as the installed app.
app_id: The application ID
installation_id: The ID of the app installation.
Returns:
The installation access token obtained from GitHub.
"""
# With thanks to https://github.com/orgs/community/discussions/48186
now = int(datetime.now().timestamp())
with open(pem_filename, "rb") as pem_file:
signing_key = jwt.jwk_from_pem(pem_file.read())
payload = {"iat": now, "exp": now + 600, "iss": app_id}
jwt_instance = jwt.JWT()
encoded_jwt = jwt_instance.encode(payload, signing_key, alg="RS256")
response = requests.post(
"https://api.github.com/app/installations/" f"{installation_id}/access_tokens",
headers={
"Authorization": f"Bearer {encoded_jwt}",
"Accept": "application/vnd.github+json",
"X-GitHub-Api-Version": "2022-11-28",
},
)
if not 200 <= response.status_code < 300:
raise RuntimeError(
"Unable to get token. Status code was "
f"{response.status_code}, body was {response.text}."
)
return response.json()["token"]
将上面收集到的信息作为三个参数传入到函数中。请注意,这取决于
jwt
和 requests
软件包,它们都可以在 pip
中以这些名称使用。
这将提供一个有效期为一小时的安装令牌。 (这比 PEM 文件的有效时间要短得多,因为它的安全性要低得多。这就是需要这种舞蹈的原因 - 您正在用相当安全的东西来交换安全性较低但更易于使用的东西
git clone
;因为它不太安全,所以必须有时间限制,以减少被盗的机会。)
假设您有表单中的存储库 URL
repo_url = https://github.com/organization/repository_name
然后您可以将存储库克隆为:
import git
if not original_url.startswith("https://"):
raise ValueError("Need an HTTPS URL")
auth_url = f"https://x-access-token:{token}@{original_url[8:]}"
git.Repo.clone_from(
auth_url,
deployment["tempdir_path"] / "repo",
branch="deployment",
)
这里我使用了 Python 的
GitPython
库。同样,您可以使用 shell 命令
$ git clone https://x-access-token:${TOKEN}@github.com/organization/repository_name
其中
${TOKEN}
包含调用上述Python函数的结果。
非常感谢 GitHub 社区上的 loujr 提供的指南,最终指导我如何做到这一点。我不再需要使用命令行参数并手动将 JWT 传递到 curl
,而是将所有内容都保留在 Python 中。