System Call Access for UXP

A lot has changed since 2019. I’ve posted my updated proposal in the Adobe Devs Slack but cross posting here as well:

UXP CLI Command Proposal

The Problem:

Executing CLI Commands (Command Prompt / Terminal) in UXP panels currently requires developers to build, sign, notarize, and ship binaries for each platform and call them with uxp.shell.openPath() even if all they are trying to accomplish are simple / one-liner commands.

The Solution:
An equivalent to child_process.exec() / child_process.execSync() in Node.js / CEP but for UXP, but with improved security.

Potential Code Examples:

const { exec, execSync } = require('uxp');
const res = execSync('echo helloSync'); 
console.log(res); // "helloSync"

exec('echo helloAsync', (err, stdout, stderr) => { 
    console.log(stdout); // "helloAsync" 
})

Permission & Security Concerns:

  • A CLI command can do anything a shipped binary can, so permissions of each are roughly the same.
  • However, an app that can access the command line and internet is always a security concern and can be subject to remote code execution vulnerabilities.
  • A possible solution for this is to disallow code generation to be used in exec / execSync the same way that "allowCodeGenerationFromStrings": true currently works in Manifest v5.
  • A list of allowed commands could be included in the manifest like so:
{
    "allowedCommands" : [
        "echo", "ffmpeg", "gimp", "setx" 
    ]
}

Use Cases:

  • Gathering system info needed for plugin such as system specs, network settings, managing environment variables.
  • Running CLI tools like ffmpeg, gimp.
  • Accessing a developer’s custom licensing framework.

I think adding this feature in some form would be an enormous relief for devs as this was one of the large concerns that arose in the community when UXP was announced alongside filesystem and webview which I’m happy to see are making progress since the start of UXP.

Thank you!

7 Likes

Hi guys, any update on this?

1 Like

@pkrishna mentioned in Slack that they were going to bring this up in an internal meeting.

Also interested if there has been any progress here.

3 Likes

Even though UXP Hybrid Plugins now exist, all we would be doing is writing our own execSync(). We are still very interested in a UXP CLI as proposed here without having to take on the overhead of compiling a C++ plugin for the sole purpose of calling external tools required in a studio environment. Any thoughts as to something like this UXP CLI proposal happening? Thanks!

1 Like

I very much agree with @joshy. We actually went the route of implementing a C++ hybrid plugin for this purpose but ultimately would love a more integrated solution that comes with UXP right away. I also think it would lower the bar for pipeline integration in a VFX/animation setting, where this kind of thing is currently a major obstacle.

2 Likes

For those interested in gaining CLI access, currently it’s not possible via UXP directly, however it can be via UXP C++ Hybrid Plugins.

Starting your own hybrid plugin from scratch or based off the example isn’t easy, but in our new UXP boilerplate Bolt UXP we have a Hybrid Plugin template available that comes pre-packaged with an execSync() function for you to start using.

      let hybridModule: {
        execSync: (cmd: string) => string;
      } = await require("bolt-uxp-hybrid.uxpaddon");

      let execSyncRes = hybridModule.execSync("echo test");

You only need C++ experience if you want to modify the hybrid portion of the plugin, if you don’t want or need to mess with that portion, you can just use as is from the JS side and start accessing the command line.

Bolt UXP is free and open-source, so feel free to use it, or if you have your own thing copy the Hybrid Plugin files into your own system:

1 Like

Few questions…

  1. How does error handling or error codes work there?
  2. Is it child process or process on its own? I you kill Photoshop or e.g. unload plugin will it kill also this process?
  3. I am thinking on how to run e.g. NodeJS server and keep it running but also then continue in UXP… that would require execAsync?
1 Like

First of all, super exciting to have a framework to facilitate this for people without in-depth C++ knowledge! Thank you @justin2taylor!!

Similar to @Jarda, I’m curious too if you have any experience with an async version? On my end I ended up implementing both a sync as well as async version, but ran into a few issues with the async version that might be somewhat inherent to the way Photoshop is scheduling its threads under the hood. To me it looked like while a sync version would run in the separate scripting thread, the async execution would be scheduled back on the main thread, not a child thread of the main thread and hence would be blocking. At least that was my observation. Then again, I didn’t spend a whole lot of time tinkering with it. I did also bring this up here.

P.S. In my version of execSync I ended up returning a tuple of status code and output, was wondering if there was a design decision to leave the exit status out?

1 Like

Great questions, as this is a V1, it’s pretty minimal example at the moment.

  1. No error handling yet, but that’s a great request, as of now results are returned as strings, including errors and successful returns.

  2. Currently using a Child Process on Windows and a popen on Mac. So yes if PS closes, so will this.

  3. A regular async exec() would be a good addition for sure for situations like that.

Since Bolt UXP is open-source, always open to feedback and improvements if you want to open an issue or PR.

To point you in the right direction, here is the source code C++ file:

Tracking here if you want to leave any additional comments:

1 Like

Answered some of your questions in the response to Jarda here:

Haven’t yet added or attempted an async / standard exec() version yet, that is good to know your findings and link to the other thread. If there’s no way around that, then requesting more flexibility from the UXP dev team would be good.

And yea a tuple with result and error is a great idea, I’ll probably add something like that to this one.

Tracking here if you want to leave any additional comments:

2 Likes

Thanks @justin2taylor This looks really useful. I appreciate all the work you put in to get that going.

1 Like

Absolutely! If you end up using it would love to hear your feedback here or in our Discord we’ve got a bunch of Bolt CEP devs and now starting to get some Bolt UXP devs since the release: