From 418e130fc9b78874fd41d6e442bca34f92bb3952 Mon Sep 17 00:00:00 2001 From: Ivan Date: Sun, 22 Mar 2026 15:08:13 +0300 Subject: [PATCH] Add documentation for running MeshChatX in Firejail and Bubblewrap sandboxes on Linux --- docs/meshchatx_linux_sandbox.md | 164 ++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 docs/meshchatx_linux_sandbox.md diff --git a/docs/meshchatx_linux_sandbox.md b/docs/meshchatx_linux_sandbox.md new file mode 100644 index 0000000..d598000 --- /dev/null +++ b/docs/meshchatx_linux_sandbox.md @@ -0,0 +1,164 @@ +# MeshChatX on Linux: Firejail and Bubblewrap + +This page shows how to run `meshchat` under **Firejail** or **Bubblewrap** (`bwrap`) on Linux. Use this when you install MeshChatX natively (wheel, package, or Poetry) and want an extra layer of filesystem and process isolation compared to running the binary directly. + +These tools do **not** replace a full virtual machine or hardware-enforced boundary. They reduce exposure of your home directory and other paths the process can write to, when you configure them with tight whitelists or bind mounts. + +**Containers:** If you already run MeshChatX with Docker or Podman, that is a different isolation model; this document is aimed at **host-installed** `meshchat`. + +## Prerequisites + +Install one or both from your distribution: + +- **Firejail:** package name is usually `firejail`. +- **Bubblewrap:** package name is usually `bubblewrap`; the binary is `bwrap`. + +You need a working `meshchat` on your `PATH` (for example after `pipx install`, `pip install --user`, or a distro package). + +Pick a **dedicated data directory** for sandboxed runs so you do not mix permissions or policies with a non-sandboxed install. The examples below use: + +```bash +DATA="${XDG_DATA_HOME:-$HOME/.local/share}/meshchatx-sandbox" +mkdir -p "$DATA/storage" "$DATA/.reticulum" +``` + +Adjust paths if you prefer another location. + +## Firejail + +Firejail applies a profile (or defaults) on top of your command. For MeshChatX you typically want: + +- **Network** left available so Reticulum and the web UI can work (do not use `--net=none` unless you know you need it). +- **Writable** only your chosen data directory (and anything else the app truly needs). + +### Installed `meshchat` (pip, pipx, or system package) + +```bash +DATA="${XDG_DATA_HOME:-$HOME/.local/share}/meshchatx-sandbox" +mkdir -p "$DATA/storage" "$DATA/.reticulum" + +firejail --quiet \ + --whitelist="$DATA" \ + meshchat --headless --host 127.0.0.1 \ + --storage-dir="$DATA/storage" \ + --reticulum-config-dir="$DATA/.reticulum" +``` + +If the default profile blocks something MeshChatX needs, you can start from a looser base and tighten later, for example: + +```bash +firejail --noprofile --whitelist="$DATA" \ + meshchat --headless --host 127.0.0.1 \ + --storage-dir="$DATA/storage" \ + --reticulum-config-dir="$DATA/.reticulum" +``` + +`--noprofile` disables many Firejail restrictions; treat it as a stepping stone, not the final hardening. + +### From source with Poetry + +Poetry needs the project tree and the virtualenv. Example: + +```bash +cd /path/to/reticulum-meshchatX +DATA="${XDG_DATA_HOME:-$HOME/.local/share}/meshchatx-sandbox" +VENV="$(poetry env info -p)" +mkdir -p "$DATA/storage" "$DATA/.reticulum" + +firejail --quiet \ + --whitelist="$(pwd)" \ + --whitelist="$VENV" \ + --whitelist="$DATA" \ + poetry run meshchat --headless --host 127.0.0.1 \ + --storage-dir="$DATA/storage" \ + --reticulum-config-dir="$DATA/.reticulum" +``` + +You may need extra `--whitelist=` entries if Poetry or dependencies read config elsewhere (for example under `$HOME/.config`). + +### USB serial (RNode or similar) + +If Reticulum talks to a radio over a serial device, Firejail may need explicit access to TTY devices, for example: + +```bash +firejail --noblacklist=/dev/ttyACM0 --noblacklist=/dev/ttyUSB0 \ + ... +``` + +Use the device nodes your system actually exposes (`dmesg`, `ls /dev/tty*`). + +## Bubblewrap (`bwrap`) + +Bubblewrap does not ship profiles; you list every mount and option. The pattern below keeps the **whole root filesystem read-only**, mounts a **writable tmpfs** on `/tmp`, and makes **only** your data directory writable at its normal path. **Network namespaces are not changed**, so Reticulum and TCP/UDP behave like an unsandboxed process unless you add `--unshare-net` (which usually breaks mesh networking). + +### Installed `meshchat` + +```bash +DATA="${XDG_DATA_HOME:-$HOME/.local/share}/meshchatx-sandbox" +mkdir -p "$DATA/storage" "$DATA/.reticulum" + +exec bwrap \ + --die-with-parent \ + --new-session \ + --proc /proc \ + --dev /dev \ + --ro-bind / / \ + --tmpfs /tmp \ + --bind "$DATA" "$DATA" \ + --uid "$(id -u)" --gid "$(id -g)" \ + meshchat --headless --host 127.0.0.1 \ + --storage-dir="$DATA/storage" \ + --reticulum-config-dir="$DATA/.reticulum" +``` + +Notes: + +- If `meshchat` lives only inside a venv that is **not** under `$DATA`, the read-only root still allows **reading** that path; you do not have to bind-mount the venv separately unless you also need writes there. +- Distributions that merge `/` and `/usr` (merged-usr) still work with `--ro-bind / /` on typical glibc setups. If `bwrap` fails with missing library paths, add the extra `--ro-bind` lines your distro documents (for example `/lib64`). + +### From source with Poetry + +Bind the repository and the Poetry venv read-only, and keep `DATA` writable: + +```bash +cd /path/to/reticulum-meshchatX +DATA="${XDG_DATA_HOME:-$HOME/.local/share}/meshchatx-sandbox" +VENV="$(poetry env info -p)" +mkdir -p "$DATA/storage" "$DATA/.reticulum" +PROJ="$(pwd)" + +exec bwrap \ + --die-with-parent \ + --new-session \ + --proc /proc \ + --dev /dev \ + --ro-bind / / \ + --tmpfs /tmp \ + --bind "$DATA" "$DATA" \ + --ro-bind "$PROJ" "$PROJ" \ + --ro-bind "$VENV" "$VENV" \ + --uid "$(id -u)" --gid "$(id -g)" \ + --setenv PATH "$VENV/bin:$PATH" \ + --chdir "$PROJ" \ + poetry run meshchat --headless --host 127.0.0.1 \ + --storage-dir="$DATA/storage" \ + --reticulum-config-dir="$DATA/.reticulum" +``` + +`poetry` itself must be reachable on `PATH` inside the sandbox (often under `/usr` or `$HOME/.local/bin`, both visible with `--ro-bind / /`). If `poetry run` fails because it cannot read `~/.config/poetry`, add a read-only bind for that directory or invoke the venv interpreter directly instead of `poetry run`: + +```bash +exec bwrap \ + ... same mounts as above ... \ + --setenv PATH "$VENV/bin:$PATH" \ + --chdir "$PROJ" \ + meshchat --headless --host 127.0.0.1 \ + --storage-dir="$DATA/storage" \ + --reticulum-config-dir="$DATA/.reticulum" +``` + +(Use the `meshchat` script or `python -m` entry point from `$VENV/bin` if your install exposes it there.) + +### USB serial under Bubblewrap + +You may need a clearer view of devices than the minimal `--dev /dev` provides. Options include `--dev-bind /dev /dev` (broader device exposure) or binding only the specific character device. Balance convenience against attack surface. \ No newline at end of file