mirror of
https://github.com/anchore/syft.git
synced 2026-02-12 02:26:42 +01:00
improve config parsing + fix command deprecation warning
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
parent
b1b57f6ba6
commit
f180d1c537
2
.github/workflows/validations.yaml
vendored
2
.github/workflows/validations.yaml
vendored
@ -361,4 +361,4 @@ jobs:
|
||||
path: snapshot
|
||||
|
||||
- name: Run CLI Tests (Linux)
|
||||
run: make cli-linux
|
||||
run: make cli
|
||||
|
||||
41
Makefile
41
Makefile
@ -17,7 +17,6 @@ SUCCESS := $(BOLD)$(GREEN)
|
||||
# the quality gate lower threshold for unit test total % coverage (by function statements)
|
||||
COVERAGE_THRESHOLD := 68
|
||||
# CI cache busting values; change these if you want CI to not use previous stored cache
|
||||
COMPARE_CACHE_BUSTER="f7e689d76a9"
|
||||
INTEGRATION_CACHE_BUSTER="23493ba738c3d2f"
|
||||
CLI_CACHE_BUSTER="789bacdf"
|
||||
BOOTSTRAP_CACHE="789bacdf"
|
||||
@ -26,7 +25,13 @@ BOOTSTRAP_CACHE="789bacdf"
|
||||
DISTDIR=./dist
|
||||
SNAPSHOTDIR=./snapshot
|
||||
GITTREESTATE=$(if $(shell git status --porcelain),dirty,clean)
|
||||
SNAPSHOT_CMD=$(shell realpath $(shell pwd)/$(SNAPSHOTDIR)/syft_linux_amd64/syft)
|
||||
OS := $(shell uname)
|
||||
|
||||
ifeq ($(OS),Darwin)
|
||||
SNAPSHOT_CMD=$(shell realpath $(shell pwd)/$(SNAPSHOTDIR)/$(BIN)-macos_darwin_amd64/$(BIN))
|
||||
else
|
||||
SNAPSHOT_CMD=$(shell realpath $(shell pwd)/$(SNAPSHOTDIR)/$(BIN)_linux_amd64/$(BIN))
|
||||
endif
|
||||
|
||||
ifeq "$(strip $(VERSION))" ""
|
||||
override VERSION = $(shell git describe --always --tags --dirty)
|
||||
@ -73,7 +78,7 @@ all: clean static-analysis test ## Run all linux-based checks (linting, license
|
||||
@printf '$(SUCCESS)All checks pass!$(RESET)\n'
|
||||
|
||||
.PHONY: test
|
||||
test: unit validate-cyclonedx-schema integration benchmark acceptance-linux ## Run all tests (currently unit, integration, and linux acceptance tests)
|
||||
test: unit validate-cyclonedx-schema integration benchmark acceptance-linux cli ## Run all tests (currently unit, integration, linux acceptance, and mac cli tests)
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
@ -215,20 +220,6 @@ acceptance-mac: $(RESULTSDIR) $(SNAPSHOTDIR) ## Run acceptance tests on build sn
|
||||
.PHONY: acceptance-linux
|
||||
acceptance-linux: acceptance-test-deb-package-install acceptance-test-rpm-package-install ## Run acceptance tests on build snapshot binaries and packages (Linux)
|
||||
|
||||
# note: this is used by CI to determine if the inline-scan report cache should be busted for the inline-compare tests
|
||||
.PHONY: compare-fingerprint
|
||||
compare-fingerprint:
|
||||
find test/inline-compare/* -type f -exec md5sum {} + | grep -v '\-reports' | grep -v 'fingerprint' | awk '{print $1}' | sort | md5sum | tee test/inline-compare/inline-compare.fingerprint && echo "$(COMPARE_CACHE_BUSTER)" >> test/inline-compare/inline-compare.fingerprint
|
||||
|
||||
.PHONY: compare-snapshot
|
||||
compare-snapshot: $(SNAPSHOTDIR) ## Compare the reports of a run of a snapshot build of syft against inline-scan
|
||||
chmod 755 $(SNAPSHOT_CMD)
|
||||
@cd test/inline-compare && SYFT_CMD=$(SNAPSHOT_CMD) make
|
||||
|
||||
.PHONY: compare
|
||||
compare: ## Compare the reports of a run of a main-branch build of syft against inline-scan
|
||||
@cd test/inline-compare && make
|
||||
|
||||
.PHONY: acceptance-test-deb-package-install
|
||||
acceptance-test-deb-package-install: $(RESULTSDIR) $(SNAPSHOTDIR)
|
||||
$(call title,Running acceptance test: DEB install)
|
||||
@ -251,17 +242,11 @@ acceptance-test-rpm-package-install: $(RESULTSDIR) $(SNAPSHOTDIR)
|
||||
cli-fingerprint:
|
||||
find test/cli/test-fixtures/image-* -type f -exec md5sum {} + | awk '{print $1}' | sort | md5sum | tee test/cli/test-fixtures/cache.fingerprint && echo "$(CLI_CACHE_BUSTER)" >> test/cli/test-fixtures/cache.fingerprint
|
||||
|
||||
.PHONY: cli-linux
|
||||
cli-linux: $(SNAPSHOTDIR) ## Run CLI tests for Linux executable
|
||||
chmod 755 "$(SNAPSHOTDIR)/$(BIN)_linux_amd64/$(BIN)"
|
||||
$(SNAPSHOTDIR)/$(BIN)_linux_amd64/$(BIN) version
|
||||
SYFT_BINARY_LOCATION='$(SNAPSHOTDIR)/$(BIN)_linux_amd64/$(BIN)' \
|
||||
go test -count=1 -v ./test/cli
|
||||
|
||||
.PHONY: cli-macos
|
||||
cli-macos: $(SNAPSHOTDIR) ## Run CLI tests for macOS executable
|
||||
$(SNAPSHOTDIR)/$(BIN)_linux_amd64/$(BIN) version
|
||||
SYFT_BINARY_LOCATION='$(SNAPSHOTDIR)/$(BIN)-macos_darwin_amd64/$(BIN)' \
|
||||
.PHONY: cli
|
||||
cli: $(SNAPSHOTDIR) ## Run CLI tests
|
||||
chmod 755 "$(SNAPSHOT_CMD)"
|
||||
$(SNAPSHOT_CMD) version
|
||||
SYFT_BINARY_LOCATION='$(SNAPSHOT_CMD)' \
|
||||
go test -count=1 -v ./test/cli
|
||||
|
||||
.PHONY: changlog-release
|
||||
|
||||
16
README.md
16
README.md
@ -93,23 +93,25 @@ quiet: false
|
||||
check-for-app-update: true
|
||||
|
||||
# cataloging packages is exposed through the packages and power-user subcommands
|
||||
packages:
|
||||
package:
|
||||
cataloger:
|
||||
# enable/disable cataloging of packages
|
||||
# SYFT_PACKAGES_CATALOGING_ENABLED env var
|
||||
cataloging-enabled: true
|
||||
# SYFT_PACKAGE_CATALOGER_ENABLED env var
|
||||
enabled: true
|
||||
|
||||
# the search space to look for packages (options: all-layers, squashed)
|
||||
# same as -s ; SYFT_PACKAGES_SCOPE env var
|
||||
# same as -s ; SYFT_PACKAGE_CATALOGER_SCOPE env var
|
||||
scope: "squashed"
|
||||
|
||||
# cataloging file metadata is exposed through the power-user subcommand
|
||||
file-metadata:
|
||||
cataloger:
|
||||
# enable/disable cataloging of file metadata
|
||||
# SYFT_FILE_METADATA_CATALOGING_ENABLED env var
|
||||
cataloging-enabled: true
|
||||
# SYFT_FILE_METADATA_CATALOGER_ENABLED env var
|
||||
enabled: true
|
||||
|
||||
# the search space to look for file metadata (options: all-layers, squashed)
|
||||
# SYFT_FILE_METADATA_SCOPE env var
|
||||
# SYFT_FILE_METADATA_CATALOGER_SCOPE env var
|
||||
scope: "squashed"
|
||||
|
||||
# the file digest algorithms to use when cataloging files (options: "sha256", "md5", "sha1")
|
||||
|
||||
29
cmd/cmd.go
29
cmd/cmd.go
@ -34,7 +34,7 @@ func init() {
|
||||
}
|
||||
|
||||
// provided to disambiguate the root vs packages command, whichever is indicated by the cli args will be set here.
|
||||
// TODO: when the root alias command is removed, this function (hack) can be removed
|
||||
// TODO: when the root alias command is removed, this variable can be removed
|
||||
var activeCmd *cobra.Command
|
||||
|
||||
func Execute() {
|
||||
@ -44,23 +44,28 @@ func Execute() {
|
||||
}
|
||||
}
|
||||
|
||||
// we must setup the config-cli bindings first before the application configuration is parsed. However, this cannot
|
||||
// be done without determining what the primary command that the config options should be bound to since there are
|
||||
// shared concerns (the root-packages alias).
|
||||
func initCmdAliasBindings() {
|
||||
// TODO: when the root alias command is removed, this function (hack) can be removed
|
||||
|
||||
// map of all commands except for root
|
||||
commands := make(map[string]*cobra.Command)
|
||||
for _, c := range rootCmd.Commands() {
|
||||
name := strings.Split(c.Use, " ")[0]
|
||||
commands[name] = c
|
||||
}
|
||||
|
||||
activeCmd = rootCmd
|
||||
for i, a := range os.Args {
|
||||
if i == 0 {
|
||||
// don't consider the bin
|
||||
continue
|
||||
}
|
||||
if a == "packages" {
|
||||
// this is positively the first subcommand directive, and is "packages"
|
||||
activeCmd = packagesCmd
|
||||
break
|
||||
}
|
||||
if !strings.HasPrefix("-", a) {
|
||||
// this is the first non-switch provided and was not "packages"
|
||||
break
|
||||
// check to see if this argument may be a command
|
||||
if c, exists := commands[a]; exists {
|
||||
activeCmd = c
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,6 +74,7 @@ func initCmdAliasBindings() {
|
||||
fmt.Fprintln(os.Stderr, color.New(color.Bold, color.Red).Sprintf("The root command is deprecated, please use the 'packages' subcommand"))
|
||||
}
|
||||
|
||||
if activeCmd == packagesCmd || activeCmd == rootCmd {
|
||||
// note: we need to lazily bind config options since they are shared between both the root command
|
||||
// and the packages command. Otherwise there will be global viper state that is in contention.
|
||||
// See for more details: https://github.com/spf13/viper/issues/233 . Additionally, the bindings must occur BEFORE
|
||||
@ -78,6 +84,11 @@ func initCmdAliasBindings() {
|
||||
if err := bindConfigOptions(activeCmd.Flags()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
if err := bindConfigOptions(packagesCmd.Flags()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func initAppConfig() {
|
||||
|
||||
@ -141,7 +141,7 @@ func setPackageFlags(flags *pflag.FlagSet) {
|
||||
func bindConfigOptions(flags *pflag.FlagSet) error {
|
||||
///////// Formatting & Input options //////////////////////////////////////////////
|
||||
|
||||
if err := viper.BindPFlag("packages.scope", flags.Lookup("scope")); err != nil {
|
||||
if err := viper.BindPFlag("package.cataloger.scope", flags.Lookup("scope")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -194,14 +194,14 @@ func packagesExecWorker(userInput string) <-chan error {
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
catalog, d, err := syft.CatalogPackages(src, appConfig.Packages.ScopeOpt)
|
||||
catalog, d, err := syft.CatalogPackages(src, appConfig.Package.Cataloger.ScopeOpt)
|
||||
if err != nil {
|
||||
errs <- fmt.Errorf("failed to catalog input: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if appConfig.Anchore.Host != "" {
|
||||
if err := runPackageSbomUpload(src, src.Metadata, catalog, d, appConfig.Packages.ScopeOpt); err != nil {
|
||||
if err := runPackageSbomUpload(src, src.Metadata, catalog, d, appConfig.Package.Cataloger.ScopeOpt); err != nil {
|
||||
errs <- err
|
||||
return
|
||||
}
|
||||
@ -213,7 +213,7 @@ func packagesExecWorker(userInput string) <-chan error {
|
||||
SourceMetadata: src.Metadata,
|
||||
Catalog: catalog,
|
||||
Distro: d,
|
||||
Scope: appConfig.Packages.ScopeOpt,
|
||||
Scope: appConfig.Package.Cataloger.ScopeOpt,
|
||||
}),
|
||||
})
|
||||
}()
|
||||
|
||||
@ -3,6 +3,8 @@ package cmd
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anchore/syft/internal"
|
||||
|
||||
"github.com/anchore/syft/internal/bus"
|
||||
"github.com/anchore/syft/internal/presenter/poweruser"
|
||||
"github.com/anchore/syft/internal/ui"
|
||||
@ -13,14 +15,24 @@ import (
|
||||
"github.com/wagoodman/go-partybus"
|
||||
)
|
||||
|
||||
const powerUserExample = ` {{.appName}} {{.command}} <image>
|
||||
|
||||
Only image sources are supported (e.g. docker: , docker-archive: , oci: , etc.), the directory source (dir:) is not supported.
|
||||
|
||||
All behavior is controlled via application configuration and environment variables (see https://github.com/anchore/syft#configuration)
|
||||
`
|
||||
|
||||
var powerUserOpts = struct {
|
||||
configPath string
|
||||
}{}
|
||||
|
||||
var powerUserCmd = &cobra.Command{
|
||||
Use: "power-user [SOURCE]",
|
||||
Use: "power-user [IMAGE]",
|
||||
Short: "Run bulk operations on container images",
|
||||
Example: ` {{.appName}} power-user <image>`,
|
||||
Example: internal.Tprintf(powerUserExample, map[string]interface{}{
|
||||
"appName": internal.ApplicationName,
|
||||
"command": "power-user",
|
||||
}),
|
||||
Args: cobra.ExactArgs(1),
|
||||
Hidden: true,
|
||||
SilenceUsage: true,
|
||||
|
||||
@ -37,12 +37,12 @@ func powerUserTasks(src source.Source) ([]powerUserTask, error) {
|
||||
}
|
||||
|
||||
func catalogPackagesTask(src source.Source) powerUserTask {
|
||||
if !appConfig.Packages.CatalogingEnabled {
|
||||
if !appConfig.Package.Cataloger.Enabled {
|
||||
return nil
|
||||
}
|
||||
|
||||
task := func(results *poweruser.JSONDocumentConfig) error {
|
||||
packageCatalog, theDistro, err := syft.CatalogPackages(src, appConfig.Packages.ScopeOpt)
|
||||
packageCatalog, theDistro, err := syft.CatalogPackages(src, appConfig.Package.Cataloger.ScopeOpt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -57,11 +57,11 @@ func catalogPackagesTask(src source.Source) powerUserTask {
|
||||
}
|
||||
|
||||
func catalogFileMetadataTask(src source.Source) (powerUserTask, error) {
|
||||
if !appConfig.FileMetadata.CatalogingEnabled {
|
||||
if !appConfig.FileMetadata.Cataloger.Enabled {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
resolver, err := src.FileResolver(appConfig.FileMetadata.ScopeOpt)
|
||||
resolver, err := src.FileResolver(appConfig.FileMetadata.Cataloger.ScopeOpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -79,11 +79,11 @@ func catalogFileMetadataTask(src source.Source) (powerUserTask, error) {
|
||||
}
|
||||
|
||||
func catalogFileDigestTask(src source.Source) (powerUserTask, error) {
|
||||
if !appConfig.FileMetadata.CatalogingEnabled {
|
||||
if !appConfig.FileMetadata.Cataloger.Enabled {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
resolver, err := src.FileResolver(appConfig.FileMetadata.ScopeOpt)
|
||||
resolver, err := src.FileResolver(appConfig.FileMetadata.Cataloger.ScopeOpt)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
@ -15,6 +16,8 @@ import (
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var ErrApplicationConfigNotFound = fmt.Errorf("application config not found")
|
||||
|
||||
// Application is the main syft application configuration.
|
||||
type Application struct {
|
||||
ConfigPath string `yaml:",omitempty" json:"configPath"` // the location where the application config was read from (either from -c or discovered while loading)
|
||||
@ -25,7 +28,7 @@ type Application struct {
|
||||
Dev Development `yaml:"dev" json:"dev" mapstructure:"dev"`
|
||||
CheckForAppUpdate bool `yaml:"check-for-app-update" json:"check-for-app-update" mapstructure:"check-for-app-update"` // whether to check for an application update on start up or not
|
||||
Anchore anchore `yaml:"anchore" json:"anchore" mapstructure:"anchore"` // options for interacting with Anchore Engine/Enterprise
|
||||
Packages Packages `yaml:"packages" json:"packages" mapstructure:"packages"`
|
||||
Package Packages `yaml:"package" json:"package" mapstructure:"package"`
|
||||
FileMetadata FileMetadata `yaml:"file-metadata" json:"file-metadata" mapstructure:"file-metadata"`
|
||||
}
|
||||
|
||||
@ -33,7 +36,9 @@ type Application struct {
|
||||
func LoadApplicationConfig(v *viper.Viper, cliOpts CliOnlyOptions) (*Application, error) {
|
||||
// the user may not have a config, and this is OK, we can use the default config + default cobra cli values instead
|
||||
setNonCliDefaultAppConfigValues(v)
|
||||
_ = readConfig(v, cliOpts.ConfigPath)
|
||||
if err := readConfig(v, cliOpts.ConfigPath); err != nil && !errors.Is(err, ErrApplicationConfigNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
config := &Application{
|
||||
CliOptions: cliOpts,
|
||||
@ -88,7 +93,7 @@ func (cfg *Application) build() error {
|
||||
}
|
||||
|
||||
for _, builder := range []func() error{
|
||||
cfg.Packages.build,
|
||||
cfg.Package.build,
|
||||
cfg.FileMetadata.build,
|
||||
} {
|
||||
if err := builder(); err != nil {
|
||||
@ -111,7 +116,9 @@ func (cfg Application) String() string {
|
||||
}
|
||||
|
||||
// readConfig attempts to read the given config path from disk or discover an alternate store location
|
||||
// nolint:funlen
|
||||
func readConfig(v *viper.Viper, configPath string) error {
|
||||
var err error
|
||||
v.AutomaticEnv()
|
||||
v.SetEnvPrefix(internal.ApplicationName)
|
||||
// allow for nested options to be specified via environment variables
|
||||
@ -132,16 +139,20 @@ func readConfig(v *viper.Viper, configPath string) error {
|
||||
|
||||
// 1. look for .<appname>.yaml (in the current directory)
|
||||
v.AddConfigPath(".")
|
||||
v.SetConfigName(internal.ApplicationName)
|
||||
if err := v.ReadInConfig(); err == nil {
|
||||
v.SetConfigName("." + internal.ApplicationName)
|
||||
if err = v.ReadInConfig(); err == nil {
|
||||
return nil
|
||||
} else if !errors.As(err, &viper.ConfigFileNotFoundError{}) {
|
||||
return fmt.Errorf("unable to parse config=%q: %w", v.ConfigFileUsed(), err)
|
||||
}
|
||||
|
||||
// 2. look for .<appname>/config.yaml (in the current directory)
|
||||
v.AddConfigPath("." + internal.ApplicationName)
|
||||
v.SetConfigName("config")
|
||||
if err := v.ReadInConfig(); err == nil {
|
||||
if err = v.ReadInConfig(); err == nil {
|
||||
return nil
|
||||
} else if !errors.As(err, &viper.ConfigFileNotFoundError{}) {
|
||||
return fmt.Errorf("unable to parse config=%q: %w", v.ConfigFileUsed(), err)
|
||||
}
|
||||
|
||||
// 3. look for ~/.<appname>.yaml
|
||||
@ -149,8 +160,10 @@ func readConfig(v *viper.Viper, configPath string) error {
|
||||
if err == nil {
|
||||
v.AddConfigPath(home)
|
||||
v.SetConfigName("." + internal.ApplicationName)
|
||||
if err := v.ReadInConfig(); err == nil {
|
||||
if err = v.ReadInConfig(); err == nil {
|
||||
return nil
|
||||
} else if !errors.As(err, &viper.ConfigFileNotFoundError{}) {
|
||||
return fmt.Errorf("unable to parse config=%q: %w", v.ConfigFileUsed(), err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -160,11 +173,13 @@ func readConfig(v *viper.Viper, configPath string) error {
|
||||
v.AddConfigPath(path.Join(dir, internal.ApplicationName))
|
||||
}
|
||||
v.SetConfigName("config")
|
||||
if err := v.ReadInConfig(); err == nil {
|
||||
if err = v.ReadInConfig(); err == nil {
|
||||
return nil
|
||||
} else if !errors.As(err, &viper.ConfigFileNotFoundError{}) {
|
||||
return fmt.Errorf("unable to parse config=%q: %w", v.ConfigFileUsed(), err)
|
||||
}
|
||||
|
||||
return fmt.Errorf("application config not found")
|
||||
return ErrApplicationConfigNotFound
|
||||
}
|
||||
|
||||
// setNonCliDefaultAppConfigValues ensures that there are sane defaults for values that do not have CLI equivalent options (where there would already be a default value)
|
||||
@ -174,8 +189,8 @@ func setNonCliDefaultAppConfigValues(v *viper.Viper) {
|
||||
v.SetDefault("check-for-app-update", true)
|
||||
v.SetDefault("dev.profile-cpu", false)
|
||||
v.SetDefault("dev.profile-mem", false)
|
||||
v.SetDefault("packages.cataloging-enabled", true)
|
||||
v.SetDefault("file-metadata.cataloging-enabled", true)
|
||||
v.SetDefault("file-metadata.scope", source.SquashedScope)
|
||||
v.SetDefault("package.cataloger.enabled", true)
|
||||
v.SetDefault("file-metadata.cataloger.enabled", true)
|
||||
v.SetDefault("file-metadata.cataloger.scope", source.SquashedScope)
|
||||
v.SetDefault("file-metadata.digests", []string{"sha256"})
|
||||
}
|
||||
|
||||
23
internal/config/cataloger_options.go
Normal file
23
internal/config/cataloger_options.go
Normal file
@ -0,0 +1,23 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
type catalogerOptions struct {
|
||||
Enabled bool `yaml:"enabled" json:"enabled" mapstructure:"enabled"`
|
||||
Scope string `yaml:"scope" json:"scope" mapstructure:"scope"`
|
||||
ScopeOpt source.Scope `yaml:"-" json:"-"`
|
||||
}
|
||||
|
||||
func (cfg *catalogerOptions) build() error {
|
||||
scopeOption := source.ParseScope(cfg.Scope)
|
||||
if scopeOption == source.UnknownScope {
|
||||
return fmt.Errorf("bad scope value %q", cfg.Scope)
|
||||
}
|
||||
cfg.ScopeOpt = scopeOption
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -1,24 +1,10 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
type FileMetadata struct {
|
||||
CatalogingEnabled bool `yaml:"cataloging-enabled" json:"cataloging-enabled" mapstructure:"cataloging-enabled"`
|
||||
Scope string `yaml:"scope" json:"scope" mapstructure:"scope"`
|
||||
ScopeOpt source.Scope `yaml:"-" json:"-"`
|
||||
Cataloger catalogerOptions `yaml:"cataloger" json:"cataloger" mapstructure:"cataloger"`
|
||||
Digests []string `yaml:"digests" json:"digests" mapstructure:"digests"`
|
||||
}
|
||||
|
||||
func (cfg *FileMetadata) build() error {
|
||||
scopeOption := source.ParseScope(cfg.Scope)
|
||||
if scopeOption == source.UnknownScope {
|
||||
return fmt.Errorf("bad scope value %q", cfg.Scope)
|
||||
}
|
||||
cfg.ScopeOpt = scopeOption
|
||||
|
||||
return nil
|
||||
return cfg.Cataloger.build()
|
||||
}
|
||||
|
||||
@ -1,23 +1,9 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/anchore/syft/syft/source"
|
||||
)
|
||||
|
||||
type Packages struct {
|
||||
CatalogingEnabled bool `yaml:"cataloging-enabled" json:"cataloging-enabled" mapstructure:"cataloging-enabled"`
|
||||
Scope string `yaml:"scope" json:"scope" mapstructure:"scope"`
|
||||
ScopeOpt source.Scope `yaml:"-" json:"-"`
|
||||
Cataloger catalogerOptions `yaml:"cataloger" json:"cataloger" mapstructure:"cataloger"`
|
||||
}
|
||||
|
||||
func (cfg *Packages) build() error {
|
||||
scopeOption := source.ParseScope(cfg.Scope)
|
||||
if scopeOption == source.UnknownScope {
|
||||
return fmt.Errorf("bad scope value %q", cfg.Scope)
|
||||
}
|
||||
cfg.ScopeOpt = scopeOption
|
||||
|
||||
return nil
|
||||
return cfg.Cataloger.build()
|
||||
}
|
||||
|
||||
@ -23,6 +23,9 @@ type JSONPackage struct {
|
||||
|
||||
func NewJSONPackages(catalog *pkg.Catalog) ([]JSONPackage, error) {
|
||||
artifacts := make([]JSONPackage, 0)
|
||||
if catalog == nil {
|
||||
return artifacts, nil
|
||||
}
|
||||
for _, p := range catalog.Sorted() {
|
||||
art, err := NewJSONPackage(p)
|
||||
if err != nil {
|
||||
|
||||
@ -15,7 +15,7 @@ type JSONDocument struct {
|
||||
|
||||
// NewJSONDocument creates and populates a new JSON document struct from the given cataloging results.
|
||||
func NewJSONDocument(config JSONDocumentConfig) (JSONDocument, error) {
|
||||
pkgsDoc, err := packages.NewJSONDocument(config.PackageCatalog, config.SourceMetadata, config.Distro, config.ApplicationConfig.Packages.ScopeOpt, config.ApplicationConfig)
|
||||
pkgsDoc, err := packages.NewJSONDocument(config.PackageCatalog, config.SourceMetadata, config.Distro, config.ApplicationConfig.Package.Cataloger.ScopeOpt, config.ApplicationConfig)
|
||||
if err != nil {
|
||||
return JSONDocument{}, err
|
||||
}
|
||||
|
||||
@ -6,6 +6,7 @@ package version
|
||||
import (
|
||||
"fmt"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const valueNotProvided = "[not provided]"
|
||||
@ -28,6 +29,13 @@ type Version struct {
|
||||
Platform string `json:"platform"` // GOOS and GOARCH at build-time
|
||||
}
|
||||
|
||||
func (v Version) IsProductionBuild() bool {
|
||||
if strings.Contains(v.Version, "SNAPSHOT") || strings.Contains(v.Version, valueNotProvided) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// FromBuild provides all version details
|
||||
func FromBuild() Version {
|
||||
return Version{
|
||||
|
||||
@ -20,13 +20,13 @@ var latestAppVersionURL = struct {
|
||||
|
||||
// IsUpdateAvailable indicates if there is a newer application version available, and if so, what the new version is.
|
||||
func IsUpdateAvailable() (bool, string, error) {
|
||||
currentVersionStr := FromBuild().Version
|
||||
currentVersion, err := hashiVersion.NewVersion(currentVersionStr)
|
||||
if err != nil {
|
||||
if currentVersionStr == valueNotProvided {
|
||||
// this is the default build arg and should be ignored (this is not an error case)
|
||||
currentBuildInfo := FromBuild()
|
||||
if !currentBuildInfo.IsProductionBuild() {
|
||||
// don't allow for non-production builds to check for a version.
|
||||
return false, "", nil
|
||||
}
|
||||
currentVersion, err := hashiVersion.NewVersion(currentBuildInfo.Version)
|
||||
if err != nil {
|
||||
return false, "", fmt.Errorf("failed to parse current application version: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@ -81,6 +81,15 @@ func TestIsUpdateAvailable(t *testing.T) {
|
||||
newVersion: "",
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "SnapshotBuildVersion",
|
||||
buildVersion: "2.0.0-SHAPSHOT-a78bf9c",
|
||||
latestVersion: "1.0.0",
|
||||
code: 200,
|
||||
isAvailable: false,
|
||||
newVersion: "",
|
||||
err: false,
|
||||
},
|
||||
{
|
||||
name: "BadUpdateValidVersion",
|
||||
buildVersion: "1.0.0",
|
||||
|
||||
@ -45,6 +45,10 @@ func ownershipByFilesRelationships(catalog *Catalog) []Relationship {
|
||||
func findOwnershipByFilesRelationships(catalog *Catalog) map[ID]map[ID]*strset.Set {
|
||||
var relationships = make(map[ID]map[ID]*strset.Set)
|
||||
|
||||
if catalog == nil {
|
||||
return relationships
|
||||
}
|
||||
|
||||
for _, candidateOwnerPkg := range catalog.Sorted() {
|
||||
if candidateOwnerPkg.Metadata == nil {
|
||||
continue
|
||||
|
||||
@ -71,7 +71,7 @@ func TestPackagesCmdFlags(t *testing.T) {
|
||||
{
|
||||
name: "packages-scope-env-binding",
|
||||
env: map[string]string{
|
||||
"SYFT_PACKAGES_SCOPE": "all-layers",
|
||||
"SYFT_PACKAGE_CATALOGER_SCOPE": "all-layers",
|
||||
},
|
||||
args: []string{"packages", "-o", "json", request},
|
||||
assertions: []traitAssertion{
|
||||
|
||||
@ -25,6 +25,7 @@ func TestPowerUserCmdFlags(t *testing.T) {
|
||||
name: "default-results",
|
||||
args: []string{"power-user", request},
|
||||
assertions: []traitAssertion{
|
||||
assertNotInOutput(" command is deprecated"), // only the root command should be deprecated
|
||||
assertInOutput(`"type": "regularFile"`), // proof of file-metadata data
|
||||
assertInOutput(`"algorithm": "sha256"`), // proof of file-metadata default digest algorithm of sha256
|
||||
assertInOutput(`"metadataType": "ApkMetadata"`), // proof of package artifacts data
|
||||
|
||||
@ -45,16 +45,19 @@ func getSyftCommand(t testing.TB, args ...string) *exec.Cmd {
|
||||
|
||||
var binaryLocation string
|
||||
if os.Getenv("SYFT_BINARY_LOCATION") != "" {
|
||||
// SYFT_BINARY_LOCATION is relative to the repository root. (e.g., "snapshot/syft-linux_amd64/syft")
|
||||
// This value is transformed due to the CLI tests' need for a path relative to the test directory.
|
||||
binaryLocation = path.Join(repoRoot(t), os.Getenv("SYFT_BINARY_LOCATION"))
|
||||
// SYFT_BINARY_LOCATION is the absolute path to the snapshot binary
|
||||
binaryLocation = os.Getenv("SYFT_BINARY_LOCATION")
|
||||
} else {
|
||||
os := runtime.GOOS
|
||||
if os == "darwin" {
|
||||
os = "macos_darwin"
|
||||
// note: there is a subtle - vs _ difference between these versions
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
binaryLocation = path.Join(repoRoot(t), fmt.Sprintf("snapshot/syft-macos_darwin_%s/syft", runtime.GOARCH))
|
||||
case "linux":
|
||||
binaryLocation = path.Join(repoRoot(t), fmt.Sprintf("snapshot/syft_linux_%s/syft", runtime.GOARCH))
|
||||
default:
|
||||
t.Fatalf("unsupported OS: %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
binaryLocation = path.Join(repoRoot(t), fmt.Sprintf("snapshot/syft-%s_%s/syft", os, runtime.GOARCH))
|
||||
}
|
||||
return exec.Command(binaryLocation, args...)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user