Files
EapilSkillMarket/config/skill-overrides/common/office_package.py
T
KeyInfo Bot 36c089fee9 Sync third-party and MCP marketplace plugins
Constraint: Public skills are published only by explicit administrator action unless they are tracked third-party market sources.
Confidence: high
Scope-risk: narrow
Directive: Keep private/internal skills out of the public marketplace and preserve normal incremental market Git history.
Tested: Marketplace validation passed.
2026-10-06 15:29:22 +08:00

53 lines
2.1 KiB
Python

"""Unpack or repack an OOXML document without shell-specific ZIP commands."""
import argparse
import os
import tempfile
import zipfile
from pathlib import Path, PurePosixPath
def unpack(source, destination):
root = Path(destination).resolve()
if root.exists() and any(root.iterdir()):
raise ValueError("Unpack destination must be empty")
with zipfile.ZipFile(source) as archive:
for info in archive.infolist():
name = PurePosixPath(info.filename.replace("\\", "/"))
if name.is_absolute() or ".." in name.parts or any(":" in part for part in name.parts):
raise ValueError(f"Unsafe ZIP entry: {info.filename}")
if (info.external_attr >> 16) & 0o170000 == 0o120000:
raise ValueError(f"ZIP symlink is not supported: {info.filename}")
archive.extractall(root)
def pack(source, destination):
root = Path(source).resolve()
output = Path(destination).resolve()
if output.is_relative_to(root):
raise ValueError("Output must be outside the unpacked directory")
if not (root / "[Content_Types].xml").is_file():
raise ValueError("Source must be the package root containing [Content_Types].xml")
output.parent.mkdir(parents=True, exist_ok=True)
fd, temporary = tempfile.mkstemp(suffix=output.suffix, dir=output.parent)
os.close(fd)
try:
with zipfile.ZipFile(temporary, "w", zipfile.ZIP_DEFLATED) as archive:
for file in sorted(root.rglob("*")):
if file.is_symlink():
raise ValueError(f"Package symlink is not supported: {file}")
if file.is_file():
archive.write(file, file.relative_to(root).as_posix())
os.replace(temporary, output)
finally:
Path(temporary).unlink(missing_ok=True)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("action", choices=("unpack", "pack"))
parser.add_argument("input")
parser.add_argument("output")
args = parser.parse_args()
{"unpack": unpack, "pack": pack}[args.action](args.input, args.output)