Fetch bootstrap data uncached so manifest hash diffs always self-heal#2
Merged
Conversation
NetworkManager built requests with the default cache policy and the shared URLCache, so management.json could be served stale — from the device URL cache or a CDN edge that hadn't purged yet. ManifestManager.downloadIfNeeded then compared cached files against that stale expected hash, matched, and logged 'Already have valid file. Skipping re-download' — so an updated payload such as ProvisioningWatcher.sh kept running the old cached copy across BootstrapMate runs. Use a shared no-cache session (urlCache = nil, requestCachePolicy = reloadIgnoringLocalAndRemoteCacheData) for every fetch so the manifest, and thus each per-item hash comparison, always reflects origin truth and a changed hash self-heals on the next run.
There was a problem hiding this comment.
Pull request overview
This PR updates the core networking layer to bypass URL caching so that management.json and related bootstrap artifacts are fetched fresh on each run, preventing stale manifests from causing hash validation to incorrectly skip re-downloads.
Changes:
- Introduces a shared
URLSessionconfigured withurlCache = niland.reloadIgnoringLocalAndRemoteCacheData. - Updates
downloadDataanddownloadFileto use the no-cache session (and explicit per-request cache policy).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+15
to
+20
| /// Session that never serves cached responses. Bootstrap data must reflect ORIGIN | ||
| /// truth on every run: management.json drives the per-item hash check, so a stale | ||
| /// manifest (from the local URL cache or a CDN edge that hasn't purged yet) makes a | ||
| /// changed file — e.g. ProvisioningWatcher.sh — compare against a stale expected hash, | ||
| /// get judged "already valid", and never re-download. Disabling the URL cache and | ||
| /// ignoring local + remote caches makes the hash diff always self-heal. |
Comment on lines
28
to
+34
| public func downloadData( | ||
| from url: URL, | ||
| followRedirects: Bool, | ||
| authHeader: String?, | ||
| completion: @escaping @Sendable (Data?, Error?) -> Void | ||
| ) { | ||
| var request = URLRequest(url: url) | ||
| var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData) |
…fest # Conflicts: # Sources/core/Managers/NetworkManager.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A re-run of BootstrapMate on an already-provisioned Mac kept executing an old cached
ProvisioningWatcher.sheven though management.json had been updated with a new hash for it. The log showed:Root cause
NetworkManagerbuilds every request withURLRequest(url:)(default.useProtocolCachePolicy) on aURLSession(configuration: .default)that uses the sharedURLCache. So management.json itself can be served stale — from the device's URL cache or a CDN edge that hasn't purged yet.ManifestManager.downloadIfNeededis correct in isolation — it compares the on-disk file's SHA-256 toitem.hashfrom the manifest — but if the manifest is stale,expectedHashis stale, so the old cached payload matches and re-download is skipped. The hash check can only self-heal if the manifest it trusts is fresh.Fix
Route all fetches through a shared no-cache session:
Now management.json (and every pkg/script) reflects origin truth on each run, so a changed hash always triggers a re-download — the hash diff self-heals without waiting on CDN purge propagation. Bootstrap runs are infrequent, so bypassing caches has negligible cost.
Test
swift buildsucceeds; change is isolated toManagers/NetworkManager.swift.