227 lines · 9.6 KB
import { env } from "cloudflare:workers";
import { z } from "zod";
import { all, first, run } from "../db";
import { sha256Hex } from "../crypto";
import { viewerFromRequest, viewerFromSessionCookie } from "../auth";
import { repoPermission, loadRepoById } from "../repos";
import { authenticatedRemote, mintRepoToken } from "../git/artifacts";
import { isCloudJob, loadJobExecution, markJobStarted, resolveSecrets, runnerStub } from "./jobs";
import type { WorkflowJobRow } from "./jobs";
import { buildJobScript } from "./script";
import { stepSecretNames } from "./compile";
import type { LogRow } from "./runner-do";
import { randomId } from "../crypto";

const TOKEN_GRACE_SECONDS = 600;
const CLAIM_CANDIDATES = 25;
const STALE_RUNNER_MS = 10 * 60 * 1000;
const MAX_LOG_CHUNK_BYTES = 1024 * 1024;
const MAX_ARTIFACT_BYTES = 1024 * 1024 * 1024;
const MAX_ARTIFACTS_PER_JOB = 20;
export const RUNNER_TOKEN_PREFIX = "stig_runner";

type RunnerRow = {
  id: string;
  repo_id: string | null;
  owner_id: string | null;
  name: string;
  labels: string;
  last_seen_at: number | null;
};

const claimBody = z.object({ labels: z.array(z.string()).optional() });
const completeBody = z.object({ exitCode: z.number().int() });

function json(data: unknown, status = 200): Response {
  return Response.json(data, { status });
}

async function authenticateRunner(request: Request): Promise<RunnerRow | null> {
  const header = request.headers.get("authorization") ?? "";