refactor(后台契约): AdminAgcModel.access 改 ProfileMembershipModelAccessToken

- shared-contracts 的 AdminAgcModel.access 由裸 String 改为 ProfileMembershipModelAccessToken,未知值在反序列化阶段被拒(评审第 18 条)
- module-runtime 补 AgcModelAccess <-> ProfileMembershipModelAccessToken 双向 From
- api-server 的 agc_models 去掉 AgcModelAccess::parse 兜底,改直接 From
- admin-web 的 AdminAgcModelAccess 改为复用 @genarrative/shared 生成类型
- 扩展 catalog_dto 测试断言缺省 Basic 与未知 access 反序列化失败
This commit is contained in:
2026-10-04 20:58:21 +08:00
parent 6424ad7e75
commit dcaab089cc
4 changed files with 42 additions and 11 deletions
+17 -5
View File
@@ -244,10 +244,7 @@ pub async fn admin_save_agc_models(
.map_err(|message| {
AppError::from_status(StatusCode::BAD_REQUEST).with_message(message)
})?;
let access = AgcModelAccess::parse(&m.access).ok_or_else(|| {
AppError::from_status(StatusCode::BAD_REQUEST)
.with_message("权限档只允许 basic 或 full")
})?;
let access = AgcModelAccess::from(m.access);
Ok(module_runtime::AgcModel {
id: m.id,
alias: m.alias,
@@ -302,7 +299,7 @@ fn catalog_dto(catalog: AgcModelCatalog) -> AdminAgcModelCatalog {
enabled: m.enabled,
agent_mode: m.agent_mode.as_str().to_string(),
protocol: Some(protocol),
access: m.access.as_str().to_string(),
access: m.access.into(),
}
})
.collect(),
@@ -330,6 +327,21 @@ mod tests {
}))
.unwrap();
assert_eq!(legacy.agent_mode, "codex");
assert_eq!(
legacy.access,
shared_contracts::runtime::ProfileMembershipModelAccessToken::Basic
);
// 权限档 token 在反序列化阶段就收口,未知值不再推迟到 `AgcModelAccess::parse`。
assert!(
serde_json::from_value::<AdminAgcModel>(json!({
"id": "model-a",
"alias": "model-a",
"modelId": "model-a",
"enabled": true,
"access": "premium"
}))
.is_err()
);
}
#[test]