Files
cc-connect/core/runas_probe.sh
T
2026-06-02 23:14:41 +08:00

142 lines
4.5 KiB
Bash

#!/bin/sh
#
# runas_probe.sh — leak-audit probe for the run_as_user sandbox.
#
# Invoked by core.RunIsolationProbe via `sudo -n -iu <target> -- /bin/sh -s`
# with this script piped on stdin. Writes a stable, parseable report to
# stdout. Every line is prefixed with a section tag so the Go side can
# read it deterministically without shell quoting hazards.
#
# This script must NOT read or echo any secret material. It reports
# existence and access, never contents.
#
# It is also intentionally written in POSIX /bin/sh, not bash, so it runs
# on macOS and BusyBox-based systems without relying on bashisms.
#
# Environment inputs (set by the Go caller via the shell invocation):
# CC_PROBE_WORKDIR — project work_dir (required)
# CC_PROBE_OTHER_USERS — space-separated list of other run_as_user
# values configured in the same cc-connect
# instance, for cross-user denial tests
# CC_PROBE_SUPERVISOR — the supervisor Unix username (for denial test)
set -u
emit() {
# emit TAG VALUE ...
printf '%s\n' "$*"
}
emit "BEGIN probe-version=1"
# ---------------------------------------------------------------- identity
emit "ID $(id 2>/dev/null || echo unknown)"
emit "WHOAMI $(whoami 2>/dev/null || echo unknown)"
emit "GROUPS $(id -Gn 2>/dev/null || echo unknown)"
emit "UMASK $(umask 2>/dev/null || echo unknown)"
emit "PWD $(pwd 2>/dev/null || echo unknown)"
emit "HOME ${HOME:-unknown}"
emit "SHELL ${SHELL:-unknown}"
# ---------------------------------------------------------------- work_dir
if [ -n "${CC_PROBE_WORKDIR:-}" ]; then
emit "WORKDIR_PATH ${CC_PROBE_WORKDIR}"
if [ -d "${CC_PROBE_WORKDIR}" ]; then
emit "WORKDIR_EXISTS yes"
else
emit "WORKDIR_EXISTS no"
fi
if [ -r "${CC_PROBE_WORKDIR}" ]; then
emit "WORKDIR_READABLE yes"
else
emit "WORKDIR_READABLE no"
fi
if [ -w "${CC_PROBE_WORKDIR}" ]; then
emit "WORKDIR_WRITABLE yes"
else
emit "WORKDIR_WRITABLE no"
fi
fi
# ----------------------------------------------------- target user's config
# Things the target user is supposed to have in THEIR home. We just check
# existence — not contents.
for f in \
"${HOME}/.claude/settings.json" \
"${HOME}/.claude.json" \
"${HOME}/.claude/plugins" \
"${HOME}/.pgpass" \
"${HOME}/keys" \
"${HOME}/.ssh" \
"${HOME}/.config/gh"
do
if [ -e "$f" ]; then
emit "TARGET_HAS $f"
else
emit "TARGET_MISSING $f"
fi
done
# ------------------------------------------- cross-user denial tests
# For each OTHER configured run_as_user, try to READ a file inside their
# home. Expected outcome: denied. We report DENIED or LEAKED per path.
if [ -n "${CC_PROBE_OTHER_USERS:-}" ]; then
for other in ${CC_PROBE_OTHER_USERS}; do
if [ "$other" = "$(whoami)" ]; then
continue
fi
other_home=$(getent passwd "$other" 2>/dev/null | cut -d: -f6)
if [ -z "$other_home" ]; then
emit "CROSS_UNKNOWN $other"
continue
fi
for f in \
"$other_home/.claude/settings.json" \
"$other_home/.claude.json" \
"$other_home/.ssh/id_rsa" \
"$other_home/.ssh/id_ed25519" \
"$other_home/.pgpass" \
"$other_home/keys"
do
if [ ! -e "$f" ]; then
emit "CROSS_MISSING ${other} ${f}"
continue
fi
if [ -r "$f" ]; then
emit "CROSS_LEAKED ${other} ${f}"
else
emit "CROSS_DENIED ${other} ${f}"
fi
done
done
fi
# ---------------------------------------------------- supervisor denial
if [ -n "${CC_PROBE_SUPERVISOR:-}" ]; then
sup=${CC_PROBE_SUPERVISOR}
if [ "$sup" != "$(whoami)" ]; then
sup_home=$(getent passwd "$sup" 2>/dev/null | cut -d: -f6)
if [ -n "$sup_home" ]; then
for f in \
"$sup_home/.claude/settings.json" \
"$sup_home/.claude.json" \
"$sup_home/.ssh/id_rsa" \
"$sup_home/.ssh/id_ed25519" \
"$sup_home/.pgpass"
do
if [ ! -e "$f" ]; then
emit "SUPERVISOR_MISSING ${f}"
continue
fi
if [ -r "$f" ]; then
emit "SUPERVISOR_LEAKED ${f}"
else
emit "SUPERVISOR_DENIED ${f}"
fi
done
fi
fi
fi
emit "END probe-version=1"