mirror of
https://github.com/anchore/syft
synced 2024-11-10 06:14:16 +00:00
Internalize majority of cmd package (#2533)
* internalize majority of cmd package and migrate integration tests Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * add internal api encoder Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * create internal representation of all formats Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * export capability to get default encoders Signed-off-by: Alex Goodman <wagoodman@users.noreply.github.com> * restore test fixtures 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
bf3cd9ed3b
commit
e0e1c4ba0a
232 changed files with 809 additions and 661 deletions
4
.github/workflows/validations.yaml
vendored
4
.github/workflows/validations.yaml
vendored
|
@ -86,8 +86,8 @@ jobs:
|
||||||
- name: Restore integration test cache
|
- name: Restore integration test cache
|
||||||
uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 #v4.0.0
|
uses: actions/cache@13aacd865c20de90d75de3b17ebe84f7a17d57d2 #v4.0.0
|
||||||
with:
|
with:
|
||||||
path: ${{ github.workspace }}/test/integration/test-fixtures/cache
|
path: ${{ github.workspace }}/cmd/syft/internal/test/integration/test-fixtures/cache
|
||||||
key: ${{ runner.os }}-integration-test-cache-${{ hashFiles('test/integration/test-fixtures/cache.fingerprint') }}
|
key: ${{ runner.os }}-integration-test-cache-${{ hashFiles('/cmd/syft/internal/test/integration/test-fixtures/cache.fingerprint') }}
|
||||||
|
|
||||||
- name: Run integration tests
|
- name: Run integration tests
|
||||||
run: make integration
|
run: make integration
|
||||||
|
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -32,7 +32,6 @@ VERSION
|
||||||
/test/results
|
/test/results
|
||||||
coverage.txt
|
coverage.txt
|
||||||
*.log
|
*.log
|
||||||
test/integration/test-fixtures/**/go.sum
|
|
||||||
|
|
||||||
# probable archives
|
# probable archives
|
||||||
.images
|
.images
|
||||||
|
|
|
@ -234,7 +234,7 @@ rough outline how that works:
|
||||||
the `/test` directory. These tests should focus on correctness of functionality in depth. % test coverage metrics
|
the `/test` directory. These tests should focus on correctness of functionality in depth. % test coverage metrics
|
||||||
only considers unit tests and no other forms of testing.
|
only considers unit tests and no other forms of testing.
|
||||||
|
|
||||||
- `integration`: located within `test/integration`, these tests focus on the behavior surfaced by the common library
|
- `integration`: located within `cmd/syft/internal/test/integration`, these tests focus on the behavior surfaced by the common library
|
||||||
entrypoints from the `syft` package and make light assertions about the results surfaced. Additionally, these tests
|
entrypoints from the `syft` package and make light assertions about the results surfaced. Additionally, these tests
|
||||||
tend to make diversity assertions for enum-like objects, ensuring that as enum values are added to a definition
|
tend to make diversity assertions for enum-like objects, ensuring that as enum values are added to a definition
|
||||||
that integration tests will automatically fail if no test attempts to use that enum value. For more details see
|
that integration tests will automatically fail if no test attempts to use that enum value. For more details see
|
||||||
|
|
|
@ -185,7 +185,7 @@ tasks:
|
||||||
- fixtures
|
- fixtures
|
||||||
vars:
|
vars:
|
||||||
TEST_PKGS:
|
TEST_PKGS:
|
||||||
sh: "go list ./... | grep -v {{ .OWNER }}/{{ .PROJECT }}/test | tr '\n' ' '"
|
sh: "go list ./... | grep -v {{ .OWNER }}/{{ .PROJECT }}/test | grep -v {{ .OWNER }}/{{ .PROJECT }}/cmd/syft/internal/test | tr '\n' ' '"
|
||||||
|
|
||||||
# unit test coverage threshold (in % coverage)
|
# unit test coverage threshold (in % coverage)
|
||||||
COVERAGE_THRESHOLD: 62
|
COVERAGE_THRESHOLD: 62
|
||||||
|
@ -197,7 +197,7 @@ tasks:
|
||||||
integration:
|
integration:
|
||||||
desc: Run integration tests
|
desc: Run integration tests
|
||||||
cmds:
|
cmds:
|
||||||
- "go test -v ./test/integration"
|
- "go test -v ./cmd/syft/internal/test/integration"
|
||||||
# exercise most of the CLI with the data race detector
|
# exercise most of the CLI with the data race detector
|
||||||
- "go run -race cmd/syft/main.go alpine:latest"
|
- "go run -race cmd/syft/main.go alpine:latest"
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ tasks:
|
||||||
fingerprints:
|
fingerprints:
|
||||||
desc: Generate test fixture fingerprints
|
desc: Generate test fixture fingerprints
|
||||||
generates:
|
generates:
|
||||||
- test/integration/test-fixtures/cache.fingerprint
|
- cmd/syft/internal/test/integration/test-fixtures/cache.fingerprint
|
||||||
- syft/pkg/cataloger/binary/test-fixtures/cache.fingerprint
|
- syft/pkg/cataloger/binary/test-fixtures/cache.fingerprint
|
||||||
- syft/pkg/cataloger/java/test-fixtures/java-builds/cache.fingerprint
|
- syft/pkg/cataloger/java/test-fixtures/java-builds/cache.fingerprint
|
||||||
- syft/pkg/cataloger/golang/test-fixtures/archs/binaries.fingerprint
|
- syft/pkg/cataloger/golang/test-fixtures/archs/binaries.fingerprint
|
||||||
|
@ -275,7 +275,7 @@ tasks:
|
||||||
- test/cli/test-fixtures/cache.fingerprint
|
- test/cli/test-fixtures/cache.fingerprint
|
||||||
cmds:
|
cmds:
|
||||||
# for IMAGE integration test fixtures
|
# for IMAGE integration test fixtures
|
||||||
- "cd test/integration/test-fixtures && make cache.fingerprint"
|
- "cd cmd/syft/internal/test/integration/test-fixtures && make cache.fingerprint"
|
||||||
# for BINARY test fixtures
|
# for BINARY test fixtures
|
||||||
- "cd syft/pkg/cataloger/binary/test-fixtures && make cache.fingerprint"
|
- "cd syft/pkg/cataloger/binary/test-fixtures && make cache.fingerprint"
|
||||||
# for JAVA BUILD test fixtures
|
# for JAVA BUILD test fixtures
|
||||||
|
@ -286,7 +286,7 @@ tasks:
|
||||||
- "cd syft/pkg/cataloger/redhat/test-fixtures && make rpms.fingerprint"
|
- "cd syft/pkg/cataloger/redhat/test-fixtures && make rpms.fingerprint"
|
||||||
# for Kernel test fixtures
|
# for Kernel test fixtures
|
||||||
- "cd syft/pkg/cataloger/kernel/test-fixtures && make cache.fingerprint"
|
- "cd syft/pkg/cataloger/kernel/test-fixtures && make cache.fingerprint"
|
||||||
# for INSTALL integration test fixtures
|
# for INSTALL test fixtures
|
||||||
- "cd test/install && make cache.fingerprint"
|
- "cd test/install && make cache.fingerprint"
|
||||||
# for CLI test fixtures
|
# for CLI test fixtures
|
||||||
- "cd test/cli/test-fixtures && make cache.fingerprint"
|
- "cd test/cli/test-fixtures && make cache.fingerprint"
|
||||||
|
|
|
@ -9,8 +9,8 @@ import (
|
||||||
|
|
||||||
"github.com/anchore/clio"
|
"github.com/anchore/clio"
|
||||||
"github.com/anchore/stereoscope"
|
"github.com/anchore/stereoscope"
|
||||||
"github.com/anchore/syft/cmd/syft/cli/commands"
|
|
||||||
handler "github.com/anchore/syft/cmd/syft/cli/ui"
|
handler "github.com/anchore/syft/cmd/syft/cli/ui"
|
||||||
|
"github.com/anchore/syft/cmd/syft/internal/commands"
|
||||||
"github.com/anchore/syft/cmd/syft/internal/ui"
|
"github.com/anchore/syft/cmd/syft/internal/ui"
|
||||||
"github.com/anchore/syft/internal/bus"
|
"github.com/anchore/syft/internal/bus"
|
||||||
"github.com/anchore/syft/internal/log"
|
"github.com/anchore/syft/internal/log"
|
||||||
|
|
|
@ -1,129 +0,0 @@
|
||||||
package options
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/hashicorp/go-multierror"
|
|
||||||
|
|
||||||
"github.com/anchore/clio"
|
|
||||||
"github.com/anchore/syft/syft/format/cyclonedxjson"
|
|
||||||
"github.com/anchore/syft/syft/format/cyclonedxxml"
|
|
||||||
"github.com/anchore/syft/syft/format/github"
|
|
||||||
"github.com/anchore/syft/syft/format/spdxjson"
|
|
||||||
"github.com/anchore/syft/syft/format/spdxtagvalue"
|
|
||||||
"github.com/anchore/syft/syft/format/syftjson"
|
|
||||||
"github.com/anchore/syft/syft/format/table"
|
|
||||||
"github.com/anchore/syft/syft/format/template"
|
|
||||||
"github.com/anchore/syft/syft/format/text"
|
|
||||||
"github.com/anchore/syft/syft/sbom"
|
|
||||||
)
|
|
||||||
|
|
||||||
var _ clio.PostLoader = (*Format)(nil)
|
|
||||||
|
|
||||||
// Format contains all user configuration for output formatting.
|
|
||||||
type Format struct {
|
|
||||||
Pretty *bool `yaml:"pretty" json:"pretty" mapstructure:"pretty"`
|
|
||||||
Template FormatTemplate `yaml:"template" json:"template" mapstructure:"template"`
|
|
||||||
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 {
|
|
||||||
return Format{
|
|
||||||
Template: DefaultFormatTemplate(),
|
|
||||||
SyftJSON: DefaultFormatJSON(),
|
|
||||||
SPDXJSON: DefaultFormatSPDXJSON(),
|
|
||||||
CyclonedxJSON: DefaultFormatCyclonedxJSON(),
|
|
||||||
CyclonedxXML: DefaultFormatCyclonedxXML(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o *Format) Encoders() ([]sbom.FormatEncoder, error) {
|
|
||||||
// setup all encoders based on the configuration
|
|
||||||
var list encoderList
|
|
||||||
|
|
||||||
// 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(syftjson.ID)(o.SyftJSON.formatEncoders())
|
|
||||||
list.add(table.ID)(table.NewFormatEncoder())
|
|
||||||
list.add(text.ID)(text.NewFormatEncoder())
|
|
||||||
list.add(github.ID)(github.NewFormatEncoder())
|
|
||||||
list.addWithErr(cyclonedxxml.ID)(o.CyclonedxXML.formatEncoders())
|
|
||||||
list.addWithErr(cyclonedxjson.ID)(o.CyclonedxJSON.formatEncoders())
|
|
||||||
list.addWithErr(spdxjson.ID)(o.SPDXJSON.formatEncoders())
|
|
||||||
list.addWithErr(spdxtagvalue.ID)(spdxTagValueEncoders())
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
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 {
|
|
||||||
var pretty bool
|
|
||||||
if o.Pretty != nil {
|
|
||||||
pretty = *o.Pretty
|
|
||||||
}
|
|
||||||
return cyclonedxjson.EncoderConfig{
|
|
||||||
Version: version,
|
|
||||||
Pretty: pretty,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
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 {
|
|
||||||
var pretty bool
|
|
||||||
if o.Pretty != nil {
|
|
||||||
pretty = *o.Pretty
|
|
||||||
}
|
|
||||||
return cyclonedxxml.EncoderConfig{
|
|
||||||
Version: version,
|
|
||||||
Pretty: pretty,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,43 +0,0 @@
|
||||||
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 {
|
|
||||||
var pretty bool
|
|
||||||
if o.Pretty != nil {
|
|
||||||
pretty = *o.Pretty
|
|
||||||
}
|
|
||||||
return spdxjson.EncoderConfig{
|
|
||||||
Version: v,
|
|
||||||
Pretty: pretty,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
"github.com/wagoodman/go-progress"
|
"github.com/wagoodman/go-progress"
|
||||||
|
|
||||||
"github.com/anchore/clio"
|
"github.com/anchore/clio"
|
||||||
"github.com/anchore/syft/cmd/syft/cli/options"
|
"github.com/anchore/syft/cmd/syft/internal/options"
|
||||||
"github.com/anchore/syft/cmd/syft/internal/ui"
|
"github.com/anchore/syft/cmd/syft/internal/ui"
|
||||||
"github.com/anchore/syft/internal"
|
"github.com/anchore/syft/internal"
|
||||||
"github.com/anchore/syft/internal/bus"
|
"github.com/anchore/syft/internal/bus"
|
|
@ -14,7 +14,7 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/anchore/clio"
|
"github.com/anchore/clio"
|
||||||
"github.com/anchore/syft/cmd/syft/cli/options"
|
"github.com/anchore/syft/cmd/syft/internal/options"
|
||||||
"github.com/anchore/syft/syft/sbom"
|
"github.com/anchore/syft/syft/sbom"
|
||||||
"github.com/anchore/syft/syft/source"
|
"github.com/anchore/syft/syft/source"
|
||||||
)
|
)
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/anchore/clio"
|
"github.com/anchore/clio"
|
||||||
"github.com/anchore/syft/cmd/syft/cli/options"
|
"github.com/anchore/syft/cmd/syft/internal/options"
|
||||||
"github.com/anchore/syft/cmd/syft/internal/ui"
|
"github.com/anchore/syft/cmd/syft/internal/ui"
|
||||||
"github.com/anchore/syft/internal"
|
"github.com/anchore/syft/internal"
|
||||||
"github.com/anchore/syft/internal/log"
|
"github.com/anchore/syft/internal/log"
|
|
@ -14,7 +14,7 @@ import (
|
||||||
|
|
||||||
"github.com/anchore/clio"
|
"github.com/anchore/clio"
|
||||||
"github.com/anchore/stereoscope/pkg/image"
|
"github.com/anchore/stereoscope/pkg/image"
|
||||||
"github.com/anchore/syft/cmd/syft/cli/options"
|
"github.com/anchore/syft/cmd/syft/internal/options"
|
||||||
"github.com/anchore/syft/cmd/syft/internal/ui"
|
"github.com/anchore/syft/cmd/syft/internal/ui"
|
||||||
"github.com/anchore/syft/internal"
|
"github.com/anchore/syft/internal"
|
||||||
"github.com/anchore/syft/internal/bus"
|
"github.com/anchore/syft/internal/bus"
|
|
@ -5,7 +5,7 @@ import (
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/anchore/syft/cmd/syft/cli/options"
|
"github.com/anchore/syft/cmd/syft/internal/options"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_scanOptions_validateLegacyOptionsNotUsed(t *testing.T) {
|
func Test_scanOptions_validateLegacyOptionsNotUsed(t *testing.T) {
|
|
@ -11,8 +11,8 @@ import (
|
||||||
|
|
||||||
"github.com/anchore/clio"
|
"github.com/anchore/clio"
|
||||||
hashiVersion "github.com/anchore/go-version"
|
hashiVersion "github.com/anchore/go-version"
|
||||||
"github.com/anchore/syft/cmd/syft/cli/options"
|
|
||||||
"github.com/anchore/syft/cmd/syft/internal"
|
"github.com/anchore/syft/cmd/syft/internal"
|
||||||
|
"github.com/anchore/syft/cmd/syft/internal/options"
|
||||||
"github.com/anchore/syft/internal/bus"
|
"github.com/anchore/syft/internal/bus"
|
||||||
"github.com/anchore/syft/internal/log"
|
"github.com/anchore/syft/internal/log"
|
||||||
"github.com/anchore/syft/syft/event"
|
"github.com/anchore/syft/syft/event"
|
58
cmd/syft/internal/options/format.go
Normal file
58
cmd/syft/internal/options/format.go
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
package options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anchore/clio"
|
||||||
|
"github.com/anchore/syft/syft/format"
|
||||||
|
"github.com/anchore/syft/syft/sbom"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ clio.PostLoader = (*Format)(nil)
|
||||||
|
|
||||||
|
// Format contains all user configuration for output formatting.
|
||||||
|
type Format struct {
|
||||||
|
Pretty *bool `yaml:"pretty" json:"pretty" mapstructure:"pretty"`
|
||||||
|
Template FormatTemplate `yaml:"template" json:"template" mapstructure:"template"`
|
||||||
|
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 {
|
||||||
|
return Format{
|
||||||
|
Template: DefaultFormatTemplate(),
|
||||||
|
SyftJSON: DefaultFormatJSON(),
|
||||||
|
SPDXJSON: DefaultFormatSPDXJSON(),
|
||||||
|
CyclonedxJSON: DefaultFormatCyclonedxJSON(),
|
||||||
|
CyclonedxXML: DefaultFormatCyclonedxXML(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o Format) Encoders() ([]sbom.FormatEncoder, error) {
|
||||||
|
return format.EncodersConfig{
|
||||||
|
Template: o.Template.config(),
|
||||||
|
SyftJSON: o.SyftJSON.config(),
|
||||||
|
SPDXJSON: o.SPDXJSON.config(format.AllVersions), // we support multiple versions, not just a single version
|
||||||
|
CyclonedxJSON: o.CyclonedxJSON.config(format.AllVersions), // we support multiple versions, not just a single version
|
||||||
|
CyclonedxXML: o.CyclonedxXML.config(format.AllVersions), // we support multiple versions, not just a single version
|
||||||
|
}.Encoders()
|
||||||
|
}
|
||||||
|
|
||||||
|
func multiLevelOption[T any](defaultValue T, option ...*T) *T {
|
||||||
|
result := defaultValue
|
||||||
|
for _, opt := range option {
|
||||||
|
if opt != nil {
|
||||||
|
result = *opt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &result
|
||||||
|
}
|
24
cmd/syft/internal/options/format_cyclonedx_json.go
Normal file
24
cmd/syft/internal/options/format_cyclonedx_json.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anchore/syft/syft/format/cyclonedxjson"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FormatCyclonedxJSON struct {
|
||||||
|
Pretty *bool `yaml:"pretty" json:"pretty" mapstructure:"pretty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultFormatCyclonedxJSON() FormatCyclonedxJSON {
|
||||||
|
return FormatCyclonedxJSON{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o FormatCyclonedxJSON) config(version string) cyclonedxjson.EncoderConfig {
|
||||||
|
var pretty bool
|
||||||
|
if o.Pretty != nil {
|
||||||
|
pretty = *o.Pretty
|
||||||
|
}
|
||||||
|
return cyclonedxjson.EncoderConfig{
|
||||||
|
Version: version,
|
||||||
|
Pretty: pretty,
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,7 @@ func TestFormatCyclonedxJSON_buildConfig(t *testing.T) {
|
||||||
ft := &FormatCyclonedxJSON{}
|
ft := &FormatCyclonedxJSON{}
|
||||||
ft = setAllToNonZero(t, ft).(*FormatCyclonedxJSON)
|
ft = setAllToNonZero(t, ft).(*FormatCyclonedxJSON)
|
||||||
|
|
||||||
subject := ft.buildConfig("Version")
|
subject := ft.config("Version")
|
||||||
assertExpectedValue(t, subject)
|
assertExpectedValue(t, subject)
|
||||||
}
|
}
|
||||||
|
|
24
cmd/syft/internal/options/format_cyclonedx_xml.go
Normal file
24
cmd/syft/internal/options/format_cyclonedx_xml.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anchore/syft/syft/format/cyclonedxxml"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FormatCyclonedxXML struct {
|
||||||
|
Pretty *bool `yaml:"pretty" json:"pretty" mapstructure:"pretty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultFormatCyclonedxXML() FormatCyclonedxXML {
|
||||||
|
return FormatCyclonedxXML{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o FormatCyclonedxXML) config(version string) cyclonedxxml.EncoderConfig {
|
||||||
|
var pretty bool
|
||||||
|
if o.Pretty != nil {
|
||||||
|
pretty = *o.Pretty
|
||||||
|
}
|
||||||
|
return cyclonedxxml.EncoderConfig{
|
||||||
|
Version: version,
|
||||||
|
Pretty: pretty,
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,6 @@ func TestFormatCyclonedxXML_buildConfig(t *testing.T) {
|
||||||
ft := FormatCyclonedxXML{}
|
ft := FormatCyclonedxXML{}
|
||||||
ftp := setAllToNonZero(t, &ft).(*FormatCyclonedxXML)
|
ftp := setAllToNonZero(t, &ft).(*FormatCyclonedxXML)
|
||||||
|
|
||||||
subject := ftp.buildConfig("Version")
|
subject := ftp.config("Version")
|
||||||
assertExpectedValue(t, subject)
|
assertExpectedValue(t, subject)
|
||||||
}
|
}
|
24
cmd/syft/internal/options/format_spdx_json.go
Normal file
24
cmd/syft/internal/options/format_spdx_json.go
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
package options
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anchore/syft/syft/format/spdxjson"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FormatSPDXJSON struct {
|
||||||
|
Pretty *bool `yaml:"pretty" json:"pretty" mapstructure:"pretty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultFormatSPDXJSON() FormatSPDXJSON {
|
||||||
|
return FormatSPDXJSON{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o FormatSPDXJSON) config(v string) spdxjson.EncoderConfig {
|
||||||
|
var pretty bool
|
||||||
|
if o.Pretty != nil {
|
||||||
|
pretty = *o.Pretty
|
||||||
|
}
|
||||||
|
return spdxjson.EncoderConfig{
|
||||||
|
Version: v,
|
||||||
|
Pretty: pretty,
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,6 @@ func TestFormatSPDXJSON_buildConfig(t *testing.T) {
|
||||||
ft := &FormatSPDXJSON{}
|
ft := &FormatSPDXJSON{}
|
||||||
ft = setAllToNonZero(t, ft).(*FormatSPDXJSON)
|
ft = setAllToNonZero(t, ft).(*FormatSPDXJSON)
|
||||||
|
|
||||||
subject := ft.buildConfig("Version")
|
subject := ft.config("Version")
|
||||||
assertExpectedValue(t, subject)
|
assertExpectedValue(t, subject)
|
||||||
}
|
}
|
|
@ -2,7 +2,6 @@ package options
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/anchore/syft/syft/format/syftjson"
|
"github.com/anchore/syft/syft/format/syftjson"
|
||||||
"github.com/anchore/syft/syft/sbom"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type FormatSyftJSON struct {
|
type FormatSyftJSON struct {
|
||||||
|
@ -16,12 +15,7 @@ func DefaultFormatJSON() FormatSyftJSON {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o FormatSyftJSON) formatEncoders() ([]sbom.FormatEncoder, error) {
|
func (o FormatSyftJSON) config() syftjson.EncoderConfig {
|
||||||
enc, err := syftjson.NewFormatEncoderWithConfig(o.buildConfig())
|
|
||||||
return []sbom.FormatEncoder{enc}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o FormatSyftJSON) buildConfig() syftjson.EncoderConfig {
|
|
||||||
var pretty bool
|
var pretty bool
|
||||||
if o.Pretty != nil {
|
if o.Pretty != nil {
|
||||||
pretty = *o.Pretty
|
pretty = *o.Pretty
|
|
@ -10,6 +10,6 @@ func TestFormatSyftJSON_buildConfig(t *testing.T) {
|
||||||
ft := &FormatSyftJSON{}
|
ft := &FormatSyftJSON{}
|
||||||
ft = setAllToNonZero(t, ft).(*FormatSyftJSON)
|
ft = setAllToNonZero(t, ft).(*FormatSyftJSON)
|
||||||
|
|
||||||
subject := ft.buildConfig()
|
subject := ft.config()
|
||||||
assertExpectedValue(t, subject)
|
assertExpectedValue(t, subject)
|
||||||
}
|
}
|
|
@ -3,7 +3,6 @@ package options
|
||||||
import (
|
import (
|
||||||
"github.com/anchore/clio"
|
"github.com/anchore/clio"
|
||||||
"github.com/anchore/syft/syft/format/template"
|
"github.com/anchore/syft/syft/format/template"
|
||||||
"github.com/anchore/syft/syft/sbom"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ clio.FlagAdder = (*FormatTemplate)(nil)
|
var _ clio.FlagAdder = (*FormatTemplate)(nil)
|
||||||
|
@ -26,12 +25,8 @@ func (o *FormatTemplate) AddFlags(flags clio.FlagSet) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o FormatTemplate) formatEncoders() ([]sbom.FormatEncoder, error) {
|
func (o FormatTemplate) config() template.EncoderConfig {
|
||||||
if !o.Enabled {
|
return template.EncoderConfig{
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
enc, err := template.NewFormatEncoder(template.EncoderConfig{
|
|
||||||
TemplatePath: o.Path,
|
TemplatePath: o.Path,
|
||||||
})
|
}
|
||||||
return []sbom.FormatEncoder{enc}, err
|
|
||||||
}
|
}
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
"github.com/anchore/syft/cmd/syft/cli/options"
|
"github.com/anchore/syft/cmd/syft/internal/options"
|
||||||
"github.com/anchore/syft/syft/format"
|
"github.com/anchore/syft/syft/format"
|
||||||
"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"
|
|
@ -12,7 +12,7 @@ import (
|
||||||
|
|
||||||
"github.com/anchore/clio"
|
"github.com/anchore/clio"
|
||||||
stereoscopeFile "github.com/anchore/stereoscope/pkg/file"
|
stereoscopeFile "github.com/anchore/stereoscope/pkg/file"
|
||||||
"github.com/anchore/syft/cmd/syft/cli/options"
|
"github.com/anchore/syft/cmd/syft/internal/options"
|
||||||
"github.com/anchore/syft/syft/cataloging/filecataloging"
|
"github.com/anchore/syft/syft/cataloging/filecataloging"
|
||||||
"github.com/anchore/syft/syft/file"
|
"github.com/anchore/syft/syft/file"
|
||||||
"github.com/anchore/syft/syft/file/cataloger/filecontent"
|
"github.com/anchore/syft/syft/file/cataloger/filecontent"
|
|
@ -5,3 +5,6 @@
|
||||||
# functionality), committing it seems like an acceptable exception.
|
# functionality), committing it seems like an acceptable exception.
|
||||||
!image-pkg-coverage/pkgs/java/*.jar
|
!image-pkg-coverage/pkgs/java/*.jar
|
||||||
!image-pkg-coverage/pkgs/java/*.hpi
|
!image-pkg-coverage/pkgs/java/*.hpi
|
||||||
|
|
||||||
|
**/go.sum
|
||||||
|
!image-go-bin-arch-coverage/go.sum
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue