Architecture
Architecture and trust boundaries
SteamOS NVIDIA Image Builder is a local desktop workflow. The user supplies an official Valve recovery image; the application creates disposable working storage and exports a separate result. It does not upload or redistribute the Valve image.
Responsibility boundaries
The read-only governance authority is
BOUNDARIES.md.
The table below is only an implementation summary.
| Component | Owns | Must not own |
|---|---|---|
| Main/progress UI | Image selection, explicit user choices, status, cancellation, and diagnostics | Compatibility decisions, shell commands, credentials, or filesystem mutation |
| Rust host backend | State machines, safe paths, downloads, hashes, QEMU lifecycle, immutable pins, handoffs, result validation, and export | Trusting human log text or silently selecting compatibility fallbacks |
| Native Fedora appliance | Fast read-only image inspection, disposable overlay creation, marker mutation, and independent output inspection | NVIDIA compatibility policy or access to unrelated host directories |
| Managed x86_64 Fedora appliance | Exact-kernel NVIDIA compilation and offline SteamOS-root validation/mutation | Selecting arbitrary headers, packages, signers, roots, or A/B slots |
| NVIDIA support repository | Resolver/build/install contracts, reviewed keys and userspace locks, artifact formats, and canonical publishing | Choosing a user image or host output path |
| NVIDIA source repository | Versioned project patches and exact source commits | Image mutation, release authorization, or runtime credentials |
| Gamescope repository | Gamescope-specific source/artifact policy | NVIDIA kernel-module fallback policy |
Host backend module layout
The Tauri crate root intentionally contains only shared policy constants, module wiring, and the public application entry point. Backend responsibilities are separated as follows:
| Rust module | Responsibility |
|---|---|
app.rs |
Tauri construction, fixed command registration, and application shutdown events |
appliance.rs |
QEMU/QMP/SSH processes, disposable runtimes, host preparation, health, and workflow command orchestration |
contracts.rs |
Versioned support/build/install/manifest data and pinned support-file identities |
image.rs |
Input validation, layout inspection, working-copy mutation, space checks, export, and independent verification |
nvidia.rs |
NVIDIA/source resolution, authenticated downloads, reviewed userspace closure, exact builds, and publication |
installer.rs |
Offline-root handoff, structured support-result validation, storage policy, and target mutation |
settings.rs |
Versioned preferences and GitHub maintainer authentication/authorization |
windows.rs |
Native progress and maintainer child-window construction |
tests.rs |
Default and explicitly ignored live integration tests |
The frontend follows the same boundary: diagnostic compaction lives in
log-diagnostics.js, while ANSI/control parsing and safe DOM rendering live in
terminal-renderer.js. Compatibility and command construction remain in Rust.
Data flow
user recovery image (read-only)
|
v
Rust signature detection + hashing
|
v
normalized raw runtime storage -----> native Fedora inspection
| |
| v
| disposable qcow2 overlay
| |
+--------------------------> x86_64 Fedora
|
pinned modules + reviewed userspace lock
|
v
validate-only, then mutation
|
v
Rust export to a create-only partial file
|
v
fresh native Fedora independent inspection
|
v
atomic image + manifest finalization
The original image is never attached writable. The working overlay is the only SteamOS block device mutated, and it is discarded after failures. The x86_64 worker is separate because an Apple Silicon appliance cannot execute SteamOS’s x86_64 pacman and mkinitcpio tools correctly.
Protocol and lifecycle
Rust launches QEMU directly and allocates loopback-only SSH and QMP ports. Cloud-init writes a fixed readiness marker. After SSH becomes available, Rust requires protocol version 1, the expected guest architecture, sufficient guest space, and the complete required-tool inventory. Process exit, marker mismatch, health failure, and timeout are distinct lifecycle failures.
Each runtime directory contains ephemeral QEMU state, cloud-init media, SSH keys, logs, normalized storage, overlays, and staged artifacts. Runtime directories and appliance images are ignored by Git. Normal completion removes ephemeral workers; diagnostic logs are archived without embedding host paths in the generated image manifest.
Supply-chain boundary
Normal NVIDIA installation accepts only:
- an immutable support commit whose required files match embedded sizes and SHA-256 hashes;
- an exact SteamOS/kernel/NVIDIA identity;
- an authenticated module archive with matching provenance and vermagic;
- an exact reviewed userspace lock and minimal keyring;
- package and detached-signature bytes matching that lock; and
- a structured installer result independently revalidated by Rust.
- a rootfs-resident payload receipt binding the validated module, userspace,
firmware, and initramfs evidence so later Valve-installer propagation can be
checked by exact
receiptId.
Logs are diagnostic only. A missing lock, changed signer, unavailable historical input, ambiguous kernel/root/EFI/var partition, or mismatched result fails closed and becomes a maintainer compatibility issue.
The support-owned bounded result/progress validator runs inside the x86_64 appliance after both validation-only and mutation attempts. Rust separately requires and cross-checks the mandatory success proofs; neither an installer exit code nor a receipt by itself can promote an image.
macOS development bootstrap
Run:
./cargodev_init_macos.sh
The script supports Apple Silicon and Intel macOS, installs missing Homebrew dependencies, reports every required tool version, enforces minimum supported versions, and launches Tauri development mode. The native appliance can be built with:
./builder/appliance/build_macos.sh
On Apple Silicon, prepare the separate software-emulated installer/build worker with:
./builder/appliance/build_macos.sh --architecture x86_64
Generated qcow2 images, appliance work directories, runtime directories, logs, keys, and output images must remain untracked.
Current compatibility and limitations
- macOS is the implemented host platform; Apple Silicon is the primary tested host and Intel macOS follows the native x86_64 QEMU path.
- SteamOS 3.8.14 with NVIDIA 575.64.05 is the first reviewed userspace-lock target. Other pairs require their own reviewed lock.
- NVIDIA mutation can be structurally validated, but the result is not yet classified as install-ready. Valve installer propagation, Gamescope changes, A/B update behavior, and NVIDIA hardware boot remain separate gates.
- The application has a fail-closed macOS USB writer and independently tested raw-device copy/read-back engine. It accepts only a manifest-bound, sector-aligned raw output and a repeatedly validated whole external physical removable disk, then requires a short-lived one-use token and explicit final confirmation. Normal packaged physical writes remain unavailable until a signed least-privilege helper is installed; running the GUI as root is not a supported workaround.
Troubleshooting boundary
Users should resolve only ordinary input, disk-space, and transient-network problems. Missing exact artifacts, headers, reviewed locks, signer changes, compiler failures, and compatibility mismatches are maintainer issues. Preserve the smart diagnostic-log summary when reporting those failures; do not source alternate packages or keys manually.