chore: update src/pages/api/internal/hooks/pre-receive.ts

swadhinbiswas committed 8 months ago
1333f3c
1 parent 25d2b94
commit 1333f3c
1 file changed
+24 -8
▼src/pages/api/internal/hooks/pre-receive.ts
+24-8
4
4
import type { APIRoute } from "astro";
5
5
import { eq, and } from "drizzle-orm";
6
6
import micromatch from "micromatch";
7
+import { resolveRepoPath } from "@/lib/git-storage";
7
8
8
9
export const POST: APIRoute = async ({ request, url }) => {
9
10
const hookSecret = process.env.INTERNAL_HOOK_SECRET;
29
30
30
31
const { refname, newrev, oldrev, pusher } = body;
31
32
const userId = pusher; // The SSH server sends REMOTE_USER as userId
32
- // const isForcePush = ... // Hard to detect strictly from here without more Git context, but typically oldrev mismatch?
33
- // Actually, force push is when newrev is not a descendant of oldrev. We can check that if we have git access.
34
- // For now, let's focus on branch existence and roles.
33
+ const isSystemPush = userId === "system" || userId === "internal-bot";
35
34
36
- const branchName = refname.replace("refs/heads/", "");
37
- if (!branchName) {
38
- return new Response("OK", { status: 200 }); // Not a branch push (e.g. tag), or ignore for now
35
+ // We enforce branch protection only for branch refs.
36
+ if (!refname.startsWith("refs/heads/")) {
37
+ return new Response("OK", { status: 200 });
39
38
}
39
+ const branchName = refname.slice("refs/heads/".length);
40
40
41
41
const db = getDatabase() as NodePgDatabase<typeof schema>;
42
42
68
68
if (!repo) {
69
69
return new Response("Repo not found", { status: 404 });
70
70
}
71
+ const localRepoPath = await resolveRepoPath(repo.diskPath);
72
+ const pusherUser = userId
73
+ ? await db.query.users.findFirst({
74
+ where: eq(schema.users.id, userId),
75
+ columns: { id: true, isAdmin: true },
76
+ })
77
+ : null;
78
+ const isPrivilegedPush = isSystemPush || !!pusherUser?.isAdmin;
71
79
72
80
// Fetch protection rules
73
81
const rules = await db.query.branchProtection.findMany({
94
102
95
103
// 1. Require PR
96
104
if (matchingRule.requiresPr) {
105
+ if (isPrivilegedPush) {
106
+ return new Response("OK", { status: 200 });
107
+ }
108
+
97
109
// If newrev allows force push (0000 -> sha is Create, Sha -> 0000 is Delete)
98
110
const isDelete = newrev === "0000000000000000000000000000000000000000";
99
111
123
135
124
136
// 2. Prevent Force Push
125
137
if (!matchingRule.allowForcePushes) {
138
+ if (isPrivilegedPush) {
139
+ return new Response("OK", { status: 200 });
140
+ }
141
+
126
142
// We need to check if it's a force push.
127
143
// git rev-list oldrev ^newrev (if output non-empty, it's non-fast-forward?)
128
144
// Actually simpler: `git merge-base --is-ancestor oldrev newrev`
135
151
// This is expensive for an API request? Maybe. But necessary.
136
152
// We can use simple-git.
137
153
const { simpleGit } = await import("simple-git");
138
- const git = simpleGit(repoPath);
154
+ const git = simpleGit(localRepoPath);
139
155
try {
140
156
// merge-base --is-ancestor oldrev newrev
141
157
await git.raw(["merge-base", "--is-ancestor", oldrev, newrev]);
164
180
let changedFiles: string[] = [];
165
181
try {
166
182
const { simpleGit } = await import("simple-git");
167
- const git = simpleGit(repoPath);
183
+ const git = simpleGit(localRepoPath);
168
184
169
185
// Determine base revision for diff
170
186
let baseRev = oldrev;
171
187