public inbox for tools@linux.kernel.org
 help / color / mirror / Atom feed
From: "Michael S. Tsirkin" <mst@redhat.com>
To: Konstantin Ryabitsev <mricon@kernel.org>
Cc: users@kernel.org, tools@kernel.org
Subject: Re: b4 review available in master
Date: Sat, 28 Feb 2026 16:04:24 -0500	[thread overview]
Message-ID: <20260228155515-mutt-send-email-mst@kernel.org> (raw)
In-Reply-To: <20260228-sceptical-fierce-swift-db217c@lemur>

On Sat, Feb 28, 2026 at 03:53:40PM -0500, Konstantin Ryabitsev wrote:
> On Sat, Feb 28, 2026 at 03:47:51PM -0500, Michael S. Tsirkin wrote:
> > > Bah, that "--" was needed for Claude. /o\
> > 
> > at least for me, claude works without --. shrug.
> 
> Yes, but that's without passing --allowedTools, which takes a really complex
> format with a ton of spaces. I may deprecate that in lieu of shipping policy
> files instead.

Since we are discussing this, I thought I'd share the following, written
a while ago with help from claude. I know I sleep better with this than
with running random stuff from the intertubes directly.

-->

review: add sandbox wrappers and docs for AI review agents

Add bwrap and firejail wrapper scripts that sandbox review agents
against prompt injection in untrusted patches. Document agent
configuration including a bunch of agents.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>

---

