收口 M3 复核遗留:文档如实口径、fork-source 状态说明、forkAuthorization 机器守卫、e2e 引用去行号
- 技术方案 §3.4:删掉「GET /games/{gameId} 追加 forkSourceAvailable」——实现里不存在该字段;改为如实口径:改造入口显隐只依据 forkAuthorization,真实可复刻形态由 /fork-source 的 source 回答,若 M2b 要区分「可源码级改造 / 只能参考」届时再加
- 实施计划(M1)§5:同步去掉 forkSourceAvailable 并注明「未实现、也不需要」,保留其余字段清单不动
- 技术方案 §2.6 时序图:说明字句从「GET …/fork-source 是待实现接口」改为「M2a 已实现(形状见 §3.4 登录用户表)」,并在图内加一行 Note 标注「图中字段名是 M2b 目标形状」;图属目标形态的免责声明保留
- parity 脚本:game_payload 增加 mustEmit ['forkAuthorization']——该字段 TS 侧可选(旧响应可省),但公开与作者响应必须发出,否则详情页授权徽章与改造入口会静默退化成「禁止共创」;public_game_payload 以 game_payload 为 base,因此一并受保护
- e2e 脚本头部:把全部行号引用(含已过期 2–4 行的那些)改为「文件 + 符号」引用(router()/lineage_read_or_not_found()/GameDistributionLineageNode/lineage.rs 常量与函数等),并删除「消费链路在未提交的 M2a WIP 里」这类会过期的措辞,改为「已在 M2a 落地」;只改注释,断言逻辑未动
This commit is contained in:
@@ -52,7 +52,8 @@ fn sha256_hex(bytes: &[u8]) -> String {
|
||||
/// 参考副本相对项目的路径:`reference/<gameId>/`。
|
||||
///
|
||||
/// 作品 ID 来自平台响应,只接受路径安全取值;拼接复用归档条目门禁(拒绝 `..`、盘符与
|
||||
/// 绝对路径),保证参考副本永远落在项目内的子目录,不会逃出项目根。
|
||||
/// 绝对路径),保证参考副本永远落在项目内的子目录,不会逃出项目根。这是参考目录的**唯一**
|
||||
/// 推导处:调用方把它 join 到项目根,不再另起第二份拼接规则。
|
||||
pub(crate) fn fork_reference_relative_path(game_id: &str) -> Result<PathBuf, String> {
|
||||
let game_id = game_id.trim();
|
||||
// 空标识必须显式拒绝:`safe_archive_relative_path` 会把空段丢掉,`reference/` 会被
|
||||
@@ -71,14 +72,6 @@ pub(crate) fn fork_reference_relative_path(game_id: &str) -> Result<PathBuf, Str
|
||||
Ok(relative)
|
||||
}
|
||||
|
||||
/// 参考副本目录:`<project>/reference/<gameId>/`。
|
||||
pub(crate) fn fork_reference_directory(
|
||||
project_root: &Path,
|
||||
game_id: &str,
|
||||
) -> Result<PathBuf, String> {
|
||||
Ok(project_root.join(fork_reference_relative_path(game_id)?))
|
||||
}
|
||||
|
||||
/// 用平台作品的成品包建一个新项目。
|
||||
///
|
||||
/// 先按标准初始化生成合规脚手架,再把参考副本铺进 `<project>/reference/<gameId>/`,
|
||||
@@ -215,16 +208,20 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fork_reference_directory_stays_inside_the_project() {
|
||||
let root = Path::new("C:/work/project");
|
||||
fn fork_reference_relative_path_stays_inside_the_project() {
|
||||
// 生产路径就是「把这唯一的相对路径 join 到项目根」,因此这里直接钉相对路径本身。
|
||||
assert_eq!(
|
||||
fork_reference_directory(root, "game_1").expect("safe id"),
|
||||
root.join("reference").join("game_1")
|
||||
fork_reference_relative_path("game_1").expect("safe id"),
|
||||
Path::new("reference").join("game_1")
|
||||
);
|
||||
assert_eq!(
|
||||
Path::new("C:/work/project").join(fork_reference_relative_path("game_1").unwrap()),
|
||||
Path::new("C:/work/project/reference/game_1")
|
||||
);
|
||||
// 路径不安全的标识一律失败关闭,不拼出逃出项目根的路径。
|
||||
for unsafe_id in ["", "..", "../escape", "a/b", "a\\b", "C:game", " "] {
|
||||
assert!(
|
||||
fork_reference_directory(root, unsafe_id).is_err(),
|
||||
fork_reference_relative_path(unsafe_id).is_err(),
|
||||
"should reject {unsafe_id:?}"
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user