From de7274f081f381c8f8158605e0321c36c376e2e6 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 9 Sep 2026 08:08:57 -0400 Subject: [PATCH] Avoid macOS GPG socket overflow on long runner paths (#1266) * Initial plan * Fix signature verification GPG homes on long runner paths * Keep macOS GPG verification homes within socket limits Use /tmp for signature verification on macOS while preserving runner temp behavior elsewhere. Cover long and canonical OS temp paths and regenerate action bundles. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 32d31c8d-ddbc-4e57-a5c3-f70588fef3f3 --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Bruno Borges Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 32d31c8d-ddbc-4e57-a5c3-f70588fef3f3 --- __tests__/gpg.test.ts | 80 +++++++++++++++++++++++++++++++++++++++++ dist/cleanup/index.js | 8 +++-- dist/setup/220.index.js | 8 +++-- dist/setup/463.index.js | 8 +++-- dist/setup/81.index.js | 8 +++-- src/gpg.ts | 11 ++++-- 6 files changed, 108 insertions(+), 15 deletions(-) diff --git a/__tests__/gpg.test.ts b/__tests__/gpg.test.ts index 2e411bcc..f9a0ca3c 100644 --- a/__tests__/gpg.test.ts +++ b/__tests__/gpg.test.ts @@ -9,10 +9,18 @@ import { } from '@jest/globals'; import {fileURLToPath} from 'url'; import * as fs from 'fs'; +import * as os from 'os'; import * as path from 'path'; import * as io from '@actions/io'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const mockTmpDir = jest.fn(os.tmpdir); + +jest.unstable_mockModule('os', () => ({ + ...os, + default: {...os, tmpdir: mockTmpDir}, + tmpdir: mockTmpDir +})); jest.unstable_mockModule('@actions/exec', () => ({ exec: jest.fn() @@ -34,6 +42,7 @@ describe('gpg tests', () => { await io.rmRF(tempDir); await io.mkdirP(tempDir); jest.clearAllMocks(); + mockTmpDir.mockImplementation(os.tmpdir); (exec.exec as jest.Mock).mockResolvedValue(0); }); @@ -222,6 +231,77 @@ describe('gpg tests', () => { }); describe('verifyPackageSignature', () => { + describe.each(['long', 'canonical macOS'])('%s TMPDIR', tempDirKind => { + afterEach(() => { + process.env['RUNNER_TEMP'] = tempDir; + }); + + it.each(['success', 'import failure', 'verification failure'])( + 'uses a short macOS home or RUNNER_TEMP elsewhere and cleans up after %s', + async outcome => { + const longRunnerTemp = path.join( + tempDir, + 'long-runner-path-'.repeat(8) + ); + const signaturePath = path.join(tempDir, 'jdk.tar.gz.sig'); + const expectedParent = + process.platform === 'darwin' ? '/tmp' : longRunnerTemp; + let gpgHome = ''; + process.env['RUNNER_TEMP'] = longRunnerTemp; + mockTmpDir.mockReturnValue( + tempDirKind === 'long' + ? longRunnerTemp + : `/private/var/folders/ab/${'c'.repeat(31)}/T` + ); + fs.mkdirSync(longRunnerTemp, {recursive: true}); + fs.writeFileSync(signaturePath, 'signature'); + (tc.downloadTool as jest.Mock).mockResolvedValue(signaturePath); + (exec.exec as jest.Mock).mockImplementation( + async (_command: string, args: string[]) => { + gpgHome = path.join(expectedParent, path.posix.basename(args[1])); + expect(args[1]).toBe(gpg.toGpgPath(gpgHome)); + if (process.platform === 'darwin') { + expect( + Buffer.byteLength(path.join(gpgHome, 'S.gpg-agent.browser')) + ).toBeLessThan(104); + } + expect( + fs.readFileSync(path.join(gpgHome, 'public-key-0.asc'), 'utf8') + ).toBe('public key'); + if (process.platform !== 'win32') { + expect(fs.statSync(gpgHome).mode & 0o777).toBe(0o700); + } + if ( + (outcome === 'import failure' && args.includes('--import')) || + (outcome === 'verification failure' && + args.includes('--verify')) + ) { + throw new Error(outcome); + } + return 0; + } + ); + + const verification = gpg.verifyPackageSignature( + path.join(tempDir, 'jdk.tar.gz'), + 'https://example.com/jdk.tar.gz.sig', + 'public key' + ); + if (outcome === 'success') { + await verification; + } else { + await expect(verification).rejects.toThrow(outcome); + } + expect(exec.exec).toHaveBeenCalledTimes( + outcome === 'import failure' ? 1 : 2 + ); + expect(fs.existsSync(gpgHome)).toBe(false); + expect(fs.existsSync(signaturePath)).toBe(false); + expect(fs.readdirSync(longRunnerTemp)).toEqual([]); + } + ); + }); + it('imports bundled key and verifies package', async () => { const publicKeyContent = '-----BEGIN PGP PUBLIC KEY BLOCK-----\ntest\n-----END PGP PUBLIC KEY BLOCK-----'; diff --git a/dist/cleanup/index.js b/dist/cleanup/index.js index 934dff64..00ad7724 100644 --- a/dist/cleanup/index.js +++ b/dist/cleanup/index.js @@ -35784,8 +35784,8 @@ function toGpgPath(p) { .replace(/\\/g, '/') .replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`); } -function createGpgHome(prefix) { - const gpgHome = fs.mkdtempSync(path.join(util.getTempDir(), prefix)); +function createGpgHome(prefix, tempDir = util.getTempDir()) { + const gpgHome = fs.mkdtempSync(path.join(tempDir, prefix)); if (process.platform !== 'win32') { fs.chmodSync(gpgHome, 0o700); } @@ -35844,7 +35844,9 @@ async function verifyPackageSignature(archivePath, signatureUrl, publicKeyConten const signaturePath = await tc.downloadTool(signatureUrl); let gpgHome; try { - gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX); + // Both RUNNER_TEMP and TMPDIR can exceed macOS's 104-byte agent socket limit. + const tempDir = process.platform === 'darwin' ? '/tmp' : util.getTempDir(); + gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX, tempDir); } catch (error) { try { diff --git a/dist/setup/220.index.js b/dist/setup/220.index.js index b1af6f1a..f5cfebc7 100644 --- a/dist/setup/220.index.js +++ b/dist/setup/220.index.js @@ -215,8 +215,8 @@ function toGpgPath(p) { .replace(/\\/g, '/') .replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`); } -function createGpgHome(prefix) { - const gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(_util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4(), prefix)); +function createGpgHome(prefix, tempDir = _util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4()) { + const gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(tempDir, prefix)); if (process.platform !== 'win32') { fs__WEBPACK_IMPORTED_MODULE_0__.chmodSync(gpgHome, 0o700); } @@ -275,7 +275,9 @@ async function verifyPackageSignature(archivePath, signatureUrl, publicKeyConten const signaturePath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_5__/* .downloadTool */ .bq(signatureUrl); let gpgHome; try { - gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX); + // Both RUNNER_TEMP and TMPDIR can exceed macOS's 104-byte agent socket limit. + const tempDir = process.platform === 'darwin' ? '/tmp' : _util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4(); + gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX, tempDir); } catch (error) { try { diff --git a/dist/setup/463.index.js b/dist/setup/463.index.js index c07adf58..02b5bfc9 100644 --- a/dist/setup/463.index.js +++ b/dist/setup/463.index.js @@ -327,8 +327,8 @@ function toGpgPath(p) { .replace(/\\/g, '/') .replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`); } -function createGpgHome(prefix) { - const gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(_util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4(), prefix)); +function createGpgHome(prefix, tempDir = _util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4()) { + const gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(tempDir, prefix)); if (process.platform !== 'win32') { fs__WEBPACK_IMPORTED_MODULE_0__.chmodSync(gpgHome, 0o700); } @@ -387,7 +387,9 @@ async function verifyPackageSignature(archivePath, signatureUrl, publicKeyConten const signaturePath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_5__/* .downloadTool */ .bq(signatureUrl); let gpgHome; try { - gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX); + // Both RUNNER_TEMP and TMPDIR can exceed macOS's 104-byte agent socket limit. + const tempDir = process.platform === 'darwin' ? '/tmp' : _util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4(); + gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX, tempDir); } catch (error) { try { diff --git a/dist/setup/81.index.js b/dist/setup/81.index.js index eb322254..3ac82d8f 100644 --- a/dist/setup/81.index.js +++ b/dist/setup/81.index.js @@ -302,8 +302,8 @@ function toGpgPath(p) { .replace(/\\/g, '/') .replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`); } -function createGpgHome(prefix) { - const gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(_util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4(), prefix)); +function createGpgHome(prefix, tempDir = _util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4()) { + const gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(tempDir, prefix)); if (process.platform !== 'win32') { fs__WEBPACK_IMPORTED_MODULE_0__.chmodSync(gpgHome, 0o700); } @@ -362,7 +362,9 @@ async function verifyPackageSignature(archivePath, signatureUrl, publicKeyConten const signaturePath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_5__/* .downloadTool */ .bq(signatureUrl); let gpgHome; try { - gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX); + // Both RUNNER_TEMP and TMPDIR can exceed macOS's 104-byte agent socket limit. + const tempDir = process.platform === 'darwin' ? '/tmp' : _util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4(); + gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX, tempDir); } catch (error) { try { diff --git a/src/gpg.ts b/src/gpg.ts index 0d4f76aa..b522d126 100644 --- a/src/gpg.ts +++ b/src/gpg.ts @@ -26,8 +26,11 @@ export function toGpgPath(p: string): string { .replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`); } -function createGpgHome(prefix: string): string { - const gpgHome = fs.mkdtempSync(path.join(util.getTempDir(), prefix)); +function createGpgHome( + prefix: string, + tempDir: string = util.getTempDir() +): string { + const gpgHome = fs.mkdtempSync(path.join(tempDir, prefix)); if (process.platform !== 'win32') { fs.chmodSync(gpgHome, 0o700); } @@ -107,7 +110,9 @@ export async function verifyPackageSignature( const signaturePath = await tc.downloadTool(signatureUrl); let gpgHome: string; try { - gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX); + // Both RUNNER_TEMP and TMPDIR can exceed macOS's 104-byte agent socket limit. + const tempDir = process.platform === 'darwin' ? '/tmp' : util.getTempDir(); + gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX, tempDir); } catch (error) { try { await io.rmRF(signaturePath);