Supply Chain Integrity

Python Libraries

All Python dependencies are sourced exclusively from PyPI over HTTPS. No private indexes or mirrors are used.

uv manages the dependency tree. uv.lock records the exact version and SHA-256 hash of every package in the full transitive closure. uv sync --frozen verifies each downloaded wheel against its recorded hash before installation — a mismatch is a hard error.

UV Bootstrap

The installation script setup.ps1 bootstraps uv by downloading the official uv-{arch}-pc-windows-msvc.zip binary archive from GitHub releases. The archive is never executed. uv.exe is extracted from it and placed inside the Vocalance install tree at %LOCALAPPDATA%\Programs\Vocalance\tools\uv.exe. No system-wide UV installation occurs.

Before extraction, the script verifies the archive’s SHA-256 against a value computed offline and hard-coded at development time:

$UV_VERSION    = '0.11.22'
$UV_ZIP_SHA256 = @{
    'x86_64'  = '<hex digest>'
    'aarch64' = '<hex digest>'
}

$actual = (Get-FileHash -Path $uvZipPath -Algorithm SHA256).Hash.ToLower()
if ($actual -ne $UV_ZIP_SHA256[$arch].ToLower()) {
    Remove-Item -LiteralPath $uvZipPath -Force -ErrorAction SilentlyContinue
    throw "Integrity check failed ..."
}

The hashes are produced by scripts/security/compute_uv_binary_hash.ps1 whenever a developer bumps $UV_VERSION. A mismatch deletes the downloaded archive and aborts setup; uv.exe is never extracted from an unverified archive.

AI Models

The AI model feature is optional (the installation script will ask the user whether they want to enable it — see Installation flow) and only a subset of dictation modes require it. When enabled, models are downloaded at first launch from Hugging Face.

Three controls are applied in sequence to every download.

Model allowlist

Only three models are permitted. The allowlist is hard-coded as a frozen Pydantic model in vocalance/app/config/app_config.py:

class LocalLLMArtifact(BaseModel):
    model_config = ConfigDict(frozen=True)
    id: str
    repo_id: str
    gguf_filenames: tuple[str, ...]
    gguf_sha256: Dict[str, str]  # filename → expected SHA-256

The three permitted models are:

  • qwen2.5-1.5b-q5km — Qwen2.5 1.5B Instruct (Q5_K_M)

  • qwen3-4b-q5km — Qwen3 4B (Q5_K_M)

  • qwen3-8b-q5km — Qwen3 8B (Q5_K_M)

Any model ID not in this list is rejected by the LLMConfig field validator before a download is ever attempted.

Redirect pinning

Hugging Face CDN downloads are often served via HTTP redirect. Before following any redirect, the downloader validates that the target hostname is present in a hard-coded allowlist of trusted Hugging Face infrastructure domains:

_TRUSTED_HF_HOSTS = frozenset({
    "huggingface.co",
    "cdn-lfs.huggingface.co",
    "cdn-lfs-us-1.huggingface.co",
    "hf.co",
    "cdn-lfs.hf.co",
    "cdn-lfs-us-1.hf.co",
    "cdn-lfs-eu-1.hf.co",
    "xethub.hf.co",
    "cas-bridge.xethub.hf.co",
})

def _validate_hf_redirect(response: httpx.Response) -> None:
    if response.is_redirect:
        location = response.headers.get("location", "")
        host = urlparse(location).hostname or ""
        trusted = host in _TRUSTED_HF_HOSTS or any(
            host.endswith(f".{h}") for h in _TRUSTED_HF_HOSTS
        )
        if not trusted:
            raise ValueError(f"Blocked redirect to untrusted host: {host!r}")

The allowlist covers both the legacy huggingface.co CDN subdomains and the current hf.co CDN (cdn-lfs-us-1.hf.co, cdn-lfs-eu-1.hf.co, cdn-lfs.hf.co) as well as the XetHub storage bridge (cas-bridge.xethub.hf.co) introduced in February 2025. A redirect to any host not in this set, or not a subdomain of a listed host, aborts the download.

SHA-256 verification

Each gguf_sha256 entry holds the expected digest of the corresponding .gguf file, computed offline by a developer using scripts/security/compute_llm_hashes.py. After every completed download:

actual = self._sha256_of_file(partial_path)
if actual != expected_sha256.lower():
    os.remove(partial_path)
    raise IntegrityError(
        f"SHA-256 mismatch for {filename!r}: "
        f"expected {expected_sha256} got {actual}"
    )

A mismatch deletes the file and raises IntegrityError, surfaced to the user as an explicit error. The application will not load a model that failed verification.

Bundled Models

The YAMNet sound classifier and Vosk speech recognition model are embedded directly in the release zip and are never downloaded separately (no need for external integrity validation).