The trust chain bootstrap.zsh establishes on a fresh machine: what is fetched, from where,
how (or whether) each artifact is verified, and which trust anchors the installer inherits
from. Scope is Nix, which the script installs; go-task, which it runs from the Nix store; and
Homebrew, which the first switch installs; and the audit signals emitted before each. SSH keys live in 1Password; Claude hook
secret-scanning lives in the jshvn/ai repo.
The per-machine security boundary is explicit selection: every switch keys off the machine
name task setup wrote to $XDG_STATE_HOME/dotfiles/machine, never a hostname or an
environment variable.
- What is downloaded: the Nix install script, then the Nix release tarball it fetches.
- From where:
https://nixos.org/nix/install(a redirect toreleases.nixos.org); the tarball fromreleases.nixos.org, with the SHA-256 the script embeds. - How it is verified: the script, HTTPS only, no checksum pin; the tarball, by the SHA-256 inside the script.
- What it does with sudo: creates the
/nixAPFS volume (/etc/synthetic.conf,/etc/fstabthroughvifs), thenixbldgroup and build users, thenix-daemonlaunchd job and/etc/nix/nix.conf; prepends a block sourcingnix-daemon.shto/etc/zshrcand/etc/bashrc, keeping.backup-before-nixcopies. - Why this trust boundary is accepted: it is the upstream installer, the same path
jgrid.net's Macs use.
bootstrap.zshdownloads it to a file first and prints the path, so it can be read before the consent keypress; the script then runs from that file, not from a pipe. - Audit signal: before running it,
bootstrap.zshprints anAUDIT:block to stderr naming the source URL and the trust note, then requires a single keypress read from/dev/tty(Enter to proceed; any other key aborts). Consent from the terminal means bootstrap cannot run through acurl ... | zshpipe.
- What is downloaded: the go-task store path the flake's locked nixpkgs names
(
nix run --inputs-from <checkout> nixpkgs#go-task). Nothing is installed: every later run uses the go-task Homebrew installs. - From where:
cache.nixos.org; the nixpkgs source from GitHub. - How it is verified: Nix checks the store path's signature against the cache's key; the
nixpkgs source by the content hash
flake.lockpins. - Why this trust boundary is accepted: the same anchors every switch already trusts.
- What is downloaded: the Homebrew install shell script (
install.sh). - From where:
https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh. - How it is verified: HTTPS only. No checksum pin. No signature verification.
- What it does with sudo: runs as the user (it refuses root), creates
/opt/homebrewand hands it to the user, and installs the Xcode Command Line Tools if they are missing. Its sudo calls reuse the password the switch just asked for. - Why this trust boundary is accepted: the canonical install path published by
brew.sh; a checksum pin would need updating on every installer change for little gain over HTTPS. - Audit signal: none of its own.
modules/homebrew.nixruns it inside the switch, only when/opt/homebrew/bin/brewis missing, after printinginstalling Homebrew...; the password the switch asks for is the consent.
darwin-rebuild switch fetches the nixpkgs, nix-darwin and home-manager sources
flake.lock pins (by content hash) and any store paths from cache.nixos.org, each
signature-checked against the cache's key. Nix supplies nix-darwin, home-manager, the Nix
(nixVersions.latest) that replaces the installer's as both the daemon and the default
profile, and nixpkgs' CA bundle at /etc/ssl/certs/ca-certificates.crt; every package Josh
uses, go-task included, comes from Homebrew, with its bottle checksums.
| Threat | Mitigation | Residual Risk |
|---|---|---|
MITM on raw.githubusercontent.com or nixos.org during an installer fetch |
TLS only | Real -- accepted as the cost of an unpinned install path |
Compromise of the GitHub mirror or releases.nixos.org serving an installer |
HTTPS only; the Nix script is saved and can be read before it runs | Real -- documented |
| Compromise of a Homebrew bottle in the CDN | SHA-256 validated by brew |
Mitigated |
| Compromise of formula metadata declaring a wrong SHA-256 | Formula commits are PR-reviewed by Homebrew | Mitigated |
A tampered store path from cache.nixos.org |
Nix verifies the narinfo signature | Mitigated |
| A flake input moved under the same name | flake.lock pins content hashes |
Mitigated |
Local user runs bootstrap with a hostile $DOTFILEDIR |
bootstrap.zsh resolves it from $0 |
Mitigated |
- Apple. macOS itself,
curl,sh,zsh, the system TLS trust store. - GitHub Inc.
raw.githubusercontent.comandghcr.io, and the flake inputsflake.nixdeclares andflake.lockpins (the nixpkgs, nix-darwin and home-manager sources). - The Homebrew project. The install script, formula metadata, the bottling pipeline.
- The NixOS Foundation.
nixos.org,releases.nixos.org,cache.nixos.organd its signing key, and the nixpkgs sources the lock pins. - The nix-darwin and home-manager projects. The module code the lock pins and the switch evaluates.
- SSH key handling -- each profile's
profiles/<name>/holds its public key (key.pub) and the 1Password agent config (agent.toml, which keys the agent offers, in order);apps/1password/env.zshexportsSSH_AUTH_SOCKandapps/ssh/configsetsIdentityAgentfor every host. - Claude hook secret-scanning -- the jshvn/ai repo.
- Per-machine credential management -- no secret enters the repo; SSH and signing keys stay in 1Password.
# What bootstrap will run (Step 1), or read the copy bootstrap.zsh saved:
curl -fsSL https://nixos.org/nix/install | less
# What the first switch will run when Homebrew is missing (Step 3):
curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh | lessNot in scope:
- Pinned-checksum installers. Vendor both install scripts at a known commit and verify their checksums before execution. Eliminates the residual Step 1 and Step 3 risk at the cost of installer staleness.
Structural regressions are gated: .github/workflows/ci.yml evaluates every machine and
profile, lints, runs the hermetic tests and builds lerasium's closure on every push to master
and every pull request.