From 61827e9a4df536ccb36e380f2f5110f8a93229d1 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 26 May 2026 01:47:47 +0000 Subject: [PATCH 1/2] Redact /pair API key from Insights log ring buffer When a pairing request is approved, /pair mints a master-scoped osk-v1 API key (agentIndex: nil, expiration: .never for permanent pairings) and returns it once to the connector. That secret was also being stored verbatim in the Insights log ring buffer via logRequest's responseBody field. Insights logs are kept in memory and rendered in the app UI, so any of the following leaked the full credential: * a screen recording or shoulder-surf while the Insights tab is open * a memory dump or crash report * a future support-bundle/log-export feature * the existing in-app InsightsView search box Replace the apiKey field with a clearly-marked placeholder ('osk-v1-***REDACTED***') in the logged copy of the response only. The wire body returned to the legitimate paired connector is unchanged, so end-to-end pairing flow keeps working exactly as before; this commit only stops the secret from being saved into the diagnostic ring buffer that the user can browse after the fact. Co-authored-by: Michael Meding --- .../OsaurusCore/Networking/HTTPHandler.swift | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/Packages/OsaurusCore/Networking/HTTPHandler.swift b/Packages/OsaurusCore/Networking/HTTPHandler.swift index 0f88775490..147f16f5d4 100644 --- a/Packages/OsaurusCore/Networking/HTTPHandler.swift +++ b/Packages/OsaurusCore/Networking/HTTPHandler.swift @@ -1514,6 +1514,11 @@ final class HTTPHandler: ChannelInboundHandler, Sendable { let isPermanent: Bool } + /// Placeholder written to the Insights log in place of a freshly-minted + /// API key. Surfaces clearly in the UI so operators know a redaction + /// happened, while being inert as a credential. + fileprivate static let redactedAPIKeyPlaceholder = "osk-v1-***REDACTED***" + /// POST /pair — unauthenticated endpoint for cryptographic Bonjour pairing. private func handlePairEndpoint( head: HTTPRequestHead, @@ -1708,6 +1713,20 @@ final class HTTPHandler: ChannelInboundHandler, Sendable { (try? JSONEncoder().encode(response)).map { String(decoding: $0, as: UTF8.self) } ?? #"{"error":"Encoding failed"}"# + // Build a redacted copy for Insights: the full osk-v1 key is a + // bearer secret that grants master-scoped API access. It must + // never sit in the in-app log ring buffer, where it could leak + // via screen recordings, support-bundle exports, or memory + // dumps. The wire response is unchanged. + let redactedResponse = PairResponse( + agentAddress: agentAddress, + apiKey: Self.redactedAPIKeyPlaceholder, + isPermanent: isPermanent + ) + let redactedJson = + (try? JSONEncoder().encode(redactedResponse)).map { String(decoding: $0, as: UTF8.self) } + ?? #"{"redacted":true}"# + hop { var headers = [("Content-Type", "application/json; charset=utf-8")] headers.append(contentsOf: cors) @@ -1717,7 +1736,7 @@ final class HTTPHandler: ChannelInboundHandler, Sendable { path: "/pair", userAgent: logUserAgent, requestBody: logRequestBody, - responseBody: json, + responseBody: redactedJson, responseStatus: 200, startTime: logStartTime ) From 9c795b554b956441af3e4cab301697d86ada022e Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 27 May 2026 05:08:34 +0000 Subject: [PATCH 2/2] Fix flake: skip ModelManager launch-time HF fetch under xctest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ModelManager.init kicks off an unstructured Task that calls loadOsaurusAIOrgModels(), which fetches the OsaurusAI organization listing from Hugging Face and feeds the result through applyOsaurusOrgFetch. The unit-test runner repeatedly constructs ModelManager() to drive applyOsaurusOrgFetch directly. The background launch-time fetch races with those test calls — whichever finishes last wins, and the merge result is non-deterministic. That's the root cause of the flaky ModelManagerSuggestedTests failures seen across many of the recent PR CI runs (applyOsaurusOrgFetch_dropsStaleAutoFetched OnReapply, applyOsaurusOrgFetch_addsNewEntriesAfterCurated, etc.). Gate the launch-time fetch on a small isRunningInTestEnvironment helper that checks for any of XCTestConfigurationFilePath, XCTestBundlePath, or XCTestSessionIdentifier in the process environment. Those variables are only present inside an xctest host process; production app launches still get the HF fetch exactly as before. This is a network call, so removing it under tests also has the side benefit of making the test suite work offline / on hermetic CI runners. Co-authored-by: Michael Meding --- .../Managers/Model/ModelManager.swift | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/Packages/OsaurusCore/Managers/Model/ModelManager.swift b/Packages/OsaurusCore/Managers/Model/ModelManager.swift index c87d515f6f..dc65956958 100644 --- a/Packages/OsaurusCore/Managers/Model/ModelManager.swift +++ b/Packages/OsaurusCore/Managers/Model/ModelManager.swift @@ -188,7 +188,27 @@ final class ModelManager: NSObject, ObservableObject { // Pull the OsaurusAI HF org listing once on launch so newly published // models surface in the Recommended tab without requiring a code push. - Task { [weak self] in await self?.loadOsaurusAIOrgModels() } + // + // The unit-test runner constructs `ModelManager()` repeatedly to drive + // `applyOsaurusOrgFetch` directly. If the launch-time HF fetch races + // with those test calls, whichever finishes last wins and the merge + // result is non-deterministic — that's the regression class behind + // `ModelManagerSuggestedTests/applyOsaurusOrgFetch_*` flaking in CI. + // Skip the background fetch under XCTest; production launches still + // get it because `XCTestConfigurationFilePath` is only set inside + // a test host. + if !Self.isRunningInTestEnvironment { + Task { [weak self] in await self?.loadOsaurusAIOrgModels() } + } + } + + /// True when the current process was launched by xctest. Used to gate + /// network-touching launch-time side effects so tests can drive the + /// affected code paths deterministically. + nonisolated private static var isRunningInTestEnvironment: Bool { + ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] != nil + || ProcessInfo.processInfo.environment["XCTestBundlePath"] != nil + || ProcessInfo.processInfo.environment["XCTestSessionIdentifier"] != nil } // MARK: - Public Methods