添加 CI/CD 自动化工作流

- 添加 .github/workflows/ci.yml:多平台测试、MSRV 验证、覆盖率、性能基准、自动发布
- 添加 .github/scripts/sanity_check.sh:安全性扫描脚本
- 更新 README 添加 CI 和覆盖率徽章
- 更新 SECURITY.md 响应时间说明(个人维护,无限期宽限)
This commit is contained in:
huangxt
2026-03-07 19:54:34 +08:00
parent 679fa8cff6
commit ce88fd8365
5 changed files with 441 additions and 3 deletions
+162
View File
@@ -0,0 +1,162 @@
#!/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() 用于固定大小切片转换(已知安全)
# 收集 src/ 下所有非测试 .rs 文件中的匹配项
PANIC_HITS=$(grep -rn 'panic!\|\.unwrap()\|\.expect(' src/ --include='*.rs' \
| grep -v '#\[cfg(test)\]' \
| grep -v 'mod tests' \
| grep -v '// test' \
| grep -v '#\[test\]' \
| grep -v 'fn test_' \
|| 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=$(grep -rniE "$SENSITIVE_PATTERNS" src/ --include='*.rs' \
| grep -v '#\[cfg(test)\]' \
| grep -v 'mod tests' \
| grep -v '// test' \
| grep -v 'fn test_' \
|| 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_NAMEtag 构建),验证匹配
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=$(grep -rn 'unsafe' src/ --include='*.rs' \
| grep -v '#!\[forbid(unsafe_code)\]' \
| grep -v '// unsafe' \
| grep -v '#\[cfg(test)\]' \
| grep -v 'mod tests' \
|| 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