From 250fe7eaa12e82ba2f6a6d97ef1fc9c38e88eb4c Mon Sep 17 00:00:00 2001 From: Colin McDonnell Date: Thu, 12 Mar 2026 06:15:01 +0000 Subject: [PATCH] fix test token scoping: override GITHUB_TOKEN via OIDC in ensureGitHubToken MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- entry | 9 +++++++-- get-installation-token/entry | 7 ++++++- package.json | 2 +- post | 2 +- test/utils.ts | 4 ---- utils/github.ts | 39 ++++++++++++++++++++++++++---------- 6 files changed, 43 insertions(+), 20 deletions(-) diff --git a/entry b/entry index 607c243..b443e72 100755 --- a/entry +++ b/entry @@ -143506,10 +143506,15 @@ var findInstallationId = async (jwt2, repoOwner, repoName) => { ); }; 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 config3 = { 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, repoName: repoContext.name }; @@ -149732,7 +149737,7 @@ import { isAbsolute, resolve } from "node:path"; // package.json var package_default = { name: "@pullfrog/pullfrog", - version: "0.0.179", + version: "0.0.180", type: "module", files: [ "index.js", diff --git a/get-installation-token/entry b/get-installation-token/entry index 9386ce5..dce7502 100755 --- a/get-installation-token/entry +++ b/get-installation-token/entry @@ -25898,10 +25898,15 @@ var findInstallationId = async (jwt, repoOwner, repoName) => { ); }; 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 config = { 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, repoName: repoContext.name }; diff --git a/package.json b/package.json index 5fc86a7..9eefbab 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@pullfrog/pullfrog", - "version": "0.0.179", + "version": "0.0.180", "type": "module", "files": [ "index.js", diff --git a/post b/post index fd3e5c4..1643e46 100755 --- a/post +++ b/post @@ -41284,7 +41284,7 @@ var core3 = __toESM(require_core(), 1); // package.json var package_default = { name: "@pullfrog/pullfrog", - version: "0.0.179", + version: "0.0.180", type: "module", files: [ "index.js", diff --git a/test/utils.ts b/test/utils.ts index 927c2c1..cc25b03 100644 --- a/test/utils.ts +++ b/test/utils.ts @@ -216,10 +216,6 @@ export async function runAgentStreaming(options: RunStreamingOptions): Promise, diff --git a/utils/github.ts b/utils/github.ts index 8c650b7..7f2d5b4 100644 --- a/utils/github.ts +++ b/utils/github.ts @@ -277,11 +277,17 @@ const findInstallationId = async ( // for local development only async function acquireTokenViaGitHubApp(opts?: AcquireTokenOptions): Promise { + 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 config: GitHubAppConfig = { - appId: process.env.GITHUB_APP_ID!, - privateKey: process.env.GITHUB_PRIVATE_KEY?.replace(/\\n/g, "\n")!, + appId: process.env.GITHUB_APP_ID, + privateKey: process.env.GITHUB_PRIVATE_KEY.replace(/\\n/g, "\n"), repoOwner: repoContext.owner, repoName: repoContext.name, }; @@ -292,20 +298,31 @@ async function acquireTokenViaGitHubApp(opts?: AcquireTokenOptions): Promise { + // 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 (isOIDCAvailable() || (process.env.GITHUB_APP_ID && process.env.GITHUB_PRIVATE_KEY)) { - const token = await acquireNewToken(); - process.env.GITHUB_TOKEN = token; - } + const token = await acquireNewToken(); + process.env.GITHUB_TOKEN = token; } }