130 lines · 5.1 KB
import { z } from "zod";
import { all, first, run } from "../db";
import { randomId } from "../crypto";
import { conflict, HttpError, notFoundError } from "../errors";
import { commitFileChange } from "../git/web-commit";
import { assertBelowCap, CAPS, limitWrite } from "../limits";
import { toProtection } from "../protection";
import type { BranchProtection, BranchProtectionRow } from "../protection";
import { loadSecuritySettings, saveSecuritySettings } from "../security/settings";
import { noContent, readJson, requireScopedRepo, unprocessable } from "./http";
import type { ApiContext } from "./http";

const TAG_PREFIX = "refs/tags/";
const HTTP_CONFLICT = 409;
const MAX_CONTENT_BYTES = 5 * 1024 * 1024;

function ruleJson(rule: BranchProtection) {
  const kind = rule.pattern.startsWith(TAG_PREFIX) ? "tag" : "branch";
  return {
    id: rule.id,
    pattern: kind === "tag" ? rule.pattern.slice(TAG_PREFIX.length) : rule.pattern,
    kind,
    allow_force_push: rule.allowForcePushes,
    allow_deletions: rule.allowDeletions,
    require_pull_request: rule.requirePullRequest,
    required_approvals: rule.requiredApprovals,
    enforce_admins: rule.enforceAdmins,
  };
}

export async function listProtections(ctx: ApiContext, owner: string, name: string): Promise<Response> {
  const { repo } = await requireScopedRepo(ctx, owner, name, "admin", "admin");
  const rows = await all<BranchProtectionRow>(
    "SELECT * FROM branch_protections WHERE repo_id = ? ORDER BY pattern",
    repo.id,
  );
  return Response.json(rows.map((row) => ruleJson(toProtection(row))));
}

const protectionInput = z.object({