Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0e53a97619 | |||
| cc56089a41 | |||
| 401496f19f | |||
| 8822968cbb |
@@ -40481,7 +40481,7 @@ function query({
|
|||||||
// package.json
|
// package.json
|
||||||
var package_default = {
|
var package_default = {
|
||||||
name: "@pullfrog/action",
|
name: "@pullfrog/action",
|
||||||
version: "0.0.92",
|
version: "0.0.96",
|
||||||
type: "module",
|
type: "module",
|
||||||
files: [
|
files: [
|
||||||
"index.js",
|
"index.js",
|
||||||
@@ -40911,6 +40911,9 @@ function checkExistingToken() {
|
|||||||
const envToken = process.env.GITHUB_INSTALLATION_TOKEN;
|
const envToken = process.env.GITHUB_INSTALLATION_TOKEN;
|
||||||
return inputToken || envToken || null;
|
return inputToken || envToken || null;
|
||||||
}
|
}
|
||||||
|
function getGitHubTokenInput() {
|
||||||
|
return core2.getInput("github_token") || null;
|
||||||
|
}
|
||||||
function isGitHubActionsEnvironment() {
|
function isGitHubActionsEnvironment() {
|
||||||
return Boolean(process.env.GITHUB_ACTIONS);
|
return Boolean(process.env.GITHUB_ACTIONS);
|
||||||
}
|
}
|
||||||
@@ -41057,24 +41060,31 @@ async function acquireNewToken() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
function getDefaultGitHubToken() {
|
function getDefaultGitHubToken() {
|
||||||
if (isGitHubActionsEnvironment()) {
|
const inputToken = getGitHubTokenInput();
|
||||||
|
if (inputToken) {
|
||||||
|
return inputToken;
|
||||||
|
}
|
||||||
|
const token = process.env.GITHUB_TOKEN;
|
||||||
|
if (!token && isGitHubActionsEnvironment()) {
|
||||||
const githubEnvVars = Object.keys(process.env).filter((key) => key.startsWith("GITHUB_")).reduce(
|
const githubEnvVars = Object.keys(process.env).filter((key) => key.startsWith("GITHUB_")).reduce(
|
||||||
(acc, key) => {
|
(acc, key) => {
|
||||||
acc[key] = key === "GITHUB_TOKEN" ? "***" : process.env[key];
|
acc[key] = key === "GITHUB_TOKEN" ? process.env[key] ? "***SET***" : "NOT_SET" : process.env[key];
|
||||||
return acc;
|
return acc;
|
||||||
},
|
},
|
||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
log.debug(`GitHub env vars: ${JSON.stringify(githubEnvVars)}`);
|
log.warning(
|
||||||
|
`GITHUB_TOKEN not found. Available GITHUB_* env vars: ${JSON.stringify(githubEnvVars)}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return process.env.GITHUB_TOKEN || null;
|
return token || null;
|
||||||
}
|
}
|
||||||
async function setupGitHubInstallationToken() {
|
async function setupGitHubInstallationToken() {
|
||||||
const existingToken = checkExistingToken();
|
const existingToken = checkExistingToken();
|
||||||
if (existingToken) {
|
if (existingToken) {
|
||||||
core2.setSecret(existingToken);
|
core2.setSecret(existingToken);
|
||||||
log.info("Using provided GitHub installation token");
|
log.info("Using provided GitHub installation token");
|
||||||
return { githubInstallationToken: existingToken, wasAcquired: false };
|
return { githubInstallationToken: existingToken, wasAcquired: false, isFallbackToken: false };
|
||||||
}
|
}
|
||||||
const acquiredToken = await acquireNewToken();
|
const acquiredToken = await acquireNewToken();
|
||||||
if (!acquiredToken) {
|
if (!acquiredToken) {
|
||||||
@@ -41087,11 +41097,11 @@ async function setupGitHubInstallationToken() {
|
|||||||
log.info("Using GITHUB_TOKEN (app not installed or token exchange failed)");
|
log.info("Using GITHUB_TOKEN (app not installed or token exchange failed)");
|
||||||
core2.setSecret(defaultToken);
|
core2.setSecret(defaultToken);
|
||||||
process.env.GITHUB_INSTALLATION_TOKEN = defaultToken;
|
process.env.GITHUB_INSTALLATION_TOKEN = defaultToken;
|
||||||
return { githubInstallationToken: defaultToken, wasAcquired: false };
|
return { githubInstallationToken: defaultToken, wasAcquired: false, isFallbackToken: true };
|
||||||
}
|
}
|
||||||
core2.setSecret(acquiredToken);
|
core2.setSecret(acquiredToken);
|
||||||
process.env.GITHUB_INSTALLATION_TOKEN = acquiredToken;
|
process.env.GITHUB_INSTALLATION_TOKEN = acquiredToken;
|
||||||
return { githubInstallationToken: acquiredToken, wasAcquired: true };
|
return { githubInstallationToken: acquiredToken, wasAcquired: true, isFallbackToken: false };
|
||||||
}
|
}
|
||||||
async function revokeInstallationToken(token) {
|
async function revokeInstallationToken(token) {
|
||||||
const apiUrl = process.env.GITHUB_API_URL || "https://api.github.com";
|
const apiUrl = process.env.GITHUB_API_URL || "https://api.github.com";
|
||||||
@@ -41427,6 +41437,9 @@ var DEFAULT_REPO_SETTINGS = {
|
|||||||
};
|
};
|
||||||
async function getRepoSettings(token, repoContext) {
|
async function getRepoSettings(token, repoContext) {
|
||||||
const apiUrl = process.env.API_URL || "https://pullfrog.ai";
|
const apiUrl = process.env.API_URL || "https://pullfrog.ai";
|
||||||
|
const timeoutMs = 5e3;
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${apiUrl}/api/repo/${repoContext.owner}/${repoContext.name}/settings`,
|
`${apiUrl}/api/repo/${repoContext.owner}/${repoContext.name}/settings`,
|
||||||
@@ -41435,9 +41448,11 @@ async function getRepoSettings(token, repoContext) {
|
|||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json"
|
||||||
}
|
},
|
||||||
|
signal: controller.signal
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
clearTimeout(timeoutId);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
return DEFAULT_REPO_SETTINGS;
|
return DEFAULT_REPO_SETTINGS;
|
||||||
}
|
}
|
||||||
@@ -41447,6 +41462,7 @@ async function getRepoSettings(token, repoContext) {
|
|||||||
}
|
}
|
||||||
return settings;
|
return settings;
|
||||||
} catch {
|
} catch {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
return DEFAULT_REPO_SETTINGS;
|
return DEFAULT_REPO_SETTINGS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -41494,12 +41510,20 @@ async function main(inputs) {
|
|||||||
try {
|
try {
|
||||||
log.info(`\u{1F438} Running pullfrog/action@${package_default.version}...`);
|
log.info(`\u{1F438} Running pullfrog/action@${package_default.version}...`);
|
||||||
setupGitConfig();
|
setupGitConfig();
|
||||||
const { githubInstallationToken, wasAcquired } = await setupGitHubInstallationToken();
|
const { githubInstallationToken, wasAcquired, isFallbackToken } = await setupGitHubInstallationToken();
|
||||||
if (wasAcquired) {
|
if (wasAcquired) {
|
||||||
tokenToRevoke = githubInstallationToken;
|
tokenToRevoke = githubInstallationToken;
|
||||||
}
|
}
|
||||||
const repoContext = parseRepoContext();
|
const repoContext = parseRepoContext();
|
||||||
const repoSettings = await getRepoSettings(githubInstallationToken, repoContext);
|
let repoSettings;
|
||||||
|
if (isFallbackToken) {
|
||||||
|
log.info("Using default repository settings (app not installed)");
|
||||||
|
repoSettings = DEFAULT_REPO_SETTINGS;
|
||||||
|
} else {
|
||||||
|
log.info("Fetching repository settings...");
|
||||||
|
repoSettings = await getRepoSettings(githubInstallationToken, repoContext);
|
||||||
|
log.info("Repository settings fetched");
|
||||||
|
}
|
||||||
const agent = repoSettings.defaultAgent || "claude";
|
const agent = repoSettings.defaultAgent || "claude";
|
||||||
if (agent !== "claude") throw new Error(`Unsupported agent: ${agent}`);
|
if (agent !== "claude") throw new Error(`Unsupported agent: ${agent}`);
|
||||||
setupGitAuth(githubInstallationToken, repoContext);
|
setupGitAuth(githubInstallationToken, repoContext);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { type } from "arktype";
|
|||||||
import { claude } from "./agents/claude.ts";
|
import { claude } from "./agents/claude.ts";
|
||||||
import { createMcpConfigs } from "./mcp/config.ts";
|
import { createMcpConfigs } from "./mcp/config.ts";
|
||||||
import packageJson from "./package.json" with { type: "json" };
|
import packageJson from "./package.json" with { type: "json" };
|
||||||
import { getRepoSettings } from "./utils/api.ts";
|
import { DEFAULT_REPO_SETTINGS, getRepoSettings, type RepoSettings } from "./utils/api.ts";
|
||||||
import { log } from "./utils/cli.ts";
|
import { log } from "./utils/cli.ts";
|
||||||
import {
|
import {
|
||||||
parseRepoContext,
|
parseRepoContext,
|
||||||
@@ -34,14 +34,24 @@ export async function main(inputs: Inputs): Promise<MainResult> {
|
|||||||
|
|
||||||
setupGitConfig();
|
setupGitConfig();
|
||||||
|
|
||||||
const { githubInstallationToken, wasAcquired } = await setupGitHubInstallationToken();
|
const { githubInstallationToken, wasAcquired, isFallbackToken } =
|
||||||
|
await setupGitHubInstallationToken();
|
||||||
if (wasAcquired) {
|
if (wasAcquired) {
|
||||||
tokenToRevoke = githubInstallationToken;
|
tokenToRevoke = githubInstallationToken;
|
||||||
}
|
}
|
||||||
const repoContext = parseRepoContext();
|
const repoContext = parseRepoContext();
|
||||||
|
|
||||||
// Fetch repo settings (agent, permissions, workflows) from API
|
// Fetch repo settings (agent, permissions, workflows) from API
|
||||||
const repoSettings = await getRepoSettings(githubInstallationToken, repoContext);
|
// Skip API call if we're using GITHUB_TOKEN fallback (app not installed)
|
||||||
|
let repoSettings: RepoSettings;
|
||||||
|
if (isFallbackToken) {
|
||||||
|
log.info("Using default repository settings (app not installed)");
|
||||||
|
repoSettings = DEFAULT_REPO_SETTINGS;
|
||||||
|
} else {
|
||||||
|
log.info("Fetching repository settings...");
|
||||||
|
repoSettings = await getRepoSettings(githubInstallationToken, repoContext);
|
||||||
|
log.info("Repository settings fetched");
|
||||||
|
}
|
||||||
const agent = repoSettings.defaultAgent || "claude";
|
const agent = repoSettings.defaultAgent || "claude";
|
||||||
if (agent !== "claude") throw new Error(`Unsupported agent: ${agent}`);
|
if (agent !== "claude") throw new Error(`Unsupported agent: ${agent}`);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@pullfrog/action",
|
"name": "@pullfrog/action",
|
||||||
"version": "0.0.92",
|
"version": "0.0.96",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"files": [
|
"files": [
|
||||||
"index.js",
|
"index.js",
|
||||||
|
|||||||
+11
-2
@@ -13,7 +13,7 @@ export interface RepoSettings {
|
|||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DEFAULT_REPO_SETTINGS: RepoSettings = {
|
export const DEFAULT_REPO_SETTINGS: RepoSettings = {
|
||||||
defaultAgent: null,
|
defaultAgent: null,
|
||||||
webAccessLevel: "full_access",
|
webAccessLevel: "full_access",
|
||||||
webAccessAllowTrusted: false,
|
webAccessAllowTrusted: false,
|
||||||
@@ -32,6 +32,11 @@ export async function getRepoSettings(
|
|||||||
): Promise<RepoSettings> {
|
): Promise<RepoSettings> {
|
||||||
const apiUrl = process.env.API_URL || "https://pullfrog.ai";
|
const apiUrl = process.env.API_URL || "https://pullfrog.ai";
|
||||||
|
|
||||||
|
// Add timeout to prevent hanging (5 seconds)
|
||||||
|
const timeoutMs = 5000;
|
||||||
|
const controller = new AbortController();
|
||||||
|
const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const response = await fetch(
|
||||||
`${apiUrl}/api/repo/${repoContext.owner}/${repoContext.name}/settings`,
|
`${apiUrl}/api/repo/${repoContext.owner}/${repoContext.name}/settings`,
|
||||||
@@ -41,9 +46,12 @@ export async function getRepoSettings(
|
|||||||
Authorization: `Bearer ${token}`,
|
Authorization: `Bearer ${token}`,
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
|
signal: controller.signal,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
// If API returns 404 or other error, fall back to defaults
|
// If API returns 404 or other error, fall back to defaults
|
||||||
return DEFAULT_REPO_SETTINGS;
|
return DEFAULT_REPO_SETTINGS;
|
||||||
@@ -58,7 +66,8 @@ export async function getRepoSettings(
|
|||||||
|
|
||||||
return settings;
|
return settings;
|
||||||
} catch {
|
} catch {
|
||||||
// If fetch fails (network error, etc.), fall back to defaults
|
clearTimeout(timeoutId);
|
||||||
|
// If fetch fails (network error, timeout, etc.), fall back to defaults
|
||||||
return DEFAULT_REPO_SETTINGS;
|
return DEFAULT_REPO_SETTINGS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-9
@@ -49,6 +49,10 @@ function checkExistingToken(): string | null {
|
|||||||
return inputToken || envToken || null;
|
return inputToken || envToken || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getGitHubTokenInput(): string | null {
|
||||||
|
return core.getInput("github_token") || null;
|
||||||
|
}
|
||||||
|
|
||||||
function isGitHubActionsEnvironment(): boolean {
|
function isGitHubActionsEnvironment(): boolean {
|
||||||
return Boolean(process.env.GITHUB_ACTIONS);
|
return Boolean(process.env.GITHUB_ACTIONS);
|
||||||
}
|
}
|
||||||
@@ -255,37 +259,54 @@ async function acquireNewToken(): Promise<string | null> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getDefaultGitHubToken(): string | null {
|
function getDefaultGitHubToken(): string | null {
|
||||||
// Debug: log all GITHUB_* env vars
|
// Try input first (explicitly passed from workflow)
|
||||||
if (isGitHubActionsEnvironment()) {
|
const inputToken = getGitHubTokenInput();
|
||||||
|
if (inputToken) {
|
||||||
|
return inputToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then try environment variable (automatically set by GitHub Actions)
|
||||||
|
const token = process.env.GITHUB_TOKEN;
|
||||||
|
|
||||||
|
// Log diagnostic info when GITHUB_TOKEN is missing
|
||||||
|
if (!token && isGitHubActionsEnvironment()) {
|
||||||
const githubEnvVars = Object.keys(process.env)
|
const githubEnvVars = Object.keys(process.env)
|
||||||
.filter((key) => key.startsWith("GITHUB_"))
|
.filter((key) => key.startsWith("GITHUB_"))
|
||||||
.reduce(
|
.reduce(
|
||||||
(acc, key) => {
|
(acc, key) => {
|
||||||
acc[key] = key === "GITHUB_TOKEN" ? "***" : process.env[key];
|
acc[key] =
|
||||||
|
key === "GITHUB_TOKEN"
|
||||||
|
? process.env[key]
|
||||||
|
? "***SET***"
|
||||||
|
: "NOT_SET"
|
||||||
|
: process.env[key];
|
||||||
return acc;
|
return acc;
|
||||||
},
|
},
|
||||||
{} as Record<string, string | undefined>
|
{} as Record<string, string | undefined>
|
||||||
);
|
);
|
||||||
log.debug(`GitHub env vars: ${JSON.stringify(githubEnvVars)}`);
|
log.warning(
|
||||||
|
`GITHUB_TOKEN not found. Available GITHUB_* env vars: ${JSON.stringify(githubEnvVars)}`
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return process.env.GITHUB_TOKEN || null;
|
return token || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup GitHub installation token for the action
|
* Setup GitHub installation token for the action
|
||||||
* Returns the token and whether it was acquired (needs revocation)
|
* Returns the token, whether it was acquired (needs revocation), and whether we fell back to GITHUB_TOKEN
|
||||||
* Falls back to GITHUB_TOKEN if app is not installed
|
* Falls back to GITHUB_TOKEN if app is not installed
|
||||||
*/
|
*/
|
||||||
export async function setupGitHubInstallationToken(): Promise<{
|
export async function setupGitHubInstallationToken(): Promise<{
|
||||||
githubInstallationToken: string;
|
githubInstallationToken: string;
|
||||||
wasAcquired: boolean;
|
wasAcquired: boolean;
|
||||||
|
isFallbackToken: boolean;
|
||||||
}> {
|
}> {
|
||||||
const existingToken = checkExistingToken();
|
const existingToken = checkExistingToken();
|
||||||
if (existingToken) {
|
if (existingToken) {
|
||||||
core.setSecret(existingToken);
|
core.setSecret(existingToken);
|
||||||
log.info("Using provided GitHub installation token");
|
log.info("Using provided GitHub installation token");
|
||||||
return { githubInstallationToken: existingToken, wasAcquired: false };
|
return { githubInstallationToken: existingToken, wasAcquired: false, isFallbackToken: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
const acquiredToken = await acquireNewToken();
|
const acquiredToken = await acquireNewToken();
|
||||||
@@ -302,13 +323,13 @@ export async function setupGitHubInstallationToken(): Promise<{
|
|||||||
log.info("Using GITHUB_TOKEN (app not installed or token exchange failed)");
|
log.info("Using GITHUB_TOKEN (app not installed or token exchange failed)");
|
||||||
core.setSecret(defaultToken);
|
core.setSecret(defaultToken);
|
||||||
process.env.GITHUB_INSTALLATION_TOKEN = defaultToken;
|
process.env.GITHUB_INSTALLATION_TOKEN = defaultToken;
|
||||||
return { githubInstallationToken: defaultToken, wasAcquired: false };
|
return { githubInstallationToken: defaultToken, wasAcquired: false, isFallbackToken: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
core.setSecret(acquiredToken);
|
core.setSecret(acquiredToken);
|
||||||
process.env.GITHUB_INSTALLATION_TOKEN = acquiredToken;
|
process.env.GITHUB_INSTALLATION_TOKEN = acquiredToken;
|
||||||
|
|
||||||
return { githubInstallationToken: acquiredToken, wasAcquired: true };
|
return { githubInstallationToken: acquiredToken, wasAcquired: true, isFallbackToken: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user