Skip to content

系统架构

状态: ✅ 已落地(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 形式。

总体方案

采用"统一编排器 + 告警采集器 + 修复执行器 + 报告器"的分层设计。

mermaid
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.jsonpnpm-lock.yaml

首期优先支持"手动指定 + 基于 owner 自动发现"。

修复优先级

默认按以下顺序执行:

  1. Critical 的依赖漏洞
  2. High 的依赖漏洞
  3. 会阻塞 CI 的 lockfile 问题
  4. 可模板化处理的 code scanning 问题
  5. 其余问题只输出建议

运行模式

本地直接运行

  • report-only:只拉取告警并生成报告
  • fix:执行修复但不推送
  • fix-and-pr:执行修复并推送分支 / 创建 PR

GitHub Action 运行

触发方式:workflow_dispatchschedule

输入参数:owner / organization、repositories、severity-threshold、mode、max-repos、dry-run

专用 Agent 设计

角色定位

负责安全告警自动修复的任务编排:

  • 拉取并统一标准化 GitHub 安全告警
  • 根据配置决定要处理哪些仓库、哪些告警、哪些修复策略
  • 调用对应技能完成采集、过滤、修复、验证和报告
  • 在失败时给出结构化原因

输入

  • GitHub Token / GitHub App 凭证
  • 目标仓库列表或自动发现参数
  • 修复策略配置
  • 严重级别过滤规则
  • 运行模式:report-onlyfixfix-and-pr

输出

  • 每个仓库的执行结果
  • 已修复告警列表
  • 未修复告警列表及原因
  • 创建的分支、提交、PR、评论链接
  • Markdown 报告与 JSON 报告

决策原则

  • 默认先修复高收益、低风险问题
  • 默认优先修复依赖问题,其次修复 lockfile 问题,最后处理可模板化的 code scanning 问题
  • 当验证失败、升级跨度过大或需要业务判断时,停止自动提交,仅输出建议

pnpm frozen-lockfile 自动修复

触发条件

  • 修复依赖漏洞后安装失败
  • 单独执行验证时 pnpm i --frozen-lockfile 失败
  • 检测到 package.jsonpnpm-lock.yaml 不一致

修复流程

  1. 固定 Node 与 pnpm 版本
  2. 读取并记录失败日志,识别是否属于 lockfile 漂移问题
  3. 在工作分支中执行 lockfile 修复命令
  4. 再次执行 pnpm i --frozen-lockfile
  5. 若通过,进入后续 lint/build/test
  6. 若仍失败,输出分类原因并停止自动提交

实现要点

  • 在 GitHub Actions 中显式固定 pnpm 版本
  • 在仓库配置中允许声明推荐 pnpm 版本
  • 记录 lockfile diff 摘要
  • 支持 packageManager 字段作为优先版本来源

报告设计

Markdown 报告

  • 运行元信息:时间、模式、阈值、仓库数
  • 汇总统计:扫描仓库数、命中告警数、已修复数、失败数、跳过数
  • 按仓库明细
  • 按严重级别统计
  • 按告警来源统计
  • 失败原因分类
  • 生成的 PR / 分支链接

JSON 报告

  • runId
  • startedAt / finishedAt
  • config
  • summary
  • repositories[]
  • 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
ORMTypeORM + TypeORM Adaptermomei
数据库SQLite(开发)/ MySQL / PostgreSQLmomei
任务队列BullMQ + Redis
日志winston(结构化 JSON 日志)momei
监控Sentry(@sentry/nuxt)momei
PWA@vite-pwa/nuxtmomei

库(packages/*)

类别选型
构建tsdown(输出 ESM + CJS + dts)
测试Vitest
E2EPlaywright
LintESLint(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 协议要求)
  • 解密仅在任务执行时、在 worker 内存中进行,用完即丢弃;token / privateKey 明文永不落库、永不进日志、永不进前端响应(API 返回 hasToken 布尔)
  • 完整设计与落地步骤见 C22 PAT 无感升级评估
  • M6 单用户模式下凭据管理简化;M7 多用户模式下按组织隔离

暗色模式

  • 通过 <html> 上的 .dark CSS 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-auth genericOAuth,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 / both
  • ScanRun.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 > false
  • aiTrigger:API 请求 aiTrigger > Repository.aiTrigger > 'both'
  • provider / model / apiKey / baseUrl / apiUrl:仅取 Organization 级(仓库级无 override)

错误规则:aiEnabled=true 但 Organization 未配 Key → 400 AI_KEY_REQUIREDaiEnabled=trueRepository.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.yml 7 个 ai-* inputs 对齐)

A 阶段 audit 必查项:每加一个 RuntimeConfig 新字段必须三执行器都验证(不一致会埋 "未来 sandbox 启用后才发现 AI Key 透传缺失" 的坑)。

应用层 API 契约(M26.1 commit 40db65a

端点方法权限行为
/api/organizations/[id]/ai-configPATCHadmin / org_admin更新 Organization.ai*;API Key 明文 → AES-256-GCM 加密;响应不回显 apiKey 明文(仅返回 hasAiApiKey
/api/repos/[id]/ai-configGETviewable返回 Repository + Organization + effective 三段配置;凭据最小化(响应不含 apiKey 明文)
/api/repos/[id]/ai-configPOSTadmin / 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(i18n ai.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 字段必须三执行器都验证)

关联文档

Released under the MIT License.