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.

g1t.sh
85 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Money in billing's messages reads to the cent, and the deploy reads migrations again after a failure1/**
2 * What every sudo response carries, and the page shown to whoever is
3 * turned away. No Workers imports, so it can be tested under Node.
4 */
5
6/**
7 * The pages ship no JavaScript, so no script may run at all; styles and
8 * images and fonts come only from sudo itself, and forms post only back
9 * to sudo.
10 */
11export const CONTENT_SECURITY_POLICY = [
12 "default-src 'none'",
13 "script-src 'none'",
14 "style-src 'self'",
15 "font-src 'self'",
16 "img-src 'self' data:",
17 "form-action 'self'",
18 "frame-ancestors 'none'",
19 "base-uri 'none'",
20 "upgrade-insecure-requests",
21].join("; ");
22
23const HEADERS: Record<string, string> = {
24 "cache-control": "no-store",
25 "x-robots-tag": "noindex, nofollow, noarchive",
26 "x-frame-options": "DENY",
27 "x-content-type-options": "nosniff",
28 // Same-origin keeps the Referer that the same-origin check falls back on.
29 "referrer-policy": "same-origin",
30 "strict-transport-security": "max-age=63072000; includeSubDomains",
31 "cross-origin-opener-policy": "same-origin",
32 "cross-origin-resource-policy": "same-origin",
33 "permissions-policy": "camera=(), microphone=(), geolocation=(), payment=(), usb=(), interest-cohort=()",
34};
35
36/** The response with sudo's headers; a policy it already set is kept. */
37export function secure(response: Response): Response {
38 const secured = new Response(response.body, response);
39 for (const [name, value] of Object.entries(HEADERS)) secured.headers.set(name, value);
40 if (!secured.headers.has("content-security-policy")) {
41 secured.headers.set("content-security-policy", CONTENT_SECURITY_POLICY);
42 }
43 return secured;
44}
45
46const DENIED_STYLE = `
47:root{color-scheme:dark}
48body{margin:0;min-height:100vh;display:grid;place-items:center;background:#0f0f11;color:#ededef;
49font:15px/1.6 'Hanken Grotesk',ui-sans-serif,system-ui,sans-serif;-webkit-font-smoothing:antialiased}
50main{max-width:28rem;padding:2rem 1rem;text-align:center}
51.badge{display:inline-block;border:1px solid #b6a8ff66;color:#b6a8ff;background:#b6a8ff1a;border-radius:999px;
52padding:.1rem .6rem;font:600 12px/1.6 ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.02em}
53h1{margin:1rem 0 .5rem;font-size:1.25rem;letter-spacing:-.01em}
54p{margin:0;color:#a0a0a8}code{color:#ededef;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.9em}`;
55
56let styleHash: Promise<string> | null = null;
57
58function hashOfStyle(): Promise<string> {
59 styleHash ??= crypto.subtle
60 .digest("SHA-256", new TextEncoder().encode(DENIED_STYLE))
61 .then((digest) => btoa(String.fromCharCode(...new Uint8Array(digest))));
62 return styleHash;
63}
64
65function escapeHtml(text: string): string {
66 return text.replace(/[&<>"']/g, (char) => `&#${char.charCodeAt(0)};`);
67}
68
69/**
70 * A self-contained page for a refusal: its one inline stylesheet is
71 * allowed by its hash, and nothing else is.
72 */
73export async function denied(status: number, title: string, message: string): Promise<Response> {
74 const html = `<!doctype html><html lang="en"><head><meta charset="utf-8">
75<meta name="viewport" content="width=device-width, initial-scale=1"><meta name="robots" content="noindex, nofollow">
76<title>${escapeHtml(title)} · sudo</title><style>${DENIED_STYLE}</style></head>
77<body><main><span class="badge">sudo</span><h1>${escapeHtml(title)}</h1><p>${escapeHtml(message)}</p></main></body></html>`;
78 return new Response(html, {
79 status,
80 headers: {
81 "content-type": "text/html; charset=utf-8",
82 "content-security-policy": `default-src 'none'; style-src 'sha256-${await hashOfStyle()}'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'`,
83 },
84 });
85}

This file's history is long; its oldest lines are credited to the oldest commit read.