Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: change decode for server payload to match action payload #51

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 1 addition & 14 deletions src/actions.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,19 @@
import * as core from "@actions/core";
import * as github from "@actions/github";
import { EmitterWebhookEventName as WebhookEventName } from "@octokit/webhooks";
import { Type as T } from "@sinclair/typebox";
import { Value } from "@sinclair/typebox/value";
import { LogReturn, Logs } from "@ubiquity-os/ubiquity-os-logger";
import { config } from "dotenv";
import { postComment } from "./comment";
import { Context } from "./context";
import { customOctokit } from "./octokit";
import { verifySignature } from "./signature";
import { commandCallSchema } from "./types/command";
import { inputSchema } from "./types/input-schema";
import { HandlerReturn } from "./types/sdk";
import { jsonType } from "./types/util";
import { getPluginOptions, Options } from "./util";

config();

const inputSchema = T.Object({
stateId: T.String(),
eventName: T.String(),
eventPayload: jsonType(T.Record(T.String(), T.Any())),
command: jsonType(commandCallSchema),
authToken: T.String(),
settings: jsonType(T.Record(T.String(), T.Any())),
ref: T.String(),
signature: T.String(),
});

export async function createActionsPlugin<TConfig = unknown, TEnv = unknown, TCommand = unknown, TSupportedEvents extends WebhookEventName = WebhookEventName>(
handler: (context: Context<TConfig, TEnv, TCommand, TSupportedEvents>) => HandlerReturn,
options?: Options
Expand Down
19 changes: 4 additions & 15 deletions src/server.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { EmitterWebhookEventName as WebhookEventName } from "@octokit/webhooks";
import { Type as T } from "@sinclair/typebox";
import { Value } from "@sinclair/typebox/value";
import { LogReturn, Logs } from "@ubiquity-os/ubiquity-os-logger";
import { Hono } from "hono";
Expand All @@ -10,21 +9,11 @@ import { Context } from "./context";
import { PluginRuntimeInfo } from "./helpers/runtime-info";
import { customOctokit } from "./octokit";
import { verifySignature } from "./signature";
import { inputSchema } from "./types/input-schema";
import { Manifest } from "./types/manifest";
import { HandlerReturn } from "./types/sdk";
import { getPluginOptions, Options } from "./util";

const inputSchema = T.Object({
stateId: T.String(),
eventName: T.String(),
eventPayload: T.Record(T.String(), T.Any()),
command: T.Union([T.Null(), T.Object({ name: T.String(), parameters: T.Unknown() })]),
authToken: T.String(),
settings: T.Record(T.String(), T.Any()),
ref: T.String(),
signature: T.String(),
});

export function createPlugin<TConfig = unknown, TEnv = unknown, TCommand = unknown, TSupportedEvents extends WebhookEventName = WebhookEventName>(
handler: (context: Context<TConfig, TEnv, TCommand, TSupportedEvents>) => HandlerReturn,
manifest: Manifest,
Expand All @@ -49,11 +38,11 @@ export function createPlugin<TConfig = unknown, TEnv = unknown, TCommand = unkno
console.log(inputSchemaErrors, { depth: null });
throw new HTTPException(400, { message: "Invalid body" });
}
const inputs = Value.Decode(inputSchema, body);
const signature = inputs.signature;
if (!pluginOptions.bypassSignatureVerification && !(await verifySignature(pluginOptions.kernelPublicKey, inputs, signature))) {
const signature = body.signature;
if (!pluginOptions.bypassSignatureVerification && !(await verifySignature(pluginOptions.kernelPublicKey, body, signature))) {
throw new HTTPException(400, { message: "Invalid signature" });
}
const inputs = Value.Decode(inputSchema, body);

let config: TConfig;
if (pluginOptions.settingsSchema) {
Expand Down
14 changes: 14 additions & 0 deletions src/types/input-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Type as T } from "@sinclair/typebox";
import { commandCallSchema } from "./command";
import { jsonType } from "./util";

export const inputSchema = T.Object({
stateId: T.String(),
eventName: T.String(),
eventPayload: jsonType(T.Record(T.String(), T.Any())),
command: jsonType(commandCallSchema),
authToken: T.String(),
settings: jsonType(T.Record(T.String(), T.Any())),
ref: T.String(),
signature: T.String(),
});
48 changes: 7 additions & 41 deletions tests/sdk.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,33 +32,7 @@ const sdkOctokitImportPath = "../src/octokit";
const githubActionImportPath = "@actions/github";
const githubCoreImportPath = "@actions/core";

async function getWorkerInputs(
stateId: string,
eventName: string,
eventPayload: object,
settings: object,
authToken: string,
ref: string,
command: CommandCall | null
) {
const inputs = {
stateId,
eventName,
eventPayload,
settings,
authToken,
ref,
command,
};
const signature = await signPayload(JSON.stringify(inputs), privateKey);

return {
...inputs,
signature,
};
}

async function getWorkflowInputs(
async function getInputs(
stateId: string,
eventName: string,
eventPayload: object,
Expand Down Expand Up @@ -133,15 +107,7 @@ describe("SDK worker tests", () => {
expect(res.status).toEqual(400);
});
it("Should deny POST request with invalid signature", async () => {
const inputs = await getWorkerInputs(
"stateId",
issueCommentedEvent.eventName,
issueCommentedEvent.eventPayload,
{ shouldFail: false },
"test",
"main",
null
);
const inputs = await getInputs("stateId", issueCommentedEvent.eventName, issueCommentedEvent.eventPayload, { shouldFail: false }, "test", "main", null);

const res = await app.request("/", {
headers: {
Expand Down Expand Up @@ -193,7 +159,7 @@ describe("SDK worker tests", () => {
{ kernelPublicKey: publicKey }
);

const inputs = await getWorkerInputs(
const inputs = await getInputs(
"stateId",
issueCommentedEvent.eventName,
issueCommentedEvent.eventPayload,
Expand Down Expand Up @@ -228,7 +194,7 @@ describe("SDK worker tests", () => {
});
});
it("Should accept correct request", async () => {
const inputs = await getWorkerInputs(
const inputs = await getInputs(
"stateId",
issueCommentedEvent.eventName,
issueCommentedEvent.eventPayload,
Expand Down Expand Up @@ -265,7 +231,7 @@ describe("SDK actions tests", () => {
};

it("Should accept correct request", async () => {
const githubInputs = await getWorkflowInputs("stateId", issueCommentedEvent.eventName, issueCommentedEvent.eventPayload, {}, "test_token", "main", {
const githubInputs = await getInputs("stateId", issueCommentedEvent.eventName, issueCommentedEvent.eventPayload, {}, "test_token", "main", {
name: "test",
parameters: { param1: "test" },
});
Expand Down Expand Up @@ -327,7 +293,7 @@ describe("SDK actions tests", () => {
});
});
it("Should deny invalid signature", async () => {
const githubInputs = await getWorkflowInputs("stateId", issueCommentedEvent.eventName, issueCommentedEvent.eventPayload, {}, "test_token", "main", null);
const githubInputs = await getInputs("stateId", issueCommentedEvent.eventName, issueCommentedEvent.eventPayload, {}, "test_token", "main", null);

jest.unstable_mockModule("@actions/github", () => ({
default: {},
Expand Down Expand Up @@ -364,7 +330,7 @@ describe("SDK actions tests", () => {
expect(setOutput).not.toHaveBeenCalled();
});
it("Should accept inputs in different order", async () => {
const githubInputs = await getWorkflowInputs("stateId", issueCommentedEvent.eventName, issueCommentedEvent.eventPayload, {}, "test_token", "main", null);
const githubInputs = await getInputs("stateId", issueCommentedEvent.eventName, issueCommentedEvent.eventPayload, {}, "test_token", "main", null);

jest.unstable_mockModule(githubActionImportPath, () => ({
default: {},
Expand Down
Loading