mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
add gitleak to cli
This commit is contained in:
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
"github.com/Infisical/infisical-merge/packages/models"
|
||||
"github.com/Infisical/infisical-merge/packages/util"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -30,11 +30,6 @@ var exportCmd = &cobra.Command{
|
||||
DisableFlagsInUseLine: true,
|
||||
Example: "infisical export --env=prod --format=json > secrets.json",
|
||||
Args: cobra.NoArgs,
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
toggleDebug(cmd, args)
|
||||
// util.RequireLogin()
|
||||
// util.RequireLocalWorkspaceFile()
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
environmentName, _ := cmd.Flags().GetString("env")
|
||||
if !cmd.Flags().Changed("env") {
|
||||
@@ -175,8 +170,7 @@ func formatAsJson(envs []models.SingleEnvironmentVariable) string {
|
||||
// Dump as a json array
|
||||
json, err := json.Marshal(envs)
|
||||
if err != nil {
|
||||
log.Errorln("Unable to marshal environment variables to JSON")
|
||||
log.Debugln(err)
|
||||
log.Err(err).Msgf("Unable to marshal environment variables to JSON")
|
||||
return ""
|
||||
}
|
||||
return string(json)
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/Infisical/infisical-merge/packages/util"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/manifoldco/promptui"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -30,8 +30,8 @@ var initCmd = &cobra.Command{
|
||||
if util.WorkspaceConfigFileExistsInCurrentPath() {
|
||||
shouldOverride, err := shouldOverrideWorkspacePrompt()
|
||||
if err != nil {
|
||||
log.Errorln("Unable to parse your answer")
|
||||
log.Debug(err)
|
||||
log.Error().Msg("Unable to parse your answer")
|
||||
log.Debug().Err(err)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var debugLogging bool
|
||||
|
||||
type PlainFormatter struct {
|
||||
}
|
||||
|
||||
func (f *PlainFormatter) Format(entry *log.Entry) ([]byte, error) {
|
||||
return []byte(fmt.Sprintf("%s\n", entry.Message)), nil
|
||||
}
|
||||
func toggleDebug(cmd *cobra.Command, args []string) {
|
||||
if debugLogging {
|
||||
log.Info("Debug logs enabled")
|
||||
log.SetLevel(log.DebugLevel)
|
||||
log.SetFormatter(&log.TextFormatter{})
|
||||
} else {
|
||||
plainFormatter := new(PlainFormatter)
|
||||
log.SetFormatter(plainFormatter)
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
"github.com/fatih/color"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/manifoldco/promptui"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/crypto/argon2"
|
||||
)
|
||||
@@ -44,12 +44,11 @@ var loginCmd = &cobra.Command{
|
||||
Use: "login",
|
||||
Short: "Login into your Infisical account",
|
||||
DisableFlagsInUseLine: true,
|
||||
PreRun: toggleDebug,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
currentLoggedInUserDetails, err := util.GetCurrentLoggedInUserDetails()
|
||||
// if the key can't be found or there is an error getting current credentials from key ring, allow them to override
|
||||
if err != nil && (strings.Contains(err.Error(), "The specified item could not be found in the keyring") || strings.Contains(err.Error(), "unable to get key from Keyring") || strings.Contains(err.Error(), "GetUserCredsFromKeyRing")) {
|
||||
log.Debug(err)
|
||||
log.Debug().Err(err)
|
||||
} else if err != nil {
|
||||
util.HandleError(err)
|
||||
}
|
||||
@@ -97,8 +96,8 @@ var loginCmd = &cobra.Command{
|
||||
|
||||
loginOneResponse, loginTwoResponse, err := getFreshUserCredentials(email, password)
|
||||
if err != nil {
|
||||
log.Infoln("Unable to authenticate with the provided credentials, please try again")
|
||||
log.Debugln(err)
|
||||
fmt.Println("Unable to authenticate with the provided credentials, please try again")
|
||||
log.Debug().Err(err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -152,7 +151,7 @@ var loginCmd = &cobra.Command{
|
||||
var decryptedPrivateKey []byte
|
||||
|
||||
if loginTwoResponse.EncryptionVersion == 1 {
|
||||
log.Debug("Login version 1")
|
||||
log.Debug().Msg("Login version 1")
|
||||
encryptedPrivateKey, _ := base64.StdEncoding.DecodeString(loginTwoResponse.EncryptedPrivateKey)
|
||||
tag, err := base64.StdEncoding.DecodeString(loginTwoResponse.Tag)
|
||||
if err != nil {
|
||||
@@ -175,7 +174,7 @@ var loginCmd = &cobra.Command{
|
||||
decryptedPrivateKey = computedDecryptedPrivateKey
|
||||
|
||||
} else if loginTwoResponse.EncryptionVersion == 2 {
|
||||
log.Debug("Login version 2")
|
||||
log.Debug().Msg("Login version 2")
|
||||
protectedKey, err := base64.StdEncoding.DecodeString(loginTwoResponse.ProtectedKey)
|
||||
if err != nil {
|
||||
util.HandleError(err)
|
||||
@@ -239,7 +238,7 @@ var loginCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
if string(decryptedPrivateKey) == "" || email == "" || loginTwoResponse.Token == "" {
|
||||
log.Debugf("[decryptedPrivateKey=%s] [email=%s] [loginTwoResponse.Token=%s]", string(decryptedPrivateKey), email, loginTwoResponse.Token)
|
||||
log.Debug().Msgf("[decryptedPrivateKey=%s] [email=%s] [loginTwoResponse.Token=%s]", string(decryptedPrivateKey), email, loginTwoResponse.Token)
|
||||
util.PrintErrorMessageAndExit("We were unable to fetch required details to complete your login. Run with -d to see more info")
|
||||
}
|
||||
|
||||
@@ -252,9 +251,9 @@ var loginCmd = &cobra.Command{
|
||||
err = util.StoreUserCredsInKeyRing(userCredentialsToBeStored)
|
||||
if err != nil {
|
||||
currentVault, _ := util.GetCurrentVaultBackend()
|
||||
log.Errorf("Unable to store your credentials in system vault [%s]. Rerun with flag -d to see full logs", currentVault)
|
||||
log.Errorln("To trouble shoot further, read https://infisical.com/docs/cli/faq")
|
||||
log.Debugln(err)
|
||||
log.Error().Msgf("Unable to store your credentials in system vault [%s]. Rerun with flag -d to see full logs", currentVault)
|
||||
log.Error().Msgf("\nTo trouble shoot further, read https://infisical.com/docs/cli/faq")
|
||||
log.Debug().Err(err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -397,7 +396,7 @@ func askForLoginCredentials() (email string, password string, err error) {
|
||||
}
|
||||
|
||||
func getFreshUserCredentials(email string, password string) (*api.GetLoginOneV2Response, *api.GetLoginTwoV2Response, error) {
|
||||
log.Debugln("getFreshUserCredentials:", "email", email, "password", password)
|
||||
log.Debug().Msg(fmt.Sprint("getFreshUserCredentials: ", "email", email, "password: ", password))
|
||||
httpClient := resty.New()
|
||||
httpClient.SetRetryCount(5)
|
||||
|
||||
|
||||
@@ -16,9 +16,6 @@ var resetCmd = &cobra.Command{
|
||||
DisableFlagsInUseLine: true,
|
||||
Example: "infisical reset",
|
||||
Args: cobra.NoArgs,
|
||||
PreRun: func(cmd *cobra.Command, args []string) {
|
||||
toggleDebug(cmd, args)
|
||||
},
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
// delete config
|
||||
_, pathToDir, err := util.GetFullConfigFilePath()
|
||||
|
||||
@@ -5,7 +5,10 @@ package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/Infisical/infisical-merge/packages/config"
|
||||
@@ -30,8 +33,8 @@ func Execute() {
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
|
||||
rootCmd.PersistentFlags().BoolVarP(&debugLogging, "debug", "d", false, "Enable verbose logging")
|
||||
cobra.OnInitialize(initLog)
|
||||
rootCmd.PersistentFlags().StringP("log-level", "l", "info", "log level (trace, debug, info, warn, error, fatal)")
|
||||
rootCmd.PersistentFlags().StringVar(&config.INFISICAL_URL, "domain", util.INFISICAL_DEFAULT_API_URL, "Point the CLI to your own backend [can also set via environment variable name: INFISICAL_API_URL]")
|
||||
rootCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) {
|
||||
if !util.IsRunningInDocker() {
|
||||
@@ -46,5 +49,30 @@ func init() {
|
||||
config.INFISICAL_URL = envInfisicalBackendUrl
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func initLog() {
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||
|
||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
ll, err := rootCmd.Flags().GetString("log-level")
|
||||
if err != nil {
|
||||
log.Fatal().Msg(err.Error())
|
||||
}
|
||||
switch strings.ToLower(ll) {
|
||||
case "trace":
|
||||
zerolog.SetGlobalLevel(zerolog.TraceLevel)
|
||||
case "debug":
|
||||
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
||||
case "info":
|
||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
case "warn":
|
||||
zerolog.SetGlobalLevel(zerolog.WarnLevel)
|
||||
case "err", "error":
|
||||
zerolog.SetGlobalLevel(zerolog.ErrorLevel)
|
||||
case "fatal":
|
||||
zerolog.SetGlobalLevel(zerolog.FatalLevel)
|
||||
default:
|
||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
"github.com/Infisical/infisical-merge/packages/models"
|
||||
"github.com/Infisical/infisical-merge/packages/util"
|
||||
"github.com/fatih/color"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -28,7 +28,6 @@ var runCmd = &cobra.Command{
|
||||
Use: "run [any infisical run command flags] -- [your application start command]",
|
||||
Short: "Used to inject environments variables into your application process",
|
||||
DisableFlagsInUseLine: true,
|
||||
PreRun: toggleDebug,
|
||||
Args: func(cmd *cobra.Command, args []string) error {
|
||||
// Check if the --command flag has been set
|
||||
commandFlagSet := cmd.Flags().Changed("command")
|
||||
@@ -124,7 +123,7 @@ var runCmd = &cobra.Command{
|
||||
env = append(env, s)
|
||||
}
|
||||
|
||||
log.Debugf("injecting the following environment variables into shell: %v", env)
|
||||
log.Debug().Msgf("injecting the following environment variables into shell: %v", env)
|
||||
|
||||
if cmd.Flags().Changed("command") {
|
||||
command := cmd.Flag("command").Value.String()
|
||||
@@ -217,7 +216,7 @@ func executeMultipleCommandWithEnvs(fullCommand string, secretsCount int, env []
|
||||
cmd.Env = env
|
||||
|
||||
color.Green("Injecting %v Infisical secrets into your application process", secretsCount)
|
||||
log.Debugf("executing command: %s %s %s \n", shell[0], shell[1], fullCommand)
|
||||
log.Debug().Msgf("executing command: %s %s %s \n", shell[0], shell[1], fullCommand)
|
||||
|
||||
return execCmd(cmd)
|
||||
}
|
||||
|
||||
307
cli/packages/cmd/scan-detect.go
Normal file
307
cli/packages/cmd/scan-detect.go
Normal file
@@ -0,0 +1,307 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Zachary Rice
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/Infisical/infisical-merge/config"
|
||||
"github.com/Infisical/infisical-merge/detect"
|
||||
"github.com/Infisical/infisical-merge/report"
|
||||
)
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(detectCmd)
|
||||
detectCmd.Flags().String("log-opts", "", "git log options")
|
||||
detectCmd.Flags().Bool("no-git", false, "treat git repo as a regular directory and scan those files, --log-opts has no effect on the scan when --no-git is set")
|
||||
detectCmd.Flags().Bool("pipe", false, "scan input from stdin, ex: `cat some_file | gitleaks detect --pipe`")
|
||||
detectCmd.Flags().Bool("follow-symlinks", false, "scan files that are symlinks to other files")
|
||||
|
||||
detectCmd.Flags().StringP("config", "c", "", configDescription)
|
||||
detectCmd.Flags().Int("exit-code", 1, "exit code when leaks have been encountered")
|
||||
detectCmd.Flags().StringP("source", "s", ".", "path to source")
|
||||
detectCmd.Flags().StringP("report-path", "r", "", "report file")
|
||||
detectCmd.Flags().StringP("report-format", "f", "json", "output format (json, csv, sarif)")
|
||||
detectCmd.Flags().StringP("baseline-path", "b", "", "path to baseline with issues that can be ignored")
|
||||
detectCmd.Flags().BoolP("verbose", "v", false, "show verbose output from scan (which file, where in the file, what secret)")
|
||||
detectCmd.Flags().BoolP("no-color", "", false, "turn off color for verbose output")
|
||||
detectCmd.Flags().Int("max-target-megabytes", 0, "files larger than this will be skipped")
|
||||
detectCmd.Flags().Bool("redact", false, "redact secrets from logs and stdout")
|
||||
|
||||
err := viper.BindPFlag("config", detectCmd.Flags().Lookup("config"))
|
||||
if err != nil {
|
||||
log.Fatal().Msgf("err binding config %s", err.Error())
|
||||
}
|
||||
|
||||
// Hide the flag
|
||||
detectCmd.Flags().MarkHidden("config")
|
||||
}
|
||||
|
||||
var detectCmd = &cobra.Command{
|
||||
Use: "scan",
|
||||
Short: "scan for secrets in repos, directories, and files",
|
||||
Run: runDetect,
|
||||
}
|
||||
|
||||
func runDetect(cmd *cobra.Command, args []string) {
|
||||
initScanConfig(cmd)
|
||||
|
||||
var (
|
||||
vc config.ViperConfig
|
||||
findings []report.Finding
|
||||
err error
|
||||
)
|
||||
|
||||
// Load config
|
||||
if err = viper.Unmarshal(&vc); err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to load config")
|
||||
}
|
||||
cfg, err := vc.Translate()
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to load config")
|
||||
}
|
||||
cfg.Path, _ = cmd.Flags().GetString("config")
|
||||
|
||||
// start timer
|
||||
start := time.Now()
|
||||
|
||||
// Setup detector
|
||||
detector := detect.NewDetector(cfg)
|
||||
detector.Config.Path, err = cmd.Flags().GetString("config")
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
source, err := cmd.Flags().GetString("source")
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
// if config path is not set, then use the {source}/.gitleaks.toml path.
|
||||
// note that there may not be a `{source}/.gitleaks.toml` file, this is ok.
|
||||
if detector.Config.Path == "" {
|
||||
detector.Config.Path = filepath.Join(source, ".gitleaks.toml")
|
||||
}
|
||||
// set verbose flag
|
||||
if detector.Verbose, err = cmd.Flags().GetBool("verbose"); err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
// set redact flag
|
||||
if detector.Redact, err = cmd.Flags().GetBool("redact"); err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
if detector.MaxTargetMegaBytes, err = cmd.Flags().GetInt("max-target-megabytes"); err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
// set color flag
|
||||
if detector.NoColor, err = cmd.Flags().GetBool("no-color"); err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
|
||||
if fileExists(filepath.Join(source, ".infisicalignore")) {
|
||||
if err = detector.AddGitleaksIgnore(filepath.Join(source, ".infisicalignore")); err != nil {
|
||||
log.Fatal().Err(err).Msg("could not call AddInfisicalIgnore")
|
||||
}
|
||||
}
|
||||
|
||||
// ignore findings from the baseline (an existing report in json format generated earlier)
|
||||
baselinePath, _ := cmd.Flags().GetString("baseline-path")
|
||||
if baselinePath != "" {
|
||||
err = detector.AddBaseline(baselinePath, source)
|
||||
if err != nil {
|
||||
log.Error().Msgf("Could not load baseline. The path must point of a gitleaks report generated using the default format: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// set follow symlinks flag
|
||||
if detector.FollowSymlinks, err = cmd.Flags().GetBool("follow-symlinks"); err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
|
||||
// set exit code
|
||||
exitCode, err := cmd.Flags().GetInt("exit-code")
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("could not get exit code")
|
||||
}
|
||||
|
||||
// determine what type of scan:
|
||||
// - git: scan the history of the repo
|
||||
// - no-git: scan files by treating the repo as a plain directory
|
||||
noGit, err := cmd.Flags().GetBool("no-git")
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("could not call GetBool() for no-git")
|
||||
}
|
||||
fromPipe, err := cmd.Flags().GetBool("pipe")
|
||||
if err != nil {
|
||||
log.Fatal().Err(err)
|
||||
}
|
||||
|
||||
// start the detector scan
|
||||
if noGit {
|
||||
findings, err = detector.DetectFiles(source)
|
||||
if err != nil {
|
||||
// don't exit on error, just log it
|
||||
log.Error().Err(err).Msg("")
|
||||
}
|
||||
} else if fromPipe {
|
||||
findings, err = detector.DetectReader(os.Stdin, 10)
|
||||
if err != nil {
|
||||
// log fatal to exit, no need to continue since a report
|
||||
// will not be generated when scanning from a pipe...for now
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
} else {
|
||||
var logOpts string
|
||||
logOpts, err = cmd.Flags().GetString("log-opts")
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
findings, err = detector.DetectGit(source, logOpts, detect.DetectType)
|
||||
if err != nil {
|
||||
// don't exit on error, just log it
|
||||
log.Error().Err(err).Msg("")
|
||||
}
|
||||
}
|
||||
|
||||
// log info about the scan
|
||||
if err == nil {
|
||||
log.Info().Msgf("scan completed in %s", FormatDuration(time.Since(start)))
|
||||
if len(findings) != 0 {
|
||||
log.Warn().Msgf("leaks found: %d", len(findings))
|
||||
} else {
|
||||
log.Info().Msg("no leaks found")
|
||||
}
|
||||
} else {
|
||||
log.Warn().Msgf("partial scan completed in %s", FormatDuration(time.Since(start)))
|
||||
if len(findings) != 0 {
|
||||
log.Warn().Msgf("%d leaks found in partial scan", len(findings))
|
||||
} else {
|
||||
log.Warn().Msg("no leaks found in partial scan")
|
||||
}
|
||||
}
|
||||
|
||||
// write report if desired
|
||||
reportPath, _ := cmd.Flags().GetString("report-path")
|
||||
ext, _ := cmd.Flags().GetString("report-format")
|
||||
if reportPath != "" {
|
||||
if err := report.Write(findings, cfg, ext, reportPath); err != nil {
|
||||
log.Fatal().Err(err).Msg("could not write")
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if len(findings) != 0 {
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
}
|
||||
|
||||
func fileExists(fileName string) bool {
|
||||
// check for a .gitleaksignore file
|
||||
info, err := os.Stat(fileName)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return false
|
||||
}
|
||||
|
||||
if info != nil && err == nil {
|
||||
if !info.IsDir() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func FormatDuration(d time.Duration) string {
|
||||
scale := 100 * time.Second
|
||||
// look for the max scale that is smaller than d
|
||||
for scale > d {
|
||||
scale = scale / 10
|
||||
}
|
||||
return d.Round(scale / 100).String()
|
||||
}
|
||||
|
||||
const configDescription = `config file path
|
||||
order of precedence:
|
||||
1. --config/-c
|
||||
2. env var GITLEAKS_CONFIG
|
||||
3. (--source/-s)/.gitleaks.toml
|
||||
If none of the three options are used, then gitleaks will use the default config`
|
||||
|
||||
func initScanConfig(cmd *cobra.Command) {
|
||||
cfgPath, err := cmd.Flags().GetString("config")
|
||||
if err != nil {
|
||||
log.Fatal().Msg(err.Error())
|
||||
}
|
||||
if cfgPath != "" {
|
||||
viper.SetConfigFile(cfgPath)
|
||||
log.Debug().Msgf("using gitleaks config %s from `--config`", cfgPath)
|
||||
} else if os.Getenv("GITLEAKS_CONFIG") != "" {
|
||||
envPath := os.Getenv("GITLEAKS_CONFIG")
|
||||
viper.SetConfigFile(envPath)
|
||||
log.Debug().Msgf("using gitleaks config from GITLEAKS_CONFIG env var: %s", envPath)
|
||||
} else {
|
||||
source, err := cmd.Flags().GetString("source")
|
||||
if err != nil {
|
||||
log.Fatal().Msg(err.Error())
|
||||
}
|
||||
fileInfo, err := os.Stat(source)
|
||||
if err != nil {
|
||||
log.Fatal().Msg(err.Error())
|
||||
}
|
||||
|
||||
if !fileInfo.IsDir() {
|
||||
log.Debug().Msgf("unable to load gitleaks config from %s since --source=%s is a file, using default config",
|
||||
filepath.Join(source, ".gitleaks.toml"), source)
|
||||
viper.SetConfigType("toml")
|
||||
if err = viper.ReadConfig(strings.NewReader(config.DefaultConfig)); err != nil {
|
||||
log.Fatal().Msgf("err reading toml %s", err.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if _, err := os.Stat(filepath.Join(source, ".gitleaks.toml")); os.IsNotExist(err) {
|
||||
log.Debug().Msgf("no gitleaks config found in path %s, using default gitleaks config", filepath.Join(source, ".gitleaks.toml"))
|
||||
viper.SetConfigType("toml")
|
||||
if err = viper.ReadConfig(strings.NewReader(config.DefaultConfig)); err != nil {
|
||||
log.Fatal().Msgf("err reading default config toml %s", err.Error())
|
||||
}
|
||||
return
|
||||
} else {
|
||||
log.Debug().Msgf("using existing gitleaks config %s from `(--source)/.gitleaks.toml`", filepath.Join(source, ".gitleaks.toml"))
|
||||
}
|
||||
|
||||
viper.AddConfigPath(source)
|
||||
viper.SetConfigName(".gitleaks")
|
||||
viper.SetConfigType("toml")
|
||||
}
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
log.Fatal().Msgf("unable to load gitleaks config, err: %s", err)
|
||||
}
|
||||
}
|
||||
160
cli/packages/cmd/scan-protect.go
Normal file
160
cli/packages/cmd/scan-protect.go
Normal file
@@ -0,0 +1,160 @@
|
||||
// MIT License
|
||||
|
||||
// Copyright (c) 2019 Zachary Rice
|
||||
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/Infisical/infisical-merge/config"
|
||||
"github.com/Infisical/infisical-merge/detect"
|
||||
"github.com/Infisical/infisical-merge/report"
|
||||
)
|
||||
|
||||
func init() {
|
||||
protectCmd.Flags().Bool("staged", false, "detect secrets in a --staged state")
|
||||
protectCmd.Flags().String("log-opts", "", "git log options")
|
||||
|
||||
protectCmd.Flags().StringP("config", "c", "", configDescription)
|
||||
protectCmd.Flags().Int("exit-code", 1, "exit code when leaks have been encountered")
|
||||
protectCmd.Flags().StringP("source", "s", ".", "path to source")
|
||||
protectCmd.Flags().StringP("report-path", "r", "", "report file")
|
||||
protectCmd.Flags().StringP("report-format", "f", "json", "output format (json, csv, sarif)")
|
||||
protectCmd.Flags().StringP("baseline-path", "b", "", "path to baseline with issues that can be ignored")
|
||||
protectCmd.Flags().BoolP("verbose", "v", false, "show verbose output from scan (which file, where in the file, what secret)")
|
||||
protectCmd.Flags().BoolP("no-color", "", false, "turn off color for verbose output")
|
||||
protectCmd.Flags().Int("max-target-megabytes", 0, "files larger than this will be skipped")
|
||||
protectCmd.Flags().Bool("redact", false, "redact secrets from logs and stdout")
|
||||
|
||||
err := viper.BindPFlag("config", protectCmd.Flags().Lookup("config"))
|
||||
if err != nil {
|
||||
log.Fatal().Msgf("err binding config %s", err.Error())
|
||||
}
|
||||
|
||||
// Hide the flag
|
||||
protectCmd.Flags().MarkHidden("config")
|
||||
|
||||
rootCmd.AddCommand(protectCmd)
|
||||
}
|
||||
|
||||
var protectCmd = &cobra.Command{
|
||||
Use: "prevent",
|
||||
Short: "scan for secrets in uncommitted changes in a git repo",
|
||||
Run: runProtect,
|
||||
}
|
||||
|
||||
func runProtect(cmd *cobra.Command, args []string) {
|
||||
initScanConfig(cmd)
|
||||
var vc config.ViperConfig
|
||||
|
||||
if err := viper.Unmarshal(&vc); err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to load config")
|
||||
}
|
||||
cfg, err := vc.Translate()
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to load config")
|
||||
}
|
||||
|
||||
cfg.Path, _ = cmd.Flags().GetString("config")
|
||||
exitCode, _ := cmd.Flags().GetInt("exit-code")
|
||||
staged, _ := cmd.Flags().GetBool("staged")
|
||||
start := time.Now()
|
||||
|
||||
// Setup detector
|
||||
detector := detect.NewDetector(cfg)
|
||||
detector.Config.Path, err = cmd.Flags().GetString("config")
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
source, err := cmd.Flags().GetString("source")
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
// if config path is not set, then use the {source}/.gitleaks.toml path.
|
||||
// note that there may not be a `{source}/.gitleaks.toml` file, this is ok.
|
||||
if detector.Config.Path == "" {
|
||||
detector.Config.Path = filepath.Join(source, ".gitleaks.toml")
|
||||
}
|
||||
// set verbose flag
|
||||
if detector.Verbose, err = cmd.Flags().GetBool("verbose"); err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
// set redact flag
|
||||
if detector.Redact, err = cmd.Flags().GetBool("redact"); err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
if detector.MaxTargetMegaBytes, err = cmd.Flags().GetInt("max-target-megabytes"); err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
// set color flag
|
||||
if detector.NoColor, err = cmd.Flags().GetBool("no-color"); err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
|
||||
if fileExists(filepath.Join(source, ".infisicalignore")) {
|
||||
if err = detector.AddGitleaksIgnore(filepath.Join(source, ".infisicalignore")); err != nil {
|
||||
log.Fatal().Err(err).Msg("could not call AddInfisicalIgnore")
|
||||
}
|
||||
}
|
||||
|
||||
// get log options for git scan
|
||||
logOpts, err := cmd.Flags().GetString("log-opts")
|
||||
if err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
|
||||
// start git scan
|
||||
var findings []report.Finding
|
||||
if staged {
|
||||
findings, err = detector.DetectGit(source, logOpts, detect.ProtectStagedType)
|
||||
} else {
|
||||
findings, err = detector.DetectGit(source, logOpts, detect.ProtectType)
|
||||
}
|
||||
if err != nil {
|
||||
// don't exit on error, just log it
|
||||
log.Error().Err(err).Msg("")
|
||||
}
|
||||
|
||||
// log info about the scan
|
||||
log.Info().Msgf("scan completed in %s", FormatDuration(time.Since(start)))
|
||||
if len(findings) != 0 {
|
||||
log.Warn().Msgf("leaks found: %d", len(findings))
|
||||
} else {
|
||||
log.Info().Msg("no leaks found")
|
||||
}
|
||||
|
||||
reportPath, _ := cmd.Flags().GetString("report-path")
|
||||
ext, _ := cmd.Flags().GetString("report-format")
|
||||
if reportPath != "" {
|
||||
if err = report.Write(findings, cfg, ext, reportPath); err != nil {
|
||||
log.Fatal().Err(err).Msg("")
|
||||
}
|
||||
}
|
||||
if len(findings) != 0 {
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ import (
|
||||
"github.com/Infisical/infisical-merge/packages/util"
|
||||
"github.com/Infisical/infisical-merge/packages/visualize"
|
||||
"github.com/go-resty/resty/v2"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -28,7 +28,6 @@ var secretsCmd = &cobra.Command{
|
||||
Short: "Used to create, read update and delete secrets",
|
||||
Use: "secrets",
|
||||
DisableFlagsInUseLine: true,
|
||||
PreRun: toggleDebug,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
environmentName, _ := cmd.Flags().GetString("env")
|
||||
@@ -73,7 +72,6 @@ var secretsGetCmd = &cobra.Command{
|
||||
Use: "get [secrets]",
|
||||
DisableFlagsInUseLine: true,
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
PreRun: toggleDebug,
|
||||
Run: getSecretsByNames,
|
||||
}
|
||||
|
||||
@@ -83,7 +81,6 @@ var secretsGenerateExampleEnvCmd = &cobra.Command{
|
||||
Use: "generate-example-env",
|
||||
DisableFlagsInUseLine: true,
|
||||
Args: cobra.NoArgs,
|
||||
PreRun: toggleDebug,
|
||||
Run: generateExampleEnv,
|
||||
}
|
||||
|
||||
@@ -92,7 +89,6 @@ var secretsSetCmd = &cobra.Command{
|
||||
Short: "Used set secrets",
|
||||
Use: "set [secrets]",
|
||||
DisableFlagsInUseLine: true,
|
||||
PreRun: toggleDebug,
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
util.RequireLocalWorkspaceFile()
|
||||
@@ -134,7 +130,7 @@ var secretsSetCmd = &cobra.Command{
|
||||
currentUsersPrivateKey, _ := base64.StdEncoding.DecodeString(loggedInUserDetails.UserCredentials.PrivateKey)
|
||||
|
||||
if len(currentUsersPrivateKey) == 0 || len(encryptedWorkspaceKeySenderPublicKey) == 0 {
|
||||
log.Debugf("Missing credentials for generating plainTextEncryptionKey: [currentUsersPrivateKey=%s] [encryptedWorkspaceKeySenderPublicKey=%s]", currentUsersPrivateKey, encryptedWorkspaceKeySenderPublicKey)
|
||||
log.Debug().Msgf("Missing credentials for generating plainTextEncryptionKey: [currentUsersPrivateKey=%s] [encryptedWorkspaceKeySenderPublicKey=%s]", currentUsersPrivateKey, encryptedWorkspaceKeySenderPublicKey)
|
||||
util.PrintErrorMessageAndExit("Some required user credentials are missing to generate your [plainTextEncryptionKey]. Please run [infisical login] then try again")
|
||||
}
|
||||
|
||||
@@ -278,7 +274,6 @@ var secretsDeleteCmd = &cobra.Command{
|
||||
Short: "Used to delete secrets by name",
|
||||
Use: "delete [secrets]",
|
||||
DisableFlagsInUseLine: true,
|
||||
PreRun: toggleDebug,
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
environmentName, _ := cmd.Flags().GetString("env")
|
||||
|
||||
@@ -4,9 +4,11 @@ Copyright (c) 2023 Infisical Inc.
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/99designs/keyring"
|
||||
"github.com/Infisical/infisical-merge/packages/util"
|
||||
log "github.com/sirupsen/logrus"
|
||||
"github.com/rs/zerolog/log"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -15,25 +17,24 @@ var vaultSetCmd = &cobra.Command{
|
||||
Use: "set [vault-name]",
|
||||
Short: "Used to set the vault backend to store your login details securely at rest",
|
||||
DisableFlagsInUseLine: true,
|
||||
PreRun: toggleDebug,
|
||||
Args: cobra.MinimumNArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
wantedVaultTypeName := args[0]
|
||||
currentVaultBackend, err := util.GetCurrentVaultBackend()
|
||||
if err != nil {
|
||||
log.Errorf("Unable to set vault to [%s] because of [err=%s]", wantedVaultTypeName, err)
|
||||
log.Error().Msgf("Unable to set vault to [%s] because of [err=%s]", wantedVaultTypeName, err)
|
||||
return
|
||||
}
|
||||
|
||||
if wantedVaultTypeName == string(currentVaultBackend) {
|
||||
log.Errorf("You are already on vault backend [%s]", currentVaultBackend)
|
||||
log.Error().Msgf("You are already on vault backend [%s]", currentVaultBackend)
|
||||
return
|
||||
}
|
||||
|
||||
if isVaultToSwitchToValid(wantedVaultTypeName) {
|
||||
configFile, err := util.GetConfigFile()
|
||||
if err != nil {
|
||||
log.Errorf("Unable to set vault to [%s] because of [err=%s]", wantedVaultTypeName, err)
|
||||
log.Error().Msgf("Unable to set vault to [%s] because of [err=%s]", wantedVaultTypeName, err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -42,13 +43,13 @@ var vaultSetCmd = &cobra.Command{
|
||||
|
||||
err = util.WriteConfigFile(&configFile)
|
||||
if err != nil {
|
||||
log.Errorf("Unable to set vault to [%s] because an error occurred when saving the config file [err=%s]", wantedVaultTypeName, err)
|
||||
log.Error().Msgf("Unable to set vault to [%s] because an error occurred when saving the config file [err=%s]", wantedVaultTypeName, err)
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("Successfully, switched vault backend from [%s] to [%s]. Please login in again to store your login details in the new vault with [infisical login]", currentVaultBackend, wantedVaultTypeName)
|
||||
fmt.Printf("\nSuccessfully, switched vault backend from [%s] to [%s]. Please login in again to store your login details in the new vault with [infisical login]", currentVaultBackend, wantedVaultTypeName)
|
||||
} else {
|
||||
log.Errorf("The requested vault type [%s] is not available on this system. Only the following vault backends are available for you system: %s", wantedVaultTypeName, keyring.AvailableBackends())
|
||||
log.Error().Msgf("The requested vault type [%s] is not available on this system. Only the following vault backends are available for you system: %s", wantedVaultTypeName, keyring.AvailableBackends())
|
||||
}
|
||||
},
|
||||
}
|
||||
@@ -58,7 +59,6 @@ var vaultCmd = &cobra.Command{
|
||||
Use: "vault",
|
||||
Short: "Used to manage where your Infisical login token is saved on your machine",
|
||||
DisableFlagsInUseLine: true,
|
||||
PreRun: toggleDebug,
|
||||
Args: cobra.NoArgs,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
printAvailableVaultBackends()
|
||||
@@ -66,17 +66,17 @@ var vaultCmd = &cobra.Command{
|
||||
}
|
||||
|
||||
func printAvailableVaultBackends() {
|
||||
log.Infof("The following vaults are available on your system:")
|
||||
fmt.Printf("The following vaults are available on your system:")
|
||||
for _, backend := range keyring.AvailableBackends() {
|
||||
log.Infof("- %s", backend)
|
||||
fmt.Printf("\n- %s", backend)
|
||||
}
|
||||
|
||||
currentVaultBackend, err := util.GetCurrentVaultBackend()
|
||||
if err != nil {
|
||||
log.Errorf("printAvailableVaultBackends: unable to print the available vault backend because of error [err=%s]", err)
|
||||
log.Error().Msgf("printAvailableVaultBackends: unable to print the available vault backend because of error [err=%s]", err)
|
||||
}
|
||||
|
||||
log.Infof("\nYou are currently using [%s] vault to store your login credentials", string(currentVaultBackend))
|
||||
fmt.Printf("\n\nYou are currently using [%s] vault to store your login credentials", string(currentVaultBackend))
|
||||
}
|
||||
|
||||
// Checks if the vault that the user wants to switch to is a valid available vault
|
||||
|
||||
Reference in New Issue
Block a user