Skip to content

Commit da41303

Browse files
committed
fix: lint gate, real Brew hash, correct THREAT_MODEL
- Remove gosimple from golangci.yml (merged into staticcheck in v2) - Fix errcheck exclude-functions: use (io.ReadCloser).Close instead of invalid (net/http.Response).Body.Close field notation; add os.Remove for defer cleanup - Set real Homebrew install script SHA256 (2026-04-19 HEAD): dfd5145f - Update THREAT_MODEL.md: OMZ and auto-update both have hash verification implemented; remove stale "no hash verification" claims; document residual risk accurately
1 parent 17ae10f commit da41303

3 files changed

Lines changed: 13 additions & 12 deletions

File tree

.golangci.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ linters:
2121
- errcheck
2222
- govet
2323
- staticcheck
24-
- gosimple
2524
- ineffassign
2625
- unused
2726
- gocyclo
@@ -34,11 +33,13 @@ linters:
3433
default-signifies-exhaustive: true
3534
errcheck:
3635
exclude-functions:
37-
- (net/http.Response).Body.Close
36+
- (io.ReadCloser).Close
37+
- (io.Closer).Close
3838
- (net/http.ResponseWriter).Write
3939
- (*encoding/json.Encoder).Encode
4040
- os.WriteFile
4141
- (*os.File).Close
42+
- os.Remove
4243
gocyclo:
4344
min-complexity: 15
4445
gosec:

THREAT_MODEL.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ OpenBoot is a macOS CLI that automates developer environment setup. In a single
3838
| **Local user running `openboot`** | Full trust | The CLI runs as the user. All actions are bounded by the user's own file permissions. |
3939
| **openboot.dev API** | High, with validation | All responses are validated against a schema (`RemoteConfig.Validate()`). Response body size is capped at 1 MiB (`io.LimitReader`). The API URL is pinned to HTTPS (configurable only to HTTPS or localhost). |
4040
| **Remote config author** (`openboot install <user/slug>`) | Medium — verified identity, untrusted content | The config author is an authenticated openboot.dev user. Their package names are regex-validated. Their `post_install` commands are not executed without explicit opt-in. |
41-
| **Oh-My-Zsh GitHub CDN** (`raw.githubusercontent.com`) | Accepted risk, no hash verification | The OMZ install script is fetched and executed via `curl | sh`. No checksum is verified. This is the official OMZ install method. |
41+
| **Oh-My-Zsh GitHub CDN** (`raw.githubusercontent.com`) | Mitigated — SHA256 pinned | The OMZ install script is downloaded and its SHA256 is verified against a pinned constant (`knownOMZInstallHash` in `internal/shell/shell.go`) before execution. Execution is refused on mismatch. |
4242
| **Homebrew** | High | Homebrew is treated as a trusted package manager. Package integrity is managed by Homebrew's own SHA-256 verification. OpenBoot only passes package names to `brew install`. |
4343
| **npm registry** | Medium | npm packages are installed by name with no additional pinning beyond whatever `npm` itself enforces (no lockfile context at install time). |
4444
| **Dotfiles repository** | Untrusted until user confirms | Cloned from a URL supplied by the config or the user. The URL is validated to use HTTPS. Content of the cloned repo is not scanned. |
45-
| **GitHub Releases** (auto-update) | High, no hash verification | Binary downloads come from `github.com/openbootdotdev/openboot/releases`. No checksum is verified after download. The binary is written over the current executable. |
45+
| **GitHub Releases** (auto-update) | High — checksums verified | Binary downloads come from `github.com/openbootdotdev/openboot/releases`. The release checksums file is fetched first and the downloaded binary is verified against it before the running executable is replaced (`internal/updater/updater.go`). |
4646

4747
---
4848

@@ -126,13 +126,13 @@ OpenBoot is a macOS CLI that automates developer environment setup. In a single
126126
- HTTPS is used. TLS certificate validation is performed by the system's `curl`.
127127
- This is the officially documented install method for Oh-My-Zsh. The project does not provide a signed release artifact.
128128

