import Foundation import Security import os import HostRegistry /// In-memory keychain double behind the `SecItemShim` seam (plan §3.3): /// unsigned `swift test` binaries get errSecMissingEntitlement (-34018) from /// the real data-protection keychain, so store logic is tested against this. /// /// Behavioral single-slot model (the store uses exactly one service+account): /// - add: duplicate if a value is stored; otherwise stores kSecValueData /// - update: itemNotFound when empty; otherwise replaces the stored value /// - copyMatching: itemNotFound when empty; otherwise returns the stored value /// - delete: itemNotFound when empty; otherwise clears /// /// `force*` knobs override the next status/result (forced statuses do NOT /// touch storage — the fake stays dumb). All calls are recorded verbatim so /// tests can assert the §5.3 attribute dictionaries character-for-character. final class FakeSecItemShim: SecItemShim, Sendable { struct UpdateCall: Sendable { let query: [String: any Sendable] let attributes: [String: any Sendable] } private struct State: Sendable { var storedData: Data? var addCalls: [[String: any Sendable]] = [] var updateCalls: [UpdateCall] = [] var copyCalls: [[String: any Sendable]] = [] var deleteCalls: [[String: any Sendable]] = [] var forcedAddStatus: OSStatus? var forcedUpdateStatus: OSStatus? var forcedCopyStatus: OSStatus? var forcedDeleteStatus: OSStatus? var forcedCopyData: Data? } private let state = OSAllocatedUnfairLock(initialState: State()) // MARK: - SecItemShim func add(_ attributes: [String: any Sendable]) -> OSStatus { state.withLock { s in s.addCalls.append(attributes) if let forced = s.forcedAddStatus { return forced } guard s.storedData == nil else { return errSecDuplicateItem } s.storedData = attributes[kSecValueData as String] as? Data return errSecSuccess } } func update(query: [String: any Sendable], attributesToUpdate: [String: any Sendable]) -> OSStatus { state.withLock { s in s.updateCalls.append(UpdateCall(query: query, attributes: attributesToUpdate)) if let forced = s.forcedUpdateStatus { return forced } guard s.storedData != nil else { return errSecItemNotFound } s.storedData = attributesToUpdate[kSecValueData as String] as? Data return errSecSuccess } } func copyMatching(_ query: [String: any Sendable]) -> (status: OSStatus, data: Data?) { state.withLock { s in s.copyCalls.append(query) if let forced = s.forcedCopyStatus { return (forced, nil) } if let forcedData = s.forcedCopyData { return (errSecSuccess, forcedData) } guard let data = s.storedData else { return (errSecItemNotFound, nil) } return (errSecSuccess, data) } } func delete(_ query: [String: any Sendable]) -> OSStatus { state.withLock { s in s.deleteCalls.append(query) if let forced = s.forcedDeleteStatus { return forced } guard s.storedData != nil else { return errSecItemNotFound } s.storedData = nil return errSecSuccess } } // MARK: - Test controls func forceAddStatus(_ status: OSStatus) { state.withLock { $0.forcedAddStatus = status } } func forceUpdateStatus(_ status: OSStatus) { state.withLock { $0.forcedUpdateStatus = status } } func forceCopyStatus(_ status: OSStatus) { state.withLock { $0.forcedCopyStatus = status } } func forceDeleteStatus(_ status: OSStatus) { state.withLock { $0.forcedDeleteStatus = status } } func forceCopyData(_ data: Data) { state.withLock { $0.forcedCopyData = data } } // MARK: - Recorded calls var recordedAdds: [[String: any Sendable]] { state.withLock { $0.addCalls } } var recordedUpdates: [UpdateCall] { state.withLock { $0.updateCalls } } var recordedCopies: [[String: any Sendable]] { state.withLock { $0.copyCalls } } var recordedDeletes: [[String: any Sendable]] { state.withLock { $0.deleteCalls } } }