feat: validate content hash for specified versions

Signed-off-by: matttrach <matt.trachier@suse.com>
This commit is contained in:
matttrach 2026-04-09 16:00:32 -05:00
parent 01cbe076be
commit ecbc278ccf
No known key found for this signature in database
GPG key ID: E082F2592F87D4AE
8 changed files with 10859 additions and 51 deletions

View file

@ -1,5 +1,9 @@
import {describe, expect, it} from '@jest/globals';
import { afterAll, beforeAll, describe, expect, it, jest } from '@jest/globals';
import * as crypto from 'crypto';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { checksums } from '../src/checksums';
import * as goreleaser from '../src/goreleaser';
describe('install', () => {
@ -9,8 +13,11 @@ describe('install', () => {
}, 100000);
it('acquires latest version of GoReleaser', async () => {
const stdoutSpy = jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
const bin = await goreleaser.install('goreleaser', 'latest');
expect(fs.existsSync(bin)).toBe(true);
expect(stdoutSpy).toHaveBeenCalledWith(expect.stringContaining('Skipping checksum verification since a specific version was not requested'));
stdoutSpy.mockRestore();
}, 100000);
it('acquires v0.182.0-pro version of GoReleaser Pro', async () => {
@ -42,6 +49,14 @@ describe('install', () => {
const bin = await goreleaser.install('goreleaser-pro', 'latest');
expect(fs.existsSync(bin)).toBe(true);
}, 100000);
it('acquires a random version of GoReleaser', async () => {
const versions = Object.keys(checksums).filter(v => !v.includes('pro'));
const randomVersion = versions[Math.floor(Math.random() * versions.length)];
console.log(`Testing random GoReleaser version: ${randomVersion}`);
const bin = await goreleaser.install('goreleaser', randomVersion);
expect(fs.existsSync(bin)).toBe(true);
}, 100000);
});
describe('distribSuffix', () => {
@ -53,3 +68,32 @@ describe('distribSuffix', () => {
expect(goreleaser.distribSuffix('goreleaser')).toEqual('');
});
});
describe('verifyChecksum', () => {
let testFilePath: string;
let validChecksum: string;
beforeAll(() => {
testFilePath = path.join(os.tmpdir(), 'verify-checksum-test.txt');
const fileContent = 'test content for checksum verification';
fs.writeFileSync(testFilePath, fileContent);
const hash = crypto.createHash('sha256');
hash.update(fileContent);
validChecksum = hash.digest('hex');
});
afterAll(() => {
if (fs.existsSync(testFilePath)) {
fs.unlinkSync(testFilePath);
}
});
it('should resolve successfully when the checksum matches', async () => {
await expect(goreleaser.verifyChecksum(testFilePath, validChecksum)).resolves.toBeUndefined();
});
it('should throw an error when the checksum does not match', async () => {
await expect(goreleaser.verifyChecksum(testFilePath, 'invalid123checksum')).rejects.toThrow(/Checksum mismatch/);
});
});

18
dist/index.js generated vendored

File diff suppressed because one or more lines are too long

852
package-lock.json generated
View file

@ -9,14 +9,15 @@
"dependencies": {
"@actions/core": "^3.0.0",
"@actions/exec": "^3.0.0",
"@actions/http-client": "^4.0.0",
"@actions/tool-cache": "^4.0.0",
"js-yaml": "^4.1.1",
"semver": "^7.7.4",
"yargs": "^18.0.0"
},
"devDependencies": {
"@types/node": "^24.0.0",
"@jest/globals": "^30.3.0",
"@types/jest": "^30.0.0",
"@types/node": "^24.12.2",
"@typescript-eslint/eslint-plugin": "^6.6.0",
"@typescript-eslint/parser": "^6.6.0",
"@vercel/ncc": "^0.38.0",
@ -29,7 +30,6 @@
"prettier": "^3.0.3",
"tmp": "^0.2.1",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
}
},
@ -603,6 +603,8 @@
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jridgewell/trace-mapping": "0.3.9"
},
@ -616,6 +618,8 @@
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
@ -953,6 +957,16 @@
}
}
},
"node_modules/@jest/diff-sequences": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/@jest/diff-sequences/-/diff-sequences-30.3.0.tgz",
"integrity": "sha512-cG51MVnLq1ecVUaQ3fr6YuuAOitHK1S4WUJHnsPFE/quQr33ADUx1FfrTCpMCRxvy0Yr9BThKpDjSlcTi91tMA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/environment": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz",
@ -1014,20 +1028,499 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/@jest/get-type": {
"version": "30.1.0",
"resolved": "https://registry.npmjs.org/@jest/get-type/-/get-type-30.1.0.tgz",
"integrity": "sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz",
"integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==",
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/@jest/globals/-/globals-30.3.0.tgz",
"integrity": "sha512-+owLCBBdfpgL3HU+BD5etr1SvbXpSitJK0is1kiYjJxAAJggYMRQz5hSdd5pq1sSggfxPbw2ld71pt4x5wwViA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/environment": "^29.7.0",
"@jest/expect": "^29.7.0",
"@jest/types": "^29.6.3",
"jest-mock": "^29.7.0"
"@jest/environment": "30.3.0",
"@jest/expect": "30.3.0",
"@jest/types": "30.3.0",
"jest-mock": "30.3.0"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/@jest/environment": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/@jest/environment/-/environment-30.3.0.tgz",
"integrity": "sha512-SlLSF4Be735yQXyh2+mctBOzNDx5s5uLv88/j8Qn1wH679PDcwy67+YdADn8NJnGjzlXtN62asGH/T4vWOkfaw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/fake-timers": "30.3.0",
"@jest/types": "30.3.0",
"@types/node": "*",
"jest-mock": "30.3.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/@jest/expect": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/@jest/expect/-/expect-30.3.0.tgz",
"integrity": "sha512-76Nlh4xJxk2D/9URCn3wFi98d2hb19uWE1idLsTt2ywhvdOldbw3S570hBgn25P4ICUZ/cBjybrBex2g17IDbg==",
"dev": true,
"license": "MIT",
"dependencies": {
"expect": "30.3.0",
"jest-snapshot": "30.3.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/@jest/expect-utils": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.3.0.tgz",
"integrity": "sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/get-type": "30.1.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/@jest/fake-timers": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-30.3.0.tgz",
"integrity": "sha512-WUQDs8SOP9URStX1DzhD425CqbN/HxUYCTwVrT8sTVBfMvFqYt/s61EK5T05qnHu0po6RitXIvP9otZxYDzTGQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.3.0",
"@sinonjs/fake-timers": "^15.0.0",
"@types/node": "*",
"jest-message-util": "30.3.0",
"jest-mock": "30.3.0",
"jest-util": "30.3.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@sinclair/typebox": "^0.34.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/@jest/transform": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/@jest/transform/-/transform-30.3.0.tgz",
"integrity": "sha512-TLKY33fSLVd/lKB2YI1pH69ijyUblO/BQvCj566YvnwuzoTNr648iE0j22vRvVNk2HsPwByPxATg3MleS3gf5A==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.27.4",
"@jest/types": "30.3.0",
"@jridgewell/trace-mapping": "^0.3.25",
"babel-plugin-istanbul": "^7.0.1",
"chalk": "^4.1.2",
"convert-source-map": "^2.0.0",
"fast-json-stable-stringify": "^2.1.0",
"graceful-fs": "^4.2.11",
"jest-haste-map": "30.3.0",
"jest-regex-util": "30.0.1",
"jest-util": "30.3.0",
"pirates": "^4.0.7",
"slash": "^3.0.0",
"write-file-atomic": "^5.0.1"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/@jest/types": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.3.0.tgz",
"integrity": "sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
"@types/yargs": "^17.0.33",
"chalk": "^4.1.2"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/@sinclair/typebox": {
"version": "0.34.49",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz",
"integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==",
"dev": true,
"license": "MIT"
},
"node_modules/@jest/globals/node_modules/@sinonjs/fake-timers": {
"version": "15.3.0",
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.3.0.tgz",
"integrity": "sha512-m2xozxSfCIxjDdvbhIWazlP2i2aha/iUmbl94alpsIbd3iLTfeXgfBVbwyWogB6l++istyGZqamgA/EcqYf+Bg==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"@sinonjs/commons": "^3.0.1"
}
},
"node_modules/@jest/globals/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/@jest/globals/node_modules/babel-plugin-istanbul": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz",
"integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==",
"dev": true,
"license": "BSD-3-Clause",
"workspaces": [
"test/babel-8"
],
"dependencies": {
"@babel/helper-plugin-utils": "^7.0.0",
"@istanbuljs/load-nyc-config": "^1.0.0",
"@istanbuljs/schema": "^0.1.3",
"istanbul-lib-instrument": "^6.0.2",
"test-exclude": "^6.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@jest/globals/node_modules/ci-info": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz",
"integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/sibiraj-s"
}
],
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/@jest/globals/node_modules/expect": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/expect/-/expect-30.3.0.tgz",
"integrity": "sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/expect-utils": "30.3.0",
"@jest/get-type": "30.1.0",
"jest-matcher-utils": "30.3.0",
"jest-message-util": "30.3.0",
"jest-mock": "30.3.0",
"jest-util": "30.3.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/jest-diff": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.3.0.tgz",
"integrity": "sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/diff-sequences": "30.3.0",
"@jest/get-type": "30.1.0",
"chalk": "^4.1.2",
"pretty-format": "30.3.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/jest-haste-map": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-30.3.0.tgz",
"integrity": "sha512-mMi2oqG4KRU0R9QEtscl87JzMXfUhbKaFqOxmjb2CKcbHcUGFrJCBWHmnTiUqi6JcnzoBlO4rWfpdl2k/RfLCA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.3.0",
"@types/node": "*",
"anymatch": "^3.1.3",
"fb-watchman": "^2.0.2",
"graceful-fs": "^4.2.11",
"jest-regex-util": "30.0.1",
"jest-util": "30.3.0",
"jest-worker": "30.3.0",
"picomatch": "^4.0.3",
"walker": "^1.0.8"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
},
"optionalDependencies": {
"fsevents": "^2.3.3"
}
},
"node_modules/@jest/globals/node_modules/jest-matcher-utils": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.3.0.tgz",
"integrity": "sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/get-type": "30.1.0",
"chalk": "^4.1.2",
"jest-diff": "30.3.0",
"pretty-format": "30.3.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/jest-message-util": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.3.0.tgz",
"integrity": "sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.3.0",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"picomatch": "^4.0.3",
"pretty-format": "30.3.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/jest-mock": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.3.0.tgz",
"integrity": "sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.3.0",
"@types/node": "*",
"jest-util": "30.3.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/jest-regex-util": {
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz",
"integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/jest-snapshot": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-30.3.0.tgz",
"integrity": "sha512-f14c7atpb4O2DeNhwcvS810Y63wEn8O1HqK/luJ4F6M4NjvxmAKQwBUWjbExUtMxWJQ0wVgmCKymeJK6NZMnfQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/core": "^7.27.4",
"@babel/generator": "^7.27.5",
"@babel/plugin-syntax-jsx": "^7.27.1",
"@babel/plugin-syntax-typescript": "^7.27.1",
"@babel/types": "^7.27.3",
"@jest/expect-utils": "30.3.0",
"@jest/get-type": "30.1.0",
"@jest/snapshot-utils": "30.3.0",
"@jest/transform": "30.3.0",
"@jest/types": "30.3.0",
"babel-preset-current-node-syntax": "^1.2.0",
"chalk": "^4.1.2",
"expect": "30.3.0",
"graceful-fs": "^4.2.11",
"jest-diff": "30.3.0",
"jest-matcher-utils": "30.3.0",
"jest-message-util": "30.3.0",
"jest-util": "30.3.0",
"pretty-format": "30.3.0",
"semver": "^7.7.2",
"synckit": "^0.11.8"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/jest-util": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.3.0.tgz",
"integrity": "sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.3.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
"graceful-fs": "^4.2.11",
"picomatch": "^4.0.3"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/jest-worker": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-30.3.0.tgz",
"integrity": "sha512-DrCKkaQwHexjRUFTmPzs7sHQe0TSj9nvDALKGdwmK5mW9v7j90BudWirKAJHt3QQ9Dhrg1F7DogPzhChppkJpQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*",
"@ungap/structured-clone": "^1.3.0",
"jest-util": "30.3.0",
"merge-stream": "^2.0.0",
"supports-color": "^8.1.1"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/picomatch": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/@jest/globals/node_modules/pretty-format": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz",
"integrity": "sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/schemas": "30.0.5",
"ansi-styles": "^5.2.0",
"react-is": "^18.3.1"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/globals/node_modules/signal-exit": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">=14"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@jest/globals/node_modules/supports-color": {
"version": "8.1.1",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"has-flag": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/@jest/globals/node_modules/write-file-atomic": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz",
"integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==",
"dev": true,
"license": "ISC",
"dependencies": {
"imurmurhash": "^0.1.4",
"signal-exit": "^4.0.1"
},
"engines": {
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
}
},
"node_modules/@jest/pattern": {
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/@jest/pattern/-/pattern-30.0.1.tgz",
"integrity": "sha512-gWp7NfQW27LaBQz3TITS8L7ZCQ0TLvtmI//4OwlQRx4rnWxcPNIYjxZpDcN4+UlGxgm3jS5QPz8IPTCkb59wZA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/node": "*",
"jest-regex-util": "30.0.1"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/pattern/node_modules/jest-regex-util": {
"version": "30.0.1",
"resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-30.0.1.tgz",
"integrity": "sha512-jHEQgBXAgc+Gh4g0p3bCevgRCVRkB4VB70zhoAE48gxeSr1hfUOsM/C2WoJgVL7Eyg//hudYENbm3Ne+/dRVVA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/reporters": {
@ -1087,6 +1580,61 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/@jest/snapshot-utils": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/@jest/snapshot-utils/-/snapshot-utils-30.3.0.tgz",
"integrity": "sha512-ORbRN9sf5PP82v3FXNSwmO1OTDR2vzR2YTaR+E3VkSBZ8zadQE6IqYdYEeFH1NIkeB2HIGdF02dapb6K0Mj05g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.3.0",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"natural-compare": "^1.4.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/snapshot-utils/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@sinclair/typebox": "^0.34.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/snapshot-utils/node_modules/@jest/types": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.3.0.tgz",
"integrity": "sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
"@types/yargs": "^17.0.33",
"chalk": "^4.1.2"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@jest/snapshot-utils/node_modules/@sinclair/typebox": {
"version": "0.34.49",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz",
"integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==",
"dev": true,
"license": "MIT"
},
"node_modules/@jest/source-map": {
"version": "29.6.3",
"resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz",
@ -1312,28 +1860,36 @@
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz",
"integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==",
"dev": true,
"license": "MIT"
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@tsconfig/node12": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
"dev": true,
"license": "MIT"
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@tsconfig/node14": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
"dev": true,
"license": "MIT"
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@tsconfig/node16": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
"dev": true,
"license": "MIT"
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
@ -1417,6 +1973,230 @@
"@types/istanbul-lib-report": "*"
}
},
"node_modules/@types/jest": {
"version": "30.0.0",
"resolved": "https://registry.npmjs.org/@types/jest/-/jest-30.0.0.tgz",
"integrity": "sha512-XTYugzhuwqWjws0CVz8QpM36+T+Dz5mTEBKhNs/esGLnCIlGdRy+Dq78NRjd7ls7r8BC8ZRMOrKlkO1hU0JOwA==",
"dev": true,
"license": "MIT",
"dependencies": {
"expect": "^30.0.0",
"pretty-format": "^30.0.0"
}
},
"node_modules/@types/jest/node_modules/@jest/expect-utils": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-30.3.0.tgz",
"integrity": "sha512-j0+W5iQQ8hBh7tHZkTQv3q2Fh/M7Je72cIsYqC4OaktgtO7v1So9UTjp6uPBHIaB6beoF/RRsCgMJKvti0wADA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/get-type": "30.1.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@types/jest/node_modules/@jest/schemas": {
"version": "30.0.5",
"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-30.0.5.tgz",
"integrity": "sha512-DmdYgtezMkh3cpU8/1uyXakv3tJRcmcXxBOcO0tbaozPwpmh4YMsnWrQm9ZmZMfa5ocbxzbFk6O4bDPEc/iAnA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@sinclair/typebox": "^0.34.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@types/jest/node_modules/@jest/types": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/@jest/types/-/types-30.3.0.tgz",
"integrity": "sha512-JHm87k7bA33hpBngtU8h6UBub/fqqA9uXfw+21j5Hmk7ooPHlboRNxHq0JcMtC+n8VJGP1mcfnD3Mk+XKe1oSw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/pattern": "30.0.1",
"@jest/schemas": "30.0.5",
"@types/istanbul-lib-coverage": "^2.0.6",
"@types/istanbul-reports": "^3.0.4",
"@types/node": "*",
"@types/yargs": "^17.0.33",
"chalk": "^4.1.2"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@types/jest/node_modules/@sinclair/typebox": {
"version": "0.34.49",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.34.49.tgz",
"integrity": "sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/jest/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/@types/jest/node_modules/ci-info": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz",
"integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/sibiraj-s"
}
],
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/@types/jest/node_modules/expect": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/expect/-/expect-30.3.0.tgz",
"integrity": "sha512-1zQrciTiQfRdo7qJM1uG4navm8DayFa2TgCSRlzUyNkhcJ6XUZF3hjnpkyr3VhAqPH7i/9GkG7Tv5abz6fqz0Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/expect-utils": "30.3.0",
"@jest/get-type": "30.1.0",
"jest-matcher-utils": "30.3.0",
"jest-message-util": "30.3.0",
"jest-mock": "30.3.0",
"jest-util": "30.3.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@types/jest/node_modules/jest-diff": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-30.3.0.tgz",
"integrity": "sha512-n3q4PDQjS4LrKxfWB3Z5KNk1XjXtZTBwQp71OP0Jo03Z6V60x++K5L8k6ZrW8MY8pOFylZvHM0zsjS1RqlHJZQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/diff-sequences": "30.3.0",
"@jest/get-type": "30.1.0",
"chalk": "^4.1.2",
"pretty-format": "30.3.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@types/jest/node_modules/jest-matcher-utils": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-30.3.0.tgz",
"integrity": "sha512-HEtc9uFQgaUHkC7nLSlQL3Tph4Pjxt/yiPvkIrrDCt9jhoLIgxaubo1G+CFOnmHYMxHwwdaSN7mkIFs6ZK8OhA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/get-type": "30.1.0",
"chalk": "^4.1.2",
"jest-diff": "30.3.0",
"pretty-format": "30.3.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@types/jest/node_modules/jest-message-util": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-30.3.0.tgz",
"integrity": "sha512-Z/j4Bo+4ySJ+JPJN3b2Qbl9hDq3VrXmnjjGEWD/x0BCXeOXPTV1iZYYzl2X8c1MaCOL+ewMyNBcm88sboE6YWw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@jest/types": "30.3.0",
"@types/stack-utils": "^2.0.3",
"chalk": "^4.1.2",
"graceful-fs": "^4.2.11",
"picomatch": "^4.0.3",
"pretty-format": "30.3.0",
"slash": "^3.0.0",
"stack-utils": "^2.0.6"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@types/jest/node_modules/jest-mock": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-30.3.0.tgz",
"integrity": "sha512-OTzICK8CpE+t4ndhKrwlIdbM6Pn8j00lvmSmq5ejiO+KxukbLjgOflKWMn3KE34EZdQm5RqTuKj+5RIEniYhog==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.3.0",
"@types/node": "*",
"jest-util": "30.3.0"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@types/jest/node_modules/jest-util": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/jest-util/-/jest-util-30.3.0.tgz",
"integrity": "sha512-/jZDa00a3Sz7rdyu55NLrQCIrbyIkbBxareejQI315f/i8HjYN+ZWsDLLpoQSiUIEIyZF/R8fDg3BmB8AtHttg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/types": "30.3.0",
"@types/node": "*",
"chalk": "^4.1.2",
"ci-info": "^4.2.0",
"graceful-fs": "^4.2.11",
"picomatch": "^4.0.3"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@types/jest/node_modules/picomatch": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/@types/jest/node_modules/pretty-format": {
"version": "30.3.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-30.3.0.tgz",
"integrity": "sha512-oG4T3wCbfeuvljnyAzhBvpN45E8iOTXCU/TD3zXW80HA3dQ4ahdqMkWGiPWZvjpQwlbyHrPTWUAqUzGzv4l1JQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/schemas": "30.0.5",
"ansi-styles": "^5.2.0",
"react-is": "^18.3.1"
},
"engines": {
"node": "^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0"
}
},
"node_modules/@types/json-schema": {
"version": "7.0.15",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
@ -1425,9 +2205,9 @@
"license": "MIT"
},
"node_modules/@types/node": {
"version": "24.10.9",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.9.tgz",
"integrity": "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==",
"version": "24.12.2",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.2.tgz",
"integrity": "sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==",
"dev": true,
"license": "MIT",
"dependencies": {
@ -1709,6 +2489,8 @@
"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"acorn": "^8.11.0"
},
@ -1807,7 +2589,9 @@
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true,
"license": "MIT"
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/argparse": {
"version": "2.0.1",
@ -2266,7 +3050,9 @@
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true,
"license": "MIT"
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/cross-spawn": {
"version": "7.0.6",
@ -2349,6 +3135,8 @@
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true,
"license": "BSD-3-Clause",
"optional": true,
"peer": true,
"engines": {
"node": ">=0.3.1"
}
@ -4076,6 +4864,22 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/jest-runtime/node_modules/@jest/globals": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz",
"integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jest/environment": "^29.7.0",
"@jest/expect": "^29.7.0",
"@jest/types": "^29.6.3",
"jest-mock": "^29.7.0"
},
"engines": {
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
"node_modules/jest-snapshot": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz",
@ -5474,6 +6278,8 @@
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
@ -5670,7 +6476,9 @@
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
"dev": true,
"license": "MIT"
"license": "MIT",
"optional": true,
"peer": true
},
"node_modules/v8-to-istanbul": {
"version": "9.3.0",
@ -5865,6 +6673,8 @@
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
"dev": true,
"license": "MIT",
"optional": true,
"peer": true,
"engines": {
"node": ">=6"
}

View file

@ -25,18 +25,18 @@
],
"author": "CrazyMax",
"license": "MIT",
"dependencies": {
"@actions/core": "^3.0.0",
"@actions/exec": "^3.0.0",
"@actions/http-client": "^4.0.0",
"@actions/tool-cache": "^4.0.0",
"js-yaml": "^4.1.1",
"semver": "^7.7.4",
"yargs": "^18.0.0"
},
"devDependencies": {
"@types/node": "^24.0.0",
"@jest/globals": "^30.3.0",
"@types/jest": "^30.0.0",
"@types/node": "^24.12.2",
"@typescript-eslint/eslint-plugin": "^6.6.0",
"@typescript-eslint/parser": "^6.6.0",
"@vercel/ncc": "^0.38.0",
@ -49,7 +49,6 @@
"prettier": "^3.0.3",
"tmp": "^0.2.1",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"typescript": "^5.2.2"
}
}

