8ce4649081
- 新增 `server-rs/crates/module-game-distribution/src/project_bundle.rs`:`validate_project_bundle_zip(bytes) -> Result<ProjectBundleManifest, ProjectBundleError>`
· 复用 `crate::package::normalize_archive_path`(不复制路径安全逻辑),路径不安全统一归 `InvalidPath`
· 拒绝清单:空包 / 非 zip / 条目数 > 10 000 / 符号链接 / 加密条目 / 嵌套 `.zip` / 完全重复与大小写折叠重复路径 / `node_modules`(任意层级)/ `.git`、`.svn`(任意层级)/ `.agent`(任意层级:避免把上一个作品的改编来源记录带给下一个人)/ 根级 `dist`、`build`、`library`、`temp`、`local`(子目录同名允许,与模板包规则一致)/ 根级 `.idea`、`.vscode` / 凭据与隐私:`.env`、`.env*`、`*.pem`、`*.key`、`*.p12`、`*.pfx`、`.npmrc`、`.netrc`、`.git-credentials`、`id_rsa*`、`id_ed25519*`、`*.map` / 单文件 > 64 MiB / 累计 > 500 MiB / 单文件 > 包体 × 100
· 规模上限与发行包**逐项相等**(200 MiB / 500 MiB / 64 MiB / 10 000 / 100):两者共用同一条上传链路,反代与 Pingora 的放行量就是按 200 MiB 校准的,放宽就得同步放开多处部署配置;单测用 `assert_eq!` 钉住这条等价关系
· 不要求根 `index.html`(源码包没有入口约定),非空即可
- `lib.rs` 只追加 `mod project_bundle;` 与 `pub use project_bundle::{...}`(+6 行);`package.rs` **零改动**,发行包行为与测试不受影响
- 测试 16 条:合法源码包通过(故意不含 `index.html`)、上述每条拒绝规则各一条、「子目录里的 `dist/` 允许」反例、常量与发行包逐项相等、manifest 的 sha256/字节数与输入一致
- 门禁:`cargo test -p module-game-distribution` 69 passed(含本校验器 16 条);wasm build 0;`cargo fmt --all -- --check` 0