mirror of
https://github.com/actions/setup-java.git
synced 2026-07-05 17:17:59 +00:00
b150355f04
* 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>
124 lines
3.0 KiB
TypeScript
124 lines
3.0 KiB
TypeScript
import * as fs from 'fs';
|
|
import * as path from 'path';
|
|
import * as io from '@actions/io';
|
|
import * as exec from '@actions/exec';
|
|
import * as tc from '@actions/tool-cache';
|
|
import * as util from './util';
|
|
import {ExecOptions} from '@actions/exec/lib/interfaces';
|
|
|
|
export const 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.
|
|
export function toGpgPath(p: string): string {
|
|
if (process.platform !== 'win32') return p;
|
|
return p
|
|
.replace(/\\/g, '/')
|
|
.replace(/^([A-Za-z]):\//, (_, drive) => `/${drive.toLowerCase()}/`);
|
|
}
|
|
|
|
export async function importKey(privateKey: string) {
|
|
fs.writeFileSync(PRIVATE_KEY_FILE, privateKey, {
|
|
encoding: 'utf-8',
|
|
flag: 'w'
|
|
});
|
|
|
|
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) {
|
|
await exec.exec(
|
|
'gpg',
|
|
['--batch', '--yes', '--delete-secret-and-public-key', keyFingerprint],
|
|
{
|
|
silent: true
|
|
}
|
|
);
|
|
}
|
|
|
|
export async function verifyPackageSignature(
|
|
archivePath: string,
|
|
signatureUrl: string,
|
|
publicKeyContent: string
|
|
) {
|
|
const signaturePath = await tc.downloadTool(signatureUrl);
|
|
let gpgHome: string;
|
|
try {
|
|
gpgHome = fs.mkdtempSync(
|
|
path.join(util.getTempDir(), 'verify-signature-gpg-home-')
|
|
);
|
|
} catch (error) {
|
|
try {
|
|
await io.rmRF(signaturePath);
|
|
} catch {
|
|
// ignore cleanup failures
|
|
}
|
|
throw new Error(
|
|
`Failed to create temporary GPG home directory for signature verification: ${
|
|
(error as Error).message
|
|
}`
|
|
);
|
|
}
|
|
try {
|
|
const publicKeyFile = path.join(gpgHome, 'public-key.asc');
|
|
fs.writeFileSync(publicKeyFile, publicKeyContent, {encoding: 'utf-8'});
|
|
const options: ExecOptions = {silent: true};
|
|
await exec.exec(
|
|
'gpg',
|
|
[
|
|
'--homedir',
|
|
toGpgPath(gpgHome),
|
|
'--batch',
|
|
'--import',
|
|
toGpgPath(publicKeyFile)
|
|
],
|
|
options
|
|
);
|
|
await exec.exec(
|
|
'gpg',
|
|
[
|
|
'--homedir',
|
|
toGpgPath(gpgHome),
|
|
'--batch',
|
|
'--verify',
|
|
toGpgPath(signaturePath),
|
|
toGpgPath(archivePath)
|
|
],
|
|
options
|
|
);
|
|
} finally {
|
|
await io.rmRF(signaturePath);
|
|
await io.rmRF(gpgHome);
|
|
}
|
|
}
|