diff --git a/Sources/core/Managers/NetworkManager.swift b/Sources/core/Managers/NetworkManager.swift index ea54b0e..de361f4 100644 --- a/Sources/core/Managers/NetworkManager.swift +++ b/Sources/core/Managers/NetworkManager.swift @@ -12,18 +12,30 @@ public final class NetworkManager { private init() {} + /// 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. + private static let noCacheSession: URLSession = { + let config = URLSessionConfiguration.default + config.urlCache = nil + config.requestCachePolicy = .reloadIgnoringLocalAndRemoteCacheData + return URLSession(configuration: config) + }() + 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) if let header = authHeader { request.addValue(header, forHTTPHeaderField: "Authorization") } - let session = URLSession(configuration: .default) - session.dataTask(with: request) { data, _, error in + Self.noCacheSession.dataTask(with: request) { data, _, error in completion(data, error) }.resume() } @@ -39,16 +51,16 @@ public final class NetworkManager { completion(.failure(DownloadError.invalidURL)) return } - var request = URLRequest(url: url) + var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData) if let header = authHeader ?? authorizationHeader { request.addValue(header, forHTTPHeaderField: "Authorization") } - let session = URLSession(configuration: .default) - - // Use dataTask instead of downloadTask to avoid system temp directory - // which is read-only during Setup Assistant - let task = session.dataTask(with: request) { data, _, error in + // Use dataTask instead of downloadTask to avoid the system temp directory, + // which is read-only during Setup Assistant. Route through the shared + // no-cache session so manifest and artifact bytes always reflect origin + // truth (a stale cached payload would defeat the per-item hash check). + let task = Self.noCacheSession.dataTask(with: request) { data, _, error in if let error = error { completion(.failure(error)) return