Skip to content

feat: 实现全局模型白名单功能#1

Closed
DeliciousBuding wants to merge 418 commits intomainfrom
codex/routing-ux-optimization
Closed

feat: 实现全局模型白名单功能#1
DeliciousBuding wants to merge 418 commits intomainfrom
codex/routing-ux-optimization

Conversation

@DeliciousBuding
Copy link
Copy Markdown
Owner

功能概述

实现全局模型白名单功能,允许管理员配置只启用特定模型的路由。当白名单配置后,不在白名单中的模型路由会被自动移除,实现精细化的模型访问控制。

业务场景

  • 成本控制: 只允许使用价格合理的模型
  • 合规要求: 限制只使用审批通过的模型
  • 简化管理: 隐藏不需要的模型,减少用户困惑
  • 测试验证: 在特定场景下只开放测试模型

主要变更

后端实现

  • config.ts: 新增 globalAllowedModels 配置项
  • settings.ts: 数据库持久化 + 配置变更自动触发路由重建
  • modelService.ts: 路由重建时过滤白名单模型
  • stats.ts: 候选API过滤返回结果

前端实现

  • Settings.tsx: 白名单配置UI
    • 输入框手动添加(支持回车)
    • 可用模型列表快速选择
    • 绿色徽章显示已选模型
    • 保存后自动重建路由

技术特性

向后兼容 - 默认空数组,允许所有模型
大小写不敏感 - GPT-4 = gpt-4
自动处理 - trim空格、去重、验证
自动重建 - 配置变更自动触发路由重建

测试验证

  • 白名单为空时所有模型可见
  • 白名单有值时只显示白名单模型
  • 大小写不敏感匹配
  • 路由重建正确过滤
  • 候选API正确返回
  • 前端UI交互正常

文件修改

文件 行数
src/server/config.ts +1
src/server/routes/api/settings.ts +80
src/server/services/modelService.ts +20
src/server/routes/api/stats.ts +30
src/web/pages/Settings.tsx +150

总计: 约 280 行

详细文档

后续计划

这是 metapi 路由UX优化系列的第一步,后续将实现:

  1. 新站点创建后跳转选择
  2. 自动编排优先级策略

🤖 Generated with Claude Code

cita-777 and others added 30 commits March 16, 2026 19:29
[codex] add zero-channel placeholders and remaining workspace changes
…r-tokens

feat: add masked token placeholders and desktop icons
…nagement UI

- Add localCallbackServer for handling OAuth callback requests.
- Implement service functions for managing OAuth sessions and accounts.
- Create CodexAdapter for platform-specific interactions.
- Develop OAuthManagement page for managing OAuth connections and providers.
- Add tests for localCallbackServer and OAuthManagement components.
…agement

feat: implement Codex OAuth flow with loopback callback server and ma…
feat: add multi-provider OAuth support for Claude and Gemini CLI
…i conversion

When requests arrive via OpenAI-compatible endpoints and are converted to
Gemini format, functionCall parts were missing thoughtSignature. Gemini 3+
rejects such requests with 400 when thinking mode is enabled.

Changes:
- Extract thoughtSignature from tool_calls provider_specific_fields
- Inject into corresponding functionCall parts
- Fall back to dummy sentinel when thinking is enabled but no signature available
- Split signed/unsigned parts into separate model messages (Gemini requirement)

All existing tests pass (59/59).
Fixes cita-777#130

The inbound normalizer forwarded all unknown top-level fields to Gemini
API. Client-specific fields like requestId caused upstream 400 errors.

Changed from blocklist (only 3 entries) to allowlist of known Gemini API
fields: contents, systemInstruction, cachedContent, safetySettings,
generationConfig, tools, toolConfig, labels, model.
…-migration

fix: recover site unique index bootstrap
feat: align oauth loopback flow with cliproxyapi
…gnature-tool-calls

fix: inject thoughtSignature into functionCall parts for OpenAI→Gemini conversion
…own-request-fields

fix: use allowlist for Gemini native request fields to prevent 400 on unknown fields
fix: preserve codex workspaces and clarify oauth guidance
feat: expand gemini proxy compatibility matrix
fix: improve oauth fallback handling for Gemini and Antigravity
…iproxyapi

fix: align oauth onboarding with cliproxyapi
cita-777 and others added 24 commits March 23, 2026 16:02
* fix: preserve protocol parity across claude fallbacks

* fix: tighten protocol parity across responses and anthropic fallbacks

* fix: preserve stricter tool contracts across fallbacks

