.. program:: jetstream server

Advanced Sandboxing
###################

For more advanced control, additional sandbox paths may be specified using the API. The API functions to manipulate sandboxes are:

  * :meth:`~jetstream.serverinterface.ServerInterface.setSandboxMapping`
  * :meth:`~jetstream.serverinterface.ServerInterface.getSandboxMappings`
  * :meth:`~jetstream.serverinterface.ServerInterface.deleteSandboxMapping`

The server stores sandbox configuration as a mapping from *username* to `sandbox mapping`. A `sandbox mapping` is defined as a mapping from `sandbox name` to a `sandbox specification`. A `sandbox specification` can be either a simple filesystem path, or map specifying a sandbox type.

A sandbox with blank name (``""``) appears to the users as root (``/``) or the topmost level they can navigate to. There can only be one sandbox with blank name per user.

.. note::
  Changing sandbox mappings using the :meth:`~jetstream.serverinterface.ServerInterface.setSandboxMapping` or :meth:`~jetstream.serverinterface.ServerInterface.deleteSandboxMapping` API functions does not affect logged on users. Changes will take effect the next time a user authenticates (see :meth:`~jetstream.serverinterface.ServerInterface.auth`).

If a persistent state directory has been specified, then sandbox mappings created using the API will be saved and loaded across server restarts. However, if there is a conflict between a persisted sandbox configuration and the :option:`--sandbox-dir` command line option (a sandbox mapping with blank username was set), the command line option will take effect and an error will printed to the log.

.. tip::

  When the server is started with :option:`--persistent-state-dir`, the sandbox mappings will be persisted across server restarts.


There are three kinds of sandboxes:

.. glossary::

  :index:`global sandbox <triple: sandboxing; sandbox; global>`
    Global sandboxes are specified with blank username (``""``) and apply to all users.

    Paths specified in global sandboxes can use :ref:`placeholders <sandboxing-file-placeholders>`.

  :index:`system sandbox <triple: sandboxing; sandbox; system>`
    System sandbox is a special version of `global sandbox` and is specified with a blank username (``""``) and blank sandbox name (``""``).

    .. note::

      If the :option:`--sandbox-dir` command line option is specified, the `system sandbox` can not be modified. To set the `system sandbox` using the API, the :option:`--sandbox-dir` command line option has to be removed.


    .. warning::

      Specifying the :option:`--sandbox-dir` on command line will take precendence over a persisted `system sandbox` configuration, and any existing `system sandbox` configuration will be deleted.

    Paths specified in system sandboxes can use :ref:`placeholders <sandboxing-file-placeholders>`.

  :index:`user sandbox <triple: sandboxing; sandbox; user>`
    User sandboxes are attached to specific usernames, and override any other sandbox specification.

    .. warning::

      Setting the sandbox mapping for a specific user to ``false`` turns off sandboxing for that user. This allows for turning off sandboxing for selected users (for example administrators) and giving them full system access, while sandboxing everyone else.

.. seealso::
  - :doc:`/using_jetstream/where_do_transfers_go`
  - :option:`--sandbox-dir`
  - :option:`--persistent-state-dir`
  - :doc:`/sandboxing/types/index`


Examples
========

Global And System Sandboxes
---------------------------

Starting the server with :option:`--sandbox-dir` set to ``/home/%u`` will result in a sandbox mapping (:meth:`~jetstream.serverinterface.ServerInterface.getSandboxMappings`):

.. code-block:: javascript

  {"": {"": "/home/%u"}}

This will sandbox all users into their individual home directories. If we then update the sandbox mapping adding a ``data`` sandbox:

.. code-block:: python

    > api.server.setSandboxMapping("", {"data": "/data"})

We now have sandbox mapping of:

.. code-block:: javascript

  {
    "": {
      "": "/home/%u",
      "data": "/data"
    }
  }

At this point, all users would have access to a second sandbox named ``data:/``, mapped to the ``/data`` partition. Users would now observe:

  * ``userA``:

    * ``/`` mapped to ``/home/%u`` (resolving to ``/home/userA``)
    * ``data:/`` mapped to ``/data``

  * ``userB``:

    * ``/`` mapped to ``/home/%u`` (resolving to ``/home/userB``)
    * ``data:/`` mapped to ``/data``

Continuing the above example, let's assume the server above also had the :option:`--persistent-state-dir` option set to retain sandbox mapping between server restarts. If we now restarted the server without :option:`--sandbox-dir` specified, users would only get the ``data:/`` sandbox mapping.


User Sandboxes
--------------

Let's assume we have a server running with the following sandbox configuration:

.. code-block:: javascript

  {
    "": {
      "": "/home/%u",
      "data": "/data"
    }
  }

If we now update the sandbox configuration for ``userA`` and ``userB`` as follows:

.. code-block:: python

    > api.server.setSandboxMapping("userA", {"data": "/storage"})
    > api.server.setSandboxMapping("userB", {"": "/external/userB", "home": "/home/userB"})

The sandbox configuration on the server will be:

.. code-block:: javascript

  {
    "": {
      "": "/home/%u",
      "data": "/data"
    },

    "userA": {
      "data": "/storage"
    },

    "userB": {
      "": "/external/userB",
      "home": "/home/userB"
    }
  }

Users logging in will observe:

    * ``userA``:

      * ``data:/`` mapped to ``/storage``

    * ``userB``:

      * ``/`` mapped to ``/external/userB``
      * ``home:/`` mapped to ``/home/userB``

    * ``userC``:

      * ``/`` mapped to ``/home/%u`` (resolving into ``/home/userC``)
      * ``data:/`` mapped to ``/data``


Now, if we want the admin user to have a full system access, we can set the sandbox mapping for the ``admin`` user to be ``false``:

.. code-block:: python

    > api.server.setSandboxMapping("admin", False)

The sandbox configuration on the server will become:

.. code-block:: javascript

  {
    "": {
      "": "/home/%u",
      "data": "/data"
    },

    "userA": {
      "data": "/storage"
    },

    "userB": {
      "": "/external/userB",
      "home": "/home/userB"
    }

    "admin": false
  }

Users logging in will observe:

    * ``userA``:

      * ``data:/`` mapped to ``/storage``

    * ``userB``:

      * ``/`` mapped to ``/external/userB``
      * ``home:/`` mapped to ``/home/userB``

    * ``userC``:

      * ``/`` mapped to ``/home/%u`` (resolving into ``/home/userC``)
      * ``data:/`` mapped to ``/data``

    * ``admin``:

      * The admin user will have access to all file systems. On Linux systems, this means the system root (``/``).