14e20cae89
- 使用 awk 在 #[cfg(test)] 处提前退出,跳过测试代码 - 替换多个 grep -v 管道为单一 awk 处理 - 修复乱码字符
156 lines
7.2 KiB
Bash
Executable File
156 lines
7.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
# =============================================================================
|
||
# libsmx 安全性扫描脚本
|
||
# =============================================================================
|
||
# 被 CI 工作流调用,执行以下检查:
|
||
# 1. 扫描非测试代码中的 panic!/unwrap()/expect()
|
||
# 2. 检查是否有硬编码密钥泄露
|
||
# 3. 验证 Cargo.toml 版本号与 Git Tag 匹配(仅在 tag 构建时)
|
||
# =============================================================================
|
||
|
||
set -euo pipefail
|
||
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
NC='\033[0m'
|
||
|
||
ERRORS=0
|
||
|
||
pass() { echo -e "${GREEN}[PASS]${NC} $1"; }
|
||
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||
fail() { echo -e "${RED}[FAIL]${NC} $1"; ERRORS=$((ERRORS + 1)); }
|
||
|
||
echo "=========================================="
|
||
echo " libsmx Security Sanity Checks"
|
||
echo "=========================================="
|
||
echo ""
|
||
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
# 1. 扫描非测试代码中的 panic!/unwrap()/expect()
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
# Reason: 密码学库不应在非测试代码中 panic,应返回 Result/Option
|
||
echo "--- 检查 panic/unwrap/expect ---"
|
||
|
||
# 排除规则:
|
||
# - #[cfg(test)] 块和 mod tests 块内的代码
|
||
# - benches/ 和 tests/ 目录
|
||
# - 白名单:try_into().unwrap() 用于固定大小切片转换(已知安全)
|
||
|
||
# Reason: 逐行 grep -v 无法排除 #[cfg(test)] 块内部的代码,
|
||
# 改用 awk 先将每个文件中 #[cfg(test)] 之后的行全部剥离,再 grep。
|
||
PANIC_HITS=$(find src/ -name '*.rs' -exec awk '/#\[cfg\(test\)\]/{exit} {print FILENAME":"NR":"$0}' {} \; \
|
||
| grep 'panic!\|\.unwrap()\|\.expect(' \
|
||
|| true)
|
||
|
||
if [ -n "$PANIC_HITS" ]; then
|
||
# 统计行数
|
||
COUNT=$(echo "$PANIC_HITS" | wc -l)
|
||
|
||
# 分类统计
|
||
UNWRAP_COUNT=$(echo "$PANIC_HITS" | grep -c '\.unwrap()' || true)
|
||
EXPECT_COUNT=$(echo "$PANIC_HITS" | grep -c '\.expect(' || true)
|
||
PANIC_COUNT=$(echo "$PANIC_HITS" | grep -c 'panic!' || true)
|
||
|
||
# try_into().unwrap() 是固定大小切片转换的惯用法,已知不会 panic
|
||
SAFE_UNWRAP=$(echo "$PANIC_HITS" | grep -c 'try_into().unwrap()' || true)
|
||
UNSAFE_UNWRAP=$((UNWRAP_COUNT - SAFE_UNWRAP))
|
||
|
||
if [ "$PANIC_COUNT" -gt 0 ]; then
|
||
fail "发现 $PANIC_COUNT 处 panic! 调用(非测试代码)"
|
||
echo "$PANIC_HITS" | grep 'panic!' | head -5
|
||
fi
|
||
|
||
if [ "$UNSAFE_UNWRAP" -gt 0 ]; then
|
||
warn "发现 $UNSAFE_UNWRAP 处 .unwrap() 调用(不含 try_into().unwrap())"
|
||
echo "$PANIC_HITS" | grep '\.unwrap()' | grep -v 'try_into().unwrap()' | head -5
|
||
fi
|
||
|
||
if [ "$EXPECT_COUNT" -gt 0 ]; then
|
||
warn "发现 $EXPECT_COUNT 处 .expect() 调用"
|
||
echo "$PANIC_HITS" | grep '\.expect(' | head -5
|
||
fi
|
||
|
||
if [ "$SAFE_UNWRAP" -gt 0 ]; then
|
||
echo -e " ${GREEN}(白名单)${NC} $SAFE_UNWRAP 处 try_into().unwrap()(固定大小切片转换,已知安全)"
|
||
fi
|
||
else
|
||
pass "非测试代码中无 panic/unwrap/expect"
|
||
fi
|
||
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
# 2. 检查硬编码密钥/敏感信息
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
echo ""
|
||
echo "--- 检查硬编码敏感信息 ---"
|
||
|
||
# Reason: 防止私钥、密码等敏感信息被提交到仓库
|
||
SENSITIVE_PATTERNS='(private.?key|secret.?key|password|passwd|api.?key|token)\s*=\s*["\x27][^\x27"]+["\x27]'
|
||
SENSITIVE_HITS=$(find src/ -name '*.rs' -exec awk '/#\[cfg\(test\)\]/{exit} {print FILENAME":"NR":"$0}' {} \; \
|
||
| grep -iE "$SENSITIVE_PATTERNS" \
|
||
|| true)
|
||
|
||
if [ -n "$SENSITIVE_HITS" ]; then
|
||
warn "发现疑似硬编码敏感信息(请人工审查):"
|
||
echo "$SENSITIVE_HITS" | head -5
|
||
else
|
||
pass "未发现硬编码敏感信息"
|
||
fi
|
||
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
# 3. 验证 Cargo.toml 版本号与 Git Tag 匹配
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
echo ""
|
||
echo "--- 检查版本号一致性 ---"
|
||
|
||
CARGO_VERSION=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
|
||
echo " Cargo.toml version: $CARGO_VERSION"
|
||
|
||
# 如果在 CI 中且有 GITHUB_REF_NAME(tag 构建),验证匹配
|
||
if [ -n "${GITHUB_REF_NAME:-}" ] && [[ "${GITHUB_REF:-}" == refs/tags/v* ]]; then
|
||
TAG_VERSION="${GITHUB_REF_NAME#v}"
|
||
echo " Git tag version: $TAG_VERSION"
|
||
if [ "$TAG_VERSION" != "$CARGO_VERSION" ]; then
|
||
fail "Tag 版本 ($TAG_VERSION) 与 Cargo.toml 版本 ($CARGO_VERSION) 不匹配!"
|
||
else
|
||
pass "Tag 与 Cargo.toml 版本匹配"
|
||
fi
|
||
else
|
||
echo " (非 tag 构建,跳过版本匹配检查)"
|
||
pass "Cargo.toml 版本号格式正确: $CARGO_VERSION"
|
||
fi
|
||
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
# 4. 检查 unsafe 代码
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
echo ""
|
||
echo "--- 检查 unsafe 代码 ---"
|
||
|
||
UNSAFE_HITS=$(find src/ -name '*.rs' -exec awk '/#\[cfg\(test\)\]/{exit} {print FILENAME":"NR":"$0}' {} \; \
|
||
| grep 'unsafe' \
|
||
| grep -v '#!\[forbid(unsafe_code)\]' \
|
||
| grep -v '// unsafe' \
|
||
|| true)
|
||
|
||
if [ -n "$UNSAFE_HITS" ]; then
|
||
fail "发现 unsafe 代码(本项目使用 #![forbid(unsafe_code)]):"
|
||
echo "$UNSAFE_HITS" | head -5
|
||
else
|
||
pass "未发现 unsafe 代码"
|
||
fi
|
||
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
# 汇总
|
||
# ─────────────────────────────────────────────────────────────────────────────
|
||
echo ""
|
||
echo "=========================================="
|
||
if [ "$ERRORS" -gt 0 ]; then
|
||
echo -e " ${RED}发现 $ERRORS 个错误!${NC}"
|
||
echo "=========================================="
|
||
exit 1
|
||
else
|
||
echo -e " ${GREEN}所有安全检查通过${NC}"
|
||
echo "=========================================="
|
||
exit 0
|
||
fi
|