1/** Application policy, shared by push, REST ref writes, and pull merges. */
2import * as Git from "alchemy/Git";
3import * as Effect from "effect/Effect";
4import { Session, Unauthorized } from "./auth.ts";
5
6export const checkRefChanges = (
7 repo: Git.RepoMetaData,
8 updates: ReadonlyArray<Git.RefUpdate>,
9) =>
10 Effect.gen(function* () {
11 const { user } = yield* Session;
12 if (user === null) return yield* new Unauthorized();
13 for (const update of updates) {
14 if (user.id.toLowerCase() !== repo.owner.toLowerCase()) {
15 return yield* new Git.PushDenied({
16 ref: update.ref,
17 reason: "only the repository owner may change refs",
18 });
19 }
20 if (
21 update.ref === `refs/heads/${repo.defaultBranch}` &&
22 /^0+$/.test(update.newOid)
23 ) {
24 return yield* new Git.PushDenied({
25 ref: update.ref,
26 reason: "the default branch cannot be deleted",
27 });
28 }
29 }
30 });