diff --git a/misc/bwrap-review-agent.sh b/misc/bwrap-review-agent.sh
new file mode 100755
index 0000000..460a21d
--- /dev/null
+++ b/misc/bwrap-review-agent.sh
@@ -0,0 +1,70 @@
+#!/bin/bash
+# bwrap-review-agent.sh -- bubblewrap sandbox for b4 review agents
+#
+# Full filesystem isolation: the entire filesystem is mounted
+# read-only, real HOME is replaced with a temporary copy containing
+# only agent auth config, and .git/b4-review/ is the sole writable
+# path.  Agent binaries installed under HOME (npm, pip, cargo) are
+# re-exposed read-only.
+#
+# Requires: bubblewrap (bwrap)
+#
+# Usage -- set as your review-agent-command in git config:
+#
+#   [b4]
+#     review-agent-command = misc/bwrap-review-agent.sh cursor-agent --yolo
+#     review-agent-prompt-path = .git/agent-reviewer.md
+
+set -euo pipefail
+
+mydir="$(cd "$(dirname "$0")" && pwd)"
+# shellcheck source=review-agent-sandbox-lib.sh
+. "$mydir/review-agent-sandbox-lib.sh"
+
+if ! command -v bwrap >/dev/null 2>&1; then
+    echo >&2 "bwrap-review-agent: bwrap not found, running agent without sandbox"
+    export HOME="$sandbox_home"
+    exec "$@"
+fi
+
+# Mount layout (later mounts override earlier ones):
+#
+#   /                    read-only   entire host filesystem
+#   /dev                 read-write  minimal private devtmpfs
+#   /proc                read-only   procfs
+#   /tmp                 read-write  private tmpfs (empty, ephemeral)
+#   $real_home           read-write  sandbox_home replaces real HOME;
+#                                    ~/.ssh, ~/.gnupg, etc. are invisible
+#   $real_home/.local/   read-only   agent binaries (pip, pipx installs)
+#   $real_home/.npm-*/   read-only   agent binaries (npm global installs)
+#   $real_home/.cargo/   read-only   agent binaries (cargo installs)
+#   $real_home/.nvm|...  read-only   node version managers
+#   $topdir              read-only   the git repository
+#   $review_dir          read-write  .git/b4-review/ -- review output
+#
+bwrap_args=(
+    --ro-bind / /                          # base: everything read-only
+    --dev /dev                             # private /dev
+    --proc /proc                           # procfs
+    --tmpfs /tmp                           # private /tmp
+    --bind "$sandbox_home" "${real_home}"  # replace HOME with sandbox copy
+    --ro-bind "$topdir" "$topdir"          # repo read-only
+    --bind "$review_dir" "$review_dir"     # review output writable
+)
+
+# Re-expose directories under real HOME that contain agent binaries
+# and their libraries/runtimes (symlinks often point into lib dirs).
+# These are mounted read-only on top of the sandbox HOME.
+for d in \
+    .local/bin .local/share/cursor-agent \
+    .npm-global \
+    .cargo/bin \
+    .nvm .fnm .volta \
+; do
+    p="${real_home}/$d"
+    if [ -d "$p" ]; then
+        bwrap_args+=(--ro-bind "$p" "$p")  # agent binary dir, read-only
+    fi
+done
+
+exec bwrap "${bwrap_args[@]}" -- "$@"
diff --git a/misc/firejail-review-agent.sh b/misc/firejail-review-agent.sh
new file mode 100755
index 0000000..aa8093f
--- /dev/null
+++ b/misc/firejail-review-agent.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+# firejail-review-agent.sh -- firejail sandbox for b4 review agents
+#
+# The repository and real HOME are mounted read-only.  HOME env is
+# redirected to a temporary copy containing only agent auth config.
+# .git/b4-review/ is the sole writable path in the repository.
+#
+# Requires: firejail
+#
+# Note: firejail cannot fully hide the real HOME from the agent
+# (read-only != invisible).  For stronger isolation, prefer
+# bwrap-review-agent.sh which replaces HOME entirely.
+#
+# Usage -- set as your review-agent-command in git config:
+#
+#   [b4]
+#     review-agent-command = misc/firejail-review-agent.sh cursor-agent --yolo
+#     review-agent-prompt-path = .git/agent-reviewer.md
+
+set -euo pipefail
+
+mydir="$(cd "$(dirname "$0")" && pwd)"
+# shellcheck source=review-agent-sandbox-lib.sh
+. "$mydir/review-agent-sandbox-lib.sh"
+
+if ! command -v firejail >/dev/null 2>&1; then
+    echo >&2 "firejail-review-agent: firejail not found, running agent without sandbox"
+    export HOME="$sandbox_home"
+    exec "$@"
+fi
+
+# Mount layout:
+#
+#   $real_home    read-only   real HOME (still visible but not writable;
+#                             ~/.ssh, ~/.gnupg are readable -- use bwrap
+#                             wrapper if this is a concern)
+#   $topdir       read-only   the git repository
+#   $review_dir   read-write  .git/b4-review/ -- review output
+#   /tmp          read-write  private tmpfs (empty, ephemeral)
+#   /dev          read-write  minimal private devtmpfs
+#   HOME env      sandbox_home  agent looks here for config by default
+#
+# Capabilities: all dropped.  No new privileges, no root.
+#
+export HOME="$sandbox_home"
+firejail --noprofile \
+    --read-only="${real_home}" \
+    --read-only="$topdir" \
+    --read-write="$review_dir" \
+    --private-tmp \
+    --private-dev \
+    --caps.drop=all \
+    --nonewprivs \
+    --noroot \
+    -- "$@"
diff --git a/misc/review-agent-sandbox-lib.sh b/misc/review-agent-sandbox-lib.sh
new file mode 100644
index 0000000..df588ff
--- /dev/null
+++ b/misc/review-agent-sandbox-lib.sh
@@ -0,0 +1,44 @@
+# review-agent-sandbox-lib.sh -- shared setup for sandbox wrappers
+#
+# Sourced by firejail-review-agent.sh and bwrap-review-agent.sh.
+# Not executable on its own.
+#
+# After sourcing, the following variables are set:
+#   topdir       -- repository top-level directory
+#   review_dir   -- .git/b4-review/ (writable review output)
+#   real_home    -- the user's real HOME
+#   sandbox_home -- temporary HOME with only agent auth config
+#
+# A trap is registered to clean up sandbox_home on exit.
+
+topdir="$(git rev-parse --show-toplevel)"
+review_dir="$topdir/.git/b4-review"
+mkdir -p "$review_dir"
+real_home="${HOME}"
+
+# Create a temporary HOME containing only agent auth config.
+# The agent process sees this as $HOME, so ~/.ssh, ~/.gnupg, etc.
+# simply do not exist.
+mkdir -p "$review_dir/.sandbox"
+sandbox_home="$(mktemp -d --tmpdir="$review_dir/.sandbox")"
+trap 'rm -rf "$sandbox_home"' EXIT INT TERM
+
+# Copy top-level config files (auth, settings) for known agents.
+# Only files under 1 MB are copied -- large session logs and caches
+# are skipped since the agent only needs credentials.
+for d in \
+    .config/cursor .config/Cursor .cursor \
+    .config/claude .claude .local/share/claude .local/state/claude \
+    .codex \
+    .gemini .config/gemini \
+; do
+    src="${real_home}/$d"
+    if [ -d "$src" ]; then
+        mkdir -p "$sandbox_home/$d"
+        find "$src" -maxdepth 1 -type f -size -1024k \
+            -exec cp -a {} "$sandbox_home/$d/" \;
+    elif [ -e "$src" ] || [ -L "$src" ]; then
+        mkdir -p "$(dirname "$sandbox_home/$d")"
+        cp -a "$src" "$sandbox_home/$d"
+    fi
+done


  reply	other threads:[~2026-02-28 21:04 UTC|newest]

