Skip to content

Commit de7274f

Browse files
CopilotbrunoborgesCopilot
authored
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 <brborges@microsoft.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 32d31c8d-ddbc-4e57-a5c3-f70588fef3f3
1 parent 134912a commit de7274f

6 files changed

Lines changed: 108 additions & 15 deletions

File tree

‎__tests__/gpg.test.ts‎

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,18 @@ import {
99
} from '@jest/globals';
1010
import {fileURLToPath} from 'url';
1111
import * as fs from 'fs';
12+
import * as os from 'os';
1213
import * as path from 'path';
1314
import * as io from '@actions/io';
1415

1516
const __dirname = path.dirname(fileURLToPath(import.meta.url));
17+
const mockTmpDir = jest.fn(os.tmpdir);
18+
19+
jest.unstable_mockModule('os', () => ({
20+
...os,
21+
default: {...os, tmpdir: mockTmpDir},
22+
tmpdir: mockTmpDir
23+
}));
1624

1725
jest.unstable_mockModule('@actions/exec', () => ({
1826
exec: jest.fn()
@@ -34,6 +42,7 @@ describe('gpg tests', () => {
3442
await io.rmRF(tempDir);
3543
await io.mkdirP(tempDir);
3644
jest.clearAllMocks();
45+
mockTmpDir.mockImplementation(os.tmpdir);
3746
(exec.exec as jest.Mock<any>).mockResolvedValue(0);
3847
});
3948

@@ -222,6 +231,77 @@ describe('gpg tests', () => {
222231
});
223232

224233
describe('verifyPackageSignature', () => {
234+
describe.each(['long', 'canonical macOS'])('%s TMPDIR', tempDirKind => {
235+
afterEach(() => {
236+
process.env['RUNNER_TEMP'] = tempDir;
237+
});
238+
239+
it.each(['success', 'import failure', 'verification failure'])(
240+
'uses a short macOS home or RUNNER_TEMP elsewhere and cleans up after %s',
241+
async outcome => {
242+
const longRunnerTemp = path.join(
243+
tempDir,
244+
'long-runner-path-'.repeat(8)
245+
);
246+
const signaturePath = path.join(tempDir, 'jdk.tar.gz.sig');
247+
const expectedParent =
248+
process.platform === 'darwin' ? '/tmp' : longRunnerTemp;
249+
let gpgHome = '';
250+
process.env['RUNNER_TEMP'] = longRunnerTemp;
251+
mockTmpDir.mockReturnValue(
252+
tempDirKind === 'long'
253+
? longRunnerTemp
254+
: `/private/var/folders/ab/${'c'.repeat(31)}/T`
255+
);
256+
fs.mkdirSync(longRunnerTemp, {recursive: true});
257+
fs.writeFileSync(signaturePath, 'signature');
258+
(tc.downloadTool as jest.Mock<any>).mockResolvedValue(signaturePath);
259+
(exec.exec as jest.Mock<any>).mockImplementation(
260+
async (_command: string, args: string[]) => {
261+
gpgHome = path.join(expectedParent, path.posix.basename(args[1]));
262+
expect(args[1]).toBe(gpg.toGpgPath(gpgHome));
263+
if (process.platform === 'darwin') {
264+
expect(
265+
Buffer.byteLength(path.join(gpgHome, 'S.gpg-agent.browser'))
266+
).toBeLessThan(104);
267+
}
268+
expect(
269+
fs.readFileSync(path.join(gpgHome, 'public-key-0.asc'), 'utf8')
270+
).toBe('public key');
271+
if (process.platform !== 'win32') {
272+
expect(fs.statSync(gpgHome).mode & 0o777).toBe(0o700);
273+
}
274+
if (
275+
(outcome === 'import failure' && args.includes('--import')) ||
276+
(outcome === 'verification failure' &&
277+
args.includes('--verify'))
278+
) {
279+
throw new Error(outcome);
280+
}
281+
return 0;
282+
}
283+
);
284+
285+
const verification = gpg.verifyPackageSignature(
286+
path.join(tempDir, 'jdk.tar.gz'),
287+
'https://example.com/jdk.tar.gz.sig',
288+
'public key'
289+
);
290+
if (outcome === 'success') {
291+
await verification;
292+
} else {
293+
await expect(verification).rejects.toThrow(outcome);
294+
}
295+
expect(exec.exec).toHaveBeenCalledTimes(
296+
outcome === 'import failure' ? 1 : 2
297+
);
298+
expect(fs.existsSync(gpgHome)).toBe(false);
299+
expect(fs.existsSync(signaturePath)).toBe(false);
300+
expect(fs.readdirSync(longRunnerTemp)).toEqual([]);
301+
}
302+
);
303+
});
304+
225305
it('imports bundled key and verifies package', async () => {
226306
const publicKeyContent =
227307
'-----BEGIN PGP PUBLIC KEY BLOCK-----\ntest\n-----END PGP PUBLIC KEY BLOCK-----';

‎dist/cleanup/index.js‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35784,8 +35784,8 @@ function toGpgPath(p) {
3578435784
.replace(/\\/g, '/')
3578535785
.replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`);
3578635786
}
35787-
function createGpgHome(prefix) {
35788-
const gpgHome = fs.mkdtempSync(path.join(util.getTempDir(), prefix));
35787+
function createGpgHome(prefix, tempDir = util.getTempDir()) {
35788+
const gpgHome = fs.mkdtempSync(path.join(tempDir, prefix));
3578935789
if (process.platform !== 'win32') {
3579035790
fs.chmodSync(gpgHome, 0o700);
3579135791
}
@@ -35844,7 +35844,9 @@ async function verifyPackageSignature(archivePath, signatureUrl, publicKeyConten
3584435844
const signaturePath = await tc.downloadTool(signatureUrl);
3584535845
let gpgHome;
3584635846
try {
35847-
gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX);
35847+
// Both RUNNER_TEMP and TMPDIR can exceed macOS's 104-byte agent socket limit.
35848+
const tempDir = process.platform === 'darwin' ? '/tmp' : util.getTempDir();
35849+
gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX, tempDir);
3584835850
}
3584935851
catch (error) {
3585035852
try {

‎dist/setup/220.index.js‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,8 @@ function toGpgPath(p) {
215215
.replace(/\\/g, '/')
216216
.replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`);
217217
}
218-
function createGpgHome(prefix) {
219-
const gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(_util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4(), prefix));
218+
function createGpgHome(prefix, tempDir = _util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4()) {
219+
const gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(tempDir, prefix));
220220
if (process.platform !== 'win32') {
221221
fs__WEBPACK_IMPORTED_MODULE_0__.chmodSync(gpgHome, 0o700);
222222
}
@@ -275,7 +275,9 @@ async function verifyPackageSignature(archivePath, signatureUrl, publicKeyConten
275275
const signaturePath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_5__/* .downloadTool */ .bq(signatureUrl);
276276
let gpgHome;
277277
try {
278-
gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX);
278+
// Both RUNNER_TEMP and TMPDIR can exceed macOS's 104-byte agent socket limit.
279+
const tempDir = process.platform === 'darwin' ? '/tmp' : _util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4();
280+
gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX, tempDir);
279281
}
280282
catch (error) {
281283
try {

‎dist/setup/463.index.js‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -327,8 +327,8 @@ function toGpgPath(p) {
327327
.replace(/\\/g, '/')
328328
.replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`);
329329
}
330-
function createGpgHome(prefix) {
331-
const gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(_util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4(), prefix));
330+
function createGpgHome(prefix, tempDir = _util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4()) {
331+
const gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(tempDir, prefix));
332332
if (process.platform !== 'win32') {
333333
fs__WEBPACK_IMPORTED_MODULE_0__.chmodSync(gpgHome, 0o700);
334334
}
@@ -387,7 +387,9 @@ async function verifyPackageSignature(archivePath, signatureUrl, publicKeyConten
387387
const signaturePath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_5__/* .downloadTool */ .bq(signatureUrl);
388388
let gpgHome;
389389
try {
390-
gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX);
390+
// Both RUNNER_TEMP and TMPDIR can exceed macOS's 104-byte agent socket limit.
391+
const tempDir = process.platform === 'darwin' ? '/tmp' : _util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4();
392+
gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX, tempDir);
391393
}
392394
catch (error) {
393395
try {

‎dist/setup/81.index.js‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -302,8 +302,8 @@ function toGpgPath(p) {
302302
.replace(/\\/g, '/')
303303
.replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`);
304304
}
305-
function createGpgHome(prefix) {
306-
const gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(_util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4(), prefix));
305+
function createGpgHome(prefix, tempDir = _util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4()) {
306+
const gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(tempDir, prefix));
307307
if (process.platform !== 'win32') {
308308
fs__WEBPACK_IMPORTED_MODULE_0__.chmodSync(gpgHome, 0o700);
309309
}
@@ -362,7 +362,9 @@ async function verifyPackageSignature(archivePath, signatureUrl, publicKeyConten
362362
const signaturePath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_5__/* .downloadTool */ .bq(signatureUrl);
363363
let gpgHome;
364364
try {
365-
gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX);
365+
// Both RUNNER_TEMP and TMPDIR can exceed macOS's 104-byte agent socket limit.
366+
const tempDir = process.platform === 'darwin' ? '/tmp' : _util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4();
367+
gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX, tempDir);
366368
}
367369
catch (error) {
368370
try {

‎src/gpg.ts‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,11 @@ export function toGpgPath(p: string): string {
2626
.replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`);
2727
}
2828

29-
function createGpgHome(prefix: string): string {
30-
const gpgHome = fs.mkdtempSync(path.join(util.getTempDir(), prefix));
29+
function createGpgHome(
30+
prefix: string,
31+
tempDir: string = util.getTempDir()
32+
): string {
33+
const gpgHome = fs.mkdtempSync(path.join(tempDir, prefix));
3134
if (process.platform !== 'win32') {
3235
fs.chmodSync(gpgHome, 0o700);
3336
}
@@ -107,7 +110,9 @@ export async function verifyPackageSignature(
107110
const signaturePath = await tc.downloadTool(signatureUrl);
108111
let gpgHome: string;
109112
try {
110-
gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX);
113+
// Both RUNNER_TEMP and TMPDIR can exceed macOS's 104-byte agent socket limit.
114+
const tempDir = process.platform === 'darwin' ? '/tmp' : util.getTempDir();
115+
gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX, tempDir);
111116
} catch (error) {
112117
try {
113118
await io.rmRF(signaturePath);

0 commit comments

Comments
 (0)