Skip to content
250 linesCodeBlameRaw
1---
2title: Guardrails
3description: Which hosts a project's jobs, checks, merge queue and deploy builds may reach on g1t's machines, how long a run may take, and how each rule is enforced.
4---
5
6Guardrails decide what a project's work may do in g1t's sandboxes: which
7hosts a sandbox can reach, and how long a run may take. A workspace sets
8defaults, and each project can override them.
9
10They apply to every sandbox g1t starts for a project: its Actions jobs,
11its checks, its merge queue and its deploy builds. Jobs and deploy builds
12get the network list with what builds need added (see [builds](#builds)),
13and their own time limit. Merge checks are not covered; see
14[what is not covered](#what-is-not-covered). Every sandbox, whatever it
15runs, is watched for [mining](#abuse-and-mining).
16
17## Where to set them
18
19- **Workspace defaults**: the workspace's **Settings**, **Guardrails**.
20 Owners can change them; members can read them.
21- **A project's overrides**: the project's **Settings**, **Guardrails**.
22 People with the Admin [role](/guides/access-and-roles/) on
23 its repository can see and change them; the page is not shown to anyone
24 else.
25
26Every setting on a project's page starts as "As the workspace", which
27follows the workspace's default, whatever it is now. Choose a value to
28override it for that project only. Allowed domains and workflow-only
29domains add up: a project's are added to the workspace's, never
30instead of them.
31
32Changes apply to runs that start after you save. A run that is under way
33keeps the guardrails it started with.
34
35## Network
36
37With **Only allowed hosts** restricted (the default), a sandbox can reach:
38
39- g1t's own hosts, always: `g1t.sh`, `api.g1t.sh` and `mcp.g1t.sh`, for
40 cloning, pushing and reporting;
41- the package registries that are on (all of them by default):
42
43 | Registry | Hosts |
44 | --- | --- |
45 | npm and Yarn | `registry.npmjs.org`, `registry.yarnpkg.com`, `repo.yarnpkg.com` |
46 | PyPI | `pypi.org`, `files.pythonhosted.org` |
47 | crates.io and Rust toolchains | `crates.io`, `index.crates.io`, `static.crates.io`, `static.rust-lang.org` |
48 | Go module proxy | `proxy.golang.org`, `sum.golang.org` |
49 | GitHub downloads | `codeload.github.com`, `raw.githubusercontent.com`, `objects.githubusercontent.com` |
50
51- the domains you list: `api.stripe.com` allows exactly that host, and
52 `*.example.com` allows every subdomain of `example.com` (not
53 `example.com` itself; list both if you need both).
54
55`github.com` itself is not on the default list. A project with
56dependencies fetched with git from GitHub, rather than as archives, needs it
57listed.
58
59### How it is enforced
60
61This is enforced outside the sandbox, by Cloudflare Containers' outbound
62interception:
63
64- A restricted sandbox starts with no internet connection at all. Its DNS
65 resolves nothing on its own, and no protocol or port other than HTTP (80)
66 and HTTPS (443) has any route out: SSH, raw TCP and UDP connections fail.
67- Every HTTP and HTTPS request it makes is handed to g1t's runner Worker
68 before it leaves. The Worker forwards requests to allowed hosts and
69 answers every other with `403`. The refusal names the host three times
70 over, since tools differ in what they show of a failed request: in its
71 status line (`403 Forbidden by g1t guardrails: example.com is not an
72 allowed domain`, which is what a tool that prints only the status shows),
73 in an `x-g1t-blocked-host` header beside `x-g1t-guardrails: blocked`, and
74 in a plain-text body saying where to allow it: **Allowed domains** for
75 every sandbox, or **Workflow-only domains** for the jobs of one workflow
76 and environment.
77- To see the host of an HTTPS request, the connection is re-encrypted with
78 a certificate the sandbox is given when it starts, which g1t adds to the
79 sandbox's trusted certificates (and points Node.js, Python, curl, Cargo
80 and git at). A program that brings its own fixed list of certificates and
81 ignores the system's cannot connect anywhere, allowed or not.
82
83Nothing running in the sandbox, root included, can change this: the rule
84is applied where the sandbox's traffic leaves it, not inside it.
85
86Each refused host appears once as a step of the run, such as
87`Blocked: example.com (not an allowed domain)`. It is a note, not the
88run's state: the run carries on. If a run needs a host, allow it and run
89it again.
90
91Tools that send usage reports home are told not to in a sandbox with only
92allowed hosts (`DO_NOT_TRACK=1`, and each common tool's own switch, such
93as `WRANGLER_SEND_METRICS=false`), so those reports are not refused and
94noted on every run.
95
96Setting **Only allowed hosts** to Open gives that project's sandboxes the
97whole internet, as before guardrails.
98
99### Builds
100
101GitHub Actions jobs and deploy builds reach the project's list, plus what
102real builds need, which no setting removes:
103
104- GitHub, where `uses:` actions, `actions/checkout`'s helpers and the
105 setup actions' downloads come from: `github.com`, `api.github.com`,
106 `codeload.github.com`, `objects.githubusercontent.com`,
107 `raw.githubusercontent.com`, `release-assets.githubusercontent.com`,
108 `ghcr.io`;
109- toolchains: `nodejs.org`, `go.dev`, `dl.google.com`,
110 `static.rust-lang.org`, `sh.rustup.rs`;
111- every package registry above, whatever the project turned on, and
112 RubyGems, Packagist, NuGet, Maven Central, Gradle and
113 Debian's mirrors;
114- container registries, for a job's own Docker Engine: Docker Hub
115 (`registry-1.docker.io`, `auth.docker.io` and the CDNs its layers come
116 from), `mirror.gcr.io`, Quay (`quay.io` and its CDNs), and Docker's
117 package repository, `download.docker.com`;
118- for deploy builds, Cloudflare's API, which the build uploads its app to.
119
120The repository itself is cloned from g1t, which is always reachable. A
121project whose guardrails set **Only allowed hosts** to Open runs its jobs
122and builds with an open network too.
123
124The containers a job starts with [Docker](/guides/actions/#docker), its
125services and its build steps share the job's network, so this list is
126theirs too: an image from another registry, or a build step that
127downloads from another host, needs that host allowed, as a step would.
128
129### Workflow-only domains
130
131Some hosts only a workflow should reach: the API a deploy uploads to, a
132release server, a package registry you publish to. Listing them under
133allowed domains would open them to every sandbox as well. List them under
134**Workflow-only domains** instead, one per line:
135
136```
137api.cloudflare.com | deploy.yml | production
138uploads.example.com | release.yml, nightly.yml
139*.internal.example.com
140```
141
142| Part | |
143| --- | --- |
144| The domain | As for allowed domains: `example.com`, or `*.example.com` for its subdomains. |
145| Workflows | Workflow files by name, comma-separated, as they are in `.g1t/workflows/`. Left out: any workflow. |
146| Environments | The environments a job must name with `environment:`, comma-separated. Left out: any job. |
147
148A domain is reached only by:
149
150- jobs of the workflows and environments its line names;
151- in a run that is not of a pull request from a fork, which runs code
152 anyone could write.
153
154Checks, the merge queue and deploy builds never reach these hosts, whatever the line says. A job that names its environment with an
155expression (`environment: ${{ inputs.target }}`) matches only lines with
156no environments.
157
158Workflow-only domains are set by the same people as the rest of the page:
159owners for the workspace's, Admin for a project's. Each change
160is recorded in the workspace's [audit log](/guides/audit-log/) as
161`update_guardrails`, saying which domains were added or removed and what
162they were limited to.
163
164A deploy that signs in to AWS, Google Cloud or Azure with the job's
165[OIDC token](/guides/actions/#oidc-tokens), rather than a key kept in a
166secret, needs its cloud's token service listed here, such as
167`sts.us-east-1.amazonaws.com | deploy.yml | production`. See
168[reaching your cloud](/guides/actions/#reaching-your-cloud) for each
169cloud's hosts.
170
171### Brokered secrets
172
173The same interception keeps a workflow's API keys out of its jobs. A
174[brokered secret](/guides/secrets-and-variables/#brokered-secrets) names
175the hosts it is for, and a job is given a stand-in in place of its value.
176As a request to one of those hosts passes the runner Worker, the Worker
177puts the real value in place of the stand-in, in the request's headers
178(inside `Authorization: Basic` too) and its query string, and swaps it
179back should the answer echo it. A request to any other host goes with the
180stand-in, and the job's log notes it once. The Worker asks for a job's
181stand-ins with that job's own token and keeps them only while the job
182runs.
183
184Brokering does not widen the network: a secret's hosts must still be ones
185the job may reach. A job whose project's network is open, but which may be
186given a brokered secret, still sends its HTTP and HTTPS through the
187Worker, which reaches every host for it, and trusts the certificate as a
188restricted sandbox does; its other protocols go straight out, as before.
189Self-hosted runners' traffic does not pass through g1t, so a runner whose
190jobs run on Linux or macOS sends the requests that carry a stand-in to g1t
191itself, through a proxy it runs for the job, and g1t fills them in the same
192way; see
193[on a self-hosted runner](/guides/secrets-and-variables/#on-a-self-hosted-runner).
194On Windows, brokered secrets stay stand-ins.
195
196## Time per run
197
198How long each kind of run may take, in minutes. By default:
199
200| Kind of run | Minutes |
201| --- | --- |
202| Checks | 45 |
203| Merge queue | 45 |
204| Merge check | 10 |
205
206At most 240 minutes. A run that reaches its time cap fails, with
207"Stopped: it reached its time cap of 45 minutes." The sandbox is stopped
208whatever is running in it. Actions jobs keep their own limit: at most 60
209minutes on g1t's machines, or less with `timeout-minutes` (see
210[Actions](/guides/actions/)).
211
212## Abuse and mining
213
214g1t does not run cryptocurrency miners, on any plan. Mining needs a mining
215pool and hours of CPU; g1t's sandboxes withhold the first and watch for the
216second:
217
218- **No pool to reach.** No mining pool is on any allowed list, so a
219 restricted sandbox's miner has nowhere to send its work.
220- **Miners by name.** A check, a build command, a workflow step or a container a job starts whose image or
221 command names a known miner (`xmrig`, `cpuminer`, `t-rex` and others), a
222 pool address (`stratum+tcp://`) or a miner's flags (`--donate-level`,
223 `--algo=rx/0`) is refused, whatever the project's rules. A running process whose command line names one stops
224 the sandbox at once.
225- **The CPU signature.** Every sandbox samples itself every 30 seconds:
226 CPU use, file and disk I/O, network bytes, new processes, and whether the
227 run did anything (a new check command or workflow step). It is stopped when, for 10 minutes straight, CPU stays at
228 or above 90% (one dip allowed) while file and disk I/O average under
229 64 KB a second, the network under 16 KB a second, fewer than five new
230 processes start, and nothing else happens.
231
232 Compiling and testing are CPU-bound too, but they read sources, write
233 objects and start processes (a `cargo build` or `npm test` starts
234 hundreds), so they do not match. A compiler can spend minutes in code
235 generation with little I/O, so when the busiest process is a known
236 compiler or runtime (`rustc`, `cc1`, `clang`, `go`, `javac`, `node` and
237 others) the sandbox is not stopped for CPU alone.
238
239A sandbox stopped this way ends with "Stopped: unusual CPU use; contact
240support if this was a real job." A check or merge queue run fails with
241it, a workflow job fails with it, and a deployment's status says it. g1t's
242staff are told, with the measurements, and look at what ran. If it was a
243real job, write to hey@flagon.io and say which run.
244
245## What is not covered
246
247- **Merge checks** only merge two commits; they get no network list.
248- **Self-hosted runners** run on your machines, whose network g1t does not
249 see: the network list is not enforced there. See
250 [self-hosted runners](/guides/self-hosted-runners/#security).