From eee12b28099b229eeb42a2d4c1e3ce28d450f5d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E5=BE=B7=E5=AE=87?= Date: Tue, 6 Oct 2026 18:50:44 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=8F=E7=BA=A2=E4=B9=A6=E5=AF=BC=E5=87=BA?= =?UTF-8?q?=E4=BA=A7=E7=89=A9=E5=88=A4=E6=8D=AE=E6=94=B9=E7=94=A8=20symlin?= =?UTF-8?q?k=5Fmetadata?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - build.rs 的 conclude 不再跟随符号链接,链接与非普通文件不计入「已产出」 - 新增 a_symlinked_artifact_does_not_count 用例(仅 unix) --- .../src/export/draft/xhs_minitool/build.rs | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/build.rs b/apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/build.rs index 6393efc00..060af0d67 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/build.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/export/draft/xhs_minitool/build.rs @@ -95,8 +95,13 @@ fn conclude( let path = artifact_path(root); let produced = matches!( - std::fs::metadata(&path), - Ok(metadata) if metadata.is_file() && metadata.len() > 0 + std::fs::symlink_metadata(&path), + // `metadata` 会跟随符号链接:指向项目外某个非空文件的链接会被当成「产出成功」, + // 而下游下载路径又按 fail closed 拒收链接。这里用 symlink_metadata 与之一致。 + Ok(metadata) + if metadata.is_file() + && !metadata.file_type().is_symlink() + && metadata.len() > 0 ); if !produced { // 脚本"成功"却没产出:多半是 agent 把 zip 写到了别处,或 pack.mjs 的参数没对齐。 @@ -232,6 +237,25 @@ mod tests { )); } + #[cfg(unix)] + #[test] + fn a_symlinked_artifact_does_not_count() { + let root = fixture_root("symlink-artifact"); + let path = artifact_path(&root); + std::fs::create_dir_all(path.parent().unwrap()).unwrap(); + let target = root.join("outside.zip"); + std::fs::write(&target, b"PK\x03\x04zip").unwrap(); + std::os::unix::fs::symlink(&target, &path).unwrap(); + + assert!( + matches!( + conclude(&root, Some(0), false, "构建完成"), + Err(XHSMiniToolExportBuildError::ArtifactMissing(_)) + ), + "指向项目外非空文件的链接不能算产出成功" + ); + } + #[test] fn a_successful_script_with_a_non_empty_artifact_returns_the_output_tail() { let root = fixture_root("ok");