Cannot run `op` from Go application

361 views Asked by At

I am trying to write a small Go wrapper application around the 1Password CLI executable op like so:

package main

import (
    "fmt"
    "log"
    "os/exec"
)

func main() {
    op := exec.Command("op", "item", "list")
    out, err := op.Output()
    if e, ok := err.(*exec.ExitError); ok {
        log.Fatal(e, ": ", string(e.Stderr))
    }
    fmt.Println(string(out))
}

However, I keep getting the following error:

2023/04/13 09:48:51 exit status 1: [ERROR] 2023/04/13 09:48:51 error initializing client: connecting to desktop app: read: connection reset, make sure the CLI is correctly installed and Connect with 1Password CLI is enabled in the 1Password app

But when I do the same thing from a Python script like so:

#!/usr/bin/env python

import subprocess

subprocess.run(["op", "item", "list"])

...I get the output just fine.

Interestingly enough though, when I call the Python script (named op.py) from the Go app, it works fine (modified Go app shown below):

package main

import (
    "fmt"
    "log"
    "os/exec"
)

func main() {
    op := exec.Command("/usr/bin/python3.11", "./op.py")
    //op := exec.Command("op", "item", "list")
    out, err := op.Output()
    if e, ok := err.(*exec.ExitError); ok {
        log.Fatal(e, ": ", string(e.Stderr))
    }
    fmt.Println(string(out))
}

I can test that it is being printed by the Go app and not by the Python script because if I remove the fmt.Printf(...), nothing gets printed.

So to summarize:

  • Go -> op: does not work
  • Python (./op.py) -> op: works fine
  • Go -> Python (./op.py) -> op: works fine
3

There are 3 answers

6
Mate Lakat On BEST ANSWER

I had the same problem accessing op from a pyenv virtual environment. I figured that the problem is that the pyenv's python executable is owned by the user (me). Changing the ownership to root:root of the python interpreter and the directory that it lives in actually helped. Not sure what is going on behind the scenes.

Here are the steps (I use the --copies to create a virtual environment, so it is not using symlinks - as symlinks would point back to root owned files):

$ python -m venv --copies .venv
$ .venv/bin/python -c "import subprocess; subprocess.call(['op', 'signin'])"
[ERROR] 2023/05/16 16:01:18 connecting to desktop app: read: connection reset, make sure the CLI is correctly installed and Connect with 1Password CLI is enabled in the 1Password app
# chown -R root:root .venv/
$ .venv/bin/python -c "import subprocess; subprocess.call(['op', 'signin'])"
 Select account  [Use arrows to move, type to filter]

Bottomline: Change the ownership of your executable (and directory it lives in) that spawns the op subprocess to root:root

Also please see this thread on 1Password that look like the same issue:

https://1password.community/discussion/135768/calling-the-cli-from-a-go-program

5
Xarus On

I'm actually using GoLang as an overlaying GUI application which communicates with several distinct cpp binaries as a centralised controller. I've implemented the following function to run generic commands:

func RunCmd(binary string, cmd []string) []string {
    var output []string
    c, b := exec.Command(binary, cmd...), new(bytes.Buffer)
    c.Stdout = b
    c.Run()
    s := bufio.NewScanner(b)
    for s.Scan() {
        output = append(output, s.Text())
    }
    return output
}

This function runs the command and returns the output as a slice of strings (one per line of output). Here's an example of calling it:

_ = RunCmd("./moveRobot", []string{"10.20.0.37", localIP.String(), "align"})

In your example, you would call it as:

out = RunCmd("op", []string{"item", "get", "DocSend", "--format=json"})

It is also possible that you need to provide the path to the op binary however, so I would try that (if it's in the same directory, then use ./op

This obviously doesn't return the output in JSON as is, but you can use it as a starting point to at least confirm the call is working.

0
Joris On

This issue was fixed in version 8.10.8 of the 1Password app. You should now be able to run your scripts without any workarounds.