Skip to content

Commit

Permalink
allow convert to take stdin (anchore#1570)
Browse files Browse the repository at this point in the history
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
  • Loading branch information
wagoodman authored Feb 14, 2023
1 parent d18d606 commit 64159da
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 17 deletions.
5 changes: 3 additions & 2 deletions cmd/syft/cli/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ import (
)

const (
convertExample = ` {{.appName}} {{.command}} img.syft.json -o spdx-json convert a syft SBOM to spdx-json, output goes to stdout in table format, by default
{{.appName}} {{.command}} img.syft.json -o cyclonedx-json=img.cdx.json convert a syft SBOM to CycloneDX, output goes to a file named img.cdx.json
convertExample = ` {{.appName}} {{.command}} img.syft.json -o spdx-json convert a syft SBOM to spdx-json, output goes to stdout
{{.appName}} {{.command}} img.syft.json -o cyclonedx-json=img.cdx.json convert a syft SBOM to CycloneDX, output is written to the file "img.cdx.json""
{{.appName}} {{.command}} - -o spdx-json convert an SBOM from STDIN to spdx-json
`
)

Expand Down
23 changes: 16 additions & 7 deletions cmd/syft/cli/convert/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package convert
import (
"context"
"fmt"
"io"
"os"

"github.com/anchore/syft/cmd/syft/cli/options"
Expand All @@ -26,15 +27,23 @@ func Run(_ context.Context, app *config.Application, args []string) error {

// this can only be a SBOM file
userInput := args[0]
f, err := os.Open(userInput)
if err != nil {
return fmt.Errorf("failed to open SBOM file: %w", err)

var reader io.ReadCloser

if userInput == "-" {
reader = os.Stdin
} else {
f, err := os.Open(userInput)
if err != nil {
return fmt.Errorf("failed to open SBOM file: %w", err)
}
defer func() {
_ = f.Close()
}()
reader = f
}
defer func() {
_ = f.Close()
}()

sbom, _, err := formats.Decode(f)
sbom, _, err := formats.Decode(reader)
if err != nil {
return fmt.Errorf("failed to decode SBOM: %w", err)
}
Expand Down
9 changes: 2 additions & 7 deletions test/cli/all_formats_convertible_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,9 @@ import (
"github.com/stretchr/testify/require"
)

func TestConvertCmdFlags(t *testing.T) {
func TestAllFormatsConvertable(t *testing.T) {
assertions := []traitAssertion{
func(tb testing.TB, stdout, _ string, _ int) {
tb.Helper()
if len(stdout) < 1000 {
tb.Errorf("there may not be any report output (len=%d)", len(stdout))
}
},
assertStdoutLengthGreaterThan(1000),
assertSuccessfulReturnCode,
}

Expand Down
50 changes: 50 additions & 0 deletions test/cli/convert_cmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package cli

import (
"fmt"
"strings"
"testing"
)

func TestConvertCmd(t *testing.T) {
assertions := []traitAssertion{
assertInOutput("PackageName: musl-utils"),
assertSuccessfulReturnCode,
}

tests := []struct {
from string
to string
}{
{from: "syft-json", to: "spdx-tag-value"},
}

for _, test := range tests {
t.Run(fmt.Sprintf("from %s to %s", test.from, test.to), func(t *testing.T) {
sbomArgs := []string{"dir:./test-fixtures/image-pkg-coverage", "-o", test.from}
cmd, stdout, stderr := runSyft(t, nil, sbomArgs...)
if cmd.ProcessState.ExitCode() != 0 {
t.Log("STDOUT:\n", stdout)
t.Log("STDERR:\n", stderr)
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
t.Fatalf("failure executing syft creating an sbom")
return
}

convertArgs := []string{"convert", "-", "-o", test.to}
cmd = getSyftCommand(t, convertArgs...)

cmd.Stdin = strings.NewReader(stdout)
stdout, stderr = runCommandObj(t, cmd, nil, false)

for _, traitFn := range assertions {
traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode())
}
if t.Failed() {
t.Log("STDOUT:\n", stdout)
t.Log("STDERR:\n", stderr)
t.Log("COMMAND:", strings.Join(cmd.Args, " "))
}
})
}
}
44 changes: 43 additions & 1 deletion test/cli/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ func runSyftCommand(t testing.TB, env map[string]string, expectError bool, args
t.Errorf("STDOUT: %s", stdout)
t.Errorf("STDERR: %s", stderr)

// this probably indicates a timeout
// this probably indicates a timeout... lets run it again with more verbosity to help debug issues
args = append(args, "-vv")
cmd = getSyftCommand(t, args...)

Expand All @@ -194,6 +194,48 @@ func runSyftCommand(t testing.TB, env map[string]string, expectError bool, args
return cmd, stdout, stderr
}

func runCommandObj(t testing.TB, cmd *exec.Cmd, env map[string]string, expectError bool) (string, string) {
cancel := make(chan bool, 1)
defer func() {
cancel <- true
}()

if env == nil {
env = make(map[string]string)
}

// we should not have tests reaching out for app update checks
env["SYFT_CHECK_FOR_APP_UPDATE"] = "false"

timeout := func() {
select {
case <-cancel:
return
case <-time.After(60 * time.Second):
}

if cmd != nil && cmd.Process != nil {
// get a stack trace printed
err := cmd.Process.Signal(syscall.SIGABRT)
if err != nil {
t.Errorf("error aborting: %+v", err)
}
}
}

go timeout()

stdout, stderr, err := runCommand(cmd, env)

if !expectError && err != nil && stdout == "" {
t.Errorf("error running syft: %+v", err)
t.Errorf("STDOUT: %s", stdout)
t.Errorf("STDERR: %s", stderr)
}

return stdout, stderr
}

func runCosign(t testing.TB, env map[string]string, args ...string) (*exec.Cmd, string, string) {
cmd := getCommand(t, ".tmp/cosign", args...)
if env == nil {
Expand Down

0 comments on commit 64159da

Please sign in to comment.