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.

44 linesCodeBlameRaw
1/**
2 * "Set up a security policy": commits a SECURITY.md on a new branch as the
3 * person asking and opens it as their pull request, then goes to it, as
4 * "Set up code scanning" does with its workflow. It adds a file to the
5 * repository: Push.
6 */
7import { redirect } from "react-router";
8
9import type { Route } from "./+types/security-policy-setup";
10import { refusal } from "../../lib/access.server";
11import { securityPolicyBranch, securityPolicyPullBody, securityPolicyTemplate } from "../../lib/security-overview";
12import { advisories, repos, work } from "../../lib/services.server";
13import { assertSameOrigin, requireUser } from "../../lib/session.server";
14
15export async function action({ request, params, context }: Route.ActionArgs) {
16 assertSameOrigin(request);
17 const user = requireUser(context, request);
18 const refused = await refusal(context, params, "push");
19 if (refused) return { error: refused };
20 const path = { namespace: params.owner, name: params.repo };
21 const base = `/${params.owner}/${params.repo}`;
22 const [branches, reporting] = await Promise.all([repos.branches(path, user), advisories.reportSettings(path, user)]);
23 const branch = securityPolicyBranch(branches.ok ? branches.value.map((known) => known.name) : []);
24 const committed = await repos.commitFile(path, user, {
25 branch,
26 path: "SECURITY.md",
27 content: securityPolicyTemplate(`${params.owner}/${params.repo}`, reporting.ok && reporting.value.privateVulnerabilityReporting, base),
28 message: "Add a security policy",
29 });
30 if (!committed.ok) return { error: committed.error.message };
31 const opened = await work.openPull(user, path, {
32 branch,
33 title: "Add a security policy",
34 body: securityPolicyPullBody("SECURITY.md"),
35 agent: user.username,
36 runtime: "external",
37 });
38 if (!opened.ok) return { error: opened.error.message };
39 throw redirect(`${base}/pull/${opened.value.number}`);
40}
41
42export async function loader({ params }: Route.LoaderArgs) {
43 throw redirect(`/${params.owner}/${params.repo}/security`);
44}