xzawed/SCAManager
GitHub: xzawed/SCAManager
SCAManager 是一个自托管的 GitHub 代码质量服务,通过并行运行静态分析器和 Claude AI 审查来量化评分并自动化 PR 门禁流程。
Stars: 1 | Forks: 0
# 🛡️ SCAManager
**自动化代码质量分析 · AI Review · GitHub 的 PR Gate 服务**
[](https://www.python.org/)
[](https://fastapi.tiangolo.com/)
[](https://www.postgresql.org/)
[-CC6600?style=flat-square&logo=anthropic&logoColor=white)](https://www.anthropic.com/)
[](https://railway.app/)
[](LICENSE)
[](https://github.com/xzawed/SCAManager/actions/workflows/ci.yml)
[](https://github.com/xzawed/SCAManager/actions/workflows/codeql.yml)
[](https://codecov.io/gh/xzawed/SCAManager)
[](https://sonarcloud.io/summary/new_code?id=xzawed_SCAManager)
[](https://sonarcloud.io/summary/new_code?id=xzawed_SCAManager)
[](https://sonarcloud.io/summary/new_code?id=xzawed_SCAManager)
[-brightgreen?style=flat-square&logo=pytest&logoColor=white)](tests/)
[-lightgrey?style=flat-square&logo=playwright&logoColor=white)](e2e/)
[](src/)
[](src/)
[](tests/)
[🇰🇷 한국어](README.ko.md)
## 📖 概述
**SCAManager** 自动管理你 GitHub 仓库的代码质量。
在每次 Push 或 PR 事件时,它会并行运行**静态分析**(25 个已注册的分析器 — pylint · flake8 · bandit · Semgrep · ESLint · ShellCheck · cppcheck · slither · RuboCop · golangci-lint 及[另外 15 个](docs/reference/language-coverage.md))和 **Claude AI review**,并给出百分制评分及从 A 到 F 的等级。
结果会通过 **Telegram · GitHub · Discord · Slack · Email · n8n** 即时推送,并且可以根据分数自动批准、拒绝或 squash-merge PR。
对于直接推送到 `main` 分支的团队,它还支持在低分提交上执行**自动提交评论**和**创建 GitHub Issue**。
## 🎯 为什么选择 SCAManager?
大多数代码审查工具让你在静态分析的精确度和 AI 的理解力之间做选择。SCAManager 并行运行这两者,并将结果合并为一个单一的分数 — 然后基于此自动执行操作。
**它的独特之处:**
- **自托管的控制平面** — pipeline、数据库和 dashboard 运行在你自己的基础设施上;没有供应商锁定,运行它也不需要第三方 SaaS 账户。你分析的代码仍然会被发送到*你*配置的服务:用于 AI review 的 Anthropic API,以及你启用的任何通知渠道。有关确切的出口列表以及如何在零外部调用的情况下运行,请参阅 [SECURITY.md § 代码去向](SECURITY.md#where-your-code-goes)。
- **集成静态分析与 AI 的单一 pipeline** — 25 个已注册的静态分析器与 Claude AI review 并行运行;结果汇聚为单一分数
- **基于评分的 PR Gate** — 根据数值阈值自动批准、拒绝或通过 Telegram 请求人工决策
- **从手机批准** — Telegram 内联按钮允许你在任何地方审查和合并 PR,无需笔记本电脑
- **Push + PR 分析** — 不仅仅是 PR;纯粹的 push 也会触发分析,自动创建 GitHub Issue,并发布提交评论
- **49 种语言的 AI review** — 为每种支持的语言提供特定的检查清单,而非通用的 prompt
**最适合:** 希望对代码质量 pipeline 拥有完全控制权的独立开发者和小型团队。
## 🌐 多语言支持 (English / 한국어 / 日本語)
SCAManager 在所有面向用户的界面 — UI、通知和 AI 代码审查 prompt — 支持 **3 种语言**。
| 界面 | 翻译范围 | 事实来源 |
|---------|------------|-----------------|
| **Web UI** (登录 / dashboard / 设置 / 管理) | 所有标签、按钮、提示 | 标题下拉菜单 🌐 (顶部导航) |
| **通知** (Telegram / Discord / Slack / Email / GitHub PR 评论 / 提交评论 / Issue) | 所有消息模板 | 3 层回退:用户语言 → 仓库通知语言 → 默认 |
| **AI 代码审查** (Claude — 49 种语言) | Tier1/Tier2/Tier3 + 通用指南 | 2 层回退:仓库所有者语言 → 用户语言 → 默认 |
**如何切换**:点击顶部标题栏中的语言下拉菜单 🌐。更改将立即应用并通过 cookie 持久化。
**注意**:
- 语言偏好存储在用户账户上(标题下拉菜单是唯一的事实来源 — 在 `/settings` 中没有单独的语言设置)
- GitHub Issue 标题 + Email 主题保留英文前缀以便于搜索 (`[SCAManager]`, `[Code Review]`)
- Anthropic prompt 缓存会根据语言自动区分(系统文本哈希不同 → 缓存键分离,无需手动配置)
- 熔断开关:设置 `I18N_DISABLED=1` 以仅回退到默认语言环境(用于操作紧急情况)
详细环境变量:[docs/reference/env-vars.md](docs/reference/env-vars.md)
## ✨ 功能
### 🔍 自动化代码分析
| 分析项 | 工具 | 目标 |
|----------|-------|--------|
| 代码质量 | pylint + flake8 + Semgrep + cppcheck + RuboCop + golangci-lint | `.py` + C/C++ (cppcheck) + `.rb` (RuboCop) + `.go` (golangci-lint) + **22 种语言** (Semgrep — [src/analyzer/io/tools/semgrep.py](src/analyzer/io/tools/semgrep.py) 中的 `SUPPORTED_LANGUAGES`) |
| 安全性 | bandit + Semgrep + slither + RuboCop Security cops + gosec (通过 golangci-lint) | `.py` 文件(排除测试)+ Solidity (slither) + Ruby / Go 安全规则 |
| JS/TS 质量 | ESLint (flat config) | `.js` `.mjs` `.ts` `.tsx` |
| Shell 质量 | ShellCheck | `.sh` `.bash` 及其他 shell 脚本 |
| Solidity | slither | `.sol` — reentrancy · tx.origin · weak-prng · 感知类别 |
| Ruby | RuboCop | `.rb` — 单独检测 Security cops |
| Go | golangci-lint | `.go` — meta-linter (gosec / errcheck / staticcheck / unused,自动 `go.mod`) |
| AI Review | Claude Sonnet 4.6 | **49 种语言**,带有特定语言的检查清单 |
| 提交信息 | Claude AI | Push / PR 信息 |
- 自动处理 `push` 和 PR (`opened` / `synchronize` / `reopened`) 事件
- 静态分析和 AI review 通过 `asyncio.gather()` **并行**运行 — 延迟最低
- 如果没有 `ANTHROPIC_API_KEY`,AI 项目使用中性默认值 — **在没有 AI 的情况下最高可达 89 分(等级 B)**
### 🏆 评分系统
| 类别 | 分数 | 扣分规则 |
|----------|--------|----------------|
| 🧹 代码质量 | 25 | error −3 · warning −1 (CQ_WARNING_CAP = 合计上限 25) |
| 🔒 安全性 | 20 | HIGH −7 · LOW/MED −2 |
| 📝 提交信息 | 15 | Claude AI (0–20 → 缩放至 0–15) |
| 🧠 实现方向 | 25 | Claude AI (0–20 → 缩放至 0–25) |
| 🧪 测试覆盖率 | 15 | Claude AI (0–10 → 缩放至 0–15;豁免配置/文档文件) |
| **总分** | **100** | |
**等级阈值**
| 等级 | 分数 | 含义 |
|-------|-------|---------|
| 🥇 A | 90+ | 优秀 |
| 🥈 B | 75+ | 良好 |
| 🥉 C | 60+ | 平均水平 |
| ⚠️ D | 45+ | 需要改进 |
| 🚨 F | ≤ 44 | 严重 |
### 🔔 通知渠道
| 渠道 | 内容 | 配置 |
|---------|---------|---------------|
| 📱 Telegram | 评分 · AI 总结 · 建议 · 静态问题 (HTML) | 默认 |
| 💬 GitHub PR 评论 | 分类/文件反馈 + 评分表 | 逐仓库配置 |
| 📌 GitHub 提交评论 | 在 push 提交上发布的 AI review | 逐仓库配置 |
| 🐛 GitHub Issue | 在低分或 bandit HIGH 时自动创建 | 逐仓库配置 |
| 🎮 Discord | Embed 格式的通知 | 逐仓库配置 |
| 💼 Slack | Attachment 格式的通知 | 逐仓库配置 |
| 📧 Email | SMTP HTML 邮件 | 逐仓库配置 |
| 🔗 通用 Webhook | 通用 JSON POST | 逐仓库配置 |
| 🔄 n8n | 外部工作流触发 (Issue → Claude CLI → 自动 PR) | 逐仓库配置 |
所有渠道都通过 `asyncio.gather(return_exceptions=True)` 独立运行 — 一个渠道的失败永远不会影响其他渠道。
### 📡 Telegram 洞察
除了实时的 push/PR 提醒外,SCAManager 的 Telegram 集成还提供定期的报告、趋势检测和交互式的 bot 命令。
#### 每周报告
每周一 KST 09:00,SCAManager 会向每个仓库配置的 Telegram 聊天发送一份每周总结:
```
📊 Weekly Report — owner/myrepo
Period: Apr 21 – Apr 27
Analyses: 12 | Avg score: 81.4 (B)
High: 94 (A) | Low: 62 (C)
Top issues this week:
· security: 8 occurrences
· code_quality: 14 occurrences
```
#### 趋势警报
每天 KST 12:00,SCAManager 会检查 7 天移动平均值。如果它比前一时期**下降 10 分以上**(至少需要 5 次分析),将自动发送趋势警报:
```
⚠️ Score trend alert — owner/myrepo
7-day moving avg dropped: 83.2 → 71.5 (−11.7)
Recent low-score analyses may need attention.
```
#### Bot 命令
关联你的 Telegram 账户(见下文)后,向 bot 发送这些命令:
| 命令 | 描述 |
|---------|-------------|
| `/stats
` | 仓库的每周平均分、分析次数和主要问题 |
| `/settings ` | 当前的 gate 模式、阈值和通知设置 |
| `/connect ` | 将你的 Telegram 账户关联到你的 SCAManager 个人资料 |
#### 关联你的 Telegram 账户(`/connect` OTP 流程)
1. 转到 **Settings → "Outbound Channels" 卡片 → Telegram Connection**,然后点击 **"🔗 Issue Code"**
2. 出现一个 8 位数的 OTP(有效期为 5 分钟)
3. 在 Telegram 中向 SCAManager bot 发送 `/connect 12345678`
4. bot 回复 "✅ Account linked" — 现在可以使用 bot 命令了
### ⚡ PR Gate 引擎
基于评分的 PR 自动化。
```
Analysis complete
├── [Auto mode] score ≥ approve_threshold → GitHub APPROVE
│ score < reject_threshold → GitHub REQUEST_CHANGES
│
├── [Semi-auto mode] Send Telegram inline buttons → manual approve/reject
│
└── [Auto Merge] score ≥ merge_threshold → squash merge
(independent of approve_mode)
```
| 设置 | 行为 |
|---------|----------|
| `approve_mode="auto"` | 按阈值自动批准 / 请求更改 |
| `approve_mode="semi-auto"` | 通过 Telegram 按钮手动决策 |
| `auto_merge=true` | 满足阈值时执行 Squash merge |
#### ♻️ 感知 CI 的自动合并重试
当 `auto_merge=true` 且由于 CI 仍在运行导致合并失败时(`mergeable_state=unstable` 或 `unknown`),SCAManager 会将 PR 排队等待重试,而不是直接放弃:
- 首次入队:发送 Telegram "⏳ merge queued" 通知 (1×)
- 在 24 小时内通过 `check_suite.completed` webhook 或 1 分钟的 cron 最多重试 30 次
- 最终结果:Telegram 成功/失败通知 (1×)
### 📊 可观测性
用于诊断和成本控制的生产级监控仪表。
| 层级 | 模块 | 捕获内容 |
|-------|--------|------------------|
| Claude API 成本 | `src/shared/claude_metrics.py` | 每次调用的 model · input/output tokens · USD 成本估算 · 延迟(结构化日志)。 |
| Pipeline 耗时 | `src/shared/stage_metrics.py` `stage_timer` 上下文管理器为每个 pipeline 阶段发出 `duration_ms` + `status`。 |
| 自动合并尝试 | `src/shared/merge_metrics.py` + `merge_attempts` 表 | 每次自动合并尝试(无论成功或失败)都会被持久化,并带有标准化的 `failure_reason` 标签(`branch_protection_blocked`, `unstable_ci`, `permission_denied`, …)+ `score`/`threshold` 快照。 |
这三个层级都会无条件发出结构化日志,因此任何日志转发器(Datadog, CloudWatch, Grafana Loki, Railway Logs)都可以解析它们。无需依赖外部 SaaS。
### 🖥️ Web Dashboard
通过 GitHub OAuth 登录后,即可通过浏览器访问所有功能。
- **添加仓库** — 从 GitHub 下拉菜单自动创建 Webhook
- **评分历史图表** — 基于 Chart.js 的可视化
- **分析详情** — AI review · 分类反馈 · 静态分析问题
- **设置页面** — 🚀 一键预设 · 6 卡片渐进式展开 (Quick Settings · PR Behavior Rules · Post-event automation · Outbound Channels · Integration & Auth · Danger zone) · 切换显示/隐藏
- **主题** — Dark / Light / Pastel / Catppuccin — 完整支持所有四种主题
### 💻 CLI 代码审查
从终端立即运行本地代码审查。
```
# 与最后一次 commit 进行比较(默认)
python -m src.cli review
# 与特定 branch 进行比较
python -m src.cli review --base main
# 仅分析 staged changes
python -m src.cli review --staged
# JSON 输出
python -m src.cli review --json
```
### 🪝 CLI Hook (本地 pre-push 自动审查)
一个在 `git push` 时自动运行代码审查的 Git Hook。
```
# 在注册 repo 后运行一次
git pull
bash .scamanager/install-hook.sh
# 随后的每次 push 都会触发自动 review
git push origin main
# → AI review 打印到 terminal
# → 自动保存到 SCAManager dashboard
```
- **需要 `ANTHROPIC_API_KEY`** — 该 hook 直接调用 Anthropic Messages API(它不再调用 `claude -p`;当 Agent SDK 的计费在 2025-06-15 被拆分时,该调用路径已被弃用)
- 默认使用 `claude-haiku-4-5` 以保持每次 push 的低成本 — 可通过 `SCAMANAGER_REVIEW_MODEL` 覆盖
- 结果会同时显示在终端和 dashboard 中
- Push 永远不会被阻塞 — hook 总是以 `0` 退出
## 🛠️ 技术栈
| 类别 | 技术 |
|----------|------------|
| **语言** | Python 3.12 |
| **Web 框架** | FastAPI + Uvicorn |
| **认证** | GitHub OAuth2 (authlib) + Starlette SessionMiddleware |
| **数据库** | PostgreSQL · SQLAlchemy 2 · Alembic · FailoverSessionFactory |
| **AI (服务端)** | Anthropic Claude API (claude-sonnet-4-6) |
| **AI (本地 Hook)** | Anthropic Messages API (默认 `claude-haiku-4-5`,可通过 `SCAMANAGER_REVIEW_MODEL` 覆盖) |
| **静态分析** | **Tier1 25 工具** — pylint · flake8 · bandit (Python) + Semgrep (22+) + ESLint + ShellCheck + cppcheck + slither + RuboCop + golangci-lint + 另外 15 个 (hadolint · ktlint · tflint · tsc · sqlfluff · yamllint · phpstan · swiftlint · stylelint · htmlhint · buf_lint · dart_analyze · psscriptanalyzer · dotnet_format · clippy) — 参见 [docs/reference/language-coverage.md](docs/reference/language-coverage.md) |
| **测试** | pytest · pytest-asyncio · httpx TestClient |
| **E2E 测试** | Playwright (Chromium) |
| **Web UI** | Jinja2 · Chart.js · CSS 变量 (4 种主题) |
| **通知** | Telegram · GitHub · Discord · Slack · Email · n8n · Webhook |
| **部署** | Railway / 本地部署 (systemd · nginx · Docker Compose) |
## 🚀 快速开始
### 📋 前置条件
- Python **3.12** 或更高版本
- PostgreSQL
- GitHub OAuth App (Client ID / Client Secret)
- (可选) Telegram Bot Token · SMTP 服务器 · ANTHROPIC_API_KEY
### ⬇️ 安装
```
git clone https://github.com/xzawed/SCAManager.git
cd SCAManager
# 开发环境 — 一步完成 pip + npm(包含 pytest 和 Tailwind toolchain)
make install
# 🔴 每次全新 clone 后需运行一次:Tailwind bundle 是 build artifact 且被 gitignored,
# 而 base.html 链接了 /static/css/dist/tailwind.css — 跳过此步骤将导致其返回 404。
# (在 Railway 上,相同的 build 在 railway.toml `buildCommand` 内运行。)
make css-build
# 🔴 Local guard hooks — .pre-commit-config.yaml 中的每个 hook(secret scan、docs-number parity、
# architecture-tree sync、config-layer sync 等)仅通过 pre-commit 运行。跳过此步骤,
# guards 将在新机器上静默缺失;commits 仍会成功。需要两种 hook 类型
# (commit-msg 是一个单独的 stage)。详情:docs/runbooks/secret-prevention.md
python -m pip install pre-commit
python -m pre_commit install --hook-type pre-commit --hook-type commit-msg
# 仅 Python deps(production image / 无 Node.js 可用)
pip install -r requirements.txt # runtime
pip install -r requirements-dev.txt # + pytest · Playwright
```
### ⚙️ 环境变量
```
cp .env.example .env
```
**必填项**
| 变量 | 描述 |
|----------|-------------|
| `DATABASE_URL` | PostgreSQL 连接 URL (`postgres://` 会自动转换为 `postgresql://`) |
| `TELEGRAM_BOT_TOKEN` | Telegram Bot API token |
| `TELEGRAM_CHAT_ID` | 默认通知 Chat ID |
| `GITHUB_CLIENT_ID` | GitHub OAuth App Client ID |
| `GITHUB_CLIENT_SECRET` | GitHub OAuth App Client Secret |
| `SESSION_SECRET` | Session cookie 签名密钥(**32 个以上的随机字符,必填**) |
**推荐**
| 变量 | 描述 |
|----------|-------------|
| `APP_BASE_URL` | 部署 URL (`https://your-app.railway.app`) — 应用于 OAuth 重定向 URI 和 Webhook URL |
| `ANTHROPIC_API_KEY` | Claude AI review 密钥(如果省略,将应用中性默认值) |
**可选**
| 变量 | 描述 |
|----------|-------------|
| `API_KEY` | REST API 认证密钥 (X-API-Key 标头) |
| `GITHUB_TOKEN` | 用于旧版仓库的 GitHub API token |
| `GITHUB_WEBHOOK_SECRET` | 用于旧版仓库的 Webhook 密钥 |
| `SMTP_HOST` / `SMTP_PORT` / `SMTP_USER` / `SMTP_PASS` | Email 通知 SMTP 设置 |
| `DATABASE_URL_FALLBACK` | 用于故障转移的备选数据库 URL(如果未设置,则为单引擎模式) |
| `DB_FAILOVER_PROBE_INTERVAL` | 主数据库恢复检查间隔(以秒为单位,默认为 30) |
| `DATABASE_URL_WORKER` | 用于 RLS 角色分离选项 A 的仅后台数据库 URL(如果未设置,则重用 `DATABASE_URL` — 必须是具有 BYPASSRLS 权限的 worker 角色凭证) |
| `DB_SSLMODE` | PostgreSQL SSL 模式 (`require` / `disable`) |
| `DB_FORCE_IPV4` | 强制 IPv4 连接 (`true` — Railway 环境) |
### ▶️ 运行
```
# Development server(自动运行 DB migration)
uvicorn src.main:app --reload --port 8000
# 或通过 Make
make run
```
## 🧪 开发命令
```
make install # Install dependencies (pip + npm)
make test # Full test suite (compact output)
make test-v # Full test suite (verbose output)
make test-fast # Fast unit tests only (excludes tests/integration/, -m "not slow")
make test-slow # Integration tests only (tests/integration/ — real subprocess)
make test-file f=tests/path/test.py # Single file test
make test-local # Windows-friendly — excludes slow subprocess tests, short tracebacks
make test-perf # Perf marker tests (e2e/ -m perf, separate from test-e2e)
make test-isolated # Isolated test run (stashes .env, unsets credentials)
make test-cov # Tests + coverage report
make lint # pylint + flake8 + bandit
make lint-strict # pylint regression guard (fail if score < 9.90)
make lint-js # ESLint on src/templates/**/*.html inline scripts
make css-build # Build Tailwind v4 CSS (production minified)
make css-dev # Watch and rebuild Tailwind v4 CSS (dev mode)
make gate # Full phase gate — tests + lint in one command
make review # CLI code review (HEAD~1)
make run # Development server (port 8000)
make migrate # Run DB migrations
make revision m="desc" # Create new migration file
make install-playwright # Install Playwright + Chromium
make test-e2e # E2E tests (headless)
make test-e2e-headed # E2E tests (with browser)
make perf-report # Generate performance report (local + production)
```
## 🌐 URL 路由
```
/login → 🔑 GitHub OAuth login
/repos/add → ➕ Add repository
/ → 📊 Repository overview dashboard
/dashboard → 📈 KPI dashboard (avg score / security HIGH / auto-merge rate)
/repos/{owner/repo} → 📈 Score history + analysis log
/repos/{owner/repo}/analyses/{id} → 🔍 Analysis detail (AI review · feedback)
/repos/{owner/repo}/settings → ⚙️ Gate · notifications · Hook settings
```
## 📡 API Endpoints
展开完整的端点列表
**认证 (OAuth)**
```
GET /login 301 redirect → /auth/github (backward-compatible)
GET /auth/github Start GitHub OAuth
GET /auth/callback GitHub OAuth callback
POST /auth/logout Logout
```
**Web Dashboard**
```
GET / Repository list
GET /dashboard KPI dashboard (avg score / security / auto-merge rate)
GET /repos/add Add repository page
GET /repos/{repo} Repo detail (chart + history)
GET /repos/{repo}/analyses/{id} Analysis detail
GET /repos/{repo}/settings Settings page
GET /insights 301 → /dashboard (deprecated)
GET /insights/me 301 → /dashboard (deprecated)
POST /repos/add Register repo + auto-create Webhook + Hook files
POST /repos/{repo}/settings Save settings
POST /repos/{repo}/reinstall-hook Re-commit CLI Hook files
POST /repos/{repo}/reinstall-webhook Re-register Webhook
POST /repos/{repo}/delete Delete repo (including Webhook + history)
```
**Webhook 接收器**
```
POST /webhooks/github GitHub Webhook (HMAC-SHA256 verified)
POST /api/webhook/telegram Telegram Gate callback (HMAC auth)
POST /webhooks/railway/{token} Railway deploy event (token auth)
```
**REST API** (需要 X-API-Key 标头 — fail-closed:如果未设置 `API_KEY`,除非为本地开发设置了 `API_AUTH_DISABLED=1`,否则每个请求都会收到 `503`)
```
GET /api/repos Repository list
GET /api/repos/{repo}/analyses Analysis history (skip · limit pagination)
PUT /api/repos/{repo}/config Update repo settings
DELETE /api/repos/{repo} Delete repo (API mode — manual Webhook removal)
GET /api/repos/{repo}/stats Score statistics · trends
GET /api/analyses/{id} Analysis detail
```
**CLI Hook** (hook_token 认证)
```
GET /api/hook/verify Verify hook registration
POST /api/hook/result Save code review result
```
**用户 API** (需要 OAuth session)
```
POST /api/users/me/telegram-otp Issue 8-digit OTP for Telegram /connect linking
```
**内部 Cron** (需要 INTERNAL_CRON_API_KEY)
```
POST /api/internal/cron/weekly Trigger weekly Telegram summary report
POST /api/internal/cron/trend Trigger trend alert check (7-day moving avg)
POST /api/internal/cron/scan-security Trigger GitHub Code/Secret Scanning alert poll
POST /api/internal/cron/retry-pending-merges Trigger CI-aware auto-merge retry queue processing
POST /api/internal/cron/sweep-orphans Surface & purge orphaned analysis_attempts (loss detection)
POST /api/internal/cron/retention-sweep GC expired insight cache + terminal merge-retry rows
```
**健康检查**
```
GET /health {"status":"ok"}
```
## 🏗️ 架构
```
GitHub Push/PR
└─ POST /webhooks/github (HMAC-SHA256 verified, per-repo secret TTL-cached)
└─ BackgroundTask: run_analysis_pipeline()
├─ Register repo in DB · SHA dedup check (idempotency)
├─ get_pr_files / get_push_files
│
├─ asyncio.gather() ── parallel execution
│ ├─ analyze_file() × N (pylint · flake8 · bandit · semgrep · eslint · shellcheck · cppcheck · slither · rubocop · golangci-lint)
│ └─ review_code() (Claude AI — 49-language checklists, token budget 8000)
│
├─ calculate_score() → score · grade
├─ Save Analysis to DB
│
├─ run_gate_check() [PR events only]
│ ├─ pr_review_comment → GitHub PR comment
│ ├─ approve_mode=auto → GitHub APPROVE / REQUEST_CHANGES
│ ├─ approve_mode=semi → Telegram inline keyboard
│ └─ auto_merge → squash merge
│
└─ asyncio.gather(return_exceptions=True) ── independent notifications
├─ Telegram
├─ GitHub Commit Comment [push + commit_comment=on]
├─ GitHub Issue [score < threshold or bandit HIGH]
├─ Discord
├─ Slack
├─ Generic Webhook
├─ Email
└─ n8n
```
## ☁️ 部署
### 🚂 Railway
1. 创建一个 Railway 项目并连接此仓库
2. 添加 **PostgreSQL 插件** (`DATABASE_URL` 会自动生成)
3. 在 **Variables** 标签页中设置环境变量
```
TELEGRAM_BOT_TOKEN =
TELEGRAM_CHAT_ID =
GITHUB_CLIENT_ID =
GITHUB_CLIENT_SECRET =
SESSION_SECRET =
APP_BASE_URL = https://your-app.up.railway.app ← required!
ANTHROPIC_API_KEY = sk-ant-... ← recommended
```
4. 部署 — 数据库迁移会在应用启动时自动运行 (lifespan)
### 🖥️ 本地部署
```
# 基本启动命令(--proxy-headers:信任 reverse proxy IP)
uvicorn src.main:app --host 0.0.0.0 --port 8000 --proxy-headers
```
**数据库故障转移** — 将 `DATABASE_URL_FALLBACK` 设置为备选数据库 URL,以便在主库发生故障时自动进行故障转移。无论哪个数据库处于活动状态,`/health` 端点都会返回 `{"status": "ok"}`。
有关详细信息,请参阅[本地部署迁移指南](docs/guides/onpremise-migration-guide.md)。
## 🔧 GitHub OAuth App 设置
1. **GitHub → Settings → Developer settings → OAuth Apps → New OAuth App**
2. 填写字段:
| 字段 | 值 |
|-------|-------|
| Application name | SCAManager |
| Homepage URL | `https://your-domain` |
| Authorization callback URL | `https://your-domain/auth/callback` |
3. 将 **Client ID** 和 **Client Secret** 设置为环境变量
## ➕ 添加仓库
1. 登录 → dashboard → 点击 **+ Add Repo**
2. 从 GitHub 下拉菜单中选择仓库
3. 点击 **Create Webhook + Add Repo**
- 自动创建 GitHub Webhook(带有 HMAC 密钥)
- 自动提交 `.scamanager/config.json` 和 `install-hook.sh`
4. 在下次 Push 或 PR 时自动开始分析 ✅
### Webhook URL 更改(例如:迁移部署 URL 后)
**Settings → CLI Hook 卡片 → 🔗 Re-register Webhook**
Webhook 将基于当前的 `APP_BASE_URL` 重新创建。
### 安装 CLI Hook (本地 pre-push)
```
git pull
bash .scamanager/install-hook.sh
# 自动 code review 在随后的每次 git push 时运行
```
## 💻 GitHub Codespaces
```
# 容器启动后立即可用(无需 .env — 使用 SQLite 内存模式)
make test # Full test suite
make lint # Code quality check
make run # Dev server (port 8000 auto-forwarded)
# CLI code review(需要 ANTHROPIC_API_KEY)
ANTHROPIC_API_KEY=sk-ant-... python -m src.cli review
```
## 🤝 贡献
欢迎提交 Issue 和 pull request。从 **[CONTRIBUTING.md](CONTRIBUTING.md)** ([한국어](CONTRIBUTING.ko.md)) 开始 — 它涵盖了本仓库实际需要的本地设置(Tailwind 构建和两个 pre-commit hook 阶段很容易被忽略)、如何运行测试套件、分支和提交规范以及 PR 清单。
三件容易让首次贡献者踩坑的事情:
| 陷阱 | 为什么重要 |
|--------|----------------|
| 在全新克隆后运行 `make css-build` | Tailwind bundle 是被 gitignore 的构建产物;跳过它会导致 `base.html` 为其样式表返回 404 |
| `pre-commit install --hook-type pre-commit --hook-type commit-msg` | 每个本地检查(密钥扫描、文档数量一致性、架构树同步、配置层同步)**仅**通过 pre-commit 运行。跳过它提交仍然会成功 — 默默地失去保护 |
| 双语代码注释 | 新的注释以韩语编写,下一行是英语。这是一项约定,而非强制执行的 hook。参见 [CONTRIBUTING.md § 代码注释](CONTRIBUTING.md#code-comments-bilingual) |
## 🔐 安全
请**不要为安全漏洞公开提交 issue。**请改用
[GitHub 的私人漏洞报告](https://github.com/xzawed/SCAManager/security/advisories/new)
。完整的政策 — 受支持的版本、范围、响应目标,以及离开你部署环境的准确数据列表 — 包含在 **[SECURITY.md](SECURITY.md)** ([한국어](SECURITY.ko.md)) 中。
SCAManager 会处理你的源代码,因此明确出口流量是值得的:自托管运行可将 pipeline、数据库和 dashboard 保留在你的基础设施上,但 AI review
会将 diff 发送到 Anthropic API,并且你启用的每个通知渠道都会将分析输出发送到该渠道的提供商。
[SECURITY.md § 代码去向](SECURITY.md#where-your-code-goes)
列出了每个目的地以及如何禁用它。
## 📄 许可证
[MIT License](LICENSE) © 2026 xzawed标签:AI代码审查, GitHub集成, 云安全监控, 安全专业人员, 测试用例, 特征检测, 跨平台, 逆向工具, 静态分析