mirror of
https://github.com/anchore/syft.git
synced 2025-11-18 17:03:17 +01:00
add poweruser concerns to the application config
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
parent
ff4ed40d50
commit
f22d7d23c1
13
internal/config/anchore.go
Normal file
13
internal/config/anchore.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
type anchore struct {
|
||||||
|
// upload options
|
||||||
|
Host string `yaml:"host" json:"host" mapstructure:"host"` // -H , hostname of the engine/enterprise instance to upload to (setting this value enables upload)
|
||||||
|
Path string `yaml:"path" json:"path" mapstructure:"path"` // override the engine/enterprise API upload path
|
||||||
|
// IMPORTANT: do not show the username in any YAML/JSON output (sensitive information)
|
||||||
|
Username string `yaml:"-" json:"-" mapstructure:"username"` // -u , username to authenticate upload
|
||||||
|
// IMPORTANT: do not show the password in any YAML/JSON output (sensitive information)
|
||||||
|
Password string `yaml:"-" json:"-" mapstructure:"password"` // -p , password to authenticate upload
|
||||||
|
Dockerfile string `yaml:"dockerfile" json:"dockerfile" mapstructure:"dockerfile"` // -d , dockerfile to attach for upload
|
||||||
|
OverwriteExistingImage bool `yaml:"overwrite-existing-image" json:"overwrite-existing-image" mapstructure:"overwrite-existing-image"` // --overwrite-existing-image , if any of the SBOM components have already been uploaded this flag will ensure they are overwritten with the current upload
|
||||||
|
}
|
||||||
181
internal/config/application.go
Normal file
181
internal/config/application.go
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/anchore/syft/syft/source"
|
||||||
|
|
||||||
|
"github.com/adrg/xdg"
|
||||||
|
"github.com/anchore/syft/internal"
|
||||||
|
"github.com/mitchellh/go-homedir"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
"gopkg.in/yaml.v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
Output string `yaml:"output" json:"output" mapstructure:"output"` // -o, the Presenter hint string to use for report formatting
|
||||||
|
Quiet bool `yaml:"quiet" json:"quiet" mapstructure:"quiet"` // -q, indicates to not show any status output to stderr (ETUI or logging UI)
|
||||||
|
Log logging `yaml:"log" json:"log" mapstructure:"log"` // all logging-related options
|
||||||
|
CliOptions CliOnlyOptions `yaml:"-" json:"-"` // all options only available through the CLI (not via env vars or config)
|
||||||
|
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"`
|
||||||
|
FileMetadata FileMetadata `yaml:"file-metadata" json:"file-metadata" mapstructure:"file-metadata"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// LoadApplicationConfig populates the given viper object with application configuration discovered on disk
|
||||||
|
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)
|
||||||
|
|
||||||
|
config := &Application{
|
||||||
|
CliOptions: cliOpts,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := v.Unmarshal(config); err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to parse config: %w", err)
|
||||||
|
}
|
||||||
|
config.ConfigPath = v.ConfigFileUsed()
|
||||||
|
|
||||||
|
if err := config.build(); err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid application config: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return config, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// build inflates simple config values into syft native objects (or other complex objects) after the config is fully read in.
|
||||||
|
func (cfg *Application) build() error {
|
||||||
|
if cfg.Quiet {
|
||||||
|
// TODO: this is bad: quiet option trumps all other logging options
|
||||||
|
// we should be able to quiet the console logging and leave file logging alone...
|
||||||
|
// ... this will be an enhancement for later
|
||||||
|
cfg.Log.LevelOpt = logrus.PanicLevel
|
||||||
|
} else {
|
||||||
|
if cfg.Log.Level != "" {
|
||||||
|
if cfg.CliOptions.Verbosity > 0 {
|
||||||
|
return fmt.Errorf("cannot explicitly set log level (cfg file or env var) and use -v flag together")
|
||||||
|
}
|
||||||
|
|
||||||
|
lvl, err := logrus.ParseLevel(strings.ToLower(cfg.Log.Level))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("bad log level configured (%q): %w", cfg.Log.Level, err)
|
||||||
|
}
|
||||||
|
// set the log level explicitly
|
||||||
|
cfg.Log.LevelOpt = lvl
|
||||||
|
} else {
|
||||||
|
// set the log level implicitly
|
||||||
|
switch v := cfg.CliOptions.Verbosity; {
|
||||||
|
case v == 1:
|
||||||
|
cfg.Log.LevelOpt = logrus.InfoLevel
|
||||||
|
case v >= 2:
|
||||||
|
cfg.Log.LevelOpt = logrus.DebugLevel
|
||||||
|
default:
|
||||||
|
cfg.Log.LevelOpt = logrus.WarnLevel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.Anchore.Host == "" && cfg.Anchore.Dockerfile != "" {
|
||||||
|
return fmt.Errorf("cannot provide dockerfile option without enabling upload")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, builder := range []func() error{
|
||||||
|
cfg.Packages.build,
|
||||||
|
cfg.FileMetadata.build,
|
||||||
|
} {
|
||||||
|
if err := builder(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg Application) String() string {
|
||||||
|
// yaml is pretty human friendly (at least when compared to json)
|
||||||
|
appCfgStr, err := yaml.Marshal(&cfg)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
return string(appCfgStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// readConfig attempts to read the given config path from disk or discover an alternate store location
|
||||||
|
func readConfig(v *viper.Viper, configPath string) error {
|
||||||
|
v.AutomaticEnv()
|
||||||
|
v.SetEnvPrefix(internal.ApplicationName)
|
||||||
|
// allow for nested options to be specified via environment variables
|
||||||
|
// e.g. pod.context = APPNAME_POD_CONTEXT
|
||||||
|
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
|
||||||
|
|
||||||
|
// use explicitly the given user config
|
||||||
|
if configPath != "" {
|
||||||
|
v.SetConfigFile(configPath)
|
||||||
|
if err := v.ReadInConfig(); err != nil {
|
||||||
|
return fmt.Errorf("unable to read application config=%q : %w", configPath, err)
|
||||||
|
}
|
||||||
|
// don't fall through to other options if the config path was explicitly provided
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// start searching for valid configs in order...
|
||||||
|
|
||||||
|
// 1. look for .<appname>.yaml (in the current directory)
|
||||||
|
v.AddConfigPath(".")
|
||||||
|
v.SetConfigName(internal.ApplicationName)
|
||||||
|
if err := v.ReadInConfig(); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. look for .<appname>/config.yaml (in the current directory)
|
||||||
|
v.AddConfigPath("." + internal.ApplicationName)
|
||||||
|
v.SetConfigName("config")
|
||||||
|
if err := v.ReadInConfig(); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. look for ~/.<appname>.yaml
|
||||||
|
home, err := homedir.Dir()
|
||||||
|
if err == nil {
|
||||||
|
v.AddConfigPath(home)
|
||||||
|
v.SetConfigName("." + internal.ApplicationName)
|
||||||
|
if err := v.ReadInConfig(); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. look for <appname>/config.yaml in xdg locations (starting with xdg home config dir, then moving upwards)
|
||||||
|
v.AddConfigPath(path.Join(xdg.ConfigHome, internal.ApplicationName))
|
||||||
|
for _, dir := range xdg.ConfigDirs {
|
||||||
|
v.AddConfigPath(path.Join(dir, internal.ApplicationName))
|
||||||
|
}
|
||||||
|
v.SetConfigName("config")
|
||||||
|
if err := v.ReadInConfig(); err == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Errorf("application config not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// setNonCliDefaultAppConfigValues ensures that there are sane defaults for values that do not have CLI equivalent options (where there would already be a default value)
|
||||||
|
func setNonCliDefaultAppConfigValues(v *viper.Viper) {
|
||||||
|
v.SetDefault("anchore.path", "")
|
||||||
|
v.SetDefault("log.structured", false)
|
||||||
|
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("file-metadata.digests", []string{"sha256"})
|
||||||
|
}
|
||||||
7
internal/config/cli_only_options.go
Normal file
7
internal/config/cli_only_options.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
// CliOnlyOptions are options that are in the application config in memory, but are only exposed via CLI switches (not from unmarshaling a config file)
|
||||||
|
type CliOnlyOptions struct {
|
||||||
|
ConfigPath string // -c. where the read config is on disk
|
||||||
|
Verbosity int // -v or -vv , controlling which UI (ETUI vs logging) and what the log level should be
|
||||||
|
}
|
||||||
@ -1,228 +0,0 @@
|
|||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/adrg/xdg"
|
|
||||||
"github.com/anchore/syft/internal"
|
|
||||||
"github.com/anchore/syft/syft/presenter"
|
|
||||||
"github.com/anchore/syft/syft/source"
|
|
||||||
"github.com/mitchellh/go-homedir"
|
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"github.com/spf13/viper"
|
|
||||||
"gopkg.in/yaml.v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Application is the main syft application configuration.
|
|
||||||
type Application struct {
|
|
||||||
ConfigPath string `yaml:",omitempty"` // the location where the application config was read from (either from -c or discovered while loading)
|
|
||||||
PresenterOpt presenter.Option `yaml:"-"` // -o, the native Presenter.Option to use for report formatting
|
|
||||||
Output string `yaml:"output" mapstructure:"output"` // -o, the Presenter hint string to use for report formatting
|
|
||||||
ScopeOpt source.Scope `yaml:"-"` // -s, the native source.Scope option to use for how to catalog the container image
|
|
||||||
Scope string `yaml:"scope" mapstructure:"scope"` // -s, the source.Scope string hint for how to catalog the container image
|
|
||||||
Quiet bool `yaml:"quiet" mapstructure:"quiet"` // -q, indicates to not show any status output to stderr (ETUI or logging UI)
|
|
||||||
Log logging `yaml:"log" mapstructure:"log"` // all logging-related options
|
|
||||||
CliOptions CliOnlyOptions `yaml:"-"` // all options only available through the CLI (not via env vars or config)
|
|
||||||
Dev Development `mapstructure:"dev"`
|
|
||||||
CheckForAppUpdate bool `yaml:"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" mapstructure:"anchore"` // options for interacting with Anchore Engine/Enterprise
|
|
||||||
}
|
|
||||||
|
|
||||||
// CliOnlyOptions are options that are in the application config in memory, but are only exposed via CLI switches (not from unmarshaling a config file)
|
|
||||||
type CliOnlyOptions struct {
|
|
||||||
ConfigPath string // -c. where the read config is on disk
|
|
||||||
Verbosity int // -v or -vv , controlling which UI (ETUI vs logging) and what the log level should be
|
|
||||||
}
|
|
||||||
|
|
||||||
// logging contains all logging-related configuration options available to the user via the application config.
|
|
||||||
type logging struct {
|
|
||||||
Structured bool `yaml:"structured" mapstructure:"structured"` // show all log entries as JSON formatted strings
|
|
||||||
LevelOpt logrus.Level `yaml:"level"` // the native log level object used by the logger
|
|
||||||
Level string `yaml:"-" mapstructure:"level"` // the log level string hint
|
|
||||||
FileLocation string `yaml:"file" mapstructure:"file"` // the file path to write logs to
|
|
||||||
}
|
|
||||||
|
|
||||||
type anchore struct {
|
|
||||||
// upload options
|
|
||||||
UploadEnabled bool `yaml:"upload-enabled" mapstructure:"upload-enabled"` // whether to upload results to Anchore Engine/Enterprise (defaults to "false" unless there is the presence of -h CLI option)
|
|
||||||
Host string `yaml:"host" mapstructure:"host"` // -H , hostname of the engine/enterprise instance to upload to
|
|
||||||
Path string `yaml:"path" mapstructure:"path"` // override the engine/enterprise API upload path
|
|
||||||
Username string `yaml:"username" mapstructure:"username"` // -u , username to authenticate upload
|
|
||||||
Password string `yaml:"password" mapstructure:"password"` // -p , password to authenticate upload
|
|
||||||
Dockerfile string `yaml:"dockerfile" mapstructure:"dockerfile"` // -d , dockerfile to attach for upload
|
|
||||||
OverwriteExistingImage bool `yaml:"overwrite-existing-image" mapstructure:"overwrite-existing-image"` // --overwrite-existing-image , if any of the SBOM components have already been uploaded this flag will ensure they are overwritten with the current upload
|
|
||||||
}
|
|
||||||
|
|
||||||
type Development struct {
|
|
||||||
ProfileCPU bool `mapstructure:"profile-cpu"`
|
|
||||||
ProfileMem bool `mapstructure:"profile-mem"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// LoadApplicationConfig populates the given viper object with application configuration discovered on disk
|
|
||||||
func LoadApplicationConfig(v *viper.Viper, cliOpts CliOnlyOptions, wasHostnameSet bool) (*Application, error) {
|
|
||||||
// the user may not have a config, and this is OK, we can use the default config + default cobra cli values instead
|
|
||||||
setNonCliDefaultValues(v)
|
|
||||||
_ = readConfig(v, cliOpts.ConfigPath)
|
|
||||||
|
|
||||||
config := &Application{
|
|
||||||
CliOptions: cliOpts,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := v.Unmarshal(config); err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to parse config: %w", err)
|
|
||||||
}
|
|
||||||
config.ConfigPath = v.ConfigFileUsed()
|
|
||||||
|
|
||||||
if err := config.build(v, wasHostnameSet); err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return config, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// build inflates simple config values into syft native objects (or other complex objects) after the config is fully read in.
|
|
||||||
func (cfg *Application) build(v *viper.Viper, wasHostnameSet bool) error {
|
|
||||||
// set the presenter
|
|
||||||
presenterOption := presenter.ParseOption(cfg.Output)
|
|
||||||
if presenterOption == presenter.UnknownPresenter {
|
|
||||||
return fmt.Errorf("bad --output value '%s'", cfg.Output)
|
|
||||||
}
|
|
||||||
cfg.PresenterOpt = presenterOption
|
|
||||||
|
|
||||||
// set the source
|
|
||||||
scopeOption := source.ParseScope(cfg.Scope)
|
|
||||||
if scopeOption == source.UnknownScope {
|
|
||||||
return fmt.Errorf("bad --scope value '%s'", cfg.Scope)
|
|
||||||
}
|
|
||||||
cfg.ScopeOpt = scopeOption
|
|
||||||
|
|
||||||
if cfg.Quiet {
|
|
||||||
// TODO: this is bad: quiet option trumps all other logging options
|
|
||||||
// we should be able to quiet the console logging and leave file logging alone...
|
|
||||||
// ... this will be an enhancement for later
|
|
||||||
cfg.Log.LevelOpt = logrus.PanicLevel
|
|
||||||
} else {
|
|
||||||
if cfg.Log.Level != "" {
|
|
||||||
if cfg.CliOptions.Verbosity > 0 {
|
|
||||||
return fmt.Errorf("cannot explicitly set log level (cfg file or env var) and use -v flag together")
|
|
||||||
}
|
|
||||||
|
|
||||||
lvl, err := logrus.ParseLevel(strings.ToLower(cfg.Log.Level))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("bad log level configured (%q): %w", cfg.Log.Level, err)
|
|
||||||
}
|
|
||||||
// set the log level explicitly
|
|
||||||
cfg.Log.LevelOpt = lvl
|
|
||||||
} else {
|
|
||||||
// set the log level implicitly
|
|
||||||
switch v := cfg.CliOptions.Verbosity; {
|
|
||||||
case v == 1:
|
|
||||||
cfg.Log.LevelOpt = logrus.InfoLevel
|
|
||||||
case v >= 2:
|
|
||||||
cfg.Log.LevelOpt = logrus.DebugLevel
|
|
||||||
default:
|
|
||||||
cfg.Log.LevelOpt = logrus.WarnLevel
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// check if upload should be done relative to the CLI and config behavior
|
|
||||||
if !v.IsSet("anchore.upload-enabled") && wasHostnameSet {
|
|
||||||
// we know the user didn't specify to upload in the config file and a --hostname option was provided (so set upload)
|
|
||||||
cfg.Anchore.UploadEnabled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if !cfg.Anchore.UploadEnabled && cfg.Anchore.Dockerfile != "" {
|
|
||||||
return fmt.Errorf("cannot provide dockerfile option without enabling upload")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cfg Application) String() string {
|
|
||||||
// redact sensitive information
|
|
||||||
if cfg.Anchore.Username != "" {
|
|
||||||
cfg.Anchore.Username = "********"
|
|
||||||
}
|
|
||||||
|
|
||||||
if cfg.Anchore.Password != "" {
|
|
||||||
cfg.Anchore.Password = "********"
|
|
||||||
}
|
|
||||||
|
|
||||||
// yaml is pretty human friendly (at least when compared to json)
|
|
||||||
appCfgStr, err := yaml.Marshal(&cfg)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(appCfgStr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// readConfig attempts to read the given config path from disk or discover an alternate store location
|
|
||||||
func readConfig(v *viper.Viper, configPath string) error {
|
|
||||||
v.AutomaticEnv()
|
|
||||||
v.SetEnvPrefix(internal.ApplicationName)
|
|
||||||
// allow for nested options to be specified via environment variables
|
|
||||||
// e.g. pod.context = APPNAME_POD_CONTEXT
|
|
||||||
v.SetEnvKeyReplacer(strings.NewReplacer(".", "_", "-", "_"))
|
|
||||||
|
|
||||||
// use explicitly the given user config
|
|
||||||
if configPath != "" {
|
|
||||||
v.SetConfigFile(configPath)
|
|
||||||
if err := v.ReadInConfig(); err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// don't fall through to other options if this fails
|
|
||||||
return fmt.Errorf("unable to read config: %v", configPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
// start searching for valid configs in order...
|
|
||||||
|
|
||||||
// 1. look for .<appname>.yaml (in the current directory)
|
|
||||||
v.AddConfigPath(".")
|
|
||||||
v.SetConfigName(internal.ApplicationName)
|
|
||||||
if err := v.ReadInConfig(); err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. look for .<appname>/config.yaml (in the current directory)
|
|
||||||
v.AddConfigPath("." + internal.ApplicationName)
|
|
||||||
v.SetConfigName("config")
|
|
||||||
if err := v.ReadInConfig(); err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. look for ~/.<appname>.yaml
|
|
||||||
home, err := homedir.Dir()
|
|
||||||
if err == nil {
|
|
||||||
v.AddConfigPath(home)
|
|
||||||
v.SetConfigName("." + internal.ApplicationName)
|
|
||||||
if err := v.ReadInConfig(); err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. look for <appname>/config.yaml in xdg locations (starting with xdg home config dir, then moving upwards)
|
|
||||||
v.AddConfigPath(path.Join(xdg.ConfigHome, internal.ApplicationName))
|
|
||||||
for _, dir := range xdg.ConfigDirs {
|
|
||||||
v.AddConfigPath(path.Join(dir, internal.ApplicationName))
|
|
||||||
}
|
|
||||||
v.SetConfigName("config")
|
|
||||||
if err := v.ReadInConfig(); err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Errorf("application config not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// setNonCliDefaultValues ensures that there are sane defaults for values that do not have CLI equivalent options (where there would already be a default value)
|
|
||||||
func setNonCliDefaultValues(v *viper.Viper) {
|
|
||||||
v.SetDefault("log.level", "")
|
|
||||||
v.SetDefault("log.file", "")
|
|
||||||
v.SetDefault("log.structured", false)
|
|
||||||
v.SetDefault("check-for-app-update", true)
|
|
||||||
v.SetDefault("dev.profile-cpu", false)
|
|
||||||
v.SetDefault("dev.profile-mem", false)
|
|
||||||
}
|
|
||||||
6
internal/config/development.go
Normal file
6
internal/config/development.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
type Development struct {
|
||||||
|
ProfileCPU bool `yaml:"profile-cpu" json:"profile-cpu" mapstructure:"profile-cpu"`
|
||||||
|
ProfileMem bool `yaml:"profile-mem" json:"profile-mem" mapstructure:"profile-mem"`
|
||||||
|
}
|
||||||
24
internal/config/file_metadata.go
Normal file
24
internal/config/file_metadata.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
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:"-"`
|
||||||
|
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
|
||||||
|
}
|
||||||
11
internal/config/logging.go
Normal file
11
internal/config/logging.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import "github.com/sirupsen/logrus"
|
||||||
|
|
||||||
|
// logging contains all logging-related configuration options available to the user via the application config.
|
||||||
|
type logging struct {
|
||||||
|
Structured bool `yaml:"structured" json:"structured" mapstructure:"structured"` // show all log entries as JSON formatted strings
|
||||||
|
LevelOpt logrus.Level `yaml:"-" json:"-"` // the native log level object used by the logger
|
||||||
|
Level string `yaml:"level" json:"level" mapstructure:"level"` // the log level string hint
|
||||||
|
FileLocation string `yaml:"file" json:"file-location" mapstructure:"file"` // the file path to write logs to
|
||||||
|
}
|
||||||
23
internal/config/packages.go
Normal file
23
internal/config/packages.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
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:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user