mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 08:23:15 +01:00
Add "pretty" json configuration and change default behavior to be space-efficient (#2275)
* expose underlying format options Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * remove escape html options and address PR feedback Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * incorporate PR feedback Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * fix cli test Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> --------- Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com>
This commit is contained in:
parent
7cfb5f630a
commit
1676934c63
28
README.md
28
README.md
@ -537,9 +537,16 @@ catalogers:
|
|||||||
# all format configuration
|
# all format configuration
|
||||||
format:
|
format:
|
||||||
|
|
||||||
|
# default value for all formats that support the "pretty" option (default is unset)
|
||||||
|
pretty:
|
||||||
|
|
||||||
# all syft-json format options
|
# all syft-json format options
|
||||||
json:
|
json:
|
||||||
|
|
||||||
|
# include space indention and newlines (inherits default value from 'format.pretty' or 'false' if parent is unset)
|
||||||
|
# note: inherits default value from 'format.pretty' or 'false' if parent is unset
|
||||||
|
pretty: false
|
||||||
|
|
||||||
# transform any syft-json output to conform to an approximation of the v11.0.1 schema. This includes:
|
# transform any syft-json output to conform to an approximation of the v11.0.1 schema. This includes:
|
||||||
# - using the package metadata type names from before v12 of the JSON schema (changed in https://github.com/anchore/syft/pull/1983)
|
# - using the package metadata type names from before v12 of the JSON schema (changed in https://github.com/anchore/syft/pull/1983)
|
||||||
#
|
#
|
||||||
@ -557,6 +564,27 @@ format:
|
|||||||
# same as -t ; SYFT_TEMPLATE_PATH env var
|
# same as -t ; SYFT_TEMPLATE_PATH env var
|
||||||
path: ""
|
path: ""
|
||||||
|
|
||||||
|
# all spdx-json format options
|
||||||
|
spdx-json:
|
||||||
|
|
||||||
|
# include space indention and newlines
|
||||||
|
# note: inherits default value from 'format.pretty' or 'false' if parent is unset
|
||||||
|
pretty: false
|
||||||
|
|
||||||
|
# all cyclonedx-json format options
|
||||||
|
cyclonedx-json:
|
||||||
|
|
||||||
|
# include space indention and newlines
|
||||||
|
# note: inherits default value from 'format.pretty' or 'false' if parent is unset
|
||||||
|
pretty: false
|
||||||
|
|
||||||
|
# all cyclonedx-xml format options
|
||||||
|
cyclonedx-xml:
|
||||||
|
|
||||||
|
# include space indention
|
||||||
|
# note: inherits default value from 'format.pretty' or 'false' if parent is unset
|
||||||
|
pretty: false
|
||||||
|
|
||||||
|
|
||||||
# cataloging packages is exposed through the packages and power-user subcommands
|
# cataloging packages is exposed through the packages and power-user subcommands
|
||||||
package:
|
package:
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
package options
|
package options
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
|
|
||||||
|
"github.com/anchore/clio"
|
||||||
"github.com/anchore/syft/syft/format/cyclonedxjson"
|
"github.com/anchore/syft/syft/format/cyclonedxjson"
|
||||||
"github.com/anchore/syft/syft/format/cyclonedxxml"
|
"github.com/anchore/syft/syft/format/cyclonedxxml"
|
||||||
"github.com/anchore/syft/syft/format/github"
|
"github.com/anchore/syft/syft/format/github"
|
||||||
@ -13,16 +18,34 @@ import (
|
|||||||
"github.com/anchore/syft/syft/sbom"
|
"github.com/anchore/syft/syft/sbom"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var _ clio.PostLoader = (*Format)(nil)
|
||||||
|
|
||||||
// Format contains all user configuration for output formatting.
|
// Format contains all user configuration for output formatting.
|
||||||
type Format struct {
|
type Format struct {
|
||||||
|
Pretty *bool `yaml:"pretty" json:"pretty" mapstructure:"pretty"`
|
||||||
Template FormatTemplate `yaml:"template" json:"template" mapstructure:"template"`
|
Template FormatTemplate `yaml:"template" json:"template" mapstructure:"template"`
|
||||||
JSON FormatJSON `yaml:"json" json:"json" mapstructure:"json"`
|
SyftJSON FormatSyftJSON `yaml:"json" json:"json" mapstructure:"json"`
|
||||||
|
SPDXJSON FormatSPDXJSON `yaml:"spdx-json" json:"spdx-json" mapstructure:"spdx-json"`
|
||||||
|
CyclonedxJSON FormatCyclonedxJSON `yaml:"cyclonedx-json" json:"cyclonedx-json" mapstructure:"cyclonedx-json"`
|
||||||
|
CyclonedxXML FormatCyclonedxXML `yaml:"cyclonedx-xml" json:"cyclonedx-xml" mapstructure:"cyclonedx-xml"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Format) PostLoad() error {
|
||||||
|
o.SyftJSON.Pretty = multiLevelOption[bool](false, o.Pretty, o.SyftJSON.Pretty)
|
||||||
|
o.SPDXJSON.Pretty = multiLevelOption[bool](false, o.Pretty, o.SPDXJSON.Pretty)
|
||||||
|
o.CyclonedxJSON.Pretty = multiLevelOption[bool](false, o.Pretty, o.CyclonedxJSON.Pretty)
|
||||||
|
o.CyclonedxXML.Pretty = multiLevelOption[bool](false, o.Pretty, o.CyclonedxXML.Pretty)
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DefaultFormat() Format {
|
func DefaultFormat() Format {
|
||||||
return Format{
|
return Format{
|
||||||
Template: DefaultFormatTemplate(),
|
Template: DefaultFormatTemplate(),
|
||||||
JSON: DefaultFormatJSON(),
|
SyftJSON: DefaultFormatJSON(),
|
||||||
|
SPDXJSON: DefaultFormatSPDXJSON(),
|
||||||
|
CyclonedxJSON: DefaultFormatCyclonedxJSON(),
|
||||||
|
CyclonedxXML: DefaultFormatCyclonedxXML(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,14 +55,75 @@ func (o *Format) Encoders() ([]sbom.FormatEncoder, error) {
|
|||||||
|
|
||||||
// in the future there will be application configuration options that can be used to set the default output format
|
// in the future there will be application configuration options that can be used to set the default output format
|
||||||
list.addWithErr(template.ID)(o.Template.formatEncoders())
|
list.addWithErr(template.ID)(o.Template.formatEncoders())
|
||||||
list.addWithErr(syftjson.ID)(o.JSON.formatEncoders())
|
list.addWithErr(syftjson.ID)(o.SyftJSON.formatEncoders())
|
||||||
list.add(table.ID)(table.NewFormatEncoder())
|
list.add(table.ID)(table.NewFormatEncoder())
|
||||||
list.add(text.ID)(text.NewFormatEncoder())
|
list.add(text.ID)(text.NewFormatEncoder())
|
||||||
list.add(github.ID)(github.NewFormatEncoder())
|
list.add(github.ID)(github.NewFormatEncoder())
|
||||||
list.addWithErr(cyclonedxxml.ID)(cycloneDxXMLEncoders())
|
list.addWithErr(cyclonedxxml.ID)(o.CyclonedxXML.formatEncoders())
|
||||||
list.addWithErr(cyclonedxjson.ID)(cycloneDxJSONEncoders())
|
list.addWithErr(cyclonedxjson.ID)(o.CyclonedxJSON.formatEncoders())
|
||||||
list.addWithErr(spdxjson.ID)(spdxJSONEncoders())
|
list.addWithErr(spdxjson.ID)(o.SPDXJSON.formatEncoders())
|
||||||
list.addWithErr(spdxtagvalue.ID)(spdxTagValueEncoders())
|
list.addWithErr(spdxtagvalue.ID)(spdxTagValueEncoders())
|
||||||
|
|
||||||
return list.encoders, list.err
|
return list.encoders, list.err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: when application configuration is made for this format then this should be ported to the options object
|
||||||
|
// that is created for that configuration (as done with the template output option)
|
||||||
|
func spdxTagValueEncoders() ([]sbom.FormatEncoder, error) {
|
||||||
|
var (
|
||||||
|
encs []sbom.FormatEncoder
|
||||||
|
errs error
|
||||||
|
)
|
||||||
|
for _, v := range spdxtagvalue.SupportedVersions() {
|
||||||
|
enc, err := spdxtagvalue.NewFormatEncoderWithConfig(spdxtagvalue.EncoderConfig{Version: v})
|
||||||
|
if err != nil {
|
||||||
|
errs = multierror.Append(errs, err)
|
||||||
|
} else {
|
||||||
|
encs = append(encs, enc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return encs, errs
|
||||||
|
}
|
||||||
|
|
||||||
|
type encoderList struct {
|
||||||
|
encoders []sbom.FormatEncoder
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *encoderList) addWithErr(name sbom.FormatID) func([]sbom.FormatEncoder, error) {
|
||||||
|
return func(encs []sbom.FormatEncoder, err error) {
|
||||||
|
if err != nil {
|
||||||
|
l.err = multierror.Append(l.err, fmt.Errorf("unable to configure %q format encoder: %w", name, err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
for _, enc := range encs {
|
||||||
|
if enc == nil {
|
||||||
|
l.err = multierror.Append(l.err, fmt.Errorf("unable to configure %q format encoder: nil encoder returned", name))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
l.encoders = append(l.encoders, enc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *encoderList) add(name sbom.FormatID) func(...sbom.FormatEncoder) {
|
||||||
|
return func(encs ...sbom.FormatEncoder) {
|
||||||
|
for _, enc := range encs {
|
||||||
|
if enc == nil {
|
||||||
|
l.err = multierror.Append(l.err, fmt.Errorf("unable to configure %q format encoder: nil encoder returned", name))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
l.encoders = append(l.encoders, enc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func multiLevelOption[T any](defaultValue T, option ...*T) *T {
|
||||||
|
result := defaultValue
|
||||||
|
for _, opt := range option {
|
||||||
|
if opt != nil {
|
||||||
|
result = *opt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &result
|
||||||
|
}
|
||||||
|
|||||||
39
cmd/syft/cli/options/format_cyclonedx_json.go
Normal file
39
cmd/syft/cli/options/format_cyclonedx_json.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/format/cyclonedxjson"
|
||||||
|
"github.com/anchore/syft/syft/sbom"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FormatCyclonedxJSON struct {
|
||||||
|
Pretty *bool `yaml:"pretty" json:"pretty" mapstructure:"pretty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultFormatCyclonedxJSON() FormatCyclonedxJSON {
|
||||||
|
return FormatCyclonedxJSON{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o FormatCyclonedxJSON) formatEncoders() ([]sbom.FormatEncoder, error) {
|
||||||
|
var (
|
||||||
|
encs []sbom.FormatEncoder
|
||||||
|
errs error
|
||||||
|
)
|
||||||
|
for _, v := range cyclonedxjson.SupportedVersions() {
|
||||||
|
enc, err := cyclonedxjson.NewFormatEncoderWithConfig(o.buildConfig(v))
|
||||||
|
if err != nil {
|
||||||
|
errs = multierror.Append(errs, err)
|
||||||
|
} else {
|
||||||
|
encs = append(encs, enc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return encs, errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o FormatCyclonedxJSON) buildConfig(version string) cyclonedxjson.EncoderConfig {
|
||||||
|
return cyclonedxjson.EncoderConfig{
|
||||||
|
Version: version,
|
||||||
|
Pretty: *o.Pretty,
|
||||||
|
}
|
||||||
|
}
|
||||||
67
cmd/syft/cli/options/format_cyclonedx_json_test.go
Normal file
67
cmd/syft/cli/options/format_cyclonedx_json_test.go
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
package options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFormatCyclonedxJSON_buildConfig(t *testing.T) {
|
||||||
|
// assert when building the config that we respond to all possible fields
|
||||||
|
|
||||||
|
ft := &FormatCyclonedxJSON{}
|
||||||
|
ft = setAllToNonZero(t, ft).(*FormatCyclonedxJSON)
|
||||||
|
|
||||||
|
subject := ft.buildConfig("Version")
|
||||||
|
assertExpectedValue(t, subject)
|
||||||
|
}
|
||||||
|
|
||||||
|
func setAllToNonZero(t testing.TB, structPtr any) any {
|
||||||
|
// set all fields on the struct to non-zero values
|
||||||
|
rt := reflect.TypeOf(structPtr)
|
||||||
|
if rt.Kind() != reflect.Ptr || rt.Elem().Kind() != reflect.Struct {
|
||||||
|
t.Fatal("expected a pointer to a struct")
|
||||||
|
}
|
||||||
|
|
||||||
|
rv := reflect.ValueOf(structPtr).Elem()
|
||||||
|
for i := 0; i < rt.Elem().NumField(); i++ {
|
||||||
|
val := getNonZeroExampleValue(t, rv.Field(i).Interface(), rt.Elem().Field(i).Name)
|
||||||
|
rv.Field(i).Set(reflect.ValueOf(val))
|
||||||
|
}
|
||||||
|
return structPtr
|
||||||
|
}
|
||||||
|
|
||||||
|
func getNonZeroExampleValue(t testing.TB, v any, name string) any {
|
||||||
|
switch v.(type) {
|
||||||
|
case bool:
|
||||||
|
return true
|
||||||
|
case *bool:
|
||||||
|
val := true
|
||||||
|
return &val
|
||||||
|
case string:
|
||||||
|
return name
|
||||||
|
}
|
||||||
|
t.Fatalf("unsupported type: %T", v)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func assertExpectedValue(t *testing.T, structTy any) {
|
||||||
|
rt := reflect.TypeOf(structTy)
|
||||||
|
rv := reflect.ValueOf(structTy)
|
||||||
|
|
||||||
|
for i := 0; i < rt.NumField(); i++ {
|
||||||
|
f := rt.Field(i)
|
||||||
|
fieldValue := rv.Field(i)
|
||||||
|
|
||||||
|
if fieldValue.Type().Kind() == reflect.String {
|
||||||
|
// use the field name as the expected value
|
||||||
|
assert.Equalf(t, f.Name, fieldValue.String(), "field %q value differs", f.Name)
|
||||||
|
} else {
|
||||||
|
// use the zero value for the type
|
||||||
|
if reflect.DeepEqual(fieldValue.Interface(), reflect.Zero(fieldValue.Type()).Interface()) {
|
||||||
|
t.Errorf("field '%s' is zero", f.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
39
cmd/syft/cli/options/format_cyclonedx_xml.go
Normal file
39
cmd/syft/cli/options/format_cyclonedx_xml.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/format/cyclonedxxml"
|
||||||
|
"github.com/anchore/syft/syft/sbom"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FormatCyclonedxXML struct {
|
||||||
|
Pretty *bool `yaml:"pretty" json:"pretty" mapstructure:"pretty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultFormatCyclonedxXML() FormatCyclonedxXML {
|
||||||
|
return FormatCyclonedxXML{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o FormatCyclonedxXML) formatEncoders() ([]sbom.FormatEncoder, error) {
|
||||||
|
var (
|
||||||
|
encs []sbom.FormatEncoder
|
||||||
|
errs error
|
||||||
|
)
|
||||||
|
for _, v := range cyclonedxxml.SupportedVersions() {
|
||||||
|
enc, err := cyclonedxxml.NewFormatEncoderWithConfig(o.buildConfig(v))
|
||||||
|
if err != nil {
|
||||||
|
errs = multierror.Append(errs, err)
|
||||||
|
} else {
|
||||||
|
encs = append(encs, enc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return encs, errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o FormatCyclonedxXML) buildConfig(version string) cyclonedxxml.EncoderConfig {
|
||||||
|
return cyclonedxxml.EncoderConfig{
|
||||||
|
Version: version,
|
||||||
|
Pretty: *o.Pretty,
|
||||||
|
}
|
||||||
|
}
|
||||||
15
cmd/syft/cli/options/format_cyclonedx_xml_test.go
Normal file
15
cmd/syft/cli/options/format_cyclonedx_xml_test.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFormatCyclonedxXML_buildConfig(t *testing.T) {
|
||||||
|
// assert when building the config that we respond to all possible fields
|
||||||
|
|
||||||
|
ft := FormatCyclonedxXML{}
|
||||||
|
ftp := setAllToNonZero(t, &ft).(*FormatCyclonedxXML)
|
||||||
|
|
||||||
|
subject := ftp.buildConfig("Version")
|
||||||
|
assertExpectedValue(t, subject)
|
||||||
|
}
|
||||||
@ -1,25 +0,0 @@
|
|||||||
package options
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/anchore/syft/syft/format/syftjson"
|
|
||||||
"github.com/anchore/syft/syft/sbom"
|
|
||||||
)
|
|
||||||
|
|
||||||
type FormatJSON struct {
|
|
||||||
Legacy bool `yaml:"legacy" json:"legacy" mapstructure:"legacy"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func DefaultFormatJSON() FormatJSON {
|
|
||||||
return FormatJSON{
|
|
||||||
Legacy: false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o FormatJSON) formatEncoders() ([]sbom.FormatEncoder, error) {
|
|
||||||
enc, err := syftjson.NewFormatEncoderWithConfig(
|
|
||||||
syftjson.EncoderConfig{
|
|
||||||
Legacy: o.Legacy,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
return []sbom.FormatEncoder{enc}, err
|
|
||||||
}
|
|
||||||
39
cmd/syft/cli/options/format_spdx_json.go
Normal file
39
cmd/syft/cli/options/format_spdx_json.go
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
package options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/format/spdxjson"
|
||||||
|
"github.com/anchore/syft/syft/sbom"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FormatSPDXJSON struct {
|
||||||
|
Pretty *bool `yaml:"pretty" json:"pretty" mapstructure:"pretty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultFormatSPDXJSON() FormatSPDXJSON {
|
||||||
|
return FormatSPDXJSON{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o FormatSPDXJSON) formatEncoders() ([]sbom.FormatEncoder, error) {
|
||||||
|
var (
|
||||||
|
encs []sbom.FormatEncoder
|
||||||
|
errs error
|
||||||
|
)
|
||||||
|
for _, v := range spdxjson.SupportedVersions() {
|
||||||
|
enc, err := spdxjson.NewFormatEncoderWithConfig(o.buildConfig(v))
|
||||||
|
if err != nil {
|
||||||
|
errs = multierror.Append(errs, err)
|
||||||
|
} else {
|
||||||
|
encs = append(encs, enc)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return encs, errs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o FormatSPDXJSON) buildConfig(v string) spdxjson.EncoderConfig {
|
||||||
|
return spdxjson.EncoderConfig{
|
||||||
|
Version: v,
|
||||||
|
Pretty: *o.Pretty,
|
||||||
|
}
|
||||||
|
}
|
||||||
15
cmd/syft/cli/options/format_spdx_json_test.go
Normal file
15
cmd/syft/cli/options/format_spdx_json_test.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFormatSPDXJSON_buildConfig(t *testing.T) {
|
||||||
|
// assert when building the config that we respond to all possible fields
|
||||||
|
|
||||||
|
ft := &FormatSPDXJSON{}
|
||||||
|
ft = setAllToNonZero(t, ft).(*FormatSPDXJSON)
|
||||||
|
|
||||||
|
subject := ft.buildConfig("Version")
|
||||||
|
assertExpectedValue(t, subject)
|
||||||
|
}
|
||||||
29
cmd/syft/cli/options/format_syft_json.go
Normal file
29
cmd/syft/cli/options/format_syft_json.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anchore/syft/syft/format/syftjson"
|
||||||
|
"github.com/anchore/syft/syft/sbom"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FormatSyftJSON struct {
|
||||||
|
Legacy bool `yaml:"legacy" json:"legacy" mapstructure:"legacy"`
|
||||||
|
Pretty *bool `yaml:"pretty" json:"pretty" mapstructure:"pretty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultFormatJSON() FormatSyftJSON {
|
||||||
|
return FormatSyftJSON{
|
||||||
|
Legacy: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o FormatSyftJSON) formatEncoders() ([]sbom.FormatEncoder, error) {
|
||||||
|
enc, err := syftjson.NewFormatEncoderWithConfig(o.buildConfig())
|
||||||
|
return []sbom.FormatEncoder{enc}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o FormatSyftJSON) buildConfig() syftjson.EncoderConfig {
|
||||||
|
return syftjson.EncoderConfig{
|
||||||
|
Legacy: o.Legacy,
|
||||||
|
Pretty: *o.Pretty,
|
||||||
|
}
|
||||||
|
}
|
||||||
15
cmd/syft/cli/options/format_syft_json_test.go
Normal file
15
cmd/syft/cli/options/format_syft_json_test.go
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
package options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFormatSyftJSON_buildConfig(t *testing.T) {
|
||||||
|
// assert when building the config that we respond to all possible fields
|
||||||
|
|
||||||
|
ft := &FormatSyftJSON{}
|
||||||
|
ft = setAllToNonZero(t, ft).(*FormatSyftJSON)
|
||||||
|
|
||||||
|
subject := ft.buildConfig()
|
||||||
|
assertExpectedValue(t, subject)
|
||||||
|
}
|
||||||
@ -46,6 +46,17 @@ func DefaultOutput() Output {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Output) PostLoad() error {
|
||||||
|
var errs error
|
||||||
|
for _, loader := range []clio.PostLoader{&o.OutputFile, &o.Format} {
|
||||||
|
if err := loader.PostLoad(); err != nil {
|
||||||
|
errs = multierror.Append(errs, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return errs
|
||||||
|
}
|
||||||
|
|
||||||
func (o *Output) AddFlags(flags clio.FlagSet) {
|
func (o *Output) AddFlags(flags clio.FlagSet) {
|
||||||
var names []string
|
var names []string
|
||||||
for _, id := range supportedIDs() {
|
for _, id := range supportedIDs() {
|
||||||
@ -88,111 +99,6 @@ func (o Output) OutputNameSet() *strset.Set {
|
|||||||
return names
|
return names
|
||||||
}
|
}
|
||||||
|
|
||||||
type encoderList struct {
|
|
||||||
encoders []sbom.FormatEncoder
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *encoderList) addWithErr(name sbom.FormatID) func([]sbom.FormatEncoder, error) {
|
|
||||||
return func(encs []sbom.FormatEncoder, err error) {
|
|
||||||
if err != nil {
|
|
||||||
l.err = multierror.Append(l.err, fmt.Errorf("unable to configure %q format encoder: %w", name, err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
for _, enc := range encs {
|
|
||||||
if enc == nil {
|
|
||||||
l.err = multierror.Append(l.err, fmt.Errorf("unable to configure %q format encoder: nil encoder returned", name))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
l.encoders = append(l.encoders, enc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (l *encoderList) add(name sbom.FormatID) func(...sbom.FormatEncoder) {
|
|
||||||
return func(encs ...sbom.FormatEncoder) {
|
|
||||||
for _, enc := range encs {
|
|
||||||
if enc == nil {
|
|
||||||
l.err = multierror.Append(l.err, fmt.Errorf("unable to configure %q format encoder: nil encoder returned", name))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
l.encoders = append(l.encoders, enc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: when application configuration is made for this format then this should be ported to the options object
|
|
||||||
// that is created for that configuration (as done with the template output option)
|
|
||||||
func cycloneDxXMLEncoders() ([]sbom.FormatEncoder, error) {
|
|
||||||
var (
|
|
||||||
encs []sbom.FormatEncoder
|
|
||||||
errs error
|
|
||||||
)
|
|
||||||
for _, v := range cyclonedxxml.SupportedVersions() {
|
|
||||||
enc, err := cyclonedxxml.NewFormatEncoderWithConfig(cyclonedxxml.EncoderConfig{Version: v})
|
|
||||||
if err != nil {
|
|
||||||
errs = multierror.Append(errs, err)
|
|
||||||
} else {
|
|
||||||
encs = append(encs, enc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return encs, errs
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: when application configuration is made for this format then this should be ported to the options object
|
|
||||||
// that is created for that configuration (as done with the template output option)
|
|
||||||
func cycloneDxJSONEncoders() ([]sbom.FormatEncoder, error) {
|
|
||||||
var (
|
|
||||||
encs []sbom.FormatEncoder
|
|
||||||
errs error
|
|
||||||
)
|
|
||||||
for _, v := range cyclonedxjson.SupportedVersions() {
|
|
||||||
enc, err := cyclonedxjson.NewFormatEncoderWithConfig(cyclonedxjson.EncoderConfig{Version: v})
|
|
||||||
if err != nil {
|
|
||||||
errs = multierror.Append(errs, err)
|
|
||||||
} else {
|
|
||||||
encs = append(encs, enc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return encs, errs
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: when application configuration is made for this format then this should be ported to the options object
|
|
||||||
// that is created for that configuration (as done with the template output option)
|
|
||||||
func spdxJSONEncoders() ([]sbom.FormatEncoder, error) {
|
|
||||||
var (
|
|
||||||
encs []sbom.FormatEncoder
|
|
||||||
errs error
|
|
||||||
)
|
|
||||||
for _, v := range spdxjson.SupportedVersions() {
|
|
||||||
enc, err := spdxjson.NewFormatEncoderWithConfig(spdxjson.EncoderConfig{Version: v})
|
|
||||||
if err != nil {
|
|
||||||
errs = multierror.Append(errs, err)
|
|
||||||
} else {
|
|
||||||
encs = append(encs, enc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return encs, errs
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: when application configuration is made for this format then this should be ported to the options object
|
|
||||||
// that is created for that configuration (as done with the template output option)
|
|
||||||
func spdxTagValueEncoders() ([]sbom.FormatEncoder, error) {
|
|
||||||
var (
|
|
||||||
encs []sbom.FormatEncoder
|
|
||||||
errs error
|
|
||||||
)
|
|
||||||
for _, v := range spdxtagvalue.SupportedVersions() {
|
|
||||||
enc, err := spdxtagvalue.NewFormatEncoderWithConfig(spdxtagvalue.EncoderConfig{Version: v})
|
|
||||||
if err != nil {
|
|
||||||
errs = multierror.Append(errs, err)
|
|
||||||
} else {
|
|
||||||
encs = append(encs, enc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return encs, errs
|
|
||||||
}
|
|
||||||
|
|
||||||
func supportedIDs() []sbom.FormatID {
|
func supportedIDs() []sbom.FormatID {
|
||||||
encs := []sbom.FormatID{
|
encs := []sbom.FormatID{
|
||||||
// encoders that support a single version
|
// encoders that support a single version
|
||||||
|
|||||||
@ -27,6 +27,7 @@ func Test_getEncoders(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
opts := DefaultOutput()
|
opts := DefaultOutput()
|
||||||
|
require.NoError(t, opts.Format.PostLoad())
|
||||||
opts.Format.Template.Path = "somewhere"
|
opts.Format.Template.Path = "somewhere"
|
||||||
|
|
||||||
encoders, err := opts.Encoders()
|
encoders, err := opts.Encoders()
|
||||||
@ -158,6 +159,7 @@ func Test_EncoderCollection_ByString_IDOnly_Defaults(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
opts := DefaultOutput()
|
opts := DefaultOutput()
|
||||||
|
require.NoError(t, opts.Format.PostLoad())
|
||||||
opts.Format.Template.Path = "somewhere"
|
opts.Format.Template.Path = "somewhere"
|
||||||
|
|
||||||
defaultEncoders, err := opts.Encoders()
|
defaultEncoders, err := opts.Encoders()
|
||||||
|
|||||||
@ -41,6 +41,7 @@ func Test_MakeSBOMWriter(t *testing.T) {
|
|||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
opt := DefaultOutput()
|
opt := DefaultOutput()
|
||||||
|
require.NoError(t, opt.Format.PostLoad())
|
||||||
encoders, err := opt.Encoders()
|
encoders, err := opt.Encoders()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
_, err = makeSBOMWriter(tt.outputs, "", encoders)
|
_, err = makeSBOMWriter(tt.outputs, "", encoders)
|
||||||
|
|||||||
25
go.mod
25
go.mod
@ -10,7 +10,7 @@ require (
|
|||||||
github.com/acobaugh/osrelease v0.1.0
|
github.com/acobaugh/osrelease v0.1.0
|
||||||
github.com/anchore/bubbly v0.0.0-20230801194016-acdb4981b461
|
github.com/anchore/bubbly v0.0.0-20230801194016-acdb4981b461
|
||||||
github.com/anchore/clio v0.0.0-20231016125544-c98a83e1c7fc
|
github.com/anchore/clio v0.0.0-20231016125544-c98a83e1c7fc
|
||||||
github.com/anchore/fangs v0.0.0-20230818131516-2186b10924fe
|
github.com/anchore/fangs v0.0.0-20231103141714-84c94dc43a2e
|
||||||
github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a
|
github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a
|
||||||
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb
|
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb
|
||||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
|
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
|
||||||
@ -107,7 +107,7 @@ require (
|
|||||||
github.com/containerd/ttrpc v1.2.2 // indirect
|
github.com/containerd/ttrpc v1.2.2 // indirect
|
||||||
github.com/containerd/typeurl/v2 v2.1.1 // indirect
|
github.com/containerd/typeurl/v2 v2.1.1 // indirect
|
||||||
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||||
github.com/docker/cli v24.0.0+incompatible // indirect
|
github.com/docker/cli v24.0.0+incompatible // indirect
|
||||||
github.com/docker/distribution v2.8.3+incompatible // indirect
|
github.com/docker/distribution v2.8.3+incompatible // indirect
|
||||||
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
github.com/docker/docker-credential-helpers v0.7.0 // indirect
|
||||||
@ -140,7 +140,7 @@ require (
|
|||||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||||
github.com/klauspost/compress v1.16.5 // indirect
|
github.com/klauspost/compress v1.17.0 // indirect
|
||||||
github.com/klauspost/pgzip v1.2.5 // indirect
|
github.com/klauspost/pgzip v1.2.5 // indirect
|
||||||
github.com/kr/pretty v0.3.1 // indirect
|
github.com/kr/pretty v0.3.1 // indirect
|
||||||
github.com/kr/text v0.2.0 // indirect
|
github.com/kr/text v0.2.0 // indirect
|
||||||
@ -169,23 +169,25 @@ require (
|
|||||||
github.com/opencontainers/runtime-spec v1.1.0-rc.1 // indirect
|
github.com/opencontainers/runtime-spec v1.1.0-rc.1 // indirect
|
||||||
github.com/opencontainers/selinux v1.11.0 // indirect
|
github.com/opencontainers/selinux v1.11.0 // indirect
|
||||||
github.com/pborman/indent v1.2.1 // indirect
|
github.com/pborman/indent v1.2.1 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8 // indirect
|
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
|
||||||
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
github.com/pierrec/lz4/v4 v4.1.15 // indirect
|
||||||
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
github.com/pjbgf/sha1cd v0.3.0 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pkg/profile v1.7.0 // indirect
|
github.com/pkg/profile v1.7.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/rivo/uniseg v0.2.0 // indirect
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
github.com/rogpeppe/go-internal v1.11.0 // indirect
|
||||||
|
github.com/sagikazarmark/locafero v0.3.0 // indirect
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||||
github.com/shopspring/decimal v1.2.0 // indirect
|
github.com/shopspring/decimal v1.2.0 // indirect
|
||||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||||
github.com/skeema/knownhosts v1.2.0 // indirect
|
github.com/skeema/knownhosts v1.2.0 // indirect
|
||||||
|
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||||
github.com/spf13/cast v1.5.1 // indirect
|
github.com/spf13/cast v1.5.1 // indirect
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
github.com/spf13/viper v1.16.0 // indirect
|
github.com/spf13/viper v1.17.0 // indirect
|
||||||
github.com/subosito/gotenv v1.4.2 // indirect
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
github.com/sylabs/sif/v2 v2.11.5 // indirect
|
github.com/sylabs/sif/v2 v2.11.5 // indirect
|
||||||
github.com/sylabs/squashfs v0.6.1 // indirect
|
github.com/sylabs/squashfs v0.6.1 // indirect
|
||||||
github.com/therootcompany/xz v1.0.1 // indirect
|
github.com/therootcompany/xz v1.0.1 // indirect
|
||||||
@ -204,15 +206,18 @@ require (
|
|||||||
go.opencensus.io v0.24.0 // indirect
|
go.opencensus.io v0.24.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.14.0 // indirect
|
go.opentelemetry.io/otel v1.14.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.14.0 // indirect
|
go.opentelemetry.io/otel/trace v1.14.0 // indirect
|
||||||
|
go.uber.org/atomic v1.9.0 // indirect
|
||||||
|
go.uber.org/multierr v1.9.0 // indirect
|
||||||
golang.org/x/crypto v0.15.0 // indirect
|
golang.org/x/crypto v0.15.0 // indirect
|
||||||
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
|
||||||
golang.org/x/sync v0.3.0 // indirect
|
golang.org/x/sync v0.3.0 // indirect
|
||||||
golang.org/x/sys v0.14.0 // indirect
|
golang.org/x/sys v0.14.0 // indirect
|
||||||
golang.org/x/term v0.14.0 // indirect
|
golang.org/x/term v0.14.0 // indirect
|
||||||
golang.org/x/text v0.14.0 // indirect
|
golang.org/x/text v0.14.0 // indirect
|
||||||
golang.org/x/tools v0.13.0 // indirect
|
golang.org/x/tools v0.13.0 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 // indirect
|
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 // indirect
|
||||||
google.golang.org/grpc v1.58.3 // indirect
|
google.golang.org/grpc v1.58.3 // indirect
|
||||||
google.golang.org/protobuf v1.31.0 // indirect
|
google.golang.org/protobuf v1.31.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
|
|||||||
52
go.sum
52
go.sum
@ -98,8 +98,8 @@ github.com/anchore/bubbly v0.0.0-20230801194016-acdb4981b461 h1:xGu4/uMWucwWV0YV
|
|||||||
github.com/anchore/bubbly v0.0.0-20230801194016-acdb4981b461/go.mod h1:Ger02eh5NpPm2IqkPAy396HU1KlK3BhOeCljDYXySSk=
|
github.com/anchore/bubbly v0.0.0-20230801194016-acdb4981b461/go.mod h1:Ger02eh5NpPm2IqkPAy396HU1KlK3BhOeCljDYXySSk=
|
||||||
github.com/anchore/clio v0.0.0-20231016125544-c98a83e1c7fc h1:A1KFO+zZZmbNlz1+WKsCF0RKVx6XRoxsAG3lrqH9hUQ=
|
github.com/anchore/clio v0.0.0-20231016125544-c98a83e1c7fc h1:A1KFO+zZZmbNlz1+WKsCF0RKVx6XRoxsAG3lrqH9hUQ=
|
||||||
github.com/anchore/clio v0.0.0-20231016125544-c98a83e1c7fc/go.mod h1:QeWvNzxsrUNxcs6haQo3OtISfXUXW0qAuiG4EQiz0GU=
|
github.com/anchore/clio v0.0.0-20231016125544-c98a83e1c7fc/go.mod h1:QeWvNzxsrUNxcs6haQo3OtISfXUXW0qAuiG4EQiz0GU=
|
||||||
github.com/anchore/fangs v0.0.0-20230818131516-2186b10924fe h1:pVpLCGWdNeskAw7vGNdCAcGMezrNljHIqOc9HaOja5M=
|
github.com/anchore/fangs v0.0.0-20231103141714-84c94dc43a2e h1:O8ZubApaSl7dRzKNvyfGq9cLIPLQ5v3Iz0Y3huHKCgg=
|
||||||
github.com/anchore/fangs v0.0.0-20230818131516-2186b10924fe/go.mod h1:82EGoxZTfBXSW0/zollEP+Qs3wkiKmip5yBT5j+eZpY=
|
github.com/anchore/fangs v0.0.0-20231103141714-84c94dc43a2e/go.mod h1:yPsN3NUGhU5dcBtYBa1dMNzGu1yT5ZAfSjKq9DY4aV8=
|
||||||
github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a h1:nJ2G8zWKASyVClGVgG7sfM5mwoZlZ2zYpIzN2OhjWkw=
|
github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a h1:nJ2G8zWKASyVClGVgG7sfM5mwoZlZ2zYpIzN2OhjWkw=
|
||||||
github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a/go.mod h1:ubLFmlsv8/DFUQrZwY5syT5/8Er3ugSr4rDFwHsE3hg=
|
github.com/anchore/go-logger v0.0.0-20230725134548-c21dafa1ec5a/go.mod h1:ubLFmlsv8/DFUQrZwY5syT5/8Er3ugSr4rDFwHsE3hg=
|
||||||
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb h1:iDMnx6LIjtjZ46C0akqveX83WFzhpTD3eqOthawb5vU=
|
github.com/anchore/go-macholibre v0.0.0-20220308212642-53e6d0aaf6fb h1:iDMnx6LIjtjZ46C0akqveX83WFzhpTD3eqOthawb5vU=
|
||||||
@ -211,8 +211,9 @@ github.com/dave/jennifer v1.7.0 h1:uRbSBH9UTS64yXbh4FrMHfgfY762RD+C7bUPKODpSJE=
|
|||||||
github.com/dave/jennifer v1.7.0/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc=
|
github.com/dave/jennifer v1.7.0/go.mod h1:nXbxhEmQfOZhWml3D1cDK5M1FLnMSozpbFN/m3RmGZc=
|
||||||
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da h1:ZOjWpVsFZ06eIhnh4mkaceTiVoktdU67+M7KDHJ268M=
|
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da h1:ZOjWpVsFZ06eIhnh4mkaceTiVoktdU67+M7KDHJ268M=
|
||||||
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da/go.mod h1:B3tI9iGHi4imdLi4Asdha1Sc6feLMTfPLXh9IUYmysk=
|
github.com/deitch/magic v0.0.0-20230404182410-1ff89d7342da/go.mod h1:B3tI9iGHi4imdLi4Asdha1Sc6feLMTfPLXh9IUYmysk=
|
||||||
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
|
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
|
||||||
@ -488,8 +489,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
|||||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
github.com/klauspost/compress v1.11.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
|
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||||
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
|
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
|
||||||
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||||
@ -623,8 +624,8 @@ github.com/pborman/indent v1.2.1/go.mod h1:FitS+t35kIYtB5xWTZAPhnmrxcciEEOdbyrrp
|
|||||||
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
|
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
|
||||||
github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
|
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||||
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
|
github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0=
|
||||||
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||||
@ -640,8 +641,9 @@ github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDj
|
|||||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||||
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
|
||||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||||
@ -675,6 +677,10 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb
|
|||||||
github.com/saferwall/pe v1.4.7 h1:A+G3DxX49paJ5OsxBfHKskhyDtmTjShlDmBd81IsHlQ=
|
github.com/saferwall/pe v1.4.7 h1:A+G3DxX49paJ5OsxBfHKskhyDtmTjShlDmBd81IsHlQ=
|
||||||
github.com/saferwall/pe v1.4.7/go.mod h1:SNzv3cdgk8SBI0UwHfyTcdjawfdnN+nbydnEL7GZ25s=
|
github.com/saferwall/pe v1.4.7/go.mod h1:SNzv3cdgk8SBI0UwHfyTcdjawfdnN+nbydnEL7GZ25s=
|
||||||
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
|
github.com/sagikazarmark/crypt v0.3.0/go.mod h1:uD/D+6UF4SrIR1uGEv7bBNkNqLGqUr43MRiaGWX1Nig=
|
||||||
|
github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9cJvm4SvQ=
|
||||||
|
github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||||
|
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
|
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d h1:hrujxIzL1woJ7AwssoOcM/tq5JjjG2yYOc8odClEiXA=
|
||||||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
|
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d/go.mod h1:uugorj2VCxiV1x+LzaIdVa9b4S4qGAcH6cbhh4qVxOU=
|
||||||
github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo=
|
github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo=
|
||||||
@ -703,6 +709,8 @@ github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ
|
|||||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||||
github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM=
|
github.com/skeema/knownhosts v1.2.0 h1:h9r9cf0+u7wSE+M183ZtMGgOJKiL96brpaz5ekfJCpM=
|
||||||
github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo=
|
github.com/skeema/knownhosts v1.2.0/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo=
|
||||||
|
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||||
|
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM=
|
github.com/spdx/gordf v0.0.0-20201111095634-7098f93598fb/go.mod h1:uKWaldnbMnjsSAXRurWqqrdyZen1R7kxl8TkmWk2OyM=
|
||||||
github.com/spdx/tools-golang v0.5.3 h1:ialnHeEYUC4+hkm5vJm4qz2x+oEJbS0mAMFrNXdQraY=
|
github.com/spdx/tools-golang v0.5.3 h1:ialnHeEYUC4+hkm5vJm4qz2x+oEJbS0mAMFrNXdQraY=
|
||||||
@ -718,13 +726,12 @@ github.com/spf13/cast v1.5.1/go.mod h1:b9PdjNptOpzXr7Rq1q9gJML/2cdGQAo69NKzQ10KN
|
|||||||
github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
|
github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
|
||||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
|
||||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM=
|
github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM=
|
||||||
github.com/spf13/viper v1.16.0 h1:rGGH0XDZhdUOryiDWjmIvUSWpbNqisK8Wk0Vyefw8hc=
|
github.com/spf13/viper v1.17.0 h1:I5txKw7MJasPL/BrfkbA0Jyo/oELqVmux4pR/UxOMfI=
|
||||||
github.com/spf13/viper v1.16.0/go.mod h1:yg78JgCJcbrQOvV9YLXgkLaZqUidkY9K+Dd1FofRzQg=
|
github.com/spf13/viper v1.17.0/go.mod h1:BmMMMLQXSbcHK6KAOiFLz0l5JHrU89OdIRHvsk0+yVI=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
@ -741,12 +748,11 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
github.com/sylabs/sif/v2 v2.11.5 h1:7ssPH3epSonsTrzbS1YxeJ9KuqAN7ISlSM61a7j/mQM=
|
github.com/sylabs/sif/v2 v2.11.5 h1:7ssPH3epSonsTrzbS1YxeJ9KuqAN7ISlSM61a7j/mQM=
|
||||||
github.com/sylabs/sif/v2 v2.11.5/go.mod h1:GBoZs9LU3e4yJH1dcZ3Akf/jsqYgy5SeguJQC+zd75Y=
|
github.com/sylabs/sif/v2 v2.11.5/go.mod h1:GBoZs9LU3e4yJH1dcZ3Akf/jsqYgy5SeguJQC+zd75Y=
|
||||||
github.com/sylabs/squashfs v0.6.1 h1:4hgvHnD9JGlYWwT0bPYNt9zaz23mAV3Js+VEgQoRGYQ=
|
github.com/sylabs/squashfs v0.6.1 h1:4hgvHnD9JGlYWwT0bPYNt9zaz23mAV3Js+VEgQoRGYQ=
|
||||||
@ -827,10 +833,14 @@ go.opentelemetry.io/otel/trace v1.14.0 h1:wp2Mmvj41tDsyAJXiWDWpfNsOiIyd38fy85pyK
|
|||||||
go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
|
go.opentelemetry.io/otel/trace v1.14.0/go.mod h1:8avnQLK+CG77yNLUae4ea2JDQ6iT+gozhnZjy/rw9G8=
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
|
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||||
|
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||||
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
||||||
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||||
|
go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI=
|
||||||
|
go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ=
|
||||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
@ -862,6 +872,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
|||||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||||
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
|
||||||
|
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
@ -1086,8 +1098,8 @@ golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
|||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.1.0 h1:xYY+Bajn2a7VBmTM5GikTmnK8ZuX8YgnQCqZpbBNtmA=
|
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||||
golang.org/x/time v0.1.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
@ -1258,10 +1270,10 @@ google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ6
|
|||||||
google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||||
google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98 h1:Z0hjGZePRE0ZBWotvtrwxFNrNE9CUAGtplaDK5NNI/g=
|
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb h1:XFBgcDwm7irdHTbz4Zk2h7Mh+eis4nfJEFQFYzJzuIA=
|
||||||
google.golang.org/genproto v0.0.0-20230711160842-782d3b101e98/go.mod h1:S7mY02OqCJTD0E1OiQy1F72PWFB4bZJ87cAtLPYgDR0=
|
google.golang.org/genproto v0.0.0-20230913181813-007df8e322eb/go.mod h1:yZTlhN0tQnXo3h00fuXNCxJdLdIdnVFVBaRJ5LWBbw4=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98 h1:bVf09lpb+OJbByTj913DRJioFFAjf/ZGxEz7MajTp2U=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13 h1:N3bU/SQDCDyD6R528GJ/PwW9KjYcJA3dgyH+MovAkIM=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230711160842-782d3b101e98/go.mod h1:TUfxEVdsvPg18p6AslUXFoLdpED4oBnGwyqk3dV1XzM=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20230920204549-e6e6cdab5c13/go.mod h1:KSqppvjFjtoCI+KGd4PELB0qLNxdJHRGqRI09mB6pQA=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
|||||||
@ -15,6 +15,7 @@ func SupportedVersions() []string {
|
|||||||
|
|
||||||
type EncoderConfig struct {
|
type EncoderConfig struct {
|
||||||
Version string
|
Version string
|
||||||
|
Pretty bool // don't include spaces and newlines; same as jq -c
|
||||||
}
|
}
|
||||||
|
|
||||||
type encoder struct {
|
type encoder struct {
|
||||||
@ -23,7 +24,7 @@ type encoder struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewFormatEncoderWithConfig(cfg EncoderConfig) (sbom.FormatEncoder, error) {
|
func NewFormatEncoderWithConfig(cfg EncoderConfig) (sbom.FormatEncoder, error) {
|
||||||
enc, err := cyclonedxutil.NewEncoder(cfg.Version, cyclonedx.BOMFileFormatJSON)
|
enc, err := cyclonedxutil.NewEncoder(cfg.Version, cyclonedx.BOMFileFormatJSON, cfg.Pretty)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -36,6 +37,7 @@ func NewFormatEncoderWithConfig(cfg EncoderConfig) (sbom.FormatEncoder, error) {
|
|||||||
func DefaultEncoderConfig() EncoderConfig {
|
func DefaultEncoderConfig() EncoderConfig {
|
||||||
return EncoderConfig{
|
return EncoderConfig{
|
||||||
Version: cyclonedxutil.DefaultVersion,
|
Version: cyclonedxutil.DefaultVersion,
|
||||||
|
Pretty: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,12 +3,15 @@ package cyclonedxjson
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"flag"
|
"flag"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/format/internal/cyclonedxutil"
|
||||||
"github.com/anchore/syft/syft/format/internal/testutil"
|
"github.com/anchore/syft/syft/format/internal/testutil"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
"github.com/anchore/syft/syft/sbom"
|
"github.com/anchore/syft/syft/sbom"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,11 +19,68 @@ var updateSnapshot = flag.Bool("update-cyclonedx-json", false, "update the *.gol
|
|||||||
var updateImage = flag.Bool("update-image", false, "update the golden image used for image encoder testing")
|
var updateImage = flag.Bool("update-image", false, "update the golden image used for image encoder testing")
|
||||||
|
|
||||||
func getEncoder(t testing.TB) sbom.FormatEncoder {
|
func getEncoder(t testing.TB) sbom.FormatEncoder {
|
||||||
enc, err := NewFormatEncoderWithConfig(DefaultEncoderConfig())
|
cfg := DefaultEncoderConfig()
|
||||||
|
cfg.Pretty = true
|
||||||
|
|
||||||
|
enc, err := NewFormatEncoderWithConfig(cfg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
return enc
|
return enc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPrettyOutput(t *testing.T) {
|
||||||
|
run := func(opt bool) string {
|
||||||
|
enc, err := NewFormatEncoderWithConfig(EncoderConfig{
|
||||||
|
Version: cyclonedxutil.DefaultVersion,
|
||||||
|
Pretty: opt,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
dir := t.TempDir()
|
||||||
|
s := testutil.DirectoryInput(t, dir)
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
err = enc.Encode(&buffer, s)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return strings.TrimSpace(buffer.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("pretty", func(t *testing.T) {
|
||||||
|
actual := run(true)
|
||||||
|
assert.Contains(t, actual, "\n")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("compact", func(t *testing.T) {
|
||||||
|
actual := run(false)
|
||||||
|
assert.NotContains(t, actual, "\n")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEscapeHTML(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
s := testutil.DirectoryInput(t, dir)
|
||||||
|
s.Artifacts.Packages.Add(pkg.Package{
|
||||||
|
Name: "<html-package>",
|
||||||
|
})
|
||||||
|
|
||||||
|
// by default we do not escape HTML
|
||||||
|
t.Run("default", func(t *testing.T) {
|
||||||
|
cfg := DefaultEncoderConfig()
|
||||||
|
|
||||||
|
enc, err := NewFormatEncoderWithConfig(cfg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
err = enc.Encode(&buffer, s)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
actual := buffer.String()
|
||||||
|
assert.Contains(t, actual, "<html-package>")
|
||||||
|
assert.NotContains(t, actual, "\\u003chtml-package\\u003e")
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestCycloneDxDirectoryEncoder(t *testing.T) {
|
func TestCycloneDxDirectoryEncoder(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
testutil.AssertEncoderAgainstGoldenSnapshot(t,
|
testutil.AssertEncoderAgainstGoldenSnapshot(t,
|
||||||
|
|||||||
@ -17,6 +17,7 @@ func SupportedVersions() []string {
|
|||||||
|
|
||||||
type EncoderConfig struct {
|
type EncoderConfig struct {
|
||||||
Version string
|
Version string
|
||||||
|
Pretty bool // set indent to 0
|
||||||
}
|
}
|
||||||
|
|
||||||
type encoder struct {
|
type encoder struct {
|
||||||
@ -25,7 +26,7 @@ type encoder struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewFormatEncoderWithConfig(cfg EncoderConfig) (sbom.FormatEncoder, error) {
|
func NewFormatEncoderWithConfig(cfg EncoderConfig) (sbom.FormatEncoder, error) {
|
||||||
enc, err := cyclonedxutil.NewEncoder(cfg.Version, cyclonedx.BOMFileFormatXML)
|
enc, err := cyclonedxutil.NewEncoder(cfg.Version, cyclonedx.BOMFileFormatXML, cfg.Pretty)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -38,6 +39,7 @@ func NewFormatEncoderWithConfig(cfg EncoderConfig) (sbom.FormatEncoder, error) {
|
|||||||
func DefaultEncoderConfig() EncoderConfig {
|
func DefaultEncoderConfig() EncoderConfig {
|
||||||
return EncoderConfig{
|
return EncoderConfig{
|
||||||
Version: cyclonedxutil.DefaultVersion,
|
Version: cyclonedxutil.DefaultVersion,
|
||||||
|
Pretty: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -3,11 +3,14 @@ package cyclonedxxml
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"flag"
|
"flag"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/format/internal/cyclonedxutil"
|
||||||
"github.com/anchore/syft/syft/format/internal/testutil"
|
"github.com/anchore/syft/syft/format/internal/testutil"
|
||||||
"github.com/anchore/syft/syft/sbom"
|
"github.com/anchore/syft/syft/sbom"
|
||||||
)
|
)
|
||||||
@ -16,11 +19,42 @@ var updateSnapshot = flag.Bool("update-cyclonedx-xml", false, "update the *.gold
|
|||||||
var updateImage = flag.Bool("update-image", false, "update the golden image used for image encoder testing")
|
var updateImage = flag.Bool("update-image", false, "update the golden image used for image encoder testing")
|
||||||
|
|
||||||
func getEncoder(t testing.TB) sbom.FormatEncoder {
|
func getEncoder(t testing.TB) sbom.FormatEncoder {
|
||||||
enc, err := NewFormatEncoderWithConfig(DefaultEncoderConfig())
|
cfg := DefaultEncoderConfig()
|
||||||
|
cfg.Pretty = true
|
||||||
|
|
||||||
|
enc, err := NewFormatEncoderWithConfig(cfg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
return enc
|
return enc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPrettyOutput(t *testing.T) {
|
||||||
|
enc, err := NewFormatEncoderWithConfig(EncoderConfig{
|
||||||
|
Version: cyclonedxutil.DefaultVersion,
|
||||||
|
Pretty: false,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
dir := t.TempDir()
|
||||||
|
s := testutil.DirectoryInput(t, dir)
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
err = enc.Encode(&buffer, s)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
actual := buffer.String()
|
||||||
|
lines := strings.Split(actual, "\n")
|
||||||
|
require.NotEmpty(t, lines)
|
||||||
|
whitespace := regexp.MustCompile(`^\s+`)
|
||||||
|
for _, line := range lines {
|
||||||
|
if len(line) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// require a non-whitespace character (tab, space, etc) as the first character of the line
|
||||||
|
require.False(t, whitespace.Match([]byte(line)), "line should not start with whitespace: %q", line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCycloneDxDirectoryEncoder(t *testing.T) {
|
func TestCycloneDxDirectoryEncoder(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
testutil.AssertEncoderAgainstGoldenSnapshot(t,
|
testutil.AssertEncoderAgainstGoldenSnapshot(t,
|
||||||
|
|||||||
@ -14,9 +14,10 @@ const DefaultVersion = "1.5"
|
|||||||
type Encoder struct {
|
type Encoder struct {
|
||||||
version cyclonedx.SpecVersion
|
version cyclonedx.SpecVersion
|
||||||
format cyclonedx.BOMFileFormat
|
format cyclonedx.BOMFileFormat
|
||||||
|
pretty bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewEncoder(version string, format cyclonedx.BOMFileFormat) (Encoder, error) {
|
func NewEncoder(version string, format cyclonedx.BOMFileFormat, pretty bool) (Encoder, error) {
|
||||||
specVersion, err := SpecVersionFromString(version)
|
specVersion, err := SpecVersionFromString(version)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Encoder{}, err
|
return Encoder{}, err
|
||||||
@ -24,13 +25,14 @@ func NewEncoder(version string, format cyclonedx.BOMFileFormat) (Encoder, error)
|
|||||||
return Encoder{
|
return Encoder{
|
||||||
version: specVersion,
|
version: specVersion,
|
||||||
format: format,
|
format: format,
|
||||||
|
pretty: pretty,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e Encoder) Encode(writer io.Writer, s sbom.SBOM) error {
|
func (e Encoder) Encode(writer io.Writer, s sbom.SBOM) error {
|
||||||
bom := cyclonedxhelpers.ToFormatModel(s)
|
bom := cyclonedxhelpers.ToFormatModel(s)
|
||||||
enc := cyclonedx.NewBOMEncoder(writer, e.format)
|
enc := cyclonedx.NewBOMEncoder(writer, e.format)
|
||||||
enc.SetPretty(true)
|
enc.SetPretty(e.pretty)
|
||||||
enc.SetEscapeHTML(false)
|
enc.SetEscapeHTML(false)
|
||||||
|
|
||||||
return enc.EncodeVersion(bom, e.version)
|
return enc.EncodeVersion(bom, e.version)
|
||||||
|
|||||||
@ -48,12 +48,8 @@ func AssertEncoderAgainstGoldenSnapshot(t *testing.T, cfg EncoderSnapshotTestCon
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var expected []byte
|
|
||||||
if cfg.Redactor != nil {
|
if cfg.Redactor != nil {
|
||||||
actual = cfg.Redactor.Redact(actual)
|
actual = cfg.Redactor.Redact(actual)
|
||||||
expected = cfg.Redactor.Redact(testutils.GetGoldenFileContents(t))
|
|
||||||
} else {
|
|
||||||
expected = testutils.GetGoldenFileContents(t)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.UpdateSnapshot && cfg.PersistRedactionsInSnapshot {
|
if cfg.UpdateSnapshot && cfg.PersistRedactionsInSnapshot {
|
||||||
@ -62,6 +58,13 @@ func AssertEncoderAgainstGoldenSnapshot(t *testing.T, cfg EncoderSnapshotTestCon
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var expected []byte
|
||||||
|
if cfg.Redactor != nil {
|
||||||
|
expected = cfg.Redactor.Redact(testutils.GetGoldenFileContents(t))
|
||||||
|
} else {
|
||||||
|
expected = testutils.GetGoldenFileContents(t)
|
||||||
|
}
|
||||||
|
|
||||||
if cfg.IsJSON {
|
if cfg.IsJSON {
|
||||||
require.JSONEq(t, string(expected), string(actual))
|
require.JSONEq(t, string(expected), string(actual))
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -23,6 +23,7 @@ func SupportedVersions() []string {
|
|||||||
|
|
||||||
type EncoderConfig struct {
|
type EncoderConfig struct {
|
||||||
Version string
|
Version string
|
||||||
|
Pretty bool // don't include spaces and newlines; same as jq -c
|
||||||
}
|
}
|
||||||
|
|
||||||
type encoder struct {
|
type encoder struct {
|
||||||
@ -38,6 +39,7 @@ func NewFormatEncoderWithConfig(cfg EncoderConfig) (sbom.FormatEncoder, error) {
|
|||||||
func DefaultEncoderConfig() EncoderConfig {
|
func DefaultEncoderConfig() EncoderConfig {
|
||||||
return EncoderConfig{
|
return EncoderConfig{
|
||||||
Version: spdxutil.DefaultVersion,
|
Version: spdxutil.DefaultVersion,
|
||||||
|
Pretty: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,9 +86,12 @@ func (e encoder) Encode(writer io.Writer, s sbom.SBOM) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enc := json.NewEncoder(writer)
|
enc := json.NewEncoder(writer)
|
||||||
// prevent > and < from being escaped in the payload
|
|
||||||
enc.SetEscapeHTML(false)
|
enc.SetEscapeHTML(false)
|
||||||
|
|
||||||
|
if e.cfg.Pretty {
|
||||||
enc.SetIndent("", " ")
|
enc.SetIndent("", " ")
|
||||||
|
}
|
||||||
|
|
||||||
return enc.Encode(encodeDoc)
|
return enc.Encode(encodeDoc)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,12 +3,15 @@ package spdxjson
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"flag"
|
"flag"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/format/internal/spdxutil"
|
||||||
"github.com/anchore/syft/syft/format/internal/testutil"
|
"github.com/anchore/syft/syft/format/internal/testutil"
|
||||||
|
"github.com/anchore/syft/syft/pkg"
|
||||||
"github.com/anchore/syft/syft/sbom"
|
"github.com/anchore/syft/syft/sbom"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -16,11 +19,68 @@ var updateSnapshot = flag.Bool("update-spdx-json", false, "update the *.golden f
|
|||||||
var updateImage = flag.Bool("update-image", false, "update the golden image used for image encoder testing")
|
var updateImage = flag.Bool("update-image", false, "update the golden image used for image encoder testing")
|
||||||
|
|
||||||
func getEncoder(t testing.TB) sbom.FormatEncoder {
|
func getEncoder(t testing.TB) sbom.FormatEncoder {
|
||||||
enc, err := NewFormatEncoderWithConfig(DefaultEncoderConfig())
|
cfg := DefaultEncoderConfig()
|
||||||
|
cfg.Pretty = true
|
||||||
|
|
||||||
|
enc, err := NewFormatEncoderWithConfig(cfg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
return enc
|
return enc
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPrettyOutput(t *testing.T) {
|
||||||
|
run := func(opt bool) string {
|
||||||
|
enc, err := NewFormatEncoderWithConfig(EncoderConfig{
|
||||||
|
Version: spdxutil.DefaultVersion,
|
||||||
|
Pretty: opt,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
dir := t.TempDir()
|
||||||
|
s := testutil.DirectoryInput(t, dir)
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
err = enc.Encode(&buffer, s)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return strings.TrimSpace(buffer.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("pretty", func(t *testing.T) {
|
||||||
|
actual := run(true)
|
||||||
|
assert.Contains(t, actual, "\n")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("compact", func(t *testing.T) {
|
||||||
|
actual := run(false)
|
||||||
|
assert.NotContains(t, actual, "\n")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEscapeHTML(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
s := testutil.DirectoryInput(t, dir)
|
||||||
|
s.Artifacts.Packages.Add(pkg.Package{
|
||||||
|
Name: "<html-package>",
|
||||||
|
})
|
||||||
|
|
||||||
|
// by default we do not escape HTML
|
||||||
|
t.Run("default", func(t *testing.T) {
|
||||||
|
cfg := DefaultEncoderConfig()
|
||||||
|
|
||||||
|
enc, err := NewFormatEncoderWithConfig(cfg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
err = enc.Encode(&buffer, s)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
actual := buffer.String()
|
||||||
|
assert.Contains(t, actual, "<html-package>")
|
||||||
|
assert.NotContains(t, actual, "\\u003chtml-package\\u003e")
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func TestSPDXJSONDirectoryEncoder(t *testing.T) {
|
func TestSPDXJSONDirectoryEncoder(t *testing.T) {
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
testutil.AssertEncoderAgainstGoldenSnapshot(t,
|
testutil.AssertEncoderAgainstGoldenSnapshot(t,
|
||||||
|
|||||||
@ -14,6 +14,7 @@ const ID sbom.FormatID = "syft-json"
|
|||||||
|
|
||||||
type EncoderConfig struct {
|
type EncoderConfig struct {
|
||||||
Legacy bool // transform the output to the legacy syft-json format (pre v1.0 changes, enumerated in the README.md)
|
Legacy bool // transform the output to the legacy syft-json format (pre v1.0 changes, enumerated in the README.md)
|
||||||
|
Pretty bool // don't include spaces and newlines; same as jq -c
|
||||||
}
|
}
|
||||||
|
|
||||||
type encoder struct {
|
type encoder struct {
|
||||||
@ -37,6 +38,7 @@ func NewFormatEncoderWithConfig(cfg EncoderConfig) (sbom.FormatEncoder, error) {
|
|||||||
func DefaultEncoderConfig() EncoderConfig {
|
func DefaultEncoderConfig() EncoderConfig {
|
||||||
return EncoderConfig{
|
return EncoderConfig{
|
||||||
Legacy: false,
|
Legacy: false,
|
||||||
|
Pretty: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,9 +61,12 @@ func (e encoder) Encode(writer io.Writer, s sbom.SBOM) error {
|
|||||||
doc := ToFormatModel(s, e.cfg)
|
doc := ToFormatModel(s, e.cfg)
|
||||||
|
|
||||||
enc := json.NewEncoder(writer)
|
enc := json.NewEncoder(writer)
|
||||||
// prevent > and < from being escaped in the payload
|
|
||||||
enc.SetEscapeHTML(false)
|
enc.SetEscapeHTML(false)
|
||||||
|
|
||||||
|
if e.cfg.Pretty {
|
||||||
enc.SetIndent("", " ")
|
enc.SetIndent("", " ")
|
||||||
|
}
|
||||||
|
|
||||||
return enc.Encode(&doc)
|
return enc.Encode(&doc)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,14 @@
|
|||||||
package syftjson
|
package syftjson
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
"flag"
|
"flag"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
stereoFile "github.com/anchore/stereoscope/pkg/file"
|
stereoFile "github.com/anchore/stereoscope/pkg/file"
|
||||||
"github.com/anchore/syft/internal"
|
"github.com/anchore/syft/internal"
|
||||||
"github.com/anchore/syft/syft/artifact"
|
"github.com/anchore/syft/syft/artifact"
|
||||||
@ -31,12 +36,69 @@ func TestDefaultNameAndVersion(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPrettyOutput(t *testing.T) {
|
||||||
|
run := func(opt bool) string {
|
||||||
|
enc, err := NewFormatEncoderWithConfig(EncoderConfig{
|
||||||
|
Pretty: opt,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
dir := t.TempDir()
|
||||||
|
s := testutil.DirectoryInput(t, dir)
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
err = enc.Encode(&buffer, s)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return strings.TrimSpace(buffer.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("pretty", func(t *testing.T) {
|
||||||
|
actual := run(true)
|
||||||
|
assert.Contains(t, actual, "\n")
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("compact", func(t *testing.T) {
|
||||||
|
actual := run(false)
|
||||||
|
assert.NotContains(t, actual, "\n")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEscapeHTML(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
s := testutil.DirectoryInput(t, dir)
|
||||||
|
s.Artifacts.Packages.Add(pkg.Package{
|
||||||
|
Name: "<html-package>",
|
||||||
|
})
|
||||||
|
|
||||||
|
// by default we do not escape HTML
|
||||||
|
t.Run("default", func(t *testing.T) {
|
||||||
|
cfg := DefaultEncoderConfig()
|
||||||
|
|
||||||
|
enc, err := NewFormatEncoderWithConfig(cfg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
var buffer bytes.Buffer
|
||||||
|
err = enc.Encode(&buffer, s)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
actual := buffer.String()
|
||||||
|
assert.Contains(t, actual, "<html-package>")
|
||||||
|
assert.NotContains(t, actual, "\\u003chtml-package\\u003e")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func TestDirectoryEncoder(t *testing.T) {
|
func TestDirectoryEncoder(t *testing.T) {
|
||||||
|
cfg := DefaultEncoderConfig()
|
||||||
|
cfg.Pretty = true
|
||||||
|
enc, err := NewFormatEncoderWithConfig(cfg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
dir := t.TempDir()
|
dir := t.TempDir()
|
||||||
testutil.AssertEncoderAgainstGoldenSnapshot(t,
|
testutil.AssertEncoderAgainstGoldenSnapshot(t,
|
||||||
testutil.EncoderSnapshotTestConfig{
|
testutil.EncoderSnapshotTestConfig{
|
||||||
Subject: testutil.DirectoryInput(t, dir),
|
Subject: testutil.DirectoryInput(t, dir),
|
||||||
Format: NewFormatEncoder(),
|
Format: enc,
|
||||||
UpdateSnapshot: *updateSnapshot,
|
UpdateSnapshot: *updateSnapshot,
|
||||||
PersistRedactionsInSnapshot: true,
|
PersistRedactionsInSnapshot: true,
|
||||||
IsJSON: true,
|
IsJSON: true,
|
||||||
@ -46,6 +108,11 @@ func TestDirectoryEncoder(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestImageEncoder(t *testing.T) {
|
func TestImageEncoder(t *testing.T) {
|
||||||
|
cfg := DefaultEncoderConfig()
|
||||||
|
cfg.Pretty = true
|
||||||
|
enc, err := NewFormatEncoderWithConfig(cfg)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
testImage := "image-simple"
|
testImage := "image-simple"
|
||||||
testutil.AssertEncoderAgainstGoldenImageSnapshot(t,
|
testutil.AssertEncoderAgainstGoldenImageSnapshot(t,
|
||||||
testutil.ImageSnapshotTestConfig{
|
testutil.ImageSnapshotTestConfig{
|
||||||
@ -54,7 +121,7 @@ func TestImageEncoder(t *testing.T) {
|
|||||||
},
|
},
|
||||||
testutil.EncoderSnapshotTestConfig{
|
testutil.EncoderSnapshotTestConfig{
|
||||||
Subject: testutil.ImageInput(t, testImage, testutil.FromSnapshot()),
|
Subject: testutil.ImageInput(t, testImage, testutil.FromSnapshot()),
|
||||||
Format: NewFormatEncoder(),
|
Format: enc,
|
||||||
UpdateSnapshot: *updateSnapshot,
|
UpdateSnapshot: *updateSnapshot,
|
||||||
PersistRedactionsInSnapshot: true,
|
PersistRedactionsInSnapshot: true,
|
||||||
IsJSON: true,
|
IsJSON: true,
|
||||||
|
|||||||
@ -23,6 +23,7 @@ func TestAllFormatsExpressible(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
opts := options.DefaultOutput()
|
opts := options.DefaultOutput()
|
||||||
|
require.NoError(t, opts.PostLoad())
|
||||||
encoders, err := opts.Encoders()
|
encoders, err := opts.Encoders()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|||||||
@ -39,8 +39,8 @@ func TestPackagesCmdFlags(t *testing.T) {
|
|||||||
args: []string{"packages", "-o", "json", coverageImage},
|
args: []string{"packages", "-o", "json", coverageImage},
|
||||||
assertions: []traitAssertion{
|
assertions: []traitAssertion{
|
||||||
assertJsonReport,
|
assertJsonReport,
|
||||||
assertInOutput(`"metadataType": "apk-db-entry"`),
|
assertInOutput(`"metadataType":"apk-db-entry"`),
|
||||||
assertNotInOutput(`"metadataType": "ApkMetadata"`),
|
assertNotInOutput(`"metadataType":"ApkMetadata"`),
|
||||||
assertSuccessfulReturnCode,
|
assertSuccessfulReturnCode,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -126,8 +126,8 @@ func TestPackagesCmdFlags(t *testing.T) {
|
|||||||
},
|
},
|
||||||
assertions: []traitAssertion{
|
assertions: []traitAssertion{
|
||||||
assertJsonReport,
|
assertJsonReport,
|
||||||
assertNotInOutput(`"metadataType": "apk-db-entry"`),
|
assertNotInOutput(`"metadataType":"apk-db-entry"`),
|
||||||
assertInOutput(`"metadataType": "ApkMetadata"`),
|
assertInOutput(`"metadataType":"ApkMetadata"`),
|
||||||
assertSuccessfulReturnCode,
|
assertSuccessfulReturnCode,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -26,9 +26,9 @@ func TestPowerUserCmdFlags(t *testing.T) {
|
|||||||
args: []string{"power-user", "docker-archive:" + getFixtureImage(t, "image-pkg-coverage")},
|
args: []string{"power-user", "docker-archive:" + getFixtureImage(t, "image-pkg-coverage")},
|
||||||
assertions: []traitAssertion{
|
assertions: []traitAssertion{
|
||||||
assertNotInOutput(" command is deprecated"), // only the root command should be deprecated
|
assertNotInOutput(" command is deprecated"), // only the root command should be deprecated
|
||||||
assertInOutput(`"type": "RegularFile"`), // proof of file-metadata data
|
assertInOutput(`"type":"RegularFile"`), // proof of file-metadata data
|
||||||
assertInOutput(`"algorithm": "sha256"`), // proof of file-metadata default digest algorithm of sha256
|
assertInOutput(`"algorithm":"sha256"`), // proof of file-metadata default digest algorithm of sha256
|
||||||
assertInOutput(`"metadataType": "apk-db-entry"`), // proof of package artifacts data
|
assertInOutput(`"metadataType":"apk-db-entry"`), // proof of package artifacts data
|
||||||
assertSuccessfulReturnCode,
|
assertSuccessfulReturnCode,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -39,7 +39,7 @@ func TestPowerUserCmdFlags(t *testing.T) {
|
|||||||
"SYFT_FILE_CONTENTS_GLOBS": "/api-key.txt",
|
"SYFT_FILE_CONTENTS_GLOBS": "/api-key.txt",
|
||||||
},
|
},
|
||||||
assertions: []traitAssertion{
|
assertions: []traitAssertion{
|
||||||
assertInOutput(`"contents": "c29tZV9BcEkta0V5ID0gIjEyMzQ1QTdhOTAxYjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MCIK"`), // proof of the content cataloger
|
assertInOutput(`"contents":"c29tZV9BcEkta0V5ID0gIjEyMzQ1QTdhOTAxYjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MCIK"`), // proof of the content cataloger
|
||||||
assertSuccessfulReturnCode,
|
assertSuccessfulReturnCode,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -48,9 +48,9 @@ func TestPowerUserCmdFlags(t *testing.T) {
|
|||||||
args: []string{"power-user", "dir:test-fixtures/image-pkg-coverage"},
|
args: []string{"power-user", "dir:test-fixtures/image-pkg-coverage"},
|
||||||
assertions: []traitAssertion{
|
assertions: []traitAssertion{
|
||||||
assertNotInOutput(" command is deprecated"), // only the root command should be deprecated
|
assertNotInOutput(" command is deprecated"), // only the root command should be deprecated
|
||||||
assertInOutput(`"type": "RegularFile"`), // proof of file-metadata data
|
assertInOutput(`"type":"RegularFile"`), // proof of file-metadata data
|
||||||
assertInOutput(`"algorithm": "sha256"`), // proof of file-metadata default digest algorithm of sha256
|
assertInOutput(`"algorithm":"sha256"`), // proof of file-metadata default digest algorithm of sha256
|
||||||
assertInOutput(`"metadataType": "apk-db-entry"`), // proof of package artifacts data
|
assertInOutput(`"metadataType":"apk-db-entry"`), // proof of package artifacts data
|
||||||
assertSuccessfulReturnCode,
|
assertSuccessfulReturnCode,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -61,7 +61,7 @@ func TestPowerUserCmdFlags(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: []string{"power-user", "docker-archive:" + secretsFixture},
|
args: []string{"power-user", "docker-archive:" + secretsFixture},
|
||||||
assertions: []traitAssertion{
|
assertions: []traitAssertion{
|
||||||
assertInOutput(`"classification": "generic-api-key"`), // proof of the secrets cataloger finding something
|
assertInOutput(`"classification":"generic-api-key"`), // proof of the secrets cataloger finding something
|
||||||
assertInOutput(`"12345A7a901b345678901234567890123456789012345678901234567890"`), // proof of the secrets cataloger finding the api key
|
assertInOutput(`"12345A7a901b345678901234567890123456789012345678901234567890"`), // proof of the secrets cataloger finding the api key
|
||||||
assertSuccessfulReturnCode,
|
assertSuccessfulReturnCode,
|
||||||
},
|
},
|
||||||
@ -70,7 +70,7 @@ func TestPowerUserCmdFlags(t *testing.T) {
|
|||||||
name: "default-secret-results-dont-reveal-values",
|
name: "default-secret-results-dont-reveal-values",
|
||||||
args: []string{"power-user", "docker-archive:" + secretsFixture},
|
args: []string{"power-user", "docker-archive:" + secretsFixture},
|
||||||
assertions: []traitAssertion{
|
assertions: []traitAssertion{
|
||||||
assertInOutput(`"classification": "generic-api-key"`), // proof of the secrets cataloger finding something
|
assertInOutput(`"classification":"generic-api-key"`), // proof of the secrets cataloger finding something
|
||||||
assertNotInOutput(`"12345A7a901b345678901234567890123456789012345678901234567890"`), // proof of the secrets cataloger finding the api key
|
assertNotInOutput(`"12345A7a901b345678901234567890123456789012345678901234567890"`), // proof of the secrets cataloger finding the api key
|
||||||
assertSuccessfulReturnCode,
|
assertSuccessfulReturnCode,
|
||||||
},
|
},
|
||||||
@ -82,7 +82,7 @@ func TestPowerUserCmdFlags(t *testing.T) {
|
|||||||
},
|
},
|
||||||
args: []string{"power-user", "dir:test-fixtures/image-secrets-dir"},
|
args: []string{"power-user", "dir:test-fixtures/image-secrets-dir"},
|
||||||
assertions: []traitAssertion{
|
assertions: []traitAssertion{
|
||||||
assertInOutput(`"classification": "generic-api-key"`), // proof of the secrets cataloger finding something
|
assertInOutput(`"classification":"generic-api-key"`), // proof of the secrets cataloger finding something
|
||||||
assertInOutput(`"12345A7a901b345678901234567890123456789012345678901234567890"`), // proof of the secrets cataloger finding the api key
|
assertInOutput(`"12345A7a901b345678901234567890123456789012345678901234567890"`), // proof of the secrets cataloger finding the api key
|
||||||
assertSuccessfulReturnCode,
|
assertSuccessfulReturnCode,
|
||||||
},
|
},
|
||||||
|
|||||||
@ -86,7 +86,10 @@ func assertNotInOutput(data string) traitAssertion {
|
|||||||
func assertNoStderr(tb testing.TB, _, stderr string, _ int) {
|
func assertNoStderr(tb testing.TB, _, stderr string, _ int) {
|
||||||
tb.Helper()
|
tb.Helper()
|
||||||
if len(stderr) > 0 {
|
if len(stderr) > 0 {
|
||||||
tb.Errorf("expected stderr to be empty, but got %q", stderr)
|
tb.Errorf("expected stderr to be empty, but wasn't")
|
||||||
|
if showOutput != nil && *showOutput {
|
||||||
|
tb.Errorf("STDERR:%s", stderr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,7 +99,10 @@ func assertInOutput(data string) traitAssertion {
|
|||||||
stdout = stripansi.Strip(stdout)
|
stdout = stripansi.Strip(stdout)
|
||||||
stderr = stripansi.Strip(stderr)
|
stderr = stripansi.Strip(stderr)
|
||||||
if !strings.Contains(stdout, data) && !strings.Contains(stderr, data) {
|
if !strings.Contains(stdout, data) && !strings.Contains(stderr, data) {
|
||||||
tb.Errorf("data=%q was NOT found in any output, but should have been there\nSTDOUT:%s\nSTDERR:%s", data, stdout, stderr)
|
tb.Errorf("data=%q was NOT found in any output, but should have been there", data)
|
||||||
|
if showOutput != nil && *showOutput {
|
||||||
|
tb.Errorf("STDOUT:%s\nSTDERR:%s", stdout, stderr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -67,6 +67,7 @@ func TestEncodeDecodeEncodeCycleComparison(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
opts := options.DefaultOutput()
|
opts := options.DefaultOutput()
|
||||||
|
require.NoError(t, opts.PostLoad())
|
||||||
encoderList, err := opts.Encoders()
|
encoderList, err := opts.Encoders()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user