ctx a coded policy
reads, as JSON, and prints its answer. Three places take a script:
A profile’s policy
workspace.yaml
guard.py
{name, config}
when the runtime needs settings, as in a runtimes entry. A method’s
programs are asked in order, up to the first deny, and each answer counts
as if a policy of its own gave it
(when answers disagree):
an ask from one program and a route from another both hold. A method with
no program is never asked and costs nothing.
In code, a profile takes the same block, with a ScriptSource for each
program:
The program
A program runs the way any program runs on its runtime. Mirage never edits it:- Input:
ctxas JSON, in the environment variableMIRAGE_POLICY_CTXand on stdin. On monty, which has nosys.stdin, stdin arrives as astdinvariable, so read the environment variable to run anywhere.MIRAGE_POLICY_CTXis reserved, and the session never sees it. It is the only variable Mirage passes the program: the session’s variables stay out of its environment. A runtime may add its own, as wasi addsPYTHONHOME,PYTHONPATHandPYTHONDONTWRITEBYTECODE. - Session: the program starts in the session’s working directory, so
os.getcwd()is the session’s. The session’s variables are inctx["env"], not inos.environ. Animportnever loads a module from the session’s directory. - Answer: printed on stdout. Nothing, or
null, is no opinion.
A deny or an ask without a
reason gets the default one. Anything else on
stdout, such as a debug line, fails the program; write those to stderr.
ctx
Every field a coded policy reads, under the Python names, as plain data. Forcat notes.txt | wc -l in /data, pre_execute gets:
pre_command gets one entry of commands, with the session fields beside
it:
Every
ctx also has session_id, cwd, env, profile and mounts,
the mount roots the session can see. A runtime’s script: also gets
runtime: its name and captures.
Files and the session
A program reads the workspace as the session it judges for:open(),os.listdir()andos.stat()go through the workspace. A hidden path does not exist, path rules apply, and a write is refused (EROFS).- Its own reads are not judged again by its profile’s
pre_vfs. - Monty has no
os.path,os.walkorPath.glob; usePath.exists(),Path.is_dir()andPath.iterdir(), which run on every runtime.
When a program fails
A program that exits non-zero, runs past 10 seconds, prints anything but an answer its method can give, or names a runtime that cannot run here refuses the action. The reason names the profile and what went wrong, such asprofile 'reviewer' policy exited 1, and the program’s stderr goes to
the log. Silence on failure would let through exactly what the policy is
there to judge.
route_policy: and runtime scripts are deployment settings, so the same
mistakes fail the line with a routing error instead.
Runtimes
Each runtime is the policy’s own, built from the name and settings the
profile gives and never shared with the agent.
wasi needs a CPython WASI
build: its folder as config: {home: ...}, or in MIRAGE_WASI_HOME.
Monty runs a program in about a millisecond. wasi starts CPython on every
run, 100 to 300 ms, so it suits the methods asked less often; pre_vfs,
asked for every file call from outside a line, is usually monty’s.