Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exec cmd failed silently #151

Open
huydinhle opened this issue Dec 6, 2022 · 14 comments
Open

Exec cmd failed silently #151

huydinhle opened this issue Dec 6, 2022 · 14 comments

Comments

@huydinhle
Copy link

huydinhle commented Dec 6, 2022

I'm trying to execute a onepassword cli command and it doesn't work even though exit code return 0

func main() {
	cmd := "op item create --format=json --vault=<REDACTED> --category=\"API Credential\" --title=test credentials=secretivepassword notes=lala "
	p := script.Exec(cmd)
	//p.Wait()
	num, err := p.Stdout()
	if err != nil {
		log.Fatal().Err(err).Msg("failed at executing")
	}
	log.Info().Int("num", int(num)).Msg("output")
}

If I add p.Wait() in there I will get error which is

{"level":"fatal","error":"io: read/write on closed pipe","time":"2022-12-05T22:23:03-08:00","message":"failed at executing"}

How can I debug or fix this?

If I copied the exact thing into my terminal, it would work correctly.

@huydinhle
Copy link
Author

huydinhle commented Dec 6, 2022

If I use the exec command, then it works properly

func main() {
	out, errout, err := Shellout("op item create --format=json --vault=<REDACTED> --category=\"API Credential\" --title=test credentials=secretivepassword notes=lala ")
	if err != nil {
		log.Info().Err(err)
	}
	fmt.Println("--- stdout ---")
	fmt.Println(out)
	fmt.Println("--- stderr ---")
	fmt.Println(errout)
}

const ShellToUse = "bash"

func Shellout(command string) (string, string, error) {
	var stdout bytes.Buffer
	var stderr bytes.Buffer
	cmd := exec.Command(ShellToUse, "-c", command)
	cmd.Stdout = &stdout
	cmd.Stderr = &stderr
	err := cmd.Run()
	return stdout.String(), stderr.String(), err
}

@bitfield
Copy link
Owner

bitfield commented Dec 6, 2022

p.Wait() waits for the command to finish, throws its output away, and then closes the pipe, which explains why you can't then call Stdout() on it—there's nothing left to write to stdout!

When you say "it doesn't work even though exit code return 0", what do you mean? What does the program print to stdout? If the op command prints an error message, you should see that.

@huydinhle
Copy link
Author

@bitfield I tried adding p.Wait() to see if it has anything to do with the pipe not finishing.

However, if there is no p.Wait involved, script would just exit 0 with nothing on Stdout. 🤷 . If I send the exact cmd into the exec instead of script then it gives the correct output with 0 exit code.

@bitfield
Copy link
Owner

bitfield commented Dec 6, 2022

I think you're running into #148 here—clearly the program is returning some error, but we're not seeing it. Let me check back with you here once that issue is fixed, and we'll see if that sheds any light on the problem.

@bitfield
Copy link
Owner

bitfield commented Dec 7, 2022

Could you check your program against script v0.21.4 and see if it now works as expected? (Or at least, if it doesn't, that you can see any error reported by the op command.)

@huydinhle
Copy link
Author

huydinhle commented Dec 7, 2022

@bitfield This is very interesting. It might have something to do with onepassword cli. I tried this script version and still the same problem

package main

import (
	"github.com/bitfield/script"
	"github.com/rs/zerolog/log"
)

func main() {
	cmd := `op item create`
	p := script.Exec(cmd)
	exitCode, err := p.Stdout()
	if err != nil {
		log.Fatal().Err(err).Msg("failed at executing")
	}
	log.Info().Int("num", int(exitCode)).Msg("output")
}

Output with go run main.go

{"level":"info","num":0,"time":"2022-12-07T08:42:16-08:00","message":"output"}

and If I run this with just my terminal this is what I got

❯ op item create
[ERROR] 2022/12/07 08:44:30 Provide the item category with '--category' flag

@huydinhle
Copy link
Author

you can easily reproduce this by install onepassword cli

https://developer.1password.com/docs/cli/get-started/

On mac you do

brew install --cask 1password/tap/1password-cli
op --version

@huydinhle
Copy link
Author

ping! @bitfield, Is there any update on this bug? Here is the minimal code to reproduce it, and the output using the op cli in the terminal vs using script package. Tried to debug it this for a while to see what's wrong but I cannot figure it out

minimal code to reproduce

package main

import (
	"github.com/bitfield/script"
	"github.com/rs/zerolog/log"
)

func main() {
	cmd := `op item create`
	p := script.Exec(cmd)
	exitCode, err := p.Match("hello").Stdout()
	if err != nil {
		log.Fatal().Err(err).Msg("failed at executing")
	}
	log.Info().Int("num", int(exitCode)).Msg("output")

}

op cli output in terminal

❯ op item create
[ERROR] 2022/12/08 09:31:09 You are not currently signed in. Please run `op signin --help` for instructions

script package output

❯ go run main.go
{"level":"info","num":0,"time":"2022-12-08T09:31:38-08:00","message":"output"}

Notes: bitfield/script exit 0 as if there is no error

@bitfield
Copy link
Owner

bitfield commented Dec 8, 2022

I don't have anything useful for you at the moment; I can point out a couple of problems with your program, though.

  1. The p.Match("hello") stage will automatically filter out any output lines from op that don't contain "hello". That's probably not what you want if you want to see any error message printed by the command.
  2. The first value returned by Stdout is not the exit status, but the number of bytes successfully written to the output. You can get the exit status of the last Exec command run by the pipe with ExitStatus:
func main() {
	cmd := `op whoami`
	p := script.Exec(cmd)
	_, err := p.Stdout()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(p.ExitStatus())
}

For me, this prints:

[ERROR] 2022/12/08 18:03:38 no account found for filter 
2022/12/08 18:03:38 exit status 1
exit status 1

... which is roughly what I'd expect. I can't try op item create because it prompts me to link to an account, but I don't have one. But see what the above program produces for you when you run op item create.

@huydinhle
Copy link
Author

huydinhle commented Dec 8, 2022

@bitfield my bad on this. you don't need to do the match, and you do not need to login to reproduce it. The whole point is to not login and run this exact program and see script exit 0 instead of erroring out

package main

import (
	"github.com/bitfield/script"
	"github.com/rs/zerolog/log"
)

func main() {
	cmd := `op item create`
	exitCode, err := script.Exec(cmd).Stdout()
	if err != nil {
		log.Fatal().Err(err).Msg("failed at executing")
	}
	log.Info().Int("num", int(exitCode)).Msg("output")

}

{"level":"info","num":0,"time":"2022-12-08T10:11:32-08:00","message":"output"}

@huydinhle
Copy link
Author

@bitfield script should have been erroring out like the op command did like this


❯ op item create
[ERROR] 2022/12/08 10:14:09 You are not currently signed in. Please run `op signin --help` for instructions

@bitfield
Copy link
Owner

bitfield commented Dec 8, 2022

Yes, it looks as though the op item create command is returning zero exit status and producing no output in this case, doesn’t it? I have no idea why that would be—is the source for that tool available?

Evidently op whoami does return a non-zero status and print its error, as expected, and script handles that correctly. So if this is a bug in script itself, I’m puzzled about what it could be.

@huydinhle
Copy link
Author

@bitfield true, true . yeah you can close this if you want. Pretty sure this is a op problem. Thank you for answering all the questions

@bitfield
Copy link
Owner

bitfield commented Dec 9, 2022

I'll leave it open for now just in case anyone else has problems with automating op and comes here to find out why! This is something I'd raise with the OnePassword support team, since presumably their tool is meant to work correctly in this situation, but doesn't.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants