feat: Add verify-signature plumbing and Temurin+Microsoft verification support (#1060)

* Add verify-signature plumbing and Temurin verification support

* Rebuild dist after signature verification changes

* Refine signature verification errors and regenerate dist

* refactor: make gpg.ts generic, move Adoptium-specific constant to temurin distribution

* fix: mock renameWinArchive in temurin tests and add signature e2e job

* refactor: bundle Adoptium public key, replace keyserver lookup with local import

* feat: add verify-signature-public-key input to allow custom GPG key override

* refactor: extract Adoptium public key to adoptium-key.ts; tighten gpg.ts cleanup scope

* Add verify-signature plumbing and Temurin verification support

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Add Microsoft signature verification support

* Regenerate dist bundles for Microsoft signature checks

* Harden Microsoft signature URL handling

* Add setup-java-microsoft-signature-verification e2e job

* chore: regenerate dist files

* Fix e2e-versions: remove duplicate job, update signature jobs to checkout@v7 with env vars

* Fix Prettier formatting in test files

* fix: mock renameWinArchive in microsoft-installer tests to fix Windows CI failure

* fix: use --homedir flag instead of GNUPGHOME env var for Windows GPG compatibility

The Git-bundled GPG on Windows (MSYS2-based) does not automatically convert
Windows-style paths in environment variables like GNUPGHOME. This caused GPG
to fail with exit code 2 when verifying Microsoft JDK signatures on Windows,
because the GNUPGHOME path (D:\a\_temp\...) was not recognized as a valid
POSIX path.

Fix: pass --homedir as an explicit command-line argument to both gpg --import
and gpg --verify. MSYS2 does correctly convert Windows paths in command-line
arguments, so this approach works reliably on Windows, Linux, and macOS.

* fix: convert Windows paths to POSIX format for MSYS2 GPG on Windows

The Git-bundled GPG on Windows (C:\Program Files\Git\usr\bin\gpg.exe) is
an MSYS2-based binary that uses POSIX path conventions internally. When
Windows-style paths with backslashes and drive letters (D:\a\_temp\...)
are passed as arguments, GPG may fail to resolve them correctly, resulting
in a fatal error (exit code 2).

Fix: add a toGpgPath() helper that converts Windows paths to MSYS2 POSIX
format (/d/a/_temp/...) before passing them to any gpg command. On Linux
and macOS the helper is a no-op.

Applied to all four paths used in verifyPackageSignature:
- gpgHome (--homedir argument)
- publicKeyFile (--import argument)
- signaturePath (--verify signature argument)
- archivePath (--verify data argument)

* Fix gpg test formatting

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Bruno Borges <brborges@microsoft.com>
This commit is contained in:
John
2026-06-29 13:19:49 +01:00
committed by GitHub
parent e9339ddc84
commit b150355f04
20 changed files with 1117 additions and 112 deletions
+60 -2
View File
@@ -52241,7 +52241,7 @@ else {
"use strict";
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE_DEPENDENCY_PATH = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0;
exports.DISTRIBUTIONS_ONLY_MAJOR_VERSION = exports.INPUT_MVN_TOOLCHAIN_VENDOR = exports.INPUT_MVN_TOOLCHAIN_ID = exports.MVN_TOOLCHAINS_FILE = exports.MVN_SETTINGS_FILE = exports.M2_DIR = exports.STATE_GPG_PRIVATE_KEY_FINGERPRINT = exports.INPUT_JOB_STATUS = exports.INPUT_CACHE_DEPENDENCY_PATH = exports.INPUT_CACHE = exports.INPUT_DEFAULT_GPG_PASSPHRASE = exports.INPUT_DEFAULT_GPG_PRIVATE_KEY = exports.INPUT_GPG_PASSPHRASE = exports.INPUT_GPG_PRIVATE_KEY = exports.INPUT_OVERWRITE_SETTINGS = exports.INPUT_SETTINGS_PATH = exports.INPUT_SERVER_PASSWORD = exports.INPUT_SERVER_USERNAME = exports.INPUT_SERVER_ID = exports.INPUT_VERIFY_SIGNATURE_PUBLIC_KEY = exports.INPUT_VERIFY_SIGNATURE = exports.INPUT_CHECK_LATEST = exports.INPUT_JDK_FILE = exports.INPUT_DISTRIBUTION = exports.INPUT_JAVA_PACKAGE = exports.INPUT_ARCHITECTURE = exports.INPUT_JAVA_VERSION_FILE = exports.INPUT_JAVA_VERSION = exports.MACOS_JAVA_CONTENT_POSTFIX = void 0;
exports.MACOS_JAVA_CONTENT_POSTFIX = 'Contents/Home';
exports.INPUT_JAVA_VERSION = 'java-version';
exports.INPUT_JAVA_VERSION_FILE = 'java-version-file';
@@ -52250,6 +52250,8 @@ exports.INPUT_JAVA_PACKAGE = 'java-package';
exports.INPUT_DISTRIBUTION = 'distribution';
exports.INPUT_JDK_FILE = 'jdkFile';
exports.INPUT_CHECK_LATEST = 'check-latest';
exports.INPUT_VERIFY_SIGNATURE = 'verify-signature';
exports.INPUT_VERIFY_SIGNATURE_PUBLIC_KEY = 'verify-signature-public-key';
exports.INPUT_SERVER_ID = 'server-id';
exports.INPUT_SERVER_USERNAME = 'server-username';
exports.INPUT_SERVER_PASSWORD = 'server-password';
@@ -52311,14 +52313,27 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
});
};
Object.defineProperty(exports, "__esModule", ({ value: true }));
exports.deleteKey = exports.importKey = exports.PRIVATE_KEY_FILE = void 0;
exports.verifyPackageSignature = exports.deleteKey = exports.importKey = exports.toGpgPath = exports.PRIVATE_KEY_FILE = void 0;
const fs = __importStar(__nccwpck_require__(79896));
const path = __importStar(__nccwpck_require__(16928));
const io = __importStar(__nccwpck_require__(94994));
const exec = __importStar(__nccwpck_require__(95236));
const tc = __importStar(__nccwpck_require__(33472));
const util = __importStar(__nccwpck_require__(54527));
exports.PRIVATE_KEY_FILE = path.join(util.getTempDir(), 'private-key.asc');
const PRIVATE_KEY_FINGERPRINT_REGEX = /\w{40}/;
// 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
// internally. Passing Windows paths with backslashes can cause fatal GPG errors
// (exit code 2), so all paths passed to GPG must be in POSIX format on Windows.
function toGpgPath(p) {
if (process.platform !== 'win32')
return p;
return p
.replace(/\\/g, '/')
.replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`);
}
exports.toGpgPath = toGpgPath;
function importKey(privateKey) {
return __awaiter(this, void 0, void 0, function* () {
fs.writeFileSync(exports.PRIVATE_KEY_FILE, privateKey, {
@@ -52355,6 +52370,49 @@ function deleteKey(keyFingerprint) {
});
}
exports.deleteKey = deleteKey;
function verifyPackageSignature(archivePath, signatureUrl, publicKeyContent) {
return __awaiter(this, void 0, void 0, function* () {
const signaturePath = yield tc.downloadTool(signatureUrl);
let gpgHome;
try {
gpgHome = fs.mkdtempSync(path.join(util.getTempDir(), 'verify-signature-gpg-home-'));
}
catch (error) {
try {
yield io.rmRF(signaturePath);
}
catch (_a) {
// ignore cleanup failures
}
throw new Error(`Failed to create temporary GPG home directory for signature verification: ${error.message}`);
}
try {
const publicKeyFile = path.join(gpgHome, 'public-key.asc');
fs.writeFileSync(publicKeyFile, publicKeyContent, { encoding: 'utf-8' });
const options = { silent: true };
yield exec.exec('gpg', [
'--homedir',
toGpgPath(gpgHome),
'--batch',
'--import',
toGpgPath(publicKeyFile)
], options);
yield exec.exec('gpg', [
'--homedir',
toGpgPath(gpgHome),
'--batch',
'--verify',
toGpgPath(signaturePath),
toGpgPath(archivePath)
], options);
}
finally {
yield io.rmRF(signaturePath);
yield io.rmRF(gpgHome);
}
});
}
exports.verifyPackageSignature = verifyPackageSignature;
/***/ }),