Files
ApiCore/ApiCore-Whisper/tests/test_fetch_model.py
T
Nick SzaunigandClaude Opus 5.5 c53810b8a6
Backend Image / build-and-push (push) Successful in 5m49s
Frontend Image / build-and-push (push) Successful in 13m3s
Manifests / validate (push) Successful in 17s
Whisper Image / build-and-push (push) Successful in 1m56s
feat: Abschreiben im Cluster mit Whisper-Image und Voice-CronJob (T7 L3 Task 13)
ApiCore-Whisper: transcribe.py liest das Manifest im RAM-Arbeitsordner,
dekodiert mit festem Demuxer je Endung, misst die Länge vor dem
Abschreiben (TOO_LONG > 240 s, DECODE_FAILED bei Länge 0), sperrt das
Netz vor dem Modell-Laden und schreibt nur Zähler auf stdout. Image:
python:3.12-slim per Digest, Nutzer 1000, alle Pakete mit Hash
(faster-whisper 1.2.1, av 18.1.0 wegen Inkompatibilität mit av 19),
Modell faster-whisper-small auf fester Revision mit SHA-256 je Datei.
CI-Workflow nur bei Änderungen unter ApiCore-Whisper/, Actions per SHA.

deploy/k8s/components/voice: CronJob alle 2 Minuten mit fetch, whisper,
ingest (gleiche UID, getrennte /tmp-Volumes, damit der Decoder dem
Container mit den Secrets nichts unterschieben kann; whisper ohne
Secrets und Umgebungsvariablen außer WHISPER_CPU_THREADS), Overlay mit
Platzhalter-Digest, ConfigMap-Werte für Sprache, Policy-Tests (55).
Die Anbindung des Anthropic-Schlüssels bleibt offen (Ruling 9).

Refs #27

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-10-16 11:12:59 +02:00

48 lines
1.5 KiB
Python

"""Tests for the build-time model download (no network)."""
from __future__ import annotations
import hashlib
import sys
from pathlib import Path
import pytest
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
import fetch_model # noqa: E402
def test_verify_accepts_the_pinned_hash(tmp_path: Path):
file = tmp_path / "a.bin"
file.write_bytes(b"model")
fetch_model.verify(file, hashlib.sha256(b"model").hexdigest())
def test_verify_rejects_a_changed_file(tmp_path: Path):
file = tmp_path / "a.bin"
file.write_bytes(b"tampered")
with pytest.raises(fetch_model.ChecksumMismatch):
fetch_model.verify(file, hashlib.sha256(b"model").hexdigest())
def test_download_refuses_plain_http(tmp_path: Path):
with pytest.raises(ValueError):
fetch_model.download("http://example.invalid/x", tmp_path / "x")
def test_every_pinned_file_has_a_sha256_and_the_revision_is_a_commit():
assert len(fetch_model.REVISION) == 40
assert set(fetch_model.FILES) >= {"model.bin", "config.json", "tokenizer.json", "vocabulary.txt"}
for digest in fetch_model.FILES.values():
assert len(digest) == 64 and int(digest, 16) >= 0
def test_fetch_all_stops_on_a_mismatch(tmp_path: Path, monkeypatch):
def fake_download(url: str, target: Path) -> None:
target.write_bytes(b"evil")
monkeypatch.setattr(fetch_model, "download", fake_download)
with pytest.raises(fetch_model.ChecksumMismatch):
fetch_model.fetch_all(tmp_path / "m", {"model.bin": hashlib.sha256(b"good").hexdigest()})