Obtain job-level token by default for less privileged runs (#198)

This commit is contained in:
Mateusz Burzyński
2026-01-29 21:30:08 +00:00
committed by pullfrog[bot]
parent bb7e7584d4
commit 2daab6fc78
6 changed files with 73 additions and 37 deletions
+6 -2
View File
@@ -44,7 +44,7 @@ export function setupTestRepo(options: SetupOptions): void {
interface SetupGitParams {
token: string;
originalToken: string | undefined;
githubJobToken: string | undefined;
bashPermission: BashPermission;
owner: string;
name: string;
@@ -134,7 +134,11 @@ export async function setupGit(params: SetupGitParams): Promise<void> {
// - restricted/disabled: workflow token (limited by permissions block)
// this protects the base repo while allowing fork PR edits via fork remote
const originToken =
params.bashPermission === "enabled" ? params.token : params.originalToken || params.token;
params.bashPermission === "enabled"
? params.token
: // in GitHub Actions environment this less-capable job token should always be available in the action's input
// but in other environments there is no secondary token like this so we just use the installation token itself
params.githubJobToken || params.token;
// non-PR events: set up origin with token, stay on default branch
if (params.event.is_pr !== true || !params.event.issue_number) {
+26 -11
View File
@@ -11,18 +11,35 @@ export { revokeGitHubInstallationToken as revokeInstallationToken };
// store token in memory instead of process.env
let githubInstallationToken: string | undefined;
function setEnvironmentVariable(name: string, value: string | undefined) {
const hadValue = Object.hasOwn(process.env, name);
const originalValue = process.env[name];
if (typeof value === "string") {
process.env[name] = value;
} else {
delete process.env[name];
}
return () => {
if (hadValue) {
process.env[name] = originalValue;
} else {
delete process.env[name];
}
};
}
/**
* Setup GitHub installation token for the action
*/
export async function resolveInstallationToken() {
assert(!githubInstallationToken, "GitHub installation token is already set.");
const originalToken = process.env.GITHUB_TOKEN;
if (originalToken) {
process.env.ORIGINAL_GITHUB_TOKEN = originalToken;
}
const githubJobToken = core.getInput("token");
const externalToken = process.env.GH_TOKEN;
const token = externalToken || (await acquireNewToken());
process.env.GITHUB_TOKEN = token;
const revertGithubToken = setEnvironmentVariable("GITHUB_TOKEN", token);
githubInstallationToken = token;
if (isGitHubActions) {
@@ -33,14 +50,12 @@ export async function resolveInstallationToken() {
return {
token,
originalToken,
// in GitHub Actions environment this fallback token should always come from the action's input
// but in other environments there is no secondary token like this so we just use the installation token itself
githubJobToken,
async [Symbol.asyncDispose]() {
githubInstallationToken = undefined;
if (originalToken) {
process.env.GITHUB_TOKEN = originalToken;
} else {
delete process.env.GITHUB_TOKEN;
}
revertGithubToken();
// GH_TOKEN isn't acquired here, so it's not revoked here either
if (externalToken) {
return;