| 1 | /** Application policy, shared by push, REST ref writes, and pull merges. */ |
| 2 | import * as Git from "alchemy/Git"; |
| 3 | import * as Effect from "effect/Effect"; |
| 4 | import { Session, Unauthorized } from "./auth.ts"; |
| 5 | |
| 6 | export 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 | }); |