# Hatchling Install Hook Security Constraints

**Date**: 2026-03-10
**Issue**: GAP-21 (#495)
**Scope**: `hatch_build.py` — the PEP 517 build hook that runs at `pip install llmhosts` time

---

## Why This Matters

Hatchling build hooks execute with the full privileges of the installing user. In CI pipelines and container builds, that user is frequently root. Advisory council finding GAP-21 (#495) identified that LLMHosts shipped a build hook with no documented security model, no stated network access policy, and no sandboxing rationale — creating an audit gap for enterprise and security-conscious users.

Supply chain attacks increasingly target build-time hooks precisely because they run silently, with elevated privileges, before the installed package is even loaded. XZ Utils (CVE-2024-3094) and the SolarWinds build-system compromise both exploited the trust users extend to installation steps. The correct response is not to claim immunity but to publish a clear, auditable, enforceable security contract.

pip does not provide sandboxing. These invariants are enforced by code review policy and CI verification — not by a runtime security boundary. That is why documentation and automated checks are the primary defense.

---

## What the Hook Actually Does

The hook performs four operations and nothing else:

1. Detects NVIDIA GPU presence by invoking `nvidia-smi --query-gpu=name,memory.total --format=csv,noheader` as a subprocess (skipped silently if `nvidia-smi` is not on `PATH`).
2. Reads the reported VRAM amount to select the appropriate build variant (CPU-only, CUDA-base, or CUDA-full).
3. Sets the `LLMHOSTS_GPU_TIER` environment variable so maturin picks the correct pre-built wheel.
4. Returns. All operations complete in under two seconds.

There is no configuration file written, no network request made, no state persisted anywhere on the filesystem.

---

## Security Invariants (Non-Negotiable)

These constraints apply to all current and future versions of `hatch_build.py`. A PR that violates any of them must be blocked at review.

### 1. Zero Network Access

The hook MUST NOT make any HTTP, DNS, or socket call during `pip install`. Network calls at install time are a supply chain red flag and trivially enable data exfiltration of machine identifiers or environment variables. Detection method: CI runs the install inside a `docker run --network none` container; any socket attempt causes an immediate failure.

### 2. Zero Filesystem Writes Outside the Build Directory

The hook MUST NOT write to `~/.config`, `/etc`, `/tmp`, `/var`, or any path outside the wheel build directory. Persistent writes during install violate user expectations and leave forensic artifacts that security auditors flag. Detection method: `inotifywait -r /` during a test install; any write outside the build tree fails the check.

### 3. Read-Only Hardware Detection Only

GPU detection is limited to:
- `nvidia-smi --query-gpu=...` subprocess (reads existing driver data, no state change)
- `/sys/class/drm/` sysfs reads (Linux, kernel-managed read-only interface)
- `sysctl hw.memsize` (macOS, read-only)
- `metal.MTLCreateSystemDefaultDevice()` (macOS, read-only API query)

The hook MUST NOT modify any system state as a side effect of detection.

### 4. Graceful Degradation

If any detection step fails — missing binary, permission error, unexpected output format — the hook falls back to CPU-only mode and continues. GPU detection is informational. The install must never abort due to a detection failure.

### 5. No Remote Code Evaluation

The hook MUST NOT download, import, or evaluate any code from a network source. All logic must be present verbatim in `hatch_build.py` at the time the wheel is built.

---

## Verification

| Check | Method |
|---|---|
| Network isolation | `docker run --network none pip install llmhosts` — must succeed |
| No filesystem writes | `inotifywait` watch during install — zero writes outside build dir |
| Graceful degradation | Install on CPU-only VM — must complete without error |
| Source size | `wc -l hatch_build.py` — must be under 150 lines |
| No HTTP imports | `grep -E 'requests|urllib|httpx|socket' hatch_build.py` — must return nothing |

---

## Acceptance Criteria

- [ ] Hook runs successfully in `docker run --network none` container
- [ ] No files written outside the build directory (verified with `inotifywait`)
- [ ] Install completes on a machine with no GPU (graceful degradation confirmed)
- [ ] Hook source is under 150 lines with zero external HTTP imports
- [ ] Security invariants are reproduced verbatim in the `hatch_build.py` module docstring

---

## Implementation Note

The module docstring of `hatch_build.py` must contain a condensed version of the five invariants above. This ensures that anyone reading the source file — whether in a security audit, a dependency scanner, or a code review — encounters the contract without needing to find this document.

*Tracking: GAP-21, issue #495. Owner: core team. Review required on any modification to `hatch_build.py`.*
