Skip to content

Fix and harden Windows tentacle upgrade download path#420

Merged
ppXD merged 3 commits into
mainfrom
fix-windows-tentacle-download-webclient
Jun 4, 2026
Merged

Fix and harden Windows tentacle upgrade download path#420
ppXD merged 3 commits into
mainfrom
fix-windows-tentacle-download-webclient

Conversation

@ppXD

@ppXD ppXD commented Jun 4, 2026

Copy link
Copy Markdown
Collaborator

Summary

Make the Windows tentacle self-upgrade work, and work reliably across Windows versions and environments.

Correctness fix (the field report: upgrade to 1.8.13 failed with "End of central directory record could not be found", exit 14):

  • Invoke-WebRequest -OutFile corrupted the large binary download on PS 5.1 → extraction failed. Switch to System.Net.WebClient.DownloadFile + forced TLS 1.2.
  • The .sha256 companion (served by GitHub as application/octet-stream) was fetched with Invoke-WebRequest, which returns .Content as a byte[] for octet-stream → the hex split failed → SHA verification was silently skipped, letting the corrupt download through. Switch to WebClient.DownloadString (always a string) + log an ASCII snippet of any malformed companion.
  • Extract via [System.IO.Compression.ZipFile]::ExtractToDirectory instead of Expand-Archive.
  • Script is now pure ASCII so PS 5.1 + the web log don't mojibake under non-Latin OEM codepages.

Reliability hardening (raise success rate toward 100%):

  • Retry the download with backoff (3 attempts, env-tunable SQUID_UPGRADE_DOWNLOAD_RETRIES) — survives transient TCP reset / CDN 503 / proxy blips.
  • Route through the configured proxy with default credentials — authenticated corporate proxies (407) no longer block it.
  • Reject a 0-byte / truncated download with a clear message instead of an opaque extraction error.
  • Retry extraction + binary swap — Defender briefly locking a freshly-written file no longer fails the upgrade.

Same fix + hardening applied to install-tentacle.ps1.

Test plan

  • 705 upgrade unit tests + resource/strategy/parity drift detectors green (macOS)
  • Cross-platform drift detectors: WebClient+TLS12 download, ZipFile extraction, pure-ASCII script, retry/proxy/size hardening
  • Octet-stream SHA regression test — reproduces the real cause; fails the old Invoke-WebRequest code
  • Behavioural download-retry E2E — LocalReleaseMirror.FailNextArchiveRequests(1) injects a 503; the real .ps1 retries and the upgrade still succeeds
  • Windows E2E green on a real Windows runner (run 26962192825, 10m): production .ps1 end-to-end — WebClient download → SHA → ZipFile extract → swap → restart → last-upgrade.json
  • Windows E2E matrix (windows-2019 + windows-2022) — re-dispatched on this branch with the hardening + retry test
  • Manual confirmation on the reporting operator's box (already verified WebClient returns the byte-exact archive: size + SHA match)

ppXD added 2 commits June 4, 2026 23:35
Windows PowerShell 5.1's Invoke-WebRequest broke the self-upgrade two ways:

- `-OutFile` corrupted the large binary download, so extraction failed with
  "End of central directory record could not be found" (exit 14).
- For the .sha256 companion (served by GitHub as application/octet-stream),
  Invoke-WebRequest returns .Content as a byte[], so the hex split produced
  garbage, the 64-hex regex failed, and SHA verification was silently skipped
  — letting the corrupt download through unchecked.

Switch both the upgrade and install scripts to System.Net.WebClient
(DownloadFile / DownloadString) with forced TLS 1.2, and extract via
[System.IO.Compression.ZipFile]::ExtractToDirectory instead of Expand-Archive.
Make the whole upgrade script pure ASCII so PS 5.1 and the web log don't
mojibake it under non-Latin OEM codepages, and log an ASCII snippet of any
malformed SHA companion so operators can diagnose from the web log.

Add cross-platform drift detectors pinning the WebClient/TLS12/ZipFile/ASCII
shape and an octet-stream SHA regression test that reproduces the real cause,
and reconcile stale test pins that were validating the old Invoke-WebRequest
shape.
Raise upgrade success rate toward 100% by surviving the transient Windows
failures that cause most field upgrade failures:

- Retry the archive download with linear backoff (3 attempts, env-tunable via
  SQUID_UPGRADE_DOWNLOAD_RETRIES) so a single TCP reset / CDN 503 / proxy blip
  doesn't fail the whole upgrade.
- Route the download through the machine's configured proxy with default
  credentials so authenticated corporate proxies (407) don't block it.
- Reject a 0-byte / truncated download with a clear message instead of an
  opaque "central directory" error at extraction time.
- Retry extraction and the binary swap so Defender briefly locking a
  freshly-written file doesn't fail the upgrade.

The same hardening is applied to install-tentacle.ps1.

Add a behavioural E2E proving the download-retry recovers from a transient 503
(LocalReleaseMirror.FailNextArchiveRequests), cross-platform drift detectors
pinning the retry / proxy / size measures, and a windows-2019 + windows-2022
matrix on the Windows E2E workflow to prove the upgrade across Windows versions.
@ppXD ppXD changed the title Fix Windows tentacle upgrade download corruption and SHA skip Fix and harden Windows tentacle upgrade download path Jun 4, 2026
The size floor (< 1024 bytes) rejected the install E2E fixtures' tiny test
archives (~143 bytes), failing 11 Windows install tests. Validate the PK magic
bytes (0x50 0x4B) instead: a valid zip of any size passes, and HTML error pages
/ truncated downloads are still rejected -- more robustly than a size floor,
which would also miss large error pages.

Also swap the E2E matrix off the retired windows-2019 runner label (which
queues forever with no available runner) to windows-2025.
@ppXD
ppXD merged commit fd7be7e into main Jun 4, 2026
17 of 18 checks passed
@ppXD
ppXD deleted the fix-windows-tentacle-download-webclient branch June 4, 2026 23:30
@ppXD ppXD added this to the 1.8.14 milestone Jun 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant