136 lines · 5.1 KB
import { z } from "zod";
import { all } from "../db";
import { notFoundError } from "../errors";
import { limitWrite } from "../limits";
import { approveRunRow, cancelRunRow, loadRunByNumber } from "../ci/run-control";
import { listRepoRunners, mintRegistrationToken, removeRepoRunner, repoScope } from "../ci/runner-registration";
import { forkRunsAllowed, setForkRunsAllowed } from "../ci/runner-policy";
import { noContent, readJson, requireScopedRepo } from "./http";
import type { ApiContext } from "./http";

const MAX_RUNS_LISTED = 20;
const MAX_JOBS_LISTED = 200;

const registrationInput = z.object({
  scope: z.enum(["repository", "owner"]).default("repository"),
  labels: z.array(z.string().trim().min(1).max(32)).max(20).default([]),
});
const policyInput = z.object({ allow_fork_pull_requests: z.boolean() });

export async function createRegistrationToken(ctx: ApiContext, owner: string, name: string): Promise<Response> {
  const data = await readJson(ctx.request, registrationInput);
  await limitWrite(ctx.viewer);
  const { repo } = await requireScopedRepo(ctx, owner, name, "admin", "admin");
  const scope = await repoScope(repo, data.scope, ctx.viewer);
  const minted = await mintRegistrationToken(scope, ctx.viewer.id, data.labels);
  return Response.json({ token: minted.token, expires_at: minted.expiresAt }, { status: 201 });
}

export async function listRunnersApi(ctx: ApiContext, owner: string, name: string): Promise<Response> {
  const { repo } = await requireScopedRepo(ctx, owner, name, "admin", "admin");
  return Response.json({
    runners: await listRepoRunners(repo),
    allow_fork_pull_requests: await forkRunsAllowed(repo.id),
  });
}

export async function deleteRunnerApi(ctx: ApiContext, owner: string, name: string, id: string): Promise<Response> {
  await limitWrite(ctx.viewer);
  const { repo } = await requireScopedRepo(ctx, owner, name, "admin", "admin");
  if (!(await removeRepoRunner(repo, id, ctx.viewer))) throw notFoundError("Runner not found");