deploy-claude-code: bypass permissions + root по умолчанию (t-261016120111)

This commit is contained in:
Simbiot Harness 2026-10-16 13:04:02 +00:00
parent ecc9765996
commit b9755187cf

View file

@ -11,14 +11,19 @@
# 5) daemon-reload + enable --now + финальная проверка версий и здоровья
#
# Использование (root или sudo):
# bash scripts/deploy-claude-code.sh # дефолты: :7681, юзер claude, токен сгенерится
# bash scripts/deploy-claude-code.sh # дефолты: :7681, root + bypass permissions
# bash scripts/deploy-claude-code.sh --port 7681 --user lunar --token MySecret
# bash scripts/deploy-claude-code.sh --run-as claude # ограниченный режим: юзер claude
# bash scripts/deploy-claude-code.sh --dry-run --port 9000 --user bob --token x
# bash scripts/deploy-claude-code.sh --check # только здоровье, без установки
#
# Опции:
# --port N порт ttyd (по умолчанию 7681, как на Лунаре)
# --user NAME OS-юзер сервиса И логин basic-auth (по умолчанию claude)
# --user NAME логин basic-auth (по умолчанию claude)
# --run-as NAME юзер сервиса ttyd (по умолчанию root — агенту нужны
# права на редактирование любых файлов; t-261016120111)
# --ask-permissions НЕ прокидывать --dangerously-skip-permissions
# (по умолчанию флаг прокидывается всегда — bypass)
# --token SECRET пароль basic-auth (по умолчанию: openssl rand -hex 12)
# --service NAME имя systemd-юнита (по умолчанию ttyd-claude)
# --ttyd-version V версия ttyd (по умолчанию 1.7.7)
@ -32,14 +37,17 @@
# --check только проверка здоровья (версии + HTTP + сервис)
# -h | --help эта справка
#
# Безопасность: веб-терминнал закрыт basic-auth (-c user:token) — как на Лунаре
# (логин lunar / Zm9yZXZ0b25lClaude01). Сервис работает от непривилегированного
# юзера (User=), никакого root-shell в браузере.
# Безопасность: веб-терминал закрыт basic-auth (-c user:token). ПО УМОЛЧАНИЮ
# сервис работает от root и claude запускается с --dangerously-skip-permissions
# (мандат t-261016120111: агент должен уметь редактировать любые файлы).
# Для ограниченной развёртки: --run-as <user> --ask-permissions.
# ============================================================================
set -euo pipefail
PORT="7681"
USER_NAME="claude"
RUN_AS="root"
ASK_PERMISSIONS=0
TOKEN=""
SERVICE="ttyd-claude"
TTYD_VERSION="1.7.7"
@ -62,6 +70,8 @@ while [ $# -gt 0 ]; do
case "$1" in
--port) PORT="${2:-}"; shift 2 ;;
--user) USER_NAME="${2:-}"; shift 2 ;;
--run-as) RUN_AS="${2:-}"; shift 2 ;;
--ask-permissions) ASK_PERMISSIONS=1; shift ;;
--token) TOKEN="${2:-}"; shift 2 ;;
--service) SERVICE="${2:-}"; shift 2 ;;
--ttyd-version) TTYD_VERSION="${2:-}"; shift 2 ;;
@ -79,6 +89,7 @@ while [ $# -gt 0 ]; do
opt="${1%%=*}"; val="${1#*=}"
case "$opt" in
--port) PORT="$val" ;; --user) USER_NAME="$val" ;;
--run-as) RUN_AS="$val" ;; --ask-permissions) ASK_PERMISSIONS=1 ;;
--token) TOKEN="$val" ;; --service) SERVICE="$val" ;;
--ttyd-version) TTYD_VERSION="$val" ;; --node-version) NODE_VERSION="$val" ;;
--claude-version) CLAUDE_VERSION="$val" ;; --interface) INTERFACE="$val" ;;
@ -93,6 +104,10 @@ done
|| die "--port должен быть числом 1..65535 (получили: '$PORT')"
[[ "$USER_NAME" =~ ^[a-z_][a-z0-9_-]{0,31}$ ]] \
|| die "--user должен быть валидным unix-логином (a-z, 0-9, _, -; получили: '$USER_NAME')"
[[ "$RUN_AS" =~ ^[a-z_][a-z0-9_-]{0,31}$ ]] \
|| die "--run-as должен быть валидным unix-логином (получили: '$RUN_AS')"
id -u "$RUN_AS" >/dev/null 2>&1 || [ "$DRY_RUN" -eq 1 ] || [ "$CHECK_ONLY" -eq 1 ] \
|| die "--run-as: юзер '$RUN_AS' не существует (скрипт его не создаёт — создай сам или запусти без --run-as для root)"
[[ "$SERVICE" =~ ^[a-zA-Z0-9_.@-]+$ ]] || die "--service: некорректное имя юнита '$SERVICE'"
case "$TOKEN" in
*:*) die "--token не может содержать ':' (ломает -c user:token)" ;;
@ -223,17 +238,22 @@ else
bash -c "set -e; curl -fsSL -o /usr/local/bin/ttyd https://github.com/tsl0922/ttyd/releases/download/$TTYD_VERSION/ttyd.$TARCH && chmod +x /usr/local/bin/ttyd"
fi
# ── 4) OS-юзер и systemd-юнит ────────────────────────────────────────────────
if [ "$DRY_RUN" -eq 0 ]; then
if ! id -u "$USER_NAME" >/dev/null 2>&1; then
log "создаю юзера $USER_NAME (без root-shell в веб-терминале)"
useradd -m -s /bin/bash "$USER_NAME"
fi
# ── 4) systemd-юнит ──────────────────────────────────────────────────────────
# По умолчанию сервис работает от root (RUN_AS=root): агент получает право
# редактировать любые файлы (мандат t-261016120111). Ограниченный режим:
# --run-as <user> (+ можно --ask-permissions).
if [ "$DRY_RUN" -eq 0 ] && [ "$RUN_AS" != "root" ]; then
id -u "$RUN_AS" >/dev/null 2>&1 || { log "создаю юзера $RUN_AS (без root-shell в веб-терминале)"; useradd -m -s /bin/bash "$RUN_AS"; }
fi
WRITABLE='-W'; [ "$READONLY" -eq 1 ] && WRITABLE=''
# bypass permissions: --dangerously-skip-permissions прокидывается ПО УМОЛЧАНИЮ
CLAUDE_ARGS=''
[ "$ASK_PERMISSIONS" -eq 0 ] && CLAUDE_ARGS='--dangerously-skip-permissions'
UNIT_PATH="/etc/systemd/system/${SERVICE}.service"
ENV_LINES="Environment=HOME=/home/${USER_NAME}
SERVICE_HOME="/home/${RUN_AS}"
[ "$RUN_AS" = "root" ] && SERVICE_HOME="/root"
ENV_LINES="Environment=HOME=${SERVICE_HOME}
Environment=PATH=/usr/local/bin:/usr/bin:/bin"
if [ ${#UNIT_ENV[@]} -gt 0 ]; then
for e in "${UNIT_ENV[@]}"; do ENV_LINES+="
@ -245,9 +265,9 @@ After=network-online.target
Wants=network-online.target
[Service]
User=${USER_NAME}
User=${RUN_AS}
${ENV_LINES}
ExecStart=/usr/local/bin/ttyd ${WRITABLE} -c ${USER_NAME}:${TOKEN} -p ${PORT} -i ${INTERFACE} claude
ExecStart=/usr/local/bin/ttyd ${WRITABLE} -c ${USER_NAME}:${TOKEN} -p ${PORT} -i ${INTERFACE} claude ${CLAUDE_ARGS}
Restart=always
RestartSec=3
@ -286,4 +306,5 @@ log " URL : http://${IP}:${PORT}"
log " логин : ${USER_NAME}"
log " пароль : ${TOKEN}"
log " сервис : systemctl status ${SERVICE}"
log " режим : User=${RUN_AS}; claude-флаги: ${CLAUDE_ARGS:-—} (bypass permissions по умолчанию, t-261016120111)"
log " первый вход: открой URL, пройди авторизацию claude (или передай --env ANTHROPIC_BASE_URL=... при развёртке)"