Thread overview: 69+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-27 19:53 b4 review available in master Konstantin Ryabitsev
2026-02-28 15:12 ` Mark Brown
2026-02-28 15:47   ` Konstantin Ryabitsev
2026-02-28 16:00     ` Konstantin Ryabitsev
2026-02-28 18:12       ` Mark Brown
2026-02-28 15:53 ` Mark Brown
2026-02-28 21:11   ` Mark Brown
2026-03-03  5:14     ` Konstantin Ryabitsev
2026-03-03 12:42       ` Mark Brown
2026-03-03 18:21         ` Konstantin Ryabitsev
2026-03-12 17:21           ` Alexandre Belloni
2026-03-13 15:42             ` Konstantin Ryabitsev
2026-03-13 15:55               ` Alexandre Belloni
2026-03-21 10:01                 ` Alexandre Belloni
2026-03-12 17:35           ` Mark Brown
2026-03-13 15:42             ` Konstantin Ryabitsev
2026-02-28 16:36 ` Conor Dooley
2026-02-28 16:45   ` Konstantin Ryabitsev
2026-02-28 16:48     ` Conor Dooley
2026-02-28 16:57       ` Konstantin Ryabitsev
2026-02-28 17:00         ` Conor Dooley
2026-02-28 17:05           ` Konstantin Ryabitsev
2026-02-28 17:12             ` Conor Dooley
2026-02-28 17:21               ` Konstantin Ryabitsev
2026-02-28 17:34                 ` Konstantin Ryabitsev
2026-02-28 18:37                   ` Conor Dooley
2026-02-28 22:16                   ` Conor Dooley
2026-02-28 22:32                     ` Conor Dooley
2026-03-03  5:16                       ` Konstantin Ryabitsev
2026-03-04 21:38                         ` Conor Dooley
2026-03-04 22:40                           ` Konstantin Ryabitsev
2026-03-04 22:55                             ` Conor Dooley
2026-03-05  3:26                               ` Konstantin Ryabitsev
2026-03-05  6:17                             ` Konstantin Ryabitsev
2026-02-28 18:31 ` Michael S. Tsirkin
2026-02-28 20:06   ` Konstantin Ryabitsev
2026-02-28 20:23     ` Michael S. Tsirkin
2026-02-28 20:37       ` Konstantin Ryabitsev
2026-02-28 20:47         ` Michael S. Tsirkin
2026-02-28 20:53           ` Konstantin Ryabitsev
2026-02-28 21:04             ` Michael S. Tsirkin [this message]
2026-03-02  9:30 ` Michael S. Tsirkin
2026-03-02 10:33 ` Michael S. Tsirkin
2026-03-03  1:58 ` Junio C Hamano
2026-03-03  4:26   ` Konstantin Ryabitsev
2026-03-03 11:20     ` Matthieu Baerts
2026-03-04 20:56 ` range-diff hangs Marc Kleine-Budde
2026-03-14  4:20   ` Konstantin Ryabitsev
2026-03-14  9:27     ` Marc Kleine-Budde
2026-03-16 23:28 ` b4 review available in master Jonathan Corbet
2026-03-16 23:41   ` Jonathan Corbet
2026-03-17  0:15     ` Konstantin Ryabitsev
2026-03-17 14:11       ` Jonathan Corbet
2026-03-17 14:23         ` Konstantin Ryabitsev
2026-03-17 20:30           ` Konstantin Ryabitsev
2026-03-17 21:46             ` Jonathan Corbet
2026-03-17 22:39               ` Konstantin Ryabitsev
2026-03-17 23:37                 ` Konstantin Ryabitsev
2026-03-18  7:56                   ` Geert Uytterhoeven
2026-03-18 13:00                     ` Mark Brown
2026-03-18 13:26                     ` Konstantin Ryabitsev
2026-03-18 16:47                   ` Jonathan Corbet
2026-03-18 18:31                     ` Laurent Pinchart
2026-03-18 19:22                     ` Konstantin Ryabitsev
2026-03-17  0:12   ` Konstantin Ryabitsev
2026-03-18 13:43   ` Johannes Thumshirn
2026-03-20 16:53 ` Louis Chauvet
2026-03-20 19:31   ` Konstantin Ryabitsev
2026-03-20 21:14     ` Alexandre Belloni

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260228155515-mutt-send-email-mst@kernel.org \
    --to=mst@redhat.com \
    --cc=mricon@kernel.org \
    --cc=tools@kernel.org \
    --cc=users@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox