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  }