From a0f80383135e7e534fa91ac697eeb0c0f5ea6321 Mon Sep 17 00:00:00 2001 From: Daniel Banck Date: Mon, 14 Mar 2022 11:40:31 +0100 Subject: [PATCH 1/6] add test case for checksum download --- src/index.test.ts | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/src/index.test.ts b/src/index.test.ts index 9cfe86b..27cfea7 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,7 +1,7 @@ import * as assert from 'assert'; import * as path from 'path'; -import { Release, getRelease } from './index'; +import { Release } from './index'; describe('LS installer', () => { it('should calculate correct file sha256 sum', async () => { @@ -13,4 +13,34 @@ describe('LS installer', () => { assert.strictEqual(sum, expectedSum); }); + it('should download the correct sha256 sum', async () => { + const validSum = + '8629ccc47ee8d4dfe6d23efb93b293948a088a936180d07d3f2ed118f6dd64a5'; + const release = new Release({ + name: 'terraform-ls', + version: '0.25.2', + shasums: 'terraform-ls_0.25.2_SHA256SUMS', + shasums_signature: 'terraform-ls_0.25.2_SHA256SUMS.sig', + shasums_signatures: [ + 'terraform-ls_0.25.2_SHA256SUMS.72D7468F.sig', + 'terraform-ls_0.25.2_SHA256SUMS.sig', + ], + builds: [ + { + name: 'terraform-ls', + version: '0.25.2', + os: 'darwin', + arch: 'amd64', + filename: 'terraform-ls_0.25.2_darwin_amd64.zip', + url: 'https://releases.hashicorp.com/terraform-ls/0.25.2/terraform-ls_0.25.2_darwin_amd64.zip', + }, + ], + }); + + const remoteSum = await release.downloadSha256Sum( + release.builds[0].filename + ); + + assert.strictEqual(remoteSum, validSum); + }); }); From aa1938cb2defc8a340930d61173b868ba63b5c5d Mon Sep 17 00:00:00 2001 From: Daniel Banck Date: Mon, 14 Mar 2022 11:45:19 +0100 Subject: [PATCH 2/6] set correct responseType for shasum downloads The default axios responseType is 'json'. In this case we're downloading a text file (list of shasums) and a binary file (the signature), so different responeTypes are required. --- src/index.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/index.ts b/src/index.ts index 472a08b..61625bf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -158,7 +158,7 @@ export class Release { this.shasums_signature = release.shasums_signature; } } - + public getBuild(platform: string, arch: string): Build { return this.builds.find(b => b.os === platform && b.arch === arch); } @@ -168,7 +168,7 @@ export class Release { return new Promise(async (resolve, reject) => { try { - const result = await request(downloadUrl, {headers: {...headers}, responseType: 'stream'}); + const result = await request(downloadUrl, { headers: { ...headers }, responseType: 'stream' }); result.pipe(fs.createWriteStream(installPath)) resolve(); } catch (e) { @@ -200,8 +200,12 @@ export class Release { async downloadSha256Sum(buildName: string): Promise { const [shasumsResponse, shasumsSignature] = await Promise.all([ - request(`${releasesUrl}/${this.name}/${this.version}/${this.shasums}`), - request(`${releasesUrl}/${this.name}/${this.version}/${this.shasums_signature}`), + request(`${releasesUrl}/${this.name}/${this.version}/${this.shasums}`, { + responseType: 'text' + }), + request(`${releasesUrl}/${this.name}/${this.version}/${this.shasums_signature}`, { + responseType: 'arraybuffer' + }), ]); const publicKey = await openpgp.readKey({ armoredKey: hashiPublicKey }); const signature = await openpgp.readSignature({ binarySignature: Buffer.from(shasumsSignature, 'hex') }); From da53386d49faae38ec0155b19393cd3802e2414c Mon Sep 17 00:00:00 2001 From: Daniel Banck Date: Mon, 14 Mar 2022 12:29:14 +0100 Subject: [PATCH 3/6] add test for downloading and validating a release --- package-lock.json | 246 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + src/index.test.ts | 46 ++++++--- 3 files changed, 280 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index fb86b8b..1cf8a0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,6 +4,32 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, "@tootallnate/once": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", @@ -59,6 +85,16 @@ "debug": "4" } }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, "ansi-colors": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", @@ -102,6 +138,12 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, "asn1.js": { "version": "5.4.1", "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", @@ -230,6 +272,12 @@ "readdirp": "~3.6.0" } }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, "cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -273,6 +321,12 @@ "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, "data-uri-to-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz", @@ -315,6 +369,22 @@ "vm2": "^3.9.3" } }, + "del": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", + "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", + "dev": true, + "requires": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + } + }, "depd": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", @@ -326,6 +396,15 @@ "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -371,11 +450,33 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, + "fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, "fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, "fd-slicer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", @@ -493,6 +594,20 @@ "is-glob": "^4.0.1" } }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, "graceful-fs": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz", @@ -555,6 +670,18 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -611,12 +738,30 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, "is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", "dev": true }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, "is-unicode-supported": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", @@ -693,6 +838,22 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dev": true, + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -835,6 +996,15 @@ "p-limit": "^3.0.2" } }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, "pac-proxy-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz", @@ -873,6 +1043,12 @@ "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", "dev": true }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, "pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", @@ -924,6 +1100,12 @@ "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -970,6 +1152,30 @@ "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", "dev": true }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -1003,6 +1209,12 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, "smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -1087,6 +1299,25 @@ "has-flag": "^4.0.0" } }, + "temp-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz", + "integrity": "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==", + "dev": true + }, + "tempy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tempy/-/tempy-1.0.1.tgz", + "integrity": "sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==", + "dev": true, + "requires": { + "del": "^6.0.0", + "is-stream": "^2.0.0", + "temp-dir": "^2.0.0", + "type-fest": "^0.16.0", + "unique-string": "^2.0.0" + } + }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1128,12 +1359,27 @@ "prelude-ls": "~1.1.2" } }, + "type-fest": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz", + "integrity": "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==", + "dev": true + }, "typescript": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", "dev": true }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, "universalify": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", diff --git a/package.json b/package.json index bd081d4..92661f9 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@types/node": "^14.18.10", "@types/yauzl": "^2.9.2", "mocha": "^9.2.0", + "tempy": "^1.0.1", "ts-node": "^9.1.1", "typescript": "^4.2.4" } diff --git a/src/index.test.ts b/src/index.test.ts index 27cfea7..06488d9 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,22 +1,16 @@ import * as assert from 'assert'; import * as path from 'path'; +import * as fs from 'fs'; +import * as tempy from 'tempy'; + import { Release } from './index'; describe('LS installer', () => { - it('should calculate correct file sha256 sum', async () => { - const release = new Release({ name: "terraform-ls", version: "1.0.0" }); - const expectedSum = "0314c6a66b059bde92c5ed0f11601c144cbd916eff6d1241b5b44e076e5888dc"; - const testPath = path.resolve(__dirname, "..", "testFixture", "shasumtest.txt"); + let release; - const sum = await release.calculateFileSha256Sum(testPath); - assert.strictEqual(sum, expectedSum); - }); - - it('should download the correct sha256 sum', async () => { - const validSum = - '8629ccc47ee8d4dfe6d23efb93b293948a088a936180d07d3f2ed118f6dd64a5'; - const release = new Release({ + before(() => { + release = new Release({ name: 'terraform-ls', version: '0.25.2', shasums: 'terraform-ls_0.25.2_SHA256SUMS', @@ -36,11 +30,37 @@ describe('LS installer', () => { }, ], }); + }); + + it('should calculate correct file sha256 sum', async () => { + const expectedSum = "0314c6a66b059bde92c5ed0f11601c144cbd916eff6d1241b5b44e076e5888dc"; + const testPath = path.resolve(__dirname, "..", "testFixture", "shasumtest.txt"); + + const sum = await release.calculateFileSha256Sum(testPath); + assert.strictEqual(sum, expectedSum); + }); + + it('should download the correct sha256 sum', async () => { + const expectedSum = + '8629ccc47ee8d4dfe6d23efb93b293948a088a936180d07d3f2ed118f6dd64a5'; const remoteSum = await release.downloadSha256Sum( release.builds[0].filename ); - assert.strictEqual(remoteSum, validSum); + assert.strictEqual(remoteSum, expectedSum); }); + + it('should download the release', async () => { + const build = release.getBuild('darwin', 'amd64'); + const tmpDir = tempy.directory(); + const zipFile = path.resolve(tmpDir, `terraform-ls_v${release.version}.zip`); + + await release.download(build.url, zipFile, 'js-releases/mocha-test'); + await release.verify(zipFile, build.filename); + + fs.rmSync(tmpDir, { + recursive: true + }); + }) }); From ca947f439bce93ed56fccf76576864195e8fccc0 Mon Sep 17 00:00:00 2001 From: Daniel Banck Date: Mon, 14 Mar 2022 12:50:44 +0100 Subject: [PATCH 4/6] fix incomplete download errors The download method now waits until all data has been downloaded and written to the destination file. Before this, the method was resolved too early, and as a result, subsequent operations ran on an incomplete download. This caused operations like verify to fail, because of a different shasum. --- src/index.test.ts | 6 ++---- src/index.ts | 18 ++++++++---------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/index.test.ts b/src/index.test.ts index 06488d9..a8cfa46 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -41,13 +41,11 @@ describe('LS installer', () => { }); it('should download the correct sha256 sum', async () => { - const expectedSum = - '8629ccc47ee8d4dfe6d23efb93b293948a088a936180d07d3f2ed118f6dd64a5'; + const expectedSum = '8629ccc47ee8d4dfe6d23efb93b293948a088a936180d07d3f2ed118f6dd64a5'; const remoteSum = await release.downloadSha256Sum( release.builds[0].filename ); - assert.strictEqual(remoteSum, expectedSum); }); @@ -62,5 +60,5 @@ describe('LS installer', () => { fs.rmSync(tmpDir, { recursive: true }); - }) + }).timeout(20 * 1000) // increase timeout for file download }); diff --git a/src/index.ts b/src/index.ts index 61625bf..8b1cfdd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,9 +2,12 @@ import * as crypto from 'crypto'; import * as fs from 'fs'; import * as openpgp from 'openpgp'; import * as semver from 'semver'; +import * as stream from 'stream'; import * as yauzl from 'yauzl'; +import { promisify } from 'util'; import { request } from './utils'; +const finished = promisify(stream.finished); const hashiPublicKeyId = '72D7468F'; const hashiPublicKey = `-----BEGIN PGP PUBLIC KEY BLOCK----- @@ -163,18 +166,13 @@ export class Release { return this.builds.find(b => b.os === platform && b.arch === arch); } - public download(downloadUrl: string, installPath: string, identifier: string): Promise { + public async download(downloadUrl: string, installPath: string, identifier: string): Promise { const headers = { 'User-Agent': identifier }; + const writer = fs.createWriteStream(installPath); - return new Promise(async (resolve, reject) => { - try { - const result = await request(downloadUrl, { headers: { ...headers }, responseType: 'stream' }); - result.pipe(fs.createWriteStream(installPath)) - resolve(); - } catch (e) { - return reject(e.message); - } - }); + const result = await request(downloadUrl, { headers: { ...headers }, responseType: 'stream' }); + result.pipe(writer); + await finished(writer); } public async verify(pkg: string, buildName: string): Promise { From 91aaf72dc4b03dcc3301fa937a1330b1d5788c4f Mon Sep 17 00:00:00 2001 From: Daniel Banck Date: Mon, 14 Mar 2022 13:24:00 +0100 Subject: [PATCH 5/6] add gitattributes file to fix checksum test on windows --- .gitattributes | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..f857120 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,8 @@ +# Ensure line endings are always Unix-style for known text files +# GitHub Actions CI doesn't have "native" solution for this +# See https://github.com/actions/checkout/issues/226 +*.ts text eol=lf +*.json text eol=lf +*.md text eol=lf +*.tf text eol=lf +*.txt text eol=lf From 99a3e2bfd38cf93f5b16310f4da05560b1be9ec6 Mon Sep 17 00:00:00 2001 From: Daniel Banck Date: Mon, 14 Mar 2022 13:24:22 +0100 Subject: [PATCH 6/6] add type for shared release variable in tests --- src/index.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/index.test.ts b/src/index.test.ts index a8cfa46..7750cde 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -7,7 +7,7 @@ import * as tempy from 'tempy'; import { Release } from './index'; describe('LS installer', () => { - let release; + let release: Release; before(() => { release = new Release({