Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 24 additions & 8 deletions cmd/sops/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,13 @@ import (
"github.com/getsops/sops/v3/version"
)

var log *logrus.Logger
var (
log *logrus.Logger

// Whether the config file warning was already shown to the user.
// Used and set by findConfigFile().
showedConfigFileWarning bool
)

func init() {
log = logging.NewLogger("CMD")
Expand Down Expand Up @@ -364,7 +370,7 @@ func main() {
if c.GlobalString("config") != "" {
configPath = c.GlobalString("config")
} else {
configPath, err = config.FindConfigFile(".")
configPath, err = findConfigFile()
if err != nil {
return common.NewExitError(err, codes.ErrorGeneric)
}
Expand Down Expand Up @@ -685,7 +691,7 @@ func main() {
if c.GlobalString("config") != "" {
configPath = c.GlobalString("config")
} else {
configPath, err = config.FindConfigFile(".")
configPath, err = findConfigFile()
if err != nil {
return common.NewExitError(err, codes.ErrorGeneric)
}
Expand Down Expand Up @@ -2183,11 +2189,21 @@ func keyservices(c *cli.Context) (svcs []keyservice.KeyServiceClient) {
return
}

// Wrapper of config.LookupConfigFile that takes care of handling the returned warning.
func findConfigFile() (string, error) {
result, err := config.LookupConfigFile(".")
if len(result.Warning) > 0 && !showedConfigFileWarning {
showedConfigFileWarning = true
log.Warn(result.Warning)
}
return result.Path, err
}

func loadStoresConfig(context *cli.Context, path string) (*config.StoresConfig, error) {
configPath := context.GlobalString("config")
if configPath == "" {
// Ignore config not found errors returned from FindConfigFile since the config file is not mandatory
foundPath, err := config.FindConfigFile(".")
// Ignore config not found errors returned from findConfigFile since the config file is not mandatory
foundPath, err := findConfigFile()
if err != nil {
return config.NewStoresConfig(), nil
}
Expand Down Expand Up @@ -2322,14 +2338,14 @@ func keyGroups(c *cli.Context, file string) ([]sops.KeyGroup, error) {
return []sops.KeyGroup{group}, nil
}

// loadConfig will look for an existing config file, either provided through the command line, or using config.FindConfigFile.
// loadConfig will look for an existing config file, either provided through the command line, or using findConfigFile
// Since a config file is not required, this function does not error when one is not found, and instead returns a nil config pointer
func loadConfig(c *cli.Context, file string, kmsEncryptionContext map[string]*string) (*config.Config, error) {
var err error
configPath := c.GlobalString("config")
if configPath == "" {
// Ignore config not found errors returned from FindConfigFile since the config file is not mandatory
configPath, err = config.FindConfigFile(".")
// Ignore config not found errors returned from findConfigFile since the config file is not mandatory
configPath, err = findConfigFile()
if err != nil {
// If we can't find a config file, but we were not explicitly requested to, assume it does not exist
return nil, nil
Expand Down
63 changes: 53 additions & 10 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,65 @@ func (fs osFS) Stat(name string) (os.FileInfo, error) {
var fs fileSystem = osFS{stat: os.Stat}

const (
maxDepth = 100
configFileName = ".sops.yaml"
maxDepth = 100
configFileName = ".sops.yaml"
alternateConfigName = ".sops.yml"
)

// FindConfigFile looks for a sops config file in the current working directory and on parent directories, up to the limit defined by the maxDepth constant.
func FindConfigFile(start string) (string, error) {
// ConfigFileResult contains the path to a config file and any warnings
type ConfigFileResult struct {
Path string
Warning string
}

// LookupConfigFile looks for a sops config file in the current working directory
// and on parent directories, up to the maxDepth limit.
// It returns a result containing the file path and any warnings.
func LookupConfigFile(start string) (ConfigFileResult, error) {
filepath := path.Dir(start)
var foundAlternatePath string

for i := 0; i < maxDepth; i++ {
_, err := fs.Stat(path.Join(filepath, configFileName))
if err != nil {
filepath = path.Join(filepath, "..")
} else {
return path.Join(filepath, configFileName), nil
configPath := path.Join(filepath, configFileName)
_, err := fs.Stat(configPath)
if err == nil {
result := ConfigFileResult{Path: configPath}

if foundAlternatePath != "" {
result.Warning = fmt.Sprintf(
"ignoring %q when searching for config file; the config file must be called %q; using %q instead",
foundAlternatePath, configFileName, configPath)
}
return result, nil
}

// Check for alternate filename if we haven't found one yet
if foundAlternatePath == "" {
alternatePath := path.Join(filepath, alternateConfigName)
_, altErr := fs.Stat(alternatePath)
if altErr == nil {
foundAlternatePath = alternatePath
}
}

filepath = path.Join(filepath, "..")
}
return "", fmt.Errorf("Config file not found")

// No config file found
result := ConfigFileResult{}
if foundAlternatePath != "" {
result.Warning = fmt.Sprintf(
"ignoring %q when searching for config file; the config file must be called %q",
foundAlternatePath, configFileName)
}

return result, fmt.Errorf("config file not found")
}

// FindConfigFile looks for a sops config file in the current working directory and on parent directories, up to the limit defined by the maxDepth constant.
func FindConfigFile(start string) (string, error) {
result, err := LookupConfigFile(start)
return result.Path, err
}

type DotenvStoreConfig struct{}
Expand Down
Loading