fix(cua): keep standalone application URLs stable across reuse

This commit is contained in:
creatixchu committed 2026-10-29 17:37:31 +08:00
1 parent 1c9d95a778
commit e87a535d57
2 files changed
+15 -4

No files matched your search

@@ -28,8 +28,8 @@ enum StandaloneApplication {
let files = FileManager.default
try files.createDirectory(at: root, withIntermediateDirectories: true, attributes: [.posixPermissions: 0o700])
let root = root.resolvingSymlinksInPath()
let generation = root.appendingPathComponent(runtimeKey)
let application = generation.appendingPathComponent(source.lastPathComponent)
let generation = root.appendingPathComponent(runtimeKey, isDirectory: true)
let application = generation.appendingPathComponent(source.lastPathComponent, isDirectory: true)
guard !hasApplicationAncestor(application) else {
throw NativeFailure(code: "NATIVE_APPLICATION_REQUIRED", message: "Computer Use application storage must be outside another .app: \(root.path)")
}
@@ -50,10 +50,10 @@ enum StandaloneApplication {
}
return application
}
let staging = root.appendingPathComponent(".staging-\(UUID().uuidString)")
let staging = root.appendingPathComponent(".staging-\(UUID().uuidString)", isDirectory: true)
try files.createDirectory(at: staging, withIntermediateDirectories: false, attributes: [.posixPermissions: 0o700])
do {
let stagedApplication = staging.appendingPathComponent(source.lastPathComponent)
let stagedApplication = staging.appendingPathComponent(source.lastPathComponent, isDirectory: true)
try files.copyItem(at: source, to: stagedApplication)
try validate(stagedApplication, runtimeKey: runtimeKey)
try files.moveItem(at: staging, to: generation)
@@ -111,6 +111,17 @@ func aChangedCachedApplicationIsRejected(file: String) throws {
}
}
@Test func aCachedSymlinkCannotRedirectTheHelperIntoAnEnclosingApplication() throws {
let f = try ApplicationFixture(); defer { f.close() }
let key = try f.key
try FileManager.default.createDirectory(at: f.cache, withIntermediateDirectories: true)
try FileManager.default.createSymbolicLink(at: f.cache.appendingPathComponent(key),
withDestinationURL: f.application.deletingLastPathComponent())
#expect(throws: (any Error).self) {
try StandaloneApplication.install(f.application, runtimeKey: key, root: f.cache, deadline: f.deadline)
}
}
@Test func aCompetingInstallerDoesNotUseAPartialGeneration() throws {
let f = try ApplicationFixture(); defer { f.close() }
let key = try f.key