修复图标规范内联引用校验
Project CI / Repository checks (pull_request) Failing after 13s
Project CI / Backend tests (pull_request) Failing after 13s
Project CI / Frontend tests (pull_request) Successful in 2m35s
Project CI / Native shell tests (pull_request) Has been cancelled

在共享执行入口转换 referenceId 前校验引用 ID 与 owner。

新增调用顺序回归测试并同步决策记录。
This commit is contained in:
2026-08-08 21:37:14 +08:00
parent 02b4b6955d
commit c188accafb
3 changed files with 18 additions and 1 deletions
@@ -6775,7 +6775,7 @@
- `editor_project_icon.rs` 独立承接图标规范、图标 spritesheet、自动切片和手工拆分。普通图片模块只暴露可复用的 prompt builder 执行入口与强类型 provider 请求分流;nanobanana、无参考图 generation、有参考图 edit 的选择集中在同一个 helper,图标图集复用该 helper,不复制 provider 分支。
- 图标规范生成的可选参考图与图标图集的必选主规范统一使用 `referenceId`,只接受当前 owner 的项目资源 ID 或账号素材 ID,不接受 objectKey、URL 或临时 key。SpacetimeDB `resolve_editor_reference_and_return` 因而只接收 `reference_id` 并按两张表主键查询,删除 `image_src` 二级索引。图标图集的普通附加参考图 `referenceImageSrcs` 仍允许 owned objectKey、项目资源 ID 或素材 ID,并继续走既有 owner 校验与真实图片下载链。
- External v1 图标图集请求与 OpenAPI 同步改为必填 `referenceId`。前端和 Editor Agent 优先传正式 resource ID,其次传 asset ID;本地临时 ID、objectKey 和图片地址不得回退成主规范引用,未登记时明确失败并要求先上传或登记。
- `resolve_editor_reference_and_return` 的歧义只在当前 owner 范围内判断:两张表先按 `owner_user_id` 过滤,同名但属于其它账号的行不阻断合法引用。记录存在 `asset_object_id` 时按该 ID 定位并同时核对 bucket、object key 与 owner,只有缺少 ID 的兼容旧行才按位置查询。图标规范入队 / inline 预检只验证这组行与对象元数据最终共享图片执行器再下载一次参考图正文,避免同一引用在入队、worker 预检和生成阶段重复下载。
- `resolve_editor_reference_and_return` 的歧义只在当前 owner 范围内判断:两张表先按 `owner_user_id` 过滤,同名但属于其它账号的行不阻断合法引用。记录存在 `asset_object_id` 时按该 ID 定位并同时核对 bucket、object key 与 owner,只有缺少 ID 的兼容旧行才按位置查询。图标规范入队 / inline 预检只验证这组行与对象元数据inline 与 worker 共用的最终执行入口还必须在把 `referenceId` 转入通用图片请求前再次执行同一 ID / owner 校验。最终共享图片执行器再下载一次参考图正文,避免同一引用在入队、worker 预检和生成阶段重复下载。
- 关联:`server-rs/crates/api-server/src/editor_project_icon.rs``server-rs/crates/api-server/src/editor_project.rs``server-rs/crates/spacetime-module/src/editor_project_storage.rs``docs/openapi/genarrative-external-v1.openapi.json`
## 2026-08-06 音效与背景音乐恢复共享音频 Composer
@@ -16098,6 +16098,22 @@ mod tests {
);
}
#[test]
fn icon_spec_execution_validates_id_reference_before_shared_image_dispatch() {
let source = include_str!("editor_project_icon.rs");
assert_function_contains_in_order(
source,
"pub(crate) async fn generate_icon_spec_for_owner",
"fn validate_icon_spec_request_fields",
&[
"validate_icon_spec_request_fields(",
"validate_icon_spec_reference_for_owner(",
"build_icon_spec_image_request(",
],
);
}
#[test]
fn image_generation_preflight_checks_references_provider_and_pricing() {
let source = concat!(
@@ -549,6 +549,7 @@ pub(crate) async fn generate_icon_spec_for_owner(
mut payload: EditorIconSpecGenerationRequest,
) -> Result<Json<Value>, AppError> {
validate_icon_spec_request_fields(&mut payload)?;
validate_icon_spec_reference_for_owner(state, &caller, &payload).await?;
let request_param = payload.request_param.clone();
let has_reference_image = payload.reference_id.is_some();
let generation_inputs = payload.generation_inputs.clone();