Import Maven signing keys into an isolated GPG home (#1214)

* Isolate Maven signing keys

Import signing keys into an action-owned temporary GPG home, export GNUPGHOME, and remove the owned directory in the post action. Cover import failure, multiple keys and invocations, unrelated keyrings, missing state, and Windows path conversion.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Fix cleanup state assertion

Account for isolated GPG-home cleanup when cache saving is disabled.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Update generated action bundles

Apply repository formatting and commit the setup and cleanup bundles produced by the validated Node 24 build.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

* Address isolated GPG home review feedback

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Bruno Borges <brborges@microsoft.com>
This commit is contained in:
Julien Dubois
2026-08-05 18:05:36 +02:00
committed by GitHub
parent f4bfb3ddea
commit 634b0f0d18
17 changed files with 715 additions and 309 deletions
+1 -1
View File
@@ -172,7 +172,7 @@ steps:
| `server-password-env-var` | Environment variable name for Maven repository password or token. | `GITHUB_TOKEN` | | `server-password-env-var` | Environment variable name for Maven repository password or token. | `GITHUB_TOKEN` |
| `settings-path` | Directory where `settings.xml` is written. | `~/.m2` | | `settings-path` | Directory where `settings.xml` is written. | `~/.m2` |
| `overwrite-settings` | Overwrite an existing `settings.xml`. | `true` | | `overwrite-settings` | Overwrite an existing `settings.xml`. | `true` |
| `gpg-private-key` | GPG private key to import. | | | `gpg-private-key` | GPG private key to import into an isolated temporary keyring. | |
| `gpg-passphrase-env-var` | Environment variable name for the GPG private key passphrase. | `GPG_PASSPHRASE` when a key is set | | `gpg-passphrase-env-var` | Environment variable name for the GPG private key passphrase. | `GPG_PASSPHRASE` when a key is set |
| `mvn-toolchain-id` | Maven Toolchain ID. When multiple Java versions are installed, the number of IDs must match the number of versions. | `${mvn-toolchain-vendor}_${java-version}` | | `mvn-toolchain-id` | Maven Toolchain ID. When multiple Java versions are installed, the number of IDs must match the number of versions. | `${mvn-toolchain-vendor}_${java-version}` |
| `mvn-toolchain-vendor` | Maven Toolchain vendor value. | `${distribution}` | | `mvn-toolchain-vendor` | Maven Toolchain vendor value. | `${distribution}` |
+64 -1
View File
@@ -41,10 +41,18 @@ jest.unstable_mockModule('@actions/core', () => ({
toPosixPath: jest.fn((p: string) => p) toPosixPath: jest.fn((p: string) => p)
})); }));
jest.unstable_mockModule('../src/gpg.js', () => ({
importKey: jest.fn(),
removeGpgHome: jest.fn(),
toGpgPath: jest.fn()
}));
// Dynamic imports after mocking // Dynamic imports after mocking
const core = await import('@actions/core'); const core = await import('@actions/core');
const gpg = await import('../src/gpg.js');
const auth = await import('../src/auth.js'); const auth = await import('../src/auth.js');
const {M2_DIR, MVN_SETTINGS_FILE} = await import('../src/constants.js'); const {M2_DIR, MVN_SETTINGS_FILE, STATE_GPG_HOME} =
await import('../src/constants.js');
const __dirname = path.dirname(fileURLToPath(import.meta.url)); const __dirname = path.dirname(fileURLToPath(import.meta.url));
const m2Dir = path.join(__dirname, M2_DIR); const m2Dir = path.join(__dirname, M2_DIR);
@@ -60,8 +68,17 @@ describe('auth tests', () => {
spyOSHomedir.mockReturnValue(__dirname); spyOSHomedir.mockReturnValue(__dirname);
spyInfo = core.info as jest.Mock; spyInfo = core.info as jest.Mock;
spyInfo.mockImplementation(() => null); spyInfo.mockImplementation(() => null);
(gpg.toGpgPath as jest.Mock<any>).mockImplementation((p: string) => p);
}, 300000); }, 300000);
afterEach(() => {
(core.getInput as jest.Mock).mockReset();
(core.exportVariable as jest.Mock).mockReset();
(gpg.importKey as jest.Mock).mockReset();
(gpg.removeGpgHome as jest.Mock).mockReset();
(gpg.toGpgPath as jest.Mock).mockReset();
});
afterAll(async () => { afterAll(async () => {
try { try {
await io.rmRF(m2Dir); await io.rmRF(m2Dir);
@@ -144,6 +161,52 @@ describe('auth tests', () => {
); );
}, 100000); }, 100000);
it('exports a GPG-compatible path and persists the native GPG home', async () => {
const gpgHome = 'D:\\a\\_temp\\setup-java-gpg-1';
const exportedGpgHome = '/d/a/_temp/setup-java-gpg-1';
(gpg.importKey as jest.Mock<any>).mockResolvedValue(gpgHome);
(gpg.toGpgPath as jest.Mock<any>).mockReturnValue(exportedGpgHome);
(core.getInput as jest.Mock<any>).mockImplementation((name: string) => {
const inputs: Record<string, string> = {
'server-id': 'packages',
'server-username-env-var': 'USERNAME',
'server-password-env-var': 'PASSWORD',
'settings-path': m2Dir,
'gpg-private-key': 'KEY ONE\nKEY TWO'
};
return inputs[name] ?? '';
});
await auth.configureAuthentication();
expect(gpg.importKey).toHaveBeenCalledWith('KEY ONE\nKEY TWO');
expect(core.saveState).toHaveBeenCalledWith(STATE_GPG_HOME, gpgHome);
expect(gpg.toGpgPath).toHaveBeenCalledWith(gpgHome);
expect(core.exportVariable).toHaveBeenCalledWith(
'GNUPGHOME',
exportedGpgHome
);
});
it('removes the isolated GPG home when environment export fails', async () => {
const gpgHome = path.join(__dirname, 'runner', 'temp', 'setup-java-gpg-2');
(gpg.importKey as jest.Mock<any>).mockResolvedValue(gpgHome);
(core.exportVariable as jest.Mock<any>).mockImplementation(() => {
throw new Error('environment file unavailable');
});
(core.getInput as jest.Mock<any>).mockImplementation((name: string) => {
if (name === 'gpg-private-key') return 'KEY CONTENTS';
if (name === 'settings-path') return m2Dir;
return '';
});
await expect(auth.configureAuthentication()).rejects.toThrow(
'environment file unavailable'
);
expect(gpg.removeGpgHome).toHaveBeenCalledWith(gpgHome);
});
it('overwrites existing settings.xml files', async () => { it('overwrites existing settings.xml files', async () => {
const id = 'packages'; const id = 'packages';
const username = 'USERNAME'; const username = 'USERNAME';
+58 -1
View File
@@ -63,6 +63,8 @@ const core = await import('@actions/core');
const cache = await import('@actions/cache'); const cache = await import('@actions/cache');
const {run: cleanup} = await import('../src/cleanup-java.js'); const {run: cleanup} = await import('../src/cleanup-java.js');
const util = await import('../src/util.js'); const util = await import('../src/util.js');
const constants = await import('../src/constants.js');
const {GPG_HOME_PREFIX} = await import('../src/gpg.js');
const {registerJdk, buildJdkCacheKey} = await import('../src/jdk-cache.js'); const {registerJdk, buildJdkCacheKey} = await import('../src/jdk-cache.js');
const jdkTempRoots: string[] = []; const jdkTempRoots: string[] = [];
@@ -114,11 +116,65 @@ describe('cleanup', () => {
(core.getInput as jest.Mock<any>).mockImplementation((name: string) => { (core.getInput as jest.Mock<any>).mockImplementation((name: string) => {
return name === 'cache' ? 'gradle' : ''; return name === 'cache' ? 'gradle' : '';
}); });
await cleanup(); await cleanup();
expect(spyCacheSave).toHaveBeenCalled(); expect(spyCacheSave).toHaveBeenCalled();
expect(spyWarning).not.toHaveBeenCalled(); expect(spyWarning).not.toHaveBeenCalled();
}); });
it('removes the isolated GPG home without touching unrelated key material', async () => {
const tempDir = util.getTempDir();
fs.mkdirSync(tempDir, {recursive: true});
const gpgHome = fs.mkdtempSync(path.join(tempDir, GPG_HOME_PREFIX));
const unrelatedGpgHome = fs.mkdtempSync(
path.join(tempDir, 'user-gpg-home-')
);
fs.writeFileSync(
path.join(unrelatedGpgHome, 'private.key'),
'pre-existing'
);
(core.getInput as jest.Mock<any>).mockReturnValue('');
(core.getState as jest.Mock<any>).mockImplementation((name: string) =>
name === constants.STATE_GPG_HOME ? gpgHome : ''
);
await cleanup();
expect(fs.existsSync(gpgHome)).toBe(false);
expect(
fs.readFileSync(path.join(unrelatedGpgHome, 'private.key'), 'utf8')
).toBe('pre-existing');
fs.rmSync(unrelatedGpgHome, {recursive: true, force: true});
});
it('makes repeated cleanup of the same GPG home idempotent', async () => {
const tempDir = util.getTempDir();
fs.mkdirSync(tempDir, {recursive: true});
const gpgHome = fs.mkdtempSync(path.join(tempDir, GPG_HOME_PREFIX));
(core.getInput as jest.Mock<any>).mockReturnValue('');
(core.getState as jest.Mock<any>).mockImplementation((name: string) =>
name === constants.STATE_GPG_HOME ? gpgHome : ''
);
await cleanup();
await cleanup();
expect(fs.existsSync(gpgHome)).toBe(false);
expect(core.setFailed).not.toHaveBeenCalled();
});
it('skips GPG cleanup when no home was persisted', async () => {
(core.getInput as jest.Mock<any>).mockReturnValue('');
(core.getState as jest.Mock<any>).mockReturnValue('');
await cleanup();
expect(spyInfo).not.toHaveBeenCalledWith(
'Removing private key from isolated GPG home'
);
expect(core.setFailed).not.toHaveBeenCalled();
});
it('does not fail even though the save process throws error', async () => { it('does not fail even though the save process throws error', async () => {
spyCacheSave.mockImplementation((paths: string[], key: string) => spyCacheSave.mockImplementation((paths: string[], key: string) =>
Promise.reject(new Error('Unexpected error')) Promise.reject(new Error('Unexpected error'))
@@ -148,7 +204,8 @@ describe('cleanup', () => {
await cleanup(); await cleanup();
expect(spyCacheSave).not.toHaveBeenCalled(); expect(spyCacheSave).not.toHaveBeenCalled();
expect(core.getState).not.toHaveBeenCalled(); expect(core.getState).toHaveBeenCalledTimes(1);
expect(core.getState).toHaveBeenCalledWith(constants.STATE_GPG_HOME);
expect(spyInfo).toHaveBeenCalledWith( expect(spyInfo).toHaveBeenCalledWith(
'Cache saving is skipped because cache-read-only is enabled.' 'Cache saving is skipped because cache-read-only is enabled.'
); );
@@ -86,7 +86,7 @@ jest.unstable_mockModule('../../src/util.js', () => ({
jest.unstable_mockModule('../../src/gpg.js', () => ({ jest.unstable_mockModule('../../src/gpg.js', () => ({
importKey: jest.fn(), importKey: jest.fn(),
deleteKey: jest.fn(), removeGpgHome: jest.fn(),
verifyPackageSignature: jest.fn() verifyPackageSignature: jest.fn()
})); }));
@@ -72,7 +72,7 @@ jest.unstable_mockModule('../../src/util.js', () => ({
jest.unstable_mockModule('../../src/gpg.js', () => ({ jest.unstable_mockModule('../../src/gpg.js', () => ({
importKey: jest.fn(), importKey: jest.fn(),
deleteKey: jest.fn(), removeGpgHome: jest.fn(),
verifyPackageSignature: jest.fn() verifyPackageSignature: jest.fn()
})); }));
+177 -54
View File
@@ -8,6 +8,7 @@ import {
afterEach afterEach
} from '@jest/globals'; } from '@jest/globals';
import {fileURLToPath} from 'url'; import {fileURLToPath} from 'url';
import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import * as io from '@actions/io'; import * as io from '@actions/io';
@@ -30,7 +31,10 @@ process.env['RUNNER_TEMP'] = tempDir;
describe('gpg tests', () => { describe('gpg tests', () => {
beforeEach(async () => { beforeEach(async () => {
await io.rmRF(tempDir);
await io.mkdirP(tempDir); await io.mkdirP(tempDir);
jest.clearAllMocks();
(exec.exec as jest.Mock<any>).mockResolvedValue(0);
}); });
afterAll(async () => { afterAll(async () => {
@@ -71,74 +75,193 @@ describe('gpg tests', () => {
}); });
describe('importKey', () => { describe('importKey', () => {
it('attempts to import private key and returns null key id on failure', async () => { it('imports private keys into a unique isolated GPG home', async () => {
const privateKey = 'KEY CONTENTS'; const privateKey = 'KEY CONTENTS';
const keyId = await gpg.importKey(privateKey); let privateKeyFile = '';
(exec.exec as jest.Mock<any>).mockImplementation(
async (_command: string, _args: string[]) => {
const [createdGpgHome] = fs.readdirSync(tempDir);
privateKeyFile = path.join(
tempDir,
createdGpgHome,
fs
.readdirSync(path.join(tempDir, createdGpgHome))
.find(file => file.startsWith('private-key-')) ?? ''
);
expect(fs.readFileSync(privateKeyFile, 'utf8')).toBe(privateKey);
if (process.platform !== 'win32') {
expect(fs.statSync(privateKeyFile).mode & 0o777).toBe(0o600);
}
return 0;
}
);
expect(keyId).toBeNull(); const gpgHome = await gpg.importKey(privateKey);
expect(path.dirname(gpgHome)).toBe(tempDir);
expect(path.basename(gpgHome).startsWith(gpg.GPG_HOME_PREFIX)).toBe(true);
expect(fs.existsSync(gpgHome)).toBe(true);
expect(fs.existsSync(privateKeyFile)).toBe(false);
if (process.platform !== 'win32') {
expect(fs.statSync(gpgHome).mode & 0o777).toBe(0o700);
}
expect(exec.exec).toHaveBeenCalledWith( expect(exec.exec).toHaveBeenCalledWith(
'gpg', 'gpg',
expect.anything(), [
expect.anything() '--homedir',
gpg.toGpgPath(gpgHome),
'--batch',
'--import',
gpg.toGpgPath(privateKeyFile)
],
{silent: true}
); );
}); });
it('removes the private-key file and isolated home when import fails', async () => {
let gpgHome = '';
let privateKeyFile = '';
(exec.exec as jest.Mock<any>).mockImplementation(
async (_command: string, _args: string[]) => {
const [createdGpgHome] = fs.readdirSync(tempDir);
gpgHome = path.join(tempDir, createdGpgHome);
privateKeyFile = path.join(
gpgHome,
fs
.readdirSync(gpgHome)
.find(file => file.startsWith('private-key-')) ?? ''
);
expect(fs.existsSync(privateKeyFile)).toBe(true);
throw new Error('invalid key');
}
);
await expect(gpg.importKey('INVALID KEY')).rejects.toThrow('invalid key');
expect(fs.existsSync(privateKeyFile)).toBe(false);
expect(fs.existsSync(gpgHome)).toBe(false);
});
it('imports multi-key input without parsing or deleting fingerprints', async () => {
const privateKeys = 'KEY ONE\nKEY TWO';
(exec.exec as jest.Mock<any>).mockImplementation(
async (_command: string, _args: string[]) => {
const [createdGpgHome] = fs.readdirSync(tempDir);
const keyFile = fs
.readdirSync(path.join(tempDir, createdGpgHome))
.find(file => file.startsWith('private-key-'));
expect(
fs.readFileSync(
path.join(tempDir, createdGpgHome, keyFile ?? ''),
'utf8'
)
).toBe(privateKeys);
return 0;
}
);
const gpgHome = await gpg.importKey(privateKeys);
expect(gpgHome).toContain(gpg.GPG_HOME_PREFIX);
expect(exec.exec).toHaveBeenCalledTimes(1);
expect((exec.exec as jest.Mock).mock.calls[0][1]).not.toContain(
'--delete-secret-and-public-key'
);
});
it('uses a separate GPG home for each invocation', async () => {
const firstGpgHome = await gpg.importKey('FIRST KEY');
const secondGpgHome = await gpg.importKey('SECOND KEY');
expect(firstGpgHome).not.toBe(secondGpgHome);
expect(fs.existsSync(firstGpgHome)).toBe(true);
expect(fs.existsSync(secondGpgHome)).toBe(true);
});
}); });
describe('deleteKey', () => { describe('removeGpgHome', () => {
it('deletes private key', async () => { it('removes only action-owned GPG homes and is idempotent', async () => {
const keyId = 'asdfhjkl'; const gpgHome = await gpg.importKey('KEY CONTENTS');
await gpg.deleteKey(keyId); const unrelatedGpgHome = path.join(tempDir, 'user-gpg-home');
fs.mkdirSync(unrelatedGpgHome);
expect(exec.exec).toHaveBeenCalledWith( await gpg.removeGpgHome(gpgHome);
'gpg', await gpg.removeGpgHome(gpgHome);
expect.anything(),
expect.anything() expect(exec.exec).toHaveBeenNthCalledWith(
2,
'gpgconf',
['--homedir', gpg.toGpgPath(gpgHome), '--kill', 'gpg-agent'],
{silent: true, ignoreReturnCode: true}
); );
expect(exec.exec).toHaveBeenCalledTimes(2);
expect(fs.existsSync(gpgHome)).toBe(false);
expect(fs.existsSync(unrelatedGpgHome)).toBe(true);
}); });
describe('verifyPackageSignature', () => { it('removes the GPG home when gpgconf is unavailable', async () => {
it('imports bundled key and verifies package', async () => { const gpgHome = await gpg.importKey('KEY CONTENTS');
const publicKeyContent = (exec.exec as jest.Mock<any>).mockRejectedValueOnce(
'-----BEGIN PGP PUBLIC KEY BLOCK-----\ntest\n-----END PGP PUBLIC KEY BLOCK-----'; new Error('gpgconf not found')
(tc.downloadTool as jest.Mock<any>).mockResolvedValue( );
'/tmp/jdk.tar.gz.sig'
);
await gpg.verifyPackageSignature(
'/tmp/jdk.tar.gz',
'https://example.com/jdk.tar.gz.sig',
publicKeyContent
);
expect(tc.downloadTool).toHaveBeenCalledWith( await gpg.removeGpgHome(gpgHome);
'https://example.com/jdk.tar.gz.sig'
); expect(fs.existsSync(gpgHome)).toBe(false);
expect(exec.exec).toHaveBeenNthCalledWith( });
1,
'gpg', it('refuses to remove a GPG home it does not own', async () => {
[ const unrelatedGpgHome = path.join(tempDir, 'user-gpg-home');
'--homedir', fs.mkdirSync(unrelatedGpgHome, {recursive: true});
expect.any(String),
'--batch', await expect(gpg.removeGpgHome(unrelatedGpgHome)).rejects.toThrow(
'--import', 'Refusing to remove unexpected GPG home'
expect.stringContaining('public-key.asc') );
], expect(fs.existsSync(unrelatedGpgHome)).toBe(true);
expect.objectContaining({silent: true}) });
); });
expect(exec.exec).toHaveBeenNthCalledWith(
2, describe('verifyPackageSignature', () => {
'gpg', it('imports bundled key and verifies package', async () => {
[ const publicKeyContent =
'--homedir', '-----BEGIN PGP PUBLIC KEY BLOCK-----\ntest\n-----END PGP PUBLIC KEY BLOCK-----';
expect.any(String), (tc.downloadTool as jest.Mock<any>).mockResolvedValue(
'--batch', '/tmp/jdk.tar.gz.sig'
'--verify', );
'/tmp/jdk.tar.gz.sig', await gpg.verifyPackageSignature(
'/tmp/jdk.tar.gz' '/tmp/jdk.tar.gz',
], 'https://example.com/jdk.tar.gz.sig',
expect.objectContaining({silent: true}) publicKeyContent
); );
});
expect(tc.downloadTool).toHaveBeenCalledWith(
'https://example.com/jdk.tar.gz.sig'
);
expect(exec.exec).toHaveBeenNthCalledWith(
1,
'gpg',
[
'--homedir',
expect.any(String),
'--batch',
'--import',
expect.stringContaining('public-key.asc')
],
expect.objectContaining({silent: true})
);
expect(exec.exec).toHaveBeenNthCalledWith(
2,
'gpg',
[
'--homedir',
expect.any(String),
'--batch',
'--verify',
'/tmp/jdk.tar.gz.sig',
'/tmp/jdk.tar.gz'
],
expect.objectContaining({silent: true})
);
}); });
}); });
}); });
+1 -1
View File
@@ -72,7 +72,7 @@ inputs:
required: false required: false
default: true default: true
gpg-private-key: gpg-private-key:
description: 'GPG private key to import. Default is empty string.' description: 'GPG private key to import into an isolated temporary keyring. Default is empty string.'
required: false required: false
default: '' default: ''
gpg-passphrase-env-var: gpg-passphrase-env-var:
+83 -52
View File
@@ -30769,13 +30769,12 @@ module.exports = {
/* harmony export */ __nccwpck_require__.d(__webpack_exports__, { /* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
/* harmony export */ Ch: () => (/* binding */ INPUT_CACHE_READ_ONLY), /* harmony export */ Ch: () => (/* binding */ INPUT_CACHE_READ_ONLY),
/* harmony export */ Fi: () => (/* binding */ STATE_GPG_HOME),
/* harmony export */ GL: () => (/* binding */ INPUT_CACHE_JDK), /* harmony export */ GL: () => (/* binding */ INPUT_CACHE_JDK),
/* harmony export */ gk: () => (/* binding */ INPUT_CACHE), /* harmony export */ gk: () => (/* binding */ INPUT_CACHE),
/* harmony export */ wG: () => (/* binding */ INPUT_JOB_STATUS), /* harmony export */ wG: () => (/* binding */ INPUT_JOB_STATUS)
/* harmony export */ wm: () => (/* binding */ STATE_GPG_PRIVATE_KEY_FINGERPRINT),
/* harmony export */ wz: () => (/* binding */ INPUT_GPG_PRIVATE_KEY)
/* harmony export */ }); /* harmony export */ });
/* unused harmony exports MACOS_JAVA_CONTENT_POSTFIX, INPUT_JAVA_VERSION, INPUT_JAVA_VERSION_FILE, INPUT_ARCHITECTURE, INPUT_JAVA_PACKAGE, INPUT_DISTRIBUTION, INPUT_JDK_FILE, INPUT_JDK_FILE_DEPRECATED, INPUT_CHECK_LATEST, INPUT_FORCE_DOWNLOAD, INPUT_SET_DEFAULT, INPUT_PROBLEM_MATCHER, INPUT_VERIFY_SIGNATURE, INPUT_VERIFY_SIGNATURE_PUBLIC_KEY, INPUT_SERVER_ID, INPUT_SERVER_USERNAME_ENV_VAR, INPUT_SERVER_PASSWORD_ENV_VAR, INPUT_SERVER_USERNAME_DEPRECATED, INPUT_SERVER_PASSWORD_DEPRECATED, INPUT_SETTINGS_PATH, INPUT_OVERWRITE_SETTINGS, INPUT_GPG_PASSPHRASE_ENV_VAR, INPUT_GPG_PASSPHRASE_DEPRECATED, INPUT_DEFAULT_SERVER_USERNAME, INPUT_DEFAULT_SERVER_PASSWORD, INPUT_DEFAULT_GPG_PRIVATE_KEY, INPUT_DEFAULT_GPG_PASSPHRASE, MAVEN_GPG_PASSPHRASE_DEFAULT_ENV, GPG_PASSPHRASE_PROFILE_ID, INPUT_CACHE_DEPENDENCY_PATH, INPUT_CACHE_PATH, M2_DIR, MVN_SETTINGS_FILE, MVN_TOOLCHAINS_FILE, INPUT_MVN_TOOLCHAIN_ID, INPUT_MVN_TOOLCHAIN_VENDOR, INPUT_SHOW_DOWNLOAD_PROGRESS, MAVEN_ARGS_ENV, MAVEN_NO_TRANSFER_PROGRESS_FLAG, MAVEN_NO_TRANSFER_PROGRESS_LONG_FLAG, DISTRIBUTIONS_ONLY_MAJOR_VERSION */ /* unused harmony exports MACOS_JAVA_CONTENT_POSTFIX, INPUT_JAVA_VERSION, INPUT_JAVA_VERSION_FILE, INPUT_ARCHITECTURE, INPUT_JAVA_PACKAGE, INPUT_DISTRIBUTION, INPUT_JDK_FILE, INPUT_JDK_FILE_DEPRECATED, INPUT_CHECK_LATEST, INPUT_FORCE_DOWNLOAD, INPUT_SET_DEFAULT, INPUT_PROBLEM_MATCHER, INPUT_VERIFY_SIGNATURE, INPUT_VERIFY_SIGNATURE_PUBLIC_KEY, INPUT_SERVER_ID, INPUT_SERVER_USERNAME_ENV_VAR, INPUT_SERVER_PASSWORD_ENV_VAR, INPUT_SERVER_USERNAME_DEPRECATED, INPUT_SERVER_PASSWORD_DEPRECATED, INPUT_SETTINGS_PATH, INPUT_OVERWRITE_SETTINGS, INPUT_GPG_PRIVATE_KEY, INPUT_GPG_PASSPHRASE_ENV_VAR, INPUT_GPG_PASSPHRASE_DEPRECATED, INPUT_DEFAULT_SERVER_USERNAME, INPUT_DEFAULT_SERVER_PASSWORD, INPUT_DEFAULT_GPG_PRIVATE_KEY, INPUT_DEFAULT_GPG_PASSPHRASE, MAVEN_GPG_PASSPHRASE_DEFAULT_ENV, GPG_PASSPHRASE_PROFILE_ID, INPUT_CACHE_DEPENDENCY_PATH, INPUT_CACHE_PATH, M2_DIR, MVN_SETTINGS_FILE, MVN_TOOLCHAINS_FILE, INPUT_MVN_TOOLCHAIN_ID, INPUT_MVN_TOOLCHAIN_VENDOR, INPUT_SHOW_DOWNLOAD_PROGRESS, MAVEN_ARGS_ENV, MAVEN_NO_TRANSFER_PROGRESS_FLAG, MAVEN_NO_TRANSFER_PROGRESS_LONG_FLAG, DISTRIBUTIONS_ONLY_MAJOR_VERSION */
const MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home'; const MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home';
const INPUT_JAVA_VERSION = 'java-version'; const INPUT_JAVA_VERSION = 'java-version';
const INPUT_JAVA_VERSION_FILE = 'java-version-file'; const INPUT_JAVA_VERSION_FILE = 'java-version-file';
@@ -30816,7 +30815,7 @@ const INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path';
const INPUT_CACHE_PATH = 'cache-path'; const INPUT_CACHE_PATH = 'cache-path';
const INPUT_CACHE_READ_ONLY = 'cache-read-only'; const INPUT_CACHE_READ_ONLY = 'cache-read-only';
const INPUT_JOB_STATUS = 'job-status'; const INPUT_JOB_STATUS = 'job-status';
const STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint'; const STATE_GPG_HOME = 'gpg-home';
const M2_DIR = '.m2'; const M2_DIR = '.m2';
const MVN_SETTINGS_FILE = 'settings.xml'; const MVN_SETTINGS_FILE = 'settings.xml';
const MVN_TOOLCHAINS_FILE = 'toolchains.xml'; const MVN_TOOLCHAINS_FILE = 'toolchains.xml';
@@ -34222,10 +34221,11 @@ const lowercaseKeys = (obj) => Object.keys(obj).reduce((c, k) => ((c[k.toLowerCa
/* harmony export */ Ck: () => (/* binding */ mkdir), /* harmony export */ Ck: () => (/* binding */ mkdir),
/* harmony export */ H8: () => (/* binding */ IS_WINDOWS), /* harmony export */ H8: () => (/* binding */ IS_WINDOWS),
/* harmony export */ Qh: () => (/* binding */ isRooted), /* harmony export */ Qh: () => (/* binding */ isRooted),
/* harmony export */ rm: () => (/* binding */ rm),
/* harmony export */ t2: () => (/* binding */ exists), /* harmony export */ t2: () => (/* binding */ exists),
/* harmony export */ vr: () => (/* binding */ tryGetExecutablePath) /* harmony export */ vr: () => (/* binding */ tryGetExecutablePath)
/* harmony export */ }); /* harmony export */ });
/* unused harmony exports chmod, copyFile, lstat, open, readdir, rename, rm, rmdir, stat, symlink, unlink, readlink, UV_FS_O_EXLOCK, READONLY, isDirectory, getCmdPath */ /* unused harmony exports chmod, copyFile, lstat, open, readdir, rename, rmdir, stat, symlink, unlink, readlink, UV_FS_O_EXLOCK, READONLY, isDirectory, getCmdPath */
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __nccwpck_require__(9896); /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __nccwpck_require__(9896);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __nccwpck_require__(6928); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __nccwpck_require__(6928);
var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) { var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
@@ -34415,9 +34415,10 @@ function getCmdPath() {
/* harmony export */ __nccwpck_require__.d(__webpack_exports__, { /* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
/* harmony export */ K7: () => (/* binding */ which), /* harmony export */ K7: () => (/* binding */ which),
/* harmony export */ U$: () => (/* binding */ mkdirP) /* harmony export */ U$: () => (/* binding */ mkdirP),
/* harmony export */ Yz: () => (/* binding */ rmRF)
/* harmony export */ }); /* harmony export */ });
/* unused harmony exports cp, mv, rmRF, findInPath */ /* unused harmony exports cp, mv, findInPath */
/* harmony import */ var assert__WEBPACK_IMPORTED_MODULE_0__ = __nccwpck_require__(2613); /* harmony import */ var assert__WEBPACK_IMPORTED_MODULE_0__ = __nccwpck_require__(2613);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __nccwpck_require__(6928); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __nccwpck_require__(6928);
/* harmony import */ var _io_util_js__WEBPACK_IMPORTED_MODULE_2__ = __nccwpck_require__(90); /* harmony import */ var _io_util_js__WEBPACK_IMPORTED_MODULE_2__ = __nccwpck_require__(90);
@@ -34510,7 +34511,7 @@ function mv(source_1, dest_1) {
*/ */
function rmRF(inputPath) { function rmRF(inputPath) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
if (ioUtil.IS_WINDOWS) { if (_io_util_js__WEBPACK_IMPORTED_MODULE_2__/* .IS_WINDOWS */ .H8) {
// Check for invalid characters // Check for invalid characters
// https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
if (/[*"<>|]/.test(inputPath)) { if (/[*"<>|]/.test(inputPath)) {
@@ -34519,7 +34520,7 @@ function rmRF(inputPath) {
} }
try { try {
// note if path does not exist, error is silent // note if path does not exist, error is silent
yield ioUtil.rm(inputPath, { yield _io_util_js__WEBPACK_IMPORTED_MODULE_2__.rm(inputPath, {
force: true, force: true,
maxRetries: 3, maxRetries: 3,
recursive: true, recursive: true,
@@ -35733,6 +35734,8 @@ var cleanup_java_core = __nccwpck_require__(3838);
var external_fs_ = __nccwpck_require__(9896); var external_fs_ = __nccwpck_require__(9896);
// EXTERNAL MODULE: external "path" // EXTERNAL MODULE: external "path"
var external_path_ = __nccwpck_require__(6928); var external_path_ = __nccwpck_require__(6928);
// EXTERNAL MODULE: external "crypto"
var external_crypto_ = __nccwpck_require__(6982);
// EXTERNAL MODULE: ./node_modules/@actions/io/lib/io.js // EXTERNAL MODULE: ./node_modules/@actions/io/lib/io.js
var lib_io = __nccwpck_require__(8701); var lib_io = __nccwpck_require__(8701);
// EXTERNAL MODULE: ./node_modules/@actions/exec/lib/exec.js + 2 modules // EXTERNAL MODULE: ./node_modules/@actions/exec/lib/exec.js + 2 modules
@@ -35748,8 +35751,9 @@ var src_util = __nccwpck_require__(4527);
const PRIVATE_KEY_FILE = external_path_.join(src_util/* getTempDir */.G4(), 'private-key.asc');
const PRIVATE_KEY_FINGERPRINT_REGEX = /\w{40}/; const GPG_HOME_PREFIX = 'setup-java-gpg-';
const VERIFY_GPG_HOME_PREFIX = 'verify-signature-gpg-home-';
// Convert a Windows path (D:\a\_temp\...) to a POSIX path (/d/a/_temp/...). // Convert a Windows path (D:\a\_temp\...) to a POSIX path (/d/a/_temp/...).
// The Git-bundled GPG on Windows (MSYS2-based) uses POSIX path conventions // The Git-bundled GPG on Windows (MSYS2-based) uses POSIX path conventions
// internally. Passing Windows paths with backslashes can cause fatal GPG errors // internally. Passing Windows paths with backslashes can cause fatal GPG errors
@@ -35761,41 +35765,67 @@ function toGpgPath(p) {
.replace(/\\/g, '/') .replace(/\\/g, '/')
.replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`); .replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`);
} }
async function importKey(privateKey) { function createGpgHome(prefix) {
fs.writeFileSync(PRIVATE_KEY_FILE, privateKey, { const gpgHome = fs.mkdtempSync(path.join(util.getTempDir(), prefix));
encoding: 'utf-8', if (process.platform !== 'win32') {
flag: 'w' fs.chmodSync(gpgHome, 0o700);
}); }
let output = ''; return gpgHome;
const options = {
silent: true,
listeners: {
stdout: (data) => {
output += data.toString();
}
}
};
await exec.exec('gpg', [
'--batch',
'--import-options',
'import-show',
'--import',
PRIVATE_KEY_FILE
], options);
await io.rmRF(PRIVATE_KEY_FILE);
const match = output.match(PRIVATE_KEY_FINGERPRINT_REGEX);
return match && match[0];
} }
async function deleteKey(keyFingerprint) { async function importKey(privateKey) {
await lib_exec/* exec */.m('gpg', ['--batch', '--yes', '--delete-secret-and-public-key', keyFingerprint], { const gpgHome = createGpgHome(GPG_HOME_PREFIX);
silent: true const privateKeyFile = path.join(gpgHome, `private-key-${randomUUID()}.asc`);
}); try {
fs.writeFileSync(privateKeyFile, privateKey, {
encoding: 'utf-8',
flag: 'wx',
mode: 0o600
});
try {
await exec.exec('gpg', [
'--homedir',
toGpgPath(gpgHome),
'--batch',
'--import',
toGpgPath(privateKeyFile)
], { silent: true });
}
finally {
fs.rmSync(privateKeyFile, { force: true });
}
return gpgHome;
}
catch (error) {
await removeGpgHome(gpgHome);
throw error;
}
}
async function removeGpgHome(gpgHome) {
if (!gpgHome) {
return;
}
const resolvedGpgHome = external_path_.resolve(gpgHome);
const resolvedTempDir = external_path_.resolve(src_util/* getTempDir */.G4());
if (external_path_.dirname(resolvedGpgHome) !== resolvedTempDir ||
!external_path_.basename(resolvedGpgHome).startsWith(GPG_HOME_PREFIX)) {
throw new Error(`Refusing to remove unexpected GPG home: ${gpgHome}`);
}
if (!external_fs_.existsSync(resolvedGpgHome)) {
return;
}
try {
await lib_exec/* exec */.m('gpgconf', ['--homedir', toGpgPath(resolvedGpgHome), '--kill', 'gpg-agent'], { silent: true, ignoreReturnCode: true });
}
catch {
// gpgconf may be unavailable, but directory removal must still be attempted.
}
await lib_io/* rmRF */.Yz(resolvedGpgHome);
} }
async function verifyPackageSignature(archivePath, signatureUrl, publicKeyContent) { async function verifyPackageSignature(archivePath, signatureUrl, publicKeyContent) {
const signaturePath = await tc.downloadTool(signatureUrl); const signaturePath = await tc.downloadTool(signatureUrl);
let gpgHome; let gpgHome;
try { try {
gpgHome = fs.mkdtempSync(path.join(util.getTempDir(), 'verify-signature-gpg-home-')); gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX);
} }
catch (error) { catch (error) {
try { try {
@@ -35842,16 +35872,17 @@ var external_url_ = __nccwpck_require__(7016);
async function removePrivateKeyFromKeychain() { async function cleanup_java_removeGpgHome() {
if (cleanup_java_core/* getInput */.V4(constants/* INPUT_GPG_PRIVATE_KEY */.wz, { required: false })) { const gpgHome = cleanup_java_core/* getState */.Gu(constants/* STATE_GPG_HOME */.Fi);
cleanup_java_core/* info */.pq('Removing private key from keychain'); if (!gpgHome) {
try { return;
const keyFingerprint = cleanup_java_core/* getState */.Gu(constants/* STATE_GPG_PRIVATE_KEY_FINGERPRINT */.wm); }
await deleteKey(keyFingerprint); cleanup_java_core/* info */.pq('Removing private key from isolated GPG home');
} try {
catch (error) { await removeGpgHome(gpgHome);
cleanup_java_core/* setFailed */.C1(`Failed to remove private key due to: ${error.message}`); }
} catch (error) {
cleanup_java_core/* setFailed */.C1(`Failed to remove isolated GPG home due to: ${error.message}`);
} }
} }
/** /**
@@ -35899,7 +35930,7 @@ async function ignoreError(promise) {
}); });
} }
async function run() { async function run() {
await removePrivateKeyFromKeychain(); await cleanup_java_removeGpgHome();
await ignoreError(saveCaches()); await ignoreError(saveCaches());
} }
if (process.argv[1] === (0,external_url_.fileURLToPath)(import.meta.url)) { if (process.argv[1] === (0,external_url_.fileURLToPath)(import.meta.url)) {
+74 -43
View File
@@ -170,25 +170,30 @@ class MicrosoftDistributions extends base_installer/* JavaBase */.O {
/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ Fh: () => (/* binding */ importKey), /* harmony export */ Fh: () => (/* binding */ importKey),
/* harmony export */ Yi: () => (/* binding */ verifyPackageSignature) /* harmony export */ Yi: () => (/* binding */ verifyPackageSignature),
/* harmony export */ mS: () => (/* binding */ removeGpgHome),
/* harmony export */ nY: () => (/* binding */ toGpgPath)
/* harmony export */ }); /* harmony export */ });
/* unused harmony exports PRIVATE_KEY_FILE, toGpgPath, deleteKey */ /* unused harmony export GPG_HOME_PREFIX */
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(9896); /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(9896);
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6928); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6928);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _actions_io__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(8701); /* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6982);
/* harmony import */ var _actions_exec__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5260); /* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(crypto__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _actions_tool_cache__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9805); /* harmony import */ var _actions_io__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8701);
/* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(4527); /* harmony import */ var _actions_exec__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(5260);
/* harmony import */ var _actions_tool_cache__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(9805);
/* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(4527);
const PRIVATE_KEY_FILE = path__WEBPACK_IMPORTED_MODULE_1__.join(_util_js__WEBPACK_IMPORTED_MODULE_5__/* .getTempDir */ .G4(), 'private-key.asc');
const PRIVATE_KEY_FINGERPRINT_REGEX = /\w{40}/; const GPG_HOME_PREFIX = 'setup-java-gpg-';
const VERIFY_GPG_HOME_PREFIX = 'verify-signature-gpg-home-';
// Convert a Windows path (D:\a\_temp\...) to a POSIX path (/d/a/_temp/...). // Convert a Windows path (D:\a\_temp\...) to a POSIX path (/d/a/_temp/...).
// The Git-bundled GPG on Windows (MSYS2-based) uses POSIX path conventions // The Git-bundled GPG on Windows (MSYS2-based) uses POSIX path conventions
// internally. Passing Windows paths with backslashes can cause fatal GPG errors // internally. Passing Windows paths with backslashes can cause fatal GPG errors
@@ -200,45 +205,71 @@ function toGpgPath(p) {
.replace(/\\/g, '/') .replace(/\\/g, '/')
.replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`); .replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`);
} }
async function importKey(privateKey) { function createGpgHome(prefix) {
fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(PRIVATE_KEY_FILE, privateKey, { const gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(_util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4(), prefix));
encoding: 'utf-8', if (process.platform !== 'win32') {
flag: 'w' fs__WEBPACK_IMPORTED_MODULE_0__.chmodSync(gpgHome, 0o700);
}); }
let output = ''; return gpgHome;
const options = {
silent: true,
listeners: {
stdout: (data) => {
output += data.toString();
}
}
};
await _actions_exec__WEBPACK_IMPORTED_MODULE_3__/* .exec */ .m('gpg', [
'--batch',
'--import-options',
'import-show',
'--import',
PRIVATE_KEY_FILE
], options);
await _actions_io__WEBPACK_IMPORTED_MODULE_2__/* .rmRF */ .Yz(PRIVATE_KEY_FILE);
const match = output.match(PRIVATE_KEY_FINGERPRINT_REGEX);
return match && match[0];
} }
async function deleteKey(keyFingerprint) { async function importKey(privateKey) {
await exec.exec('gpg', ['--batch', '--yes', '--delete-secret-and-public-key', keyFingerprint], { const gpgHome = createGpgHome(GPG_HOME_PREFIX);
silent: true const privateKeyFile = path__WEBPACK_IMPORTED_MODULE_1__.join(gpgHome, `private-key-${(0,crypto__WEBPACK_IMPORTED_MODULE_2__.randomUUID)()}.asc`);
}); try {
fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(privateKeyFile, privateKey, {
encoding: 'utf-8',
flag: 'wx',
mode: 0o600
});
try {
await _actions_exec__WEBPACK_IMPORTED_MODULE_4__/* .exec */ .m('gpg', [
'--homedir',
toGpgPath(gpgHome),
'--batch',
'--import',
toGpgPath(privateKeyFile)
], { silent: true });
}
finally {
fs__WEBPACK_IMPORTED_MODULE_0__.rmSync(privateKeyFile, { force: true });
}
return gpgHome;
}
catch (error) {
await removeGpgHome(gpgHome);
throw error;
}
}
async function removeGpgHome(gpgHome) {
if (!gpgHome) {
return;
}
const resolvedGpgHome = path__WEBPACK_IMPORTED_MODULE_1__.resolve(gpgHome);
const resolvedTempDir = path__WEBPACK_IMPORTED_MODULE_1__.resolve(_util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4());
if (path__WEBPACK_IMPORTED_MODULE_1__.dirname(resolvedGpgHome) !== resolvedTempDir ||
!path__WEBPACK_IMPORTED_MODULE_1__.basename(resolvedGpgHome).startsWith(GPG_HOME_PREFIX)) {
throw new Error(`Refusing to remove unexpected GPG home: ${gpgHome}`);
}
if (!fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(resolvedGpgHome)) {
return;
}
try {
await _actions_exec__WEBPACK_IMPORTED_MODULE_4__/* .exec */ .m('gpgconf', ['--homedir', toGpgPath(resolvedGpgHome), '--kill', 'gpg-agent'], { silent: true, ignoreReturnCode: true });
}
catch {
// gpgconf may be unavailable, but directory removal must still be attempted.
}
await _actions_io__WEBPACK_IMPORTED_MODULE_3__/* .rmRF */ .Yz(resolvedGpgHome);
} }
async function verifyPackageSignature(archivePath, signatureUrl, publicKeyContent) { async function verifyPackageSignature(archivePath, signatureUrl, publicKeyContent) {
const signaturePath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_4__/* .downloadTool */ .bq(signatureUrl); const signaturePath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_5__/* .downloadTool */ .bq(signatureUrl);
let gpgHome; let gpgHome;
try { try {
gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(_util_js__WEBPACK_IMPORTED_MODULE_5__/* .getTempDir */ .G4(), 'verify-signature-gpg-home-')); gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX);
} }
catch (error) { catch (error) {
try { try {
await _actions_io__WEBPACK_IMPORTED_MODULE_2__/* .rmRF */ .Yz(signaturePath); await _actions_io__WEBPACK_IMPORTED_MODULE_3__/* .rmRF */ .Yz(signaturePath);
} }
catch { catch {
// ignore cleanup failures // ignore cleanup failures
@@ -249,14 +280,14 @@ async function verifyPackageSignature(archivePath, signatureUrl, publicKeyConten
const publicKeyFile = path__WEBPACK_IMPORTED_MODULE_1__.join(gpgHome, 'public-key.asc'); const publicKeyFile = path__WEBPACK_IMPORTED_MODULE_1__.join(gpgHome, 'public-key.asc');
fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(publicKeyFile, publicKeyContent, { encoding: 'utf-8' }); fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(publicKeyFile, publicKeyContent, { encoding: 'utf-8' });
const options = { silent: true }; const options = { silent: true };
await _actions_exec__WEBPACK_IMPORTED_MODULE_3__/* .exec */ .m('gpg', [ await _actions_exec__WEBPACK_IMPORTED_MODULE_4__/* .exec */ .m('gpg', [
'--homedir', '--homedir',
toGpgPath(gpgHome), toGpgPath(gpgHome),
'--batch', '--batch',
'--import', '--import',
toGpgPath(publicKeyFile) toGpgPath(publicKeyFile)
], options); ], options);
await _actions_exec__WEBPACK_IMPORTED_MODULE_3__/* .exec */ .m('gpg', [ await _actions_exec__WEBPACK_IMPORTED_MODULE_4__/* .exec */ .m('gpg', [
'--homedir', '--homedir',
toGpgPath(gpgHome), toGpgPath(gpgHome),
'--batch', '--batch',
@@ -266,8 +297,8 @@ async function verifyPackageSignature(archivePath, signatureUrl, publicKeyConten
], options); ], options);
} }
finally { finally {
await _actions_io__WEBPACK_IMPORTED_MODULE_2__/* .rmRF */ .Yz(signaturePath); await _actions_io__WEBPACK_IMPORTED_MODULE_3__/* .rmRF */ .Yz(signaturePath);
await _actions_io__WEBPACK_IMPORTED_MODULE_2__/* .rmRF */ .Yz(gpgHome); await _actions_io__WEBPACK_IMPORTED_MODULE_3__/* .rmRF */ .Yz(gpgHome);
} }
} }
+74 -43
View File
@@ -268,25 +268,30 @@ class TemurinDistribution extends base_installer/* JavaBase */.O {
/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ Fh: () => (/* binding */ importKey), /* harmony export */ Fh: () => (/* binding */ importKey),
/* harmony export */ Yi: () => (/* binding */ verifyPackageSignature) /* harmony export */ Yi: () => (/* binding */ verifyPackageSignature),
/* harmony export */ mS: () => (/* binding */ removeGpgHome),
/* harmony export */ nY: () => (/* binding */ toGpgPath)
/* harmony export */ }); /* harmony export */ });
/* unused harmony exports PRIVATE_KEY_FILE, toGpgPath, deleteKey */ /* unused harmony export GPG_HOME_PREFIX */
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(9896); /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(9896);
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6928); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6928);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _actions_io__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(8701); /* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6982);
/* harmony import */ var _actions_exec__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5260); /* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(crypto__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _actions_tool_cache__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9805); /* harmony import */ var _actions_io__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8701);
/* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(4527); /* harmony import */ var _actions_exec__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(5260);
/* harmony import */ var _actions_tool_cache__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(9805);
/* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(4527);
const PRIVATE_KEY_FILE = path__WEBPACK_IMPORTED_MODULE_1__.join(_util_js__WEBPACK_IMPORTED_MODULE_5__/* .getTempDir */ .G4(), 'private-key.asc');
const PRIVATE_KEY_FINGERPRINT_REGEX = /\w{40}/; const GPG_HOME_PREFIX = 'setup-java-gpg-';
const VERIFY_GPG_HOME_PREFIX = 'verify-signature-gpg-home-';
// Convert a Windows path (D:\a\_temp\...) to a POSIX path (/d/a/_temp/...). // Convert a Windows path (D:\a\_temp\...) to a POSIX path (/d/a/_temp/...).
// The Git-bundled GPG on Windows (MSYS2-based) uses POSIX path conventions // The Git-bundled GPG on Windows (MSYS2-based) uses POSIX path conventions
// internally. Passing Windows paths with backslashes can cause fatal GPG errors // internally. Passing Windows paths with backslashes can cause fatal GPG errors
@@ -298,45 +303,71 @@ function toGpgPath(p) {
.replace(/\\/g, '/') .replace(/\\/g, '/')
.replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`); .replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`);
} }
async function importKey(privateKey) { function createGpgHome(prefix) {
fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(PRIVATE_KEY_FILE, privateKey, { const gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(_util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4(), prefix));
encoding: 'utf-8', if (process.platform !== 'win32') {
flag: 'w' fs__WEBPACK_IMPORTED_MODULE_0__.chmodSync(gpgHome, 0o700);
}); }
let output = ''; return gpgHome;
const options = {
silent: true,
listeners: {
stdout: (data) => {
output += data.toString();
}
}
};
await _actions_exec__WEBPACK_IMPORTED_MODULE_3__/* .exec */ .m('gpg', [
'--batch',
'--import-options',
'import-show',
'--import',
PRIVATE_KEY_FILE
], options);
await _actions_io__WEBPACK_IMPORTED_MODULE_2__/* .rmRF */ .Yz(PRIVATE_KEY_FILE);
const match = output.match(PRIVATE_KEY_FINGERPRINT_REGEX);
return match && match[0];
} }
async function deleteKey(keyFingerprint) { async function importKey(privateKey) {
await exec.exec('gpg', ['--batch', '--yes', '--delete-secret-and-public-key', keyFingerprint], { const gpgHome = createGpgHome(GPG_HOME_PREFIX);
silent: true const privateKeyFile = path__WEBPACK_IMPORTED_MODULE_1__.join(gpgHome, `private-key-${(0,crypto__WEBPACK_IMPORTED_MODULE_2__.randomUUID)()}.asc`);
}); try {
fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(privateKeyFile, privateKey, {
encoding: 'utf-8',
flag: 'wx',
mode: 0o600
});
try {
await _actions_exec__WEBPACK_IMPORTED_MODULE_4__/* .exec */ .m('gpg', [
'--homedir',
toGpgPath(gpgHome),
'--batch',
'--import',
toGpgPath(privateKeyFile)
], { silent: true });
}
finally {
fs__WEBPACK_IMPORTED_MODULE_0__.rmSync(privateKeyFile, { force: true });
}
return gpgHome;
}
catch (error) {
await removeGpgHome(gpgHome);
throw error;
}
}
async function removeGpgHome(gpgHome) {
if (!gpgHome) {
return;
}
const resolvedGpgHome = path__WEBPACK_IMPORTED_MODULE_1__.resolve(gpgHome);
const resolvedTempDir = path__WEBPACK_IMPORTED_MODULE_1__.resolve(_util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4());
if (path__WEBPACK_IMPORTED_MODULE_1__.dirname(resolvedGpgHome) !== resolvedTempDir ||
!path__WEBPACK_IMPORTED_MODULE_1__.basename(resolvedGpgHome).startsWith(GPG_HOME_PREFIX)) {
throw new Error(`Refusing to remove unexpected GPG home: ${gpgHome}`);
}
if (!fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(resolvedGpgHome)) {
return;
}
try {
await _actions_exec__WEBPACK_IMPORTED_MODULE_4__/* .exec */ .m('gpgconf', ['--homedir', toGpgPath(resolvedGpgHome), '--kill', 'gpg-agent'], { silent: true, ignoreReturnCode: true });
}
catch {
// gpgconf may be unavailable, but directory removal must still be attempted.
}
await _actions_io__WEBPACK_IMPORTED_MODULE_3__/* .rmRF */ .Yz(resolvedGpgHome);
} }
async function verifyPackageSignature(archivePath, signatureUrl, publicKeyContent) { async function verifyPackageSignature(archivePath, signatureUrl, publicKeyContent) {
const signaturePath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_4__/* .downloadTool */ .bq(signatureUrl); const signaturePath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_5__/* .downloadTool */ .bq(signatureUrl);
let gpgHome; let gpgHome;
try { try {
gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(_util_js__WEBPACK_IMPORTED_MODULE_5__/* .getTempDir */ .G4(), 'verify-signature-gpg-home-')); gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX);
} }
catch (error) { catch (error) {
try { try {
await _actions_io__WEBPACK_IMPORTED_MODULE_2__/* .rmRF */ .Yz(signaturePath); await _actions_io__WEBPACK_IMPORTED_MODULE_3__/* .rmRF */ .Yz(signaturePath);
} }
catch { catch {
// ignore cleanup failures // ignore cleanup failures
@@ -347,14 +378,14 @@ async function verifyPackageSignature(archivePath, signatureUrl, publicKeyConten
const publicKeyFile = path__WEBPACK_IMPORTED_MODULE_1__.join(gpgHome, 'public-key.asc'); const publicKeyFile = path__WEBPACK_IMPORTED_MODULE_1__.join(gpgHome, 'public-key.asc');
fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(publicKeyFile, publicKeyContent, { encoding: 'utf-8' }); fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(publicKeyFile, publicKeyContent, { encoding: 'utf-8' });
const options = { silent: true }; const options = { silent: true };
await _actions_exec__WEBPACK_IMPORTED_MODULE_3__/* .exec */ .m('gpg', [ await _actions_exec__WEBPACK_IMPORTED_MODULE_4__/* .exec */ .m('gpg', [
'--homedir', '--homedir',
toGpgPath(gpgHome), toGpgPath(gpgHome),
'--batch', '--batch',
'--import', '--import',
toGpgPath(publicKeyFile) toGpgPath(publicKeyFile)
], options); ], options);
await _actions_exec__WEBPACK_IMPORTED_MODULE_3__/* .exec */ .m('gpg', [ await _actions_exec__WEBPACK_IMPORTED_MODULE_4__/* .exec */ .m('gpg', [
'--homedir', '--homedir',
toGpgPath(gpgHome), toGpgPath(gpgHome),
'--batch', '--batch',
@@ -364,8 +395,8 @@ async function verifyPackageSignature(archivePath, signatureUrl, publicKeyConten
], options); ], options);
} }
finally { finally {
await _actions_io__WEBPACK_IMPORTED_MODULE_2__/* .rmRF */ .Yz(signaturePath); await _actions_io__WEBPACK_IMPORTED_MODULE_3__/* .rmRF */ .Yz(signaturePath);
await _actions_io__WEBPACK_IMPORTED_MODULE_2__/* .rmRF */ .Yz(gpgHome); await _actions_io__WEBPACK_IMPORTED_MODULE_3__/* .rmRF */ .Yz(gpgHome);
} }
} }
+83 -45
View File
@@ -49,8 +49,15 @@ async function configureAuthentication() {
await createAuthenticationSettings(id, usernameEnvVar, passwordEnvVar, settingsDirectory, overwriteSettings, gpgPassphraseEnvVar); await createAuthenticationSettings(id, usernameEnvVar, passwordEnvVar, settingsDirectory, overwriteSettings, gpgPassphraseEnvVar);
if (gpgPrivateKey) { if (gpgPrivateKey) {
_actions_core__WEBPACK_IMPORTED_MODULE_1__/* .info */ .pq('Importing private gpg key'); _actions_core__WEBPACK_IMPORTED_MODULE_1__/* .info */ .pq('Importing private gpg key');
const keyFingerprint = (await _gpg_js__WEBPACK_IMPORTED_MODULE_5__/* .importKey */ .Fh(gpgPrivateKey)) || ''; const gpgHome = await _gpg_js__WEBPACK_IMPORTED_MODULE_5__/* .importKey */ .Fh(gpgPrivateKey);
_actions_core__WEBPACK_IMPORTED_MODULE_1__/* .saveState */ .LZ(_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .STATE_GPG_PRIVATE_KEY_FINGERPRINT */ .wm, keyFingerprint); try {
_actions_core__WEBPACK_IMPORTED_MODULE_1__/* .saveState */ .LZ(_constants_js__WEBPACK_IMPORTED_MODULE_7__/* .STATE_GPG_HOME */ .Fi, gpgHome);
_actions_core__WEBPACK_IMPORTED_MODULE_1__/* .exportVariable */ .dN('GNUPGHOME', _gpg_js__WEBPACK_IMPORTED_MODULE_5__/* .toGpgPath */ .nY(gpgHome));
}
catch (error) {
await _gpg_js__WEBPACK_IMPORTED_MODULE_5__/* .removeGpgHome */ .mS(gpgHome);
throw error;
}
} }
} }
function getInputWithDeprecatedAlias(inputName, deprecatedInputName, defaultValue) { function getInputWithDeprecatedAlias(inputName, deprecatedInputName, defaultValue) {
@@ -124,25 +131,30 @@ async function write(directory, settings, overwriteSettings) {
/* harmony export */ __webpack_require__.d(__webpack_exports__, { /* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ Fh: () => (/* binding */ importKey), /* harmony export */ Fh: () => (/* binding */ importKey),
/* harmony export */ Yi: () => (/* binding */ verifyPackageSignature) /* harmony export */ Yi: () => (/* binding */ verifyPackageSignature),
/* harmony export */ mS: () => (/* binding */ removeGpgHome),
/* harmony export */ nY: () => (/* binding */ toGpgPath)
/* harmony export */ }); /* harmony export */ });
/* unused harmony exports PRIVATE_KEY_FILE, toGpgPath, deleteKey */ /* unused harmony export GPG_HOME_PREFIX */
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(9896); /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(9896);
/* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_0__); /* harmony import */ var fs__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(fs__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6928); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6928);
/* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__); /* harmony import */ var path__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(path__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var _actions_io__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(8701); /* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6982);
/* harmony import */ var _actions_exec__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(5260); /* harmony import */ var crypto__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(crypto__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _actions_tool_cache__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9805); /* harmony import */ var _actions_io__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8701);
/* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(4527); /* harmony import */ var _actions_exec__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(5260);
/* harmony import */ var _actions_tool_cache__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(9805);
/* harmony import */ var _util_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(4527);
const PRIVATE_KEY_FILE = path__WEBPACK_IMPORTED_MODULE_1__.join(_util_js__WEBPACK_IMPORTED_MODULE_5__/* .getTempDir */ .G4(), 'private-key.asc');
const PRIVATE_KEY_FINGERPRINT_REGEX = /\w{40}/; const GPG_HOME_PREFIX = 'setup-java-gpg-';
const VERIFY_GPG_HOME_PREFIX = 'verify-signature-gpg-home-';
// Convert a Windows path (D:\a\_temp\...) to a POSIX path (/d/a/_temp/...). // Convert a Windows path (D:\a\_temp\...) to a POSIX path (/d/a/_temp/...).
// The Git-bundled GPG on Windows (MSYS2-based) uses POSIX path conventions // The Git-bundled GPG on Windows (MSYS2-based) uses POSIX path conventions
// internally. Passing Windows paths with backslashes can cause fatal GPG errors // internally. Passing Windows paths with backslashes can cause fatal GPG errors
@@ -154,45 +166,71 @@ function toGpgPath(p) {
.replace(/\\/g, '/') .replace(/\\/g, '/')
.replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`); .replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`);
} }
async function importKey(privateKey) { function createGpgHome(prefix) {
fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(PRIVATE_KEY_FILE, privateKey, { const gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(_util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4(), prefix));
encoding: 'utf-8', if (process.platform !== 'win32') {
flag: 'w' fs__WEBPACK_IMPORTED_MODULE_0__.chmodSync(gpgHome, 0o700);
}); }
let output = ''; return gpgHome;
const options = {
silent: true,
listeners: {
stdout: (data) => {
output += data.toString();
}
}
};
await _actions_exec__WEBPACK_IMPORTED_MODULE_3__/* .exec */ .m('gpg', [
'--batch',
'--import-options',
'import-show',
'--import',
PRIVATE_KEY_FILE
], options);
await _actions_io__WEBPACK_IMPORTED_MODULE_2__/* .rmRF */ .Yz(PRIVATE_KEY_FILE);
const match = output.match(PRIVATE_KEY_FINGERPRINT_REGEX);
return match && match[0];
} }
async function deleteKey(keyFingerprint) { async function importKey(privateKey) {
await exec.exec('gpg', ['--batch', '--yes', '--delete-secret-and-public-key', keyFingerprint], { const gpgHome = createGpgHome(GPG_HOME_PREFIX);
silent: true const privateKeyFile = path__WEBPACK_IMPORTED_MODULE_1__.join(gpgHome, `private-key-${(0,crypto__WEBPACK_IMPORTED_MODULE_2__.randomUUID)()}.asc`);
}); try {
fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(privateKeyFile, privateKey, {
encoding: 'utf-8',
flag: 'wx',
mode: 0o600
});
try {
await _actions_exec__WEBPACK_IMPORTED_MODULE_4__/* .exec */ .m('gpg', [
'--homedir',
toGpgPath(gpgHome),
'--batch',
'--import',
toGpgPath(privateKeyFile)
], { silent: true });
}
finally {
fs__WEBPACK_IMPORTED_MODULE_0__.rmSync(privateKeyFile, { force: true });
}
return gpgHome;
}
catch (error) {
await removeGpgHome(gpgHome);
throw error;
}
}
async function removeGpgHome(gpgHome) {
if (!gpgHome) {
return;
}
const resolvedGpgHome = path__WEBPACK_IMPORTED_MODULE_1__.resolve(gpgHome);
const resolvedTempDir = path__WEBPACK_IMPORTED_MODULE_1__.resolve(_util_js__WEBPACK_IMPORTED_MODULE_6__/* .getTempDir */ .G4());
if (path__WEBPACK_IMPORTED_MODULE_1__.dirname(resolvedGpgHome) !== resolvedTempDir ||
!path__WEBPACK_IMPORTED_MODULE_1__.basename(resolvedGpgHome).startsWith(GPG_HOME_PREFIX)) {
throw new Error(`Refusing to remove unexpected GPG home: ${gpgHome}`);
}
if (!fs__WEBPACK_IMPORTED_MODULE_0__.existsSync(resolvedGpgHome)) {
return;
}
try {
await _actions_exec__WEBPACK_IMPORTED_MODULE_4__/* .exec */ .m('gpgconf', ['--homedir', toGpgPath(resolvedGpgHome), '--kill', 'gpg-agent'], { silent: true, ignoreReturnCode: true });
}
catch {
// gpgconf may be unavailable, but directory removal must still be attempted.
}
await _actions_io__WEBPACK_IMPORTED_MODULE_3__/* .rmRF */ .Yz(resolvedGpgHome);
} }
async function verifyPackageSignature(archivePath, signatureUrl, publicKeyContent) { async function verifyPackageSignature(archivePath, signatureUrl, publicKeyContent) {
const signaturePath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_4__/* .downloadTool */ .bq(signatureUrl); const signaturePath = await _actions_tool_cache__WEBPACK_IMPORTED_MODULE_5__/* .downloadTool */ .bq(signatureUrl);
let gpgHome; let gpgHome;
try { try {
gpgHome = fs__WEBPACK_IMPORTED_MODULE_0__.mkdtempSync(path__WEBPACK_IMPORTED_MODULE_1__.join(_util_js__WEBPACK_IMPORTED_MODULE_5__/* .getTempDir */ .G4(), 'verify-signature-gpg-home-')); gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX);
} }
catch (error) { catch (error) {
try { try {
await _actions_io__WEBPACK_IMPORTED_MODULE_2__/* .rmRF */ .Yz(signaturePath); await _actions_io__WEBPACK_IMPORTED_MODULE_3__/* .rmRF */ .Yz(signaturePath);
} }
catch { catch {
// ignore cleanup failures // ignore cleanup failures
@@ -203,14 +241,14 @@ async function verifyPackageSignature(archivePath, signatureUrl, publicKeyConten
const publicKeyFile = path__WEBPACK_IMPORTED_MODULE_1__.join(gpgHome, 'public-key.asc'); const publicKeyFile = path__WEBPACK_IMPORTED_MODULE_1__.join(gpgHome, 'public-key.asc');
fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(publicKeyFile, publicKeyContent, { encoding: 'utf-8' }); fs__WEBPACK_IMPORTED_MODULE_0__.writeFileSync(publicKeyFile, publicKeyContent, { encoding: 'utf-8' });
const options = { silent: true }; const options = { silent: true };
await _actions_exec__WEBPACK_IMPORTED_MODULE_3__/* .exec */ .m('gpg', [ await _actions_exec__WEBPACK_IMPORTED_MODULE_4__/* .exec */ .m('gpg', [
'--homedir', '--homedir',
toGpgPath(gpgHome), toGpgPath(gpgHome),
'--batch', '--batch',
'--import', '--import',
toGpgPath(publicKeyFile) toGpgPath(publicKeyFile)
], options); ], options);
await _actions_exec__WEBPACK_IMPORTED_MODULE_3__/* .exec */ .m('gpg', [ await _actions_exec__WEBPACK_IMPORTED_MODULE_4__/* .exec */ .m('gpg', [
'--homedir', '--homedir',
toGpgPath(gpgHome), toGpgPath(gpgHome),
'--batch', '--batch',
@@ -220,8 +258,8 @@ async function verifyPackageSignature(archivePath, signatureUrl, publicKeyConten
], options); ], options);
} }
finally { finally {
await _actions_io__WEBPACK_IMPORTED_MODULE_2__/* .rmRF */ .Yz(signaturePath); await _actions_io__WEBPACK_IMPORTED_MODULE_3__/* .rmRF */ .Yz(signaturePath);
await _actions_io__WEBPACK_IMPORTED_MODULE_2__/* .rmRF */ .Yz(gpgHome); await _actions_io__WEBPACK_IMPORTED_MODULE_3__/* .rmRF */ .Yz(gpgHome);
} }
} }
+2 -2
View File
@@ -30770,6 +30770,7 @@ module.exports = {
/* harmony export */ __nccwpck_require__.d(__webpack_exports__, { /* harmony export */ __nccwpck_require__.d(__webpack_exports__, {
/* harmony export */ At: () => (/* binding */ INPUT_CACHE_DEPENDENCY_PATH), /* harmony export */ At: () => (/* binding */ INPUT_CACHE_DEPENDENCY_PATH),
/* harmony export */ E8: () => (/* binding */ INPUT_SET_DEFAULT), /* harmony export */ E8: () => (/* binding */ INPUT_SET_DEFAULT),
/* harmony export */ Fi: () => (/* binding */ STATE_GPG_HOME),
/* harmony export */ GL: () => (/* binding */ INPUT_CACHE_JDK), /* harmony export */ GL: () => (/* binding */ INPUT_CACHE_JDK),
/* harmony export */ I9: () => (/* binding */ INPUT_FORCE_DOWNLOAD), /* harmony export */ I9: () => (/* binding */ INPUT_FORCE_DOWNLOAD),
/* harmony export */ K$: () => (/* binding */ GPG_PASSPHRASE_PROFILE_ID), /* harmony export */ K$: () => (/* binding */ GPG_PASSPHRASE_PROFILE_ID),
@@ -30810,7 +30811,6 @@ module.exports = {
/* harmony export */ vO: () => (/* binding */ MVN_SETTINGS_FILE), /* harmony export */ vO: () => (/* binding */ MVN_SETTINGS_FILE),
/* harmony export */ wX: () => (/* binding */ INPUT_SHOW_DOWNLOAD_PROGRESS), /* harmony export */ wX: () => (/* binding */ INPUT_SHOW_DOWNLOAD_PROGRESS),
/* harmony export */ wc: () => (/* binding */ INPUT_JDK_FILE_DEPRECATED), /* harmony export */ wc: () => (/* binding */ INPUT_JDK_FILE_DEPRECATED),
/* harmony export */ wm: () => (/* binding */ STATE_GPG_PRIVATE_KEY_FINGERPRINT),
/* harmony export */ wz: () => (/* binding */ INPUT_GPG_PRIVATE_KEY), /* harmony export */ wz: () => (/* binding */ INPUT_GPG_PRIVATE_KEY),
/* harmony export */ xp: () => (/* binding */ INPUT_DEFAULT_SERVER_PASSWORD) /* harmony export */ xp: () => (/* binding */ INPUT_DEFAULT_SERVER_PASSWORD)
/* harmony export */ }); /* harmony export */ });
@@ -30855,7 +30855,7 @@ const INPUT_CACHE_DEPENDENCY_PATH = 'cache-dependency-path';
const INPUT_CACHE_PATH = 'cache-path'; const INPUT_CACHE_PATH = 'cache-path';
const INPUT_CACHE_READ_ONLY = 'cache-read-only'; const INPUT_CACHE_READ_ONLY = 'cache-read-only';
const INPUT_JOB_STATUS = 'job-status'; const INPUT_JOB_STATUS = 'job-status';
const STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint'; const STATE_GPG_HOME = 'gpg-home';
const M2_DIR = '.m2'; const M2_DIR = '.m2';
const MVN_SETTINGS_FILE = 'settings.xml'; const MVN_SETTINGS_FILE = 'settings.xml';
const MVN_TOOLCHAINS_FILE = 'toolchains.xml'; const MVN_TOOLCHAINS_FILE = 'toolchains.xml';
+1 -1
View File
@@ -873,7 +873,7 @@ See the help docs on [Publishing a Package](https://help.github.com/en/github/ma
#### Legacy / alternative: let setup-java import the key #### Legacy / alternative: let setup-java import the key
If you prefer signing with the `gpg` executable (for example because you are using `maven-gpg-plugin` older than 3.2.0), you can let setup-java import the key instead by providing the `gpg-private-key` and `gpg-passphrase-env-var` inputs. The private key is written to a file in the runner's temp directory, imported into the GPG keychain, and the file is promptly removed before proceeding with the rest of the setup process. A cleanup step removes the imported private key from the GPG keychain after the job completes regardless of the job status. This ensures that the private key is no longer accessible on self-hosted runners and cannot "leak" between jobs (hosted runners are always clean instances). If you prefer signing with the `gpg` executable (for example because you are using `maven-gpg-plugin` older than 3.2.0), you can let setup-java import the key instead by providing the `gpg-private-key` and `gpg-passphrase-env-var` inputs. setup-java creates a uniquely named, permission-restricted GPG home in the runner's temp directory, imports the key only into that isolated keyring, and exports `GNUPGHOME` for subsequent Maven and GPG commands. The temporary key file is permission-restricted and removed whether the import succeeds or fails. A cleanup step removes the complete action-owned GPG home after the job regardless of job status, without modifying the runner user's default keyring. Each setup-java invocation owns a separate keyring, including on persistent self-hosted runners.
setup-java imports the key independently of the plugin version, but the generated passphrase profile described below uses `gpg.passphraseEnvName`, which requires `maven-gpg-plugin` 3.2.0 or newer. Since `gpg-passphrase-env-var` defaults to `GPG_PASSPHRASE`, setup-java writes that profile unless you override the input to `MAVEN_GPG_PASSPHRASE`. setup-java imports the key independently of the plugin version, but the generated passphrase profile described below uses `gpg.passphraseEnvName`, which requires `maven-gpg-plugin` 3.2.0 or newer. Since `gpg-passphrase-env-var` defaults to `GPG_PASSPHRASE`, setup-java writes that profile unless you override the input to `MAVEN_GPG_PASSPHRASE`.
+8 -2
View File
@@ -52,8 +52,14 @@ export async function configureAuthentication() {
if (gpgPrivateKey) { if (gpgPrivateKey) {
core.info('Importing private gpg key'); core.info('Importing private gpg key');
const keyFingerprint = (await gpg.importKey(gpgPrivateKey)) || ''; const gpgHome = await gpg.importKey(gpgPrivateKey);
core.saveState(constants.STATE_GPG_PRIVATE_KEY_FINGERPRINT, keyFingerprint); try {
core.saveState(constants.STATE_GPG_HOME, gpgHome);
core.exportVariable('GNUPGHOME', gpg.toGpgPath(gpgHome));
} catch (error) {
await gpg.removeGpgHome(gpgHome);
throw error;
}
} }
} }
+14 -14
View File
@@ -8,19 +8,19 @@ import {
} from './util.js'; } from './util.js';
import {fileURLToPath} from 'url'; import {fileURLToPath} from 'url';
async function removePrivateKeyFromKeychain() { async function removeGpgHome() {
if (core.getInput(constants.INPUT_GPG_PRIVATE_KEY, {required: false})) { const gpgHome = core.getState(constants.STATE_GPG_HOME);
core.info('Removing private key from keychain'); if (!gpgHome) {
try { return;
const keyFingerprint = core.getState( }
constants.STATE_GPG_PRIVATE_KEY_FINGERPRINT
); core.info('Removing private key from isolated GPG home');
await gpg.deleteKey(keyFingerprint); try {
} catch (error) { await gpg.removeGpgHome(gpgHome);
core.setFailed( } catch (error) {
`Failed to remove private key due to: ${(error as Error).message}` core.setFailed(
); `Failed to remove isolated GPG home due to: ${(error as Error).message}`
} );
} }
} }
@@ -73,7 +73,7 @@ async function ignoreError(promise: Promise<void>) {
} }
export async function run() { export async function run() {
await removePrivateKeyFromKeychain(); await removeGpgHome();
await ignoreError(saveCaches()); await ignoreError(saveCaches());
} }
+1 -1
View File
@@ -43,7 +43,7 @@ export const INPUT_CACHE_PATH = 'cache-path';
export const INPUT_CACHE_READ_ONLY = 'cache-read-only'; export const INPUT_CACHE_READ_ONLY = 'cache-read-only';
export const INPUT_JOB_STATUS = 'job-status'; export const INPUT_JOB_STATUS = 'job-status';
export const STATE_GPG_PRIVATE_KEY_FINGERPRINT = 'gpg-private-key-fingerprint'; export const STATE_GPG_HOME = 'gpg-home';
export const M2_DIR = '.m2'; export const M2_DIR = '.m2';
export const MVN_SETTINGS_FILE = 'settings.xml'; export const MVN_SETTINGS_FILE = 'settings.xml';
+72 -46
View File
@@ -1,14 +1,14 @@
import * as fs from 'fs'; import * as fs from 'fs';
import * as path from 'path'; import * as path from 'path';
import {randomUUID} from 'crypto';
import * as io from '@actions/io'; import * as io from '@actions/io';
import * as exec from '@actions/exec'; import * as exec from '@actions/exec';
import * as tc from '@actions/tool-cache'; import * as tc from '@actions/tool-cache';
import * as util from './util.js'; import * as util from './util.js';
import {ExecOptions} from '@actions/exec'; import {ExecOptions} from '@actions/exec';
export const PRIVATE_KEY_FILE = path.join(util.getTempDir(), 'private-key.asc'); export const GPG_HOME_PREFIX = 'setup-java-gpg-';
const VERIFY_GPG_HOME_PREFIX = 'verify-signature-gpg-home-';
const PRIVATE_KEY_FINGERPRINT_REGEX = /\w{40}/;
// Convert a Windows path (D:\a\_temp\...) to a POSIX path (/d/a/_temp/...). // Convert a Windows path (D:\a\_temp\...) to a POSIX path (/d/a/_temp/...).
// The Git-bundled GPG on Windows (MSYS2-based) uses POSIX path conventions // The Git-bundled GPG on Windows (MSYS2-based) uses POSIX path conventions
@@ -21,49 +21,77 @@ export function toGpgPath(p: string): string {
.replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`); .replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`);
} }
export async function importKey(privateKey: string) { function createGpgHome(prefix: string): string {
fs.writeFileSync(PRIVATE_KEY_FILE, privateKey, { const gpgHome = fs.mkdtempSync(path.join(util.getTempDir(), prefix));
encoding: 'utf-8', if (process.platform !== 'win32') {
flag: 'w' fs.chmodSync(gpgHome, 0o700);
}); }
return gpgHome;
let output = '';
const options: ExecOptions = {
silent: true,
listeners: {
stdout: (data: Buffer) => {
output += data.toString();
}
}
};
await exec.exec(
'gpg',
[
'--batch',
'--import-options',
'import-show',
'--import',
PRIVATE_KEY_FILE
],
options
);
await io.rmRF(PRIVATE_KEY_FILE);
const match = output.match(PRIVATE_KEY_FINGERPRINT_REGEX);
return match && match[0];
} }
export async function deleteKey(keyFingerprint: string) { export async function importKey(privateKey: string): Promise<string> {
await exec.exec( const gpgHome = createGpgHome(GPG_HOME_PREFIX);
'gpg', const privateKeyFile = path.join(gpgHome, `private-key-${randomUUID()}.asc`);
['--batch', '--yes', '--delete-secret-and-public-key', keyFingerprint],
{ try {
silent: true fs.writeFileSync(privateKeyFile, privateKey, {
encoding: 'utf-8',
flag: 'wx',
mode: 0o600
});
try {
await exec.exec(
'gpg',
[
'--homedir',
toGpgPath(gpgHome),
'--batch',
'--import',
toGpgPath(privateKeyFile)
],
{silent: true}
);
} finally {
fs.rmSync(privateKeyFile, {force: true});
} }
);
return gpgHome;
} catch (error) {
await removeGpgHome(gpgHome);
throw error;
}
}
export async function removeGpgHome(gpgHome: string): Promise<void> {
if (!gpgHome) {
return;
}
const resolvedGpgHome = path.resolve(gpgHome);
const resolvedTempDir = path.resolve(util.getTempDir());
if (
path.dirname(resolvedGpgHome) !== resolvedTempDir ||
!path.basename(resolvedGpgHome).startsWith(GPG_HOME_PREFIX)
) {
throw new Error(`Refusing to remove unexpected GPG home: ${gpgHome}`);
}
if (!fs.existsSync(resolvedGpgHome)) {
return;
}
try {
await exec.exec(
'gpgconf',
['--homedir', toGpgPath(resolvedGpgHome), '--kill', 'gpg-agent'],
{silent: true, ignoreReturnCode: true}
);
} catch {
// gpgconf may be unavailable, but directory removal must still be attempted.
}
await io.rmRF(resolvedGpgHome);
} }
export async function verifyPackageSignature( export async function verifyPackageSignature(
@@ -74,9 +102,7 @@ export async function verifyPackageSignature(
const signaturePath = await tc.downloadTool(signatureUrl); const signaturePath = await tc.downloadTool(signatureUrl);
let gpgHome: string; let gpgHome: string;
try { try {
gpgHome = fs.mkdtempSync( gpgHome = createGpgHome(VERIFY_GPG_HOME_PREFIX);
path.join(util.getTempDir(), 'verify-signature-gpg-home-')
);
} catch (error) { } catch (error) {
try { try {
await io.rmRF(signaturePath); await io.rmRF(signaturePath);