Commit 1e443ae
authored
chore(install): verify downloaded tarball integrity + enforce HTTPS (#1221)
* chore(install): verify downloaded tarball integrity + enforce HTTPS
Tightens install.sh so the downloaded tarball is checked against the
integrity value the npm registry publishes for that specific version.
Changes:
* Consolidated curl/wget into `fetch_url` and `fetch_url_to_file`
helpers that pass `--proto =https --tlsv1.2` (curl) or `--https-only`
(wget) so we don't silently follow an http redirect.
* After download, compute the SSRI-style hash (e.g. `sha512-<base64>`)
of the tarball and compare to the value returned by
`GET /<pkg>/<version>`. Mismatch aborts before extraction.
* Download the tarball into a `mktemp` file outside the install dir
so a failed verification can't leave a partial blob where a later
run might trust it; an `EXIT` trap cleans up.
Behavior for users on a successful install is unchanged.
* fix(install): harden integrity parsing and drop xxd dependency
Two follow-up fixes flagged by Cursor bugbot on #1221:
1. `get_published_integrity` pipeline tripped `set -e` under `pipefail`
when npm metadata was truncated/malformed. Extract the body first,
then parse via a `parse_json_string` helper that tolerates a
missing field (returns empty). The caller's "refusing to install
without a published checksum" message now fires with context
instead of the script exiting silently.
2. `compute_integrity` relied on `xxd -r -p` in the `shasum` fallback
branch to convert hex to binary. `xxd` isn't POSIX — it ships with
vim-common and is often absent on minimal/Alpine containers. With
`set -e` the missing binary killed the script before the friendly
else-branch error could print.
Replaced the fallback stack with a single openssl-only path.
openssl is ubiquitous (macOS, mainstream Linux, default Alpine
image, WSL, Git Bash); requiring it removes the portability bug
and simplifies the function. If openssl is genuinely missing the
script now prints a platform-specific install hint.
Verified locally:
* happy path (real install) still passes
* simulated missing-integrity response prints the helpful message
* tampered-download still fails with expected vs got mismatch
* fix(install): close wget HTTPS-downgrade gap with --max-redirect=0
Cursor bugbot flagged that wget's `--https-only` only applies to
recursive downloads — for the single-file fetches in this script it's
effectively a no-op, so a MITM could theoretically redirect us to an
http:// mirror. curl's `--proto '=https'` closed this correctly; wget
had a gap.
Swap `--https-only` for `--max-redirect=0` on both wget calls. npm's
registry serves metadata and tarballs directly with no redirect (verified
with `curl -sI`), so this is safe for the happy path and hard-blocks
any attempt to downgrade to http via redirect.
Side benefit: the two metadata fetches (version + integrity) also got
this protection. Previously the tarball was covered by the integrity
check that follows, but a MITM on the metadata call could have fed us
a fake version + matching fake integrity value. Now that vector is
closed too.1 parent 00ef6f4 commit 1e443ae
1 file changed
+122
-18
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
115 | 115 | | |
116 | 116 | | |
117 | 117 | | |
118 | | - | |
119 | | - | |
120 | | - | |
121 | | - | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
122 | 127 | | |
123 | | - | |
124 | 128 | | |
125 | | - | |
126 | | - | |
| 129 | + | |
127 | 130 | | |
128 | | - | |
| 131 | + | |
129 | 132 | | |
130 | 133 | | |
131 | 134 | | |
| |||
135 | 138 | | |
136 | 139 | | |
137 | 140 | | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
138 | 179 | | |
139 | 180 | | |
140 | 181 | | |
| |||
147 | 188 | | |
148 | 189 | | |
149 | 190 | | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
150 | 226 | | |
151 | 227 | | |
152 | 228 | | |
| |||
201 | 277 | | |
202 | 278 | | |
203 | 279 | | |
204 | | - | |
205 | | - | |
206 | | - | |
207 | | - | |
208 | | - | |
209 | | - | |
210 | | - | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
211 | 288 | | |
212 | 289 | | |
213 | | - | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
214 | 317 | | |
215 | 318 | | |
216 | 319 | | |
| |||
250 | 353 | | |
251 | 354 | | |
252 | 355 | | |
253 | | - | |
254 | | - | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
255 | 359 | | |
256 | 360 | | |
257 | 361 | | |
| |||
0 commit comments