Skip to content

Commit 0e53a97

Browse files
committed
improve github_token flow
1 parent cc56089 commit 0e53a97

File tree

5 files changed

+51
-17
lines changed

5 files changed

+51
-17
lines changed

entry.js

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40481,7 +40481,7 @@ function query({
4048140481
// package.json
4048240482
var package_default = {
4048340483
name: "@pullfrog/action",
40484-
version: "0.0.95",
40484+
version: "0.0.96",
4048540485
type: "module",
4048640486
files: [
4048740487
"index.js",
@@ -41084,7 +41084,7 @@ async function setupGitHubInstallationToken() {
4108441084
if (existingToken) {
4108541085
core2.setSecret(existingToken);
4108641086
log.info("Using provided GitHub installation token");
41087-
return { githubInstallationToken: existingToken, wasAcquired: false };
41087+
return { githubInstallationToken: existingToken, wasAcquired: false, isFallbackToken: false };
4108841088
}
4108941089
const acquiredToken = await acquireNewToken();
4109041090
if (!acquiredToken) {
@@ -41097,11 +41097,11 @@ async function setupGitHubInstallationToken() {
4109741097
log.info("Using GITHUB_TOKEN (app not installed or token exchange failed)");
4109841098
core2.setSecret(defaultToken);
4109941099
process.env.GITHUB_INSTALLATION_TOKEN = defaultToken;
41100-
return { githubInstallationToken: defaultToken, wasAcquired: false };
41100+
return { githubInstallationToken: defaultToken, wasAcquired: false, isFallbackToken: true };
4110141101
}
4110241102
core2.setSecret(acquiredToken);
4110341103
process.env.GITHUB_INSTALLATION_TOKEN = acquiredToken;
41104-
return { githubInstallationToken: acquiredToken, wasAcquired: true };
41104+
return { githubInstallationToken: acquiredToken, wasAcquired: true, isFallbackToken: false };
4110541105
}
4110641106
async function revokeInstallationToken(token) {
4110741107
const apiUrl = process.env.GITHUB_API_URL || "https://api.github.com";
@@ -41437,6 +41437,9 @@ var DEFAULT_REPO_SETTINGS = {
4143741437
};
4143841438
async function getRepoSettings(token, repoContext) {
4143941439
const apiUrl = process.env.API_URL || "https://pullfrog.ai";
41440+
const timeoutMs = 5e3;
41441+
const controller = new AbortController();
41442+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
4144041443
try {
4144141444
const response = await fetch(
4144241445
`${apiUrl}/api/repo/${repoContext.owner}/${repoContext.name}/settings`,
@@ -41445,9 +41448,11 @@ async function getRepoSettings(token, repoContext) {
4144541448
headers: {
4144641449
Authorization: `Bearer ${token}`,
4144741450
"Content-Type": "application/json"
41448-
}
41451+
},
41452+
signal: controller.signal
4144941453
}
4145041454
);
41455+
clearTimeout(timeoutId);
4145141456
if (!response.ok) {
4145241457
return DEFAULT_REPO_SETTINGS;
4145341458
}
@@ -41457,6 +41462,7 @@ async function getRepoSettings(token, repoContext) {
4145741462
}
4145841463
return settings;
4145941464
} catch {
41465+
clearTimeout(timeoutId);
4146041466
return DEFAULT_REPO_SETTINGS;
4146141467
}
4146241468
}
@@ -41504,12 +41510,20 @@ async function main(inputs) {
4150441510
try {
4150541511
log.info(`\u{1F438} Running pullfrog/action@${package_default.version}...`);
4150641512
setupGitConfig();
41507-
const { githubInstallationToken, wasAcquired } = await setupGitHubInstallationToken();
41513+
const { githubInstallationToken, wasAcquired, isFallbackToken } = await setupGitHubInstallationToken();
4150841514
if (wasAcquired) {
4150941515
tokenToRevoke = githubInstallationToken;
4151041516
}
4151141517
const repoContext = parseRepoContext();
41512-
const repoSettings = await getRepoSettings(githubInstallationToken, repoContext);
41518+
let repoSettings;
41519+
if (isFallbackToken) {
41520+
log.info("Using default repository settings (app not installed)");
41521+
repoSettings = DEFAULT_REPO_SETTINGS;
41522+
} else {
41523+
log.info("Fetching repository settings...");
41524+
repoSettings = await getRepoSettings(githubInstallationToken, repoContext);
41525+
log.info("Repository settings fetched");
41526+
}
4151341527
const agent = repoSettings.defaultAgent || "claude";
4151441528
if (agent !== "claude") throw new Error(`Unsupported agent: ${agent}`);
4151541529
setupGitAuth(githubInstallationToken, repoContext);

main.ts

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { type } from "arktype";
22
import { claude } from "./agents/claude.ts";
33
import { createMcpConfigs } from "./mcp/config.ts";
44
import packageJson from "./package.json" with { type: "json" };
5-
import { getRepoSettings } from "./utils/api.ts";
5+
import { DEFAULT_REPO_SETTINGS, getRepoSettings, type RepoSettings } from "./utils/api.ts";
66
import { log } from "./utils/cli.ts";
77
import {
88
parseRepoContext,
@@ -34,14 +34,24 @@ export async function main(inputs: Inputs): Promise<MainResult> {
3434

3535
setupGitConfig();
3636

37-
const { githubInstallationToken, wasAcquired } = await setupGitHubInstallationToken();
37+
const { githubInstallationToken, wasAcquired, isFallbackToken } =
38+
await setupGitHubInstallationToken();
3839
if (wasAcquired) {
3940
tokenToRevoke = githubInstallationToken;
4041
}
4142
const repoContext = parseRepoContext();
4243

4344
// Fetch repo settings (agent, permissions, workflows) from API
44-
const repoSettings = await getRepoSettings(githubInstallationToken, repoContext);
45+
// Skip API call if we're using GITHUB_TOKEN fallback (app not installed)
46+
let repoSettings: RepoSettings;
47+
if (isFallbackToken) {
48+
log.info("Using default repository settings (app not installed)");
49+
repoSettings = DEFAULT_REPO_SETTINGS;
50+
} else {
51+
log.info("Fetching repository settings...");
52+
repoSettings = await getRepoSettings(githubInstallationToken, repoContext);
53+
log.info("Repository settings fetched");
54+
}
4555
const agent = repoSettings.defaultAgent || "claude";
4656
if (agent !== "claude") throw new Error(`Unsupported agent: ${agent}`);
4757

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@pullfrog/action",
3-
"version": "0.0.95",
3+
"version": "0.0.96",
44
"type": "module",
55
"files": [
66
"index.js",

utils/api.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export interface RepoSettings {
1313
}>;
1414
}
1515

16-
const DEFAULT_REPO_SETTINGS: RepoSettings = {
16+
export const DEFAULT_REPO_SETTINGS: RepoSettings = {
1717
defaultAgent: null,
1818
webAccessLevel: "full_access",
1919
webAccessAllowTrusted: false,
@@ -32,6 +32,11 @@ export async function getRepoSettings(
3232
): Promise<RepoSettings> {
3333
const apiUrl = process.env.API_URL || "https://pullfrog.ai";
3434

35+
// Add timeout to prevent hanging (5 seconds)
36+
const timeoutMs = 5000;
37+
const controller = new AbortController();
38+
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
39+
3540
try {
3641
const response = await fetch(
3742
`${apiUrl}/api/repo/${repoContext.owner}/${repoContext.name}/settings`,
@@ -41,9 +46,12 @@ export async function getRepoSettings(
4146
Authorization: `Bearer ${token}`,
4247
"Content-Type": "application/json",
4348
},
49+
signal: controller.signal,
4450
}
4551
);
4652

53+
clearTimeout(timeoutId);
54+
4755
if (!response.ok) {
4856
// If API returns 404 or other error, fall back to defaults
4957
return DEFAULT_REPO_SETTINGS;
@@ -58,7 +66,8 @@ export async function getRepoSettings(
5866

5967
return settings;
6068
} catch {
61-
// If fetch fails (network error, etc.), fall back to defaults
69+
clearTimeout(timeoutId);
70+
// If fetch fails (network error, timeout, etc.), fall back to defaults
6271
return DEFAULT_REPO_SETTINGS;
6372
}
6473
}

utils/github.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -294,18 +294,19 @@ function getDefaultGitHubToken(): string | null {
294294

295295
/**
296296
* Setup GitHub installation token for the action
297-
* Returns the token and whether it was acquired (needs revocation)
297+
* Returns the token, whether it was acquired (needs revocation), and whether we fell back to GITHUB_TOKEN
298298
* Falls back to GITHUB_TOKEN if app is not installed
299299
*/
300300
export async function setupGitHubInstallationToken(): Promise<{
301301
githubInstallationToken: string;
302302
wasAcquired: boolean;
303+
isFallbackToken: boolean;
303304
}> {
304305
const existingToken = checkExistingToken();
305306
if (existingToken) {
306307
core.setSecret(existingToken);
307308
log.info("Using provided GitHub installation token");
308-
return { githubInstallationToken: existingToken, wasAcquired: false };
309+
return { githubInstallationToken: existingToken, wasAcquired: false, isFallbackToken: false };
309310
}
310311

311312
const acquiredToken = await acquireNewToken();
@@ -322,13 +323,13 @@ export async function setupGitHubInstallationToken(): Promise<{
322323
log.info("Using GITHUB_TOKEN (app not installed or token exchange failed)");
323324
core.setSecret(defaultToken);
324325
process.env.GITHUB_INSTALLATION_TOKEN = defaultToken;
325-
return { githubInstallationToken: defaultToken, wasAcquired: false };
326+
return { githubInstallationToken: defaultToken, wasAcquired: false, isFallbackToken: true };
326327
}
327328

328329
core.setSecret(acquiredToken);
329330
process.env.GITHUB_INSTALLATION_TOKEN = acquiredToken;
330331

331-
return { githubInstallationToken: acquiredToken, wasAcquired: true };
332+
return { githubInstallationToken: acquiredToken, wasAcquired: true, isFallbackToken: false };
332333
}
333334

334335
/**

0 commit comments

Comments
 (0)