Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

61 linesCodeBlameRaw
1import { Link } from "react-router";
2
3import type { Route } from "./+types/settings-guardrails";
4import { GuardrailsForm } from "../../components/guardrails";
5import { RepoSettingsHeading } from "../../components/repo-settings-heading";
6import { SANDBOX_RUN_KINDS, settingsFromForm } from "../../lib/guardrails";
7import { page } from "../../lib/meta";
8import { guardrails } from "../../lib/services.server";
9import { assertSameOrigin, getViewer, requireUser, unwrap } from "../../lib/session.server";
10import { requireCapability, requireInsider } from "../../lib/access.server";
11
12export function meta({ params, ...args }: Route.MetaArgs) {
13 return page(args, { title: `Guardrails · ${params.owner}/${params.repo} · g1t` });
14}
15
16export async function loader({ params, context }: Route.LoaderArgs) {
17 const viewer = getViewer(context);
18 // Admin; to anyone without a role here the page does not exist.
19 await requireInsider(context, params, "manage_protection");
20 const view = await guardrails.getGuardrails(viewer, params.owner, { namespace: params.owner, name: params.repo });
21 return { view: unwrap(view) };
22}
23
24export async function action({ request, params, context }: Route.ActionArgs) {
25 assertSameOrigin(request);
26 const user = requireUser(context, request);
27 await requireCapability(context, params, "manage_protection");
28 const form = await request.formData();
29 const current = await guardrails.getGuardrails(user, params.owner);
30 if (!current.ok) return { saved: false, error: current.error.message };
31 const settings = settingsFromForm(form, {
32 registries: current.value.registries.map((registry) => registry.id),
33 kinds: SANDBOX_RUN_KINDS,
34 });
35 const saved = await guardrails.updateGuardrails(user, params.owner, { namespace: params.owner, name: params.repo }, settings);
36 return saved.ok ? { saved: true, error: null } : { saved: false, error: saved.error.message };
37}
38
39export default function RepoGuardrails({ loaderData, actionData, params }: Route.ComponentProps) {
40 const base = `/${params.owner}/${params.repo}`;
41 return (
42 <>
43 <RepoSettingsHeading base={base} />
44 <p className="mb-8 max-w-3xl text-sm text-muted">
45 What g1t, its checks and the merge queue may do in this project's sandboxes. Anything left as the
46 workspace's follows the{" "}
47 <Link to={`/${params.owner}/-/guardrails`} className="text-fg underline-offset-2 hover:underline">
48 workspace's defaults
49 </Link>
50 . Changes apply to runs that start after you save.
51 </p>
52 <GuardrailsForm
53 view={loaderData.view}
54 level="project"
55 editable
56 saved={actionData?.saved ?? false}
57 error={actionData?.error}
58 />
59 </>
60 );
61}