9791
src/checksums.ts Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
import * as goreleaser from './goreleaser';
import * as semver from 'semver';
import * as core from '@actions/core';
import * as httpm from '@actions/http-client';
import * as semver from 'semver';
import * as goreleaser from './goreleaser';
const maxRetries = 10;
const timeoutMs = 1000;
@ -18,8 +18,9 @@ const withRetry = async <T>(operation: () => Promise<T>): Promise<T> => {
break;
}
core.debug(`Attempt ${attempt + 1} failed, retrying in ${timeoutMs}: ${lastError.message}`);
await new Promise(resolve => setTimeout(resolve, timeoutMs));
const delay = Math.min(30000, timeoutMs * Math.pow(2, attempt));
core.debug(`Attempt ${attempt + 1} failed, retrying in ${delay}ms: ${lastError.message}`);
await new Promise(resolve => setTimeout(resolve, delay));
}
}
@ -74,7 +75,7 @@ export const getReleaseTag = async (distribution: string, version: string): Prom
return <Array<GitHubRelease>>JSON.parse(body);
});
const res = releases.filter(r => r.tag_name === tag).shift();
const res = releases.find(r => r.tag_name === tag);
if (res) {
return res;
}

View file

@ -1,11 +1,14 @@
import * as fs from 'fs';
import * as path from 'path';
import * as util from 'util';
import yaml from 'js-yaml';
import * as context from './context';
import * as github from './github';
import * as core from '@actions/core';
import * as tc from '@actions/tool-cache';
import * as crypto from 'crypto';
import * as fs from 'fs';
import yaml from 'js-yaml';
import * as path from 'path';
import * as semver from 'semver';
import * as util from 'util';
import { checksums } from './checksums';
import * as context from './context';
import * as github from './github';
export async function install(distribution: string, version: string): Promise<string> {
const release: github.GitHubRelease = await github.getRelease(distribution, version);
@ -21,6 +24,22 @@ export async function install(distribution: string, version: string): Promise<st
const downloadPath: string = await tc.downloadTool(downloadUrl);
core.debug(`Downloaded to ${downloadPath}`);
const isExactVersion = !!semver.valid(version);
if (isExactVersion) {
core.info('Verifying checksum');
const versionChecksums = checksums[release.tag_name];
if (!versionChecksums) {
throw new Error(`Checksums for version ${release.tag_name} not found.`);
}
const expectedChecksum = versionChecksums[filename];
if (!expectedChecksum) {
throw new Error(`Checksum for ${filename} at version ${release.tag_name} not found.`);
}
await verifyChecksum(downloadPath, expectedChecksum);
} else {
core.info('Skipping checksum verification since a specific version was not requested');
}
core.info('Extracting GoReleaser');
let extPath: string;
if (context.osPlat == 'win32') {
@ -39,7 +58,10 @@ export async function install(distribution: string, version: string): Promise<st
const cachePath: string = await tc.cacheDir(extPath, 'goreleaser-action', release.tag_name.replace(/^v/, ''));
core.debug(`Cached to ${cachePath}`);
const exePath: string = path.join(cachePath, context.osPlat == 'win32' ? 'goreleaser.exe' : 'goreleaser');
let exePath: string = path.join(cachePath, context.osPlat == 'win32' ? 'goreleaser.exe' : 'goreleaser');
if (!fs.existsSync(exePath)) {
exePath = path.join(cachePath, context.osPlat == 'win32' ? 'goreleaser-pro.exe' : 'goreleaser-pro');
}
core.debug(`Exe path is ${exePath}`);
return exePath;
@ -85,8 +107,8 @@ const getFilename = (distribution: string): string => {
};
export async function getDistPath(yamlfile: string): Promise<string> {
const cfg = yaml.load(fs.readFileSync(yamlfile, 'utf8'));
return cfg.dist || 'dist';
const cfg = yaml.load(await fs.promises.readFile(yamlfile, 'utf8')) as { dist?: string };
return cfg?.dist || 'dist';
}
export async function getArtifacts(distpath: string): Promise<string | undefined> {
@ -94,19 +116,36 @@ export async function getArtifacts(distpath: string): Promise<string | undefined
if (!fs.existsSync(artifactsFile)) {
return undefined;
}
const content = fs.readFileSync(artifactsFile, {encoding: 'utf-8'}).trim();
const content = (await fs.promises.readFile(artifactsFile, {encoding: 'utf-8'})).trim();
if (content === 'null') {
return undefined;
}
return content;
}
export async function verifyChecksum(filePath: string, expectedChecksum: string): Promise<void> {
return new Promise((resolve, reject) => {
const hash = crypto.createHash('sha256');
const stream = fs.createReadStream(filePath);
stream.on('data', data => hash.update(data));
stream.on('end', () => {
const actualChecksum = hash.digest('hex');
if (actualChecksum !== expectedChecksum) {
reject(new Error(`Checksum mismatch. Expected ${expectedChecksum}, got ${actualChecksum}`));
} else {
resolve();
}
});
stream.on('error', err => reject(err));
});
}
export async function getMetadata(distpath: string): Promise<string | undefined> {
const metadataFile = path.join(distpath, 'metadata.json');
if (!fs.existsSync(metadataFile)) {
return undefined;
}
const content = fs.readFileSync(metadataFile, {encoding: 'utf-8'}).trim();
const content = (await fs.promises.readFile(metadataFile, {encoding: 'utf-8'})).trim();
if (content === 'null') {
return undefined;
}

124
update-checksums.sh Executable file
View file

@ -0,0 +1,124 @@
#!/usr/bin/env bash
set -euo pipefail
if ! command -v jq &> /dev/null; then
echo "Error: jq is required but not installed."
exit 1
fi
# don't go back further than v0.180
MIN_MAJOR=0
MIN_MINOR=182
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
OUT_FILE="$DIR/src/checksums.ts"
FLAT_FILE=$(mktemp)
trap 'rm -f "$FLAT_FILE"' EXIT
echo "Loading existing checksums..."
if [ -f "$OUT_FILE" ]; then
EXISTING_JSON=$(grep -v "^//" "$OUT_FILE" | sed -e 's/^export const checksums.*= //' -e 's/;$//' || echo "{}")
if ! echo "$EXISTING_JSON" | jq empty >/dev/null 2>&1; then
echo "[WARNING] Existing checksums.ts is not valid JSON. Starting fresh."
EXISTING_JSON="{}"
fi
else
EXISTING_JSON="{}"
fi
EXISTING_KEYS=$(echo "$EXISTING_JSON" | jq -r 'keys[]' 2>/dev/null || echo "")
FETCHED_URLS=""
fetch_checksums() {
local tag=$1
local repo=$2
if [ "$tag" = "null" ] || [ -z "$tag" ]; then
return
fi
local clean_v=$(echo "$tag" | sed 's/^v//' | sed 's/-pro$//' | sed 's/~pro$//')
local major=$(echo "$clean_v" | cut -d. -f1 || echo "")
local minor=$(echo "$clean_v" | cut -d. -f2 || echo "")
if [[ "$major" =~ ^[0-9]+$ ]] && [[ "$minor" =~ ^[0-9]+$ ]]; then
if [ "$major" -eq "$MIN_MAJOR" ] && [ "$minor" -lt "$MIN_MINOR" ]; then
return
fi
fi
if echo "$EXISTING_KEYS" | grep -F -q -x "$tag"; then
echo "Checksums for $tag ($repo) already exist, skipping."
return
fi
local url="https://github.com/goreleaser/$repo/releases/download/$tag/checksums.txt"
# Check if we already fetched this exact url
if echo " $FETCHED_URLS " | grep -q " $url "; then
return
fi
echo "Fetching checksums for $tag ($repo)..."
local checksums
# Try the standard checksums.txt, or fallback to the older naming convention
checksums=$(curl -sfL "$url" || curl -sfL "https://github.com/goreleaser/$repo/releases/download/$tag/${repo}_checksums.txt" || true)
if [ -z "$checksums" ]; then
echo "[WARNING] Failed to fetch checksums for $tag at $url"
return
fi
checksums=$(echo "$checksums" | tr -d '\r')
FETCHED_URLS="$FETCHED_URLS $url "
while read -r sha256 filename; do
if [ -z "$sha256" ] || [ -z "$filename" ]; then continue; fi
echo "$tag $filename $sha256" >> "$FLAT_FILE"
done <<< "$checksums"
}
echo "Fetching all GoReleaser tags..."
GORELEASER_TAGS=$(curl -sfL "https://goreleaser.com/releases.json" | jq -r '.[].tag_name')
for tag in $GORELEASER_TAGS; do
fetch_checksums "$tag" "goreleaser"
done
echo "Fetching all GoReleaser Pro tags..."
PRO_TAGS=$(curl -sfL "https://goreleaser.com/releases-pro.json" | jq -r '.[].tag_name')
for tag in $PRO_TAGS; do
# Pro tags older than 2.7.0 are resolved with a `-pro` suffix by the action
clean_v=$(echo "$tag" | sed 's/^v//' | sed 's/-pro$//' | sed 's/~pro$//')
major=$(echo "$clean_v" | cut -d. -f1 || echo "")
minor=$(echo "$clean_v" | cut -d. -f2 || echo "")
if [[ "$major" =~ ^[0-9]+$ ]] && [[ "$minor" =~ ^[0-9]+$ ]]; then
if [ "$major" -lt 2 ] || ( [ "$major" -eq 2 ] && [ "$minor" -lt 7 ] ); then
if [[ "$tag" != *"-pro" ]]; then
tag="${tag}-pro"
fi
fi
fi
fetch_checksums "$tag" "goreleaser-pro"
done
echo "Merging new checksums with existing..."
NEW_JSON=$(jq -n -R '
reduce inputs as $line ({};
($line | split(" ")) as $parts |
if ($parts | length) >= 3 then
.[$parts[0]][$parts[1]] = $parts[2]
else
.
end
)
' < "$FLAT_FILE")
MERGED_JSON=$(echo "$EXISTING_JSON" | jq --argjson new "$NEW_JSON" '. * $new')
echo "// This file contains sha256 checksums of GoReleaser binaries." > "$OUT_FILE"
echo "// Auto-generated by update-checksums.sh" >> "$OUT_FILE"
echo -n "export const checksums: Record<string, Record<string, string>> = " >> "$OUT_FILE"
echo "$MERGED_JSON;" >> "$OUT_FILE"
echo -e "\nSuccessfully updated src/checksums.ts!"