machines: with the
provider that reaches it, and run captured programs there with the
machine runtime, whose machine names it. You create and stop the machine;
Mirage only runs programs on it. captures defaults to
@external, every program Mirage
does not have itself.
execute(machine=), a
machine on the shell request, or a policy’s Route(machine=).
A program there opens workspace files at the same paths, so the machine
must see the mounts. docker, e2b, ssh, smolvm, microsandbox, and
apple_container pick how with mount_type: ssh serves them from the
workspace, fuse from a Mirage inside the machine, and both mixes the two.
Daytona uses a Mirage inside.
Sandlock is a runtime, not a machine:
it runs programs on this Linux host, confined, with a
FUSE folder you grant.
After following a provider page’s Connecting the workspace steps, run the
shared workspace file check
to confirm reads and writes cross the runtime boundary.
Language compatibility
Python modules, file modes and other language APIs come from the interpreter installed on the machine. Mirage forwards the captured program’s arguments, input, environment and working directory; a working directory the machine lacks fails the program with exit 126. Each run also getsMIRAGE_PROCESS, the id of its Mirage process (w1:9), which every process
it starts inherits. Each provider’s Runtime behavior table describes
that boundary.
File operations reach workspace mounts through the connection configured
for that provider. They also remain subject to the machine’s own
permissions and confinement.
Processes and signals
ps lists a program on a machine with the machine and its pid there, and
everything the program started as processes of their own, found by a scan
of the machine’s /proc for its MIRAGE_PROCESS:
ps -o machine,mpid selects those columns, and ps f or ps --forest
draws each command under its parent’s. A process a scan found leaves the
list once a scan no longer sees it.
kill sends a signal to a program on a machine as you sent it: a program
that traps USR1 gets it and runs on, and one that TERM ends exits with
its own status, which wait reports. KILL is sent only when you ask for it
(kill -9, timeout -k) or when Mirage shuts the workspace down. Mirage’s
own stops, a head that has read enough, a line’s timeout, a cancelled
line, send TERM, then KILL a second later, to every process on the machine
that carries the run’s MIRAGE_PROCESS.
In a Mirage shell a pid is Mirage’s: they start at 4194305, past any
machine’s own. A smaller number given to kill, kill -0, wait or
ps -p is a machine pid, the process whose program has that pid on its
machine; one that two machines both have is refused as an ambiguous job
spec. Inside a program on a machine a pid is that machine’s, and a line
sent whole to a machine (@line) runs in that machine’s shell, with its
pids. Every one of these follows the session’s processes grants.
Machine states
Each check finds a machine in one of three states:GET /v1/workspaces/{id}/machines checks every machine and lists the host
first; GET /v1/workspaces/{id}/machines/{machine} checks one and lists its
processes. mirage workspace list-machines prints the same table.
The machine image
Every machine needs a POSIX shell at/bin/sh, which starts each command,
and grep, which finds what a run cut short left running. With
libfaketime in the image, programs
see the workspace’s system_time;
without it they see the machine’s clock.
With mount_type: ssh the machine also needs sshfs.
A machine that serves the mounts with its own Mirage needs fuse3 and
Mirage. The repository’s Dockerfile builds that image from the current
checkout, with every mountable backend:
MIRAGE_EXTRAS:
container, Microsandbox or smolvm, or use it as a Daytona image or an E2B template base.
Add the programs your captures need, such as Node.js for node. The Mirage
inside is the Python build, whichever SDK the host uses.
Timeouts
command_limits apply to a program on a machine as to any command: a line past
its @line entry’s timeout_seconds exits 124, and max_bytes and
max_lines cap the program’s output.
Serving session files
Withmount_type: ssh, workspace file access follows the session’s permissions
and policies. You do not need to expose a public file server or copy service
credentials into the machine. Each machine is assigned to one session.
Mirage refuses to run a program when it cannot enforce the session’s file
restrictions. Unsupported cases include:
- Restrictions on
/or/dev. - Hiding a mount when doing so would expose the machine’s own files underneath.
- Restrictions on mounts served by a separate Mirage inside the machine.
- File rules that depend on which program opens a file.