拒绝栅格资源 subtype 静默降级
Project CI / AI game creator shell Rust shard 4/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust smoke (pull_request) Has been cancelled
Project CI / AI game creator shell Rust crates (pull_request) Has been cancelled
Project CI / Backend tests (pull_request) Has been cancelled
Project CI / Native shell tests (pull_request) Has been cancelled
Project CI / Frontend tests (pull_request) Has been cancelled
Project CI / Repository checks (pull_request) Has been cancelled
Project CI / AI game creator shell web tests (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 2/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 1/4 (pull_request) Has been cancelled
Project CI / AI game creator shell Rust shard 3/4 (pull_request) Has been cancelled

非图片族和未知 sourceSubtype 改为明确报错
补充栅格正规化回归测试并同步规范
This commit is contained in:
2026-09-17 23:06:30 +08:00
parent 3d4c7929c3
commit 72cd0747a4
2 changed files with 41 additions and 17 deletions
@@ -3872,19 +3872,25 @@ pub(crate) fn normalize_local_project_raster_resource_at(
.map_err(|error| format!("序列化源图片身份失败:{error}"))?;
let identity_hash = sha256_hex(&identity_material);
let asset_id = format!("normalized-{}", &identity_hash[..24]);
// 该接口只把栅格源登记成 manifest 图片资产:源 subtype 只接受**图片族**成员,
// 未声明、认不出或非图片族成员(音频 / 视频 / 文档 / 字体 / 代码…)时按图片收口。
// 只排除 `Unknown` 是不够的:`source_subtype` 是外部入参,传 `background-music` 就会把
// 一张 PNG 登记成音频 kind,和本函数的存在理由直接冲突。
let source_kind = input
// 该接口只把栅格源登记成 manifest 图片资产:源 subtype 只接受**图片族**成员。
// 未声明/空白时按没有类型信息处理为 `image`;认不出或传入非图片族成员
// (音频 / 视频 / 文档 / 字体 / 代码…)直接失败,避免静默掩盖调用方错误。
let source_kind = match input
.source_subtype
.as_deref()
.map(str::trim)
.filter(|value| !value.is_empty())
.map(|value| GameCreationAppAssetKind::parse_with_context(value, "resource-edit.normalize"))
.filter(|kind| *kind != GameCreationAppAssetKind::Unknown)
.filter(|kind| {
matches!(
{
None => GameCreationAppAssetKind::Image,
Some(value) => {
let kind =
GameCreationAppAssetKind::parse_with_context(value, "resource-edit.normalize");
if kind == GameCreationAppAssetKind::Unknown {
return Err(format!(
"sourceSubtype 必须是图片族 kind,无法识别:{value}"
));
}
if !matches!(
kind,
GameCreationAppAssetKind::Image
| GameCreationAppAssetKind::Scene
@@ -3894,9 +3900,15 @@ pub(crate) fn normalize_local_project_raster_resource_at(
| GameCreationAppAssetKind::IconSpritesheet
| GameCreationAppAssetKind::IconSpec
| GameCreationAppAssetKind::UiDesign
)
})
.unwrap_or(GameCreationAppAssetKind::Image);
) {
return Err(format!(
"sourceSubtype 必须是图片族 kind,不能使用:{}",
kind.as_str()
));
}
kind
}
};
let asset = GameCreationAppAssetManifestEntry {
id: asset_id.clone(),
kind: source_kind,
@@ -9112,7 +9124,7 @@ mod tests {
source_resource_id: format!("task:{task_id}:assets/task-hero.png"),
source_path: "assets/task-hero.png".to_string(),
source_media_type: "image/png".to_string(),
source_subtype: Some("task-artifact".to_string()),
source_subtype: None,
producer_task_id: task_id.clone(),
};
@@ -9144,6 +9156,18 @@ mod tests {
assert_eq!(replay.asset.id, first.asset.id);
assert_eq!(replay.manifest.assets.len(), 1);
for invalid_subtype in ["background-music", "legacy-raster-kind"] {
let error = normalize_local_project_raster_resource_at(
NormalizeLocalProjectRasterResourceInput {
expected_project_revision: replay.committed_project_revision,
source_subtype: Some(invalid_subtype.to_string()),
..request.clone()
},
)
.expect_err("non-image or unknown source subtype must fail");
assert!(error.contains("sourceSubtype 必须是图片族 kind"), "{error}");
}
let rejected =
normalize_local_project_raster_resource_at(NormalizeLocalProjectRasterResourceInput {
expected_project_revision: replay.committed_project_revision,
@@ -9181,7 +9205,7 @@ mod tests {
source_resource_id: format!("task:{task_id}:assets/task-hero.png"),
source_path: "assets/task-hero.png".to_string(),
source_media_type: "image/png".to_string(),
source_subtype: Some("task-artifact".to_string()),
source_subtype: None,
producer_task_id: task_id,
};
let first = normalize_local_project_raster_resource_at(request.clone())
@@ -9244,7 +9268,7 @@ mod tests {
source_resource_id: format!("task:{task_id}:assets/task-hero.png"),
source_path: "assets/task-hero.png".to_string(),
source_media_type: "image/png".to_string(),
source_subtype: Some("task-artifact".to_string()),
source_subtype: None,
producer_task_id: task_id,
};
let first = normalize_local_project_raster_resource_at(request.clone())