With it off, OpenShell reads as not usable, the page offers Set up, and the dialog's Docker row says where the setting is.
A yes is remembered for ten minutes; a no is asked again each time.
0.1 reaches its gateway from a host-network container, which Docker Desktop allows only with that setting.
A sandbox that cannot start for this reason says so in plain words.
"This session" and "Always allow" now reach the session's commands at once.
OpenShell: the policy is rendered again and set on the sandbox; macOS and Windows: the session's own proxy takes the host.
Each sandbox carries its registry's id; a second OpenWorker (test server, one-shot run) no longer deletes live sandboxes.
The live session test ticks the site it expects, since nothing is allowed by default.
A throwaway container asks the kernel; without Landlock the Docker row says update Docker Desktop.
A sandbox that exits at start on such a Mac gets the same message instead of ContainerExited.
Network allow list holds only the machine's ticked sites, none by default; strict/standard removed.
The app no longer installs OpenShell; setup is two checks and one step with progress.
DMG build requires grpcio so the sidecar can use OpenShell.
Network: registries and search (strict folded in) with the machine's own hosts, or allow everything.
Credentials list only what was added; shipped entries become presets with the variable each tool reads.
A hung docker info no longer fails the OpenShell checklist.
The OpenShell checklist and setup job show under the OpenShell type; the Windows setup keeps its own routes.
Co-Authored-By: Devika Verma <devikaverma11@gmail.com>
CI's pytest puts its base temp under /tmp, so the state dir under test was
under /tmp too and `assert not str(private).startswith("/tmp")` failed
there while passing locally with --basetemp outside /tmp. The point of the
check is that the folder is no longer created in tempfile.gettempdir()
itself (OPE-208); assert that instead.
Copied credentials (and the policy file) went into tempfile.mkdtemp() under /tmp and
were bind-mounted into the sandbox. NVIDIA's installer runs the gateway as a systemd
user service with PrivateTmp=true, so the gateway has its own empty /tmp: the mount
source "does not exist" for it and every session with a shared credential failed to
create. Verified through /proc/<gateway pid>/mountinfo and /proc/<pid>/root/tmp.
The folder is now `<state dir>/sandbox-runtime/ow-openshell-<pid>-<random>/`: on the
real filesystem, owner-only, and a SIBLING of `sandbox/`, never a child, because
`sandbox/` is mounted read-only into every sandbox for the runner and copied keys must
not be readable from another session's sandbox. The server pid in the name lets the
registry's reap sweep the folders of a dead server, which /tmp used to do on its own.
Engine builds run concurrently since OPE-206 (worker threads instead of the event loop).
Every build starts with SandboxRegistry.reap(), which deletes any OpenShell sandbox
carrying our label that no live server owns per the registry. A sandbox was only
recorded after it was connected and verified, so for its first seconds it looked like an
orphan: while one session's sandbox was provisioning, another session's build reaped
it. Seen in the GUI as `openshell sandbox create` failing with "The operation was
cancelled: stream closed", Docker showing create -> start -> kill -> destroy within a
second, and three DeleteSandbox calls after every CreateSandbox.
RunnerWorkspace now records the name with state "creating" before provider.create()
(and before the replacement sandbox in regrant, via a before_create hook on both
providers), removes the row if the create fails, and marks it "ready" once connected.
reap() already treats every row of a live pid as owned, so nothing else changes.
Review of OPE-205/OPE-206 found three gaps:
- The client reconnects with backoff on ANY socket close, so a session refused for a
missing image would be retried every few seconds, adding an error notice each time
and showing the "reconnecting" strip forever. The server now closes a refused session
with code 4403; the client treats that as final (no reconnect, no strip) and the
error notice in the transcript says why.
- The image check only knew Docker, while docs promise Docker or Podman. It now maps the
gateway's driver to its own tool (`docker`/`podman image inspect`, `... pull`), and
the refusal and the setup hint name that tool.
- A local image store says nothing about a remote gateway's images: when the active
gateway is remote, the check answers "cannot tell" and never refuses.
On first use of the OpenShell sandbox, `openshell sandbox create` pulls the pinned base
image (about 5 GB). OpenWorker waited for that create with a 600 s timeout, inside the
session-start request; on a slow link the pull outlived it, the session failed with
`TimeoutExpired`, the UI showed "Starting OpenWorker..." and retried, and nothing told
the user a one-time download was the cause. Settings > Sandbox said "ready" throughout.
Now the image is part of the readiness check, keyed on the gateway's compute driver
(`openshell gateway info`), not the operating system, since the same image serves
Linux, WSL and macOS and only the Docker driver can be asked:
- `preflight()` raises `OpenShellImageMissing` (an `OpenShellUnavailable`) with the
`docker pull` command when the driver is Docker and the image is absent, so a session
is refused in a second with a message that says what to do.
- Settings > Sandbox shows OpenShell as "needs download" with a hint, and keeps it
selectable; `state` joins each provider row of /v1/settings/sandbox.
- `openworker machine sandbox status` gets a row for the image; `setup` offers the pull
last, with Docker's own progress and no time limit, on macOS too.
Any host, no proxy; the files stay confined. Strict remains the default elsewhere.
Settings offers it as a third choice; credential rows hide their hosts when it is on.
The pipe's security descriptor admits only the accounts the daemon is given; the runner and shell tests run on Windows.
The registry's liveness probe no longer uses os.kill(pid, 0), which terminates a process on Windows.
Folders are bind-mounted at their real paths; the runner is a read-only mount and the main command.
The policy is rendered from the session's roots, with the owner's uid and Landlock as a hard requirement.
The runner's pipe is the gateway's gRPC exec stream; the registry caps and cleans up sandboxes.