Commit Graph
521 Commits
Author SHA1 Message Date
Rohit C Prasad 4f512b77bd Sandbox settings v6: allowed-sites tick list, three-row OpenShell setup
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.
2026-09-28 16:45:49 -07:00
Rohit C Prasad 6b7cae8d5f Sandbox settings v5: one-button setup, two network choices, CLI login presets
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.
2026-09-28 15:57:29 -07:00
Rohit Prasad 339de1a66d Merge pull request #700 from andrewyng/sandboxing-windows
Sandboxing improvements for Windows and Mac
2026-09-28 11:10:36 -07:00
Rohit C Prasad ff54ceaf73 Merge main: OpenShell guided setup (openworker#699) into the Sandbox page
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>
2026-09-28 10:30:41 -07:00
Rohit Prasad a6bcd10abb Merge pull request #699 from andrewyng/issue/ope-205-openshell-sandbox-setup
feat(sandbox): guided OpenShell setup, readiness checks, switching for open sessions (OPE-205, OPE-206, OPE-207, OPE-208, OPE-209)
2026-09-28 10:25:15 -07:00
Rohit C Prasad e84e879e6e Settings: OpenShell is not available on Windows yet; setup test reads the status header 2026-09-28 09:34:16 -07:00
Rohit C Prasad ef9b0a412d Windows setup test: judge the Windows status rows only; check the setup info 2026-09-28 09:30:57 -07:00
Rohit C Prasad f0cc63023c Settings ▸ Sandbox: one switch, then the type, then its options; the Windows setup dialog
Setup and remove routes prove the wall in a throwaway sandbox before the choice takes effect.
Credential entries are a file or a folder, labelled credential or configuration; collapsible cards.
2026-09-28 08:53:33 -07:00
Devika Verma b828796d4a Test: the private-folder check compares against the system temp dir, not the "/tmp" prefix
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.
2026-09-28 15:51:15 +05:30
Devika Verma fc357b1fde Settings > Sandbox: the setting applies to every session, both ways (wording after ISSUE 10)
Since 3ca3a67 a provider change rebuilds live sessions in both directions:
switching off closes the sandboxes of idle sessions and rebuilds them
direct; switching on rebuilds direct sessions behind a wall, or refuses
them. The header said "a running session keeps what it started with",
which was true before 3ca3a67 only. Now: "one in the middle of a turn
switches when the turn ends".
2026-09-28 15:02:25 +05:30
Devika Verma c969adb34f Sandbox: a provider change rebuilds live sessions built under the old rule (ISSUE 10)
Seen 2026-09-28 on WSL: the UI reconnected three sessions 12 s before the
user turned the sandbox on, so their engines were built direct; after the
switch the page said "sessions are refused" while those sessions kept
running commands on the host with the user's full access.

- `SessionManager.apply_sandbox_setting()`: every live engine whose
  workspace provider differs from the one a new engine would get is
  dropped (its sandbox closed) so the next connection rebuilds it under
  the new rule, and is refused if that rule cannot be met; a running turn
  is marked stale and rebuilt when it ends (`_refresh_session_tools`).
- `POST /v1/settings/sandbox` calls it when `provider` is in the body and
  returns `rebuilt_sessions`.
- The app: SettingsView reports them (`onSandboxProviderChanged`); App
  bumps `connectNonce` when the session on screen is among them, so its
  socket reconnects and the server rebuilds (or refuses) it at once.
2026-09-28 13:32:47 +05:30
Devika Verma 9633b2bb68 Settings > Sandbox: say the setting applies to new sessions, and that sub-settings are kept while off (ISSUE 8, 9)
From the fresh-user run: after switching off, two sandboxes stayed Ready
(the sessions that started with them keep them until closed; the new
session ran direct) while the header said "every session"; and the ssh
credential grant stayed in config.toml, invisible on the page. Both are by
design; the words now say so.
2026-09-28 13:05:58 +05:30
Devika Verma d0dcdd0053 Settings > Sandbox: credentials card shows its expand marker; the editor opens inside it (ISSUE 7)
Seen in the fresh-user run: the credentials card had no expand marker (its
summary is a flex row for the Add link, which drops the browser's marker),
the editor rendered below the "stored in" line, and the Path field showed
"~/" instead of its example. Now: a drawn marker that turns when open, the
editor inside the card (opening it also opens the card), and an empty path
for a new entry so the ~/.npmrc example shows.
2026-09-28 12:55:02 +05:30
Rohit C Prasad 388caf998e Windows sandbox: one mode only; traverse entries on the way to a granted folder
The same-user fallback is gone: without setup the provider refuses and Settings say why (ruling 18).
A shell could not enter a granted folder under the profile; the parents now get a traverse-only entry.
The entry check matches by SID, so it works for a real account too.
2026-09-27 22:38:07 -07:00
Devika Verma 9a7cc2bcea Settings > Sandbox: the app installs OpenShell itself where it can; one command where it cannot (OPE-207)
From a fresh-user run on WSL (2026-09-27): "Set up sandbox" handed over two
commands, gave no install instructions, and put a Copy button on notes
("found none") and file paths.

- steps carry `command` (run in a terminal, gets Copy) apart from `hint`
  (a note) and `docs` (a Guide link). `checks()` prints command or hint.
- `admin_prefix()`: `sudo -n` when this user may sudo without a password,
  else `pkexec` (the desktop's own password prompt) when there is a display
  and this is not WSL. The app never sees or holds a password.
- `install_openshell()`: NVIDIA's installer as the user on a Mac; on Linux
  under the admin prefix with `loginctl enable-linger` FIRST in the same
  run, because the installer starts the gateway through the user's systemd
  manager, which on WSL does not run until linger is on (it otherwise
  prints "could not reach the user systemd manager" and exits 0 without
  registering the gateway). The job streams its output as progress and it
  can be cancelled.
- No prefix (WSL): the openshell row hands over ONE command, linger + the
  installer, and the job stops until "Check again".
- `enable_linger()` tries the user, then the admin prefix, then hands over.
- Terminal `setup`: linger (sudo) before the installer; Guide URL printed.
- Page: "Run this in a terminal on this machine:" above a command; notes
  plain, no Copy; Guide links; install progress row; a fixable row shows
  its command only once the app could not do it.
- Wording: switch-off text says what it means ("directly on this machine,
  with the same access as your user account"); "stored in <path>" only
  while the switch is on; the credential editor explains itself with an
  npm example and placeholders; "needs download" hint points at the
  button, not a terminal command.
2026-09-27 23:59:06 +05:30
Devika Verma 126e210cec Settings > Sandbox: one switch, a readiness checklist, collapsible sub-settings, and a guided "Set up sandbox" (OPE-207)
The page listed "No sandbox", "macOS sandbox" and "OpenShell" as three equal radio
buttons (with "ready" next to no-sandbox, and "on this Mac" on every OS), and always
showed the network allow list and shared credentials even when they applied to nothing.
Choosing OpenShell did not say what the machine still needed; the user found out when a
session was refused.

Now:
- One switch, "Run agents in a sandbox". Off removes `sandbox_provider` from
  config.toml (it used to write "direct", which also disabled a headless machine's
  automatic-OpenShell rule); on picks Seatbelt on a Mac, OpenShell elsewhere, with a
  dropdown when both exist. On Windows the switch is disabled with the WSL hint.
- Under the switch, for OpenShell: a readiness checklist, the same rows `openworker
  machine sandbox status` prints, now with keys and whether the app may fix each one
  itself, plus two new rows: free disk space for the image (about 10 GB) and Landlock in
  the kernel (OpenShell refuses to start a sandbox without it). Each missing row shows
  the command to run, with Copy.
- "Set up sandbox" runs `SetupJob` on the machine's server: it fixes what the app may
  (bind-mount config and gateway restart, the config line, linger when no administrator
  is needed, the image download with per-layer progress and Cancel) and stops at a step
  that needs an administrator or an installer, showing the command; "Check again"
  continues. It never runs anything as root and never turns the sandbox off. A desktop
  notification says when the download is done.
- Network allow list and shared credentials are collapsible and shown only while the
  switch is on.

`setup_cmd` is refactored into `steps()` (rows with keys and fixability) and one
function per fix, used by both the terminal `setup` and the job, so there is one list
of checks. New endpoints: GET /v1/settings/sandbox/readiness, GET/POST
/v1/settings/sandbox/setup, POST /v1/settings/sandbox/setup/cancel.
2026-09-27 14:34:18 +05:30
Devika Verma 0bb74aae24 OpenShell: keep a session's private folder under the state dir, not /tmp (OPE-208)
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.
2026-09-27 14:26:14 +05:30
Devika Verma cd839c08ba Trim the sandbox-delete log line to one INFO line 2026-09-27 14:11:31 +05:30
Devika Verma f305c86eec Preparing-sandbox row: do not gate on connected (stale true across a session switch)
The DOM observer in the browser saw sandbox_preparing arrive on the socket but no row: after switching sessions, connected stays true from the previous socket until the new one's ready, so the !connected guard hid the row. preparingSandbox alone is the condition; ready clears it.
2026-09-27 14:08:11 +05:30
Devika Verma 0a5616da0d reap(): read ownership after listing the gateway's sandboxes, not before
A name reserved and created while 'openshell sandbox list' ran was not in the rows read earlier, so reap() took it for an orphan and deleted it mid-provisioning.
2026-09-27 14:06:37 +05:30
Devika Verma 63bc085683 Log sandbox deletions (reap and provider) and failed creates, with the caller
Diagnostic for a create that dies within a second inside the server only.
2026-09-27 14:03:18 +05:30
Devika Verma e1957477f7 Reserve a sandbox's registry row before creating it, so a concurrent build's reap() cannot delete it mid-provisioning
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.
2026-09-27 13:58:17 +05:30
Devika Verma e21a6b61b2 Preparing-sandbox row: show it on a brand-new session, and add no transcript item on sandbox_ready
The waiting row for a sandbox build lived in the transcript branch, but a new session
has no items and renders the intro screen instead, so the row never showed where it
mattered most. `idle` is now false while a sandbox is being built.

The `sandbox_ready` transcript notice is dropped: one item made a fresh session
non-idle and hid its intro screen for every sandboxed session. Which wall a session
runs behind belongs in the header (OPE-207).
2026-09-27 13:52:50 +05:30
Devika Verma ab4d6dda77 Sandbox refusal: no reconnect loop; image check follows the driver (docker or podman) and stays out of remote gateways
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.
2026-09-26 21:54:54 +05:30
Devika Verma 5e16e26b1d Session socket: build the engine (and its sandbox) off the event loop, and say so (OPE-206)
Connecting a session's socket built its engine on the event loop. With OpenShell that
build creates a container, starts the runner and verifies the mounts: seconds normally,
minutes on first use. While it ran the server answered nothing, the GUI's health checks
failed, and the app fell back to its startup screen ("Starting OpenWorker...") instead of
showing the session. A build that raised (a refused sandbox, a timeout) died in the ASGI
stack and the socket just dropped.

Now the socket handler asks `pending_sandbox_build()` (config only, no preflight) whether
this connect will build a sandbox, sends `sandbox_preparing` if so, runs `get_engine` on
a worker thread, then sends `sandbox_ready` with the workspace's description, or an
`error` event with the reason and a clean close. Engine builds are serialized per session
with a lock, since two connects could now build concurrently and with OpenShell each
build is a container.

The GUI renders the two events: a waiting row "Preparing the openshell sandbox for this
session..." until `ready`, and one quiet transcript line naming the wall once it is up.
A refusal lands in the session view as the usual error notice.
2026-09-26 17:17:12 +05:30
Devika Verma 80c72eb580 OpenShell: check for the base image up front instead of hanging the first session on its download (OPE-205)
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.
2026-09-26 17:12:05 +05:30
Rohit C Prasad 9f1696fa59 Windows sandbox: reap stale private folders; remove really removes the firewall rule
A server killed hard left its owr-* folder behind; the next full-mode start removes folders whose pipe is dead.
The rule name carried a comma the remove script split on; renamed, and old rules go by wildcard.
2026-09-25 16:28:52 -07:00
Rohit C Prasad b855717875 sandbox status: say when the machine already uses the Windows sandbox 2026-09-25 13:03:00 -07:00
Rohit C Prasad 6269eb1938 Settings ▸ Sandbox: Windows wording (this PC; network open or by the allow list) 2026-09-25 13:02:31 -07:00
Rohit C Prasad b5571573b6 Sandbox: the developer-tool folders a sandbox may read, with switches in Settings
One list per platform (coworker/sandbox/toolchains.py), machine-level, editable by name; read entries on Windows,
the Seatbelt profile on the Mac. The Windows full mode passes its environment through a file (1024-character logon limit).
2026-09-25 12:43:58 -07:00
Rohit C Prasad 50177eff67 Docs: the Windows sandbox
How it is built, the two network modes, what the user chooses, and the limits.
2026-09-25 10:54:17 -07:00
Rohit C Prasad 666363179a Windows sandbox: two accounts, loopback filters, and remove on the CLI
Setup creates OWSandboxOpenNet (no rules) and OWSandboxClosedNet (outbound blocked, loopback closed
except the proxy's port range by WFP filters); the network profile picks the account.
The provider proves the loopback wall from inside before a session starts.
2026-09-25 10:54:17 -07:00
Rohit C Prasad 8e29525970 Network profile "open" on every sandbox provider; the default on Windows
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.
2026-09-25 10:54:17 -07:00
Rohit C Prasad c8db7b9a34 Docs: the macOS sandbox, with the README and config example pointing at it 2026-09-24 21:51:51 -07:00
Rohit Prasad 5870585321 Merge pull request #685 from andrewyng/docs/openshell-readme
Add docs for OpenShell support
2026-09-24 16:17:39 -07:00
Rohit C Prasad de8ce3dd5f Docs: OpenShell sandboxes, a README tier and bullet, and the config example
(cherry picked from commit d77d1d8ec1)
2026-09-24 18:04:27 -05:00
Devika Verma 3d4fdfbead Merge pull request #684 from andrewyng/sandboxing-open-shell
Add support for Sandboxing using NVIDIA OpenShell
2026-09-25 04:21:58 +05:30
Rohit C Prasad 1b899acf65 Windows sandbox: credential grants in the account mode; Settings names the provider
Copies go into the account's own profile through the daemon, so the account owns them; the runner's new `connect` command is ssh's ProxyCommand where there is no nc; a graceful shutdown removes them.
The same-user mode keeps the file-and-variable grants and tells the agent the ssh key needs the full sandbox.
2026-09-21 23:07:45 -07:00
Rohit C Prasad 1a11109721 Windows sandbox, full mode: a hidden local account runs the daemon
`sandbox setup` (one administrator prompt) creates the account, hides it, denies remote and network logon, blocks its outbound network by firewall rule and stores its password for the user only.
The daemon is logged on as that account on its own desktop with entries on the session's folders; the profile is out of reach; the internet is reached only through the allow-list proxy.
2026-09-21 22:20:28 -07:00
Rohit C Prasad 750ae3489b Windows sandbox provider, same-user mode: writes limited by a write-restricted token
One made-up session SID restricts the daemon's token and gets a Modify entry on the session's folders; entries move without a restart and go at close.
Reads and the network are not limited in this mode and describe() says so; the full mode with a hidden account follows.
2026-09-21 22:06:15 -07:00
Rohit C Prasad 42f71f8abd Tool runner on Windows: the daemon listens on a named pipe
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.
2026-09-21 21:51:26 -07:00
Devika Verma 37a09360d1 Sandbox lifetime: a dropped engine closes its sandbox; shutdown closes all; orphans reaped at start 2026-09-21 20:56:08 -07:00
Devika Verma 5ce2a18a92 Packaged app: the sidecar runs as the tool runner, and ships the runner sources
openworker-server sandbox-runner serve|attach loads only the runner package. The spec ships the runner and toolkit sources as data, so the zipapp can be packed from the frozen build.
2026-09-21 20:50:18 -07:00
Devika Verma 7792a417f6 Credential grants: the ssh wrapper lives in the copied home, so OpenShell carries it in
The runner daemon puts that folder first on PATH. Live OpenShell test for grants added; passes on the Linux VM.
2026-09-21 20:40:12 -07:00
Devika Verma 48fecdf4ca Settings: a Sandbox page for the provider, the network allow list and shared credentials
Machine-level, read and written through /v1/settings/sandbox into the machine's config.toml.
Adds the sandbox_network_profile setting; strings in English and Chinese.
2026-09-21 19:54:44 -07:00
Devika Verma f1d3711d78 Sandbox: a failed creation removes its folder, so no copied credential is left behind 2026-09-21 19:15:40 -07:00
Devika Verma c9bbe009a1 Sandbox credential grants: chosen home files copied into the sandbox
A machine-level list (ssh, gh, aws, kube to start); enabled entries are copied into the sandbox's private home and their hosts join the allow list.
ssh and git are pointed at the copy, and ssh tunnels through the proxy; the agent is told what it was given.
2026-09-21 19:14:30 -07:00
Devika Verma cc2b921b18 Merge pull request #679 from andrewyng/rp/team-view-review
Add Team View and harden agent-team coordination
2026-09-22 06:53:31 +05:30
Rohit C Prasad b9a30e7978 Prevent resolved approvals from reappearing after delayed updates
Remember resolved calls across delayed Inbox responses and gate events without hiding newer requests.
2026-09-21 15:26:59 -07:00
Rohit C Prasad 81a01ff901 Reconcile ordinary approval cards by exact tool call identity
Carry exact call identities through approval events and reconcile cards on completion or resolved Inbox records.
2026-09-21 13:11:29 -07:00