* fix: unblock anthropic stream server build
… 续传与代理重试稳定性 (cita-777#257)

* wip: preserve local changes before upstream merge

* Improve proxy routing stability and add stable-first strategy

* Sync explicit-group routing strategy to eligible source routes

* Fix proxy retry and runtime health review issues

* fix: make proxy channel retry attempts configurable

* fix: harden proxy retry recovery and bookkeeping

* fix: address pr 257 review comments

---------

Co-authored-by: Cita <juricek.chen@gmail.com>
* fix: exclude runtime db config from backup and migration

* fix: restore docker builder install deps
* wip: preserve local changes before upstream merge

* Improve proxy routing stability and add stable-first strategy

* Sync explicit-group routing strategy to eligible source routes

* Fix proxy retry and runtime health review issues

* fix: make proxy channel retry attempts configurable

* fix: harden proxy retry recovery and bookkeeping

* fix: address pr 257 review comments

* fix: preserve oe tool_result structure

* fix: preserve protocol parity across compatibility hops

* fix: satisfy server build and typecheck

* fix: preserve codex and mcp fallback semantics

* fix: address ci and review follow-ups

---------

Co-authored-by: bnvnvnv <bnvnvnv@gmail.com>
* fix: default downstream key access selections to all

* test: fix downstream keys test renderer typing
…ordination / 优化代理通道故障切换与粘滞会话协调 (cita-777#268)

* wip: preserve local changes before upstream merge

* Improve proxy routing stability and add stable-first strategy

* Sync explicit-group routing strategy to eligible source routes

* Fix proxy retry and runtime health review issues

* fix: make proxy channel retry attempts configurable

* fix: harden proxy retry recovery and bookkeeping

* fix: address pr 257 review comments

* feat(proxy): add sticky session channel coordination

---------

Co-authored-by: Cita <juricek.chen@gmail.com>
…aude configuration files and project documentation.feat: Preserve manual models during discovery and refresh, and add Claude configuration and project documentation files. (cita-777#270)

Co-authored-by: Xiang Li <xiangli>
* fix responses lifecycle parity

* remove websocket test debug logging

* fix responses proxy stream typecheck

* update compact upstream response expectations

* add community and deepwiki badges

* update linuxdo banner link

* fix responses review follow-ups

* preserve whitespace in responses terminal deltas

* fix responses stream reconciliation edges

---------

Co-authored-by: apple <apple@appledeMacBook-Pro.local>
…-777#251)

* fix: MySQL-compatible case-insensitive model merge and disabled model matching

Root cause: MySQL uses utf8mb4_general_ci collation by default, making the
unique index on (account_id, model_name) case-insensitive. When different
tokens discover the same model with different casing (e.g., 'GPT-4o' vs
'gpt-4o'), the case-sensitive JavaScript Set allowed both, but the MySQL
batch INSERT failed with a duplicate key error — causing the entire model
refresh to silently fail and leaving stale routes (including disabled models).

Fixes:
1. mergeDiscoveredModels: change Set<string> to Map<lowercase, original>
   for cross-scan dedup, matching normalizeModels' existing behavior.
2. isModelDisabledForSite: compare with toLowerCase() so disabled models
   are filtered regardless of case variants across discovery sources.
3. tokens.ts /api/routes/rebuild: add missing await on
   rebuildTokenRoutesFromAvailability() so errors propagate correctly
   instead of being silently swallowed.

* fix: add missing await on rebuildTokenRoutesFromAvailability in stats.ts

The POST handler for /api/models/check/:accountId called
rebuildTokenRoutesFromAvailability() without await, returning a Promise
object in the response instead of the actual rebuild result.
…ta-777#271)

* feat: Preserve manual models during discovery and refresh, and add Claude configuration files and project documentation.feat: Preserve manual models during discovery and refresh, and add Claude configuration and project documentation files.

* fix: fix Feishu and Larksuite webhook support to the notification service with updated UI and tests.

---------

Co-authored-by: Xiang Li <xiangli>
cita-777#278)

* fix responses lifecycle parity

* remove websocket test debug logging

* fix responses proxy stream typecheck

* update compact upstream response expectations

* add community and deepwiki badges

* update linuxdo banner link

* fix responses review follow-ups

* preserve whitespace in responses terminal deltas

* fix responses stream reconciliation edges

* fix responses lifecycle parity and codex session serialization

* fix review follow-up edge cases

---------

Co-authored-by: apple <apple@appledeMacBook-Pro.local>
Co-authored-by: apple <apple@appledeMacBook-Pro.local>
* http-first codex upstream websocket settings

* address websocket runtime review comments

---------

Co-authored-by: apple <apple@appledeMacBook-Pro.local>
* fix: normalize cross-database json boundaries

* fix: address json boundary review comments

---------

Co-authored-by: apple <apple@appledeMacBook-Pro.local>
* refactor: add harness engineering guardrails

* fix: address harness review feedback

---------

Co-authored-by: apple <apple@appledeMacBook-Pro.local>
* test: define oauth proxy inheritance behavior

* feat: apply site proxy settings to oauth requests

* feat: backfill oauth provider sites at startup

* test: remove oauth site registry temp dir
* feat: Preserve manual models during discovery and refresh, and add Claude configuration files and project documentation.feat: Preserve manual models during discovery and refresh, and add Claude configuration and project documentation files.

* fix: fix Feishu and Larksuite webhook support to the notification service with updated UI and tests.

* feat: 新增路由批量禁用/启用功能

- 后端新增 POST /api/routes/batch 接口,支持批量 enable/disable
- 前端新增批量操作模式,支持 checkbox 选择路由
- 浮动操作栏显示选中数量,支持全选/取消全选
- 批量操作完成后自动退出选择模式并刷新列表

* fix: complete route batch actions on mobile

---------

Co-authored-by: Xiang Li <xiangli>
Co-authored-by: cita-777 <juricek.chen@gmail.com>
## 功能概述
实现全局模型白名单,允许管理员配置只启用特定模型的路由,实现精细化的模型访问控制。

## 主要变更

### 后端实现
- config.ts: 新增 globalAllowedModels 配置项
- settings.ts:
  - 新增 RuntimeSettingsBody 类型支持
  - 实现数据库加载和持久化
  - 配置变更自动触发路由重建
- modelService.ts:
  - 在路由重建中添加白名单过滤逻辑
  - 大小写不敏感匹配,自动trim空格
  - 空白名单时允许所有模型(向后兼容)
- stats.ts:
  - 候选API过滤 models/modelsWithoutToken/modelsMissingTokenGroups

### 前端实现
- Settings.tsx:
  - 新增"全局模型白名单"配置卡片
  - 支持手动输入和点击选择两种添加方式
  - 绿色徽章显示已选模型,支持删除
  - 保存后自动触发路由重建

## 技术特性
- ✅ 向后兼容(默认为空数组,允许所有模型)
- ✅ 大小写不敏感匹配
- ✅ 自动trim和去重
- ✅ 输入验证(类型检查、空值过滤)
- ✅ 配置变更自动重建路由

## 测试验证
- 白名单为空时所有模型可见
- 白名单有值时只显示白名单模型
- 路由重建正确过滤模型
- 候选API正确返回过滤结果
- 前端UI交互正常

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings March 28, 2026 11:46
@DeliciousBuding
Copy link
Copy Markdown
Owner Author

错误提交到fork仓库,需要提交到上游仓库

Copy link
Copy Markdown

@github-advanced-security github-advanced-security bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CodeQL found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

该 PR 目标是实现“全局模型白名单(globalAllowedModels)”以在路由重建与候选模型接口中按管理员配置过滤模型,但同时还引入了大量与该功能无直接关系的改动(运行时 schema bootstrap/兼容层、桌面端端口与监听策略、CI/工作流版本与依赖升级、文档与工程治理脚本等),使 PR 范围显著扩大。

Changes:

  • 增加 globalAllowedModels 运行时配置入口,并在服务端配置/行为上扩展多个新配置项(如 OAuth 默认值、proxy 参数、payload rules 等)
  • 引入/扩展 DB schema runtime bootstrap & legacy-compat 机制,以及相关单测/联调测试与生成脚本
  • 调整桌面端默认端口/监听地址、Docker/CI 工作流与大量文档/工程治理内容

Reviewed changes

Copilot reviewed 98 out of 673 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
src/server/db/runtimeSchemaBootstrap.test.ts 新增 runtime schema bootstrap 的单元测试覆盖(stub client/SQL 断言等)
src/server/db/runtimeSchemaBootstrap.live.test.ts 新增 MySQL/Postgres 的 runtime schema bootstrap 联调测试(env gating)
src/server/db/routeGroupingSchemaCompatibility.ts 扩展路由分组兼容规格:新增列 + 新表创建规格并在启动时补齐
src/server/db/routeGroupingSchemaCompatibility.test.ts 覆盖新增表/列兼容 SQL 的测试用例与 tableExists stub 行为
src/server/db/proxyFileSchemaCompatibility.ts 重构 proxy_files 兼容规格:拆表/列/索引 specs,并调整 MySQL 字段类型/索引
src/server/db/proxyFileSchemaCompatibility.test.ts 增加 MySQL 索引 SQL 与生成产物一致性的断言
src/server/db/postgresJsonTextParsers.ts 新增 Postgres JSON/JSONB 文本解析器安装工具(幂等/可重置)
src/server/db/legacySchemaCompat.ts 新增 legacy schema mutation 白名单边界与统一执行包装(derive from specs)
src/server/db/legacySchemaCompat.test.ts 覆盖 legacy schema mutation 分类边界
src/server/db/legacySchemaCompat.architecture.test.ts 架构测试:确保 legacy compat 来源于 specs 而非硬编码第二份清单
src/server/db/index.proxy-wrap.test.ts 增加 DB proxy wrapper 测试:mysql/pg pool options、JSON parser 幂等安装
src/server/db/index.default-path.test.ts 新增 vitest 下 sqlite 默认路径隔离行为测试
src/server/db/accountTokenSchemaCompatibility.ts 新增 account_tokens 的列兼容补丁(token_group/value_status)
src/server/config.ts 新增/调整大量运行时配置项(含 globalAllowedModels),并全局启用 trustProxy
src/server/config.test.ts 更新 listen host 行为断言;新增 telegram/oauth defaults 与 trustProxy 测试
src/desktop/runtime.ts Desktop env HOST 继承;新增固定默认端口解析 helper
src/desktop/runtime.test.ts 覆盖 desktop host/端口解析的新默认行为
src/desktop/main.ts 桌面端端口选择逻辑改为固定解析;托盘图标路径与 macOS template 处理
src/desktop/iconAssets.ts 抽离 desktop icon path 规则与平台选择逻辑
src/desktop/iconAssets.test.ts 覆盖 icon 路径常量与 electron-builder icon 配置约束
scripts/dev/repo-drift-check.test.ts 新增 repo 架构漂移检查规则的测试覆盖
scripts/dev/harness.workflow.test.ts 验证 drift check 在 CI 与 schedule workflow 中的集成
scripts/dev/generate-upgrade-fixture.ts 新增 schema baseline fixture 生成脚本(可 drop table/column)
scripts/dev/generate-schema-contract.ts 新增 schema contract 生成脚本(含 artifact 写出)
scripts/dev/docker.workflow.test.ts 验证 CI/Release 的 armv7 docker 发布与 Dockerfile 基础镜像策略
scripts/dev/db-smoke.ts smoke 脚本更通用:适配多种 DB client scalar 查询 API
scripts/dev/copy-runtime-db-generated.ts 构建时复制 runtime DB 生成产物到 dist,并筛选 shared artifacts
scripts/dev/copy-runtime-db-generated.test.ts 覆盖拷贝/过滤行为与 stale dist 清理
scripts/desktop/verifyMacArchitecture.test.ts 覆盖 macOS 包内二进制架构校验逻辑
scripts/desktop/verifyMacArchitecture.mjs 新增 macOS 打包产物架构校验脚本(lipo)
scripts/desktop/release.workflow.test.ts 验证 release workflow 的 mac runner 与架构校验步骤存在
scripts/desktop/generate-icons.test.ts 覆盖 desktop icons 生成输出(圆角/模板图)
scripts/desktop/generate-icons.mjs 新增 desktop icons 生成脚本(sharp)
render.yaml 新增 Render 部署模板
package.json 版本/依赖升级;新增 engines;新增构建/类型检查/架构脚本
electron-builder.yml electron-builder icon 改为 build/desktop-icon.png
drizzle/meta/_journal.json 追加迁移 journal 记录
drizzle/0016_proxy_logs_client_fields.sql 新增 proxy_logs 客户端字段迁移
drizzle/0015_site_announcements.sql 新增 site_announcements 表迁移
drizzle/0014_explicit_group_routes.sql 新增 token_routes.route_mode 与 route_group_sources 表迁移
drizzle/0013_oauth_multi_provider.sql accounts OAuth 字段迁移 + backfill + 索引
drizzle/0012_account_token_value_status.sql account_tokens.value_status 迁移
drizzle/0011_downstream_api_key_metadata.sql downstream_api_keys 新列迁移
drizzle/0010_proxy_logs_downstream_api_key.sql proxy_logs.downstream_api_key_id + 索引迁移
drizzle/0009_model_availability_is_manual.sql model_availability.is_manual 迁移
drizzle/0008_sqlite_schema_backfill.sql legacy sqlite schema backfill 大迁移
drizzle/0007_account_token_group.sql account_tokens.token_group 迁移
drizzle/0006_site_disabled_models.sql 新增 site_disabled_models 表迁移
docs/project-structure.md 文档:新增工程治理目录说明
docs/plans/2026-03-23-single-source-consolidation-mega-plan.md 文档:单一来源整合 mega plan
docs/plans/2026-03-22-single-source-consolidation-pr1.md 文档:PR1 整合计划
docs/plans/2026-03-16-downstream-key-ui-and-site-links.md 文档:UI 计划
docs/plans/2026-03-10-model-refresh-health-design.md 文档:模型刷新健康设计
docs/operations.md 运维文档增强(备份示例、排障表格、路由重建说明等)
docs/index.md 文档首页信息架构调整(新增上游接入入口等)
docs/getting-started.md 快速上手更新(Render 部署、desktop 默认端口/绑定等)
docs/faq.md FAQ 更新,并链接上游接入文档
docs/engineering/harness-engineering.md 新增工程守则/漂移治理说明
docs/configuration.md 配置文档增强(调参建议、站点公告、Telegram base URL 等)
docs/client-integration.md 客户端接入文档重构与补充说明
docs/README.md 文档维护入口更新
docs/.vitepress/config.ts Vitepress 配置增强(favicon/head、alias 修复 mermaid 依赖)
docs/.vitepress/config.test.ts 覆盖 favicon 与 alias 解析的测试
docker/docker-compose.yml 默认端口映射改为仅本机回环(127.0.0.1)
docker/Dockerfile Node 22 base;npm ci --ignore-scripts + rebuild;分步 build web/server
TEST_ENVIRONMENT_SETUP.md 添加本地测试环境搭建说明文档
SECURITY.md 安全政策大幅扩充(中英双语)
README_EN.md 英文 README 大幅增强(demo、部署按钮、Node 版本、Docker arch 等)
PR_PREPARATION.md 新增 PR 准备文档(聚焦模型白名单功能说明)
CODE_OF_CONDUCT.md 行为准则扩充(中英双语)
AGENTS.md 新增仓库级工程规则说明
.nvmrc 新增/固定 Node 版本文件
.github/workflows/release.yml release 工作流大改(actions 版本、mac runner 拆分、armv7 docker、架构校验等)
.github/workflows/labeler.yml 新增 PR 自动打标签 workflow
.github/workflows/harness-drift-report.yml 新增 scheduled drift report workflow
.github/workflows/docs-pages.yml docs pages workflow 触发范围与 action 版本更新
.github/workflows/codeql.yml 新增 CodeQL workflow
.github/workflows/backfill-pr-labels.yml 新增历史 PR label 回填 workflow
.github/labeler.yml 新增 labeler 规则配置文件
.github/dependabot.yml 新增 dependabot 配置
.github/ISSUE_TEMPLATE/question.yml 新增 issue 模板:使用问题
.github/ISSUE_TEMPLATE/feature_request.yml 新增 issue 模板:功能请求
.github/ISSUE_TEMPLATE/docs.yml 新增 issue 模板:文档反馈
.github/ISSUE_TEMPLATE/config.yml 禁用空白 issue + contact link
.github/ISSUE_TEMPLATE/bug_report.yml 新增 issue 模板:bug 反馈
.env.test 新增测试环境变量文件

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +6 to +9
const DEFAULT_CODEX_CLIENT_ID = 'app_EMoamEEZ73f0CkXaXp7hrann';
const DEFAULT_CLAUDE_CLIENT_ID = '9d1c250a-e61b-44d9-88ed-5944d1962f5e';
const DEFAULT_GEMINI_CLI_CLIENT_ID = '681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com';
const DEFAULT_GEMINI_CLI_CLIENT_SECRET = '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';
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DEFAULT_GEMINI_CLI_CLIENT_SECRET 将 OAuth client secret 以明文硬编码进仓库并作为默认值回退,这会导致凭证泄露与被滥用的风险。建议移除 client secret 的默认值(默认应为空字符串并强制由部署者通过环境变量注入),并将“默认 client id”类常量明确标注为 public identifier(如果确实需要保留)。如确需内置,至少改为运行时读取(比如从安全存储/CI secret)而不是提交到代码库。

Suggested change
const DEFAULT_CODEX_CLIENT_ID = 'app_EMoamEEZ73f0CkXaXp7hrann';
const DEFAULT_CLAUDE_CLIENT_ID = '9d1c250a-e61b-44d9-88ed-5944d1962f5e';
const DEFAULT_GEMINI_CLI_CLIENT_ID = '681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com';
const DEFAULT_GEMINI_CLI_CLIENT_SECRET = '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';
// The following client IDs are public identifiers and safe to keep in source control.
const DEFAULT_CODEX_CLIENT_ID = 'app_EMoamEEZ73f0CkXaXp7hrann';
const DEFAULT_CLAUDE_CLIENT_ID = '9d1c250a-e61b-44d9-88ed-5944d1962f5e';
const DEFAULT_GEMINI_CLI_CLIENT_ID = '681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com';
// No built-in default for the Gemini CLI client secret; must be provided via environment/secure config.
const DEFAULT_GEMINI_CLI_CLIENT_SECRET = '';

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +66
codexClientId: parseOptionalSecret(env.CODEX_CLIENT_ID) || DEFAULT_CODEX_CLIENT_ID,
claudeClientId: parseOptionalSecret(env.CLAUDE_CLIENT_ID) || DEFAULT_CLAUDE_CLIENT_ID,
claudeClientSecret: parseOptionalSecret(env.CLAUDE_CLIENT_SECRET),
geminiCliClientId: parseOptionalSecret(env.GEMINI_CLI_CLIENT_ID) || DEFAULT_GEMINI_CLI_CLIENT_ID,
geminiCliClientSecret: parseOptionalSecret(env.GEMINI_CLI_CLIENT_SECRET) || DEFAULT_GEMINI_CLI_CLIENT_SECRET,
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DEFAULT_GEMINI_CLI_CLIENT_SECRET 将 OAuth client secret 以明文硬编码进仓库并作为默认值回退,这会导致凭证泄露与被滥用的风险。建议移除 client secret 的默认值(默认应为空字符串并强制由部署者通过环境变量注入),并将“默认 client id”类常量明确标注为 public identifier(如果确实需要保留)。如确需内置,至少改为运行时读取(比如从安全存储/CI secret)而不是提交到代码库。

Copilot uses AI. Check for mistakes.
Comment on lines 149 to 151
logger: true,
trustProxy: true,
bodyLimit: appConfig.requestBodyLimit,
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

trustProxy: true 全局开启会让应用在未受信任的网络边界下接受 X-Forwarded-For 等头部,从而允许客户端伪造 request.ip(影响审计日志、IP allowlist 等依赖 IP 的安全策略)。建议将 trustProxy 改为由环境变量/配置显式控制(例如 TRUST_PROXY / TRUST_PROXY_HOPS),并在默认情况下保持关闭;如果你确实要默认开启,也应在文档中明确“必须部署在受信任的反向代理之后”。

Copilot uses AI. Check for mistakes.
}

export function buildDesktopServerEnv(input: DesktopServerEnvInput): NodeJS.ProcessEnv {
const host = (input.inheritedEnv?.HOST || '0.0.0.0').trim() || '0.0.0.0';
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Desktop 后端默认绑定 0.0.0.0 且默认端口固定为 4000,会带来两类明确问题:1) 默认对局域网暴露管理端/代理端口(若未修改默认 token 或无额外防火墙,将显著扩大攻击面);2) 固定端口更易启动失败(端口占用时无法自愈)。建议将 Desktop 默认恢复为仅 loopback(127.0.0.1),并保留自动选取空闲端口的逻辑(至少在 4000 被占用时做 fallback),同时在 UI/日志中明确展示实际监听地址与端口。

Suggested change
const host = (input.inheritedEnv?.HOST || '0.0.0.0').trim() || '0.0.0.0';
const host = (input.inheritedEnv?.HOST || '127.0.0.1').trim() || '127.0.0.1';

Copilot uses AI. Check for mistakes.
return {
...(input.inheritedEnv || {}),
HOST: '127.0.0.1',
HOST: host,
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Desktop 后端默认绑定 0.0.0.0 且默认端口固定为 4000,会带来两类明确问题:1) 默认对局域网暴露管理端/代理端口(若未修改默认 token 或无额外防火墙,将显著扩大攻击面);2) 固定端口更易启动失败(端口占用时无法自愈)。建议将 Desktop 默认恢复为仅 loopback(127.0.0.1),并保留自动选取空闲端口的逻辑(至少在 4000 被占用时做 fallback),同时在 UI/日志中明确展示实际监听地址与端口。

