swiftmacossandboxvaporrealitykit

Swift Vapor Console App - The operation couldn’t be completed. Permission denied


I am developing a Swift Vapor app. I want to access the Terminal app (among other apps).

The user will enter a front-end Terminal command and it will be performed by the backend server and the result will be displayed.

What I have done:

The issue:

The operation couldn’t be completed. Permission denied

What I have tried:

Tutorials:

Code:

import Leaf
import Vapor
/*
 // Kill a already working server instance.
 sudo lsof -i :8080
 kill PID
*/
// configures your application
public func configure(_ app: Application) async throws {
    
    // uncomment to serve files from /Public folder
    // app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory))

    app.views.use(.leaf)

    // app.environment.arguments = ["--disable-sandbox"]

    // register routes
    try routes(app)
}

    
import Vapor
    import ConsoleKit

// Web URL:
// http://127.0.0.1:8080/terminalCommand/
// #Example:
// http://127.0.0.1:8080/terminalCommand/123
func routes(_ app: Application) throws {
    
    app.get { req async throws in
        try await req.view.render("index", ["title": "TerminalCommand"])
    }

    app.get("terminalCommand", ":commandName") { req -> String in

        let terminal: Terminal = .init()
        var visibleResultMessage: String = ""
        var resultMessage: String = ""
        
        guard let commandName: String = req.parameters.get("commandName") else {
            throw Abort(.internalServerError)
        }
        
        /*
        let commandContext: CommandContext = CommandContext(console: terminal, input: .init(arguments: [""]))
        let command = TerminalCommand(app: app)
        */
        let pmset: Process = Process()
        // pmset.currentDirectoryURL = URL(fileURLWithPath: NSHomeDirectory())
        let pipe: Pipe = Pipe()
        // let workingDirectory: String = app.directory.workingDirectory
 
        let defaultExecutableURL: URL = URL(fileURLWithPath: "/System/Applications/Utilities/Terminal.app")
        
        pmset.executableURL = defaultExecutableURL
        pmset.executableURL?.startAccessingSecurityScopedResource()
        pmset.standardOutput = pipe

        do {
            try pmset.run()
            pmset.waitUntilExit()
            let data = pipe.fileHandleForReading.readDataToEndOfFile()
            if let output = String(data: data, encoding: String.Encoding.utf8) {
                // context.console.print(output)
                print(output)
            }
            resultMessage = "SUCCESS: Run terminal command."
            pmset.executableURL?.stopAccessingSecurityScopedResource()
        } catch let error {
            resultMessage = "ERROR: Run terminal command -> \(error.localizedDescription)"
        }
        
        visibleResultMessage =
        """
            Result:
        
                \(resultMessage)
        
            Output:
                
                %: \(commandName)
        
        """
        return visibleResultMessage
    }
}

Additional Info:

Thank you for you time and support.


Solution

  • The problem was in this line:

    let defaultExecutableURL: URL = URL(fileURLWithPath: "/System/Applications/Utilities/Terminal.app")
    

    The mentioned URL is a folder url, and not the executable url. The solution is:

    let defaultExecutableURL: URL = URL(fileURLWithPath: "/System/Applications/Utilities/Terminal.app/Contents/MacOS/Terminal")
    

    The error message was misleading. I have found the solution by logging the actual error and trying to find the error code 13. This lead me to another SO anwser that said that its a folder access error.