diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 30539ab6..6ac9b70c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,10 @@ on: - master pull_request: +concurrency: + group: ${{ github.ref_name }} + cancel-in-progress: true + jobs: xcode-build-12: name: Xcode 12 Build @@ -14,16 +18,18 @@ jobs: matrix: platforms: [ 'iOS_14,tvOS_14,watchOS_7', - 'iOS_13,tvOS_13,watchOS_6', + # TODO: add iOS_13 back once https://github.com/actions/runner-images/issues/7687 is resolved + 'tvOS_13,watchOS_6', ] fail-fast: false + timeout-minutes: 30 steps: - name: Checkout Repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Bundle Install run: bundle install - name: Select Xcode Version - run: sudo xcode-select --switch /Applications/Xcode_12.4.app/Contents/Developer + run: sudo xcode-select --switch /Applications/Xcode_12.5.1.app/Contents/Developer - name: Prepare Simulator Runtimes run: Scripts/github/prepare-simulators.sh ${{ matrix.platforms }} - name: Build and Test Framework @@ -40,9 +46,10 @@ jobs: 'iOS_15,tvOS_15,watchOS_8', ] fail-fast: false + timeout-minutes: 30 steps: - name: Checkout Repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Bundle Install run: bundle install - name: Select Xcode Version @@ -52,35 +59,60 @@ jobs: - name: Upload Coverage Reports if: success() run: Scripts/upload-coverage-reports.sh ${{ matrix.platforms }} + xcode-build-14: + name: Xcode 14 Build + runs-on: macOS-13 + strategy: + matrix: + platforms: [ + 'iOS_16,tvOS_16,watchOS_9', + ] + fail-fast: false + timeout-minutes: 30 + steps: + - name: Checkout Repo + uses: actions/checkout@v3 + - name: Bundle Install + run: bundle install + - name: Select Xcode Version + run: sudo xcode-select --switch /Applications/Xcode_14.3.app/Contents/Developer + - name: Build and Test Framework + run: Scripts/build.swift ${{ matrix.platforms }} xcode + - name: Upload Coverage Reports + if: success() + run: Scripts/upload-coverage-reports.sh ${{ matrix.platforms }} pod-lint: name: Pod Lint - runs-on: macOS-11 + runs-on: macOS-13 + timeout-minutes: 30 steps: - name: Checkout Repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Bundle Install run: bundle install - name: Select Xcode Version - run: sudo xcode-select --switch /Applications/Xcode_11.7.app/Contents/Developer + run: sudo xcode-select --switch /Applications/Xcode_14.3.app/Contents/Developer - name: Lint Podspec run: bundle exec pod lib lint --verbose --fail-fast --swift-version=5.0 carthage: name: Carthage - runs-on: macOS-11 + runs-on: macOS-13 + timeout-minutes: 30 steps: - name: Checkout Repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Bundle Install run: bundle install - name: Select Xcode Version - run: sudo xcode-select --switch /Applications/Xcode_11.7.app/Contents/Developer + run: sudo xcode-select --switch /Applications/Xcode_14.3.app/Contents/Developer - name: Install Carthage run: brew outdated carthage || brew upgrade carthage - name: Build Framework - run: carthage build --verbose --no-skip-current + run: carthage build --verbose --no-skip-current --use-xcframeworks spm-11: name: SPM Build macOS 11 runs-on: macOS-11 + timeout-minutes: 30 strategy: matrix: platforms: [ @@ -92,17 +124,17 @@ jobs: fail-fast: false steps: - name: Checkout Repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Bundle Install run: bundle install - name: Select Xcode Version - run: sudo xcode-select --switch /Applications/Xcode_12.4.app/Contents/Developer + run: sudo xcode-select --switch /Applications/Xcode_12.5.1.app/Contents/Developer if: ${{ matrix.platforms == 'iOS_14,tvOS_14,watchOS_7' }} - name: Select Xcode Version - run: sudo xcode-select --switch /Applications/Xcode_12.4.app/Contents/Developer + run: sudo xcode-select --switch /Applications/Xcode_12.5.1.app/Contents/Developer if: ${{ matrix.platforms == 'iOS_13,tvOS_13,watchOS_6' }} - name: Select Xcode Version - run: sudo xcode-select --switch /Applications/Xcode_12.4.app/Contents/Developer + run: sudo xcode-select --switch /Applications/Xcode_12.5.1.app/Contents/Developer if: ${{ matrix.platforms == 'macOS_11' }} - name: Select Xcode Version run: sudo xcode-select --switch /Applications/Xcode_11.7.app/Contents/Developer @@ -121,9 +153,10 @@ jobs: 'macOS_12', ] fail-fast: false + timeout-minutes: 30 steps: - name: Checkout Repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Bundle Install run: bundle install - name: Select Xcode Version @@ -132,3 +165,25 @@ jobs: run: Scripts/github/prepare-simulators.sh ${{ matrix.platforms }} - name: Build Framework run: Scripts/build.swift ${{ matrix.platforms }} spm + spm-13: + name: SPM Build macOS 13 + runs-on: macOS-13 + strategy: + matrix: + platforms: [ + 'iOS_16,tvOS_16,watchOS_9', + 'macOS_13', + ] + fail-fast: false + timeout-minutes: 30 + steps: + - name: Checkout Repo + uses: actions/checkout@v3 + - name: Bundle Install + run: bundle install + - name: Select Xcode Version + run: sudo xcode-select --switch /Applications/Xcode_14.3.app/Contents/Developer + - name: Prepare Simulator Runtimes + run: Scripts/github/prepare-simulators.sh ${{ matrix.platforms }} + - name: Build Framework + run: Scripts/build.swift ${{ matrix.platforms }} spm diff --git a/Scripts/build.swift b/Scripts/build.swift index 252872c3..0dc9a484 100755 --- a/Scripts/build.swift +++ b/Scripts/build.swift @@ -24,15 +24,23 @@ enum Platform: String, CustomStringConvertible { case iOS_13 case iOS_14 case iOS_15 + case iOS_16 + case iOS_17 case tvOS_13 case tvOS_14 case tvOS_15 + case tvOS_16 + case tvOS_17 case macOS_10_15 case macOS_11 case macOS_12 + case macOS_13 + case macOS_14 case watchOS_6 case watchOS_7 case watchOS_8 + case watchOS_9 + case watchOS_10 var destination: String { switch self { @@ -42,6 +50,10 @@ enum Platform: String, CustomStringConvertible { return "platform=iOS Simulator,OS=14.4,name=iPad Pro (12.9-inch) (4th generation)" case .iOS_15: return "platform=iOS Simulator,OS=15.5,name=iPad Pro (12.9-inch) (5th generation)" + case .iOS_16: + return "platform=iOS Simulator,OS=16.4,name=iPad Pro (12.9-inch) (6th generation)" + case .iOS_17: + return "platform=iOS Simulator,OS=17.0,name=iPad Pro (12.9-inch) (6th generation)" case .tvOS_13: return "platform=tvOS Simulator,OS=13.4,name=Apple TV" @@ -49,10 +61,16 @@ enum Platform: String, CustomStringConvertible { return "platform=tvOS Simulator,OS=14.3,name=Apple TV" case .tvOS_15: return "platform=tvOS Simulator,OS=15.4,name=Apple TV" + case .tvOS_16: + return "platform=tvOS Simulator,OS=16.4,name=Apple TV" + case .tvOS_17: + return "platform=tvOS Simulator,OS=17.0,name=Apple TV" case .macOS_10_15, .macOS_11, - .macOS_12: + .macOS_12, + .macOS_13, + .macOS_14: return "platform=OS X" case .watchOS_6: @@ -61,6 +79,10 @@ enum Platform: String, CustomStringConvertible { return "OS=7.2,name=Apple Watch Series 6 - 44mm" case .watchOS_8: return "OS=8.5,name=Apple Watch Series 6 - 44mm" + case .watchOS_9: + return "OS=9.4,name=Apple Watch Series 6 - 44mm" + case .watchOS_10: + return "OS=10.0,name=Apple Watch Series 6 - 44mm" } } @@ -68,12 +90,16 @@ enum Platform: String, CustomStringConvertible { switch self { case .iOS_13, .iOS_14, - .iOS_15: + .iOS_15, + .iOS_16, + .iOS_17: return "iphonesimulator" case .tvOS_13, .tvOS_14, - .tvOS_15: + .tvOS_15, + .tvOS_16, + .tvOS_17: return "appletvsimulator" case .macOS_10_15: @@ -82,10 +108,16 @@ enum Platform: String, CustomStringConvertible { return "macosx11.1" case .macOS_12: return "macosx12.3" + case .macOS_13: + return "macosx13.3" + case .macOS_14: + return "macosx14.0" case .watchOS_6, .watchOS_7, - .watchOS_8: + .watchOS_8, + .watchOS_9, + .watchOS_10: return "watchsimulator" } } @@ -95,22 +127,41 @@ enum Platform: String, CustomStringConvertible { case .iOS_13, .iOS_14, .iOS_15, + .iOS_16, + .iOS_17, .tvOS_13, .tvOS_14, .tvOS_15, + .tvOS_16, + .tvOS_17, .macOS_10_15, .macOS_11, - .macOS_12: + .macOS_12, + .macOS_13, + .macOS_14: return true case .watchOS_6, .watchOS_7, - .watchOS_8: + .watchOS_8, + .watchOS_9, + .watchOS_10: // watchOS does not support unit testing (yet?). return false } } + /// Whether the platform's Xcode version requires modern SPM integration in xcodebuild, given the removal of generate-xcodeproj. + var requiresModernSPMIntegration: Bool { + switch self { + case .iOS_16, .tvOS_16, .watchOS_9, .macOS_13, + .iOS_17, .tvOS_17, .watchOS_10, .macOS_14: + return true + default: + return false + } + } + var derivedDataPath: String { ".build/derivedData/" + description } @@ -119,22 +170,30 @@ enum Platform: String, CustomStringConvertible { switch self { case .iOS_13, .iOS_14, - .iOS_15: + .iOS_15, + .iOS_16, + .iOS_17: return "Valet iOS" case .tvOS_13, .tvOS_14, - .tvOS_15: + .tvOS_15, + .tvOS_16, + .tvOS_17: return "Valet tvOS" case .macOS_10_15, .macOS_11, - .macOS_12: + .macOS_12, + .macOS_13, + .macOS_14: return "Valet Mac" case .watchOS_6, .watchOS_7, - .watchOS_8: + .watchOS_8, + .watchOS_9, + .watchOS_10: return "Valet watchOS" } } @@ -152,21 +211,29 @@ enum Task: String, CustomStringConvertible { rawValue } - var project: String { - switch self { - case .spm: - return "generated/Valet.xcodeproj" - case .xcode: - return "Valet.xcodeproj" + func project(for platform: Platform) -> String? { + if platform.requiresModernSPMIntegration { + return nil + } else { + switch self { + case .spm: + return "generated/Valet.xcodeproj" + case .xcode: + return "Valet.xcodeproj" + } } } - var shouldGenerateXcodeProject: Bool { - switch self { - case .spm: - return true - case .xcode: + func shouldGenerateXcodeProject(for platform: Platform) -> Bool { + if platform.requiresModernSPMIntegration { return false + } else { + switch self { + case .spm: + return true + case .xcode: + return false + } } } @@ -194,7 +261,11 @@ enum Task: String, CustomStringConvertible { func scheme(for platform: Platform) -> String { switch self { case .spm: - return "Valet-Package" + if platform.requiresModernSPMIntegration { + return "Valet" + } else { + return "Valet-Package" + } case .xcode: return platform.scheme } @@ -203,7 +274,7 @@ enum Task: String, CustomStringConvertible { func shouldTest(on platform: Platform) -> Bool { switch self { case .spm: - // Our Package isn't set up with unit test targets, becuase SPM can't run unit tests in a codesigned environment. + // Our Package isn't set up with unit test targets, because SPM can't run unit tests in a codesigned environment. return false case .xcode: return platform.shouldTest @@ -213,33 +284,58 @@ enum Task: String, CustomStringConvertible { guard CommandLine.arguments.count > 2 else { print("Usage: build.swift platforms [spm|xcode]") - throw TaskError.code(1) + exit(0) } let rawPlatforms = CommandLine.arguments[1].components(separatedBy: ",") let rawTask = CommandLine.arguments[2] guard let task = Task(rawValue: rawTask) else { print("Received unknown task \(rawTask)") - throw TaskError.code(1) + exit(0) +} + +let platforms = rawPlatforms.map { rawPlatform -> Platform in + guard let platform = Platform(rawValue: rawPlatform) else { + print("Received unknown platform type \(rawPlatform)") + exit(0) + } + + return platform } -if task.shouldGenerateXcodeProject { +// Only generate xcodeproj for SPM on platforms that require it. +let shouldGenerateXcodeproj = task == .spm && platforms.map { task.shouldGenerateXcodeProject(for: $0) }.contains(true) +if shouldGenerateXcodeproj { try execute(commandPath: "/usr/bin/xcrun", arguments: ["/usr/bin/swift", "package", "generate-xcodeproj", "--output=generated/"]) } +for platform in platforms { + var deletedXcodeproj = false + var xcodeBuildArguments: [String] = [] + // If necessary, delete Valet.xcodeproj, otherwise xcodebuild won't generate the SPM scheme. + // If deleted, the xcodeproj will be restored by git at the end of the loop. + if task == .spm && platform.requiresModernSPMIntegration { + do { + print("Deleting Valet.xcodeproj, any uncommitted changes will be lost.") + try execute(commandPath: "/bin/rm", arguments: ["-r", "Valet.xcodeproj"]) + deletedXcodeproj = true + } catch { + print("Could not delete Valet.xcodeproj due to error: \(error)") + exit(0) + } + } -for rawPlatform in rawPlatforms { - guard let platform = Platform(rawValue: rawPlatform) else { - print("Received unknown platform type \(rawPlatform)") - throw TaskError.code(1) + if let project = task.project(for: platform) { + xcodeBuildArguments.append("-project") + xcodeBuildArguments.append(project) } - var xcodeBuildArguments = [ - "-project", task.project, + + xcodeBuildArguments.append(contentsOf: [ "-scheme", task.scheme(for: platform), "-sdk", platform.sdk, "-configuration", task.configuration, "-PBXBuildsContinueAfterErrors=0", - ] + ]) if !platform.destination.isEmpty { xcodeBuildArguments.append("-destination") xcodeBuildArguments.append(platform.destination) @@ -259,5 +355,18 @@ for rawPlatform in rawPlatforms { xcodeBuildArguments.append("test") } - try execute(commandPath: "/usr/bin/xcodebuild", arguments: xcodeBuildArguments) + do { + try execute(commandPath: "/usr/bin/xcodebuild", arguments: xcodeBuildArguments) + } catch { + print("xcodebuild failed with error: \(error)") + } + + if deletedXcodeproj { + do { + print("Restoring Valet.xcodeproj") + try execute(commandPath: "/usr/bin/git", arguments: ["restore", "Valet.xcodeproj"]) + } catch { + print("Failed to reset Valet.xcodeproj to last committed version due to error: \(error)") + } + } } diff --git a/Sources/LegacyValet/VALLegacySecureEnclaveValet.m b/Sources/LegacyValet/VALLegacySecureEnclaveValet.m index 6a8cbe8f..5360f025 100644 --- a/Sources/LegacyValet/VALLegacySecureEnclaveValet.m +++ b/Sources/LegacyValet/VALLegacySecureEnclaveValet.m @@ -264,6 +264,8 @@ - (BOOL)containsObjectForKey:(nonnull NSString *)key; return keyAlreadyInKeychain; } +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreturn-type" - (nonnull NSSet *)allKeys; { VALCheckCondition(NO, [NSSet new], @"%s is not supported on %@", __PRETTY_FUNCTION__, NSStringFromClass([self class])); @@ -273,6 +275,7 @@ - (BOOL)removeAllObjects; { VALCheckCondition(NO, NO, @"%s is not supported on %@", __PRETTY_FUNCTION__, NSStringFromClass([self class])); } +#pragma clang diagnostic pop - (nullable NSError *)migrateObjectsMatchingQuery:(nonnull NSDictionary *)secItemQuery removeOnCompletion:(BOOL)remove; { diff --git a/Sources/Valet/SinglePromptSecureEnclaveValet.swift b/Sources/Valet/SinglePromptSecureEnclaveValet.swift index 5b7df38b..fe968f3d 100644 --- a/Sources/Valet/SinglePromptSecureEnclaveValet.swift +++ b/Sources/Valet/SinglePromptSecureEnclaveValet.swift @@ -15,6 +15,7 @@ // // Xcode 13 and prior incorrectly say that LocalAuthentication is available on tvOS, so we have to check both as long as Xcode 13 and prior are supported. +// Xcode 14 moved the LAContext availability to watchOS 3, so only that version is explicitly annotated. #if !os(tvOS) && canImport(LocalAuthentication) import LocalAuthentication @@ -23,6 +24,7 @@ import Foundation /// Reads and writes keychain elements that are stored on the Secure Enclave using Accessibility attribute `.whenPasscodeSetThisDeviceOnly`. The first access of these keychain elements will require the user to confirm their presence via Touch ID, Face ID, or passcode entry. If no passcode is set on the device, accessing the keychain via a `SinglePromptSecureEnclaveValet` will fail. Data is removed from the Secure Enclave when the user removes a passcode from the device. @objc(VALSinglePromptSecureEnclaveValet) +@available(watchOS 3, *) public final class SinglePromptSecureEnclaveValet: NSObject { // MARK: Public Class Methods @@ -277,6 +279,7 @@ public final class SinglePromptSecureEnclaveValet: NSObject { // MARK: - Objective-C Compatibility +@available(watchOS 3, *) extension SinglePromptSecureEnclaveValet { // MARK: Public Class Methods diff --git a/Tests/ValetIntegrationTests/BackwardsCompatibilityTests/SecureEnclaveBackwardsCompatibilityTests.swift b/Tests/ValetIntegrationTests/BackwardsCompatibilityTests/SecureEnclaveBackwardsCompatibilityTests.swift index 8abd35ef..5f428b36 100644 --- a/Tests/ValetIntegrationTests/BackwardsCompatibilityTests/SecureEnclaveBackwardsCompatibilityTests.swift +++ b/Tests/ValetIntegrationTests/BackwardsCompatibilityTests/SecureEnclaveBackwardsCompatibilityTests.swift @@ -25,7 +25,7 @@ extension SecureEnclaveIntegrationTests { @available (*, deprecated) func test_backwardsCompatibility_withLegacyValet() throws { - guard testEnvironmentIsSigned() && testEnvironmentSupportsWhenPasscodeSet() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() && testEnvironmentSupportsWhenPasscodeSet() else { return } diff --git a/Tests/ValetIntegrationTests/BackwardsCompatibilityTests/SinglePromptSecureEnclaveBackwardsCompatibilityTests.swift b/Tests/ValetIntegrationTests/BackwardsCompatibilityTests/SinglePromptSecureEnclaveBackwardsCompatibilityTests.swift index 3d86d835..8d394e69 100644 --- a/Tests/ValetIntegrationTests/BackwardsCompatibilityTests/SinglePromptSecureEnclaveBackwardsCompatibilityTests.swift +++ b/Tests/ValetIntegrationTests/BackwardsCompatibilityTests/SinglePromptSecureEnclaveBackwardsCompatibilityTests.swift @@ -26,7 +26,7 @@ extension SinglePromptSecureEnclaveIntegrationTests { @available (*, deprecated) func test_backwardsCompatibility_withLegacyValet() throws { - guard testEnvironmentIsSigned() && testEnvironmentSupportsWhenPasscodeSet() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() && testEnvironmentSupportsWhenPasscodeSet() else { return } diff --git a/Tests/ValetIntegrationTests/BackwardsCompatibilityTests/SynchronizableBackwardsCompatibilityTests.swift b/Tests/ValetIntegrationTests/BackwardsCompatibilityTests/SynchronizableBackwardsCompatibilityTests.swift index f5da7720..0408ef0a 100644 --- a/Tests/ValetIntegrationTests/BackwardsCompatibilityTests/SynchronizableBackwardsCompatibilityTests.swift +++ b/Tests/ValetIntegrationTests/BackwardsCompatibilityTests/SynchronizableBackwardsCompatibilityTests.swift @@ -25,7 +25,7 @@ extension CloudIntegrationTests { // MARK: Backwards Compatibility func test_backwardsCompatibility_withLegacyValet() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -39,7 +39,7 @@ extension CloudIntegrationTests { } func test_backwardsCompatibility_withSharedAccessGroupLegacyValet() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } diff --git a/Tests/ValetIntegrationTests/BackwardsCompatibilityTests/ValetBackwardsCompatibilityTests.swift b/Tests/ValetIntegrationTests/BackwardsCompatibilityTests/ValetBackwardsCompatibilityTests.swift index 62d36357..d5f8e44b 100644 --- a/Tests/ValetIntegrationTests/BackwardsCompatibilityTests/ValetBackwardsCompatibilityTests.swift +++ b/Tests/ValetIntegrationTests/BackwardsCompatibilityTests/ValetBackwardsCompatibilityTests.swift @@ -130,7 +130,7 @@ class ValetBackwardsCompatibilityIntegrationTests: ValetIntegrationTests { } func test_backwardsCompatibility_withLegacySharedAccessGroupValet() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } try Valet.currentAndLegacyPermutations(with: Valet.sharedAccessGroupIdentifier).forEach { permutation, legacyValet in @@ -165,7 +165,7 @@ class ValetBackwardsCompatibilityIntegrationTests: ValetIntegrationTests { } func test_migrateObjectsFromAlwaysAccessibleValet_forwardsCompatibility_withLegacySharedAccessGroupValet() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } let alwaysAccessibleLegacyValet = VALLegacyValet(sharedAccessGroupIdentifier: Valet.sharedAccessGroupIdentifier.groupIdentifier, accessibility: .always)! @@ -177,7 +177,7 @@ class ValetBackwardsCompatibilityIntegrationTests: ValetIntegrationTests { } func test_migrateObjectsFromAlwaysAccessibleThisDeviceOnlyValet_forwardsCompatibility_withLegacySharedAccessGroupValet() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } let alwaysAccessibleLegacyValet = VALLegacyValet(sharedAccessGroupIdentifier: Valet.sharedAccessGroupIdentifier.groupIdentifier, accessibility: .alwaysThisDeviceOnly)! diff --git a/Tests/ValetIntegrationTests/CloudIntegrationTests.swift b/Tests/ValetIntegrationTests/CloudIntegrationTests.swift index ac5b0e2d..6db403c7 100644 --- a/Tests/ValetIntegrationTests/CloudIntegrationTests.swift +++ b/Tests/ValetIntegrationTests/CloudIntegrationTests.swift @@ -25,7 +25,7 @@ class CloudIntegrationTests: XCTestCase static let identifier = Valet.sharedAccessGroupIdentifier static let accessibility = CloudAccessibility.whenUnlocked var allPermutations: [Valet] { - return (testEnvironmentIsSigned() + return (testEnvironmentIsSignedOrDoesNotRequireEntitlement() ? Valet.iCloudPermutations(with: CloudIntegrationTests.identifier.asIdentifier) + Valet.iCloudPermutations(with: CloudIntegrationTests.identifier) : []) } @@ -47,7 +47,7 @@ class CloudIntegrationTests: XCTestCase func test_synchronizableValet_isDistinctFromVanillaValetWithEqualConfiguration() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } diff --git a/Tests/ValetIntegrationTests/KeychainIntegrationTests.swift b/Tests/ValetIntegrationTests/KeychainIntegrationTests.swift index 4af7cd5a..1476a316 100644 --- a/Tests/ValetIntegrationTests/KeychainIntegrationTests.swift +++ b/Tests/ValetIntegrationTests/KeychainIntegrationTests.swift @@ -23,7 +23,7 @@ import XCTest final class KeychainIntegrationTests: XCTestCase { func test_revertMigration_removesAllMigratedKeys() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } diff --git a/Tests/ValetIntegrationTests/MacTests.swift b/Tests/ValetIntegrationTests/MacTests.swift index c6b742d8..307cbc81 100644 --- a/Tests/ValetIntegrationTests/MacTests.swift +++ b/Tests/ValetIntegrationTests/MacTests.swift @@ -110,7 +110,7 @@ class ValetMacTests: XCTestCase XCTAssertEqual($0.baseKeychainQuery[kSecAttrService as String], explicitlySetIdentifier.description) } - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -124,7 +124,7 @@ class ValetMacTests: XCTestCase } func test_withExplicitlySet_canAccessKeychain() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -156,7 +156,7 @@ class ValetMacTests: XCTestCase } func test_withExplicitlySet_canReadWrittenString() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } diff --git a/Tests/ValetIntegrationTests/SecureEnclaveIntegrationTests.swift b/Tests/ValetIntegrationTests/SecureEnclaveIntegrationTests.swift index 43df0c37..a13653b5 100644 --- a/Tests/ValetIntegrationTests/SecureEnclaveIntegrationTests.swift +++ b/Tests/ValetIntegrationTests/SecureEnclaveIntegrationTests.swift @@ -31,7 +31,7 @@ class SecureEnclaveIntegrationTests: XCTestCase { super.setUp() - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } do { @@ -45,7 +45,7 @@ class SecureEnclaveIntegrationTests: XCTestCase func test_secureEnclaveValetsWithEqualConfiguration_canAccessSameData() throws { - guard testEnvironmentIsSigned() && testEnvironmentSupportsWhenPasscodeSet() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() && testEnvironmentSupportsWhenPasscodeSet() else { return } @@ -57,7 +57,7 @@ class SecureEnclaveIntegrationTests: XCTestCase func test_secureEnclaveValetsWithDifferingAccessControl_canNotAccessSameData() throws { - guard testEnvironmentIsSigned() && testEnvironmentSupportsWhenPasscodeSet() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() && testEnvironmentSupportsWhenPasscodeSet() else { return } @@ -74,7 +74,7 @@ class SecureEnclaveIntegrationTests: XCTestCase func test_canAccessKeychain() { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -88,7 +88,7 @@ class SecureEnclaveIntegrationTests: XCTestCase } func test_canAccessKeychain_sharedAccessGroup() { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -104,7 +104,7 @@ class SecureEnclaveIntegrationTests: XCTestCase #if !os(macOS) // We can't test app groups on macOS without a paid developer account, which we don't have. func test_canAccessKeychain_sharedAppGroup() { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -122,7 +122,7 @@ class SecureEnclaveIntegrationTests: XCTestCase func test_migrateObjectsMatchingQuery_failsForBadQuery() { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -137,7 +137,7 @@ class SecureEnclaveIntegrationTests: XCTestCase func test_migrateObjectsFromValet_migratesSuccessfullyToSecureEnclave() throws { - guard testEnvironmentIsSigned() && testEnvironmentSupportsWhenPasscodeSet() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() && testEnvironmentSupportsWhenPasscodeSet() else { return } @@ -175,7 +175,7 @@ class SecureEnclaveIntegrationTests: XCTestCase } func test_migrateObjectsFromValet_migratesSuccessfullyAfterCanAccessKeychainCalls() throws { - guard testEnvironmentIsSigned() && testEnvironmentSupportsWhenPasscodeSet() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() && testEnvironmentSupportsWhenPasscodeSet() else { return } diff --git a/Tests/ValetIntegrationTests/SinglePromptSecureEnclaveIntegrationTests.swift b/Tests/ValetIntegrationTests/SinglePromptSecureEnclaveIntegrationTests.swift index 7c62ab01..118fe1d0 100644 --- a/Tests/ValetIntegrationTests/SinglePromptSecureEnclaveIntegrationTests.swift +++ b/Tests/ValetIntegrationTests/SinglePromptSecureEnclaveIntegrationTests.swift @@ -35,7 +35,7 @@ class SinglePromptSecureEnclaveIntegrationTests: XCTestCase { super.setUp() - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } do { @@ -49,7 +49,7 @@ class SinglePromptSecureEnclaveIntegrationTests: XCTestCase func test_SinglePromptSecureEnclaveValetsWithEqualConfiguration_canAccessSameData() throws { - guard testEnvironmentIsSigned() && testEnvironmentSupportsWhenPasscodeSet() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() && testEnvironmentSupportsWhenPasscodeSet() else { return } @@ -61,7 +61,7 @@ class SinglePromptSecureEnclaveIntegrationTests: XCTestCase func test_SinglePromptSecureEnclaveValetsWithDifferingAccessControl_canNotAccessSameData() throws { - guard testEnvironmentIsSigned() && testEnvironmentSupportsWhenPasscodeSet() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() && testEnvironmentSupportsWhenPasscodeSet() else { return } @@ -78,7 +78,7 @@ class SinglePromptSecureEnclaveIntegrationTests: XCTestCase func test_allKeys() throws { - guard testEnvironmentIsSigned() && testEnvironmentSupportsWhenPasscodeSet() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() && testEnvironmentSupportsWhenPasscodeSet() else { return } @@ -95,7 +95,7 @@ class SinglePromptSecureEnclaveIntegrationTests: XCTestCase } func test_allKeys_doesNotReflectValetImplementationDetails() throws { - guard testEnvironmentIsSigned() && testEnvironmentSupportsWhenPasscodeSet() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() && testEnvironmentSupportsWhenPasscodeSet() else { return } @@ -108,7 +108,7 @@ class SinglePromptSecureEnclaveIntegrationTests: XCTestCase func test_canAccessKeychain() { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -122,7 +122,7 @@ class SinglePromptSecureEnclaveIntegrationTests: XCTestCase } func test_canAccessKeychain_sharedAccessGroup() { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -138,7 +138,7 @@ class SinglePromptSecureEnclaveIntegrationTests: XCTestCase #if !os(macOS) // We can't test app groups on macOS without a paid developer account, which we don't have. func test_canAccessKeychain_sharedAppGroup() { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -156,7 +156,7 @@ class SinglePromptSecureEnclaveIntegrationTests: XCTestCase func test_migrateObjectsMatchingQuery_failsForBadQuery() { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -171,7 +171,7 @@ class SinglePromptSecureEnclaveIntegrationTests: XCTestCase func test_migrateObjectsFromValet_migratesSuccessfullyToSecureEnclave() throws { - guard testEnvironmentIsSigned() && testEnvironmentSupportsWhenPasscodeSet() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() && testEnvironmentSupportsWhenPasscodeSet() else { return } @@ -209,7 +209,7 @@ class SinglePromptSecureEnclaveIntegrationTests: XCTestCase } func test_migrateObjectsFromValet_migratesSuccessfullyAfterCanAccessKeychainCalls() throws { - guard testEnvironmentIsSigned() && testEnvironmentSupportsWhenPasscodeSet() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() && testEnvironmentSupportsWhenPasscodeSet() else { return } diff --git a/Tests/ValetIntegrationTests/ValetIntegrationTests.swift b/Tests/ValetIntegrationTests/ValetIntegrationTests.swift index 06160d49..302dae11 100644 --- a/Tests/ValetIntegrationTests/ValetIntegrationTests.swift +++ b/Tests/ValetIntegrationTests/ValetIntegrationTests.swift @@ -20,10 +20,16 @@ import XCTest @testable import Valet -/// - Returns: `true` when the test environment is signed. +/// - Returns: `true` when the test environment is signed and does not require entitlement. /// - The Valet Mac Tests target is left without a host app on master. Mac test host app signing requires CI to have the Developer team credentials down in keychain, which we can't easily accomplish. /// - Note: In order to test changes locally, set the Valet Mac Tests host to Valet macOS Test Host App, delete all VAL_* keychain items in your keychain via Keychain Access.app, and run Mac tests. -func testEnvironmentIsSigned() -> Bool { +func testEnvironmentIsSignedOrDoesNotRequireEntitlement() -> Bool { + #if targetEnvironment(simulator) + if #available(iOS 16, tvOS 16, macOS 13, watchOS 9, *) { + return false + } + #endif + // Our test host appsĀ for iOS and Mac are both signed, so testing for a custom bundle identifier is analogous to testing signing. guard Bundle.main.bundleIdentifier != nil && Bundle.main.bundleIdentifier != "com.apple.dt.xctest.tool" else { #if os(iOS) || os(tvOS) @@ -42,8 +48,12 @@ func testEnvironmentSupportsWhenPasscodeSet() -> Bool { || simulatorVersionInfo.contains("tvOS 13") || simulatorVersionInfo.contains("iOS 15") || simulatorVersionInfo.contains("tvOS 15") + || simulatorVersionInfo.contains("iOS 16") + || simulatorVersionInfo.contains("tvOS 16") + || simulatorVersionInfo.contains("iOS 17") + || simulatorVersionInfo.contains("tvOS 17") { - // iOS 13, tvOS 13, iOS 15, and tvOS 15 simulators fail to store items in a Valet that has a + // iOS 13, tvOS 13, iOS 15, tvOS 15, and later simulators fail to store items in a Valet that has a // kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly flag. The documentation for this flag says: // "No items can be stored in this class on devices without a passcode". I currently do not // understand why prior simulators work with this flag, given that no simulators have a passcode. @@ -104,7 +114,7 @@ class ValetIntegrationTests: XCTestCase signedPermutations += Valet.permutations(with: ValetIntegrationTests.sharedAppGroupIdentifier) #endif return Valet.permutations(with: ValetIntegrationTests.sharedAccessGroupIdentifier.asIdentifier) - + (testEnvironmentIsSigned() + + (testEnvironmentIsSignedOrDoesNotRequireEntitlement() ? signedPermutations : []) } @@ -124,7 +134,7 @@ class ValetIntegrationTests: XCTestCase super.setUp() let permutations: [Valet] - if testEnvironmentIsSigned() { + if testEnvironmentIsSignedOrDoesNotRequireEntitlement() { permutations = [vanillaValet, anotherFlavor] + allPermutations } else { permutations = [vanillaValet] + allPermutations @@ -190,7 +200,7 @@ class ValetIntegrationTests: XCTestCase func test_canAccessKeychain_sharedAccessGroup() { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -203,7 +213,7 @@ class ValetIntegrationTests: XCTestCase // We can't test app groups on macOS without a paid developer account, which we don't have. func test_canAccessKeychain_sharedAppGroup() { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -330,7 +340,7 @@ class ValetIntegrationTests: XCTestCase func test_stringForKey_withEquivalentConfigurationButDifferingFlavor_throwsItemNotFound() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -443,7 +453,7 @@ class ValetIntegrationTests: XCTestCase } func test_objectForKey_withEquivalentConfigurationButDifferingFlavor_throwsItemNotFound() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -652,7 +662,7 @@ class ValetIntegrationTests: XCTestCase func test_removeObjectForKey_isDistinctForDifferingClasses() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -671,7 +681,7 @@ class ValetIntegrationTests: XCTestCase func test_migrateObjectsMatching_failsIfQueryHasNoInputClass() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -700,7 +710,7 @@ class ValetIntegrationTests: XCTestCase func test_migrateObjectsMatching_failsIfNoItemsMatchQuery() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -772,7 +782,7 @@ class ValetIntegrationTests: XCTestCase } func test_migrateObjectsMatchingCompactMap_successfullyMigratesTransformedKey() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -795,7 +805,7 @@ class ValetIntegrationTests: XCTestCase } func test_migrateObjectsMatchingCompactMap_successfullyMigratesTransformedValue() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -818,7 +828,7 @@ class ValetIntegrationTests: XCTestCase } func test_migrateObjectsMatchingCompactMap_returningNilDoesNotMigratePair() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -852,7 +862,7 @@ class ValetIntegrationTests: XCTestCase } func test_migrateObjectsMatchingCompactMap_throwingErrorPreventsAllMigration() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -887,7 +897,7 @@ class ValetIntegrationTests: XCTestCase } func test_migrateObjectsMatchingCompactMap_thrownErrorFromCompactMapIsRethrown() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -921,7 +931,7 @@ class ValetIntegrationTests: XCTestCase func test_migrateObjectsFromValet_migratesSingleKeyValuePairSuccessfully() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -933,7 +943,7 @@ class ValetIntegrationTests: XCTestCase func test_migrateObjectsFromValet_migratesMultipleKeyValuePairsSuccessfully() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -961,7 +971,7 @@ class ValetIntegrationTests: XCTestCase func test_migrateObjectsFromValet_removesOnCompletionWhenRequested() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -991,7 +1001,7 @@ class ValetIntegrationTests: XCTestCase func test_migrateObjectsFromValet_leavesKeychainUntouchedWhenConflictsExist() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -1048,7 +1058,7 @@ class ValetIntegrationTests: XCTestCase } func test_migrateObjectsFromValetCompactMap_successfullyMigratesTransformedKey() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -1068,7 +1078,7 @@ class ValetIntegrationTests: XCTestCase } func test_migrateObjectsFromValetCompactMap_successfullyMigratesTransformedValue() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -1088,7 +1098,7 @@ class ValetIntegrationTests: XCTestCase } func test_migrateObjectsFromValetCompactMap_returningNilDoesNotMigratePair() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -1119,7 +1129,7 @@ class ValetIntegrationTests: XCTestCase } func test_migrateObjectsFromValetCompactMap_throwingErrorPreventsAllMigration() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } @@ -1151,7 +1161,7 @@ class ValetIntegrationTests: XCTestCase } func test_migrateObjectsFromValetCompactMap_thrownErrorFromCompactMapIsRethrown() throws { - guard testEnvironmentIsSigned() else { + guard testEnvironmentIsSignedOrDoesNotRequireEntitlement() else { return } diff --git a/Valet.xcodeproj/xcshareddata/xcschemes/Valet iOS.xcscheme b/Valet.xcodeproj/xcshareddata/xcschemes/Valet iOS.xcscheme index 58e8b4e1..55ea7382 100644 --- a/Valet.xcodeproj/xcshareddata/xcschemes/Valet iOS.xcscheme +++ b/Valet.xcodeproj/xcshareddata/xcschemes/Valet iOS.xcscheme @@ -26,8 +26,17 @@ buildConfiguration = "Debug" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" - codeCoverageEnabled = "YES" - shouldUseLaunchSchemeArgsEnv = "YES"> + shouldUseLaunchSchemeArgsEnv = "YES" + codeCoverageEnabled = "YES"> + + + + @@ -40,17 +49,6 @@ - - - - - - - - - + - + - + - - - - - + diff --git a/Valet.xcodeproj/xcshareddata/xcschemes/Valet watchOS Test Host App.xcscheme b/Valet.xcodeproj/xcshareddata/xcschemes/Valet watchOS Test Host App.xcscheme index 2da03019..2c0f9743 100644 --- a/Valet.xcodeproj/xcshareddata/xcschemes/Valet watchOS Test Host App.xcscheme +++ b/Valet.xcodeproj/xcshareddata/xcschemes/Valet watchOS Test Host App.xcscheme @@ -63,10 +63,8 @@ debugDocumentVersioning = "YES" debugServiceExtension = "internal" allowLocationSimulation = "YES"> - + - + - + - - - - - +