129-
**Accepted risk:** There is no hash pinning. A compromise of the GitHub repository, CDN, or a TLS MitM would not be detected. This is the same risk accepted by every other tool that uses the official OMZ installer. It is listed here for transparency, not because there is a viable alternative that the OMZ project provides.
129+
**Mitigated:** The downloaded script's SHA256 is verified against a pinned constant before execution (`knownOMZInstallHash` in `internal/shell/shell.go`). Execution is refused on mismatch. The pinned hash must be updated manually when the OMZ installer script changes upstream.
130130

131131
---
132132

133-
### T5 — Auto-Update Binary Replacement Without Hash Verification
133+
### T5 — Auto-Update Binary Replacement
134134

135-
**Description:** When not installed via Homebrew, `DownloadAndReplace` fetches the latest release binary from `github.com/openbootdotdev/openboot/releases/latest/download/openboot-darwin-<arch>` and atomically replaces the running executable. No checksum is verified after download.
135+
**Description:** When not installed via Homebrew, `DownloadAndReplace` fetches the latest release binary from `github.com/openbootdotdev/openboot/releases/latest/download/openboot-darwin-<arch>` and atomically replaces the running executable. The release checksums file is fetched first and verified before the replacement occurs.
136136

137137
**Likelihood:** Low (requires GitHub infrastructure compromise or TLS MitM).
138138

@@ -143,12 +143,13 @@ OpenBoot is a macOS CLI that automates developer environment setup. In a single
143143
- The download URL is hardcoded to `github.com`. It is not user-configurable.
144144
- HTTPS is used with system TLS.
145145
- The replacement is atomic (`os.Rename` from a `.tmp` file), so a failed download does not corrupt the existing binary.
146+
- The release checksums file is fetched from GitHub Releases and the downloaded binary is verified against it before replacement (`fetchChecksums` + `verifyChecksum` in `internal/updater/updater.go`).
146147
- Homebrew installs (the primary distribution channel) use `brew upgrade`, which verifies the formula's SHA-256 bottle checksum.
147148
- Auto-update can be disabled with `OPENBOOT_DISABLE_AUTOUPDATE=1` or by setting `~/.openboot/config.json` `autoupdate` to `"false"` or `"notify"`.
148149

149-
**Residual risk:** Direct binary installs (non-Homebrew) have no post-download integrity check. The `OPENBOOT_UPGRADING=1` guard prevents infinite re-exec loops but does not authenticate the downloaded binary.
150+
**Residual risk:** The checksums file itself is served from GitHub Releases over HTTPS; a full GitHub infrastructure compromise would allow an attacker to replace both the binary and the checksums. The `OPENBOOT_UPGRADING=1` guard prevents infinite re-exec loops.
150151

151-
**Recommendation:** Prefer Homebrew installation, which provides formula-level SHA-256 verification. If using direct binary install in a managed fleet, set `OPENBOOT_DISABLE_AUTOUPDATE=1` and control updates out-of-band.
152+
**Recommendation:** If using direct binary install in a managed fleet, set `OPENBOOT_DISABLE_AUTOUPDATE=1` and control updates out-of-band.
152153

153154
---
154155

internal/system/system.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,10 @@ func RunCommandOutput(name string, args ...string) (string, error) {
7272

7373
// knownBrewInstallHash is the SHA256 of the Homebrew install script pinned on
7474
// 2026-04-19 (Homebrew/install HEAD as of that date). Update this constant
75-
// whenever the installer script changes upstream.
76-
// TODO: update this hash each release by running:
75+
// whenever the installer script changes upstream by running:
7776
//
7877
// curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh | sha256sum
79-
const knownBrewInstallHash = "HOMEBREW_INSTALL_SHA256"
78+
const knownBrewInstallHash = "dfd5145fe2aa5956a600e35848765273f5798ce6def01bd08ecec088a1268d91"
8079

8180
// brewInstallURL is a var so tests can redirect it to a local httptest server.
8281
var brewInstallURL = "https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh"

0 commit comments

Comments
 (0)