Merge pull request #6977 from naveenrajm7/script-sandbox-path

scripting : add vm registry suite
This commit is contained in:
osy
2025-04-07 16:05:44 -07:00
committed by GitHub
7 changed files with 128 additions and 2 deletions
+27
View File
@@ -564,6 +564,10 @@
<record-type name="qemu argument" code="QeAr" description="QEMU argument configuration.">
<property name="argument string" code="ArSt" type="text"
description="The QEMU argument as a string."/>
<property name="file urls" code="FlUr"
description="Optional URLs associated with this argument.">
<type type="file" list="yes"/>
</property>
</record-type>
<record-type name="apple configuration" code="ApCf" description="Apple virtual machine configuration.">
@@ -714,4 +718,27 @@
<direct-parameter description="The USB device to disconnect." type="usb device"/>
</command>
</suite>
<suite name="UTM Registry Suite" code="UTMr" description="UTM virtual machine registry suite. Use this to update virtual machine registry.">
<access-group identifier="com.utmapp.UTM.vm-access" />
<class-extension extends="virtual machine" description="Virtual machine registry.">
<property name="registry" code="ReGs" access="r"
description="The registry of the virtual machine.">
<type type="file" list="yes"/>
</property>
<responds-to command="update registry">
<cocoa method="updateRegistry:"/>
</responds-to>
</class-extension>
<command name="update registry" code="UTMrUpDt" description="Update the registry of the virtual machine.">
<direct-parameter description="Virtual machine to update." type="virtual machine"/>
<parameter name="with" code="UpRg" description="The registry to update the virtual machine. Currently you can only change the shared directory with this!">
<cocoa key="newRegistry"/>
<type type="file" list="yes"/>
</parameter>
</command>
</suite>
</dictionary>
+8 -1
View File
@@ -194,6 +194,10 @@ extension UTMScriptingConfigImpl {
var serializedArgument: [AnyHashable: Any] = [
"argumentString": argument.string
]
// Only add fileUrls if it is not nil and contains URLs
if let fileUrls = argument.fileUrls, !fileUrls.isEmpty {
serializedArgument["fileUrls"] = fileUrls.map({ $0 as AnyHashable })
}
return serializedArgument
}
@@ -526,7 +530,10 @@ extension UTMScriptingConfigImpl {
let additionalArguments = records.compactMap { record -> QEMUArgument? in
guard let argumentString = record["argumentString"] as? String else { return nil }
var argument = QEMUArgument(argumentString)
// fileUrls are used as required resources by QEMU.
if let fileUrls = record["fileUrls"] as? [URL] {
argument.fileUrls = fileUrls
}
return argument
}
// Update entire additional arguments with new one.
@@ -0,0 +1,77 @@
//
// Copyright © 2025 naveenrajm7. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
@objc extension UTMScriptingVirtualMachineImpl {
@objc var registry: [URL] {
let wrapper = UTMScriptingRegistryEntryImpl(vm.registryEntry)
return wrapper.serializeRegistry()
}
@objc func updateRegistry(_ command: NSScriptCommand) {
let newRegistry = command.evaluatedArguments?["newRegistry"] as? [URL]
withScriptCommand(command) { [self] in
guard let newRegistry = newRegistry else {
throw ScriptingError.invalidParameter
}
let wrapper = UTMScriptingRegistryEntryImpl(vm.registryEntry)
try await wrapper.updateRegistry(from: newRegistry, qemuProcess)
}
}
}
@MainActor
class UTMScriptingRegistryEntryImpl {
private(set) var registry: UTMRegistryEntry
init(_ registry: UTMRegistryEntry) {
self.registry = registry
}
func serializeRegistry() -> [URL] {
return registry.sharedDirectories.compactMap { $0.url }
}
func updateRegistry(from fileUrls: [URL], _ system: UTMQemuSystem?) async throws {
// Clear all shared directories, we add all directories here
registry.removeAllSharedDirectories()
// Add urls to the registry
for url in fileUrls {
// Start scoped access
let isScopedAccess = url.startAccessingSecurityScopedResource()
defer {
if isScopedAccess {
url.stopAccessingSecurityScopedResource()
}
}
// Get bookmark from UTM process
let standardBookmark = try url.bookmarkData()
let system = system ?? UTMProcess()
let (success, bookmark, path) = await system.accessData(withBookmark: standardBookmark, securityScoped: false)
guard let bookmark = bookmark, let _ = path, success else {
throw UTMQemuVirtualMachineError.accessDriveImageFailed
}
// Store bookmark in registry
let file = UTMRegistryEntry.File(dummyFromPath: url.path, remoteBookmark: bookmark)
registry.appendSharedDirectory(file)
}
}
}
@@ -90,6 +90,12 @@ class UTMScriptingVirtualMachineImpl: NSObject, UTMScriptable {
}
}
var qemuProcess: UTMQemuSystem? {
get async {
await (vm as? UTMQemuVirtualMachine)?.system
}
}
override var objectSpecifier: NSScriptObjectSpecifier? {
let appDescription = NSApplication.classDescription() as! NSScriptClassDescription
return NSUniqueIDSpecifier(containerClassDescription: appDescription,