如何在拉取请求事件中获取 github 应用程序安装 ID?

Sar*_*lai 5 git github github-api github-app

我正在使用 Github 创建一个构建管道,它将对每个拉取请求创建检查运行以分析我的应用程序的性能。我已经创建了 Github 应用程序并将其安装到我的存储库中并生成了私钥。我需要执行Authenticating as an installation以获得访问令牌。

但根据文档获取安装访问令牌,首先我必须获取该应用程序的安装列表,并且必须从该列表中找到特定的安装。但我不知道如何识别安装我的应用程序的特定存储库上引发的拉取请求事件的应用程序的特定安装 ID。

我不知道我错过了什么。

San*_*aXL 6

如果您的 CI/CD 无法与 GitHub 的 webhooks 配合使用(例如,由于防火墙的原因),您可以执行以下操作:

#!/bin/bash

HEADER=$( echo -n {\"alg\":\"RS256\"} | base64 | tr -d '=' )
PAYLOAD=$( echo -n \{\"iat\":$(date -u '+%s'),\"exp\":$(( $( date -u '+%s' ) + 600 )),\"iss\":$GITHUB_APP_ID\} | base64 | tr -d '\n' | tr -d '=' | tr / _ | tr + - )
SIGNATURE=$( echo -n "$HEADER.$PAYLOAD" | openssl dgst -sha256 -sign ./private_key -binary | openssl base64 | tr -d '\n' | tr -d '=' | tr / _ | tr + - )
TOKEN=$HEADER.$PAYLOAD.$SIGNATURE

INSTALLATION_ID=$( curl -s -H "Authorization: Bearer $TOKEN" -H "Accept: application/vnd.github.v3+json" https://api.github.com/app/installations | jq .[0].id )
INSTALLATION_TOKEN=$( curl -s -H "Authorization: Bearer $TOKEN" -H "Accept: application/vnd.github.v3+json" -d '{"permissions":{ "checks":"write"}}' https://api.github.com/app/installations/$INSTALLATION_ID/access_tokens | jq .token | tr -d '"' )
echo $INSTALLATION_TOKEN
Run Code Online (Sandbox Code Playgroud)

或者用Python:

# Implementation of: https://docs.github.com/en/developers/apps/authenticating-with-github-apps#authenticating-as-a-github-app
# Inspired by https://gist.github.com/pelson/47c0c89a3522ed8da5cc305afc2562b0

# TL;DR
# Only GitHub App has an access to annotations API. In order to access this API, we need to
# generate a token based on GitHub App's private key and ID. The token (aka JWT) is valid for only 10 min.

import json
import os
import time

import jwt
import requests
from cryptography.hazmat.backends import default_backend

path_to_github_app_key = os.environ["PATH_TO_GITHUB_APP_KEY"]
cert_bytes = open(path_to_github_app_key, "r").read().encode()
github_app_id = os.environ["GITHUB_APP_ID"]
private_key = default_backend().load_pem_private_key(cert_bytes, None)
time_since_epoch_in_seconds = int(time.time())

payload = {
    # issued at time, 60 seconds in the past to allow for clock drift
    "iat": time_since_epoch_in_seconds - 60,
    # JWT expiration time (10 minute maximum)
    "exp": time_since_epoch_in_seconds + (10 * 60),
    # GitHub App's identifier
    "iss": github_app_id,
}

encoded_payload = jwt.encode(payload, private_key, algorithm="RS256")

headers = {
    "Authorization": "Bearer {}".format(encoded_payload),
    "Accept": "application/vnd.github.v3+json",
}

resp = requests.get("https://api.github.com/app/installations", headers=headers)

installation_id = json.loads(resp.content.decode())[0]["id"]

data = '{"permissions":{ "checks":"write"}}'
resp = requests.post(
    "https://api.github.com/app/installations/"
    + str(installation_id)
    + "/access_tokens",
    headers=headers,
    data=data,
)

installation_token = json.loads(resp.content.decode())["token"]
print(installation_token)
Run Code Online (Sandbox Code Playgroud)

我花了一段时间,但这段代码有效。您需要拥有包含 GitHub 生成的私钥的GITHUB_APP_ID文件。private_key

然后您可以像这样编辑检查运行:

curl -s -H "Authorization: token $GITHUB_APP_INSTALLATION_TOKEN" -H "application/vnd.github.v3+json" -d @body.json https://api.github.com/<username/organization>/$GITHUB_REPO/check-runs
Run Code Online (Sandbox Code Playgroud)

body.json包含以下数据的 JSON 文件在哪里: https://developer.github.com/v3/checks/runs/

例如:

# Create check "Linter" and set its status to "queued".
# https://developer.github.com/v3/checks/runs/

import json
import os

import requests

github_repo = os.environ["GITHUB_REPO"]
github_token = os.environ["GITHUB_APP_INSTALLATION_TOKEN"]
head_sha = os.environ["COMMIT_SHA"]

check = {
    "name": "Linter",
    "head_sha": head_sha,
    "status": "queued",
    "output": {
        "title": "Waiting...",
        "summary": "Check code with linter",
        "text": "Execute 'golangci-lint run'",
    },
}
data = json.dumps(check)

headers = {
    "Authorization": "token " + github_token,
    "Accept": "application/vnd.github.v3+json",
}

# Send request to GitHub.
requests.post(
    "https://api.github.com/repos/<username/organization>/" + github_repo + "/check-runs",
    headers=headers,
    data=data,
)
Run Code Online (Sandbox Code Playgroud)