From bf1573eeb4a2508c0b31ad4fb07a750041f70082 Mon Sep 17 00:00:00 2001 From: Frederik Wallner Date: Sat, 4 Jul 2020 22:51:33 +0200 Subject: [PATCH 1/3] Add tests for the keyserver pool --- __tests__/gpg.test.ts | 47 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 __tests__/gpg.test.ts diff --git a/__tests__/gpg.test.ts b/__tests__/gpg.test.ts new file mode 100644 index 00000000..4e9b595d --- /dev/null +++ b/__tests__/gpg.test.ts @@ -0,0 +1,47 @@ +import * as exec from "@actions/exec"; +import { setupKeys, verify, refreshKeys } from "../src/gpg"; + +jest.mock("@actions/exec") + +const mockExec = exec.exec as jest.Mock + +describe("gpg", () => { + + afterEach(() => { + mockExec.mockClear() + }) + + it('uses the first responding keyserver in the pool', async () => { + mockExec.mockImplementation(() => Promise.resolve(0)) + await refreshKeys() + expect(mockExec).toBeCalledTimes(1) + }) + + it('uses the next keyserver in the pool if the previous fails', async () => { + const failingServers = 3 + let testedServers = 0 + + mockExec.mockImplementation(() => { + testedServers++ + if (testedServers >= failingServers) { + return Promise.resolve(0) + } else { + return Promise.resolve(1) + } + }) + + await refreshKeys() + expect(mockExec).toBeCalledTimes(3) + }) + + it('throws an error if all servers in the pool fails', async () => { + mockExec.mockImplementation(() => Promise.resolve(1)) + + try { + await refreshKeys() + } catch (e) { + expect(e).toEqual(new Error("Failed to refresh keys from any server in the pool.")); + } + }) + +}) From bde54800f2db333d93b82e6d22f35819aceb3d17 Mon Sep 17 00:00:00 2001 From: Frederik Wallner Date: Sat, 4 Jul 2020 22:52:31 +0200 Subject: [PATCH 2/3] Move gpg to separate file and add a keyserver pool --- src/gpg.ts | 53 ++++++++++++++++++++++++++++++++++++++++++++ src/linux-install.ts | 19 +--------------- 2 files changed, 54 insertions(+), 18 deletions(-) create mode 100644 src/gpg.ts diff --git a/src/gpg.ts b/src/gpg.ts new file mode 100644 index 00000000..5403e33c --- /dev/null +++ b/src/gpg.ts @@ -0,0 +1,53 @@ +import { exec } from "@actions/exec"; +import * as core from "@actions/core"; +import * as toolCache from "@actions/tool-cache"; + +export async function setupKeys() { + core.debug("Fetching verification keys"); + let path = await toolCache.downloadTool( + "https://swift.org/keys/all-keys.asc" + ); + + core.debug("Importing verification keys"); + await exec(`gpg --import "${path}"`); + + core.debug("Refreshing keys"); + await refreshKeys(); +} + +export async function verify(signaturePath: string, packagePath: string) { + core.debug("Verifying signature"); + await exec("gpg", ["--verify", signaturePath, packagePath]); +} + +export async function refreshKeys() { + const pool = [ + "hkp://pool.sks-keyservers.net", + "ha.pool.sks-keyservers.net", + "keyserver.ubuntu.com", + "hkp://keyserver.ubuntu.com", + "pgp.mit.edu" + ] + + for (const server of pool) { + core.debug(`Refreshing keys from ${server}`); + if (await refreshKeysFromServer(server)) { + core.debug(`Refresh successful`); + return + } + core.debug(`Refresh failed`); + } + + throw new Error("Failed to refresh keys from any server in the pool."); +} + +function refreshKeysFromServer(server: string): Promise { + return exec( + `gpg --keyserver ${server} --refresh-keys Swift` + ) + .then( code => code === 0 ) + .catch(error => { + core.warning(`An error occurred when trying to refresh keys from ${server}: ${error}`) + return false + }) +} diff --git a/src/linux-install.ts b/src/linux-install.ts index 11b162d0..e57bf185 100644 --- a/src/linux-install.ts +++ b/src/linux-install.ts @@ -5,6 +5,7 @@ import * as core from "@actions/core"; import * as toolCache from "@actions/tool-cache"; import { System } from "./os"; import { swiftPackage, Package } from "./swift-versions"; +import { setupKeys, verify } from "./gpg"; export async function install(version: string, system: System) { if (os.platform() !== "linux") { @@ -66,21 +67,3 @@ async function unpack( core.debug("Package cached"); return cachedPath; } - -async function setupKeys() { - core.debug("Fetching verification keys"); - let path = await toolCache.downloadTool( - "https://swift.org/keys/all-keys.asc" - ); - core.debug("Importing verification keys"); - await exec(`gpg --import "${path}"`); - core.debug("Refreshing keys"); - await exec( - "gpg --keyserver hkp://pool.sks-keyservers.net --refresh-keys Swift" - ); -} - -async function verify(signaturePath: string, packagePath: string) { - core.debug("Verifying signature"); - await exec("gpg", ["--verify", signaturePath, packagePath]); -} From 3937e508d47664631b52c412c13f4b8a473cf163 Mon Sep 17 00:00:00 2001 From: Frederik Wallner Date: Sat, 4 Jul 2020 22:53:56 +0200 Subject: [PATCH 3/3] Formatting --- __tests__/gpg.test.ts | 56 +++++++++++++++++++++---------------------- src/gpg.ts | 26 ++++++++++---------- 2 files changed, 41 insertions(+), 41 deletions(-) diff --git a/__tests__/gpg.test.ts b/__tests__/gpg.test.ts index 4e9b595d..2ad659de 100644 --- a/__tests__/gpg.test.ts +++ b/__tests__/gpg.test.ts @@ -1,47 +1,47 @@ import * as exec from "@actions/exec"; import { setupKeys, verify, refreshKeys } from "../src/gpg"; -jest.mock("@actions/exec") +jest.mock("@actions/exec"); -const mockExec = exec.exec as jest.Mock +const mockExec = exec.exec as jest.Mock; describe("gpg", () => { - afterEach(() => { - mockExec.mockClear() - }) + mockExec.mockClear(); + }); - it('uses the first responding keyserver in the pool', async () => { - mockExec.mockImplementation(() => Promise.resolve(0)) - await refreshKeys() - expect(mockExec).toBeCalledTimes(1) - }) + it("uses the first responding keyserver in the pool", async () => { + mockExec.mockImplementation(() => Promise.resolve(0)); + await refreshKeys(); + expect(mockExec).toBeCalledTimes(1); + }); - it('uses the next keyserver in the pool if the previous fails', async () => { - const failingServers = 3 - let testedServers = 0 + it("uses the next keyserver in the pool if the previous fails", async () => { + const failingServers = 3; + let testedServers = 0; mockExec.mockImplementation(() => { - testedServers++ + testedServers++; if (testedServers >= failingServers) { - return Promise.resolve(0) + return Promise.resolve(0); } else { - return Promise.resolve(1) + return Promise.resolve(1); } - }) + }); + + await refreshKeys(); + expect(mockExec).toBeCalledTimes(3); + }); - await refreshKeys() - expect(mockExec).toBeCalledTimes(3) - }) + it("throws an error if all servers in the pool fails", async () => { + mockExec.mockImplementation(() => Promise.resolve(1)); - it('throws an error if all servers in the pool fails', async () => { - mockExec.mockImplementation(() => Promise.resolve(1)) - try { - await refreshKeys() + await refreshKeys(); } catch (e) { - expect(e).toEqual(new Error("Failed to refresh keys from any server in the pool.")); + expect(e).toEqual( + new Error("Failed to refresh keys from any server in the pool.") + ); } - }) - -}) + }); +}); diff --git a/src/gpg.ts b/src/gpg.ts index 5403e33c..4a3fa641 100644 --- a/src/gpg.ts +++ b/src/gpg.ts @@ -26,28 +26,28 @@ export async function refreshKeys() { "ha.pool.sks-keyservers.net", "keyserver.ubuntu.com", "hkp://keyserver.ubuntu.com", - "pgp.mit.edu" - ] + "pgp.mit.edu", + ]; for (const server of pool) { core.debug(`Refreshing keys from ${server}`); - if (await refreshKeysFromServer(server)) { + if (await refreshKeysFromServer(server)) { core.debug(`Refresh successful`); - return + return; } core.debug(`Refresh failed`); } - + throw new Error("Failed to refresh keys from any server in the pool."); } function refreshKeysFromServer(server: string): Promise { - return exec( - `gpg --keyserver ${server} --refresh-keys Swift` - ) - .then( code => code === 0 ) - .catch(error => { - core.warning(`An error occurred when trying to refresh keys from ${server}: ${error}`) - return false - }) + return exec(`gpg --keyserver ${server} --refresh-keys Swift`) + .then((code) => code === 0) + .catch((error) => { + core.warning( + `An error occurred when trying to refresh keys from ${server}: ${error}` + ); + return false; + }); }