From 782b3b8a51089cd4e8cd69a053bc3a6a06a07042 Mon Sep 17 00:00:00 2001 From: Max Goedjen Date: Wed, 25 Mar 2026 15:03:36 -0700 Subject: [PATCH] WIP --- .../Sources/SecretAgentKit/Agent.swift | 10 ++-- .../AuthorizationCoordinator.swift | 52 ++++++++----------- .../Packages/Sources/XPCWrappers/TeamID.swift | 2 +- 3 files changed, 30 insertions(+), 34 deletions(-) diff --git a/Sources/Packages/Sources/SecretAgentKit/Agent.swift b/Sources/Packages/Sources/SecretAgentKit/Agent.swift index b5b81ad..c3d8e30 100644 --- a/Sources/Packages/Sources/SecretAgentKit/Agent.swift +++ b/Sources/Packages/Sources/SecretAgentKit/Agent.swift @@ -108,8 +108,12 @@ extension Agent { case .proceed: break case .promptForSharedAuth: - try? await store.persistAuthentication(secret: secret, forProvenance: provenance) - try await authorizationCoordinator.completedPersistence() + do { + try await store.persistAuthentication(secret: secret, forProvenance: provenance) + await authorizationCoordinator.completedPersistence(secret: secret, forProvenance: provenance) + } catch { + await authorizationCoordinator.didNotCompletePersistence(secret: secret, forProvenance: provenance) + } } try await witness?.speakNowOrForeverHoldYourPeace(forAccessTo: secret, from: store, by: provenance) let rawRepresentation = try await store.sign(data: data, with: secret, for: provenance) @@ -119,8 +123,6 @@ extension Agent { logger.debug("Agent signed request") - try await authorizationCoordinator.completedAuthorization() - return signedData } diff --git a/Sources/Packages/Sources/SecretAgentKit/AuthorizationCoordinator.swift b/Sources/Packages/Sources/SecretAgentKit/AuthorizationCoordinator.swift index 3ba35b5..6a92dca 100644 --- a/Sources/Packages/Sources/SecretAgentKit/AuthorizationCoordinator.swift +++ b/Sources/Packages/Sources/SecretAgentKit/AuthorizationCoordinator.swift @@ -15,7 +15,6 @@ struct PendingRequest: Identifiable, Hashable, CustomStringConvertible { func batchable(with request: PendingRequest) -> Bool { secret == request.secret && provenance.isSameProvenance(as: request.provenance) - } } @@ -27,47 +26,43 @@ enum Decision { actor RequestHolder { var pending: [PendingRequest] = [] - var active: PendingRequest? + var authorizing: PendingRequest? var preauthorized: PendingRequest? + func addPending(_ request: PendingRequest) { + pending.append(request) + } + + func advanceIfIdle() { + + } + func shouldBlock(_ request: PendingRequest) -> Bool { + guard request != authorizing else { return false } if let preauthorized, preauthorized.batchable(with: request) { print("Batching: \(request)") pending.removeAll(where: { $0 == request }) return false } - let isTurn = request.id == active?.id - if isTurn { - print("turn \(request)") - return false - } - if pending.isEmpty && active == nil { - active = request - return false - } else if !pending.contains(where: { $0.id == request.id }) { - pending.append(request) - } - return true + return authorizing == nil && authorizing. } func clear() { if let preauthorized, allBatchable(with: preauthorized).isEmpty { self.preauthorized = nil } - if !pending.isEmpty { - let next = pending.removeFirst() - active = next - } else { - active = nil - } } func allBatchable(with request: PendingRequest) -> [PendingRequest] { pending.filter { $0.batchable(with: request) } } - func completedPersistence() { - self.preauthorized = active + func completedPersistence(secret: AnySecret, forProvenance provenance: SigningRequestProvenance) { + self.preauthorized = PendingRequest(secret: secret, provenance: provenance) + } + + func didNotCompletePersistence(secret: AnySecret, forProvenance provenance: SigningRequestProvenance) { + self.preauthorized = nil } } @@ -87,7 +82,8 @@ final class AuthorizationCoordinator: Sendable { } logger.debug("\(secret.name) requires authentication.") let pending = PendingRequest(secret: secret, provenance: provenance) - while !Task.isCancelled, await holder.shouldBlock(pending) { + await holder.addPending(pending) + while await holder.shouldBlock(pending) { logger.debug("\(pending) waiting.") try await Task.sleep(for: .milliseconds(100)) } @@ -99,13 +95,11 @@ final class AuthorizationCoordinator: Sendable { return .proceed } - func completedAuthorization() async throws { - await holder.clear() + func completedPersistence(secret: AnySecret, forProvenance provenance: SigningRequestProvenance) async { + await holder.completedPersistence(secret: secret, forProvenance: provenance) } - func completedPersistence() async throws { - await holder.completedPersistence() + func didNotCompletePersistence(secret: AnySecret, forProvenance provenance: SigningRequestProvenance) async { + await holder.didNotCompletePersistence(secret: secret, forProvenance: provenance) } - - } diff --git a/Sources/Packages/Sources/XPCWrappers/TeamID.swift b/Sources/Packages/Sources/XPCWrappers/TeamID.swift index 56848a1..22d715e 100644 --- a/Sources/Packages/Sources/XPCWrappers/TeamID.swift +++ b/Sources/Packages/Sources/XPCWrappers/TeamID.swift @@ -11,7 +11,7 @@ extension ProcessInfo { } guard let value = SecTaskCopyValueForEntitlement(task, "com.apple.developer.team-identifier" as CFString, nil) as? String else { - assertionFailure("SecTaskCopyValueForEntitlement(com.apple.developer.team-identifier) failed") +// assertionFailure("SecTaskCopyValueForEntitlement(com.apple.developer.team-identifier) failed") return fallbackTeamID }