mirror of
https://github.com/actions/setup-java.git
synced 2026-07-08 14:21:50 +00:00
Add Microsoft signature verification support
This commit is contained in:
parent
40f7b5c4bb
commit
db1f1b8754
@ -48,7 +48,7 @@ For information about the latest releases, recent updates, and newly supported d
|
|||||||
|
|
||||||
- `check-latest`: Setting this option makes the action to check for the latest available version for the version spec.
|
- `check-latest`: Setting this option makes the action to check for the latest available version for the version spec.
|
||||||
|
|
||||||
- `verify-signature`: Verifies downloaded Java package signatures when supported by the selected distribution. Currently supported for `temurin`. If set to `true` for unsupported distributions, the action fails.
|
- `verify-signature`: Verifies downloaded Java package signatures when supported by the selected distribution. Currently supported for `temurin` and `microsoft`. If set to `true` for unsupported distributions, the action fails.
|
||||||
|
|
||||||
- `cache`: Quick [setup caching](#caching-packages-dependencies) for the dependencies managed through one of the predefined package managers. It can be one of "maven", "gradle" or "sbt".
|
- `cache`: Quick [setup caching](#caching-packages-dependencies) for the dependencies managed through one of the predefined package managers. It can be one of "maven", "gradle" or "sbt".
|
||||||
|
|
||||||
|
|||||||
@ -1,8 +1,15 @@
|
|||||||
import {MicrosoftDistributions} from '../../src/distributions/microsoft/installer';
|
import {
|
||||||
|
MicrosoftDistributions,
|
||||||
|
MICROSOFT_PUBLIC_KEY
|
||||||
|
} from '../../src/distributions/microsoft/installer';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import data from '../data/microsoft.json';
|
import data from '../data/microsoft.json';
|
||||||
import * as httpm from '@actions/http-client';
|
import * as httpm from '@actions/http-client';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
|
import * as tc from '@actions/tool-cache';
|
||||||
|
import * as gpg from '../../src/gpg';
|
||||||
|
import * as util from '../../src/util';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
describe('findPackageForDownload', () => {
|
describe('findPackageForDownload', () => {
|
||||||
let distribution: MicrosoftDistributions;
|
let distribution: MicrosoftDistributions;
|
||||||
@ -97,6 +104,7 @@ describe('findPackageForDownload', () => {
|
|||||||
.replace('{{OS_TYPE}}', os)
|
.replace('{{OS_TYPE}}', os)
|
||||||
.replace('{{ARCHIVE_TYPE}}', archive);
|
.replace('{{ARCHIVE_TYPE}}', archive);
|
||||||
expect(result.url).toBe(url);
|
expect(result.url).toBe(url);
|
||||||
|
expect(result.signatureUrl).toBe(`${url}.sig`);
|
||||||
});
|
});
|
||||||
|
|
||||||
it.each([
|
it.each([
|
||||||
@ -183,3 +191,118 @@ describe('findPackageForDownload', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('downloadTool', () => {
|
||||||
|
let spyDownloadTool: jest.SpyInstance;
|
||||||
|
let spyExtractJdkFile: jest.SpyInstance;
|
||||||
|
let spyCacheDir: jest.SpyInstance;
|
||||||
|
let spyVerifySignature: jest.SpyInstance;
|
||||||
|
let distribution: MicrosoftDistributions;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
jest
|
||||||
|
.spyOn(os, 'platform')
|
||||||
|
.mockReturnValue(process.platform as ReturnType<typeof os.platform>);
|
||||||
|
|
||||||
|
distribution = new MicrosoftDistributions({
|
||||||
|
version: '17',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false
|
||||||
|
});
|
||||||
|
|
||||||
|
spyDownloadTool = jest.spyOn(tc, 'downloadTool');
|
||||||
|
spyDownloadTool.mockImplementation(async () => {
|
||||||
|
return '/tmp/jdk.tar.gz';
|
||||||
|
});
|
||||||
|
|
||||||
|
spyExtractJdkFile = jest.spyOn(util, 'extractJdkFile');
|
||||||
|
spyExtractJdkFile.mockImplementation(async () => {
|
||||||
|
return '/tmp/unpacked';
|
||||||
|
});
|
||||||
|
|
||||||
|
jest.spyOn(fs, 'readdirSync').mockReturnValue(['jdk'] as any);
|
||||||
|
spyCacheDir = jest.spyOn(tc, 'cacheDir');
|
||||||
|
spyCacheDir.mockImplementation(async () => {
|
||||||
|
return '/tmp/cached';
|
||||||
|
});
|
||||||
|
|
||||||
|
spyVerifySignature = jest.spyOn(gpg, 'verifyPackageSignature');
|
||||||
|
spyVerifySignature.mockImplementation(async () => {});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.restoreAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('verifies signature when enabled', async () => {
|
||||||
|
const signedDistribution = new MicrosoftDistributions({
|
||||||
|
version: '17',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false,
|
||||||
|
verifySignature: true
|
||||||
|
});
|
||||||
|
|
||||||
|
await signedDistribution['downloadTool']({
|
||||||
|
version: '17.0.14+7',
|
||||||
|
url: 'https://example.com/jdk.tar.gz',
|
||||||
|
signatureUrl: 'https://example.com/jdk.tar.gz.sig'
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(spyVerifySignature).toHaveBeenCalledWith(
|
||||||
|
'/tmp/jdk.tar.gz',
|
||||||
|
'https://example.com/jdk.tar.gz.sig',
|
||||||
|
MICROSOFT_PUBLIC_KEY
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('uses custom public key when verifySignaturePublicKey is provided', async () => {
|
||||||
|
const customKey =
|
||||||
|
'-----BEGIN PGP PUBLIC KEY BLOCK-----\ncustom\n-----END PGP PUBLIC KEY BLOCK-----';
|
||||||
|
const signedDistribution = new MicrosoftDistributions({
|
||||||
|
version: '17',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false,
|
||||||
|
verifySignature: true,
|
||||||
|
verifySignaturePublicKey: customKey
|
||||||
|
});
|
||||||
|
|
||||||
|
await signedDistribution['downloadTool']({
|
||||||
|
version: '17.0.14+7',
|
||||||
|
url: 'https://example.com/jdk.tar.gz',
|
||||||
|
signatureUrl: 'https://example.com/jdk.tar.gz.sig'
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(spyVerifySignature).toHaveBeenCalledWith(
|
||||||
|
'/tmp/jdk.tar.gz',
|
||||||
|
'https://example.com/jdk.tar.gz.sig',
|
||||||
|
customKey
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fails when signature is missing and verification is enabled', async () => {
|
||||||
|
const signedDistribution = new MicrosoftDistributions({
|
||||||
|
version: '17',
|
||||||
|
architecture: 'x64',
|
||||||
|
packageType: 'jdk',
|
||||||
|
checkLatest: false,
|
||||||
|
verifySignature: true
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
signedDistribution['downloadTool']({
|
||||||
|
version: '17.0.14+7',
|
||||||
|
url: 'https://example.com/jdk.tar.gz'
|
||||||
|
})
|
||||||
|
).rejects.toThrow(
|
||||||
|
"Input 'verify-signature' is enabled, but no signature URL was found for Microsoft Build of OpenJDK version 17.0.14+7."
|
||||||
|
);
|
||||||
|
expect(spyVerifySignature).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('supports signature verification', () => {
|
||||||
|
expect(distribution['supportsSignatureVerification']()).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@ -10,12 +10,16 @@ import {
|
|||||||
getGitHubHttpHeaders,
|
getGitHubHttpHeaders,
|
||||||
renameWinArchive
|
renameWinArchive
|
||||||
} from '../../util';
|
} from '../../util';
|
||||||
|
import * as gpg from '../../gpg';
|
||||||
|
import {MICROSOFT_PUBLIC_KEY} from './microsoft-key';
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as tc from '@actions/tool-cache';
|
import * as tc from '@actions/tool-cache';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import {TypedResponse} from '@actions/http-client/lib/interfaces';
|
import {TypedResponse} from '@actions/http-client/lib/interfaces';
|
||||||
|
|
||||||
|
export {MICROSOFT_PUBLIC_KEY} from './microsoft-key';
|
||||||
|
|
||||||
export class MicrosoftDistributions extends JavaBase {
|
export class MicrosoftDistributions extends JavaBase {
|
||||||
constructor(installerOptions: JavaInstallerOptions) {
|
constructor(installerOptions: JavaInstallerOptions) {
|
||||||
super('Microsoft', installerOptions);
|
super('Microsoft', installerOptions);
|
||||||
@ -29,6 +33,28 @@ export class MicrosoftDistributions extends JavaBase {
|
|||||||
);
|
);
|
||||||
let javaArchivePath = await tc.downloadTool(javaRelease.url);
|
let javaArchivePath = await tc.downloadTool(javaRelease.url);
|
||||||
|
|
||||||
|
if (this.verifySignature) {
|
||||||
|
if (!javaRelease.signatureUrl) {
|
||||||
|
throw new Error(
|
||||||
|
`Input 'verify-signature' is enabled, but no signature URL was found for Microsoft Build of OpenJDK version ${javaRelease.version}.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
core.info(`Verifying Java package signature...`);
|
||||||
|
try {
|
||||||
|
await gpg.verifyPackageSignature(
|
||||||
|
javaArchivePath,
|
||||||
|
javaRelease.signatureUrl,
|
||||||
|
this.verifySignaturePublicKey ?? MICROSOFT_PUBLIC_KEY
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error(
|
||||||
|
`Failed to verify signature for Microsoft Build of OpenJDK version ${javaRelease.version} from ${javaRelease.signatureUrl}: ${
|
||||||
|
(error as Error).message
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
core.info(`Extracting Java archive...`);
|
core.info(`Extracting Java archive...`);
|
||||||
const extension = getDownloadArchiveExtension();
|
const extension = getDownloadArchiveExtension();
|
||||||
if (process.platform === 'win32') {
|
if (process.platform === 'win32') {
|
||||||
@ -82,10 +108,15 @@ export class MicrosoftDistributions extends JavaBase {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
url: foundRelease.files[0].download_url,
|
url: foundRelease.files[0].download_url,
|
||||||
|
signatureUrl: `${foundRelease.files[0].download_url}.sig`,
|
||||||
version: foundRelease.version
|
version: foundRelease.version
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected supportsSignatureVerification(): boolean {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private async getAvailableVersions(): Promise<tc.IToolRelease[] | null> {
|
private async getAvailableVersions(): Promise<tc.IToolRelease[] | null> {
|
||||||
// TODO get these dynamically!
|
// TODO get these dynamically!
|
||||||
// We will need Microsoft to add an endpoint where we can query for versions.
|
// We will need Microsoft to add an endpoint where we can query for versions.
|
||||||
|
|||||||
21
src/distributions/microsoft/microsoft-key.ts
Normal file
21
src/distributions/microsoft/microsoft-key.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
// Microsoft Build of OpenJDK GPG signing key
|
||||||
|
// Retrieved from: https://download.visualstudio.microsoft.com/download/pr/b90071e2-e0cf-4411-98be-dbeb09d67bf0/8622862bcd54206e158c5abca0582c9b/464279_464280_aoc_20210208.asc
|
||||||
|
export const MICROSOFT_PUBLIC_KEY = `-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||||
|
Version: BSN Pgp v1.1.0.0
|
||||||
|
|
||||||
|
mQENBGAhlWcBCADCQjj6huLTenvZSLej35e9YKEHm4lix2uvPOONexMaU8V2v7KL
|
||||||
|
RGdoXF7jwHci7efnPZ+9zpS2+g3rhvv8M7yWy9E/1psEtGzvmp1IL/qIabMEQqi+
|
||||||
|
UlhPGh7MQ/BkXAlic8Dyl3XYqr0EXS11iCiTr6Zkxs9Ee4V54gxL4gogRn4wk9sl
|
||||||
|
/nrjgDzMsUwla0pynoQQvYpqCdiAr3gKKllT1skCDqgVOMMyZxsx9HjZxg/3AJz6
|
||||||
|
r5i512L2R+3Hkv+XmxT+mnGBCFcny0DM7PjNXEmIK3ZSkro1tQML90zx3Fyh5esx
|
||||||
|
fpVvuIXGFV75o35VVCBZoiD3hcfOnIJsPQ9nABEBAAG0OE1pY3Jvc29mdCBKYXZh
|
||||||
|
IEVuZ2luZWVyaW5nIDxqYXZhcGxhdGluZnJhQG1pY3Jvc29mdC5jb20+iQE4BBMB
|
||||||
|
CAAiBQJgIZVnAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRA1Ux0xWyHB
|
||||||
|
icwTCACJO2FGNocNvdUtAb+eDKuGwt0chAJdCES2ZtgBScwrwDyWpxpRznoXWBHL
|
||||||
|
MJeLyxJoKsCG3vVlY4uh48psCzVm3OKvi7MCPT955t8W6TzfSBxTpjR8zRgJkjPJ
|
||||||
|
EGhHTlusUfz7TtM5etJF0qscSJH1grcNsgtee97mk4QyEzT8Di83NQmYxKcBrliq
|
||||||
|
yK/SWWt8VkTyYAEO6L5PoB4L9r8ka27uQs+jgCw+/Z0JMtNmmhyNGY3+a1YtPeoy
|
||||||
|
JdQaI9LphfKGbVaz6SK2aol7vj+c2TG3TLUYdOYGMH1OZlri2GTkCVjwna2GC7p4
|
||||||
|
Fa133tP85xzJEq1XeXm8WeLFo2wV
|
||||||
|
=rHCS
|
||||||
|
-----END PGP PUBLIC KEY BLOCK-----`;
|
||||||
Loading…
Reference in New Issue
Block a user