This commit is contained in:
Max Goedjen
2026-03-25 15:03:36 -07:00
parent 198761f541
commit 782b3b8a51
3 changed files with 30 additions and 34 deletions

View File

@@ -108,8 +108,12 @@ extension Agent {
case .proceed: case .proceed:
break break
case .promptForSharedAuth: case .promptForSharedAuth:
try? await store.persistAuthentication(secret: secret, forProvenance: provenance) do {
try await authorizationCoordinator.completedPersistence() 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) try await witness?.speakNowOrForeverHoldYourPeace(forAccessTo: secret, from: store, by: provenance)
let rawRepresentation = try await store.sign(data: data, with: secret, for: provenance) let rawRepresentation = try await store.sign(data: data, with: secret, for: provenance)
@@ -119,8 +123,6 @@ extension Agent {
logger.debug("Agent signed request") logger.debug("Agent signed request")
try await authorizationCoordinator.completedAuthorization()
return signedData return signedData
} }

View File

@@ -15,7 +15,6 @@ struct PendingRequest: Identifiable, Hashable, CustomStringConvertible {
func batchable(with request: PendingRequest) -> Bool { func batchable(with request: PendingRequest) -> Bool {
secret == request.secret && secret == request.secret &&
provenance.isSameProvenance(as: request.provenance) provenance.isSameProvenance(as: request.provenance)
} }
} }
@@ -27,47 +26,43 @@ enum Decision {
actor RequestHolder { actor RequestHolder {
var pending: [PendingRequest] = [] var pending: [PendingRequest] = []
var active: PendingRequest? var authorizing: PendingRequest?
var preauthorized: PendingRequest? var preauthorized: PendingRequest?
func addPending(_ request: PendingRequest) {
pending.append(request)
}
func advanceIfIdle() {
}
func shouldBlock(_ request: PendingRequest) -> Bool { func shouldBlock(_ request: PendingRequest) -> Bool {
guard request != authorizing else { return false }
if let preauthorized, preauthorized.batchable(with: request) { if let preauthorized, preauthorized.batchable(with: request) {
print("Batching: \(request)") print("Batching: \(request)")
pending.removeAll(where: { $0 == request }) pending.removeAll(where: { $0 == request })
return false return false
} }
let isTurn = request.id == active?.id return authorizing == nil && authorizing.
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
} }
func clear() { func clear() {
if let preauthorized, allBatchable(with: preauthorized).isEmpty { if let preauthorized, allBatchable(with: preauthorized).isEmpty {
self.preauthorized = nil self.preauthorized = nil
} }
if !pending.isEmpty {
let next = pending.removeFirst()
active = next
} else {
active = nil
}
} }
func allBatchable(with request: PendingRequest) -> [PendingRequest] { func allBatchable(with request: PendingRequest) -> [PendingRequest] {
pending.filter { $0.batchable(with: request) } pending.filter { $0.batchable(with: request) }
} }
func completedPersistence() { func completedPersistence(secret: AnySecret, forProvenance provenance: SigningRequestProvenance) {
self.preauthorized = active 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.") logger.debug("\(secret.name) requires authentication.")
let pending = PendingRequest(secret: secret, provenance: provenance) 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.") logger.debug("\(pending) waiting.")
try await Task.sleep(for: .milliseconds(100)) try await Task.sleep(for: .milliseconds(100))
} }
@@ -99,13 +95,11 @@ final class AuthorizationCoordinator: Sendable {
return .proceed return .proceed
} }
func completedAuthorization() async throws { func completedPersistence(secret: AnySecret, forProvenance provenance: SigningRequestProvenance) async {
await holder.clear() await holder.completedPersistence(secret: secret, forProvenance: provenance)
} }
func completedPersistence() async throws { func didNotCompletePersistence(secret: AnySecret, forProvenance provenance: SigningRequestProvenance) async {
await holder.completedPersistence() await holder.didNotCompletePersistence(secret: secret, forProvenance: provenance)
} }
} }

View File

@@ -11,7 +11,7 @@ extension ProcessInfo {
} }
guard let value = SecTaskCopyValueForEntitlement(task, "com.apple.developer.team-identifier" as CFString, nil) as? String else { 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 return fallbackTeamID
} }