diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d5d148e..dd554f2 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -15,11 +15,35 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Run unit tests + - name: Run unit tests with code coverage run: | xcodebuild test \ -project "PPPC Utility.xcodeproj" \ -scheme "PPPC Utility" \ -destination "platform=macOS" \ + -enableCodeCoverage YES \ + -resultBundlePath TestResults.xcresult \ CODE_SIGN_IDENTITY="-" \ CODE_SIGNING_REQUIRED=NO + + - name: Display code coverage summary + if: always() + run: | + if [ ! -d TestResults.xcresult ]; then + echo "Coverage bundle 'TestResults.xcresult' not found; skipping coverage summary." + exit 0 + fi + # Generate coverage report; capture output while still printing it + echo "Generating coverage report from TestResults.xcresult..." + if ! xcrun xccov view --report TestResults.xcresult | tee coverage-report.txt; then + echo "Failed to generate coverage report with xccov; printing any captured output and continuing." + cat coverage-report.txt 2>/dev/null || true + exit 0 + fi + echo + echo "Filtered coverage summary (matching app targets or PPPC-Utility/Source):" + if ! grep -E '^[A-Z].*\.app|PPPC-Utility/Source' coverage-report.txt; then + echo + echo "No matching coverage lines found; displaying full coverage report instead." + cat coverage-report.txt + fi diff --git a/CHANGELOG.md b/CHANGELOG.md index 81b4616..3819149 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Changed - Update print and os_log calls to the modern OSLog class calls for updated logging. ([Issue #112](https://github.com/jamf/PPPC-Utility/issues/112)) [@SkylerGodfrey](https://github.com/SkylerGodfrey) - Now using [Haversack](https://github.com/jamf/Haversack) for simplified access to the keychain ([Issue #124](https://github.com/jamf/PPPC-Utility/issues/124)) [@macblazer](https://github.com/macblazer). -- PPPC Utility now requires macOS 11+ to run. It can still produce profiles usable on older versions of macOS. +- PPPC Utility now requires macOS 13+ to run. It can still produce profiles usable on older versions of macOS. +- Removed Big Sur compatibility toggle and legacy `Allowed` key support. The `Authorization` key is now always used. ## [1.5.0] - 2022-10-04 diff --git a/PPPC Utility.xcodeproj/project.pbxproj b/PPPC Utility.xcodeproj/project.pbxproj index 660a02b..7161580 100644 --- a/PPPC Utility.xcodeproj/project.pbxproj +++ b/PPPC Utility.xcodeproj/project.pbxproj @@ -59,7 +59,6 @@ C0EE9A7D28639BF800738B6B /* TestTCCProfileForJamfProAPI.txt in Resources */ = {isa = PBXBuildFile; fileRef = C0EE9A7C28639BF800738B6B /* TestTCCProfileForJamfProAPI.txt */; }; C0EE9A7F2863BDE300738B6B /* JamfProAPITypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0EE9A7E2863BDE300738B6B /* JamfProAPITypes.swift */; }; C0EE9A812863BE2B00738B6B /* NetworkAuthManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0EE9A802863BE2B00738B6B /* NetworkAuthManager.swift */; }; - C0EE9A832863BEEB00738B6B /* URLSessionAsyncCompatibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0EE9A822863BEEB00738B6B /* URLSessionAsyncCompatibility.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -131,7 +130,6 @@ C0EE9A7C28639BF800738B6B /* TestTCCProfileForJamfProAPI.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TestTCCProfileForJamfProAPI.txt; sourceTree = ""; }; C0EE9A7E2863BDE300738B6B /* JamfProAPITypes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JamfProAPITypes.swift; sourceTree = ""; }; C0EE9A802863BE2B00738B6B /* NetworkAuthManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkAuthManager.swift; sourceTree = ""; }; - C0EE9A822863BEEB00738B6B /* URLSessionAsyncCompatibility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLSessionAsyncCompatibility.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -324,7 +322,6 @@ C03270BF28636397008B38E0 /* JamfProAPIClient.swift */, C0EE9A7E2863BDE300738B6B /* JamfProAPITypes.swift */, C05844B72AD4512D00141353 /* Token.swift */, - C0EE9A822863BEEB00738B6B /* URLSessionAsyncCompatibility.swift */, ); path = Networking; sourceTree = ""; @@ -535,7 +532,6 @@ 6E6216F9215321CE0043DF18 /* OpenViewController.swift in Sources */, C05844B82AD4512D00141353 /* Token.swift in Sources */, 6EC40A10214DE3B200BE4F17 /* Executable.swift in Sources */, - C0EE9A832863BEEB00738B6B /* URLSessionAsyncCompatibility.swift in Sources */, C0EE9A812863BE2B00738B6B /* NetworkAuthManager.swift in Sources */, 6EC40A16214ECF1E00BE4F17 /* SaveViewController.swift in Sources */, C05844BE2AD45F7900141353 /* UploadInfoView.swift in Sources */, @@ -667,7 +663,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IBSC_NOTICES = NO; - MACOSX_DEPLOYMENT_TARGET = 11.0; + MACOSX_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -723,7 +719,7 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; IBSC_NOTICES = NO; - MACOSX_DEPLOYMENT_TARGET = 11.0; + MACOSX_DEPLOYMENT_TARGET = 13.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = macosx; diff --git a/PPPC UtilityTests/ModelTests/ModelTests.swift b/PPPC UtilityTests/ModelTests/ModelTests.swift index a07cb54..85ea06e 100644 --- a/PPPC UtilityTests/ModelTests/ModelTests.swift +++ b/PPPC UtilityTests/ModelTests/ModelTests.swift @@ -130,7 +130,6 @@ class ModelTests: XCTestCase { func testExportProfileWithAppleEventsAndAuthorization() { // given - model.usingLegacyAllowKey = false let exe1 = Executable(identifier: "one", codeRequirement: "oneReq") let exe2 = Executable(identifier: "two", codeRequirement: "twoReq") @@ -185,65 +184,6 @@ class ModelTests: XCTestCase { } } - func testExportProfileWithAppleEventsAndLegacyAllowed() { - // given - let exe1 = Executable(identifier: "one", codeRequirement: "oneReq") - let exe2 = Executable(identifier: "two", codeRequirement: "twoReq") - - exe1.appleEvents = [AppleEventRule(source: exe1, destination: exe2, value: true)] - exe2.policy.SystemPolicyAllFiles = "Allow" - - model.selectedExecutables = [exe1, exe2] - model.usingLegacyAllowKey = true - - // when - let profile = model.exportProfile(organization: "Org", identifier: "ID", displayName: "Name", payloadDescription: "Desc") - - // then check top level settings - XCTAssertEqual("Org", profile.organization) - XCTAssertEqual("ID", profile.identifier) - XCTAssertEqual("Name", profile.displayName) - XCTAssertEqual("Desc", profile.payloadDescription) - XCTAssertEqual("System", profile.scope) - XCTAssertEqual("Configuration", profile.type) - XCTAssertNotNil(profile.uuid) - XCTAssertEqual(1, profile.version) - - // then check policy settings - // then verify the payload content top level - XCTAssertEqual(1, profile.content.count) - profile.content.forEach { content in - XCTAssertNotNil(content.uuid) - XCTAssertEqual(1, content.version) - - // then verify the services - XCTAssertEqual(2, content.services.count) - let appleEvents = content.services["AppleEvents"] - XCTAssertNotNil(appleEvents) - let appleEventsPolicy = appleEvents?.first - XCTAssertEqual("one", appleEventsPolicy?.identifier) - XCTAssertEqual("oneReq", appleEventsPolicy?.codeRequirement) - XCTAssertEqual("bundleID", appleEventsPolicy?.identifierType) - XCTAssertEqual("two", appleEventsPolicy?.receiverIdentifier) - XCTAssertEqual("twoReq", appleEventsPolicy?.receiverCodeRequirement) - XCTAssertEqual("bundleID", appleEventsPolicy?.receiverIdentifierType) - XCTAssertTrue(appleEventsPolicy?.allowed == true) - XCTAssertNil(appleEventsPolicy?.authorization) - - let allFiles = content.services["SystemPolicyAllFiles"] - XCTAssertNotNil(allFiles) - let allFilesPolicy = allFiles?.first - XCTAssertEqual("two", allFilesPolicy?.identifier) - XCTAssertEqual("twoReq", allFilesPolicy?.codeRequirement) - XCTAssertEqual("bundleID", allFilesPolicy?.identifierType) - XCTAssertNil(allFilesPolicy?.receiverIdentifier) - XCTAssertNil(allFilesPolicy?.receiverCodeRequirement) - XCTAssertNil(allFilesPolicy?.receiverIdentifierType) - XCTAssertTrue(allFilesPolicy?.allowed == true) - XCTAssertNil(allFilesPolicy?.authorization) - } - } - // MARK: - tests for importProfile func testImportProfileUsingAuthorizationKeyAllow() { @@ -330,11 +270,10 @@ class ModelTests: XCTestCase { XCTAssertEqual("Deny", model.selectedExecutables.first?.policy.SystemPolicyAllFiles) } - // MARK: - tests for profileToString + // MARK: - tests for policyFromString - func testPolicyWhenUsingAllowAndAuthorizationKey() { + func testPolicyWhenUsingAllow() { // given - model.usingLegacyAllowKey = false let app = Executable(identifier: "id", codeRequirement: "req") // when @@ -347,7 +286,6 @@ class ModelTests: XCTestCase { func testPolicyWhenUsingDeny() { // given - model.usingLegacyAllowKey = false let app = Executable(identifier: "id", codeRequirement: "req") // when @@ -360,7 +298,6 @@ class ModelTests: XCTestCase { func testPolicyWhenUsingAllowForStandardUsers() { // given - model.usingLegacyAllowKey = false let app = Executable(identifier: "id", codeRequirement: "req") // when @@ -382,134 +319,4 @@ class ModelTests: XCTestCase { XCTAssertNil(policy, "should have not created the policy with an unknown value") } - func testPolicyWhenUsingLegacyDeny() { - // given - let app = Executable(identifier: "id", codeRequirement: "req") - model.usingLegacyAllowKey = true - - // when - let policy = model.policyFromString(executable: app, value: "Deny") - - // then - XCTAssertNil(policy?.authorization, "should not set authorization when in legacy mode") - XCTAssertEqual(policy?.allowed, false) - } - - func testPolicyWhenUsingLegacyAllow() { - // given - let app = Executable(identifier: "id", codeRequirement: "req") - model.usingLegacyAllowKey = true - - // when - let policy = model.policyFromString(executable: app, value: "Allow") - - // then - XCTAssertNil(policy?.authorization, "should not set authorization when in legacy mode") - XCTAssertEqual(policy?.allowed, true) - } - - // test for the unrecognized strings for both legacy and normal - func testPolicyWhenUsingLegacyAllowButNonLegacyValueUsed() { - // given - let app = Executable(identifier: "id", codeRequirement: "req") - model.usingLegacyAllowKey = true - - // when - let policy = model.policyFromString(executable: app, value: "Let Standard Users Approve") - - // then - XCTAssertNil(policy, "should have errored out because of an invalid value") - } - - // MARK: - tests for requiresAuthorizationKey - - func testWhenServiceIsUsingAllowStandarUsersToApprove() { - // given - let profile = TCCProfileBuilder().buildProfile(authorization: .allowStandardUserToSetSystemService) - - // when - model.importProfile(tccProfile: profile) - - // then - XCTAssertTrue(model.requiresAuthorizationKey()) - } - - func testWhenServiceIsUsingOnlyAllowKey() { - // given - let profile = TCCProfileBuilder().buildProfile(authorization: .allow) - - // when - model.importProfile(tccProfile: profile) - - // then - XCTAssertFalse(model.requiresAuthorizationKey()) - } - - func testWhenServiceIsUsingOnlyDenyKey() { - // given - let profile = TCCProfileBuilder().buildProfile(authorization: .deny) - - // when - model.importProfile(tccProfile: profile) - - // then - XCTAssertFalse(model.requiresAuthorizationKey()) - } - - // MARK: - tests for changeToUseLegacyAllowKey - - func testChangingFromAuthorizationKeyToLegacyAllowKey() { - // given - let allowStandard = TCCProfileDisplayValue.allowStandardUsersToApprove.rawValue - let exeSettings = ["AddressBook": "Allow", "ListenEvent": allowStandard, "ScreenCapture": allowStandard] - let model = ModelBuilder().addExecutable(settings: exeSettings).build() - model.usingLegacyAllowKey = false - - // when - model.changeToUseLegacyAllowKey() - - // then - XCTAssertEqual(1, model.selectedExecutables.count, "should have only one exe") - let policy = model.selectedExecutables.first?.policy - XCTAssertEqual("Allow", policy?.AddressBook) - XCTAssertEqual("-", policy?.Camera) - XCTAssertEqual("-", policy?.ListenEvent) - XCTAssertEqual("-", policy?.ScreenCapture) - XCTAssertTrue(model.usingLegacyAllowKey) - } - - func testChangingFromAuthorizationKeyToLegacyAllowKeyWithMoreComplexVaues() { - // given - let allowStandard = TCCProfileDisplayValue.allowStandardUsersToApprove.rawValue - let p1Settings = ["SystemPolicyAllFiles": "Allow", - "ListenEvent": allowStandard, - "ScreenCapture": "Deny", - "Camera": "Deny"] - - let p2Settings = ["SystemPolicyAllFiles": "Deny", - "ScreenCapture": allowStandard, - "Calendar": "Allow"] - let builder = ModelBuilder().addExecutable(settings: p1Settings) - model = builder.addExecutable(settings: p2Settings).build() - model.usingLegacyAllowKey = false - - // when - model.changeToUseLegacyAllowKey() - - // then - XCTAssertEqual(2, model.selectedExecutables.count, "should have only one exe") - let policy1 = model.selectedExecutables[0].policy - XCTAssertEqual("Allow", policy1.SystemPolicyAllFiles) - XCTAssertEqual("-", policy1.ListenEvent) - XCTAssertEqual("Deny", policy1.ScreenCapture) - XCTAssertEqual("Deny", policy1.Camera) - - let policy2 = model.selectedExecutables[1].policy - XCTAssertEqual("Deny", policy2.SystemPolicyAllFiles) - XCTAssertEqual("-", policy2.ListenEvent) - XCTAssertEqual("-", policy2.ScreenCapture) - XCTAssertEqual("Allow", policy2.Calendar) - XCTAssertTrue(model.usingLegacyAllowKey) - } - } diff --git a/PPPC UtilityTests/ModelTests/PPPCServicesManagerTests.swift b/PPPC UtilityTests/ModelTests/PPPCServicesManagerTests.swift index 767cdae..d92bc82 100644 --- a/PPPC UtilityTests/ModelTests/PPPCServicesManagerTests.swift +++ b/PPPC UtilityTests/ModelTests/PPPCServicesManagerTests.swift @@ -82,7 +82,7 @@ class PPPCServicesManagerTests: XCTestCase { let service = try XCTUnwrap(services.allServices["ScreenCapture"]) // when - let actual = try XCTUnwrap(service.allowStandardUsersMacOS11Plus) + let actual = try XCTUnwrap(service.allowStandardUsers) // then XCTAssertTrue(actual) diff --git a/README.md b/README.md index 8354018..1ce0ce9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [logo]: /Resources/Assets.xcassets/AppIcon.appiconset/PPPC_Logo_32%402x.png "PPPC Utility" -PPPC Utility is a macOS (10.15 and newer) application for creating configuration profiles containing the Privacy Preferences Policy Control payload for macOS. The profiles can be saved locally, signed or unsigned. Profiles can also be uploaded directly to a Jamf Pro server. +PPPC Utility is a macOS (13.0 and newer) application for creating configuration profiles containing the Privacy Preferences Policy Control payload for macOS. The profiles can be saved locally, signed or unsigned. Profiles can also be uploaded directly to a Jamf Pro server. All changes to the application are tracked in [the changelog](https://github.com/jamf/PPPC-Utility/blob/master/CHANGELOG.md). diff --git a/Resources/Base.lproj/Main.storyboard b/Resources/Base.lproj/Main.storyboard index 76e1e55..bd1a5b6 100644 --- a/Resources/Base.lproj/Main.storyboard +++ b/Resources/Base.lproj/Main.storyboard @@ -2397,20 +2397,6 @@ - - - - - - - - - - - - - -