Files
hermes-agent/tests/test_termux_python_linkage.py
ethernet 7606b014f5 fix(termux): complete the sealed CLI payload and verify installed startup
Stage npm, ffmpeg and its bionic runtime libraries, and static ARM ripgrep. Bind caches to actual build inputs. Generate entrypoints from the project manifest and verify real CLI/TUI startup and media conversion offline. Keep versions unchanged. Windows service work remains out of scope.
2026-09-06 14:00:42 -04:00

68 lines
2.7 KiB
Python

"""Exercise the linker repair against a real native extension on Linux."""
from __future__ import annotations
import shutil
import subprocess
import sys
import sysconfig
from pathlib import Path
import pytest
from scripts.termux import python_linkage
@pytest.mark.platforms("linux")
def test_python_symbols_gain_an_explicit_library_dependency(tmp_path):
import _ctypes
library = Path(sysconfig.get_config_var("LIBDIR")) / sysconfig.get_config_var("LDLIBRARY")
extension = tmp_path / Path(_ctypes.__file__).name
shutil.copy2(_ctypes.__file__, extension)
original = subprocess.check_output(["patchelf", "--print-needed", str(extension)], text=True).splitlines()
for name in original:
if name.startswith("libpython"):
subprocess.run(["patchelf", "--remove-needed", name, str(extension)], check=True)
assert python_linkage.link_extension(extension, library)
needed = subprocess.check_output(["patchelf", "--print-needed", str(extension)], text=True).splitlines()
soname = subprocess.check_output(["patchelf", "--print-soname", str(library)], text=True).strip()
assert soname in needed
assert not python_linkage.link_extension(extension, library), "a second pass must not edit a correct extension"
subprocess.run(
[sys.executable, "-c", "import _ctypes; print(_ctypes.__file__)"],
cwd=tmp_path, check=True,
)
def test_wheel_rewrite_regenerates_record_for_changed_member(tmp_path):
import base64
import csv
import hashlib
import io
import zipfile
wheel = tmp_path / "sample-1.0-cp311-cp311-linux_aarch64.whl"
record = "sample-1.0.dist-info/RECORD"
with zipfile.ZipFile(wheel, "w") as archive:
archive.writestr("sample/_native.so", b"unrepaired native bytes")
archive.writestr("sample/__init__.py", b"")
archive.writestr("sample-1.0.dist-info/WHEEL", "Wheel-Version: 1.0\nTag: cp311-cp311-linux_aarch64\n")
archive.writestr(record, "")
def repair(path, library):
assert library == tmp_path / "libpython.so"
path.write_bytes(b"repaired native bytes")
return True
python_linkage.repair_wheel(wheel, tmp_path / "libpython.so", repair=repair)
with zipfile.ZipFile(wheel) as archive:
assert archive.read("sample/_native.so") == b"repaired native bytes"
rows = {r[0]: r[1:] for r in csv.reader(io.StringIO(archive.read(record).decode()))}
for name in archive.namelist():
if name == record:
assert rows[name] == ["", ""]
continue
data = archive.read(name)
digest = base64.urlsafe_b64encode(hashlib.sha256(data).digest()).rstrip(b"=").decode()
assert rows[name] == ["sha256=" + digest, str(len(data))]