(
path: pathlib.Path, *, required_member: str, expected_sha256: str,
expected_size: int, require_executable_mode: bool
)
| 278 | |
| 279 | |
| 280 | def verify_tar( |
| 281 | path: pathlib.Path, *, required_member: str, expected_sha256: str, |
| 282 | expected_size: int, require_executable_mode: bool |
| 283 | ) -> None: |
| 284 | matches = 0 |
| 285 | try: |
| 286 | with tarfile.open(path, mode="r:gz") as archive: |
| 287 | members = archive.getmembers() |
| 288 | if not members or len(members) > MAX_MEMBERS: |
| 289 | raise ContractError(f"tar member count is invalid: {path.name}") |
| 290 | if sum(member.size for member in members) > MAX_TOTAL_MEMBER_BYTES: |
| 291 | raise ContractError(f"tar exceeds total member-size ceiling: {path.name}") |
| 292 | seen: set[str] = set() |
| 293 | for member in members: |
| 294 | if not safe_member_name(member.name) or member.name in seen: |
| 295 | raise ContractError(f"tar has unsafe or duplicate member: {path.name}:{member.name}") |
| 296 | seen.add(member.name) |
| 297 | if member.issym() or member.islnk() or member.isdev() or member.isfifo(): |
| 298 | raise ContractError(f"tar contains a special member: {path.name}:{member.name}") |
| 299 | if member.size > MAX_MEMBER_BYTES: |
| 300 | raise ContractError(f"tar member exceeds size ceiling: {path.name}:{member.name}") |
| 301 | if member.name != required_member: |
| 302 | continue |
| 303 | if not member.isfile(): |
| 304 | raise ContractError(f"required tar executable is not regular: {path.name}") |
| 305 | if require_executable_mode and stat.S_IMODE(member.mode) != 0o755: |
| 306 | raise ContractError( |
| 307 | f"required tar executable has wrong mode: {path.name}:{member.name}" |
| 308 | ) |
| 309 | matches += 1 |
| 310 | handle = archive.extractfile(member) |
| 311 | if handle is None: |
| 312 | raise ContractError(f"required tar executable is unreadable: {path.name}") |
| 313 | with handle: |
| 314 | actual_sha256, actual_size = hash_stream( |
| 315 | handle, declared_size=member.size, label=f"{path.name}:{member.name}" |
| 316 | ) |
| 317 | if actual_sha256 != expected_sha256 or actual_size != expected_size: |
| 318 | raise ContractError(f"tar executable does not match selection: {path.name}") |
| 319 | except (tarfile.TarError, EOFError) as error: |
| 320 | raise ContractError(f"malformed tar archive: {path.name}") from error |
| 321 | if matches != 1: |
| 322 | raise ContractError(f"tar must contain exactly one required executable: {path.name}") |
| 323 | |
| 324 | |
| 325 | def zip_entry_kind(info: zipfile.ZipInfo) -> str: |
nothing calls this directly
no test coverage detected