mirror of
https://github.com/yusufipk/dikte.git
synced 2026-09-11 10:56:10 +00:00
146 lines
5.5 KiB
Bash
Executable File
146 lines
5.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
: "${OUT_DIR:=work/out}"
|
|
: "${SOURCE_DIR:=whisper.cpp}"
|
|
asset=whisper-bin-ubuntu-vulkan-x64
|
|
archive="$OUT_DIR/$asset.tar.gz"
|
|
tmp=$(mktemp -d)
|
|
trap 'rm -rf "$tmp"' EXIT
|
|
|
|
test -s "$archive"
|
|
(cd "$OUT_DIR" && sha256sum --check "$asset.tar.gz.sha256")
|
|
ARCHIVE="$archive" ASSET="$asset" python3 - <<'PY'
|
|
import os
|
|
import posixpath
|
|
import tarfile
|
|
|
|
archive = os.environ["ARCHIVE"]
|
|
asset = os.environ["ASSET"]
|
|
|
|
|
|
def under_root(name):
|
|
normalized = posixpath.normpath(name)
|
|
return (not posixpath.isabs(normalized)
|
|
and normalized != ".."
|
|
and not normalized.startswith("../")
|
|
and normalized.split("/", 1)[0] == asset)
|
|
|
|
|
|
with tarfile.open(archive, "r:gz") as bundle:
|
|
for member in bundle:
|
|
if not under_root(member.name):
|
|
raise SystemExit(f"unsafe archive member: {member.name}")
|
|
if member.isdev() or member.isfifo():
|
|
raise SystemExit(f"special archive member: {member.name}")
|
|
if not (member.isdir() or member.isfile()
|
|
or member.issym() or member.islnk()):
|
|
raise SystemExit(f"unsupported archive member: {member.name}")
|
|
if member.issym():
|
|
target = posixpath.join(posixpath.dirname(member.name),
|
|
member.linkname)
|
|
if not under_root(target):
|
|
raise SystemExit(f"unsafe symlink: {member.name}")
|
|
if member.islnk() and not under_root(member.linkname):
|
|
raise SystemExit(f"unsafe hardlink: {member.name}")
|
|
PY
|
|
tar -xzf "$archive" -C "$tmp"
|
|
root="$tmp/$asset"
|
|
|
|
test -x "$root/whisper-server"
|
|
test -f "$root/libwhisper.so"
|
|
test -f "$root/libggml.so"
|
|
test -f "$root/libggml-base.so"
|
|
test -f "$root/libggml-vulkan.so"
|
|
compgen -G "$root/libggml-cpu-*.so" >/dev/null
|
|
test -f "$root/LICENSES/whisper.cpp-MIT.txt"
|
|
test -f "$root/LICENSES/cpp-httplib-MIT.txt"
|
|
test -f "$root/LICENSES/nlohmann-json-MIT.txt"
|
|
(cd "$root" && sha256sum --check SHA256SUMS)
|
|
|
|
# All shipped ELF objects must be relocatable and must not remember /work.
|
|
while IFS= read -r -d '' file; do
|
|
file "$file" | grep -q ELF || continue
|
|
dynamic=$(readelf -d "$file")
|
|
if ! grep -Fq 'Library runpath: [$ORIGIN]' <<<"$dynamic"; then
|
|
echo "runpath is not \$ORIGIN in $file" >&2
|
|
exit 1
|
|
fi
|
|
if grep -Eq '/(home|tmp|work)/' <<<"$dynamic"; then
|
|
echo "build path remains in $file" >&2
|
|
exit 1
|
|
fi
|
|
done < <(find "$root" -type f -print0)
|
|
|
|
# Vulkan remains a plugin dependency. The executable must start without a loader.
|
|
if readelf -d "$root/whisper-server" | grep -q 'libvulkan.so'; then
|
|
echo "whisper-server links Vulkan instead of loading it as a plugin" >&2
|
|
exit 1
|
|
fi
|
|
readelf -d "$root/libggml-vulkan.so" | grep -q 'libvulkan.so.1'
|
|
|
|
# Ubuntu 22.04 establishes the glibc ceiling promised by this artifact.
|
|
ROOT="$root" python3 - <<'PY'
|
|
import os, pathlib, re, subprocess
|
|
root = pathlib.Path(os.environ['ROOT'])
|
|
seen = {'GLIBC': set(), 'GLIBCXX': set(), 'CXXABI': set()}
|
|
external = {
|
|
'libc.so.6', 'libgcc_s.so.1', 'libm.so.6', 'libstdc++.so.6',
|
|
'libvulkan.so.1', 'ld-linux-x86-64.so.2',
|
|
}
|
|
for path in root.iterdir():
|
|
if not path.is_file() or path.is_symlink():
|
|
continue
|
|
header = subprocess.run(['readelf', '-h', path], text=True,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.DEVNULL).stdout
|
|
if not header:
|
|
continue
|
|
if 'Machine: Advanced Micro Devices X86-64' not in header:
|
|
raise SystemExit(f'wrong ELF architecture: {path.name}')
|
|
dynamic = subprocess.run(['readelf', '-d', path], text=True,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.DEVNULL).stdout
|
|
needed = re.findall(r'\(NEEDED\).*\[(.*?)\]', dynamic)
|
|
unexpected = [name for name in needed
|
|
if name not in external
|
|
and not re.fullmatch(
|
|
r'lib(?:whisper|ggml(?:-base)?)\.so\.\d+', name)]
|
|
if unexpected:
|
|
raise SystemExit(
|
|
f'unexpected DT_NEEDED in {path.name}: {unexpected}')
|
|
if path.name != 'libggml-vulkan.so' and 'libvulkan.so.1' in needed:
|
|
raise SystemExit(f'Vulkan is not plugin-only in {path.name}')
|
|
contents = path.read_bytes()
|
|
for marker in (b'/home/', b'/tmp/', b'/work/'):
|
|
if marker in contents:
|
|
raise SystemExit(
|
|
f'build path {marker!r} remains in {path.name}')
|
|
text = subprocess.run(['objdump', '-T', path], text=True,
|
|
stdout=subprocess.PIPE, stderr=subprocess.DEVNULL).stdout
|
|
for family in seen:
|
|
pattern = rf'{family}_([0-9]+(?:\.[0-9]+)+)'
|
|
seen[family].update(tuple(map(int, version.split('.')))
|
|
for version in re.findall(pattern, text))
|
|
assert seen['GLIBC'] and max(seen['GLIBC']) <= (2, 34), max(seen['GLIBC'])
|
|
assert seen['GLIBCXX'] and max(seen['GLIBCXX']) <= (3, 4, 30), max(seen['GLIBCXX'])
|
|
assert seen['CXXABI'] and max(seen['CXXABI']) <= (1, 3, 13), max(seen['CXXABI'])
|
|
for family, versions in seen.items():
|
|
print(f'maximum {family} symbol:', '.'.join(map(str, max(versions))))
|
|
PY
|
|
|
|
python3 - "$root/$asset.cdx.json" <<'PY'
|
|
import json, sys
|
|
with open(sys.argv[1], encoding='utf-8') as stream:
|
|
doc = json.load(stream)
|
|
assert doc['bomFormat'] == 'CycloneDX'
|
|
assert doc['specVersion'] == '1.6'
|
|
assert doc['metadata']['component']['name'] == 'whisper-server'
|
|
assert len(doc['components']) >= 3
|
|
print('SBOM components:', len(doc['components']))
|
|
PY
|
|
|
|
LD_LIBRARY_PATH='' "$root/whisper-server" --help >/dev/null 2>&1
|
|
|
|
echo "structure: PASS"
|