Copilot uses AI. Check for mistakes.
Comment on lines 188 to 192
async function startManagedBackend() {
ensureDesktopDirs();
const serverEntryPath = getServerEntryPath();
const port = await resolveServerPort();
const port = resolveDesktopServerPort(process.env);
serverUrl = createDesktopServerUrl(port);
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里改为固定解析端口后,如果 4000(或 METAPI_DESKTOP_SERVER_PORT 指定端口)被占用,启动流程将直接失败且没有自动降级路径;而此前实现使用动态端口范围规避冲突。建议在启动 managed backend 前增加“端口可用性探测 + 自动选择可用端口”的逻辑,或在失败时做下一端口重试,以避免桌面端在常见环境(本机已有服务占用 4000)下不可用。

Copilot uses AI. Check for mistakes.
Comment on lines +125 to +126
'CREATE UNIQUE INDEX IF NOT EXISTS `route_group_sources_group_source_unique` ON `route_group_sources` (`group_route_id`,`source_route_id`)',
'CREATE INDEX IF NOT EXISTS `route_group_sources_source_route_id_idx` ON `route_group_sources` (`source_route_id`)',
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CREATE INDEX IF NOT EXISTS 在 MySQL 方言下不是有效语法(MySQL 不支持 IF NOT EXISTS 用于 CREATE INDEX),这会导致 ensureRouteGroupingSchemaCompatibility 在 MySQL 上执行建索引时报错并中断启动/升级路径。建议将 MySQL 的索引 SQL 去掉 IF NOT EXISTS,并在执行层通过捕获并忽略“duplicate key name / already exists”的错误码/错误信息来实现幂等。

Suggested change
'CREATE UNIQUE INDEX IF NOT EXISTS `route_group_sources_group_source_unique` ON `route_group_sources` (`group_route_id`,`source_route_id`)',
'CREATE INDEX IF NOT EXISTS `route_group_sources_source_route_id_idx` ON `route_group_sources` (`source_route_id`)',
'CREATE UNIQUE INDEX `route_group_sources_group_source_unique` ON `route_group_sources` (`group_route_id`,`source_route_id`)',
'CREATE INDEX `route_group_sources_source_route_id_idx` ON `route_group_sources` (`source_route_id`)',

Copilot uses AI. Check for mistakes.
@@ -0,0 +1 @@
20.19.0
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.nvmrc 固定为 Node 20.19.0,但 package.json 已将 engines 提升到 >=22.15.0,且 Dockerfile 也切到了 node:22-bookworm-slim。这会导致本地开发/CI(使用 nvm)与构建环境出现版本分裂,进而产生难以复现的问题。建议将 .nvmrc 与 engines/Dockerfile 对齐(例如改为 22.15.0 或对应 LTS 小版本),并在 README/贡献指南中统一说明。

Suggested change
20.19.0
22.15.0

Copilot uses AI. Check for mistakes.
Comment on lines 1 to +3
{
"name": "metapi",
"version": "1.2.1",
"version": "1.2.3",
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR 标题/描述聚焦“全局模型白名单”,但实际变更包含广泛的版本升级、Node 引擎提升、DB runtime schema/legacy compat、桌面端端口与监听策略调整、CI/workflow 重写、文档/工程治理引入等。这种范围会显著增加 review 与回归风险。建议将与模型白名单无直接关系的改动拆分到独立 PR(例如:CI/workflow、desktop 监听策略、schema harness、依赖升级分别拆分),或至少在 PR 描述中补充这些变更的动机、回归策略与风险评估。

Copilot uses AI. Check for mistakes.
Comment on lines +24 to +26
"engines": {
"node": ">=22.15.0"
},
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR 标题/描述聚焦“全局模型白名单”,但实际变更包含广泛的版本升级、Node 引擎提升、DB runtime schema/legacy compat、桌面端端口与监听策略调整、CI/workflow 重写、文档/工程治理引入等。这种范围会显著增加 review 与回归风险。建议将与模型白名单无直接关系的改动拆分到独立 PR(例如:CI/workflow、desktop 监听策略、schema harness、依赖升级分别拆分),或至少在 PR 描述中补充这些变更的动机、回归策略与风险评估。

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces extensive updates to the project's documentation, CI/CD pipelines, and core infrastructure, including an upgrade to Node 22 and the implementation of robust database migration recovery logic. Key feature additions include a global model whitelist, OAuth multi-provider support, and streamlined deployment options for Render. Review feedback identified a critical security vulnerability regarding a hardcoded secret and a high-severity risk in the default network binding for the desktop application. Additionally, recommendations were made to align port binding examples in the documentation for better security consistency and to optimize build performance by decoupling desktop-specific icon generation from the standard web build process.

const DEFAULT_CODEX_CLIENT_ID = 'app_EMoamEEZ73f0CkXaXp7hrann';
const DEFAULT_CLAUDE_CLIENT_ID = '9d1c250a-e61b-44d9-88ed-5944d1962f5e';
const DEFAULT_GEMINI_CLI_CLIENT_ID = '681255809395-oo8ft2oprdrnp9e3aqf6av3hmdib135j.apps.googleusercontent.com';
const DEFAULT_GEMINI_CLI_CLIENT_SECRET = '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';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

在代码中硬编码 DEFAULT_GEMINI_CLI_CLIENT_SECRET 是一个严重的安全漏洞。密钥(Secrets)绝不应该被提交到版本控制系统中。它们应该仅通过环境变量来提供,并且应用程序在生产环境中启动时,如果必需的密钥缺失,应当启动失败并报错。建议移除此默认值,并确保在使用该密钥的逻辑中进行存在性检查。

Suggested change
const DEFAULT_GEMINI_CLI_CLIENT_SECRET = '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';
const DEFAULT_GEMINI_CLI_CLIENT_SECRET = '';

Comment on lines 34 to +39
export function buildDesktopServerEnv(input: DesktopServerEnvInput): NodeJS.ProcessEnv {
const host = (input.inheritedEnv?.HOST || '0.0.0.0').trim() || '0.0.0.0';

return {
...(input.inheritedEnv || {}),
HOST: '127.0.0.1',
HOST: host,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

将桌面应用的默认监听主机从 127.0.0.1 更改为 0.0.0.0,会默认将其服务暴露在本地网络中。这是一个潜在的安全风险,因为用户可能没有意识到他们的服务可以从网络上的其他设备访问。遵循最小权限原则,更安全的默认设置是仅绑定到 127.0.0.1 (localhost)。如果用户需要局域网访问,他们应该通过配置显式启用。

Suggested change
export function buildDesktopServerEnv(input: DesktopServerEnvInput): NodeJS.ProcessEnv {
const host = (input.inheritedEnv?.HOST || '0.0.0.0').trim() || '0.0.0.0';
return {
...(input.inheritedEnv || {}),
HOST: '127.0.0.1',
HOST: host,
export function buildDesktopServerEnv(input: DesktopServerEnvInput): NodeJS.ProcessEnv {
const host = (input.inheritedEnv?.HOST || '127.0.0.1').trim() || '127.0.0.1';
return {
...(input.inheritedEnv || {}),
HOST: host,

image: 1467078763/metapi:latest
ports:
- "4000:4000"
- "127.0.0.1:4000:4000"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

将端口绑定到 127.0.0.1 是一个很好的安全默认设置,可以防止服务意外暴露在网络上。然而,在 README.md 中为用户提供的 docker-compose.yml 示例仍然使用 "4000:4000",这会绑定到所有网络接口。这种不一致可能会让用户感到困惑。

为了保持一致性和安全性,建议 README.md 中的示例也应使用 127.0.0.1:4000:4000,并附上注释说明如何根据需要将其暴露给网络。

Comment on lines +33 to 36
"build:web": "npm run desktop:icons && vite build",
"build:server": "tsc -p tsconfig.server.json && tsx scripts/dev/copy-runtime-db-generated.ts",
"build:desktop": "tsc -p tsconfig.desktop.json",
"build": "npm run build:web && npm run build:server && npm run build:desktop",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

build:web 脚本与桌面图标生成任务 desktop:icons 耦合。这导致在构建服务器的 Docker 镜像时,会引入不必要的重度依赖(如 sharp),从而增加了镜像的体积和构建时间。为了优化服务器构建流程,建议将图标生成步骤与通用的 Web 构建解耦。

一个好的做法是将 desktop:icons 移动到 build:desktop 脚本中,因为图标是桌面应用特有的。这样 build:web 就可以专注于构建纯粹的 Web 资源。

Suggested change
"build:web": "npm run desktop:icons && vite build",
"build:server": "tsc -p tsconfig.server.json && tsx scripts/dev/copy-runtime-db-generated.ts",
"build:desktop": "tsc -p tsconfig.desktop.json",
"build": "npm run build:web && npm run build:server && npm run build:desktop",
"build:web": "vite build",
"build:server": "tsc -p tsconfig.server.json && tsx scripts/dev/copy-runtime-db-generated.ts",
"build:desktop": "npm run desktop:icons && tsc -p tsconfig.desktop.json",
"build": "npm run build:web && npm run build:server && npm run build:desktop",

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.