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
118 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.

Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running1/**
Merge branch 'main' into ask-integration2 * Guardrails, as the runner applies them to a sandbox: how long a run may
3 * take, and the outbound handlers its requests may pass.
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running4 *
5 * - The time cap is enforced twice: by the harness, and by the sandbox's
6 * own alarm here, which stops the whole sandbox a little after.
Merge branch 'main' into ask-integration7 * - Every sandbox reaches the internet directly. A workflow job that may
8 * be given brokered secrets sends its HTTP and HTTPS through `egress`
9 * below, which fills them in and sends everything on, to any host.
10 * - A sandbox's report that it stopped itself for mining comes to `abuse`.
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running11 */
12import type { OutboundHandlerContext } from "@cloudflare/containers";
13
14import { type RepoPath, type RunKind, type ServiceBinding, guardrailsClient } from "@g1t/contracts";
15
Merge branch 'main' into ask-integration16import { ABUSE_HOST, type RunGuard, sandboxNamespace } from "./egress";
Merge brokered secrets: a secret a job uses only to call an API can be tied to the hosts it is for, and the job gets a stand-in in its place, which g1t fills in on the way out to those hosts and nowhere else, so the value never enters the sandbox; and a request to an allowed host that fails upstream is retried when it can be, or answered with a 502 that says why, rather than reset.17import { type BrokeredParams, brokered } from "./broker-egress.ts";
18import { forward } from "./forward.ts";
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running19
20export {
21 ABUSE_EXIT_CODE,
22 ABUSE_HOST,
23 ABUSE_MESSAGE,
24 SANDBOX_BINDINGS,
Merge branch 'main' into actions-toolkit-oidc-artifacts25 dockerFor,
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running26 harnessEnv,
27 sandboxNamespace,
Merge branch 'main' into ask-integration28 throughWorker,
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running29 timeCapMessage,
30 withPlanLimits,
31} from "./egress";
Merge branch 'main' into ask-integration32export type { PlanLimits, RunGuard } from "./egress";
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running33
Merge branch 'main' into ask-integration34/** What the outbound handler is given: what brokered secrets need (broker-egress.ts). */
35export type EgressParams = BrokeredParams;
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running36
37/** The stop by the sandbox's alarm comes this long after the harness's own. */
38export const ALARM_GRACE_SECONDS = 3 * 60;
39
40/**
41 * The guardrails of a run in `repo`. Throws when they cannot be read: a
42 * sandbox is not started without them.
43 */
44export async function guardFor(work: ServiceBinding, repo: RepoPath, kind: RunKind): Promise<RunGuard> {
45 const found = await guardrailsClient(work).runGuardrails(repo);
46 if (!found.ok) throw new Error(`g1t could not read this project's guardrails: ${found.error.message}`);
47 const policy = found.value;
48 return { policy, minutes: policy.minutes[kind] ?? 60 };
49}
50
51/**
Merge branch 'main' into ask-integration52 * The guardrails of a workflow job, deploy build or update: the time cap it
53 * was given, which is all a build's guardrails are.
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running54 */
Merge branch 'main' into ask-integration55export function buildGuard(minutes: number): RunGuard {
56 return { policy: { minutes: {} }, minutes };
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running57}
58
59/**
Merge branch 'main' into ask-integration60 * The outbound handler of a sandbox whose HTTP and HTTPS pass the Worker
61 * (a workflow job that may be given brokered secrets): every request it
62 * makes, to any host. Its brokered secrets are filled in first, if it has
63 * any, and the request is sent on with `forward`'s retries.
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running64 */
65export async function egress(
66 request: Request,
Merge brokered secrets: a secret a job uses only to call an API can be tied to the hosts it is for, and the job gets a stand-in in its place, which g1t fills in on the way out to those hosts and nowhere else, so the value never enters the sandbox; and a request to an allowed host that fails upstream is retried when it can be, or answered with a 502 that says why, rather than reset.67 env: { SANDBOX: DurableObjectNamespace; ACTIONS?: ServiceBinding },
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running68 ctx: OutboundHandlerContext<EgressParams>,
69): Promise<Response> {
70 const host = new URL(request.url).host;
71 // A sandbox reporting that it stopped itself for mining.
72 if (host === ABUSE_HOST) return abuse(request, env, ctx);
Merge branch 'main' into ask-integration73 return (await brokered(request, env, ctx)) ?? forward(request);
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running74}
75
76/**
77 * A sandbox's report that it stopped itself for mining (crates/runner
Merge branch 'main' into ask-integration78 * abuse.rs), handed to its Durable Object. The handler for `ABUSE_HOST`
79 * on every sandbox, and reached through `egress` for one whose requests
80 * pass the Worker.
Costs: a statement that keeps usage sold, running g1t, subscriptions and what was given away (comped, free use, trial, pool) apart, and says who was paid; free use carries its own cost; the run button says it is running81 */
82export async function abuse(
83 request: Request,
84 env: { SANDBOX: DurableObjectNamespace },
85 ctx: OutboundHandlerContext<unknown>,
86): Promise<Response> {
87 let verdict: unknown = null;
88 try {
89 verdict = ((await request.json()) as { verdict?: unknown }).verdict ?? null;
90 } catch {
91 // A report without its metrics still stops the run.
92 }
93 try {
94 const namespace = sandboxNamespace(env, ctx.className);
95 const sandbox = namespace.get(namespace.idFromString(ctx.containerId)) as unknown as {
96 flagAbuse(verdict: unknown): Promise<void>;
97 };
98 await sandbox.flagAbuse(verdict);
99 } catch (error) {
100 console.log("abuse report not handled", String(error));
101 }
102 return new Response("noted\n");
103}
104
105/** Adds a step to a run, with its token. Never fails the caller. */
106export async function reportRun(
107 work: ServiceBinding,
108 tracked: { runId: string; token: string },
109 report: { steps?: string[]; halt?: "budget" | "time" | "abuse"; error?: string },
110): Promise<void> {
111 await work
112 .fetch("https://service/rpc/report_run", {
113 method: "POST",
114 headers: { "content-type": "application/json" },
115 body: JSON.stringify({ runId: tracked.runId, token: tracked.token, ...report }),
116 })
117 .catch((error: unknown) => console.log("run report failed", tracked.runId, String(error)));
118}

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