Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions bin/bwclaude
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ source "${SCRIPT_DIR}/../lib/bwrap_sandbox_lib.sh"

INIT_AUTH=0
DEBUG_MODE=0
FORWARD_GH_TOKENS=0

# ═══════════════════════════════════════════════════════════════════
# Tool-specific functions
Expand Down Expand Up @@ -115,6 +116,10 @@ parse_wrapper_args() {
DEBUG_MODE=1
shift
;;
--github-tokens)
FORWARD_GH_TOKENS=1
shift
;;
--new-session)
# shellcheck disable=SC2034 # consumed by sourced bwrap_sandbox_lib.sh (sandboxed_exec)
FORCE_NEW_SESSION=1
Expand Down Expand Up @@ -197,6 +202,11 @@ Wrapper options (consumed before claude sees the command line):
Symlinks are resolved before the safety check is applied.
--rw-path PATH Mount PATH (file or directory) read-write into the sandbox.
Same blocked-path rules as --ro-path. May be repeated.
--github-tokens Forward any GH_TOKEN_* environment variables into the
sandbox so the agent can authenticate the gh(1) CLI.
Off by default. When set, use per-command token selection:
GH_TOKEN="$GH_TOKEN_NSLS2" gh pr list -R NSLS2/repo
GH_TOKEN="$GH_TOKEN_PERSONAL" gh issue list -R user/repo

All other arguments are passed through to claude unchanged.

Expand Down Expand Up @@ -382,6 +392,23 @@ build_claude_env() {
fi
done < <(compgen -e)

# GitHub CLI token passthrough (opt-in via --github-tokens)
# In --dry-run mode the value is replaced with REDACTED so that tokens
# are not printed to the terminal in the bwrap command output.
if [[ "${FORWARD_GH_TOKENS}" -eq 1 ]]; then
local _gh_val
while IFS= read -r _key; do
if [[ "${_key}" == GH_TOKEN_* ]]; then
if [[ "${DRY_RUN}" -eq 1 ]]; then
_gh_val="REDACTED"
else
_gh_val="${!_key}"
fi
BWRAP_ARGS+=(--setenv "${_key}" "${_gh_val}")
fi
done < <(compgen -e)
fi

# Enforce after the loop so host env cannot override these.
BWRAP_ARGS+=(--setenv CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS 1)
BWRAP_ARGS+=(--setenv CLAUDE_CODE_USE_FOUNDRY 1)
Expand Down
27 changes: 27 additions & 0 deletions bin/bwcodex
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ source "${SCRIPT_DIR}/../lib/bwrap_sandbox_lib.sh"
INIT_AUTH=0
DEBUG_MODE=0
PERSIST_CONFIG=0
FORWARD_GH_TOKENS=0

# ═══════════════════════════════════════════════════════════════════
# Tool-specific functions
Expand Down Expand Up @@ -143,6 +144,10 @@ parse_wrapper_args() {
DEBUG_MODE=1
shift
;;
--github-tokens)
FORWARD_GH_TOKENS=1
shift
;;
--new-session)
# shellcheck disable=SC2034 # consumed by sourced bwrap_sandbox_lib.sh (sandboxed_exec)
FORCE_NEW_SESSION=1
Expand Down Expand Up @@ -233,6 +238,11 @@ Wrapper options (consumed before codex sees the command line):
Symlinks are resolved before the safety check is applied.
--rw-path PATH Mount PATH (file or directory) read-write into the sandbox.
Same blocked-path rules as --ro-path. May be repeated.
--github-tokens Forward any GH_TOKEN_* environment variables into the
sandbox so the agent can authenticate the gh(1) CLI.
Off by default. When set, use per-command token selection:
GH_TOKEN="$GH_TOKEN_NSLS2" gh pr list -R NSLS2/repo
GH_TOKEN="$GH_TOKEN_PERSONAL" gh issue list -R user/repo

All other arguments are passed through to codex unchanged.

Expand Down Expand Up @@ -419,6 +429,23 @@ build_codex_env() {
if [[ "${DEBUG_MODE}" -eq 1 ]]; then
BWRAP_ARGS+=(--setenv RUST_LOG "debug")
fi

# GitHub CLI token passthrough (opt-in via --github-tokens)
# In --dry-run mode the value is replaced with REDACTED so that tokens
# are not printed to the terminal in the bwrap command output.
if [[ "${FORWARD_GH_TOKENS}" -eq 1 ]]; then
local _gh_val
while IFS= read -r _key; do
if [[ "${_key}" == GH_TOKEN_* ]]; then
if [[ "${DRY_RUN}" -eq 1 ]]; then
_gh_val="REDACTED"
else
_gh_val="${!_key}"
fi
BWRAP_ARGS+=(--setenv "${_key}" "${_gh_val}")
fi
done < <(compgen -e)
fi
}

