Use await using for installation token cleanup

This commit is contained in:
Mateusz Burzyński
2026-01-07 16:57:24 +01:00
parent d99a852e24
commit 2bd12b9553
5 changed files with 546 additions and 500 deletions
+1 -1
View File
@@ -1 +1 @@
v22.14.0
v24.3.0
+407 -355
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -38,7 +38,7 @@ const sharedConfig = {
bundle: true,
format: "esm",
platform: "node",
target: "node20",
target: "node24",
minify: false,
sourcemap: false,
// Bundle all dependencies - GitHub Actions doesn't have node_modules
+7 -12
View File
@@ -21,7 +21,6 @@ import { reportErrorToComment } from "./utils/errorReport.ts";
import {
createOctokit,
parseRepoContext,
revokeGitHubInstallationToken,
setupGitHubInstallationToken,
} from "./utils/github.ts";
import { setupGitAuth, setupGitConfig } from "./utils/setup.ts";
@@ -54,7 +53,6 @@ export interface MainResult {
// intermediate result types for deterministic context building
interface GitHubSetup {
token: string;
owner: string;
name: string;
octokit: Octokit;
@@ -67,12 +65,12 @@ type ApiKeySetup =
| { success: false; error: string };
export async function main(inputs: Inputs): Promise<MainResult> {
const timer = new Timer();
await using installationToken = await setupGitHubInstallationToken();
let mcpServerClose: (() => Promise<void>) | undefined;
let payload: Payload | undefined;
try {
const timer = new Timer();
// phase 1: parse and validate inputs
payload = parsePayload(inputs);
Inputs.assert(inputs);
@@ -80,7 +78,7 @@ export async function main(inputs: Inputs): Promise<MainResult> {
// phase 2: fast setup (github + temp dir)
const [githubSetup, sharedTempDir] = await Promise.all([
initializeGitHub(),
initializeGitHub(installationToken.token),
createTempDirectory(),
]);
timer.checkpoint("githubSetup");
@@ -108,9 +106,9 @@ export async function main(inputs: Inputs): Promise<MainResult> {
// phase 5: parallel long-running operations (agent install + git auth)
const toolState: ToolState = {};
const [cliPath] = await Promise.all([
installAgentCli({ agent, token: githubSetup.token }),
installAgentCli({ agent, token: installationToken.token }),
setupGitAuth({
token: githubSetup.token,
token: installationToken.token,
owner: githubSetup.owner,
name: githubSetup.name,
payload: resolvedPayload,
@@ -157,7 +155,7 @@ export async function main(inputs: Inputs): Promise<MainResult> {
const toolContext: ToolContext = {
owner: githubSetup.owner,
name: githubSetup.name,
githubInstallationToken: githubSetup.token,
githubInstallationToken: installationToken.token,
octokit: githubSetup.octokit,
payload: resolvedPayload,
repo: githubSetup.repo,
@@ -230,7 +228,6 @@ export async function main(inputs: Inputs): Promise<MainResult> {
if (mcpServerClose) {
await mcpServerClose();
}
await revokeGitHubInstallationToken();
}
}
@@ -349,10 +346,9 @@ export interface ToolState {
/**
* Initialize GitHub connection: token, octokit, repo data, settings
*/
async function initializeGitHub(): Promise<GitHubSetup> {
async function initializeGitHub(token: string): Promise<GitHubSetup> {
log.info(`🐸 Running pullfrog/action@${packageJson.version}...`);
const token = await setupGitHubInstallationToken();
const { owner, name } = parseRepoContext();
const octokit = createOctokit(token);
@@ -364,7 +360,6 @@ async function initializeGitHub(): Promise<GitHubSetup> {
]);
return {
token,
owner,
name,
octokit,
+12 -13
View File
@@ -1,6 +1,7 @@
import * as core from "@actions/core";
import { throttling } from "@octokit/plugin-throttling";
import { Octokit } from "@octokit/rest";
import assert from "node:assert/strict";
import { createSign } from "node:crypto";
import { log } from "./cli.ts";
import { retry } from "./retry.ts";
@@ -248,31 +249,29 @@ let githubInstallationToken: string | undefined;
/**
* Setup GitHub installation token for the action
*/
export async function setupGitHubInstallationToken(): Promise<string> {
export async function setupGitHubInstallationToken() {
assert(!githubInstallationToken, "GitHub installation token is already set.");
const acquiredToken = await acquireNewToken();
core.setSecret(acquiredToken);
githubInstallationToken = acquiredToken;
return acquiredToken;
return {
token: acquiredToken,
[Symbol.asyncDispose]() {
githubInstallationToken = undefined;
return revokeGitHubInstallationToken(acquiredToken);
},
};
}
/**
* Get the GitHub installation token from memory
*/
export function getGitHubInstallationToken(): string {
if (!githubInstallationToken) {
throw new Error("GitHub installation token not set. Call setupGitHubInstallationToken first.");
}
assert(githubInstallationToken, "GitHub installation token not set. Call setupGitHubInstallationToken first.");
return githubInstallationToken;
}
export async function revokeGitHubInstallationToken(): Promise<void> {
if (!githubInstallationToken) {
return;
}
const token = githubInstallationToken;
githubInstallationToken = undefined;
async function revokeGitHubInstallationToken(token: string): Promise<void> {
const apiUrl = process.env.GITHUB_API_URL || "https://api.github.com";
try {