Skip to content

Blog

Every job in its own virtual machine

Every job on runners.io runs in its own virtual machine, started fresh from our image and shared with no other job. When the job ends, the machine is destroyed, or rebuilt from the image, and a rebuild erases its disk, memory and firmware state. That is the whole of it, and this post is about what it rules out, what it leaves you with, and what it deliberately does not claim.

What a machine per job rules out

Nothing a job leaves on its machine reaches the next job. A runner that is reused between jobs as it was left keeps whatever the last job left on it: a toolchain a step modified, a credential a step wrote to disk, a half-finished file a later build trips over. None of that can happen here, because a machine is either destroyed or rebuilt from our image before anything else runs on it, and the rebuild erases its disk, memory and firmware state.

Each job also gets its own single-use runner, registered on your repository for that one job. There is no long-lived runner process that picks up whichever job comes next.

Root inside, rules outside

Inside its machine a job has root, through passwordless sudo, as it does on GitHub’s own runners. We did not take that away.

So the thing that keeps a job apart from every other job cannot be inside its machine. The rules that do it are applied outside, where nothing the job does can change them. The job can do whatever it likes to its own machine, and the machine is then destroyed.

The network

Nothing on the internet, and no other job, can open a connection to a running job. Its machine accepts no inbound connection from either, and only the replies to connections the job itself opened come back in. A job can reach the internet: package registries, container registries, git remotes and your own APIs need no allowlist on our side.

A terminal into a running job, if an owner or admin has switched it on, is opened from the inside. The job’s machine dials out to our relay and the terminal rides that connection, so it adds no way in.

We do not claim more than that about the network. In particular, this is not a promise that your jobs leave from an address of their own. The security page says what we do and do not promise about it.

What outlasts a job, because you asked

The only things that outlast a job are the ones you keep on purpose: entries in the Actions cache, layers in the Docker layer cache, and a sticky disk if you have switched sticky disks on. They are reached with a credential issued to the job’s machine. It names your GitHub account and repository by their GitHub ids, and it expires. Which repository’s entries a job reads and writes is decided by that credential, never by what the workflow asks for, so a job cannot reach another repository’s entries, or another account’s. The cache post has the rest of that.

What passes through our hands

While a job runs, the code it checks out and the secrets GitHub hands its runner are on a machine we operate, as they are on any runner you do not host yourself. When the job ends, the machine is destroyed. We keep a copy of each job’s log, and its page shows it for 90 days, the period GitHub keeps Actions logs for by default. The job’s timings and minutes stay after that, because your bill is worked out from them.

What this is not

It is not an audit. We have not published a third-party audit or certification report, and this post is not a substitute for one. If you have found a problem, or have a security question, the address is on the support page. The full description of the model, kept in step with the product, is in the documentation.

Run your CI and your infrastructure on one bill

Connect GitHub

Card required. You pay only for the minutes your jobs run.