Skip to content

Commit

Permalink
Generic webhook endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
Hacksore committed Aug 15, 2024
1 parent 1723614 commit 23791d2
Show file tree
Hide file tree
Showing 9 changed files with 475 additions and 27 deletions.
4 changes: 2 additions & 2 deletions .thing/hooks/github-canary-success.config.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"url": "http://localhost:8787/upload-canary-artifacts"
}
"url": "http://localhost:8787/webhook"
}
3 changes: 3 additions & 0 deletions .thing/hooks/github-stable-success.config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"url": "http://localhost:8787/webhook"
}
409 changes: 409 additions & 0 deletions .thing/hooks/github-stable-success.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion apps/api/src/handlers/github.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Bindings, ReleaseResponse } from "../types.js";
import { Bindings } from "../types.js";
import { Hono } from "hono/quick";
import { getLatestRelease } from "../utils.js";

Expand Down
6 changes: 1 addition & 5 deletions apps/api/src/handlers/updater.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { Hono } from "hono/quick";
import {
getLatestVersions,
getPlatformDownloads,
getStars,
} from "../utils.js";
import { getLatestVersions, getPlatformDownloads, getStars } from "../utils.js";
import { Bindings } from "../types.js";

const app = new Hono<{ Bindings: Bindings }>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,42 +1,77 @@
import { Artifacts, Bindings, WorkflowRuns } from "../types.js";
import { Artifacts, Bindings, Request, WorkflowRuns } from "../types.js";
import { GITHUB_REPO, GITHUB_USER } from "../constants.js";
import { Hono } from "hono/quick";
import { WorkflowRunEvent } from "@octokit/webhooks-types";
import { Webhooks } from "@octokit/webhooks";
import { isProd } from "../utils.js";
import { filenameToPlatform, getLatestRelease, isProd } from "../utils.js";

const app = new Hono<{ Bindings: Bindings }>();

app.post("/upload-canary-artifacts", async (c) => {
app.post("/webhook", async (c) => {
const webhooks = new Webhooks({
secret: c.env.CANARY_UPLOAD_SECRET,
});

const isProduction = isProd(c.req.url);
const body = (await c.req.json()) as WorkflowRunEvent;
const bodyAsString = JSON.stringify(body);

const signature = c.req.header("x-hub-signature-256") || "";

const isCanaryJob = body.workflow.name === "Canary";
const isSuccesfulRun =
body.action === "completed" && body.workflow_run.conclusion === "success";

// only enable this is production!
if (isProduction) {
if (!(await webhooks.verify(bodyAsString, signature))) {
return c.json({ error: "Unauthorized" });
}
if (isProduction && !(await webhooks.verify(bodyAsString, signature))) {
return c.json({ error: "Unauthorized" });
}

if (!isSuccesfulRun || !isCanaryJob) {
return c.json({
messge: "either the run was not successful or it was not a canary job",
job: body.workflow.name,
conclusion: body.workflow_run.conclusion,
});
if (!isSuccesfulRun) {
return c.json({ error: "Not a successful run" });
}

console.log("Webhook received", body.workflow.name);

if (body.workflow.name === "Canary") {
return await uploadCanaryArtifact({ c });
}

if (body.workflow.name === "Create Release") {
return await uploadStableArtifact({ c, body });
}

return c.json({ error: "Unable to handle webhook" });
});

// TODO: we need to make this only work on a new tag create
async function uploadStableArtifact({
c,
body,
}: {
c: Request;
body: WorkflowRunEvent;
}) {
const releases = await getLatestRelease(c.env.GITHUB_TOKEN);

const latesetVersion = releases.tag_name;

const versions = releases.assets
.map((asset) => ({
name: asset.name,
url: asset.browser_download_url,
platform: filenameToPlatform(asset.name),
}))
.filter((asset) => asset.name.match(/\.(dmg|msi|AppImage)$/));

// upload all the files to r2 in the stable folder
for (const asset of versions) {
const fileData = await fetch(asset.url).then((res) => res.arrayBuffer());
await c.env.BUCKET.put(`stable/${latesetVersion}/${asset.name}`, fileData);
}

return c.json(versions);
}

async function uploadCanaryArtifact({ c }: { c: Request }) {
const canaryWorkflowRunsResponse = await fetch(
`https://api.github.com/repos/${GITHUB_USER}/${GITHUB_REPO}/actions/workflows/canary.yaml/runs`,
{
Expand Down Expand Up @@ -137,6 +172,6 @@ You can download it on [overlayed.dev/canary](<https://overlayed.dev/canary>)
},
200,
);
});
}

export default app;
4 changes: 2 additions & 2 deletions apps/api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { Hono } from "hono";
import token from "./handlers/token.js";
import updater from "./handlers/updater.js";
import canary from "./handlers/canary.js";
import webhook from "./handlers/webhook.js";
import github from "./handlers/github.js";
import { cors } from "hono/cors";

Expand All @@ -20,6 +20,6 @@ app.route("/", token);
app.route("/", updater);

// routes for canary
app.route("/", canary);
app.route("/", webhook);

export default app;
5 changes: 5 additions & 0 deletions apps/api/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Endpoints } from "@octokit/types";
import { Context } from "hono";

export type RepoResponse =
Endpoints["GET /repos/{owner}/{repo}"]["response"]["data"];
Expand Down Expand Up @@ -32,3 +33,7 @@ export type Bindings = {
CANARY_UPLOAD_SECRET: string;
CANARY_WEBHOOK_URL: string;
};

export type Request = Context<{
Bindings: Bindings;
}>;
2 changes: 1 addition & 1 deletion apps/api/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export async function getLatestRelease(authToken: string) {
return releases;
}

const filenameToPlatform = (filename: string) => {
export const filenameToPlatform = (filename: string) => {
if (filename.includes("msi")) {
return "windows";
}
Expand Down

0 comments on commit 23791d2

Please sign in to comment.