# ── Codex install dir (stub) ─────────────────────────────────────
Expand Down
27 changes: 27 additions & 0 deletions bin/bwcopilot
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ source "${SCRIPT_DIR}/../lib/bwrap_sandbox_lib.sh"
# ═══════════════════════════════════════════════════════════════════

INIT_AUTH=0
FORWARD_GH_TOKENS=0

# ═══════════════════════════════════════════════════════════════════
# Tool-specific functions
Expand Down Expand Up @@ -104,6 +105,10 @@ parse_wrapper_args() {
INIT_AUTH=1
shift
;;
--github-tokens)
FORWARD_GH_TOKENS=1
shift
;;
--new-session)
# shellcheck disable=SC2034 # consumed by sourced bwrap_sandbox_lib.sh (sandboxed_exec)
FORCE_NEW_SESSION=1
Expand Down Expand Up @@ -184,6 +189,11 @@ Wrapper options (consumed before copilot sees the command line):
Symlinks are resolved before the safety check is applied.
--rw-path PATH Mount PATH (file or directory) read-write into the sandbox.
Same blocked-path rules as --ro-path. May be repeated.
--github-tokens Forward any GH_TOKEN_* environment variables into the
sandbox so the agent can authenticate the gh(1) CLI.
Off by default. When set, use per-command token selection:
GH_TOKEN="$GH_TOKEN_NSLS2" gh pr list -R NSLS2/repo
GH_TOKEN="$GH_TOKEN_PERSONAL" gh issue list -R user/repo

All other arguments are passed through to copilot unchanged.

Expand Down Expand Up @@ -366,6 +376,23 @@ build_copilot_env() {
BWRAP_ARGS+=(--setenv "${_key}" "${!_key}")
fi
done

# GitHub CLI token passthrough (opt-in via --github-tokens)
# In --dry-run mode the value is replaced with REDACTED so that tokens
# are not printed to the terminal in the bwrap command output.
if [[ "${FORWARD_GH_TOKENS}" -eq 1 ]]; then
local _gh_val
while IFS= read -r _key; do
if [[ "${_key}" == GH_TOKEN_* ]]; then
if [[ "${DRY_RUN}" -eq 1 ]]; then
_gh_val="REDACTED"
else
_gh_val="${!_key}"
fi
BWRAP_ARGS+=(--setenv "${_key}" "${_gh_val}")
fi
done < <(compgen -e)
fi
}

# ═══════════════════════════════════════════════════════════════════
Expand Down
30 changes: 30 additions & 0 deletions bin/bwopencode
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ source "${SCRIPT_DIR}/../lib/bwrap_sandbox_lib.sh"
# ═══════════════════════════════════════════════════════════════════

INIT_AUTH=0
FORWARD_GH_TOKENS=0
OC_CONFIG_BINDS=()

# ═══════════════════════════════════════════════════════════════════
Expand Down Expand Up @@ -101,6 +102,10 @@ parse_wrapper_args() {
INIT_AUTH=1
shift
;;
--github-tokens)
FORWARD_GH_TOKENS=1
shift
;;
--new-session)
# shellcheck disable=SC2034 # consumed by sourced bwrap_sandbox_lib.sh (sandboxed_exec)
FORCE_NEW_SESSION=1
Expand Down Expand Up @@ -179,6 +184,11 @@ Wrapper options (consumed before opencode sees the command line):
Symlinks are resolved before the safety check is applied.
--rw-path PATH Mount PATH (file or directory) read-write into the sandbox.
Same blocked-path rules as --ro-path. May be repeated.
--github-tokens Forward any GH_TOKEN_* environment variables into the
sandbox so the agent can authenticate the gh(1) CLI.
Off by default. When set, use per-command token selection:
GH_TOKEN="$GH_TOKEN_NSLS2" gh pr list -R NSLS2/repo
GH_TOKEN="$GH_TOKEN_PERSONAL" gh issue list -R user/repo

All other arguments are passed through to opencode unchanged.

