T-iOS-18 (F-iOS-1..13 walkthrough) + T-iOS-19 (security audit vs built artifacts): both PASS_WITH_FINDINGS, 0 CRITICAL/HIGH; real-device items DEFERRED with manual checklists. Fixes (1 MED + 3 LOW, all closed): - WebTermUITests: the single scripted happy path (manual-entry pair → list → attach → KeyBar ^L → injected held gate via POST /hook/permission → tap Approve → server-side behavior==allow assertion). Green twice locally (fresh + already-paired branches). - ios.yml: ui-test leg (server boot + TEST_RUNNER_ env as PROCESS env) + iOS17-floor leg (loud-skip if runtime absent, hard-fail if present and red); dropped CODE_SIGNING_ALLOWED=NO from app-tests leg (unsigned hosts get -34018 from the real keychain — measured) - URLSessionHTTPTransport defaults to .ephemeral (no disk cache of preview terminal bytes) - TARGETED_DEVICE_FAMILY moved to target level (built plist now UIDeviceFamily [1] only) Final: 306 automated checks green (214 pkg + 76 app + 10 integration + XCUITest); server src/ untouched; P0 complete (19/19 tasks)
32 lines
1.5 KiB
Swift
32 lines
1.5 KiB
Swift
import Foundation
|
|
import WireProtocol
|
|
|
|
/// T-iOS-15 · Production `HTTPTransport` (the WireProtocol seam's doc reserves
|
|
/// the URLSession wrapper for the production side; no package owns it, so the
|
|
/// assembly layer provides it). Deliberately logic-free: `APIClient` builds
|
|
/// every request — including the Origin-iff-G rule (plan §3.4 铁律) — and this
|
|
/// type only performs the exchange. Adding ANY header/URL logic here would
|
|
/// bypass that single audited point (review CRITICAL).
|
|
struct URLSessionHTTPTransport: HTTPTransport {
|
|
private let session: URLSession
|
|
|
|
/// Default is EPHEMERAL, not `.shared` (T-iOS-19 finding): RO GET bodies
|
|
/// include `/live-sessions/:id/preview` — raw terminal ring-buffer bytes
|
|
/// that may contain printed secrets — and `.shared`'s default URLCache
|
|
/// writes responses to disk. Ephemeral keeps them memory-only, matching
|
|
/// the WS transport and the privacy-shade posture.
|
|
init(session: URLSession = URLSession(configuration: .ephemeral)) {
|
|
self.session = session
|
|
}
|
|
|
|
func send(_ request: URLRequest) async throws -> (Data, HTTPURLResponse) {
|
|
let (data, response) = try await session.data(for: request)
|
|
guard let httpResponse = response as? HTTPURLResponse else {
|
|
// http(s)-only endpoints (HostEndpoint validates) always produce
|
|
// an HTTPURLResponse; anything else is a transport-level anomaly.
|
|
throw URLError(.badServerResponse)
|
|
}
|
|
return (data, httpResponse)
|
|
}
|
|
}
|