diff --git a/bun.lockb b/bun.lockb index 6aa5b9e..1cca6fa 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/src/github/handlers/index.ts b/src/github/handlers/index.ts index d476b46..0c7344e 100644 --- a/src/github/handlers/index.ts +++ b/src/github/handlers/index.ts @@ -106,7 +106,7 @@ async function handleEvent(event: EmitterWebhookEvent, eventHandler: InstanceTyp repository: plugin.repo, workflowId: plugin.workflowId, ref: plugin.ref, - inputs: inputs.getWorkflowInputs(), + inputs: await inputs.getWorkflowInputs(), }); } } diff --git a/src/github/handlers/repository-dispatch.ts b/src/github/handlers/repository-dispatch.ts index 7795b51..510a8c1 100644 --- a/src/github/handlers/repository-dispatch.ts +++ b/src/github/handlers/repository-dispatch.ts @@ -73,7 +73,7 @@ export async function repositoryDispatch(context: GitHubContext<"repository_disp repository: nextPlugin.plugin.repo, ref: nextPlugin.plugin.ref, workflowId: nextPlugin.plugin.workflowId, - inputs: inputs.getWorkflowInputs(), + inputs: await inputs.getWorkflowInputs(), }); } else { await dispatchWorker(nextPlugin.plugin, await inputs.getWorkerInputs()); diff --git a/src/github/types/plugin.ts b/src/github/types/plugin.ts index 79b4cec..cac7f2a 100644 --- a/src/github/types/plugin.ts +++ b/src/github/types/plugin.ts @@ -45,8 +45,8 @@ export class PluginInput( @@ -36,20 +40,29 @@ export async function createActionsPlugin c.charCodeAt(0)); + try { + const pemContents = publicKeyPem.replace("-----BEGIN PUBLIC KEY-----", "").replace("-----END PUBLIC KEY-----", "").trim(); + const binaryDer = Uint8Array.from(atob(pemContents), (c) => c.charCodeAt(0)); - const publicKey = await crypto.subtle.importKey( - "spki", - binaryDer, - { - name: "RSASSA-PKCS1-v1_5", - hash: "SHA-256", - }, - true, - ["verify"] - ); + const publicKey = await crypto.subtle.importKey( + "spki", + binaryDer, + { + name: "RSASSA-PKCS1-v1_5", + hash: "SHA-256", + }, + true, + ["verify"] + ); - const signatureArray = Uint8Array.from(atob(signature), (c) => c.charCodeAt(0)); - const dataArray = new TextEncoder().encode(JSON.stringify(payload)); + const signatureArray = Uint8Array.from(atob(signature), (c) => c.charCodeAt(0)); + const dataArray = new TextEncoder().encode(JSON.stringify(payload)); - return await crypto.subtle.verify("RSASSA-PKCS1-v1_5", publicKey, signatureArray, dataArray); + return await crypto.subtle.verify("RSASSA-PKCS1-v1_5", publicKey, signatureArray, dataArray); + } catch (error) { + console.error(error); + return false; + } } diff --git a/tests/sdk.test.ts b/tests/sdk.test.ts index 20b30ea..723e6dc 100644 --- a/tests/sdk.test.ts +++ b/tests/sdk.test.ts @@ -181,24 +181,34 @@ describe("SDK worker tests", () => { }); describe("SDK actions tests", () => { + const repo = { + owner: "ubiquity", + repo: "ubiquity-os-kernel", + }; + it("Should accept correct request", async () => { + const inputs = { + stateId: "stateId", + eventName: issueCommented.eventName, + settings: "{}", + eventPayload: JSON.stringify(issueCommented.eventPayload), + authToken: "test", + ref: "", + }; + const sign = crypto.createSign("SHA256"); + sign.update(JSON.stringify(inputs)).end(); + const signature = sign.sign(privateKey, "base64"); + jest.mock("@actions/github", () => ({ context: { runId: "1", payload: { inputs: { - stateId: "stateId", - eventName: issueCommented.eventName, - settings: "{}", - eventPayload: JSON.stringify(issueCommented.eventPayload), - authToken: "test", - ref: "", + ...inputs, + signature, }, }, - repo: { - owner: "ubiquity", - repo: "ubiquity-os-kernel", - }, + repo: repo, }, })); const setOutput = jest.fn(); @@ -223,13 +233,18 @@ describe("SDK actions tests", () => { })); const { createActionsPlugin } = await import("../src/sdk/actions"); - await createActionsPlugin(async (context: Context) => { - return { - event: context.eventName, - }; - }); - expect(setOutput).toHaveBeenCalledWith("result", { event: issueCommented.eventName }); + await createActionsPlugin( + async (context: Context) => { + return { + event: context.eventName, + }; + }, + { + kernelPublicKey: publicKey, + } + ); expect(setFailed).not.toHaveBeenCalled(); + expect(setOutput).toHaveBeenCalledWith("result", { event: issueCommented.eventName }); expect(createDispatchEvent).toHaveBeenCalledWith({ event_type: "return-data-to-ubiquity-os-kernel", owner: "ubiquity", @@ -240,4 +255,47 @@ describe("SDK actions tests", () => { }, }); }); + it("Should deny invalid signature", async () => { + const inputs = { + stateId: "stateId", + eventName: issueCommented.eventName, + settings: "{}", + eventPayload: JSON.stringify(issueCommented.eventPayload), + authToken: "test", + ref: "", + }; + + jest.mock("@actions/github", () => ({ + context: { + runId: "1", + payload: { + inputs: { + ...inputs, + signature: "invalid", + }, + }, + repo: repo, + }, + })); + const setOutput = jest.fn(); + const setFailed = jest.fn(); + jest.mock("@actions/core", () => ({ + setOutput, + setFailed, + })); + const { createActionsPlugin } = await import("../src/sdk/actions"); + + await createActionsPlugin( + async (context: Context) => { + return { + event: context.eventName, + }; + }, + { + kernelPublicKey: publicKey, + } + ); + expect(setFailed).toHaveBeenCalledWith("Error: Invalid signature"); + expect(setOutput).not.toHaveBeenCalled(); + }); });