Expand Down Expand Up @@ -366,6 +376,9 @@ build_opencode_cache_mount() {
# ── OpenCode env vars ────────────────────────────────────────────
# Pass through any OPENCODE_* env vars (config overrides, etc.)
# Also pass through AIFAPIM_* env vars for NSLS-II Hermes gateway.
# With --github-tokens, also forward GH_TOKEN_* vars so the agent
# can authenticate gh(1) via per-command:
# GH_TOKEN="$GH_TOKEN_NSLS2" gh <subcommand>
build_opencode_env() {
# AIFAPIM gateway config
pass_through_if_set AIFAPIM_HOST
Expand All @@ -377,6 +390,23 @@ build_opencode_env() {
BWRAP_ARGS+=(--setenv "${_key}" "${!_key}")
fi
done < <(compgen -e)

# GitHub CLI token passthrough (opt-in via --github-tokens)
# In --dry-run mode the value is replaced with REDACTED so that tokens
# are not printed to the terminal in the bwrap command output.
if [[ "${FORWARD_GH_TOKENS}" -eq 1 ]]; then
local _gh_val
while IFS= read -r _key; do
if [[ "${_key}" == GH_TOKEN_* ]]; then
if [[ "${DRY_RUN}" -eq 1 ]]; then
_gh_val="REDACTED"
else
_gh_val="${!_key}"
fi
BWRAP_ARGS+=(--setenv "${_key}" "${_gh_val}")
fi
done < <(compgen -e)
fi
}

# ═══════════════════════════════════════════════════════════════════
Expand Down
12 changes: 10 additions & 2 deletions docs/bw-wrappers.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,9 @@ project-dotfiles to the host data dir; `auth.json` is persisted only if
it already exists on the host (use `--init-auth` once to create it for
personal accounts).

No options beyond the common set.
| Option | Description |
| --- | --- |
| `--github-tokens` | Forward every `GH_TOKEN_*` environment variable into the sandbox so the agent can authenticate `gh`. Off by default. In `--dry-run` mode, token values are printed as `REDACTED`. Use per-command token selection inside the sandbox: `GH_TOKEN="$GH_TOKEN_NSLS2" gh pr list -R NSLS2/repo` |

## `bwclaude`

Expand Down Expand Up @@ -78,6 +80,7 @@ Additional options:
| Option | Effect |
| --- | --- |
| `--debug` | Enable verbose debug logging: sets `ANTHROPIC_LOG=debug`, `NODE_DEBUG=http,https,tls`, and passes `--debug --verbose` to `claude` |
| `--github-tokens` | Forward every `GH_TOKEN_*` environment variable into the sandbox so the agent can authenticate `gh`. Off by default. In `--dry-run` mode, token values are printed as `REDACTED`. Use per-command token selection inside the sandbox: `GH_TOKEN="$GH_TOKEN_NSLS2" gh pr list -R NSLS2/repo` |

On shared accounts, auth is ephemeral. On a personal machine, run
`bwclaude --init-auth` once to persist credentials.
Expand All @@ -91,7 +94,11 @@ inside a bubblewrap sandbox.
bwcopilot [bwcopilot-options] [copilot arguments...]
```

No options beyond the common set.
Additional options:

| Option | Effect |
| --- | --- |
| `--github-tokens` | Forward every `GH_TOKEN_*` environment variable into the sandbox so the agent can authenticate `gh`. Off by default. In `--dry-run` mode, token values are printed as `REDACTED`. Use per-command token selection inside the sandbox: `GH_TOKEN="$GH_TOKEN_NSLS2" gh pr list -R NSLS2/repo` |

On shared accounts, auth tokens are ephemeral. On a personal machine,
run `bwcopilot --init-auth` once to persist tokens.
Expand Down Expand Up @@ -120,6 +127,7 @@ Additional options:
| --- | --- |
| `--debug` | Enable verbose Codex logging (sets `RUST_LOG=debug`) |
| `--persist-config` | Bind-mount `~/.codex/config.toml` read-write into the sandbox so changes (e.g. project-trust grants) persist across sessions. Without this flag, `config.toml` is staged read-write into a per-session copy that is discarded on exit. Concurrent `--persist-config` sessions may race on writes |
| `--github-tokens` | Forward every `GH_TOKEN_*` environment variable into the sandbox so the agent can authenticate `gh`. Off by default. In `--dry-run` mode, token values are printed as `REDACTED`. Use per-command token selection inside the sandbox: `GH_TOKEN="$GH_TOKEN_NSLS2" gh pr list -R NSLS2/repo` |

Note: Codex CLI also enforces its own inner Landlock-based sandbox for
agent tool calls. The outer `bwrap` here is complementary — it scopes
Expand Down