系统架构
状态: ✅ 已落地(2026-08-05 修正——对齐当前实现;早期规划见 git 历史)
项目组成
dependfix 由以下子项目组成(标 ✅ 的已落地,其余为规划中):
dependfix/
├── packages/
│ ├── core/ # ✅ 核心业务逻辑库 @dependfix/core(告警模型/过滤/报告/日志/工具链)
│ ├── engine/ # ✅ 执行引擎 @dependfix/engine(github 采集/fixers 修复/config/编排内核,cli/mcp/platform 共享)
│ ├── cli/ # ✅ CLI 入口 dependfix(bin/参数解析/runner 薄壳/skills)
│ ├── github/ # ✅ 已并入 packages/engine/src/github/(client/fetcher/pr-creator)
│ ├── action/ # ✅ 已并入根 action.yml(Composite Action,M2 落地)
│ └── mcp/ # ✅ MCP Server @dependfix/mcp(M6 落地,依赖 engine)
├── action.yml # ✅ GitHub Composite Action 入口(M2 已落地)
├── apps/platform/ # ✅ Nuxt 全栈管理平台(Web UI + REST API,M6 落地,依赖 engine)
└── docs/ # ✅ VitePress 文档站注:M0 规划中的
packages/github曾于 2026-08-05 目录收敛并入packages/cli/src/github/(当时仅 cli 一个消费方);2026-08-09 修订——mcp/platform 成为第二个/第三个消费方后,"应用层互相依赖(mcp → cli)"导致依赖连带膨胀与版本耦合,github/与执行核心(fixers/config/app)拆入共享引擎包@dependfix/engine(方案 B,见 todo.md 进行中任务),cli 薄壳化。packages/action维持根 action.yml 形式。
总体方案
采用"统一编排器 + 告警采集器 + 修复执行器 + 报告器"的分层设计。
flowchart TD
A[运行入口 CLI / GitHub Action] --> B[任务编排器]
B --> C[仓库列表解析器]
B --> D[GitHub 告警采集器]
D --> D1[Dependabot Alerts]
D --> D2[Code Scanning Alerts]
B --> E[过滤与优先级引擎]
E --> F[修复规划器]
F --> G1[依赖升级修复器]
F --> G2[pnpm frozen-lockfile 修复器]
F --> G3[Code Scanning 建议/半自动修复器]
G1 --> H[验证执行器]
G2 --> H
G3 --> H
H --> I[分支与 PR 管理器]
H --> J[报告生成器]功能模块
入口层
- CLI 入口
- GitHub Action 入口
- 统一参数解析器
配置层
- 环境变量加载
- 仓库级配置读取
- 默认策略合并
GitHub 集成层
- 认证与 API 客户端(PAT 路径 + GitHub App installation token 路径双轨;详见 C22 PAT 无感升级评估)
- 告警拉取
- 仓库发现
- 分支、提交、PR、评论操作
核心域层
- 告警标准化模型
- 过滤与优先级模型
- 修复规划模型
- 执行结果模型
执行层
- 仓库克隆与工作目录管理
- 包管理器命令执行
- 质量门执行
- 失败回滚与清理
报告层
- 汇总统计
- 单仓库明细
- 告警-修复映射
- 失败原因归类
仓库列表获取
手动指定
- CLI 参数
- 环境变量
- 配置文件中的显式列表
自动发现
- organization / owner
- topic
- 默认分支
- 是否 archived / disabled
- 是否包含
package.json或pnpm-lock.yaml
首期优先支持"手动指定 + 基于 owner 自动发现"。
修复优先级
默认按以下顺序执行:
- Critical 的依赖漏洞
- High 的依赖漏洞
- 会阻塞 CI 的 lockfile 问题
- 可模板化处理的 code scanning 问题
- 其余问题只输出建议
运行模式
本地直接运行
report-only:只拉取告警并生成报告fix:执行修复但不推送fix-and-pr:执行修复并推送分支 / 创建 PR
GitHub Action 运行
触发方式:workflow_dispatch、schedule
输入参数:owner / organization、repositories、severity-threshold、mode、max-repos、dry-run
专用 Agent 设计
角色定位
负责安全告警自动修复的任务编排:
- 拉取并统一标准化 GitHub 安全告警
- 根据配置决定要处理哪些仓库、哪些告警、哪些修复策略
- 调用对应技能完成采集、过滤、修复、验证和报告
- 在失败时给出结构化原因
输入
- GitHub Token / GitHub App 凭证
- 目标仓库列表或自动发现参数
- 修复策略配置
- 严重级别过滤规则
- 运行模式:
report-only、fix、fix-and-pr
输出
- 每个仓库的执行结果
- 已修复告警列表
- 未修复告警列表及原因
- 创建的分支、提交、PR、评论链接
- Markdown 报告与 JSON 报告
决策原则
- 默认先修复高收益、低风险问题
- 默认优先修复依赖问题,其次修复 lockfile 问题,最后处理可模板化的 code scanning 问题
- 当验证失败、升级跨度过大或需要业务判断时,停止自动提交,仅输出建议
pnpm frozen-lockfile 自动修复
触发条件
- 修复依赖漏洞后安装失败
- 单独执行验证时
pnpm i --frozen-lockfile失败 - 检测到
package.json与pnpm-lock.yaml不一致
修复流程
- 固定 Node 与 pnpm 版本
- 读取并记录失败日志,识别是否属于 lockfile 漂移问题
- 在工作分支中执行 lockfile 修复命令
- 再次执行
pnpm i --frozen-lockfile - 若通过,进入后续 lint/build/test
- 若仍失败,输出分类原因并停止自动提交
实现要点
- 在 GitHub Actions 中显式固定 pnpm 版本
- 在仓库配置中允许声明推荐 pnpm 版本
- 记录 lockfile diff 摘要
- 支持
packageManager字段作为优先版本来源
报告设计
Markdown 报告
- 运行元信息:时间、模式、阈值、仓库数
- 汇总统计:扫描仓库数、命中告警数、已修复数、失败数、跳过数
- 按仓库明细
- 按严重级别统计
- 按告警来源统计
- 失败原因分类
- 生成的 PR / 分支链接
JSON 报告
runIdstartedAt/finishedAtconfigsummaryrepositories[]alerts[]actions[]errors[]
技术选型
技术选型与 momei 项目保持一致,优先复用已验证的成熟方案。
全栈平台(apps/platform)
| 类别 | 选型 | 来源 |
|---|---|---|
| 框架 | Nuxt 4(全栈 SSR + API Routes) | momei |
| 语言 | TypeScript(strict mode) | — |
| 包管理 | pnpm(workspace monorepo) | momei |
| UI 组件 | PrimeVue 4(基于 @primeuix/themes) | momei |
| 样式方案 | SCSS + BEM,暗色模式通过 .dark 类切换 | momei |
| 国际化 | @nuxtjs/i18n(prefix_and_default 策略) | momei |
| 认证 | better-auth(邮箱 + 第三方登录) | momei |
| ORM | TypeORM + TypeORM Adapter | momei |
| 数据库 | SQLite(开发)/ MySQL / PostgreSQL | momei |
| 任务队列 | BullMQ + Redis | — |
| 日志 | winston(结构化 JSON 日志) | momei |
| 监控 | Sentry(@sentry/nuxt) | momei |
| PWA | @vite-pwa/nuxt | momei |
库(packages/*)
| 类别 | 选型 |
|---|---|
| 构建 | tsdown(输出 ESM + CJS + dts) |
| 测试 | Vitest |
| E2E | Playwright |
| Lint | ESLint(eslint-config-cmyr) |
| 类型检查 | tsc --noEmit |
| 样式检查 | stylelint(stylelint-config-cmyr) |
| 提交规范 | commitlint(commitlint-config-cmyr) + commitizen |
| 版本发布 | 自研 release 脚本(release:plan 推导 + release:version 版本提升 + release:publish 发布,见发布管线设计与发布指南)+ pnpm changelog(conventional-changelog-cmyr-config 生成日志) |
文档站(docs/)
| 类别 | 选型 |
|---|---|
| 框架 | VitePress |
| 国际化 | VitePress 内置 i18n(root + /en/ 前缀) |
| 主题 | 默认主题 |
| 搜索 | 本地搜索 |
平台架构(apps/platform)
平台分两个阶段交付:
- M6(最小平台 MVP):仓库 CRUD + 凭据管理 + 手动扫描 + 仪表板 + 单用户 + Docker Compose/SQLite(已交付 2026-08-08)
- M7.1(认证与用户体系):RBAC 三角色(admin/org_admin/viewer)+ 用户管理 + 个人界面 + 认证扩展(AUTH_MODE 互斥:OIDC SSO / GitHub·Google OAuth / 域名黑白名单);单组织模型(默认组织)——规划定稿 + 设计先行完成(2026-08-09)
- M7.2(平台能力深化):BullMQ/Redis 任务队列 + 定时批量 + i18n + 生产部署(PostgreSQL/Helm/Sentry)+ 跨平台 Git + MCP 发布(见 archive/todo-archive-phases-m6-m7-t711.md §M7.2)
分层架构
apps/platform/
├── pages/ # Vue 3 页面
│ ├── dashboard/ # 总览仪表板
│ ├── repos/ # 仓库管理(列表/详情/配置)
│ ├── alerts/ # 告警视图(按仓库/按严重级别/按来源)
│ ├── runs/ # 执行历史与报告
│ └── settings/ # 组织设置、凭据管理
├── server/
│ ├── api/ # REST API
│ │ ├── repos/ # CRUD + 触发扫描
│ │ ├── alerts/ # 查询、过滤、修复状态
│ │ ├── runs/ # 扫描历史、报告
│ │ └── auth/ # better-auth
│ ├── services/ # 业务逻辑层
│ │ ├── repo-sync.service # 仓库自动发现与同步
│ │ ├── scan-orchestrator # 扫描编排(调用 core 包)
│ │ ├── credential.service # Token 加密/解密
│ │ └── notification.service # 通知
│ └── queue/ # BullMQ(M7)
└── packages/shared/ # 前后端共享类型核心数据模型
Organization (id / name / plan / createdAt)
└── 1:N → Repository
├── owner / repo / platform(github)
├── defaultBranch / packageManager
├── credentialId → Credential (encryptedToken)
└── 1:N → ScanRun
├── mode / severityThreshold / status
├── startedAt / finishedAt / summary
└── 1:N → ScanResult
├── alertId / source / severity
├── packageName / fixable / fixStrategy
└── recommendedVersion / errorMessage平台与现有 packages 的关系
packages/cli (dependfix)
→ 被 apps/platform/server/services/scan-orchestrator 引用
→ 平台模式下不用 CLI 参数解析,直接调用编排核心
→ 需要将 runCli 拆为"纯函数编排"和"CLI 入口"两层(T505)
packages/core (@dependfix/core)
→ apps/platform 直接依赖
→ 共享类型:NormalizedSecurityAlert, ToolchainInfo, ExecutionSummary扫描调度策略(M7)
触发方式:
├── 手动触发(Web UI 点击)
├── 定时触发(cron,组织级配置)
└── 批量触发(选择多个仓库一次执行)
并发控制:
├── 全局最大并发数(如 5)
├── 单仓库互斥(同仓库同时只能一个扫描)
└── 优先级:手动 > 定时 > 批量前端
- Vue 3 Composition API +
<script setup lang="ts"> - PrimeVue 4 + 自定义主题(暗色模式支持)
- SCSS + BEM 命名规范
- 移动端做适当响应式优化,但不是首要目标
后端
- Nuxt Server Routes 作为 REST API
- better-auth 处理认证会话
- TypeORM 实体 + 数据库迁移
- SQLite(M6 开发/部署)/ PostgreSQL(M7 生产)
- Zod 校验输入
- BullMQ + Redis 任务调度(M7)
凭据安全
- GitHub 凭据(PAT 或 GitHub App PEM 私钥)使用平台级密钥(环境变量
NUXT_ENCRYPTION_KEY)做 AES-256-GCM 加密后存储——M17.1 C38 标准化 + M18.3 接入 GitHub App 路径 - 凭据类型双轨并存:
- PAT 路径(默认):
type='classic-pat' | 'fine-grained-pat',加密字段encryptedToken,commit author 固定dependfix[bot] - GitHub App 路径(自部署多仓 org 推荐):
type='github-app',加密字段encryptedPrivateKey(PEM 私钥),commit author 动态生成{app_id}+{bot_login}[bot]@users.noreply.github.com(GitHub App 协议要求)
- PAT 路径(默认):
- 解密仅在任务执行时、在 worker 内存中进行,用完即丢弃;token / privateKey 明文永不落库、永不进日志、永不进前端响应(API 返回
hasToken布尔) - 完整设计与落地步骤见 C22 PAT 无感升级评估
- M6 单用户模式下凭据管理简化;M7 多用户模式下按组织隔离
暗色模式
- 通过
<html>上的.darkCSS class 切换 - PrimeVue 主题引擎通过
darkModeSelector: '.dark'适配 - SCSS 使用
:global(.dark) .selector覆盖样式 - 跟随系统偏好 + 用户手动切换
国际化(M7)
- 最低支持:简体中文(zh-CN,默认)+ 英文(en-US)
- 可扩展:zh-TW、ja-JP、ko-KR
- URL 策略:
prefix_and_default(zh-CN 无前缀,en-US 加/en) - 语言检测:Cookie + 浏览器偏好 + URL
M7.2 T708 任务定义与验收见 todo-archive.md §M7.2。
认证
- better-auth 为核心
- M6:邮箱密码 + 邮箱验证(单用户模式)
- M7 扩展(设计详见 platform-auth-users.md,2026-08-09 定稿):
- 插件:admin(用户管理,M7.1 启用)、genericOAuth(OIDC SSO,M7.1 启用);username、magicLink、emailOTP、twoFactor、jwt 为架构预设但未排期(username 明确不启用——设计决策 D2)
- 第三方登录:GitHub OAuth、Google OAuth(可选,未配置环境变量时自动禁用对应登录方式)
- 未配置的第三方登录方式自动禁用,不阻塞启动
- 部署模式互斥(2026-08-09 M7 规划决策):
AUTH_MODE=enterprise|public二选一,不混合——enterprise(企业内部):OIDC SSO(better-authgenericOAuth,Azure AD / Okta / Keycloak / Google Workspace)+ 邮箱域名白名单注册准入;public(公开平台):GitHub / Google OAuth + 邮箱域名黑名单注册准入。SAML 2.0 不实现(登记 backlog)
- 数据库适配器:TypeORM Adapter
- 会话:数据库持久化 + Cookie,过期 30 天,每日更新
- JWT 算法:EdDSA / Ed25519
- RBAC:M7 实现角色模型(Admin / Org Admin / Repo Admin / Viewer)
详见 安全设计。
主要风险与应对
| 风险 | 应对 |
|---|---|
| 自动修复误伤业务 | 默认只创建分支/PR 不自动合并;限制 major 升级;强制最小验证 |
| GitHub API 限流 | 批量分页拉取;并发控制;报告中记录被限流情况 |
| lockfile 修复不稳定 | 固定 Node 与 pnpm 版本;保存安装日志与 lockfile diff |
| Code Scanning 范围过大 | 首期只开放白名单规则;未命中白名单只做建议输出 |
| AI 研判误判 | AI 修复代码必须通过 lint/typecheck/build;PR 不自动合并;置信度低于阈值时仅输出建议;限制 patch 范围 |
| Prompt 注入攻击 | 限制触发权限为管理员;输入仅限结构化数据;系统指令硬编码;外部内容做清洗 |
| 多租户安全 | 仓库间数据隔离;用户 Token 加密存储;操作审计日志完整记录 |
| 监测系统 vs 自动合并解耦(M24.1 关键决策 D8) | 依赖监测系统(PRCheck)不阻断 mergify 自动合并决策:mergify 负责通过即合(按 check-success=Test 单条件触发 rebase merge);PRCheck 负责失败即显(监测 + alert firing + ack UI)——两条链路互不干扰,监测 alert firing 仅记录 alert_event 写库 + UI 告警,不修改 check 状态 / 不修改 check-success=Test 判定。根因:监测系统目标是"用户感知"(失败即显 + ack),合并系统目标是"通过即合"(check 通过即合)——两类系统目标正交,强行耦合会导致监测 bug(如 alert firing 偶发)阻塞 mergify 合并。M24.1 实施:.github/mergify.yml 注释明确边界 + dependfix README + experience-archive §五十六 三处同步。详见 经验归档 §五十六 M24.1 关键决策 D8(experience-archive.md §五十六段) + .github/mergify.yml 注释。ernance/experience-archive-§49-§57-recent-investigation.md#五十六) + .github/mergify.yml 注释。 |
apps/platform 端到端 AI 研判集成(M26 阶段)
apps/platform 管理平台作为 dependfix 内部运维与公开部署的核心入口,承担 AI breaking change 研判能力的端到端联通职责。引擎层(packages/engine/src/ai/)M5 已闭环(commit 3475e6e),CLI / MCP / GitHub Action 三条用户路径全部支持 --ai 系列参数;M26 阶段将能力补齐到 apps/platform 平台(点 "扫描" 即可启用 AI 研判 + 可观测用量与评估结果)。
完整设计先行稿:platform-ai-integration.md;阶段切片见 todo-archive.md §M26 + archive/todo-archive-phases-m26.md §M26.1(M26 阶段 2026-09-10 完整闭环 + 归档;M26.1 应用层 10 commits / ~1130 行)。
数据模型扩展(M25.2a commit 1c65582)
Organization.aiApiKeyEncrypted(text, nullable):AES-256-GCM 加密的 AI API Key(复用ENCRYPTION_KEY+Credential.encryptedToken同源加密)Organization.aiProvider(varchar(32),默认'openai-compatible'):与 engine 层AiConfig.provider对齐Organization.aiModel(varchar(100),默认'deepseek-v4-flash'):与 engine 层AiConfig.model对齐Organization.aiBaseUrl(varchar(255),nullable):OpenAI 兼容端点覆盖Organization.aiApiUrl(varchar(255),nullable):Anthropic 端点覆盖Repository.aiEnabled(boolean,默认false):单仓库 AI 研判开关Repository.aiTrigger(enum(16),默认'both'):触发范围failure/major/bothScanRun.aiConfigSnapshot(JSON):本次扫描实际使用的 AI 配置快照(apiKey 脱敏为hasApiKey布尔,便于审计回溯)
加密策略:runScanInternal 阶段从 Organization.aiApiKeyEncrypted 内存解密注入 RuntimeConfig.ai.apiKey,用后即弃;日志与错误响应走 maskSecrets 脱敏。
调用链透传
PATCH /api/organizations/[id]/ai-config → Organization.ai* 字段更新
POST /api/repos/[id]/ai-config → Repository.aiEnabled / aiTrigger 更新
POST /api/repos/[id]/scan
{ aiEnabled?, aiTrigger? } → 运行时 override
→ scan-orchestrator service
→ resolveAiConfig(request, repo, org)
├── aiEnabled = request.aiEnabled ?? repo.aiEnabled ?? false
├── aiTrigger = request.aiTrigger ?? repo.aiTrigger ?? 'both'
└── apiKey = decrypt(org.aiApiKeyEncrypted)
→ ContainerExecutor.execute(ctx)
├── ...ctx.config
└── ai: { provider, model, apiKey, trigger, baseUrl, apiUrl }
→ DependfixApp.run()
→ assessBreakingChange() # M5 已闭环
→ RunResult.aiUsage
{ calls, inputTokens, outputTokens,
totalTokens, estimatedCostUsd }合并优先级(API override > Repository 默认 > Organization 共享)
aiEnabled:API 请求aiEnabled>Repository.aiEnabled>falseaiTrigger:API 请求aiTrigger>Repository.aiTrigger>'both'provider/model/apiKey/baseUrl/apiUrl:仅取 Organization 级(仓库级无 override)
错误规则:aiEnabled=true 但 Organization 未配 Key → 400 AI_KEY_REQUIRED;aiEnabled=true 但 Repository.aiEnabled=false 且 API 未显式传 aiEnabled → 拒绝(防误启用)。
三执行器一致性(M25.2a commit 7250ec1)
container / sandbox / github-action 三执行器同步透传 RuntimeConfig.ai:
- container:通过
...ctx.config展开自动透传 - sandbox:通过
DEPENDFIX_AI_*env vars 注入(仅aiEnabled=true时注入避免空字符串覆盖默认值) - github-action:通过
workflow_dispatch inputs透传(与action.yml7 个ai-*inputs 对齐)
A 阶段 audit 必查项:每加一个 RuntimeConfig 新字段必须三执行器都验证(不一致会埋 "未来 sandbox 启用后才发现 AI Key 透传缺失" 的坑)。
应用层 API 契约(M26.1 commit 40db65a)
| 端点 | 方法 | 权限 | 行为 |
|---|---|---|---|
/api/organizations/[id]/ai-config | PATCH | admin / org_admin | 更新 Organization.ai*;API Key 明文 → AES-256-GCM 加密;响应不回显 apiKey 明文(仅返回 hasAiApiKey) |
/api/repos/[id]/ai-config | GET | viewable | 返回 Repository + Organization + effective 三段配置;凭据最小化(响应不含 apiKey 明文) |
/api/repos/[id]/ai-config | POST | admin / org_admin | 更新 Repository.aiEnabled / aiTrigger;启用时校验 Organization 已配 Key |
写操作(PATCH / POST)通过 AuditEvent.type='ai_config_update' 登记审计(payloadJson 含 before/after diff + apiKey 明文脱敏);AuditEventType union 已扩展 ai_config_update 值(M26.1 commit 40db65a 同步)。
UI 集成(M26.1 commit 80138b1 + d7fb63b)
- Organization AI 配置表单(
ai-config-form.vue):Provider / Model / API Key (Password) / Base URL / Anthropic URL 5 字段 + 保存按钮 + 已配置 Badge(i18nai.orgSection段) - 仓库 AI 研判开关(
repo-ai-toggle.vue):ToggleSwitch + trigger 三选项 Select + Organization 未配 Key 时降级为禁用 + 警告 Message(apps/platform/app/pages/repos/[id]/runs.vue顶部挂载) - 扫描对话框 AI override 折叠面板(
scan-config-dialog.vue,M26.1 后续 commit 实施):运行时覆盖仓库默认 + trigger 选项 + Organization 未配 Key 时禁用 - RunDetailDialog AI 用量 section:5 字段(calls / inputTokens / outputTokens / totalTokens / estimatedCostUsd)v-if 条件渲染(未启用 AI 时整段隐藏);i18n
ai.usageSectionTitle段 - alerts 视图 AI 评估列:evaluated / skipped 二态 Tag(
ai.alertsEvaluatedTag/ai.alertsSkippedTag)
治理验收(与 engine 层一致)
- AI 输出必须通过
lint/typecheck/build(沿用 §AI 研判误判处理 现有治理基线) - AI 生成的 PR 不自动合并(与 standards/index.md §AI 研判默认不自动合并 一致)
- 置信度低于阈值仅输出建议(engine 层
safety-gate.ts已实施) - AI API Key 日志脱敏(复用
packages/engine/src/ai/secrets.ts:maskSecrets) - 仓库级
aiEnabled=false时 API 请求 override 也被拒绝(防止误启用) - 三执行器同步透传 audit 必查项(新增 RuntimeConfig 字段必须三执行器都验证)
关联文档
- platform-ai-integration.md — M26 阶段完整设计先行稿(4 API 端点 + UI + i18n + docs)
- platform-auth-users.md — Organization 实体扩展基线(M7.1 已落地)
- platform-scheduled-batch.md — 定时扫描链路,AI 研判可统一应用
- sandbox-security-governance.md — AI 研判在供应链防护的角色
- experience-archive.md §五十六(M24.1 关键决策 D8) — 监测系统 vs 自动合并解耦