Verify JDK downloads with vendor checksums (#1167)

* Verify JDK downloads with vendor checksums

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

Copilot-Session: a800a031-600e-4d28-b23e-be309555d38d

* Handle missing vendor checksum values

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

Copilot-Session: a800a031-600e-4d28-b23e-be309555d38d

* Preserve checksum error during cleanup failure

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

Copilot-Session: a800a031-600e-4d28-b23e-be309555d38d

* Validate checksum metadata value types

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

Copilot-Session: a800a031-600e-4d28-b23e-be309555d38d

* Clarify checksum documentation

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

Copilot-Session: a800a031-600e-4d28-b23e-be309555d38d

* Expand vendor checksum verification

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

Copilot-Session: a800a031-600e-4d28-b23e-be309555d38d

* Accept SHA-256 or SHA-512 for JetBrains checksum sibling

JetBrains publishes a single, generically-named ".checksum" sibling
whose digest algorithm isn't disclosed by the filename. Older JBR 11
builds (e.g. jbrsdk_nomod-11_0_16-*-b2043.64.tar.gz) publish a SHA-256
digest there, while newer builds publish SHA-512. The JetBrains
installer previously assumed SHA-512 unconditionally, so verification
failed with "Malformed sha512 checksum metadata ... expected a
128-character hexadecimal digest" for those older builds, breaking the
jetbrains 11 e2e job on macOS and Windows.

fetchChecksum now accepts a list of candidate algorithms and infers
the actual algorithm from the returned digest's length, preferring the
strongest match. The JetBrains installer passes ['sha512', 'sha256'];
all other callers are unaffected since they already pass a single,
vendor-disclosed algorithm.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a800a031-600e-4d28-b23e-be309555d38d

* Use SapMachine archive checksum files

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

Copilot-Session: a800a031-600e-4d28-b23e-be309555d38d

---------

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a800a031-600e-4d28-b23e-be309555d38d
This commit is contained in:
Bruno Borges
2026-07-29 04:43:56 -04:00
committed by GitHub
parent 19c23b379e
commit 27f2c62824
39 changed files with 1629 additions and 103 deletions
@@ -47,8 +47,11 @@ describe('findPackageForDownload', () => {
let distribution: InstanceType<typeof OracleDistribution>;
let spyDebug: any;
let spyHttpClient: any;
let spyHttpClientGet: any;
let spyCoreError: any;
const ORACLE_CHECKSUM = 'f'.repeat(64);
beforeEach(() => {
distribution = new OracleDistribution({
version: '',
@@ -63,6 +66,14 @@ describe('findPackageForDownload', () => {
// Mock core.error to suppress error logs
spyCoreError = core.error as jest.Mock;
spyCoreError.mockImplementation(() => {});
// Every resolved release fetches its `${url}.sha256` sibling checksum;
// stub it so tests never reach the real network.
spyHttpClientGet = jest.spyOn(HttpClient.prototype, 'get');
spyHttpClientGet.mockResolvedValue({
message: {statusCode: 200},
readBody: async () => ORACLE_CHECKSUM
});
});
it.each([
@@ -133,6 +144,23 @@ describe('findPackageForDownload', () => {
expect(result.url).toBe(url);
});
it('fetches the authoritative sha256 checksum for the resolved archive', async () => {
spyHttpClient = jest.spyOn(HttpClient.prototype, 'head');
spyHttpClient.mockResolvedValue({message: {statusCode: 200}});
const result = await distribution['findPackageForDownload']('21');
jest.restoreAllMocks();
expect(result.checksum).toEqual({
algorithm: 'sha256',
value: ORACLE_CHECKSUM,
source: `${result.url}.sha256`
});
expect(spyHttpClientGet).toHaveBeenCalledWith(`${result.url}.sha256`);
expect(spyHttpClientGet).toHaveBeenCalledTimes(1);
});
it.each([
['amd64', 'x64'],
['arm64', 'aarch64']
@@ -196,6 +224,10 @@ describe('findPackageForDownload with latest', () => {
it('resolves the newest major version from the Adoptium API', async () => {
spyHttpClientHead = jest.spyOn(HttpClient.prototype, 'head');
spyHttpClientHead.mockResolvedValue({message: {statusCode: 200}});
jest.spyOn(HttpClient.prototype, 'get').mockResolvedValue({
message: {statusCode: 200},
readBody: async () => 'f'.repeat(64)
} as any);
const distribution = new OracleDistribution({
version: 'latest',