fix test token scoping: override GITHUB_TOKEN via OIDC in ensureGitHubToken
the runner's GITHUB_TOKEN (scoped to pullfrog/app) was leaking into test subprocesses targeting pullfrog/test-repo, causing 400s from the Pullfrog API on run-context fetches. instead of deleting GITHUB_TOKEN from the subprocess env, ensureGitHubToken now always mints a fresh OIDC token scoped to GITHUB_REPOSITORY when OIDC is available — replacing any inherited token with a correctly-scoped one. also adds an informative throw in acquireTokenViaGitHubApp when GITHUB_APP_ID/GITHUB_PRIVATE_KEY are missing. Made-with: Cursor
This commit is contained in:
committed by
pullfrog[bot]
parent
4a8c432a48
commit
250fe7eaa1
@@ -143506,10 +143506,15 @@ var findInstallationId = async (jwt2, repoOwner, repoName) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
async function acquireTokenViaGitHubApp(opts) {
|
async function acquireTokenViaGitHubApp(opts) {
|
||||||
|
if (!process.env.GITHUB_APP_ID || !process.env.GITHUB_PRIVATE_KEY) {
|
||||||
|
throw new Error(
|
||||||
|
"cannot acquire token via GitHub App: GITHUB_APP_ID and GITHUB_PRIVATE_KEY must be set"
|
||||||
|
);
|
||||||
|
}
|
||||||
const repoContext = parseRepoContext();
|
const repoContext = parseRepoContext();
|
||||||
const config3 = {
|
const config3 = {
|
||||||
appId: process.env.GITHUB_APP_ID,
|
appId: process.env.GITHUB_APP_ID,
|
||||||
privateKey: process.env.GITHUB_PRIVATE_KEY?.replace(/\\n/g, "\n"),
|
privateKey: process.env.GITHUB_PRIVATE_KEY.replace(/\\n/g, "\n"),
|
||||||
repoOwner: repoContext.owner,
|
repoOwner: repoContext.owner,
|
||||||
repoName: repoContext.name
|
repoName: repoContext.name
|
||||||
};
|
};
|
||||||
@@ -149732,7 +149737,7 @@ import { isAbsolute, resolve } from "node:path";
|
|||||||
// package.json
|
// package.json
|
||||||
var package_default = {
|
var package_default = {
|
||||||
name: "@pullfrog/pullfrog",
|
name: "@pullfrog/pullfrog",
|
||||||
version: "0.0.179",
|
version: "0.0.180",
|
||||||
type: "module",
|
type: "module",
|
||||||
files: [
|
files: [
|
||||||
"index.js",
|
"index.js",
|
||||||
|
|||||||
@@ -25898,10 +25898,15 @@ var findInstallationId = async (jwt, repoOwner, repoName) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
async function acquireTokenViaGitHubApp(opts) {
|
async function acquireTokenViaGitHubApp(opts) {
|
||||||
|
if (!process.env.GITHUB_APP_ID || !process.env.GITHUB_PRIVATE_KEY) {
|
||||||
|
throw new Error(
|
||||||
|
"cannot acquire token via GitHub App: GITHUB_APP_ID and GITHUB_PRIVATE_KEY must be set"
|
||||||
|
);
|
||||||
|
}
|
||||||
const repoContext = parseRepoContext();
|
const repoContext = parseRepoContext();
|
||||||
const config = {
|
const config = {
|
||||||
appId: process.env.GITHUB_APP_ID,
|
appId: process.env.GITHUB_APP_ID,
|
||||||
privateKey: process.env.GITHUB_PRIVATE_KEY?.replace(/\\n/g, "\n"),
|
privateKey: process.env.GITHUB_PRIVATE_KEY.replace(/\\n/g, "\n"),
|
||||||
repoOwner: repoContext.owner,
|
repoOwner: repoContext.owner,
|
||||||
repoName: repoContext.name
|
repoName: repoContext.name
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@pullfrog/pullfrog",
|
"name": "@pullfrog/pullfrog",
|
||||||
"version": "0.0.179",
|
"version": "0.0.180",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"files": [
|
"files": [
|
||||||
"index.js",
|
"index.js",
|
||||||
|
|||||||
@@ -41284,7 +41284,7 @@ var core3 = __toESM(require_core(), 1);
|
|||||||
// package.json
|
// package.json
|
||||||
var package_default = {
|
var package_default = {
|
||||||
name: "@pullfrog/pullfrog",
|
name: "@pullfrog/pullfrog",
|
||||||
version: "0.0.179",
|
version: "0.0.180",
|
||||||
type: "module",
|
type: "module",
|
||||||
files: [
|
files: [
|
||||||
"index.js",
|
"index.js",
|
||||||
|
|||||||
@@ -216,10 +216,6 @@ export async function runAgentStreaming(options: RunStreamingOptions): Promise<A
|
|||||||
GITHUB_OUTPUT: githubOutputFile,
|
GITHUB_OUTPUT: githubOutputFile,
|
||||||
};
|
};
|
||||||
|
|
||||||
// clear CI runner's GITHUB_TOKEN so ensureGitHubToken() mints a
|
|
||||||
// properly scoped token for the target GITHUB_REPOSITORY via OIDC
|
|
||||||
delete subEnv.GITHUB_TOKEN;
|
|
||||||
|
|
||||||
const child = spawn("node", ["play.ts", "--raw", JSON.stringify(fixture)], {
|
const child = spawn("node", ["play.ts", "--raw", JSON.stringify(fixture)], {
|
||||||
cwd: actionDir,
|
cwd: actionDir,
|
||||||
env: subEnv as Record<string, string>,
|
env: subEnv as Record<string, string>,
|
||||||
|
|||||||
+28
-11
@@ -277,11 +277,17 @@ const findInstallationId = async (
|
|||||||
|
|
||||||
// for local development only
|
// for local development only
|
||||||
async function acquireTokenViaGitHubApp(opts?: AcquireTokenOptions): Promise<string> {
|
async function acquireTokenViaGitHubApp(opts?: AcquireTokenOptions): Promise<string> {
|
||||||
|
if (!process.env.GITHUB_APP_ID || !process.env.GITHUB_PRIVATE_KEY) {
|
||||||
|
throw new Error(
|
||||||
|
"cannot acquire token via GitHub App: GITHUB_APP_ID and GITHUB_PRIVATE_KEY must be set"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
const repoContext = parseRepoContext();
|
const repoContext = parseRepoContext();
|
||||||
|
|
||||||
const config: GitHubAppConfig = {
|
const config: GitHubAppConfig = {
|
||||||
appId: process.env.GITHUB_APP_ID!,
|
appId: process.env.GITHUB_APP_ID,
|
||||||
privateKey: process.env.GITHUB_PRIVATE_KEY?.replace(/\\n/g, "\n")!,
|
privateKey: process.env.GITHUB_PRIVATE_KEY.replace(/\\n/g, "\n"),
|
||||||
repoOwner: repoContext.owner,
|
repoOwner: repoContext.owner,
|
||||||
repoName: repoContext.name,
|
repoName: repoContext.name,
|
||||||
};
|
};
|
||||||
@@ -292,20 +298,31 @@ async function acquireTokenViaGitHubApp(opts?: AcquireTokenOptions): Promise<str
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ensure a GitHub token is available in the environment.
|
* ensure a GitHub token is available in the environment.
|
||||||
*
|
*
|
||||||
* If neither `GITHUB_TOKEN` nor `GH_TOKEN` is set, attempts to acquire an
|
* when OIDC is available (CI), always mints a fresh token scoped to
|
||||||
* installation token using `GITHUB_APP_ID` / `GITHUB_PRIVATE_KEY`.
|
* GITHUB_REPOSITORY — overriding any inherited GITHUB_TOKEN that may
|
||||||
|
* be scoped to the wrong repo.
|
||||||
*
|
*
|
||||||
* **Not intended for production use** — this is a convenience for local
|
* otherwise falls back to GitHub App credentials for local development.
|
||||||
* development and test harnesses where tokens aren't pre-provisioned.
|
*
|
||||||
|
* only called from play.ts (test/dev path) — the live action calls
|
||||||
|
* main() directly and never calls this.
|
||||||
*/
|
*/
|
||||||
export async function ensureGitHubToken(): Promise<void> {
|
export async function ensureGitHubToken(): Promise<void> {
|
||||||
|
// when OIDC is available, always mint a fresh token scoped to
|
||||||
|
// GITHUB_REPOSITORY. the inherited GITHUB_TOKEN may be scoped to a
|
||||||
|
// different repo (e.g., runner token for pullfrog/app when tests
|
||||||
|
// target pullfrog/test-repo).
|
||||||
|
if (isOIDCAvailable()) {
|
||||||
|
const token = await acquireNewToken();
|
||||||
|
process.env.GITHUB_TOKEN = token;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!process.env.GITHUB_TOKEN && !process.env.GH_TOKEN) {
|
if (!process.env.GITHUB_TOKEN && !process.env.GH_TOKEN) {
|
||||||
if (isOIDCAvailable() || (process.env.GITHUB_APP_ID && process.env.GITHUB_PRIVATE_KEY)) {
|
const token = await acquireNewToken();
|
||||||
const token = await acquireNewToken();
|
process.env.GITHUB_TOKEN = token;
|
||||||
process.env.GITHUB_TOKEN = token;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user