mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
Merge pull request #189 from slowlydev/feat/enable-autodeploy-github
Add web hook verification to GitHub Autodeploy
This commit is contained in:
1
drizzle/0018_careful_killmonger.sql
Normal file
1
drizzle/0018_careful_killmonger.sql
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ALTER TABLE "admin" ADD COLUMN "githubWebhookSecret" text;
|
||||||
2632
drizzle/meta/0018_snapshot.json
Normal file
2632
drizzle/meta/0018_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -127,6 +127,13 @@
|
|||||||
"when": 1719547174326,
|
"when": 1719547174326,
|
||||||
"tag": "0017_minor_post",
|
"tag": "0017_minor_post",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 18,
|
||||||
|
"version": "6",
|
||||||
|
"when": 1719928377858,
|
||||||
|
"tag": "0018_careful_killmonger",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -36,10 +36,12 @@
|
|||||||
"@codemirror/lang-yaml": "^6.1.1",
|
"@codemirror/lang-yaml": "^6.1.1",
|
||||||
"@codemirror/language": "^6.10.1",
|
"@codemirror/language": "^6.10.1",
|
||||||
"@codemirror/legacy-modes": "6.4.0",
|
"@codemirror/legacy-modes": "6.4.0",
|
||||||
|
"@dokploy/trpc-openapi": "0.0.4",
|
||||||
"@faker-js/faker": "^8.4.1",
|
"@faker-js/faker": "^8.4.1",
|
||||||
"@hookform/resolvers": "^3.3.4",
|
"@hookform/resolvers": "^3.3.4",
|
||||||
"@lucia-auth/adapter-drizzle": "1.0.7",
|
"@lucia-auth/adapter-drizzle": "1.0.7",
|
||||||
"@octokit/auth-app": "^6.0.4",
|
"@octokit/auth-app": "^6.0.4",
|
||||||
|
"@octokit/webhooks": "^13.2.7",
|
||||||
"@radix-ui/react-accordion": "1.1.2",
|
"@radix-ui/react-accordion": "1.1.2",
|
||||||
"@radix-ui/react-alert-dialog": "^1.0.5",
|
"@radix-ui/react-alert-dialog": "^1.0.5",
|
||||||
"@radix-ui/react-avatar": "^1.0.4",
|
"@radix-ui/react-avatar": "^1.0.4",
|
||||||
@@ -113,7 +115,6 @@
|
|||||||
"tailwind-merge": "^2.2.0",
|
"tailwind-merge": "^2.2.0",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"tar-fs": "3.0.5",
|
"tar-fs": "3.0.5",
|
||||||
"@dokploy/trpc-openapi": "0.0.4",
|
|
||||||
"use-resize-observer": "9.1.0",
|
"use-resize-observer": "9.1.0",
|
||||||
"ws": "8.16.0",
|
"ws": "8.16.0",
|
||||||
"xterm-addon-fit": "^0.8.0",
|
"xterm-addon-fit": "^0.8.0",
|
||||||
|
|||||||
@@ -1,17 +1,39 @@
|
|||||||
import { and, eq } from "drizzle-orm";
|
import { and, eq } from "drizzle-orm";
|
||||||
import { db } from "@/server/db";
|
import { db } from "@/server/db";
|
||||||
|
import { Webhooks } from "@octokit/webhooks";
|
||||||
import type { NextApiRequest, NextApiResponse } from "next";
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
import { applications, compose } from "@/server/db/schema";
|
import { applications, compose } from "@/server/db/schema";
|
||||||
import { extractCommitMessage, extractHash } from "./[refreshToken]";
|
import { extractCommitMessage, extractHash } from "./[refreshToken]";
|
||||||
import type { DeploymentJob } from "@/server/queues/deployments-queue";
|
import type { DeploymentJob } from "@/server/queues/deployments-queue";
|
||||||
import { myQueue } from "@/server/queues/queueSetup";
|
import { myQueue } from "@/server/queues/queueSetup";
|
||||||
|
|
||||||
export default async function handler(
|
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||||
req: NextApiRequest,
|
const admin = await db.query.admins.findFirst({});
|
||||||
res: NextApiResponse,
|
|
||||||
) {
|
if (!admin) {
|
||||||
|
res.status(200).json({ message: "Could not find admin" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!admin.githubWebhookSecret) {
|
||||||
|
res.status(200).json({ message: "Github Webhook Secret not set" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const webhooks = new Webhooks({
|
||||||
|
secret: admin.githubWebhookSecret,
|
||||||
|
});
|
||||||
|
|
||||||
|
const signature = req.headers["x-hub-signature-256"];
|
||||||
const github = req.body;
|
const github = req.body;
|
||||||
|
|
||||||
|
const verified = await webhooks.verify(JSON.stringify(github), signature as string);
|
||||||
|
|
||||||
|
if (!verified) {
|
||||||
|
res.status(401).json({ message: "Unauthorized" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (req.headers["x-github-event"] === "ping") {
|
if (req.headers["x-github-event"] === "ping") {
|
||||||
res.status(200).json({ message: "Ping received, webhook is active" });
|
res.status(200).json({ message: "Ping received, webhook is active" });
|
||||||
return;
|
return;
|
||||||
@@ -33,7 +55,7 @@ export default async function handler(
|
|||||||
eq(applications.sourceType, "github"),
|
eq(applications.sourceType, "github"),
|
||||||
eq(applications.autoDeploy, true),
|
eq(applications.autoDeploy, true),
|
||||||
eq(applications.branch, branchName),
|
eq(applications.branch, branchName),
|
||||||
eq(applications.repository, repository),
|
eq(applications.repository, repository)
|
||||||
),
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -51,17 +73,12 @@ export default async function handler(
|
|||||||
{
|
{
|
||||||
removeOnComplete: true,
|
removeOnComplete: true,
|
||||||
removeOnFail: true,
|
removeOnFail: true,
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const composeApps = await db.query.compose.findMany({
|
const composeApps = await db.query.compose.findMany({
|
||||||
where: and(
|
where: and(eq(compose.sourceType, "github"), eq(compose.autoDeploy, true), eq(compose.branch, branchName), eq(compose.repository, repository)),
|
||||||
eq(compose.sourceType, "github"),
|
|
||||||
eq(compose.autoDeploy, true),
|
|
||||||
eq(compose.branch, branchName),
|
|
||||||
eq(compose.repository, repository),
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const composeApp of composeApps) {
|
for (const composeApp of composeApps) {
|
||||||
@@ -79,7 +96,7 @@ export default async function handler(
|
|||||||
{
|
{
|
||||||
removeOnComplete: true,
|
removeOnComplete: true,
|
||||||
removeOnFail: true,
|
removeOnFail: true,
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export default async function handler(
|
|||||||
githubAppName: data.name,
|
githubAppName: data.name,
|
||||||
githubClientId: data.client_id,
|
githubClientId: data.client_id,
|
||||||
githubClientSecret: data.client_secret,
|
githubClientSecret: data.client_secret,
|
||||||
|
githubWebhookSecret: data.webhook_secret,
|
||||||
githubPrivateKey: data.pem,
|
githubPrivateKey: data.pem,
|
||||||
})
|
})
|
||||||
.where(eq(admins.authId, authId as string))
|
.where(eq(admins.authId, authId as string))
|
||||||
|
|||||||
13925
pnpm-lock.yaml
generated
13925
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -23,6 +23,7 @@ export const admins = pgTable("admin", {
|
|||||||
githubClientSecret: text("githubClientSecret"),
|
githubClientSecret: text("githubClientSecret"),
|
||||||
githubInstallationId: text("githubInstallationId"),
|
githubInstallationId: text("githubInstallationId"),
|
||||||
githubPrivateKey: text("githubPrivateKey"),
|
githubPrivateKey: text("githubPrivateKey"),
|
||||||
|
githubWebhookSecret: text("githubWebhookSecret"),
|
||||||
letsEncryptEmail: text("letsEncryptEmail"),
|
letsEncryptEmail: text("letsEncryptEmail"),
|
||||||
sshPrivateKey: text("sshPrivateKey"),
|
sshPrivateKey: text("sshPrivateKey"),
|
||||||
enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false),
|
enableDockerCleanup: boolean("enableDockerCleanup").notNull().default(false),
|
||||||
|
|||||||
Reference in New Issue
Block a user