import { z } from "zod";
import { credentialAllows, requestCredential } from "../token-scope";
import { repoDb } from "../scoped-db";
import { badRequest, HttpError, notFoundError, unauthorized, forbidden } from "../errors";
import { limitHeavy, limitWrite } from "../limits";
import { requireRepoAccess } from "../repos";
import { isReachableCommit } from "../git/reachable";
import { listRefs } from "../git/refs";
import type { RepoRow } from "~/lib/types";
import { assertUploadBudget, decodeSarifPayload, SARIF_LIMITS, storeSarifUpload } from "./code-scanning";
import { enqueueSecurity } from "./queue";
const SARIF_UPLOAD_PATH = /^\/api\/repos\/([^/]+)\/([^/]+)\/code-scanning\/sarifs$/;
const SARIF_STATUS_PATH = /^\/api\/repos\/([^/]+)\/([^/]+)\/code-scanning\/sarifs\/([a-z0-9]+)$/;
const BASE64_OVERHEAD = 4 / 3;
const MAX_BODY_BYTES = Math.ceil(SARIF_LIMITS.maxBytes * BASE64_OVERHEAD) + 4096;
const HTTP_ACCEPTED = 202;
const HTTP_TOO_LARGE = 413;
const uploadBody = z.object({
commit_sha: z.string().regex(/^[0-9a-f]{40}$/, "commit_sha must be a full SHA"),
ref: z
.string()
.regex(/^refs\/(heads|tags|pull)\/.+/, "ref must look like refs/heads/<branch> or refs/pull/<n>/head")
.max(255),
sarif: z.string().min(1),
});
async function readBody(request: Request): Promise<string> {
const declared = Number(request.headers.get("content-length") ?? "0");
if (declared > MAX_BODY_BYTES) throw new HttpError(HTTP_TOO_LARGE, "SARIF upload too large");
if (!request.body) return "";
const reader = request.body.getReader();
const decoder = new TextDecoder();
let text = "";
let total = 0;
while (true) {
const { value, done } = await reader.read();
if (done) break;
total += value.byteLength;