feat: 审批流程模块 (T审批A审批)
- 新增 backend/app/api/approval.py 审批API - 前端H5支持发起审批、审批操作 - 添加审批卡片弹窗组件 - 路由注册审批模块
This commit is contained in:
@@ -0,0 +1,342 @@
|
||||
#!/bin/bash
|
||||
# =============================================================================
|
||||
# 安全审计脚本
|
||||
# =============================================================================
|
||||
# 用途: 跑 5 大安全工具,生成审计报告
|
||||
# 1. bandit - Python 代码静态分析
|
||||
# 2. safety - Python 依赖漏洞
|
||||
# 3. pip-audit - Python 依赖漏洞(更准)
|
||||
# 4. npm audit - JS 依赖漏洞
|
||||
# 5. gitleaks - 仓库 secret 扫描
|
||||
#
|
||||
# 用法:
|
||||
# bash scripts/security-audit.sh # 跑全部
|
||||
# bash scripts/security-audit.sh --python # 只跑 Python 套件
|
||||
# bash scripts/security-audit.sh --js # 只跑 JS 套件
|
||||
# bash scripts/security-audit.sh --secrets # 只跑 secret 扫描
|
||||
# bash scripts/security-audit.sh --output FILE # 自定义报告路径
|
||||
#
|
||||
# 退出码:
|
||||
# 0 = 全过 / 仅 INFO
|
||||
# 1 = 有 LOW
|
||||
# 2 = 有 MEDIUM
|
||||
# 3 = 有 HIGH/CRITICAL
|
||||
# =============================================================================
|
||||
|
||||
set -e
|
||||
|
||||
# 颜色
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
info() { echo -e "${BLUE}[INFO]${NC} $1"; }
|
||||
ok() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
error() { echo -e "${RED}[ERROR]${NC} $1"; }
|
||||
|
||||
# 路径
|
||||
PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
cd "$PROJECT_ROOT"
|
||||
REPORT="docs/审计报告/security_audit_$(date +%Y%m%d).md"
|
||||
LOG_DIR="/tmp/security-audit-$(date +%Y%m%d-%H%M%S)"
|
||||
mkdir -p "$LOG_DIR" "$(dirname "$REPORT")"
|
||||
|
||||
# 参数
|
||||
RUN_PYTHON=true
|
||||
RUN_JS=true
|
||||
RUN_SECRETS=true
|
||||
for arg in "$@"; do
|
||||
case $arg in
|
||||
--python) RUN_PYTHON=true; RUN_JS=false; RUN_SECRETS=false ;;
|
||||
--js) RUN_PYTHON=false; RUN_JS=true; RUN_SECRETS=false ;;
|
||||
--secrets) RUN_PYTHON=false; RUN_JS=false; RUN_SECRETS=true ;;
|
||||
--output) REPORT="$2" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# 计数器
|
||||
PASS=0
|
||||
WARN=0
|
||||
FAIL=0
|
||||
CRITICAL=0
|
||||
|
||||
# 报告头
|
||||
cat > "$REPORT" <<EOF
|
||||
# 安全审计报告
|
||||
|
||||
**审计日期**: $(date +%Y-%m-%d)
|
||||
**审计人**: Claude(自动化跑批)
|
||||
**工具**: bandit / safety / pip-audit / npm audit / gitleaks
|
||||
**关联**: [[风险跟踪表]]
|
||||
|
||||
---
|
||||
|
||||
## 1. 跑批概览
|
||||
|
||||
| 工具 | 范围 | 结果 |
|
||||
|---|---|---|
|
||||
EOF
|
||||
|
||||
# =============================================================================
|
||||
# 1. bandit (Python 静态分析)
|
||||
# =============================================================================
|
||||
if [ "$RUN_PYTHON" = true ]; then
|
||||
info "── 1/5 bandit: Python 静态分析"
|
||||
|
||||
if ! command -v bandit &> /dev/null; then
|
||||
warn "bandit 未安装,跑: pip install bandit"
|
||||
echo "| bandit | Python 静态 | ⚠️ 工具未安装 |" >> "$REPORT"
|
||||
else
|
||||
if bandit -r backend/ -f json -o "$LOG_DIR/bandit.json" 2> "$LOG_DIR/bandit.err" ; then
|
||||
ok "bandit: 无问题"
|
||||
PASS=$((PASS+1))
|
||||
echo "| bandit | Python 静态 | ✅ 无问题 |" >> "$REPORT"
|
||||
else
|
||||
# 解析 bandit JSON 报告
|
||||
if command -v jq &> /dev/null; then
|
||||
HIGH=$(jq '[.results[] | select(.issue_severity=="HIGH")] | length' "$LOG_DIR/bandit.json" 2>/dev/null || echo 0)
|
||||
MED=$(jq '[.results[] | select(.issue_severity=="MEDIUM")] | length' "$LOG_DIR/bandit.json" 2>/dev/null || echo 0)
|
||||
LOW=$(jq '[.results[] | select(.issue_severity=="LOW")] | length' "$LOG_DIR/bandit.json" 2>/dev/null || echo 0)
|
||||
else
|
||||
HIGH=0; MED=0; LOW=0
|
||||
fi
|
||||
warn "bandit: HIGH=$HIGH MED=$MED LOW=$LOW"
|
||||
[ $HIGH -gt 0 ] && FAIL=$((FAIL+HIGH)) || true
|
||||
[ $MED -gt 0 ] && WARN=$((WARN+MED)) || true
|
||||
[ $LOW -gt 0 ] && WARN=$((WARN+LOW)) || true
|
||||
echo "| bandit | Python 静态 | ⚠️ HIGH=$HIGH MED=$MED LOW=$LOW |" >> "$REPORT"
|
||||
|
||||
# 列出问题
|
||||
if [ $HIGH -gt 0 ] || [ $MED -gt 0 ]; then
|
||||
cat >> "$REPORT" <<EOR
|
||||
|
||||
### bandit 详情
|
||||
|
||||
| 文件 | 行 | 严重度 | 问题 |
|
||||
|---|---|---|---|
|
||||
EOR
|
||||
jq -r '.results[] | "| \(.filename) | \(.line_number) | \(.issue_severity) | \(.issue_text | gsub("\n"; " ")) |"' "$LOG_DIR/bandit.json" >> "$REPORT" 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# 2. safety (Python 依赖漏洞)
|
||||
# =============================================================================
|
||||
if [ "$RUN_PYTHON" = true ]; then
|
||||
info "── 2/5 safety: Python 依赖漏洞"
|
||||
|
||||
if ! command -v safety &> /dev/null; then
|
||||
warn "safety 未安装,跑: pip install safety"
|
||||
echo "| safety | Python 依赖 | ⚠️ 工具未安装 |" >> "$REPORT"
|
||||
else
|
||||
if safety check --file=backend/requirements.txt --output=text > "$LOG_DIR/safety.txt" 2>&1; then
|
||||
ok "safety: 无漏洞"
|
||||
PASS=$((PASS+1))
|
||||
echo "| safety | Python 依赖 | ✅ 无漏洞 |" >> "$REPORT"
|
||||
else
|
||||
VULN_COUNT=$(grep -c "VULNERABLE" "$LOG_DIR/safety.txt" 2>/dev/null || echo 0)
|
||||
warn "safety: $VULN_COUNT 个漏洞"
|
||||
[ $VULN_COUNT -gt 0 ] && FAIL=$((FAIL+VULN_COUNT)) || true
|
||||
echo "| safety | Python 依赖 | 🔴 $VULN_COUNT 个漏洞 |" >> "$REPORT"
|
||||
cat >> "$REPORT" <<EOR
|
||||
|
||||
### safety 详情
|
||||
|
||||
\`\`\`
|
||||
$(cat "$LOG_DIR/safety.txt" | head -30)
|
||||
\`\`\`
|
||||
EOR
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# 3. pip-audit (Python 依赖漏洞,更准)
|
||||
# =============================================================================
|
||||
if [ "$RUN_PYTHON" = true ]; then
|
||||
info "── 3/5 pip-audit: Python 依赖漏洞(精确)"
|
||||
|
||||
if ! command -v pip-audit &> /dev/null; then
|
||||
warn "pip-audit 未安装,跑: pip install pip-audit"
|
||||
echo "| pip-audit | Python 依赖 | ⚠️ 工具未安装 |" >> "$REPORT"
|
||||
else
|
||||
if pip-audit -r backend/requirements.txt --format=json > "$LOG_DIR/pip-audit.json" 2>&1; then
|
||||
ok "pip-audit: 无漏洞"
|
||||
PASS=$((PASS+1))
|
||||
echo "| pip-audit | Python 依赖 | ✅ 无漏洞 |" >> "$REPORT"
|
||||
else
|
||||
VULN_COUNT=$(python3 -c "import json; d=json.load(open('$LOG_DIR/pip-audit.json')); print(len(d.get('vulnerabilities', [])))" 2>/dev/null || echo 0)
|
||||
warn "pip-audit: $VULN_COUNT 个漏洞"
|
||||
[ $VULN_COUNT -gt 0 ] && FAIL=$((FAIL+VULN_COUNT)) || true
|
||||
echo "| pip-audit | Python 依赖 | 🔴 $VULN_COUNT 个漏洞 |" >> "$REPORT"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# 4. npm audit (JS 依赖漏洞)
|
||||
# =============================================================================
|
||||
if [ "$RUN_JS" = true ]; then
|
||||
info "── 4/5 npm audit: JS 依赖漏洞"
|
||||
|
||||
for d in frontend-admin frontend-agent frontend-h5 frontend-portal; do
|
||||
if [ -d "$d" ]; then
|
||||
info " → $d"
|
||||
if [ -f "$d/package-lock.json" ]; then
|
||||
cd "$d"
|
||||
if npm audit --json > "$LOG_DIR/npm-$d.json" 2>&1; then
|
||||
ok " $d: 无漏洞"
|
||||
PASS=$((PASS+1))
|
||||
else
|
||||
VULN=$(python3 -c "import json; d=json.load(open('$LOG_DIR/npm-$d.json')); m=d.get('metadata',{}).get('vulnerabilities',{}); print(m.get('total', 0))" 2>/dev/null || echo 0)
|
||||
CRIT=$(python3 -c "import json; d=json.load(open('$LOG_DIR/npm-$d.json')); m=d.get('metadata',{}).get('vulnerabilities',{}); print(m.get('critical', 0))" 2>/dev/null || echo 0)
|
||||
HIGH=$(python3 -c "import json; d=json.load(open('$LOG_DIR/npm-$d.json')); m=d.get('metadata',{}).get('vulnerabilities',{}); print(m.get('high', 0))" 2>/dev/null || echo 0)
|
||||
warn " $d: total=$VULN critical=$CRIT high=$HIGH"
|
||||
[ $CRIT -gt 0 ] && CRITICAL=$((CRITICAL+CRIT)) || true
|
||||
[ $HIGH -gt 0 ] && FAIL=$((FAIL+HIGH)) || true
|
||||
[ $VULN -gt 0 ] && WARN=$((WARN+VULN)) || true
|
||||
echo "| npm-audit-$d | JS 依赖 | ⚠️ total=$VULN crit=$CRIT high=$HIGH |" >> "$REPORT"
|
||||
fi
|
||||
cd "$PROJECT_ROOT"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# 5. gitleaks (Secret 扫描)
|
||||
# =============================================================================
|
||||
if [ "$RUN_SECRETS" = true ]; then
|
||||
info "── 5/5 gitleaks: Secret 扫描"
|
||||
|
||||
if ! command -v gitleaks &> /dev/null; then
|
||||
warn "gitleaks 未安装,跑(可选):"
|
||||
echo " brew install gitleaks # Mac"
|
||||
echo " scoop install gitleaks # Windows"
|
||||
echo " docker run -v \$(pwd):/repo zricethezav/gitleaks:latest detect --source /repo --no-git -v"
|
||||
echo "| gitleaks | Secret 扫描 | ⚠️ 工具未安装 |" >> "$REPORT"
|
||||
else
|
||||
if gitleaks detect --source . --no-git -v > "$LOG_DIR/gitleaks.txt" 2>&1; then
|
||||
ok "gitleaks: 无 secret 泄露"
|
||||
PASS=$((PASS+1))
|
||||
echo "| gitleaks | Secret 扫描 | ✅ 无泄露 |" >> "$REPORT"
|
||||
else
|
||||
LEAK_COUNT=$(grep -c "Finding:" "$LOG_DIR/gitleaks.txt" 2>/dev/null || echo 0)
|
||||
if [ "$LEAK_COUNT" -gt 0 ]; then
|
||||
warn "gitleaks: 发现 $LEAK_COUNT 个 secret"
|
||||
CRITICAL=$((CRITICAL+LEAK_COUNT))
|
||||
echo "| gitleaks | Secret 扫描 | 🔴 $LEAK_COUNT 个 secret |" >> "$REPORT"
|
||||
|
||||
cat >> "$REPORT" <<EOR
|
||||
|
||||
### gitleaks 详情
|
||||
|
||||
\`\`\`
|
||||
$(head -50 "$LOG_DIR/gitleaks.txt")
|
||||
\`\`\`
|
||||
|
||||
> 🚨 **CRITICAL**:发现 secret 泄露,立即:
|
||||
> 1. 撤销泄露的 token / 密钥
|
||||
> 2. 创新凭据
|
||||
> 3. 加进 .gitignore(防二次泄露)
|
||||
> 4. 改所有引用
|
||||
EOR
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# =============================================================================
|
||||
# 总结
|
||||
# =============================================================================
|
||||
cat >> "$REPORT" <<EOF
|
||||
|
||||
---
|
||||
|
||||
## 2. 总结
|
||||
|
||||
| 等级 | 数量 |
|
||||
|---|---|
|
||||
| ✅ PASS | $PASS |
|
||||
| ⚠️ WARN | $WARN |
|
||||
| 🔴 FAIL | $FAIL |
|
||||
| 🚨 CRITICAL | $CRITICAL |
|
||||
|
||||
EOF
|
||||
|
||||
if [ $CRITICAL -gt 0 ]; then
|
||||
cat >> "$REPORT" <<EOF
|
||||
## 🚨 阻断
|
||||
|
||||
发现 **$CRITICAL** 个 CRITICAL 问题,**必须**:
|
||||
1. 撤销所有泄露的 secret(token / 密钥 / 凭据)
|
||||
2. 创新凭据 + 配新引用
|
||||
3. 加进 .gitignore
|
||||
4. 评审所有引用 + 改
|
||||
|
||||
## 下一步
|
||||
|
||||
1. 修所有 CRITICAL(立即)
|
||||
2. 修所有 FAIL(本周末)
|
||||
3. 评估 WARN(下迭代)
|
||||
4. 加 CI 自动化跑(本季度)
|
||||
EOF
|
||||
echo ""
|
||||
error "🚨 CRITICAL: $CRITICAL 个 secret 泄露或 CRITICAL 漏洞,必须立即处理"
|
||||
exit 3
|
||||
fi
|
||||
|
||||
if [ $FAIL -gt 0 ]; then
|
||||
cat >> "$REPORT" <<EOF
|
||||
## 🛑 FAIL
|
||||
|
||||
发现 **$FAIL** 个 FAIL(HIGH)级问题,本周末修。
|
||||
|
||||
## 下一步
|
||||
|
||||
1. 修 FAIL(本周末)
|
||||
2. 评估 WARN(下迭代)
|
||||
3. 加 CI 自动化跑
|
||||
EOF
|
||||
echo ""
|
||||
warn "🛑 FAIL: $FAIL 个 HIGH 级问题,本周末修"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
if [ $WARN -gt 0 ]; then
|
||||
cat >> "$REPORT" <<EOF
|
||||
## ⚠️ WARN
|
||||
|
||||
发现 **$WARN** 个 MEDIUM/LOW 级问题,下迭代评估。
|
||||
|
||||
## 下一步
|
||||
|
||||
1. 评估 WARN(下迭代)
|
||||
2. 加 CI 自动化跑
|
||||
3. 跑批频率:每周一次
|
||||
EOF
|
||||
echo ""
|
||||
warn "⚠️ WARN: $WARN 个问题,下迭代评估"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cat >> "$REPORT" <<EOF
|
||||
## ✅ 全部通过
|
||||
|
||||
无 CRITICAL / FAIL / WARN,健康度 100%。
|
||||
|
||||
## 后续
|
||||
|
||||
1. 加 CI 自动化跑(每周 + 推送触发)
|
||||
2. 跑批频率:每周一次 + 重大变更后
|
||||
EOF
|
||||
|
||||
echo ""
|
||||
ok "✅ 全部通过,健康度 100%"
|
||||
ok "报告: $REPORT"
|
||||
exit 0
|
||||
Reference in New Issue
Block a user