Fix reading syft json from stdin by redirect (#1299)

I figured out that running `cat syft.json | grype` works but
`grype < syft.json` does not work. This happens, because the
IsPipedInput method only checks if stdin is a pipe which will be false
if stdin is fed by a redirect.

The go idiomatic way to fix this is by just checking if the file
produced by stat has a size > 0.

Implemented this check, that will recognize stdin by redirect, in the
IsPipedInput() method. Renamed the method to IsStdinPipeOrRedirect().

Signed-off-by: Felix Becker <git@felixbecker.name>
Co-authored-by: Benjamin Neff <benjamin@coding4coffee.ch>
This commit is contained in:
devfbe 2023-05-16 21:41:43 +02:00 committed by GitHub
parent d74e85385c
commit e1bdbc7d27
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 10 additions and 10 deletions

View file

@ -283,14 +283,14 @@ func rootExec(_ *cobra.Command, args []string) error {
}
func isVerbose() (result bool) {
isPipedInput, err := internal.IsPipedInput()
isStdinPipeOrRedirect, err := internal.IsStdinPipeOrRedirect()
if err != nil {
// since we can't tell if there was piped input we assume that there could be to disable the ETUI
log.Warnf("unable to determine if there is piped input: %+v", err)
return true
}
// verbosity should consider if there is piped input (in which case we should not show the ETUI)
return appConfig.CliOptions.Verbosity > 0 || isPipedInput
return appConfig.CliOptions.Verbosity > 0 || isStdinPipeOrRedirect
}
//nolint:funlen
@ -502,13 +502,13 @@ func validateDBLoad(loadErr error, status *db.Status) error {
}
func validateRootArgs(cmd *cobra.Command, args []string) error {
isPipedInput, err := internal.IsPipedInput()
isStdinPipeOrRedirect, err := internal.IsStdinPipeOrRedirect()
if err != nil {
log.Warnf("unable to determine if there is piped input: %+v", err)
isPipedInput = false
isStdinPipeOrRedirect = false
}
if len(args) == 0 && !isPipedInput {
if len(args) == 0 && !isStdinPipeOrRedirect {
// in the case that no arguments are given and there is no piped input we want to show the help text and return with a non-0 return code.
if err := cmd.Help(); err != nil {
return fmt.Errorf("unable to display help: %w", err)

View file

@ -142,13 +142,13 @@ func fileHasContent(f *os.File) bool {
}
func stdinReader() io.Reader {
isPipedInput, err := internal.IsPipedInput()
isStdinPipeOrRedirect, err := internal.IsStdinPipeOrRedirect()
if err != nil {
log.Warnf("unable to determine if there is piped input: %+v", err)
return nil
}
if !isPipedInput {
if !isStdinPipeOrRedirect {
return nil
}

View file

@ -5,8 +5,8 @@ import (
"os"
)
// IsPipedInput returns true if there is no input device, which means the user **may** be providing input via a pipe.
func IsPipedInput() (bool, error) {
// IsStdinPipeOrRedirect returns true if stdin is provided via pipe or redirect
func IsStdinPipeOrRedirect() (bool, error) {
fi, err := os.Stdin.Stat()
if err != nil {
return false, fmt.Errorf("unable to determine if there is piped input: %w", err)
@ -16,5 +16,5 @@ func IsPipedInput() (bool, error) {
// on stdin, as running grype as a subprocess you would expect no character device to be present but input can
// be from either stdin or indicated by the CLI. Checking if stdin is a pipe is the most direct way to determine
// if there *may* be bytes that will show up on stdin that should be used for the analysis source.
return fi.Mode()&os.ModeNamedPipe != 0, nil
return fi.Mode()&os.ModeNamedPipe != 0 || fi.Size() > 0, nil
}