From 58c48bd5a76e49493c8dd4c61a00837967924055 Mon Sep 17 00:00:00 2001 From: zhouxun <150260202+estelledc@users.noreply.github.com> Date: Fri, 24 Jul 2026 19:11:45 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=8F=91=E5=B8=83=E5=AE=89?= =?UTF-8?q?=E8=A3=85=EF=BC=9A=E6=81=A2=E5=A4=8D=E5=BD=92=E6=A1=A3=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=E6=89=A7=E8=A1=8C=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tests/test_release_build.py | 2 +- tools/verify_clean_install.py | 24 +++++++++++++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/tests/test_release_build.py b/tests/test_release_build.py index 55ce5e7..f9676bc 100644 --- a/tests/test_release_build.py +++ b/tests/test_release_build.py @@ -37,7 +37,7 @@ def test_build_is_deterministic_and_clean_installable(self) -> None: manifest["artifact"]["sha256"], hashlib.sha256((first / name).read_bytes()).hexdigest() ) installed = subprocess.run( - ["python3", str(INSTALLER), str(first / name), "--skip-tests"], + ["python3", str(INSTALLER), str(first / name)], cwd=ROOT, capture_output=True, text=True, diff --git a/tools/verify_clean_install.py b/tools/verify_clean_install.py index aaa5633..79f8714 100644 --- a/tools/verify_clean_install.py +++ b/tools/verify_clean_install.py @@ -4,6 +4,8 @@ from __future__ import annotations import argparse +import os +import shutil import stat import subprocess import sys @@ -28,6 +30,26 @@ def run(*arguments: str, cwd: Path) -> None: raise ValueError((result.stdout + result.stderr).strip() or f"command failed: {arguments}") +def extract_with_modes(archive: zipfile.ZipFile, destination: Path) -> None: + """Extract validated members without following links and restore portable modes.""" + + for item in archive.infolist(): + relative = PurePosixPath(item.filename) + target = destination.joinpath(*relative.parts) + if item.is_dir(): + target.mkdir(parents=True, exist_ok=True) + continue + mode = stat.S_IMODE(item.external_attr >> 16) + if mode not in {0o644, 0o755}: + raise ValueError(f"release ZIP has an unsupported file mode: {item.filename}") + target.parent.mkdir(parents=True, exist_ok=True) + with archive.open(item) as source, target.open("wb") as output: + shutil.copyfileobj(source, output) + os.chmod(target, mode) + if stat.S_IMODE(target.stat().st_mode) != mode: + raise ValueError(f"could not restore release file mode: {item.filename}") + + def main() -> int: args = parse_args() try: @@ -50,7 +72,7 @@ def main() -> int: raise ValueError("release ZIP contains a symbolic link") with tempfile.TemporaryDirectory(prefix="web-plan-execute-install-") as temporary: destination = Path(temporary) - archive.extractall(destination) + extract_with_modes(archive, destination) skill = destination / "web-plan-execute" run( sys.executable,