Merge nucleic/upbeat-slate-lemur-7euo into dev

This commit is contained in:
2026-07-17 22:21:12 -07:00
parent 1fc4c32097
commit 608e7d0450
5 changed files with 44 additions and 19 deletions
+13 -2
View File
@@ -116,8 +116,19 @@ in-tree means the patch can't be lost to a dependency re-resolve.
(the `cctl login` write path) gains a delete-and-retry on `errSecDuplicateItem`, since the (the `cctl login` write path) gains a delete-and-retry on `errSecDuplicateItem`, since the
now-silent `exists` can under-report an unreadable pre-existing item. Mirrors now-silent `exists` can under-report an unreadable pre-existing item. Mirrors
`KeychainOwnedAccess.withoutLegacyKeychainUI` in NucleicCore. Host-side (shipped by a normal `KeychainOwnedAccess.withoutLegacyKeychainUI` in NucleicCore. Host-side (shipped by a normal
`swift build`); `SecKeychain*` deprecation warnings are expected (built with `swift build`). The three `SecKeychain*` symbols are formally deprecated but are the only API
`WARNINGS_AS_ERRORS=false`). Marked `[Nucleic vendored patch]`. covering the legacy ACL panel; they're bound directly via `@_silgen_name` (`nucleic_SecKeychain*`,
top of file) so the required calls compile without deprecation warnings. Marked
`[Nucleic vendored patch]`.
14. **`Sources/Containerization/Vminitd.swift` — configure the gRPC pipeline before the channel goes
active.** `Vminitd.init` used the now-deprecated `HTTP2ClientTransport.WrappedChannel.wrapping(
channel:config:serviceConfig:)`, which wraps an already-connected channel best-effort and may drop
early server frames such as SETTINGS. Migrated to `wrapping(config:serviceConfig:makeChannel:)`,
which invokes the transport's `configure` inside the bootstrap's channel initializer — before the
vsock channel becomes active. `init` is now `async throws` (the new overload is async); its callers
in `VZVirtualMachineInstance` (`start`/`dialAgent`, both already async) and the integration test now
`try await`. Marked `[Nucleic vendored patch]`.
### GUEST-side patches (require rebuilding the initfs — see below) ### GUEST-side patches (require rebuilding the initfs — see below)
@@ -191,7 +191,7 @@ extension VZVirtualMachineInstance: VirtualMachineInstance {
try await self.vm.start(queue: self.queue) try await self.vm.start(queue: self.queue)
let agent = try Vminitd( let agent = try await Vminitd(
connection: try await self.vm.waitForAgent(queue: self.queue), connection: try await self.vm.waitForAgent(queue: self.queue),
group: self.group group: self.group
) )
@@ -260,7 +260,7 @@ extension VZVirtualMachineInstance: VirtualMachineInstance {
port: Vminitd.port port: Vminitd.port
) )
let handle = try conn.dupHandle() let handle = try conn.dupHandle()
return try Vminitd(connection: handle, group: self.group) return try await Vminitd(connection: handle, group: self.group)
} catch { } catch {
if let err = error as? ContainerizationError { if let err = error as? ContainerizationError {
throw err throw err
+16 -11
View File
@@ -34,18 +34,23 @@ public struct Vminitd: Sendable {
public let grpcClient: GRPCClient<HTTP2ClientTransport.WrappedChannel> public let grpcClient: GRPCClient<HTTP2ClientTransport.WrappedChannel>
private let connectionTask: Task<Void, Error> private let connectionTask: Task<Void, Error>
public init(connection: FileHandle, group: any EventLoopGroup) throws { public init(connection: FileHandle, group: any EventLoopGroup) async throws {
let channel = try ClientBootstrap(group: group) // Configure the gRPC pipeline from inside the channel initializer — before the channel
.channelInitializer { channel in // becomes active — so no early server frames (e.g. SETTINGS) are dropped. `configure` is
channel.eventLoop.makeCompletedFuture(withResultOf: { // supplied by `wrapping(config:serviceConfig:makeChannel:)` and must be called exactly once.
try channel.pipeline.syncOperations.addHandler(HTTP2ConnectBufferingHandler()) let fd = connection.fileDescriptor
}) let transport = try await HTTP2ClientTransport.WrappedChannel.wrapping(
}
.withConnectedSocket(connection.fileDescriptor).wait()
let transport = HTTP2ClientTransport.WrappedChannel.wrapping(
channel: channel,
config: .defaults { $0.connection.maxIdleTime = nil } config: .defaults { $0.connection.maxIdleTime = nil }
) ) { configure in
try await ClientBootstrap(group: group)
.withConnectedSocket(fd) { channel in
channel.eventLoop.makeCompletedFuture {
try channel.pipeline.syncOperations.addHandler(HTTP2ConnectBufferingHandler())
}.flatMap { _ in
configure(channel)
}
}
}
let grpcClient = GRPCClient(transport: transport) let grpcClient = GRPCClient(transport: transport)
self.grpcClient = grpcClient self.grpcClient = grpcClient
self.client = Com_Apple_Containerization_Sandbox_V3_SandboxContext.Client(wrapping: self.grpcClient) self.client = Com_Apple_Containerization_Sandbox_V3_SandboxContext.Client(wrapping: self.grpcClient)
@@ -22,6 +22,15 @@ import Foundation
#endif #endif
import Security // [Nucleic vendored patch] SecKeychain*UserInteractionAllowed for prompt-free reads import Security // [Nucleic vendored patch] SecKeychain*UserInteractionAllowed for prompt-free reads
// [Nucleic vendored patch] `SecKeychainGet/SetUserInteractionAllowed` are formally deprecated but
// remain the ONLY API that suppresses the legacy Keychain ACL panel. Bind the C symbols directly —
// the deprecation rides on their Swift imports, not the raw symbols — so `withoutInteractiveUI`
// compiles without deprecation warnings. Mirrors `KeychainOwnedAccess` in NucleicCore.
@_silgen_name("SecKeychainGetUserInteractionAllowed")
private func nucleic_SecKeychainGetUserInteractionAllowed(_ state: UnsafeMutablePointer<DarwinBoolean>) -> OSStatus
@_silgen_name("SecKeychainSetUserInteractionAllowed")
private func nucleic_SecKeychainSetUserInteractionAllowed(_ state: DarwinBoolean) -> OSStatus
/// Holds the result of a query to the keychain. /// Holds the result of a query to the keychain.
public struct KeychainQueryResult { public struct KeychainQueryResult {
public var username: String public var username: String
@@ -260,9 +269,9 @@ public struct KeychainQuery {
/// `KeychainOwnedAccess.withoutLegacyKeychainUI` in NucleicCore. /// `KeychainOwnedAccess.withoutLegacyKeychainUI` in NucleicCore.
private static func withoutInteractiveUI<T>(_ body: () -> T) -> T { private static func withoutInteractiveUI<T>(_ body: () -> T) -> T {
var previous = DarwinBoolean(true) var previous = DarwinBoolean(true)
SecKeychainGetUserInteractionAllowed(&previous) _ = nucleic_SecKeychainGetUserInteractionAllowed(&previous)
SecKeychainSetUserInteractionAllowed(false) _ = nucleic_SecKeychainSetUserInteractionAllowed(false)
defer { SecKeychainSetUserInteractionAllowed(previous.boolValue) } defer { _ = nucleic_SecKeychainSetUserInteractionAllowed(previous) }
return body() return body()
} }
} }
+1 -1
View File
@@ -1730,7 +1730,7 @@ extension IntegrationSuite {
try await assertExec(container, id: "create-fifo", cmd: "mkfifo /tmp/test-fifo") try await assertExec(container, id: "create-fifo", cmd: "mkfifo /tmp/test-fifo")
let vsock = try await container.dialVsock(port: 1024) let vsock = try await container.dialVsock(port: 1024)
let vminitd = try Vminitd(connection: vsock, group: Self.eventLoop) let vminitd = try await Vminitd(connection: vsock, group: Self.eventLoop)
let root = URL(filePath: container.root) let root = URL(filePath: container.root)