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.
| Billing and Usage reconcile: own-provider runs leave Billing's at-price total, and Usage's not-charged part is at price less charged | 1 | /** |
| Guardrails no longer restrict the network: every sandbox on g1t's machines reaches the internet, as a GitHub-hosted runner does, and the settings for it are gone at every level, the workspace's defaults and each project's overrides: Only allowed hosts (restrict_network), the package registries, allowed domains and workflow-only domains. Guardrails are now the time caps on checks, the merge queue and merge checks, and nothing else. | 2 | * What a sandbox's guardrails come to inside it, and the host names its |
| 3 | * outbound requests are compared by. Pure, so it can be tested on its | |
| 4 | * own; guard.ts applies it. | |
| Billing and Usage reconcile: own-provider runs leave Billing's at-price total, and Usage's not-charged part is at price less charged | 5 | * |
| Guardrails no longer restrict the network: every sandbox on g1t's machines reaches the internet, as a GitHub-hosted runner does, and the settings for it are gone at every level, the workspace's defaults and each project's overrides: Only allowed hosts (restrict_network), the package registries, allowed domains and workflow-only domains. Guardrails are now the time caps on checks, the merge queue and merge checks, and nothing else. | 6 | * Every sandbox reaches the internet, as a CI machine does. Its requests |
| 7 | * go straight out, except where the Worker has to see them: a workflow | |
| 8 | * job that may be given brokered secrets sends its HTTP and HTTPS through | |
| 9 | * the Worker (Cloudflare Containers' outbound interception), which fills | |
| 10 | * the secrets in (broker-egress.ts), and every sandbox's report that it | |
| 11 | * stopped itself for mining (`ABUSE_HOST`) is answered by its own Durable | |
| 12 | * Object. | |
| Billing and Usage reconcile: own-provider runs leave Billing's at-price total, and Usage's not-charged part is at price less charged | 13 | */ |
| 14 | ||
| Guardrails no longer restrict the network: every sandbox on g1t's machines reaches the internet, as a GitHub-hosted runner does, and the settings for it are gone at every level, the workspace's defaults and each project's overrides: Only allowed hosts (restrict_network), the package registries, allowed domains and workflow-only domains. Guardrails are now the time caps on checks, the merge queue and merge checks, and nothing else. | 15 | import type { Guardrails } from "@g1t/contracts"; |
| Billing and Usage reconcile: own-provider runs leave Billing's at-price total, and Usage's not-charged part is at price less charged | 16 | |
| 17 | /** A host name as it is compared: lower case, no port, no trailing dot. */ | |
| 18 | export function normalizeHost(host: string): string { | |
| 19 | let name = host.trim().toLowerCase(); | |
| 20 | // An IPv6 literal keeps its colons. | |
| 21 | if (name.startsWith("[")) return name.slice(0, name.indexOf("]") + 1); | |
| 22 | const colon = name.indexOf(":"); | |
| 23 | if (colon >= 0) name = name.slice(0, colon); | |
| 24 | return name.replace(/\.+$/, ""); | |
| 25 | } | |
| 26 | ||
| 27 | /** | |
| Guardrails no longer restrict the network: every sandbox on g1t's machines reaches the internet, as a GitHub-hosted runner does, and the settings for it are gone at every level, the workspace's defaults and each project's overrides: Only allowed hosts (restrict_network), the package registries, allowed domains and workflow-only domains. Guardrails are now the time caps on checks, the merge queue and merge checks, and nothing else. | 28 | * Whether `host` is on the list. `example.com` matches exactly that host; |
| 29 | * `*.example.com` matches its subdomains, at any depth, but not | |
| 30 | * `example.com` itself. Used for the hosts a brokered secret is for. | |
| Billing and Usage reconcile: own-provider runs leave Billing's at-price total, and Usage's not-charged part is at price less charged | 31 | */ |
| 32 | export function allows(patterns: readonly string[], host: string): boolean { | |
| 33 | const name = normalizeHost(host); | |
| 34 | if (!name) return false; | |
| 35 | return patterns.some((raw) => { | |
| 36 | const pattern = raw.trim().toLowerCase(); | |
| 37 | if (pattern.startsWith("*.")) { | |
| 38 | const suffix = pattern.slice(1); | |
| 39 | return name.length > suffix.length && name.endsWith(suffix); | |
| 40 | } | |
| 41 | return pattern === name; | |
| 42 | }); | |
| 43 | } | |
| 44 | ||
| Merge branch 'runner-egress-reset' | 45 | /** |
| Guardrails no longer restrict the network: every sandbox on g1t's machines reaches the internet, as a GitHub-hosted runner does, and the settings for it are gone at every level, the workspace's defaults and each project's overrides: Only allowed hosts (restrict_network), the package registries, allowed domains and workflow-only domains. Guardrails are now the time caps on checks, the merge queue and merge checks, and nothing else. | 46 | * The variables a sandbox whose HTTPS passes the Worker needs, so that its |
| 47 | * programs trust the certificate HTTPS is re-signed with there. The runner | |
| 48 | * adds that certificate to the system's store when it starts; these point | |
| 49 | * the tools that keep their own list at it. | |
| Billing and Usage reconcile: own-provider runs leave Billing's at-price total, and Usage's not-charged part is at price less charged | 50 | */ |
| 51 | export const EGRESS_CA = "/etc/cloudflare/certs/cloudflare-containers-ca.crt"; | |
| 52 | const SYSTEM_BUNDLE = "/etc/ssl/certs/ca-certificates.crt"; | |
| 53 | export const EGRESS_ENV: Record<string, string> = { | |
| 54 | G1T_EGRESS_CA: EGRESS_CA, | |
| 55 | NODE_EXTRA_CA_CERTS: EGRESS_CA, | |
| 56 | SSL_CERT_FILE: SYSTEM_BUNDLE, | |
| 57 | REQUESTS_CA_BUNDLE: SYSTEM_BUNDLE, | |
| 58 | PIP_CERT: SYSTEM_BUNDLE, | |
| 59 | CURL_CA_BUNDLE: SYSTEM_BUNDLE, | |
| 60 | CARGO_HTTP_CAINFO: SYSTEM_BUNDLE, | |
| 61 | GIT_SSL_CAINFO: SYSTEM_BUNDLE, | |
| Merge branch 'run-notes' into fast-push | 62 | }; |
| 63 | ||
| Billing and Usage reconcile: own-provider runs leave Billing's at-price total, and Usage's not-charged part is at price less charged | 64 | /** What a sandbox's guardrails come to for one run. */ |
| 65 | export type RunGuard = { | |
| 66 | policy: Guardrails; | |
| 67 | /** The time cap of this kind of run, in minutes. */ | |
| 68 | minutes: number; | |
| 69 | }; | |
| 70 | ||
| 71 | /** What the harness is told about the run's guardrails. */ | |
| Guardrails no longer restrict the network: every sandbox on g1t's machines reaches the internet, as a GitHub-hosted runner does, and the settings for it are gone at every level, the workspace's defaults and each project's overrides: Only allowed hosts (restrict_network), the package registries, allowed domains and workflow-only domains. Guardrails are now the time caps on checks, the merge queue and merge checks, and nothing else. | 72 | export function harnessEnv(guard: RunGuard, sandboxEnv: Record<string, string>): Record<string, string> { |
| 73 | return { | |
| Billing and Usage reconcile: own-provider runs leave Billing's at-price total, and Usage's not-charged part is at price less charged | 74 | GUARDRAILS: JSON.stringify({ |
| 75 | rules: guard.policy.rules, | |
| 76 | deny: guard.policy.deny, | |
| 77 | budgetUsd: guard.policy.budgetUsd, | |
| 78 | minutes: guard.minutes, | |
| 79 | defaultBranch: sandboxEnv.UPSTREAM_BRANCH ?? null, | |
| 80 | }), | |
| 81 | }; | |
| 82 | } | |
| 83 | ||
| 84 | /** What a run stopped by its time cap is told. */ | |
| 85 | export function timeCapMessage(minutes: number): string { | |
| 86 | return `Stopped: it reached its time cap of ${minutes} ${minutes === 1 ? "minute" : "minutes"}.`; | |
| 87 | } | |
| 88 | ||
| 89 | /** | |
| 90 | * Where a sandbox tells the runner it stopped itself for mining | |
| 91 | * (crates/runner abuse.rs). The runner's Durable Object answers it; it | |
| 92 | * never leaves the machine. | |
| 93 | */ | |
| 94 | export const ABUSE_HOST = "sandbox.g1t.internal"; | |
| 95 | /** What a sandbox that stopped itself for mining exits with. */ | |
| 96 | export const ABUSE_EXIT_CODE = 86; | |
| 97 | /** What such a run, check, job or build says. */ | |
| 98 | export const ABUSE_MESSAGE = "Stopped: unusual CPU use; contact support if this was a real job."; | |
| 99 | ||
| 100 | /** | |
| Merge branch 'main' into actions-toolkit-oidc-artifacts | 101 | * Whether a workflow job gets a Docker Engine of its own, from the |
| 102 | * Worker's `DOCKER` setting: on unless it says `off`. Its containers share | |
| Guardrails no longer restrict the network: every sandbox on g1t's machines reaches the internet, as a GitHub-hosted runner does, and the settings for it are gone at every level, the workspace's defaults and each project's overrides: Only allowed hosts (restrict_network), the package registries, allowed domains and workflow-only domains. Guardrails are now the time caps on checks, the merge queue and merge checks, and nothing else. | 103 | * the job's network. |
| Merge branch 'main' into actions-toolkit-oidc-artifacts | 104 | */ |
| 105 | export function dockerFor(setting: string | undefined): "on" | "off" { | |
| 106 | return setting?.trim().toLowerCase() === "off" ? "off" : "on"; | |
| 107 | } | |
| 108 | ||
| 109 | /** | |
| Guardrails no longer restrict the network: every sandbox on g1t's machines reaches the internet, as a GitHub-hosted runner does, and the settings for it are gone at every level, the workspace's defaults and each project's overrides: Only allowed hosts (restrict_network), the package registries, allowed domains and workflow-only domains. Guardrails are now the time caps on checks, the merge queue and merge checks, and nothing else. | 110 | * Whether a sandbox sends its HTTP and HTTPS through the Worker: only a |
| 111 | * workflow job that may be given brokered secrets, so they can be filled | |
| 112 | * in, and not when the operator turned that off (`EGRESS` is `off`). | |
| 113 | * Every other sandbox's requests go straight out. | |
| Billing and Usage reconcile: own-provider runs leave Billing's at-price total, and Usage's not-charged part is at price less charged | 114 | */ |
| Guardrails no longer restrict the network: every sandbox on g1t's machines reaches the internet, as a GitHub-hosted runner does, and the settings for it are gone at every level, the workspace's defaults and each project's overrides: Only allowed hosts (restrict_network), the package registries, allowed domains and workflow-only domains. Guardrails are now the time caps on checks, the merge queue and merge checks, and nothing else. | 115 | export function throughWorker(job: { brokered?: boolean } | null | undefined, setting: string | undefined): boolean { |
| 116 | return job?.brokered === true && setting?.trim().toLowerCase() !== "off"; | |
| Billing and Usage reconcile: own-provider runs leave Billing's at-price total, and Usage's not-charged part is at price less charged | 117 | } |
| 118 | ||
| 119 | /** | |
| 120 | * The Durable Object namespace behind each sandbox class, by its binding: | |
| 121 | * a sandbox's outbound handlers are told its class, and report back to its | |
| Merge branch 'worktree-agent-a56293a6f836cd343' | 122 | * own object. Each label in the machine catalogue (`INSTANCE_TYPES`) has a |
| 123 | * class of its own (wrangler.jsonc), named by its `sandboxClass`. | |
| Billing and Usage reconcile: own-provider runs leave Billing's at-price total, and Usage's not-charged part is at price less charged | 124 | */ |
| 125 | export const SANDBOX_BINDINGS: Record<string, string> = { | |
| 126 | AttemptSandbox: "SANDBOX", | |
| 127 | Sandbox2Core: "SANDBOX_2CORE", | |
| 128 | Sandbox4Core: "SANDBOX_4CORE", | |
| 129 | }; | |
| 130 | ||
| 131 | /** The namespace of a sandbox of `className`; the standard one when unknown. */ | |
| 132 | export function sandboxNamespace(env: object, className: string | undefined): DurableObjectNamespace { | |
| 133 | const bindings = env as Record<string, DurableObjectNamespace | undefined>; | |
| 134 | const binding = (className && SANDBOX_BINDINGS[className]) || "SANDBOX"; | |
| 135 | return (bindings[binding] ?? bindings.SANDBOX) as DurableObjectNamespace; | |
| 136 | } | |
| 137 | ||
| 138 | /** | |
| Merge branch 'worktree-agent-a56293a6f836cd343' | 139 | * The namespace a workflow job on `instance` starts in: its catalogue class's |
| 140 | * binding. Null when the class or its binding is missing here (a self-hosted | |
| 141 | * g1t that did not deploy that class), so the job says so rather than | |
| 142 | * running on another machine. | |
| 143 | */ | |
| 144 | export function jobNamespaceOf(env: object, instance: { sandboxClass: string }): DurableObjectNamespace | null { | |
| 145 | const binding = SANDBOX_BINDINGS[instance.sandboxClass]; | |
| 146 | return (binding && (env as Record<string, DurableObjectNamespace | undefined>)[binding]) || null; | |
| Billing and Usage reconcile: own-provider runs leave Billing's at-price total, and Usage's not-charged part is at price less charged | 147 | } |
| 148 | ||
| 149 | /** The lower of two caps, where null, zero or less means no cap. */ | |
| 150 | function lower(a: number | null | undefined, b: number | null | undefined): number | null { | |
| 151 | const caps = [a, b].filter((cap): cap is number => typeof cap === "number" && Number.isFinite(cap) && cap > 0); | |
| 152 | return caps.length ? Math.min(...caps) : null; | |
| 153 | } | |
| 154 | ||
| 155 | /** A plan's caps on one run, from its entitlements; null where it sets none. */ | |
| 156 | export type PlanLimits = { minutes?: number | null; budgetUsd?: number | null }; | |
| 157 | ||
| 158 | /** | |
| 159 | * A run's guardrails under its workspace's plan: the time and cost caps are | |
| 160 | * each the lower of the two. | |
| 161 | */ | |
| 162 | export function withPlanLimits(guard: RunGuard, limits: PlanLimits | null | undefined): RunGuard { | |
| 163 | if (!limits) return guard; | |
| 164 | return { | |
| 165 | policy: { ...guard.policy, budgetUsd: lower(guard.policy.budgetUsd, limits.budgetUsd) }, | |
| 166 | minutes: lower(guard.minutes, limits.minutes) ?? guard.minutes, | |
| 167 | }; | |
| 168 | } |
This file's history is long; its oldest lines are credited to the oldest commit read.