Skip to content

fix(sharing): reject an onboarding whose plan is not routable - #202

Merged
argszero merged 1 commit into
mainfrom
fix/sharing-onboarding-plan
Sep 13, 2026
Merged

argszero merged 1 commit into
mainfrom
fix/sharing-onboarding-plan

Conversation

@argszero

Copy link
Copy Markdown
Owner

Summary

POST /api/sharings 把 provider / plan / model 一律原样落库。上一个 PR(#201)补上了「能计价」((provider, model) 必须在 models 表中,否则调用会静默 0 计费);本 PR 补上另一半:能路由。

路由按 plan id 在 config [[plans]] 中解析端点(gateway::resolve_outbound / resolve_endpoint:cfg.plans.iter().find(|p| p.id == plan_id))。plan 不在 config 中时,该 key 永远不可路由——调用返回 503「该模型暂无可用 key」——但它仍以 status='on' 落库,并被 dao::list_models_with_availability(只按 k.status = 'on' 计数,不认识 plan)计入 available_keys。结果:市场页与共享页展示一个平台交不出的可用性。

运行期复现(注入测试模块,跑完即还原):只留一条 plan 为 no-such-plan 的 key 时,市场仍报 available_keys=1,而同一模型的 POST /v1/chat/completions 返回 503;阳性对照(真实 plan)同样 +1,说明计数器没坏,只是不区分。

Related Issue

无(本仓库当前 0 个 open issue;由代码巡查发现,与 #201 同源)

Changes

  • src/routes/sharing.rs::create 在 INSERT 之前新增守卫:req.plan 必须在 st.cfg.plans 中,否则 400 plan 不在平台的套餐目录中,无法路由
  • plan 是 #[serde(default)],省略字段即空串(同样不是任何 plan 的 id)⇒ 一并拒绝;前端上架表单本就必选 plan(提交 plan: plan.id),合法客户端不受影响
  • 两个既有测试 payload 补上 "plan":"deepseek-paygo"(它们此前省略了 plan,即在上架不可路由的 key——正是本 PR 修掉的情形)
  • 未新增 i18n 键、未改 ui/、未改 config / schema
  • 涉及配置/数据结构的改动已同步示例文件 —— 不适用(无配置改动)

Tests

  • cargo test 全部通过 —— 190 passed(189 → 190)
  • cargo fmt --check 通过
  • cargo clippy --all-targets -- -D warnings 通过
  • 新增单元测试 create_rejects_unroutable_plan:① 未知 plan → 400;② 省略 plan → 400;③ 两次拒绝均不落库;④ 阳性对照:config 中的 plan → 200 且落库;⑤ 失配配对断言:直接写入一条历史遗留的「未知 plan 却 status='on'」行,断言它仍被计入 available_keys 而该 plan 不在 config 中(⇒ 路由解析不到)——即本守卫要挡住的情形

A/B 牙齿证明:只删掉守卫块,cargo test sharing:: ⇒ 恰好 1 红 / 6 绿,且失败输出正是缺陷现象(响应体打印 "plan" 未知却 "status":"on")。

Checklist

  • 分支命名符合约定(fix/)
  • Commit message 使用 Conventional Commits 格式(fix(sharing): …)
  • 单一职责,改动最小化(1 文件,+108/−2)

POST /api/sharings 存的 provider / plan / model 一律原样落库。C2065 已补上
「能计价」((provider, model) 必须在 models 表中),本提交补上另一半:**能路由**。

路由按 plan id 在 config `[[plans]]` 中解析端点
(`gateway::resolve_outbound` / `resolve_endpoint`:
`cfg.plans.iter().find(|p| p.id == plan_id)`)。plan 不在其中时该 key
**永远不可路由**(调用 503「该模型暂无可用 key」),但它仍以 `status='on'`
落库,并被 `dao::list_models_with_availability`(`k.status = 'on'`,不认识 plan)
计入 `available_keys` ⇒ 市场与共享页展示一个平台**交不出**的可用性。

`plan` 是 `#[serde(default)]`,省略字段即空串,同样不是任何 plan 的 id,
因此一并拒绝。前端上架表单本就必选 plan(提交 `plan: plan.id`),合法客户端不受影响。

守卫放在 INSERT 之前,被拒绝的上架不落库。
@argszero
argszero merged commit ad817cd into main Sep 13, 2026
1 check passed
@argszero
argszero deleted the fix/sharing-onboarding-plan branch September 13, 2026 06:53
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.

1 participant