#!/bin/bash # # DeepAudit 安全工具一键安装脚本 (增强版) # 自动安装沙盒和外部安全扫描工具 # # 特性: # - 多种安装方式自动回退 # - 网络问题自动重试 # - 详细的错误诊断 # - 支持代理设置 # - 虚拟环境兼容 # set -e # ============================================================ # 配置 # ============================================================ # 版本配置 GITLEAKS_VERSION="8.18.4" OSV_SCANNER_VERSION="1.8.3" TRUFFLEHOG_VERSION="3.80.0" # 重试配置 MAX_RETRIES=3 RETRY_DELAY=2 # 超时配置 DOWNLOAD_TIMEOUT=60 INSTALL_TIMEOUT=120 # 获取脚本目录 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" # 工具安装目录 TOOLS_DIR="$HOME/.local/bin" mkdir -p "$TOOLS_DIR" # ============================================================ # 颜色和日志 # ============================================================ RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' log_info() { echo -e "${BLUE}→${NC} $1"; } log_success() { echo -e "${GREEN}✓${NC} $1"; } log_warning() { echo -e "${YELLOW}!${NC} $1"; } log_error() { echo -e "${RED}✗${NC} $1"; } log_debug() { [[ "$VERBOSE" == "1" ]] && echo -e "${CYAN} $1${NC}"; } log_header() { echo "" echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo -e "${BLUE} $1${NC}" echo -e "${BLUE}═══════════════════════════════════════════════════════════════${NC}" echo "" } # ============================================================ # 工具函数 # ============================================================ # 检查命令是否存在且可执行 command_exists() { command -v "$1" &> /dev/null || return 1 # 额外检查:确保命令真的能运行(排除 pyenv shim 等假阳性) case "$1" in semgrep) "$1" --version &> /dev/null ;; bandit) "$1" --version &> /dev/null ;; safety) "$1" --version &> /dev/null ;; gitleaks) "$1" version &> /dev/null ;; osv-scanner) "$1" --version &> /dev/null ;; trufflehog) "$1" --version &> /dev/null ;; *) return 0 ;; esac } # 检测操作系统 detect_os() { if [[ "$OSTYPE" == "darwin"* ]]; then OS="macos" ARCH=$(uname -m) if [[ "$ARCH" == "arm64" ]]; then ARCH_TYPE="arm64" else ARCH_TYPE="x64" fi elif [[ -f /etc/debian_version ]]; then OS="debian" ARCH_TYPE=$(dpkg --print-architecture 2>/dev/null || echo "amd64") elif [[ -f /etc/redhat-release ]]; then OS="redhat" ARCH_TYPE=$(uname -m) else OS="linux" ARCH_TYPE=$(uname -m) fi # 标准化架构名称 case "$ARCH_TYPE" in x86_64|amd64) ARCH_TYPE="x64" ;; aarch64|arm64) ARCH_TYPE="arm64" ;; esac log_info "检测到系统: $OS ($ARCH_TYPE)" } # 检测 Python 环境 detect_python() { PYTHON_CMD="" PIP_CMD="" # 优先使用虚拟环境 if [[ -n "$VIRTUAL_ENV" ]]; then log_info "检测到虚拟环境: $VIRTUAL_ENV" PYTHON_CMD="python" PIP_CMD="pip" # 检查 python3 elif command_exists python3; then PYTHON_CMD="python3" if command_exists pip3; then PIP_CMD="pip3" else PIP_CMD="python3 -m pip" fi # 检查 python elif command_exists python; then PYTHON_CMD="python" if command_exists pip; then PIP_CMD="pip" else PIP_CMD="python -m pip" fi else log_error "未找到 Python!请先安装 Python 3.8+" return 1 fi # 验证 Python 版本 PYTHON_VERSION=$($PYTHON_CMD --version 2>&1 | grep -oE '[0-9]+\.[0-9]+') log_info "Python 版本: $PYTHON_VERSION (命令: $PYTHON_CMD)" log_debug "pip 命令: $PIP_CMD" # 确保 pip 可用 if ! $PIP_CMD --version &>/dev/null; then log_warning "pip 不可用,尝试安装..." $PYTHON_CMD -m ensurepip --upgrade 2>/dev/null || true fi return 0 } # 带重试的下载函数 download_with_retry() { local url="$1" local output="$2" local description="$3" for attempt in $(seq 1 $MAX_RETRIES); do log_info "下载 $description (尝试 $attempt/$MAX_RETRIES)..." if command_exists curl; then if curl -fsSL --connect-timeout 10 --max-time $DOWNLOAD_TIMEOUT -o "$output" "$url" 2>/dev/null; then log_success "$description 下载成功" return 0 fi elif command_exists wget; then if wget -q --timeout=$DOWNLOAD_TIMEOUT -O "$output" "$url" 2>/dev/null; then log_success "$description 下载成功" return 0 fi else log_error "未找到 curl 或 wget" return 1 fi log_warning "下载失败,${RETRY_DELAY}秒后重试..." sleep $RETRY_DELAY done log_error "$description 下载失败 (已重试 $MAX_RETRIES 次)" return 1 } # 带重试的 pip 安装 pip_install_with_retry() { local package="$1" for attempt in $(seq 1 $MAX_RETRIES); do log_info "安装 $package (尝试 $attempt/$MAX_RETRIES)..." # 尝试方式 1: 普通安装 if $PIP_CMD install "$package" --timeout 60 2>&1; then log_success "$package 安装成功" return 0 fi # 尝试方式 2: --user 标志 log_debug "尝试 --user 安装..." if $PIP_CMD install "$package" --user --timeout 60 2>&1; then log_success "$package 安装成功 (--user)" return 0 fi # 尝试方式 3: --break-system-packages (Python 3.11+ PEP 668) log_debug "尝试 --break-system-packages..." if $PIP_CMD install "$package" --break-system-packages --timeout 60 2>&1; then log_success "$package 安装成功 (--break-system-packages)" return 0 fi # 尝试升级 pip 后重试 if [[ $attempt -eq 1 ]]; then log_debug "升级 pip 后重试..." $PIP_CMD install --upgrade pip --quiet 2>/dev/null || true fi sleep $RETRY_DELAY done # 尝试方式 4: 使用 pipx (推荐的 CLI 工具安装方式) if command -v pipx &> /dev/null; then log_info "尝试使用 pipx 安装 $package..." if pipx install "$package" 2>&1; then log_success "$package 安装成功 (pipx)" return 0 fi fi log_error "$package 安装失败" return 1 } # 添加到 PATH add_to_path() { local dir="$1" # 当前会话 if [[ ":$PATH:" != *":$dir:"* ]]; then export PATH="$dir:$PATH" fi # 持久化到 shell 配置 local shell_rc="" if [[ -f "$HOME/.zshrc" ]]; then shell_rc="$HOME/.zshrc" elif [[ -f "$HOME/.bashrc" ]]; then shell_rc="$HOME/.bashrc" elif [[ -f "$HOME/.bash_profile" ]]; then shell_rc="$HOME/.bash_profile" fi if [[ -n "$shell_rc" ]]; then if ! grep -q "$dir" "$shell_rc" 2>/dev/null; then echo "export PATH=\"$dir:\$PATH\"" >> "$shell_rc" log_debug "已添加 $dir 到 $shell_rc" fi fi } # ============================================================ # Python 工具安装 # ============================================================ install_python_tools() { log_header "安装 Python 安全工具" detect_python || return 1 local tools=("bandit" "safety") local failed=() local installed=() # Semgrep 单独处理(较大) log_info "检查 semgrep..." if command_exists semgrep; then log_success "semgrep 已安装: $(semgrep --version 2>&1 | head -1)" else # 尝试 pip 安装 if pip_install_with_retry "semgrep"; then installed+=("semgrep") # macOS: 尝试 brew 安装 elif [[ "$OS" == "macos" ]] && command -v brew &> /dev/null; then log_info "pip 安装失败,尝试 brew install semgrep..." if brew install semgrep 2>&1; then installed+=("semgrep") log_success "semgrep 安装成功 (brew)" else failed+=("semgrep") fi else failed+=("semgrep") log_warning "semgrep 安装失败,可尝试: brew install semgrep (macOS)" fi fi # 安装其他工具 for tool in "${tools[@]}"; do log_info "检查 $tool..." if command_exists "$tool"; then log_success "$tool 已安装" else if pip_install_with_retry "$tool"; then installed+=("$tool") else failed+=("$tool") fi fi done # 可选: TruffleHog if [[ "$INSTALL_OPTIONAL" == "1" ]] || [[ "$INTERACTIVE" == "1" ]]; then if [[ "$INTERACTIVE" == "1" ]]; then read -p "是否安装 TruffleHog (高级密钥扫描,约100MB)? [y/N] " -n 1 -r echo fi if [[ "$INSTALL_OPTIONAL" == "1" ]] || [[ $REPLY =~ ^[Yy]$ ]]; then if command_exists trufflehog; then log_success "trufflehog 已安装" else pip_install_with_retry "trufflehog" || failed+=("trufflehog") fi fi fi # 报告结果 echo "" if [[ ${#installed[@]} -gt 0 ]]; then log_success "已安装: ${installed[*]}" fi if [[ ${#failed[@]} -gt 0 ]]; then log_warning "安装失败: ${failed[*]}" log_info "💡 提示: 可尝试使用 pipx 安装: pipx install " log_info " 或使用虚拟环境: python3 -m venv venv && source venv/bin/activate && pip install " return 1 fi return 0 } # ============================================================ # 系统工具安装 (macOS) # ============================================================ install_macos_tools() { log_header "安装 macOS 系统工具" local failed=() local installed=() # 检查/安装 Homebrew if ! command_exists brew; then log_warning "Homebrew 未安装" if [[ "$INTERACTIVE" == "1" ]]; then read -p "是否安装 Homebrew? [Y/n] " -n 1 -r echo [[ $REPLY =~ ^[Nn]$ ]] && return 1 fi log_info "安装 Homebrew..." /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" || { log_error "Homebrew 安装失败" log_info "尝试使用二进制方式安装工具..." install_binary_tools return $? } # 配置 Homebrew PATH (Apple Silicon) if [[ -f "/opt/homebrew/bin/brew" ]]; then eval "$(/opt/homebrew/bin/brew shellenv)" fi fi log_success "Homebrew 可用: $(brew --version | head -1)" # Gitleaks log_info "检查 gitleaks..." if command_exists gitleaks; then log_success "gitleaks 已安装: $(gitleaks version 2>&1 | head -1)" else log_info "安装 gitleaks..." if brew install gitleaks 2>/dev/null; then installed+=("gitleaks") log_success "gitleaks 安装成功" else log_warning "brew 安装失败,尝试二进制安装..." install_gitleaks_binary || failed+=("gitleaks") fi fi # OSV-Scanner log_info "检查 osv-scanner..." if command_exists osv-scanner; then log_success "osv-scanner 已安装" else log_info "安装 osv-scanner..." if brew install osv-scanner 2>/dev/null; then installed+=("osv-scanner") log_success "osv-scanner 安装成功" else log_warning "brew 安装失败,尝试二进制安装..." install_osv_scanner_binary || failed+=("osv-scanner") fi fi # 可选: TruffleHog (brew) if [[ "$INSTALL_OPTIONAL" == "1" ]]; then if ! command_exists trufflehog; then log_info "安装 trufflehog (brew)..." brew install trufflehog 2>/dev/null || log_warning "trufflehog brew 安装失败" fi fi # 报告结果 echo "" if [[ ${#installed[@]} -gt 0 ]]; then log_success "已安装: ${installed[*]}" fi if [[ ${#failed[@]} -gt 0 ]]; then log_warning "安装失败: ${failed[*]}" return 1 fi return 0 } # ============================================================ # 二进制工具安装 (回退方案) # ============================================================ install_binary_tools() { log_info "使用二进制方式安装工具..." install_gitleaks_binary install_osv_scanner_binary } install_gitleaks_binary() { log_info "下载 Gitleaks 二进制..." local arch_suffix="" case "$OS-$ARCH_TYPE" in macos-x64) arch_suffix="darwin_x64" ;; macos-arm64) arch_suffix="darwin_arm64" ;; *-x64) arch_suffix="linux_x64" ;; *-arm64) arch_suffix="linux_arm64" ;; *) arch_suffix="linux_x64" ;; esac local url="https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_${arch_suffix}.tar.gz" local tmp_file="/tmp/gitleaks.tar.gz" if download_with_retry "$url" "$tmp_file" "Gitleaks"; then tar -xzf "$tmp_file" -C "$TOOLS_DIR" gitleaks 2>/dev/null || { # 某些版本可能没有子目录 tar -xzf "$tmp_file" -C "/tmp" 2>/dev/null mv /tmp/gitleaks "$TOOLS_DIR/" 2>/dev/null || true } chmod +x "$TOOLS_DIR/gitleaks" rm -f "$tmp_file" add_to_path "$TOOLS_DIR" log_success "Gitleaks 二进制安装成功" return 0 fi return 1 } install_osv_scanner_binary() { log_info "下载 OSV-Scanner 二进制..." local arch_suffix="" case "$OS-$ARCH_TYPE" in macos-x64) arch_suffix="darwin_amd64" ;; macos-arm64) arch_suffix="darwin_arm64" ;; *-x64) arch_suffix="linux_amd64" ;; *-arm64) arch_suffix="linux_arm64" ;; *) arch_suffix="linux_amd64" ;; esac local url="https://github.com/google/osv-scanner/releases/download/v${OSV_SCANNER_VERSION}/osv-scanner_${arch_suffix}" local target="$TOOLS_DIR/osv-scanner" if download_with_retry "$url" "$target" "OSV-Scanner"; then chmod +x "$target" add_to_path "$TOOLS_DIR" log_success "OSV-Scanner 二进制安装成功" return 0 fi return 1 } install_trufflehog_binary() { log_info "下载 TruffleHog 二进制..." local arch_suffix="" case "$OS-$ARCH_TYPE" in macos-x64) arch_suffix="darwin_amd64" ;; macos-arm64) arch_suffix="darwin_arm64" ;; *-x64) arch_suffix="linux_amd64" ;; *-arm64) arch_suffix="linux_arm64" ;; *) arch_suffix="linux_amd64" ;; esac local url="https://github.com/trufflesecurity/trufflehog/releases/download/v${TRUFFLEHOG_VERSION}/trufflehog_${TRUFFLEHOG_VERSION}_${arch_suffix}.tar.gz" local tmp_file="/tmp/trufflehog.tar.gz" if download_with_retry "$url" "$tmp_file" "TruffleHog"; then tar -xzf "$tmp_file" -C "$TOOLS_DIR" trufflehog 2>/dev/null || { tar -xzf "$tmp_file" -C "/tmp" 2>/dev/null mv /tmp/trufflehog "$TOOLS_DIR/" 2>/dev/null || true } chmod +x "$TOOLS_DIR/trufflehog" rm -f "$tmp_file" add_to_path "$TOOLS_DIR" log_success "TruffleHog 二进制安装成功" return 0 fi return 1 } # ============================================================ # Linux 工具安装 # ============================================================ install_linux_tools() { log_header "安装 Linux 系统工具" # 直接使用二进制安装(最可靠) install_binary_tools } # ============================================================ # Docker 沙盒安装 # ============================================================ install_docker_sandbox() { log_header "配置 Docker 沙盒" # 检查 Docker if ! command_exists docker; then log_error "Docker 未安装!" log_info "macOS: brew install --cask docker" log_info "Linux: https://docs.docker.com/engine/install/" return 1 fi # 检查 Docker 是否运行 if ! docker info &> /dev/null; then log_error "Docker 未运行!请启动 Docker。" # macOS: 尝试启动 Docker Desktop if [[ "$OS" == "macos" ]]; then log_info "尝试启动 Docker Desktop..." open -a Docker 2>/dev/null || true log_info "等待 Docker 启动 (最多 60 秒)..." for i in {1..12}; do sleep 5 if docker info &> /dev/null; then log_success "Docker 已启动" break fi echo -n "." done echo "" if ! docker info &> /dev/null; then log_error "Docker 启动超时,请手动启动 Docker Desktop" return 1 fi else return 1 fi fi log_success "Docker 已运行" # 构建沙盒镜像 local sandbox_dir="$PROJECT_ROOT/docker/sandbox" local dockerfile="$sandbox_dir/Dockerfile" if [[ ! -f "$dockerfile" ]]; then log_warning "沙盒 Dockerfile 不存在,创建默认配置..." mkdir -p "$sandbox_dir" create_sandbox_dockerfile "$sandbox_dir" fi log_info "构建 DeepAudit 沙盒镜像..." cd "$sandbox_dir" # 带重试的构建 for attempt in $(seq 1 $MAX_RETRIES); do log_info "构建镜像 (尝试 $attempt/$MAX_RETRIES)..." if docker build -t deepaudit-sandbox:latest -f Dockerfile . 2>&1; then log_success "沙盒镜像构建成功: deepaudit-sandbox:latest" # 验证 log_info "验证沙盒镜像..." if docker run --rm deepaudit-sandbox:latest python3 --version; then log_success "Python 环境正常" fi if docker run --rm deepaudit-sandbox:latest node --version 2>/dev/null; then log_success "Node.js 环境正常" fi return 0 fi log_warning "构建失败,重试..." sleep $RETRY_DELAY done log_error "沙盒镜像构建失败" return 1 } create_sandbox_dockerfile() { local dir="$1" cat > "$dir/Dockerfile" << 'EOF' # DeepAudit 安全沙盒 FROM python:3.11-slim-bookworm # 安装基础工具 RUN apt-get update && apt-get install -y --no-install-recommends \ curl wget netcat-openbsd dnsutils iputils-ping ca-certificates git \ && rm -rf /var/lib/apt/lists/* # 安装 Node.js 20 RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \ && apt-get install -y nodejs \ && rm -rf /var/lib/apt/lists/* # 创建非特权用户 RUN groupadd -g 1000 sandbox \ && useradd -u 1000 -g sandbox -m -s /bin/bash sandbox # 安装 Python 安全测试库 RUN pip install --no-cache-dir \ requests httpx aiohttp beautifulsoup4 lxml \ pycryptodome paramiko pyjwt python-jose sqlparse # 设置工作目录 WORKDIR /workspace RUN mkdir -p /workspace /tmp/sandbox \ && chown -R sandbox:sandbox /workspace /tmp/sandbox USER sandbox ENV PYTHONDONTWRITEBYTECODE=1 PYTHONUNBUFFERED=1 HOME=/home/sandbox CMD ["/bin/bash"] EOF log_success "已创建沙盒 Dockerfile" } # ============================================================ # 验证安装 # ============================================================ verify_installation() { log_header "验证安装结果" local tools=( "semgrep:Semgrep 静态分析" "bandit:Bandit Python安全" "safety:Safety 依赖漏洞" "gitleaks:Gitleaks 密钥检测" "osv-scanner:OSV-Scanner 漏洞" "trufflehog:TruffleHog 密钥" "npm:NPM Audit" "docker:Docker" ) local installed=0 local total=${#tools[@]} echo "" printf "%-18s %-12s %-30s\n" "工具" "状态" "版本/路径" echo "────────────────────────────────────────────────────────────" for tool_info in "${tools[@]}"; do IFS=':' read -r tool desc <<< "$tool_info" if command_exists "$tool"; then local version="" case "$tool" in semgrep) version=$(semgrep --version 2>&1 | head -1) ;; bandit) version=$(bandit --version 2>&1 | head -1) ;; safety) version=$(safety --version 2>&1 | head -1) ;; gitleaks) version=$(gitleaks version 2>&1 | head -1) ;; osv-scanner) version=$(osv-scanner --version 2>&1 | head -1) ;; trufflehog) version=$(trufflehog --version 2>&1 | head -1) ;; npm) version=$(npm --version 2>&1) ;; docker) version=$(docker --version 2>&1 | cut -d' ' -f3) ;; esac version="${version:0:28}" printf "%-18s ${GREEN}%-12s${NC} %-30s\n" "$tool" "已安装" "$version" ((installed++)) else printf "%-18s ${YELLOW}%-12s${NC} %-30s\n" "$tool" "未安装" "-" fi done echo "────────────────────────────────────────────────────────────" # Docker 沙盒检查 if command_exists docker && docker info &>/dev/null; then if docker image inspect deepaudit-sandbox:latest &>/dev/null; then echo "" log_success "Docker 沙盒镜像: deepaudit-sandbox:latest ✓" else echo "" log_warning "Docker 沙盒镜像未构建" fi fi echo "" log_info "安装统计: $installed/$total 个工具可用" # 检查 PATH if [[ ":$PATH:" != *":$TOOLS_DIR:"* ]]; then log_warning "请重启终端或运行: source ~/.zshrc (或 ~/.bashrc)" fi if [[ $installed -ge 5 ]]; then log_success "核心安全工具已就绪!" return 0 else log_warning "部分工具未安装,某些功能可能受限" return 1 fi } # ============================================================ # 更新环境配置 # ============================================================ update_env_config() { log_header "更新环境配置" local env_file="$PROJECT_ROOT/backend/.env" if [[ ! -f "$env_file" ]]; then log_warning ".env 文件不存在,跳过配置更新" return 0 fi if grep -q "SANDBOX_IMAGE" "$env_file"; then log_info "沙盒配置已存在于 .env 文件中" else log_info "添加沙盒配置到 .env 文件..." cat >> "$env_file" << 'EOF' # ============================================= # 沙盒配置 (自动添加) # ============================================= SANDBOX_IMAGE=deepaudit-sandbox:latest SANDBOX_MEMORY_LIMIT=512m SANDBOX_CPU_LIMIT=1.0 SANDBOX_TIMEOUT=60 SANDBOX_NETWORK_MODE=none EOF log_success "沙盒配置已添加到 .env" fi } # ============================================================ # 显示帮助 # ============================================================ show_help() { cat << 'EOF' DeepAudit 安全工具一键安装脚本 用法: ./setup_security_tools.sh [选项] 选项: -a, --all 全部安装 (默认交互式) -p, --python 仅安装 Python 工具 -s, --system 仅安装系统工具 -d, --docker 仅构建 Docker 沙盒 -v, --verify 仅验证安装状态 -o, --optional 包含可选工具 (TruffleHog) --verbose 显示详细输出 -h, --help 显示帮助 示例: ./setup_security_tools.sh # 交互式安装 ./setup_security_tools.sh -a # 自动全部安装 ./setup_security_tools.sh -a -o # 全部安装 + 可选工具 ./setup_security_tools.sh -v # 仅检查状态 EOF } # ============================================================ # 主函数 # ============================================================ main() { # 解析参数 INTERACTIVE="1" INSTALL_ALL="" INSTALL_PYTHON="" INSTALL_SYSTEM="" INSTALL_DOCKER="" VERIFY_ONLY="" INSTALL_OPTIONAL="" VERBOSE="" while [[ $# -gt 0 ]]; do case $1 in -a|--all) INSTALL_ALL="1"; INTERACTIVE="" ;; -p|--python) INSTALL_PYTHON="1"; INTERACTIVE="" ;; -s|--system) INSTALL_SYSTEM="1"; INTERACTIVE="" ;; -d|--docker) INSTALL_DOCKER="1"; INTERACTIVE="" ;; -v|--verify) VERIFY_ONLY="1"; INTERACTIVE="" ;; -o|--optional) INSTALL_OPTIONAL="1" ;; --verbose) VERBOSE="1" ;; -h|--help) show_help; exit 0 ;; *) log_error "未知选项: $1"; show_help; exit 1 ;; esac shift done # 显示标题 echo "" echo -e "${BLUE}╔═══════════════════════════════════════════════════════════════╗${NC}" echo -e "${BLUE}║ ║${NC}" echo -e "${BLUE}║ 🔐 DeepAudit 安全工具一键安装脚本 (增强版) ║${NC}" echo -e "${BLUE}║ ║${NC}" echo -e "${BLUE}╚═══════════════════════════════════════════════════════════════╝${NC}" echo "" # 检测系统 detect_os # 仅验证模式 if [[ "$VERIFY_ONLY" == "1" ]]; then verify_installation exit $? fi # 自动安装模式 if [[ "$INSTALL_ALL" == "1" ]]; then install_python_tools if [[ "$OS" == "macos" ]]; then install_macos_tools else install_linux_tools fi install_docker_sandbox update_env_config verify_installation exit $? fi # 单独安装模式 if [[ "$INSTALL_PYTHON" == "1" ]]; then install_python_tools verify_installation exit $? fi if [[ "$INSTALL_SYSTEM" == "1" ]]; then if [[ "$OS" == "macos" ]]; then install_macos_tools else install_linux_tools fi verify_installation exit $? fi if [[ "$INSTALL_DOCKER" == "1" ]]; then install_docker_sandbox update_env_config verify_installation exit $? fi # 交互式模式 echo "请选择要安装的组件:" echo " 1) 全部安装 (推荐)" echo " 2) 仅 Python 工具 (pip)" echo " 3) 仅系统工具 (brew/binary)" echo " 4) 仅 Docker 沙盒" echo " 5) 仅验证安装状态" echo " 6) 退出" echo "" read -p "请输入选项 [1-6]: " choice case $choice in 1) install_python_tools if [[ "$OS" == "macos" ]]; then install_macos_tools else install_linux_tools fi install_docker_sandbox update_env_config verify_installation ;; 2) install_python_tools; verify_installation ;; 3) if [[ "$OS" == "macos" ]]; then install_macos_tools else install_linux_tools fi verify_installation ;; 4) install_docker_sandbox; update_env_config; verify_installation ;; 5) verify_installation ;; 6) echo "退出"; exit 0 ;; *) log_error "无效选项"; exit 1 ;; esac log_header "安装完成" echo "" echo "下一步操作:" echo " 1. 重启终端使 PATH 生效" echo " 2. 启动后端: cd backend && uvicorn app.main:app --reload" echo " 3. 在 Agent 审计中测试工具" echo "" } main "$@"