go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/cli/config/path.go (about) 1 // Copyright (c) Mondoo, Inc. 2 // SPDX-License-Identifier: BUSL-1.1 3 4 package config 5 6 import ( 7 "os" 8 "path/filepath" 9 "runtime" 10 11 "github.com/cockroachdb/errors" 12 homedir "github.com/mitchellh/go-homedir" 13 "github.com/rs/zerolog/log" 14 "github.com/spf13/afero" 15 ) 16 17 var ( 18 UserProvidedPath string 19 Path string 20 LoadedConfig bool 21 DefaultConfigFile = "mondoo.yml" 22 DefaultInventoryFile = "inventory.yml" 23 Source string 24 AppFs afero.Fs 25 ) 26 27 func init() { 28 AppFs = afero.NewOsFs() 29 } 30 31 func probePath(path string, asFile bool) bool { 32 stat, err := AppFs.Stat(path) 33 if err != nil { 34 if os.IsNotExist(err) { 35 return false 36 } 37 log.Warn().Str("path", path).Msg("detected Schrödinger's path, cannot detect if it is usable") 38 return false 39 } 40 41 if !asFile { 42 return stat.Mode().IsDir() 43 } 44 45 if !stat.Mode().IsRegular() { 46 log.Warn().Str("path", path).Msg("cannot use configuration file, it doesn't look like a regular file") 47 return false 48 } 49 50 f, err := AppFs.Open(path) 51 if err != nil { 52 return false 53 } 54 defer f.Close() 55 return true 56 } 57 58 // ProbeDir tests a path if it's a directory and it exists 59 func ProbeDir(path string) bool { 60 return probePath(path, false) 61 } 62 63 // ProbeFile tests a path if it's a file and if we can access it 64 func ProbeFile(path string) bool { 65 return probePath(path, true) 66 } 67 68 // HomePath returns the user-level path for Mondoo. The given argument 69 // is appended and checked if it is accessible and regular. 70 // Returns error if the home directory could not be determined. 71 func HomePath(childPath ...string) (string, error) { 72 home, err := homedir.Dir() 73 if err != nil { 74 return "", errors.Wrap(err, "failed to determine user home directory") 75 } 76 77 parts := append([]string{home, ".config", "mondoo"}, childPath...) 78 homeConfig := filepath.Join(parts...) 79 return homeConfig, nil 80 } 81 82 func systemPath(isConfig bool, childPath ...string) string { 83 var parts []string 84 if runtime.GOOS == "windows" { 85 parts = append([]string{`C:\ProgramData\Mondoo\`}, childPath...) 86 } else if runtime.GOOS == "darwin" { 87 if isConfig { 88 parts = append([]string{"/Library", "Mondoo", "etc"}, childPath...) 89 } else { 90 parts = append([]string{"/Library", "Mondoo"}, childPath...) 91 } 92 } else { 93 if isConfig { 94 parts = append([]string{"/etc", "opt", "mondoo"}, childPath...) 95 } else { 96 parts = append([]string{"/opt", "mondoo"}, childPath...) 97 } 98 } 99 100 systemConfig := filepath.Join(parts...) 101 return systemConfig 102 } 103 104 // SystemConfigPath returns the system-level config path for Mondoo. The given argument 105 // is appended and checked if it is accessible and regular. 106 func SystemConfigPath(childPath ...string) string { 107 return systemPath(true, childPath...) 108 } 109 110 // SystemDataPath returns the system-level data path for Mondoo. The given argument 111 // is appended and checked if it is accessible and regular. 112 func SystemDataPath(childPath ...string) string { 113 return systemPath(false, childPath...) 114 } 115 116 func autodetectConfig() string { 117 homeConfig, err := HomePath(DefaultConfigFile) 118 if err != nil { 119 log.Fatal().Err(err).Msg("failed to autodetect mondoo config") 120 } 121 if ProbeFile(homeConfig) { 122 return homeConfig 123 } 124 125 sysConfig := SystemConfigPath(DefaultConfigFile) 126 if ProbeFile(sysConfig) { 127 return sysConfig 128 } 129 130 // Note: At this point we don't have any config. However, we will have to 131 // set up a potential config, which may be auto-created for us. Pointing it to 132 // the system config by default may be problematic, since: 133 // 1. if you're using a regular user, you can't create/write that path 134 // 2. if you're root, we probably don't want to auto-create it there 135 // due to the far-reaching impact as it may influence all users 136 137 return homeConfig 138 } 139 140 // returns the inventory path relative to the config file 141 func InventoryPath(configPath string) (string, bool) { 142 inventoryPath := filepath.Join(filepath.Dir(configPath), DefaultInventoryFile) 143 return inventoryPath, ProbeFile(inventoryPath) 144 }