mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 08:23:15 +01:00
* split up sbom.Format into encode and decode ops Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * update cmd pkg to inject format configs Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * bump cyclonedx schema to 1.5 Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * redact image metadata from github encoder tests Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * add more testing around format decoder identify Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * add test case for format version options Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * fix cli tests Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * fix CLI test Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * [wip] - review comments Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * keep encoder creation out of post load function Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * keep decider and identify functions Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * add a few more doc comments Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * remove format encoder default function helpers Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * address PR feedback Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * move back to streaming based decode functions Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * with common convention for encoder constructors Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * fix tests and allow for encoders to be created from cli options Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * fix cli tests Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * fix linting Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * buffer reads from stdin to support seeking Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> --------- Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
294 lines
5.7 KiB
Go
294 lines
5.7 KiB
Go
package options
|
|
|
|
import (
|
|
"io"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/docker/docker/pkg/homedir"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/anchore/syft/syft/sbom"
|
|
)
|
|
|
|
func Test_MakeSBOMWriter(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
outputs []string
|
|
wantErr assert.ErrorAssertionFunc
|
|
}{
|
|
{
|
|
name: "go case",
|
|
outputs: []string{"json"},
|
|
wantErr: assert.NoError,
|
|
},
|
|
{
|
|
name: "multiple",
|
|
outputs: []string{"table", "json"},
|
|
wantErr: assert.NoError,
|
|
},
|
|
{
|
|
name: "unknown format",
|
|
outputs: []string{"unknown"},
|
|
wantErr: func(t assert.TestingT, err error, bla ...interface{}) bool {
|
|
return assert.ErrorContains(t, err, `unsupported output format "unknown", supported formats are:`)
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
opt := DefaultOutput()
|
|
encoders, err := opt.Encoders()
|
|
require.NoError(t, err)
|
|
_, err = makeSBOMWriter(tt.outputs, "", encoders)
|
|
tt.wantErr(t, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func dummyFormat(name string) sbom.FormatEncoder {
|
|
return dummyEncoder{name: name}
|
|
}
|
|
|
|
var _ sbom.FormatEncoder = (*dummyEncoder)(nil)
|
|
|
|
type dummyEncoder struct {
|
|
name string
|
|
}
|
|
|
|
func (d dummyEncoder) ID() sbom.FormatID {
|
|
return sbom.FormatID(d.name)
|
|
}
|
|
|
|
func (d dummyEncoder) Aliases() []string {
|
|
return nil
|
|
}
|
|
|
|
func (d dummyEncoder) Version() string {
|
|
return sbom.AnyVersion
|
|
}
|
|
|
|
func (d dummyEncoder) Encode(writer io.Writer, s sbom.SBOM) error {
|
|
return nil
|
|
}
|
|
|
|
func Test_newSBOMMultiWriter(t *testing.T) {
|
|
type writerConfig struct {
|
|
format string
|
|
file string
|
|
}
|
|
|
|
tmp := t.TempDir()
|
|
|
|
testName := func(options []sbomWriterDescription, err bool) string {
|
|
var out []string
|
|
for _, opt := range options {
|
|
out = append(out, string(opt.Format.ID())+"="+opt.Path)
|
|
}
|
|
errs := ""
|
|
if err {
|
|
errs = "(err)"
|
|
}
|
|
return strings.Join(out, ", ") + errs
|
|
}
|
|
|
|
tests := []struct {
|
|
outputs []sbomWriterDescription
|
|
err bool
|
|
expected []writerConfig
|
|
}{
|
|
{
|
|
outputs: []sbomWriterDescription{},
|
|
err: true,
|
|
},
|
|
{
|
|
outputs: []sbomWriterDescription{
|
|
{
|
|
Format: dummyFormat("table"),
|
|
Path: "",
|
|
},
|
|
},
|
|
expected: []writerConfig{
|
|
{
|
|
format: "table",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
outputs: []sbomWriterDescription{
|
|
{
|
|
Format: dummyFormat("json"),
|
|
},
|
|
},
|
|
expected: []writerConfig{
|
|
{
|
|
format: "json",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
outputs: []sbomWriterDescription{
|
|
{
|
|
Format: dummyFormat("json"),
|
|
Path: "test-2.json",
|
|
},
|
|
},
|
|
expected: []writerConfig{
|
|
{
|
|
format: "json",
|
|
file: "test-2.json",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
outputs: []sbomWriterDescription{
|
|
{
|
|
Format: dummyFormat("json"),
|
|
Path: "test-3/1.json",
|
|
},
|
|
{
|
|
Format: dummyFormat("spdx-json"),
|
|
Path: "test-3/2.json",
|
|
},
|
|
},
|
|
expected: []writerConfig{
|
|
{
|
|
format: "json",
|
|
file: "test-3/1.json",
|
|
},
|
|
{
|
|
format: "spdx-json",
|
|
file: "test-3/2.json",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
outputs: []sbomWriterDescription{
|
|
{
|
|
Format: dummyFormat("text"),
|
|
},
|
|
{
|
|
Format: dummyFormat("spdx-json"),
|
|
Path: "test-4.json",
|
|
},
|
|
},
|
|
expected: []writerConfig{
|
|
{
|
|
format: "text",
|
|
},
|
|
{
|
|
format: "spdx-json",
|
|
file: "test-4.json",
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(testName(test.outputs, test.err), func(t *testing.T) {
|
|
outputs := test.outputs
|
|
for i := range outputs {
|
|
if outputs[i].Path != "" {
|
|
outputs[i].Path = tmp + outputs[i].Path
|
|
}
|
|
}
|
|
|
|
mw, err := newSBOMMultiWriter(outputs...)
|
|
|
|
if test.err {
|
|
assert.Error(t, err)
|
|
return
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
|
|
assert.Len(t, mw.writers, len(test.expected))
|
|
|
|
for i, e := range test.expected {
|
|
switch w := mw.writers[i].(type) {
|
|
case *sbomStreamWriter:
|
|
assert.Equal(t, string(w.format.ID()), e.format)
|
|
assert.NotNil(t, w.out)
|
|
if e.file != "" {
|
|
assert.FileExists(t, tmp+e.file)
|
|
}
|
|
case *sbomPublisher:
|
|
assert.Equal(t, string(w.format.ID()), e.format)
|
|
default:
|
|
t.Fatalf("unknown writer type: %T", w)
|
|
}
|
|
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_newSBOMWriterDescription(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
path string
|
|
expected string
|
|
}{
|
|
{
|
|
name: "expand home dir",
|
|
path: "~/place.txt",
|
|
expected: filepath.Join(homedir.Get(), "place.txt"),
|
|
},
|
|
{
|
|
name: "passthrough other paths",
|
|
path: "/other/place.txt",
|
|
expected: "/other/place.txt",
|
|
},
|
|
{
|
|
name: "no path",
|
|
path: "",
|
|
expected: "",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
o := newSBOMWriterDescription(dummyFormat("table"), tt.path)
|
|
assert.Equal(t, tt.expected, o.Path)
|
|
})
|
|
}
|
|
}
|
|
|
|
func Test_formatVersionOptions(t *testing.T) {
|
|
|
|
tests := []struct {
|
|
name string
|
|
nameVersionPairs []string
|
|
want string
|
|
}{
|
|
{
|
|
name: "gocase",
|
|
nameVersionPairs: []string{
|
|
"cyclonedx-json@1.2", "cyclonedx-json@1.3", "cyclonedx-json@1.4", "cyclonedx-json@1.5",
|
|
"cyclonedx-xml@1.0", "cyclonedx-xml@1.1", "cyclonedx-xml@1.2", "cyclonedx-xml@1.3",
|
|
"cyclonedx-xml@1.4", "cyclonedx-xml@1.5", "github-json", "spdx-json@2.2", "spdx-json@2.3",
|
|
"spdx-tag-value@2.1", "spdx-tag-value@2.2", "spdx-tag-value@2.3", "syft-json@11.0.0",
|
|
"syft-table", "syft-text", "template",
|
|
},
|
|
want: `
|
|
Available formats:
|
|
- cyclonedx-json @ 1.2, 1.3, 1.4, 1.5
|
|
- cyclonedx-xml @ 1.0, 1.1, 1.2, 1.3, 1.4, 1.5
|
|
- github-json
|
|
- spdx-json @ 2.2, 2.3
|
|
- spdx-tag-value @ 2.1, 2.2, 2.3
|
|
- syft-json
|
|
- syft-table
|
|
- syft-text
|
|
- template`,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert.Equal(t, tt.want, formatVersionOptions(tt.nameVersionPairs))
|
|
})
|
|
}
|
|
}
|