From ab35023580ab8488c8df141fd6d8139d546be062 Mon Sep 17 00:00:00 2001 From: Jonathan Jackson Date: Thu, 19 Dec 2024 16:27:02 -0500 Subject: [PATCH] CRCID Support when reporting crashes (#3653) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task/Issue URL: https://app.asana.com/0/1208592102886666/1208759541597499/f Tech Design URL: https://app.asana.com/0/1208592102886666/1208660326715650/f **Description**: DO NOT MERGE - this is a draft for input, not ready to go live yet. MacOS support for crash report cohort IDs (CRCIDs) when sending crash reports. **Optional E2E tests**: - [ ] Run PIR E2E tests Check this to run the Personal Information Removal end to end tests. If updating CCF, or any PIR related code, tick this. **Steps to test this PR**: To cause and report a crash: 1. Launch the app and force a crash, which can be done from Debug (menu) → Simulate Crash → fatalError (or similar). 2. Launch the app again (easiest with a debugger) 3. You will be prompted to submit the crash. When submitting, watch logs for “crcid” and “crash” and you should see output from these changes confirming a CRCID is received and updated. 4. Repeat steps 2-3 again, and you should see that the CRCID received initially is what’s submitted with the next crash. --- DuckDuckGo.xcodeproj/project.pbxproj | 16 ++++++- .../xcshareddata/swiftpm/Package.resolved | 4 +- DuckDuckGo/Application/AppDelegate.swift | 3 +- .../Model/CrashReportSenderExtensions.swift | 43 +++++++++++++++++++ .../CrashReports/Model/CrashReporter.swift | 7 ++- DuckDuckGo/Statistics/GeneralPixel.swift | 8 ++++ .../DataBrokerProtection/Package.swift | 2 +- LocalPackages/FeatureFlags/Package.swift | 2 +- .../NetworkProtectionMac/Package.swift | 2 +- LocalPackages/NewTabPage/Package.swift | 2 +- LocalPackages/SubscriptionUI/Package.swift | 2 +- LocalPackages/WebKitExtensions/Package.swift | 2 +- 12 files changed, 81 insertions(+), 12 deletions(-) create mode 100644 DuckDuckGo/CrashReports/Model/CrashReportSenderExtensions.swift diff --git a/DuckDuckGo.xcodeproj/project.pbxproj b/DuckDuckGo.xcodeproj/project.pbxproj index 50887e402a..12f63ecaf6 100644 --- a/DuckDuckGo.xcodeproj/project.pbxproj +++ b/DuckDuckGo.xcodeproj/project.pbxproj @@ -1319,6 +1319,9 @@ 37FC2A192CF903080048E226 /* MockPrivacyStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FC2A172CF903060048E226 /* MockPrivacyStats.swift */; }; 37FD78112A29EBD100B36DB1 /* SyncErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FD78102A29EBD100B36DB1 /* SyncErrorHandler.swift */; }; 37FD78122A29EBD100B36DB1 /* SyncErrorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 37FD78102A29EBD100B36DB1 /* SyncErrorHandler.swift */; }; + 46066CBC2D1330A100AB683B /* Persistence in Frameworks */ = {isa = PBXBuildFile; productRef = 46066CBB2D1330A100AB683B /* Persistence */; }; + 467D16672D0C98D5007C020A /* CrashReportSenderExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 467D16662D0C98D5007C020A /* CrashReportSenderExtensions.swift */; }; + 467D16682D0C98D5007C020A /* CrashReportSenderExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 467D16662D0C98D5007C020A /* CrashReportSenderExtensions.swift */; }; 4B0135CE2729F1AA00D54834 /* NSPasteboardExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0135CD2729F1AA00D54834 /* NSPasteboardExtension.swift */; }; 4B02198925E05FAC00ED7DEA /* FireproofingURLExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B02197F25E05FAC00ED7DEA /* FireproofingURLExtensions.swift */; }; 4B02198A25E05FAC00ED7DEA /* FireproofDomains.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B02198125E05FAC00ED7DEA /* FireproofDomains.swift */; }; @@ -3796,6 +3799,7 @@ 37F8ABD22CE3EE5B00CB0294 /* FeatureFlagOverridesMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlagOverridesMenu.swift; sourceTree = ""; }; 37FC2A172CF903060048E226 /* MockPrivacyStats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPrivacyStats.swift; sourceTree = ""; }; 37FD78102A29EBD100B36DB1 /* SyncErrorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncErrorHandler.swift; sourceTree = ""; }; + 467D16662D0C98D5007C020A /* CrashReportSenderExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CrashReportSenderExtensions.swift; sourceTree = ""; }; 4B0135CD2729F1AA00D54834 /* NSPasteboardExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSPasteboardExtension.swift; sourceTree = ""; }; 4B02197F25E05FAC00ED7DEA /* FireproofingURLExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FireproofingURLExtensions.swift; sourceTree = ""; }; 4B02198125E05FAC00ED7DEA /* FireproofDomains.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FireproofDomains.swift; sourceTree = ""; }; @@ -5345,6 +5349,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 46066CBC2D1330A100AB683B /* Persistence in Frameworks */, B6DA44172616C13800DD1EC2 /* OHHTTPStubs in Frameworks */, F116A7C32BD1924B00F3FCF7 /* PixelKitTestingUtilities in Frameworks */, 84BBC8012CFA0D3800BAE57A /* TestUtils in Frameworks */, @@ -8639,6 +8644,7 @@ AAC30A27268E045400D2D9CD /* CrashReportReader.swift */, AAC30A2D268F1EE300D2D9CD /* CrashReportPromptPresenter.swift */, AAC30A29268E239100D2D9CD /* CrashReport.swift */, + 467D16662D0C98D5007C020A /* CrashReportSenderExtensions.swift */, ); path = Model; sourceTree = ""; @@ -10497,6 +10503,7 @@ 9DC5FACA2C6B8E050011F068 /* AppKitExtensions */, 84BBC8002CFA0D3800BAE57A /* TestUtils */, 374EFDEE2D01C70300B30939 /* Utilities */, + 46066CBB2D1330A100AB683B /* Persistence */, ); productName = DuckDuckGoTests; productReference = AA585D90248FD31400E9A3E2 /* Unit Tests.xctest */; @@ -11571,6 +11578,7 @@ 37197EA82942443D00394917 /* BrowserTabViewController.swift in Sources */, 3706FB39293F65D500E42796 /* PrivacyDashboardPopover.swift in Sources */, 3706FB3B293F65D500E42796 /* RootView.swift in Sources */, + 467D16672D0C98D5007C020A /* CrashReportSenderExtensions.swift in Sources */, 3706FB3C293F65D500E42796 /* AddressBarTextField.swift in Sources */, 3706FB3D293F65D500E42796 /* FocusRingView.swift in Sources */, 3706FB3E293F65D500E42796 /* BookmarksBarViewModel.swift in Sources */, @@ -13085,6 +13093,7 @@ AABEE6A524AA0A7F0043105B /* SuggestionViewController.swift in Sources */, 1D6216B229069BBF00386B2C /* BWKeyStorage.swift in Sources */, AA7E919F287872EA00AB6B62 /* VisitViewModel.swift in Sources */, + 467D16682D0C98D5007C020A /* CrashReportSenderExtensions.swift in Sources */, 7BD7B0012C19D3830039D20A /* VPNIPCResources.swift in Sources */, C1935A1B2C88F9ED001AD72D /* SyncPromoViewModel.swift in Sources */, B6676BE12AA986A700525A21 /* AddressBarTextEditor.swift in Sources */, @@ -15297,7 +15306,7 @@ repositoryURL = "https://github.com/duckduckgo/BrowserServicesKit"; requirement = { kind = exactVersion; - version = 221.3.0; + version = 222.1.0; }; }; 9FF521422BAA8FF300B9819B /* XCRemoteSwiftPackageReference "lottie-spm" */ = { @@ -15700,6 +15709,11 @@ package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; productName = Navigation; }; + 46066CBB2D1330A100AB683B /* Persistence */ = { + isa = XCSwiftPackageProductDependency; + package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; + productName = Persistence; + }; 4B2D062B2A11C0E100DE1F49 /* Networking */ = { isa = XCSwiftPackageProductDependency; package = 9807F643278CA16F00E1547B /* XCRemoteSwiftPackageReference "BrowserServicesKit" */; diff --git a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index f38fb5f4a6..602e95e476 100644 --- a/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/DuckDuckGo.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -32,8 +32,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/duckduckgo/BrowserServicesKit", "state" : { - "revision" : "b71ed70ce9b0ef3ce51d4f96da0193ab70493944", - "version" : "221.3.0" + "revision" : "5704d77e3b4c77c7387518d796d31a35f7a1ffcf", + "version" : "222.1.0" } }, { diff --git a/DuckDuckGo/Application/AppDelegate.swift b/DuckDuckGo/Application/AppDelegate.swift index 1b0788355b..3aa256fb0f 100644 --- a/DuckDuckGo/Application/AppDelegate.swift +++ b/DuckDuckGo/Application/AppDelegate.swift @@ -71,7 +71,8 @@ final class AppDelegate: NSObject, NSApplicationDelegate { let fileStore: FileStore #if APPSTORE - private let crashCollection = CrashCollection(platform: .macOSAppStore) + private let crashCollection = CrashCollection(crashReportSender: CrashReportSender(platform: .macOSAppStore, + pixelEvents: CrashReportSender.pixelEvents)) #else private let crashReporter = CrashReporter() #endif diff --git a/DuckDuckGo/CrashReports/Model/CrashReportSenderExtensions.swift b/DuckDuckGo/CrashReports/Model/CrashReportSenderExtensions.swift new file mode 100644 index 0000000000..85618d2d99 --- /dev/null +++ b/DuckDuckGo/CrashReports/Model/CrashReportSenderExtensions.swift @@ -0,0 +1,43 @@ +// +// CrashReportSenderExtensions.swift +// +// Copyright © 2024 DuckDuckGo. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Crashes +import Common +import PixelKit + +extension CrashReportSender { + + static let pixelEvents: EventMapping = .init { event, _, _, _ in + switch event { + case CrashReportSenderError.crcidMissing: + PixelKit.fire(GeneralPixel.crashReportCRCIDMissing) + + case CrashReportSenderError.submissionFailed(let error): + if let error { + PixelKit.fire(DebugEvent(GeneralPixel.crashReportingSubmissionFailed), + frequency: .standard, + withHeaders: [:], + withAdditionalParameters: ["HTTPStatusCode": "\(error.statusCode)"], + withError: nil, + allowedQueryReservedCharacters: nil) + } else { + PixelKit.fire(GeneralPixel.crashReportingSubmissionFailed) + } + } + } +} diff --git a/DuckDuckGo/CrashReports/Model/CrashReporter.swift b/DuckDuckGo/CrashReports/Model/CrashReporter.swift index b3456a3adb..4883679907 100644 --- a/DuckDuckGo/CrashReports/Model/CrashReporter.swift +++ b/DuckDuckGo/CrashReports/Model/CrashReporter.swift @@ -24,7 +24,8 @@ import PixelKit final class CrashReporter { private let reader = CrashReportReader() - private lazy var sender = CrashReportSender(platform: .macOS) + private lazy var sender = CrashReportSender(platform: .macOS, pixelEvents: CrashReportSender.pixelEvents) + private lazy var crcidManager = CRCIDManager() private lazy var promptPresenter = CrashReportPromptPresenter() @UserDefaultsWrapper(key: .lastCrashReportCheckDate, defaultValue: nil) @@ -56,7 +57,9 @@ final class CrashReporter { return } Task { - await self.sender.send(contentData) + let crcid = self.crcidManager.crcid + let result = await self.sender.send(contentData, crcid: crcid) + self.crcidManager.handleCrashSenderResult(result: result.result, response: result.response) } } diff --git a/DuckDuckGo/Statistics/GeneralPixel.swift b/DuckDuckGo/Statistics/GeneralPixel.swift index 2a92aa9845..0c24d26481 100644 --- a/DuckDuckGo/Statistics/GeneralPixel.swift +++ b/DuckDuckGo/Statistics/GeneralPixel.swift @@ -26,6 +26,8 @@ enum GeneralPixel: PixelKitEventV2 { case crash case crashOnCrashHandlersSetUp + case crashReportingSubmissionFailed + case crashReportCRCIDMissing case compileRulesWait(onboardingShown: OnboardingShown, waitTime: CompileRulesWaitTime, result: WaitResult) case launchInitial(cohort: String) case launch(isDefault: Bool) @@ -473,6 +475,12 @@ enum GeneralPixel: PixelKitEventV2 { case .crashOnCrashHandlersSetUp: return "m_mac_crash_on_handlers_setup" + case .crashReportCRCIDMissing: + return "m_mac_crashreporting_crcid-missing" + + case .crashReportingSubmissionFailed: + return "m_mac_crashreporting_submission-failed" + case .compileRulesWait(onboardingShown: let onboardingShown, waitTime: let waitTime, result: let result): return "m_mac_cbr-wait_\(onboardingShown)_\(waitTime)_\(result)" diff --git a/LocalPackages/DataBrokerProtection/Package.swift b/LocalPackages/DataBrokerProtection/Package.swift index 79e021c472..2cb2248e15 100644 --- a/LocalPackages/DataBrokerProtection/Package.swift +++ b/LocalPackages/DataBrokerProtection/Package.swift @@ -29,7 +29,7 @@ let package = Package( targets: ["DataBrokerProtection"]) ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "221.3.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "222.1.0"), .package(path: "../SwiftUIExtensions"), .package(path: "../AppKitExtensions"), .package(path: "../XPCHelper"), diff --git a/LocalPackages/FeatureFlags/Package.swift b/LocalPackages/FeatureFlags/Package.swift index dcb3d9194f..c552f688dd 100644 --- a/LocalPackages/FeatureFlags/Package.swift +++ b/LocalPackages/FeatureFlags/Package.swift @@ -32,7 +32,7 @@ let package = Package( targets: ["FeatureFlags"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "221.3.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "222.1.0"), ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. diff --git a/LocalPackages/NetworkProtectionMac/Package.swift b/LocalPackages/NetworkProtectionMac/Package.swift index 3431d62c5a..ba1c4334a4 100644 --- a/LocalPackages/NetworkProtectionMac/Package.swift +++ b/LocalPackages/NetworkProtectionMac/Package.swift @@ -33,7 +33,7 @@ let package = Package( .library(name: "VPNAppLauncher", targets: ["VPNAppLauncher"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "221.3.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "222.1.0"), .package(url: "https://github.com/airbnb/lottie-spm", exact: "4.4.3"), .package(path: "../AppLauncher"), .package(path: "../UDSHelper"), diff --git a/LocalPackages/NewTabPage/Package.swift b/LocalPackages/NewTabPage/Package.swift index 46ba37e00c..f062a29127 100644 --- a/LocalPackages/NewTabPage/Package.swift +++ b/LocalPackages/NewTabPage/Package.swift @@ -32,7 +32,7 @@ let package = Package( targets: ["NewTabPage"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "221.3.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "222.1.0"), .package(path: "../WebKitExtensions"), .package(path: "../Utilities"), ], diff --git a/LocalPackages/SubscriptionUI/Package.swift b/LocalPackages/SubscriptionUI/Package.swift index 40bb88836f..1b4ee7bdce 100644 --- a/LocalPackages/SubscriptionUI/Package.swift +++ b/LocalPackages/SubscriptionUI/Package.swift @@ -13,7 +13,7 @@ let package = Package( targets: ["SubscriptionUI"]), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "221.3.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "222.1.0"), .package(path: "../SwiftUIExtensions"), .package(path: "../FeatureFlags") ], diff --git a/LocalPackages/WebKitExtensions/Package.swift b/LocalPackages/WebKitExtensions/Package.swift index 44e660355b..00965ec758 100644 --- a/LocalPackages/WebKitExtensions/Package.swift +++ b/LocalPackages/WebKitExtensions/Package.swift @@ -32,7 +32,7 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "221.3.0"), + .package(url: "https://github.com/duckduckgo/BrowserServicesKit", exact: "222.1.0"), .package(path: "../AppKitExtensions") ], targets: [