mirror of
https://github.com/openclaw/clawhub.git
synced 2026-08-14 00:47:57 +00:00
fix: authenticate GitHub repo discovery
fix: authenticate GitHub repo discovery
This commit is contained in:
@@ -599,6 +599,75 @@ describe("githubImport", () => {
|
||||
expect(fetchMock.mock.calls[3]?.[1]?.headers).not.toHaveProperty("Authorization");
|
||||
});
|
||||
|
||||
it("uses the GitHub App token for bounded repo discovery", async () => {
|
||||
const { privateKey } = generateKeyPairSync("rsa", {
|
||||
modulusLength: 2048,
|
||||
privateKeyEncoding: { type: "pkcs1", format: "pem" },
|
||||
publicKeyEncoding: { type: "spki", format: "pem" },
|
||||
});
|
||||
process.env.GITHUB_APP_ID = "3536245";
|
||||
process.env.GITHUB_APP_INSTALLATION_ID = "987654";
|
||||
process.env.GITHUB_APP_PRIVATE_KEY = privateKey;
|
||||
|
||||
const ctx = {
|
||||
runQuery: vi.fn().mockResolvedValue("123"),
|
||||
};
|
||||
const fetchMock = vi
|
||||
.fn()
|
||||
.mockResolvedValueOnce(
|
||||
Response.json({
|
||||
token: "ghs_app_token",
|
||||
expires_at: "2027-02-02T13:00:00Z",
|
||||
}),
|
||||
)
|
||||
.mockResolvedValueOnce(
|
||||
Response.json({
|
||||
id: 123,
|
||||
login: "vyctorbrzezowski",
|
||||
avatar_url: "https://avatars.githubusercontent.com/u/123?v=4",
|
||||
}),
|
||||
)
|
||||
.mockResolvedValueOnce(
|
||||
Response.json([
|
||||
{
|
||||
name: "public-skill",
|
||||
full_name: "vyctorbrzezowski/public-skill",
|
||||
html_url: "https://github.com/vyctorbrzezowski/public-skill",
|
||||
default_branch: "main",
|
||||
private: false,
|
||||
visibility: "public",
|
||||
owner: { id: 123, login: "vyctorbrzezowski" },
|
||||
},
|
||||
]),
|
||||
)
|
||||
.mockResolvedValueOnce(
|
||||
Response.json({
|
||||
truncated: false,
|
||||
tree: [{ path: "SKILL.md", type: "blob" }],
|
||||
}),
|
||||
);
|
||||
|
||||
const result = await __test.listOwnedPublicGitHubReposForUser(
|
||||
ctx as never,
|
||||
"users:1" as never,
|
||||
{ page: 1, perPage: 30 },
|
||||
fetchMock as never,
|
||||
);
|
||||
|
||||
expect(result.repos).toEqual([
|
||||
expect.objectContaining({
|
||||
repoFullName: "vyctorbrzezowski/public-skill",
|
||||
skillPath: "SKILL.md",
|
||||
}),
|
||||
]);
|
||||
expect(fetchMock).toHaveBeenCalledTimes(4);
|
||||
expect(fetchMock.mock.calls[2]?.[1]).toEqual(
|
||||
expect.objectContaining({
|
||||
headers: expect.objectContaining({ Authorization: "Bearer ghs_app_token" }),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("falls back to the repo archive when GitHub truncates the discovery tree", async () => {
|
||||
const ctx = {
|
||||
runQuery: vi.fn().mockResolvedValue("123"),
|
||||
|
||||
@@ -432,7 +432,10 @@ async function listOwnedPublicGitHubReposForUser(
|
||||
url.searchParams.set("per_page", String(fallbackPerPage));
|
||||
url.searchParams.set("page", String(page));
|
||||
|
||||
const response = await fetchGitHubApi(url.toString(), fetcher, undefined, false);
|
||||
// Public repo discovery still benefits from the installation token's
|
||||
// higher rate limit. If the app cannot access this endpoint, fetchGitHubApi
|
||||
// retries with the configured token or anonymous public access.
|
||||
const response = await fetchGitHubApi(url.toString(), fetcher);
|
||||
if (!response.ok) throwGitHubApiError(response.status);
|
||||
|
||||
const payload = (await response.json()) as unknown;
|
||||
|
||||
Reference in New Issue
Block a user