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

Update webhook to accept x-www-form-urlencoded requests #54

Merged
merged 3 commits into from Aug 9, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
38 changes: 19 additions & 19 deletions api/webhook/github.ts
Expand Up @@ -13,7 +13,7 @@ import {
Context,
APIGatewayProxyResultV2,
} from "../../deps.ts";
import { respondJSON } from "../../utils/http.ts";
import { respondJSON, parseRequestBody } from "../../utils/http.ts";
import { Database } from "../../utils/database.ts";
import { getMeta, uploadMetaJson } from "../../utils/storage.ts";
import type { WebhookPayloadCreate } from "../../utils/webhooks.d.ts";
Expand Down Expand Up @@ -56,9 +56,27 @@ export async function handler(

const headers = new Headers(event.headers);

if (
!(headers.get("content-type") ?? "").startsWith("application/json") &&
!(headers.get("content-type") ?? "").startsWith(
"application/x-www-form-urlencoded",
)
) {
return respondJSON({
statusCode: 400,
body: JSON.stringify({
success: false,
error: "content-type is not json or x-www-form-urlencoded",
}),
});
}

// Check the GitHub event type.
const ghEvent = headers.get("x-github-event");

// Decode event body in the case the event is submitted as form-urlencoded
event = parseRequestBody(event);

switch (ghEvent) {
case "ping":
return pingEvent({ headers, moduleName, event });
Expand All @@ -83,15 +101,6 @@ async function pingEvent(
},
): Promise<APIGatewayProxyResultV2> {
// Get version, version type, and repository from event
if (!(headers.get("content-type") ?? "").startsWith("application/json")) {
return respondJSON({
statusCode: 400,
body: JSON.stringify({
success: false,
error: "content-type is not json",
}),
});
}
if (!event.body) {
return respondJSON({
statusCode: 400,
Expand Down Expand Up @@ -187,15 +196,6 @@ async function createEvent(
},
): Promise<APIGatewayProxyResultV2> {
// Get version, version type, and repository from event
if (!(headers.get("content-type") ?? "").startsWith("application/json")) {
return respondJSON({
statusCode: 400,
body: JSON.stringify({
success: false,
error: "content-type is not json",
}),
});
}
if (!event.body) {
return respondJSON({
statusCode: 400,
Expand Down
71 changes: 71 additions & 0 deletions api/webhook/github_create_test.ts
@@ -1,6 +1,7 @@
import { handler } from "./github.ts";
import {
createJSONWebhookEvent,
createJSONWebhookWebFormEvent,
createContext,
} from "../../utils/test_utils.ts";
import { Database } from "../../utils/database.ts";
Expand All @@ -11,6 +12,9 @@ const database = new Database(Deno.env.get("MONGO_URI")!);
const decoder = new TextDecoder();

const createevent = await readJson("./api/webhook/testdata/createevent.json");
const urlencodedcreateevent = await await Deno.readTextFile(
"./api/webhook/testdata/createevent.txt",
);
const createeventBranch = await readJson(
"./api/webhook/testdata/createevent_branch.json",
);
Expand Down Expand Up @@ -204,6 +208,73 @@ Deno.test({
},
});

Deno.test({
name: "create event success - web form",
async fn() {
// Send create event
const resp = await handler(
createJSONWebhookWebFormEvent(
"create",
"/webhook/gh/ltest2",
btoa(urlencodedcreateevent),
{ name: "ltest2" },
{},
),
createContext(),
);

const builds = await database._builds.find({});

// Check that a new build was queued
assertEquals(builds.length, 1);
assertEquals(
builds[0],
{
_id: builds[0]._id,
created_at: builds[0].created_at,
options: {
moduleName: "ltest2",
type: "github",
repository: "luca-rand/testing",
ref: "0.0.7",
version: "0.0.7",
},
status: "queued",
},
);

assertEquals(resp, {
body:
`{"success":true,"data":{"module":"ltest2","version":"0.0.7","repository":"luca-rand/testing","status_url":"https://deno.land/status/${
builds[0]._id.$oid
}"}}`,
headers: {
"content-type": "application/json",
},
statusCode: 200,
});

// Check that the database entry
assertEquals(
await database.getModule("ltest2"),
{
name: "ltest2",
type: "github",
repository: "luca-rand/testing",
description: "Move along, just for testing",
star_count: 2,
},
);

// Check that no versions.json file was created
assertEquals(await getMeta("ltest2", "versions.json"), undefined);

// Clean up
await database._builds.deleteMany({});
await database._modules.deleteMany({});
},
});

Deno.test({
name: "create event not a tag",
async fn() {
Expand Down
54 changes: 54 additions & 0 deletions api/webhook/github_ping_test.ts
@@ -1,6 +1,7 @@
import { handler } from "./github.ts";
import {
createJSONWebhookEvent,
createJSONWebhookWebFormEvent,
createContext,
} from "../../utils/test_utils.ts";
import { Database } from "../../utils/database.ts";
Expand All @@ -11,6 +12,9 @@ const database = new Database(Deno.env.get("MONGO_URI")!);
const decoder = new TextDecoder();

const pingevent = await readJson("./api/webhook/testdata/pingevent.json");
const urlendodedpingevent = await Deno.readTextFile(
"./api/webhook/testdata/pingevent.txt",
);

Deno.test({
name: "ping event no name",
Expand Down Expand Up @@ -129,6 +133,56 @@ Deno.test({
},
});

Deno.test({
name: "ping event success - web form",
async fn() {
// Send ping event
const resp = await handler(
createJSONWebhookWebFormEvent(
"ping",
"/webhook/gh/ltest2",
btoa(urlendodedpingevent),
{ name: "ltest2" },
{},
),
createContext(),
);
assertEquals(resp, {
body:
'{"success":true,"data":{"module":"ltest2","repository":"luca-rand/testing"}}',
headers: {
"content-type": "application/json",
},
statusCode: 200,
});

// Check that the database entry
assertEquals(
await database.getModule("ltest2"),
{
name: "ltest2",
type: "github",
repository: "luca-rand/testing",
description: "Move along, just for testing",
star_count: 2,
},
);

// Check that a versions.json file was created
assertEquals(
JSON.parse(decoder.decode(await getMeta("ltest2", "versions.json"))),
{ latest: null, versions: [] },
);

// Check that no new build was queued
assertEquals(await database._builds.find({}), []);

// Clean up
await s3.deleteObject("ltest2/meta/versions.json");
await database._modules.deleteMany({});
},
});

Deno.test({
name: "ping event max registered to repository",
async fn() {
Expand Down
1 change: 1 addition & 0 deletions api/webhook/testdata/createevent.txt
@@ -0,0 +1 @@
payload=%7B%22ref%22%3A%220.0.7%22%2C%22ref_type%22%3A%22tag%22%2C%22master_branch%22%3A%22master%22%2C%22description%22%3A%22Move%20along%2C%20just%20for%20testing%22%2C%22pusher_type%22%3A%22user%22%2C%22repository%22%3A%7B%22id%22%3A274939732%2C%22node_id%22%3A%22MDEwOlJlcG9zaXRvcnkyNzQ5Mzk3MzI%3D%22%2C%22name%22%3A%22testing%22%2C%22full_name%22%3A%22luca-rand%2Ftesting%22%2C%22private%22%3Afalse%2C%22owner%22%3A%7B%22login%22%3A%22luca-rand%22%2C%22id%22%3A52681900%2C%22node_id%22%3A%22MDEyOk9yZ2FuaXphdGlvbjUyNjgxOTAw%22%2C%22avatar_url%22%3A%22https%3A%2F%2Favatars3.githubusercontent.com%2Fu%2F52681900%3Fv%3D4%22%2C%22gravatar_id%22%3A%22%22%2C%22url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Fluca-rand%22%2C%22html_url%22%3A%22https%3A%2F%2Fgithub.com%2Fluca-rand%22%2C%22followers_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Fluca-rand%2Ffollowers%22%2C%22following_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Fluca-rand%2Ffollowing%7B%2Fother_user%7D%22%2C%22gists_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Fluca-rand%2Fgists%7B%2Fgist_id%7D%22%2C%22starred_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Fluca-rand%2Fstarred%7B%2Fowner%7D%7B%2Frepo%7D%22%2C%22subscriptions_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Fluca-rand%2Fsubscriptions%22%2C%22organizations_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Fluca-rand%2Forgs%22%2C%22repos_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Fluca-rand%2Frepos%22%2C%22events_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Fluca-rand%2Fevents%7B%2Fprivacy%7D%22%2C%22received_events_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Fluca-rand%2Freceived_events%22%2C%22type%22%3A%22Organization%22%2C%22site_admin%22%3Afalse%7D%2C%22html_url%22%3A%22https%3A%2F%2Fgithub.com%2Fluca-rand%2Ftesting%22%2C%22description%22%3A%22Move%20along%2C%20just%20for%20testing%22%2C%22fork%22%3Afalse%2C%22url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%22%2C%22forks_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fforks%22%2C%22keys_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fkeys%7B%2Fkey_id%7D%22%2C%22collaborators_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fcollaborators%7B%2Fcollaborator%7D%22%2C%22teams_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fteams%22%2C%22hooks_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fhooks%22%2C%22issue_events_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fissues%2Fevents%7B%2Fnumber%7D%22%2C%22events_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fevents%22%2C%22assignees_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fassignees%7B%2Fuser%7D%22%2C%22branches_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fbranches%7B%2Fbranch%7D%22%2C%22tags_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Ftags%22%2C%22blobs_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fgit%2Fblobs%7B%2Fsha%7D%22%2C%22git_tags_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fgit%2Ftags%7B%2Fsha%7D%22%2C%22git_refs_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fgit%2Frefs%7B%2Fsha%7D%22%2C%22trees_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fgit%2Ftrees%7B%2Fsha%7D%22%2C%22statuses_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fstatuses%2F%7Bsha%7D%22%2C%22languages_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Flanguages%22%2C%22stargazers_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fstargazers%22%2C%22contributors_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fcontributors%22%2C%22subscribers_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fsubscribers%22%2C%22subscription_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fsubscription%22%2C%22commits_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fcommits%7B%2Fsha%7D%22%2C%22git_commits_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fgit%2Fcommits%7B%2Fsha%7D%22%2C%22comments_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fcomments%7B%2Fnumber%7D%22%2C%22issue_comment_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fissues%2Fcomments%7B%2Fnumber%7D%22%2C%22contents_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fcontents%2F%7B%2Bpath%7D%22%2C%22compare_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fcompare%2F%7Bbase%7D...%7Bhead%7D%22%2C%22merges_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fmerges%22%2C%22archive_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2F%7Barchive_format%7D%7B%2Fref%7D%22%2C%22downloads_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fdownloads%22%2C%22issues_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fissues%7B%2Fnumber%7D%22%2C%22pulls_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fpulls%7B%2Fnumber%7D%22%2C%22milestones_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fmilestones%7B%2Fnumber%7D%22%2C%22notifications_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fnotifications%7B%3Fsince%2Call%2Cparticipating%7D%22%2C%22labels_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Flabels%7B%2Fname%7D%22%2C%22releases_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Freleases%7B%2Fid%7D%22%2C%22deployments_url%22%3A%22https%3A%2F%2Fapi.github.com%2Frepos%2Fluca-rand%2Ftesting%2Fdeployments%22%2C%22created_at%22%3A%222020-06-25T14%3A37%3A46Z%22%2C%22updated_at%22%3A%222020-07-27T12%3A39%3A23Z%22%2C%22pushed_at%22%3A%222020-07-28T15%3A00%3A40Z%22%2C%22git_url%22%3A%22git%3A%2F%2Fgithub.com%2Fluca-rand%2Ftesting.git%22%2C%22ssh_url%22%3A%22git%40github.com%3Aluca-rand%2Ftesting.git%22%2C%22clone_url%22%3A%22https%3A%2F%2Fgithub.com%2Fluca-rand%2Ftesting.git%22%2C%22svn_url%22%3A%22https%3A%2F%2Fgithub.com%2Fluca-rand%2Ftesting%22%2C%22homepage%22%3Anull%2C%22size%22%3A5%2C%22stargazers_count%22%3A2%2C%22watchers_count%22%3A2%2C%22language%22%3A%22TypeScript%22%2C%22has_issues%22%3Atrue%2C%22has_projects%22%3Atrue%2C%22has_downloads%22%3Atrue%2C%22has_wiki%22%3Atrue%2C%22has_pages%22%3Afalse%2C%22forks_count%22%3A0%2C%22mirror_url%22%3Anull%2C%22archived%22%3Afalse%2C%22disabled%22%3Afalse%2C%22open_issues_count%22%3A1%2C%22license%22%3A%7B%22key%22%3A%22mit%22%2C%22name%22%3A%22MIT%20License%22%2C%22spdx_id%22%3A%22MIT%22%2C%22url%22%3A%22https%3A%2F%2Fapi.github.com%2Flicenses%2Fmit%22%2C%22node_id%22%3A%22MDc6TGljZW5zZTEz%22%7D%2C%22forks%22%3A0%2C%22open_issues%22%3A1%2C%22watchers%22%3A2%2C%22default_branch%22%3A%22master%22%7D%2C%22organization%22%3A%7B%22login%22%3A%22luca-rand%22%2C%22id%22%3A52681900%2C%22node_id%22%3A%22MDEyOk9yZ2FuaXphdGlvbjUyNjgxOTAw%22%2C%22url%22%3A%22https%3A%2F%2Fapi.github.com%2Forgs%2Fluca-rand%22%2C%22repos_url%22%3A%22https%3A%2F%2Fapi.github.com%2Forgs%2Fluca-rand%2Frepos%22%2C%22events_url%22%3A%22https%3A%2F%2Fapi.github.com%2Forgs%2Fluca-rand%2Fevents%22%2C%22hooks_url%22%3A%22https%3A%2F%2Fapi.github.com%2Forgs%2Fluca-rand%2Fhooks%22%2C%22issues_url%22%3A%22https%3A%2F%2Fapi.github.com%2Forgs%2Fluca-rand%2Fissues%22%2C%22members_url%22%3A%22https%3A%2F%2Fapi.github.com%2Forgs%2Fluca-rand%2Fmembers%7B%2Fmember%7D%22%2C%22public_members_url%22%3A%22https%3A%2F%2Fapi.github.com%2Forgs%2Fluca-rand%2Fpublic_members%7B%2Fmember%7D%22%2C%22avatar_url%22%3A%22https%3A%2F%2Favatars3.githubusercontent.com%2Fu%2F52681900%3Fv%3D4%22%2C%22description%22%3A%22Random%20stuff%22%7D%2C%22sender%22%3A%7B%22login%22%3A%22lucacasonato%22%2C%22id%22%3A7829205%2C%22node_id%22%3A%22MDQ6VXNlcjc4MjkyMDU%3D%22%2C%22avatar_url%22%3A%22https%3A%2F%2Favatars0.githubusercontent.com%2Fu%2F7829205%3Fv%3D4%22%2C%22gravatar_id%22%3A%22%22%2C%22url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Flucacasonato%22%2C%22html_url%22%3A%22https%3A%2F%2Fgithub.com%2Flucacasonato%22%2C%22followers_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Flucacasonato%2Ffollowers%22%2C%22following_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Flucacasonato%2Ffollowing%7B%2Fother_user%7D%22%2C%22gists_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Flucacasonato%2Fgists%7B%2Fgist_id%7D%22%2C%22starred_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Flucacasonato%2Fstarred%7B%2Fowner%7D%7B%2Frepo%7D%22%2C%22subscriptions_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Flucacasonato%2Fsubscriptions%22%2C%22organizations_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Flucacasonato%2Forgs%22%2C%22repos_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Flucacasonato%2Frepos%22%2C%22events_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Flucacasonato%2Fevents%7B%2Fprivacy%7D%22%2C%22received_events_url%22%3A%22https%3A%2F%2Fapi.github.com%2Fusers%2Flucacasonato%2Freceived_events%22%2C%22type%22%3A%22User%22%2C%22site_admin%22%3Afalse%7D%7D