Merge branch 'feat/m35-nyai-manifest-authority-and-sd-stagi'

This commit is contained in:
AskaEth committed 2026-11-10 21:42:40 +08:00
commit 46278fd051
5 files changed
+1088 -152

No files matched your search

Binary file not shown.
+679 -152
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.
+52
View File
@@ -0,0 +1,52 @@
/* test_fmt_utc.c — fmt_utc() 边界单测(宿主)。
*
* fmt_utc 是 nyai.c 里的 static 函数;这里把 main 改名后直接 include 源码来测,
* 不引入测试框架、不复制实现(避免单测与实现漂移)。
* 覆盖:epoch/负数、1 月、2 月(闰/平)、3 月、12 月 31 日、闰年 2/29、2100 世纪闰年规则、
* 2038 int32 边界。真机时区无关(fmt_utc 固定 UTC)。
*
* 用法:cc -Wall -Wextra test_fmt_utc.c -o test_fmt_utc && ./test_fmt_utc
*/
#define main nyai_main_unused
#include "nyai.c"
#undef main
#include <stdio.h>
#include <string.h>
struct utc_case { long long t; const char *want; };
int main(void)
{
static const struct utc_case cases[] = {
{ 0LL, "t0" }, /* epoch 由调用方定义为「无时间」 */
{ -1LL, "t0" },
{ 1LL, "19700101-000001" },
{ 1LL * 1767225600, "20260101-000000" }, /* 2026-01-01(曾打成 20251901) */
{ 1769904000LL, "20260201-000000" }, /* 2026-02-01(曾打成 20251931) */
{ 1772236800LL, "20260228-000000" }, /* 2026-02-28(平年) */
{ 1709164800LL, "20240229-000000" }, /* 2024-02-29(闰年) */
{ 951782400LL, "20000229-000000" }, /* 2000-02-29(400 年闰) */
{ 4102444800LL, "21000101-000000" }, /* 2100-01-01(非闰世纪) */
{ 1772323200LL, "20260301-000000" }, /* 2026-03-01(March-based 起点) */
{ 1798761599LL, "20261231-235959" }, /* 年末最后一秒 */
{ 2145916800LL, "20380101-000000" },
{ 2147483647LL, "20380119-031407" }, /* int32 time_t 上界 */
};
int fail = 0;
for (unsigned i = 0; i < sizeof cases / sizeof cases[0]; i++) {
char got[32];
fmt_utc(cases[i].t, got, sizeof got);
if (strcmp(got, cases[i].want) != 0) {
printf("FAIL fmt_utc(%lld) = %s, want %s\n",
cases[i].t, got, cases[i].want);
fail++;
}
}
if (fail == 0) {
printf("PASS fmt_utc: %u cases\n", (unsigned)(sizeof cases / sizeof cases[0]));
return 0;
}
printf("FAILED %d/%u\n", fail, (unsigned)(sizeof cases / sizeof cases[0]));
return 1;
}
+357
View File
@@ -0,0 +1,357 @@
#!/bin/bash
# test_nyai.sh — nyai 宿主回归(M35:app.json 清单权威 + SD 暂存 + 无条件清理)
#
# 覆盖:
# 1 文件名/后缀与包名完全不同(weird-name.bin)仍按清单装进 MeowAPPs/<app.json.package>
# 2 真实反例:签名 os.meow.reader 包命名成 os.meow.reader-0.1.7.mpk 仍装进 MeowAPPs/os.meow.reader
# 3 footer.package ≠ app.json.package → 拒装,错误文案同时给出两个名字
# 4 os.meow.* 无签名 → 拒装
# 5 第三方无签名 → 放行(行为不变)
# 6 恶意 app.json.package(../x、a/b、.、..)→ 拒装且不落盘到目录外
# 7 成功 / 各种失败 / 解压失败 / SIGTERM 中断 → MeowOS/tmp/pkgs 无残留
# 8 索引路径:Packages 的 Package 字段取自清单(文件改名后按包名仍可装)
# 9 upgrade 复用 install 引擎:清单包名/目标包名不一致、降级都拒
#
# 依赖:宿主 cc(编 nyai_host / meow_verify_host / meow_sign)。
# 签名用例需要维护者私钥:默认 ~/.keys/meowos-signing/signing.key,
# 可用 NYAI_TEST_SIGN_KEY 覆盖;无私钥时签名用例 SKIP(不判 FAIL)。
# 真实反例包默认 ~/.cache/os.meow.reader-0.1.7-signed.mpk,可用 NYAI_TEST_REAL_MPK 覆盖。
#
# 用法:./test_nyai.sh [-v]
set -u
HERE=$(cd "$(dirname "$0")" && pwd)
ROOT=$(cd "$HERE/../.." && pwd)
VERBOSE=0
[ "${1:-}" = "-v" ] && VERBOSE=1
WORK=${NYAI_TEST_WORK:-$(mktemp -d "${TMPDIR:-/tmp}/nyai-m35.XXXXXX")}
mkdir -p "$WORK"
CLEANUP_WORK=1
[ -n "${NYAI_TEST_WORK:-}" ] && CLEANUP_WORK=0
trap '[ "$CLEANUP_WORK" = 1 ] && rm -rf "$WORK"' EXIT
PASS=0; FAIL=0; SKIP=0
ok() { PASS=$((PASS+1)); printf 'PASS %s\n' "$1"; }
bad() { FAIL=$((FAIL+1)); printf 'FAIL %s\n' "$1"; [ -n "${2:-}" ] && printf ' %s\n' "$2"; }
skip() { SKIP=$((SKIP+1)); printf 'SKIP %s (%s)\n' "$1" "${2:-}"; }
KEY=${NYAI_TEST_SIGN_KEY:-$HOME/.keys/meowos-signing/signing.key}
[ -r "$KEY" ] || KEY=""
REAL_MPK=${NYAI_TEST_REAL_MPK:-$HOME/.cache/os.meow.reader-0.1.7-signed.mpk}
# ---------------- 构建 ----------------
echo "== build =="
( cd "$HERE" && ./build_nyai.sh host >/dev/null ) || { echo "build nyai_host failed"; exit 1; }
NYAI="$HERE/nyai_host"
CC=${CC_HOST:-cc}
V="$ROOT/patch_v2/meow_verify"
mkdir -p "$WORK/tools"
"$CC" -Os -Wno-sign-compare -Wno-unterminated-string-initialization -Wno-unused-function \
-c "$V/tweetnacl.c" -o "$WORK/tools/tn.o" || { echo "build tweetnacl failed"; exit 1; }
"$CC" -Os -c "$V/sha256.c" -o "$WORK/tools/sha.o" || exit 1
"$CC" -Os -I"$V" -c "$V/meow_verify.c" -o "$WORK/tools/mv.o" || exit 1
"$CC" "$WORK/tools/mv.o" "$WORK/tools/sha.o" "$WORK/tools/tn.o" -o "$WORK/tools/meow_verify_host" || exit 1
if [ -n "$KEY" ]; then
"$CC" -Os -I"$V" -I"$ROOT/patch_v2/meow_sign" "$ROOT/patch_v2/meow_sign/meow_sign.c" \
"$WORK/tools/tn.o" "$WORK/tools/sha.o" -o "$WORK/tools/meow_sign" || exit 1
fi
VERIFY="$WORK/tools/meow_verify_host"
# ---------------- 辅助 ----------------
sb() { # sb <name> → 打印沙箱 MeowROOT
local d="$WORK/case-$1"
rm -rf "$d"
mkdir -p "$d/root/MeowAPPs" "$d/root/MeowOS/opt/nyai"
printf '%s\n' "$d/root"
}
mkpkg() { # mkpkg <dir> <package> <version_code>
rm -rf "$1"; mkdir -p "$1"
printf '{"name":"Test","package":"%s","exec":"bin","version":"0.1.%s","version_code":%s}\n' \
"$2" "$3" "$3" > "$1/app.json"
printf '#!/bin/sh\nexit 0\n' > "$1/bin"; chmod +x "$1/bin"
}
pack() { tar czf "$2" -C "$1" .; }
mk_evil_tar() { # mk_evil_tar <out.mpk> <member-name> <package>:成员名可含 ../ 或绝对路径
python3 - "$1" "$2" "$3" <<'PY'
import sys, tarfile, io, gzip
out, name, pkg = sys.argv[1], sys.argv[2], sys.argv[3]
buf = io.BytesIO()
with tarfile.open(fileobj=buf, mode='w') as t:
ti = tarfile.TarInfo(name); ti.size = 3; t.addfile(ti, io.BytesIO(b'pwn'))
j = ('{"name":"X","package":"%s","exec":"x","version":"1","version_code":1}' % pkg).encode()
tj = tarfile.TarInfo('app.json'); tj.size = len(j); t.addfile(tj, io.BytesIO(j))
open(out, 'wb').write(gzip.compress(buf.getvalue()))
PY
}
mk_bomb_tar() { # mk_bomb_tar <out.mpk>:成员头声明 700MB 的解压炸弹
python3 - "$1" <<'PY'
import sys, tarfile, gzip
ti = tarfile.TarInfo('big.bin'); ti.size = 700 * 1024 * 1024
ti.mtime = 0; ti.mode = 0o644; ti.uid = ti.gid = 0
hdr = ti.tobuf(format=tarfile.USTAR_FORMAT)
open(sys.argv[1], 'wb').write(gzip.compress(hdr + b'\0' * 1024))
PY
}
sign() { # sign <pkg> <mpk>:文件名茎必须等于包名(meow_sign 约定),签完覆盖原文件
[ -n "$KEY" ] || return 2
mkdir -p "$WORK/sign"
cp "$2" "$WORK/sign/$1.mpk"
"$WORK/tools/meow_sign" sign "$WORK/sign/$1.mpk" "$KEY" >/dev/null 2>&1 || return 1
cp "$WORK/sign/$1.mpk" "$2"
}
nyai_run() { # nyai_run <root> <args...>
local r=$1; shift
MEOWROOT="$r" MEOW_VERIFY_BIN="$VERIFY" "$NYAI" "$@"
}
tmp_clean() { # tmp_clean <root>:MeowOS/tmp/pkgs 下无任何条目
local n
n=$(find "$1/MeowOS/tmp/pkgs" -mindepth 1 2>/dev/null | wc -l | tr -d ' ')
[ "$n" = "0" ]
}
show() { [ "$VERBOSE" = 1 ] && printf '%s\n' "$1"; }
expect() { # expect <label> <cond...>
local l=$1; shift
if "$@"; then ok "$l"; else bad "$l"; fi
}
echo "== tests =="
# ---- 0 fmt_utc 边界(直接 include nyai.c 的 static 函数,2026-01/02 曾算错) ----
if "$CC" -Wall -Wextra "$HERE/test_fmt_utc.c" -o "$WORK/tools/test_fmt_utc" 2>"$WORK/fmt_utc.build.log"; then
if "$WORK/tools/test_fmt_utc" >"$WORK/fmt_utc.log" 2>&1; then
ok "0 fmt_utc 边界($(cat "$WORK/fmt_utc.log"))"
else
bad "0 fmt_utc 边界" "$(cat "$WORK/fmt_utc.log")"
fi
else
bad "0 fmt_utc 编译" "$(cat "$WORK/fmt_utc.build.log")"
fi
# ---- 1 文件名与包名完全不同 ----
r=$(sb 1); mkpkg "$WORK/b1" os.meow.demo 1; pack "$WORK/b1" "$WORK/p1.mpk"
if sign os.meow.demo "$WORK/p1.mpk"; then
cp "$WORK/p1.mpk" "$WORK/weird-name.bin"
out=$(nyai_run "$r" install "$WORK/weird-name.bin" 2>&1); rc=$?
show "$out"
expect "1a weird-name.bin(无 .mpk 后缀)按清单装入 MeowAPPs/os.meow.demo" \
test $rc -eq 0 -a -f "$r/MeowAPPs/os.meow.demo/app.json"
expect "1b 未按文件名生成目录" test ! -e "$r/MeowAPPs/weird-name"
expect "1c 成功后 MeowOS/tmp/pkgs 无残留" tmp_clean "$r"
else
skip "1 文件名解绑(签名)" "无签名私钥"
fi
# ---- 2 真实反例:reader 包改名 ----
if [ -r "$REAL_MPK" ]; then
r=$(sb 2)
cp "$REAL_MPK" "$WORK/os.meow.reader-0.1.7.mpk"
out=$(nyai_run "$r" install "$WORK/os.meow.reader-0.1.7.mpk" 2>&1); rc=$?
show "$out"
expect "2a os.meow.reader-0.1.7.mpk 仍装进 MeowAPPs/os.meow.reader(不再按文件名取包名)" \
test $rc -eq 0 -a -f "$r/MeowAPPs/os.meow.reader/app.json"
expect "2b 没有生成 MeowAPPs/os.meow.reader-0.1.7" test ! -e "$r/MeowAPPs/os.meow.reader-0.1.7"
expect "2c 成功后无暂存残留" tmp_clean "$r"
else
skip "2 真实 reader 包改名安装" "缺 $REAL_MPK"
fi
# ---- 3 footer.package ≠ app.json.package ----
if [ -n "$KEY" ]; then
r=$(sb 3); mkpkg "$WORK/b3" os.meow.mismatch-b 1; pack "$WORK/b3" "$WORK/mis-a.mpk"
# 签名时文件名茎 = 包名 → footer 写 os.meow.mismatch-a,清单里却是 os.meow.mismatch-b
sign os.meow.mismatch-a "$WORK/mis-a.mpk"
out=$(nyai_run "$r" install "$WORK/mis-a.mpk" 2>&1); rc=$?
show "$out"
expect "3a footer.package ≠ app.json.package → 拒装" test $rc -ne 0
expect "3b 错误文案含两个包名与「不一致」" \
sh -c 'printf "%s" "$1" | grep -q "签名包名(os.meow.mismatch-a) 与 app.json(os.meow.mismatch-b) 不一致"' _ "$out"
expect "3c 拒装后未落盘任何 App" test ! -e "$r/MeowAPPs/os.meow.mismatch-b" -a ! -e "$r/MeowAPPs/os.meow.mismatch-a"
expect "3d 拒装后无暂存残留" tmp_clean "$r"
else
skip "3 footer/清单不一致" "无签名私钥"
fi
# ---- 4 os.meow.* 无签名 ----
r=$(sb 4); mkpkg "$WORK/b4" os.meow.unsigned 1; pack "$WORK/b4" "$WORK/unsigned-sys.mpk"
out=$(nyai_run "$r" install "$WORK/unsigned-sys.mpk" 2>&1); rc=$?
show "$out"
expect "4a os.meow.* 无签名 → 拒装" test $rc -ne 0
expect "4b 错误文案含「必须签名」" sh -c 'printf "%s" "$1" | grep -q "必须签名"' _ "$out"
expect "4c 未落盘 + 无残留" test ! -e "$r/MeowAPPs/os.meow.unsigned"
expect "4d 拒装后无暂存残留" tmp_clean "$r"
# ---- 5 第三方无签名放行 ----
r=$(sb 5); mkpkg "$WORK/b5" dev.local.thirdparty 1; pack "$WORK/b5" "$WORK/thirdparty.mpk"
out=$(nyai_run "$r" install "$WORK/thirdparty.mpk" 2>&1); rc=$?
show "$out"
expect "5a 第三方无签名 → 放行安装(行为不变)" \
test $rc -eq 0 -a -f "$r/MeowAPPs/dev.local.thirdparty/app.json"
expect "5b 成功后无残留" tmp_clean "$r"
# ---- 6 恶意 package 名 ----
for badname in "../escape" "a/b" "." ".."; do
r=$(sb 6)
mkpkg "$WORK/b6" "$badname" 1; pack "$WORK/b6" "$WORK/evil.mpk"
out=$(nyai_run "$r" install "$WORK/evil.mpk" 2>&1); rc=$?
show "$out"
expect "6 [$badname] 拒装" test $rc -ne 0
expect "6 [$badname] 错误文案指向 app.json.package" \
sh -c 'printf "%s" "$1" | grep -q "app.json.package 非法"' _ "$out"
expect "6 [$badname] 未落盘到目录外(root/escape、root/a、沙箱父目录)" \
test ! -e "$r/escape" -a ! -e "$r/a" -a ! -e "$WORK/case-6/escape" -a ! -e "$WORK/case-6/a"
expect "6 [$badname] MeowAPPs/MeowOS 目录未被破坏" \
test -d "$r/MeowAPPs" -a -d "$r/MeowOS"
expect "6 [$badname] 无暂存残留" tmp_clean "$r"
done
# ---- 7 解压失败 / SIGTERM 中断 ----
r=$(sb 7)
printf 'this is not a gzip stream\n' > "$WORK/broken.mpk"
out=$(nyai_run "$r" install "$WORK/broken.mpk" 2>&1); rc=$?
show "$out"
expect "7a 非法包(非 gzip/tar)→ 拒装" test $rc -ne 0
expect "7b 解压失败后无暂存残留" tmp_clean "$r"
mkpkg "$WORK/b7" dev.test.slow 1
head -c 134217728 /dev/zero > "$WORK/b7/big.bin" # 128MB,拉长解包时间以便打信号
pack "$WORK/b7" "$WORK/slow.mpk"
r=$(sb 7s)
MEOWROOT="$r" MEOW_VERIFY_BIN="$VERIFY" "$NYAI" install "$WORK/slow.mpk" >"$WORK/sig.log" 2>&1 &
pid=$!
sleep 0.30
kill -TERM "$pid" 2>/dev/null
wait "$pid"; rc=$?
show "$(cat "$WORK/sig.log")"
if grep -q "收到信号" "$WORK/sig.log"; then
expect "7c SIGTERM 中断:退出码 143" test "$rc" -eq 143
expect "7d SIGTERM 中断后无暂存残留" tmp_clean "$r"
expect "7e SIGTERM 中断后未落盘 App" test ! -e "$r/MeowAPPs/dev.test.slow"
else
skip "7c-e SIGTERM 中断清理" "解包在信号前已完成(rc=$rc)"
fi
rm -f "$WORK/b7/big.bin"
# ---- 8 索引路径:Package 取自清单 ----
r=$(sb 8)
mkdir -p "$WORK/repo"
mkpkg "$WORK/b8" os.meow.idx 3; pack "$WORK/b8" "$WORK/idx.mpk"
if sign os.meow.idx "$WORK/idx.mpk"; then
cp "$WORK/idx.mpk" "$WORK/repo/zzz-renamed-file.mpk" # 文件名与包名完全不同
printf 'local %s\n' "$WORK/repo" > "$r/MeowOS/opt/nyai/sources.list"
"$NYAI" index "$WORK/repo" >"$WORK/idx.log" 2>&1
expect "8a 索引 Package 字段来自 app.json(不是文件名)" \
grep -q '^Package: os.meow.idx$' "$WORK/repo/Packages"
out=$(nyai_run "$r" install os.meow.idx 2>&1); rc=$?
show "$out"
expect "8b 按索引包名安装成功" test $rc -eq 0 -a -f "$r/MeowAPPs/os.meow.idx/app.json"
expect "8c 索引安装后无残留" tmp_clean "$r"
else
skip "8 索引路径" "无签名私钥"
fi
# ---- 9 upgrade 复用 install 引擎 ----
r=$(sb 9)
mkpkg "$WORK/b9" dev.local.up 1; pack "$WORK/b9" "$WORK/up1.mpk"
nyai_run "$r" install "$WORK/up1.mpk" >/dev/null 2>&1
mkpkg "$WORK/b9" dev.local.up 2; pack "$WORK/b9" "$WORK/up2-any-name.bin"
out=$(nyai_run "$r" upgrade dev.local.up "$WORK/up2-any-name.bin" 2>&1); rc=$?
show "$out"
expect "9a upgrade 接受任意文件名(清单包名 == 目标包名)" \
test $rc -eq 0 -a "$(grep -o '"version_code":[0-9]*' "$r/MeowAPPs/dev.local.up/app.json")" = '"version_code":2'
expect "9b upgrade 后无残留" tmp_clean "$r"
mkpkg "$WORK/b9" dev.local.up 0; pack "$WORK/b9" "$WORK/up0.mpk"
out=$(nyai_run "$r" upgrade dev.local.up "$WORK/up0.mpk" 2>&1); rc=$?
show "$out"
expect "9c 降级被拒" sh -c 'test $1 -ne 0 && printf "%s" "$2" | grep -q "不允许降级"' _ "$rc" "$out"
mkpkg "$WORK/b9" dev.local.other 3; pack "$WORK/b9" "$WORK/upother.mpk"
out=$(nyai_run "$r" upgrade dev.local.up "$WORK/upother.mpk" 2>&1); rc=$?
show "$out"
expect "9d 清单包名 ≠ upgrade 目标 → 拒" \
sh -c 'test $1 -ne 0 && printf "%s" "$2" | grep -q "与目标包名(dev.local.up) 不一致"' _ "$rc" "$out"
expect "9e 以上失败均无残留" tmp_clean "$r"
# ---- 10 评审 r1 回归:大小写绕过(P1)/ 尾点 / 名字冲突 / 成员名 / 解压炸弹 ----
# 10a 先装一个合法签名系统包,再试图用大写包名顶掉它(exFAT 名字不区分大小写)
if [ -n "$KEY" ]; then
r=$(sb 10a); mkpkg "$WORK/b10a" os.meow.demo 1; pack "$WORK/b10a" "$WORK/demo10a.mpk"
sign os.meow.demo "$WORK/demo10a.mpk"
nyai_run "$r" install "$WORK/demo10a.mpk" >/dev/null 2>&1
before=$(md5sum "$r/MeowAPPs/os.meow.demo/app.json" | cut -d' ' -f1)
mkpkg "$WORK/b10ae" "OS.MEOW.DEMO" 99; pack "$WORK/b10ae" "$WORK/evil-case.mpk"
out=$(nyai_run "$r" install "$WORK/evil-case.mpk" 2>&1); rc=$?
show "$out"
after=$(md5sum "$r/MeowAPPs/os.meow.demo/app.json" | cut -d' ' -f1)
expect "10a 大写包名 OS.MEOW.DEMO 被拒(valid_pkg 只收小写)" test $rc -ne 0
expect "10a 错误文案指向 app.json.package 非法" \
sh -c 'printf "%s" "$1" | grep -q "app.json.package 非法"' _ "$out"
expect "10a 已装 os.meow.demo 未被顶掉(app.json 未变)" test "$before" = "$after"
expect "10a 未生成大写目录" test ! -e "$r/MeowAPPs/OS.MEOW.DEMO"
expect "10a 无残留" tmp_clean "$r"
else
skip "10a 大小写绕过" "无签名私钥"
fi
# 10b 尾点包名(exFAT/Windows 尾点映射怪癖)
r=$(sb 10b); mkpkg "$WORK/b10b" "dev.test." 1; pack "$WORK/b10b" "$WORK/trailing-dot.mpk"
out=$(nyai_run "$r" install "$WORK/trailing-dot.mpk" 2>&1); rc=$?
show "$out"
expect "10b 尾点包名 dev.test. 被拒" \
sh -c 'test $1 -ne 0 && printf "%s" "$2" | grep -q "app.json.package 非法"' _ "$rc" "$out"
expect "10b 无残留" tmp_clean "$r"
# 10c 已存在仅大小写不同的目录 → 部署前拦(exFAT 上会顶掉已装 App)
r=$(sb 10c); mkdir -p "$r/MeowAPPs/DEV.TEST.CLASH"
mkpkg "$WORK/b10c" dev.test.clash 1; pack "$WORK/b10c" "$WORK/clash.mpk"
out=$(nyai_run "$r" install "$WORK/clash.mpk" 2>&1); rc=$?
show "$out"
expect "10c 与已装目录仅大小写不同 → 拒装" \
sh -c 'test $1 -ne 0 && printf "%s" "$2" | grep -q "仅大小写不同"' _ "$rc" "$out"
expect "10c 已存在的目录未被改动" test -d "$r/MeowAPPs/DEV.TEST.CLASH"
expect "10c 无残留" tmp_clean "$r"
# 10d tar 成员名净化(不依赖外部 tar 的路径处理)
if command -v python3 >/dev/null 2>&1; then
for nm in "/tmp/evil.txt:dev.evil.abs" "../evil.txt:dev.evil.dd" "-evil.txt:dev.evil.dash"; do
member=${nm%%:*}; pkg=${nm##*:}
r=$(sb "10d-$pkg")
mk_evil_tar "$WORK/evil-member.mpk" "$member" "$pkg"
out=$(nyai_run "$r" install "$WORK/evil-member.mpk" 2>&1); rc=$?
show "$out"
expect "10d [$member] 成员名非法 → 拒装" \
sh -c 'test $1 -ne 0 && printf "%s" "$2" | grep -q "包成员路径非法"' _ "$rc" "$out"
expect "10d [$member] 无残留且未落盘" test ! -e "$r/MeowAPPs/$pkg" -a -z "$(find "$r/MeowOS/tmp/pkgs" -mindepth 1 2>/dev/null)"
done
# 10e 控制字符成员名(tar -tv 可能把它转义成可见文本 → 靠解包后的 on-disk 名字复核)
r=$(sb 10e)
python3 - "$WORK/evil-ctrl.mpk" <<'PY'
import sys, tarfile, io, gzip
buf = io.BytesIO()
with tarfile.open(fileobj=buf, mode='w') as t:
ti = tarfile.TarInfo('ev\x01il.txt'); ti.size = 3; t.addfile(ti, io.BytesIO(b'pwn'))
j = b'{"name":"X","package":"dev.evil.ctrl","exec":"x","version":"1","version_code":1}'
tj = tarfile.TarInfo('app.json'); tj.size = len(j); t.addfile(tj, io.BytesIO(j))
open(sys.argv[1], 'wb').write(gzip.compress(buf.getvalue()))
PY
out=$(nyai_run "$r" install "$WORK/evil-ctrl.mpk" 2>&1); rc=$?
show "$out"
expect "10e 控制字符成员名 → 拒装" \
sh -c 'test $1 -ne 0 && printf "%s" "$2" | grep -q "控制字符"' _ "$rc" "$out"
expect "10e 无残留" tmp_clean "$r"
# 10f 解压炸弹:成员头声明 700MB(上限 512MB)
r=$(sb 10f)
mk_bomb_tar "$WORK/bomb.mpk"
out=$(nyai_run "$r" install "$WORK/bomb.mpk" 2>&1); rc=$?
show "$out"
expect "10f 解压炸弹(700MB)→ 拒装" \
sh -c 'test $1 -ne 0 && printf "%s" "$2" | grep -q "防解压炸弹"' _ "$rc" "$out"
expect "10f 无残留" tmp_clean "$r"
else
skip "10d-f 成员名/解压炸弹" "无 python3"
fi
# ---------------- 汇总 ----------------
printf '\n== summary: %d passed, %d failed, %d skipped ==\n' "$PASS" "$FAIL" "$SKIP"
[ "$FAIL" -eq 0 ] || exit 1
exit 0