feat(260504-bw4): add --with-ssh and --ssh-key flags to claudebox
This commit is contained in:
parent
29996a2d40
commit
41ebf10458
1 changed files with 107 additions and 0 deletions
107
claudebox.sh
107
claudebox.sh
|
|
@ -4,6 +4,8 @@ DRY_RUN=false
|
|||
CHECK_MODE=false
|
||||
SHELL_MODE=false
|
||||
GC_MODE=false
|
||||
WITH_SSH=false
|
||||
SSH_KEYS=()
|
||||
CLAUDE_ARGS=()
|
||||
|
||||
while (( $# > 0 )); do
|
||||
|
|
@ -13,6 +15,12 @@ while (( $# > 0 )); do
|
|||
--check) CHECK_MODE=true ;;
|
||||
--shell) SHELL_MODE=true ;;
|
||||
--gc) GC_MODE=true ;;
|
||||
--with-ssh) WITH_SSH=true ;;
|
||||
--ssh-key)
|
||||
shift
|
||||
[[ $# -gt 0 ]] || { echo "Error: --ssh-key requires a path" >&2; exit 1; }
|
||||
SSH_KEYS+=("${1/#\~/$HOME}")
|
||||
;;
|
||||
--) shift; CLAUDE_ARGS+=("$@"); break ;;
|
||||
*) CLAUDE_ARGS+=("$1") ;;
|
||||
esac
|
||||
|
|
@ -20,6 +28,22 @@ while (( $# > 0 )); do
|
|||
done
|
||||
export SKIP_AUDIT # consumed by Plan 02 audit display
|
||||
|
||||
# Validate and resolve SSH key paths
|
||||
for _i in "${!SSH_KEYS[@]}"; do
|
||||
_key="${SSH_KEYS[$_i]}"
|
||||
# Expand ~ if not already done
|
||||
_key="${_key/#\~/$HOME}"
|
||||
# Make absolute
|
||||
if [[ "$_key" != /* ]]; then
|
||||
_key="$PWD/$_key"
|
||||
fi
|
||||
if [[ ! -f "$_key" || ! -r "$_key" ]]; then
|
||||
echo "Error: --ssh-key path does not exist or is not readable: $_key" >&2
|
||||
exit 1
|
||||
fi
|
||||
SSH_KEYS[$_i]="$_key"
|
||||
done
|
||||
|
||||
# Garbage-collect stale instance directories (D-11, INST-04)
|
||||
gc_instances() {
|
||||
local removed=0
|
||||
|
|
@ -106,6 +130,30 @@ else
|
|||
BOLD="" RESET="" DIM="" CYAN="" YELLOW="" GREEN="" RED=""
|
||||
fi
|
||||
|
||||
# SSH agent validation (must be after ANSI vars are set)
|
||||
if [[ "$WITH_SSH" == true ]]; then
|
||||
if [[ -v SSH_AUTH_SOCK && -S "$SSH_AUTH_SOCK" ]]; then
|
||||
: # agent is running, keep WITH_SSH=true
|
||||
else
|
||||
echo "${YELLOW}Warning: --with-ssh given but SSH_AUTH_SOCK is unset or not a socket; agent will not be forwarded.${RESET}" >&2
|
||||
WITH_SSH=false
|
||||
fi
|
||||
fi
|
||||
|
||||
# Compute SSH active state
|
||||
if [[ "$WITH_SSH" == true ]] || (( ${#SSH_KEYS[@]} > 0 )); then
|
||||
SSH_ACTIVE=true
|
||||
else
|
||||
SSH_ACTIVE=false
|
||||
fi
|
||||
|
||||
# Determine if known_hosts should be mounted
|
||||
if [[ "$SSH_ACTIVE" == true && -f "$HOME/.ssh/known_hosts" ]]; then
|
||||
KNOWN_HOSTS_MOUNT=true
|
||||
else
|
||||
KNOWN_HOSTS_MOUNT=false
|
||||
fi
|
||||
|
||||
# Mask sensitive values (D-04)
|
||||
mask_value() {
|
||||
local name="$1" value="$2"
|
||||
|
|
@ -290,6 +338,13 @@ for var in "${HOST_ALLOWLIST[@]}"; do
|
|||
fi
|
||||
done
|
||||
|
||||
# SSH_AUTH_SOCK: pass into sandbox when agent forwarding is active
|
||||
if [[ "$WITH_SSH" == true ]]; then
|
||||
ENV_ARGS+=(--setenv SSH_AUTH_SOCK "$SSH_AUTH_SOCK")
|
||||
AUDIT_HOST_KEYS+=(SSH_AUTH_SOCK)
|
||||
AUDIT_HOST_VALS[SSH_AUTH_SOCK]="$SSH_AUTH_SOCK"
|
||||
fi
|
||||
|
||||
# CLAUDEBOX_EXTRA_ENV escape hatch (D-03, comma-separated)
|
||||
if [[ -v CLAUDEBOX_EXTRA_ENV ]]; then
|
||||
IFS=',' read -ra EXTRAS <<< "$CLAUDEBOX_EXTRA_ENV"
|
||||
|
|
@ -367,6 +422,22 @@ print_audit() {
|
|||
if [[ "$CREDS_MOUNT" == true ]]; then
|
||||
printf ' %-12s %s (read-write)\n' "credentials" "$CREDS_FILE" >&2
|
||||
fi
|
||||
if [[ "$SSH_ACTIVE" == true ]]; then
|
||||
if [[ "$WITH_SSH" == true ]]; then
|
||||
printf ' %-12s %s (read-write, --with-ssh)\n' "agent" "$SSH_AUTH_SOCK" >&2
|
||||
fi
|
||||
for _key in "${SSH_KEYS[@]}"; do
|
||||
_base=$(basename "$_key")
|
||||
printf ' %-12s %s (read-only)\n' "ssh-key" "$_key" >&2
|
||||
if [[ -f "${_key}.pub" ]]; then
|
||||
printf ' %-12s %s (read-only)\n' "ssh-key" "${_key}.pub" >&2
|
||||
fi
|
||||
unset _base
|
||||
done
|
||||
if [[ "$KNOWN_HOSTS_MOUNT" == true ]]; then
|
||||
printf ' %-12s %s (read-only)\n' "known_hosts" "$HOME/.ssh/known_hosts" >&2
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "" >&2
|
||||
|
||||
|
|
@ -442,6 +513,24 @@ if [[ "$DRY_RUN" == true ]]; then
|
|||
if [[ "$CREDS_MOUNT" == true ]]; then
|
||||
echo " --bind $CREDS_FILE $HOME/.claude/.credentials.json \\"
|
||||
fi
|
||||
if [[ "$SSH_ACTIVE" == true ]]; then
|
||||
echo " --dir $HOME/.ssh \\"
|
||||
if [[ "$WITH_SSH" == true ]]; then
|
||||
echo " --bind $SSH_AUTH_SOCK $SSH_AUTH_SOCK \\"
|
||||
fi
|
||||
for _dry_key in "${SSH_KEYS[@]}"; do
|
||||
_dry_base=$(basename "$_dry_key")
|
||||
echo " --ro-bind $_dry_key $HOME/.ssh/$_dry_base \\"
|
||||
if [[ -f "${_dry_key}.pub" ]]; then
|
||||
echo " --ro-bind ${_dry_key}.pub $HOME/.ssh/${_dry_base}.pub \\"
|
||||
fi
|
||||
unset _dry_base
|
||||
done
|
||||
if [[ "$KNOWN_HOSTS_MOUNT" == true ]]; then
|
||||
echo " --ro-bind $HOME/.ssh/known_hosts $HOME/.ssh/known_hosts \\"
|
||||
fi
|
||||
fi
|
||||
unset _dry_key
|
||||
printf ' --ro-bind %q %s/.gitconfig \\\n' "$GITCONFIG_TMP" "$HOME"
|
||||
echo " --bind $CWD $CWD \\"
|
||||
echo " --chdir $CWD \\"
|
||||
|
|
@ -485,6 +574,24 @@ fi
|
|||
if [[ "$CREDS_MOUNT" == true ]]; then
|
||||
BWRAP_ARGS+=(--bind "$CREDS_FILE" "$HOME/.claude/.credentials.json")
|
||||
fi
|
||||
if [[ "$SSH_ACTIVE" == true ]]; then
|
||||
BWRAP_ARGS+=(--dir "$HOME/.ssh")
|
||||
if [[ "$WITH_SSH" == true ]]; then
|
||||
BWRAP_ARGS+=(--bind "$SSH_AUTH_SOCK" "$SSH_AUTH_SOCK")
|
||||
fi
|
||||
for _key in "${SSH_KEYS[@]}"; do
|
||||
_base=$(basename "$_key")
|
||||
BWRAP_ARGS+=(--ro-bind "$_key" "$HOME/.ssh/$_base")
|
||||
if [[ -f "${_key}.pub" ]]; then
|
||||
BWRAP_ARGS+=(--ro-bind "${_key}.pub" "$HOME/.ssh/${_base}.pub")
|
||||
fi
|
||||
unset _base
|
||||
done
|
||||
if [[ "$KNOWN_HOSTS_MOUNT" == true ]]; then
|
||||
BWRAP_ARGS+=(--ro-bind "$HOME/.ssh/known_hosts" "$HOME/.ssh/known_hosts")
|
||||
fi
|
||||
fi
|
||||
unset _key
|
||||
BWRAP_ARGS+=(
|
||||
--ro-bind "$GITCONFIG_TMP" "$HOME/.gitconfig"
|
||||
--bind "$CWD" "$CWD"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue