diff --git a/cli/packages/cmd/run.go b/cli/packages/cmd/run.go index 1c07f06c8..d9ed47a36 100644 --- a/cli/packages/cmd/run.go +++ b/cli/packages/cmd/run.go @@ -33,6 +33,13 @@ var runCmd = &cobra.Command{ return } + substitute, err := cmd.Flags().GetBool("substitute") + if err != nil { + log.Errorln("Unable to parse the substitute flag") + log.Debugln(err) + return + } + projectId, err := cmd.Flags().GetString("projectId") if err != nil { log.Errorln("Unable to parse the project id flag") @@ -82,7 +89,13 @@ var runCmd = &cobra.Command{ } } - execCmd(args[0], args[1:], envsFromApi) + if substitute { + substitutions := util.SubstituteSecrets(envsFromApi) + execCmd(args[0], args[1:], substitutions) + } else { + execCmd(args[0], args[1:], envsFromApi) + } + }, } @@ -90,6 +103,7 @@ func init() { rootCmd.AddCommand(runCmd) runCmd.Flags().StringP("env", "e", "dev", "Set the environment (dev, prod, etc.) from which your secrets should be pulled from") runCmd.Flags().String("projectId", "", "The project ID from which your secrets should be pulled from") + runCmd.Flags().Bool("substitute", true, "Parse shell variable substitutions in your secrets") } // Credit: inspired by AWS Valut diff --git a/cli/packages/util/secrets.go b/cli/packages/util/secrets.go index d38ec5805..5cf76d48e 100644 --- a/cli/packages/util/secrets.go +++ b/cli/packages/util/secrets.go @@ -222,8 +222,7 @@ func getExpandedEnvVariable(secrets []models.SingleEnvironmentVariable, variable return secret.Value } - fullyReplacedValue := secret.Value - fmt.Println("variablesToPopulate", variablesToPopulate) + valueToEdit := secret.Value for _, variableWithSign := range variablesToPopulate { variableWithoutSign := strings.Trim(variableWithSign, "}") variableWithoutSign = strings.Trim(variableWithoutSign, "${") @@ -236,10 +235,8 @@ func getExpandedEnvVariable(secrets []models.SingleEnvironmentVariable, variable var expandedVariableValue string if preComputedVariable, found := hashMapOfCompleteVariables[variableWithoutSign]; found { - fmt.Println("precompute for varable: ", variableWithoutSign) expandedVariableValue = preComputedVariable } else { - fmt.Println("compute for varable: ", variableWithoutSign) expandedVariableValue = getExpandedEnvVariable(secrets, variableWithoutSign, hashMapOfCompleteVariables, hashMapOfSelfRefs) hashMapOfCompleteVariables[variableWithoutSign] = expandedVariableValue } @@ -248,12 +245,13 @@ func getExpandedEnvVariable(secrets []models.SingleEnvironmentVariable, variable if _, found := hashMapOfSelfRefs[variableWithoutSign]; found { continue } else { - fullyReplacedValue = strings.ReplaceAll(fullyReplacedValue, variableWithSign, expandedVariableValue) + valueToEdit = strings.ReplaceAll(valueToEdit, variableWithSign, expandedVariableValue) } } - - return fullyReplacedValue } + + return valueToEdit + } else { continue } @@ -266,9 +264,9 @@ func SubstituteSecrets(secrets []models.SingleEnvironmentVariable) []models.Sing hashMapOfCompleteVariables := make(map[string]string) hashMapOfSelfRefs := make(map[string]string) expandedSecrets := []models.SingleEnvironmentVariable{} + for _, secret := range secrets { expandedVariable := getExpandedEnvVariable(secrets, secret.Key, hashMapOfCompleteVariables, hashMapOfSelfRefs) - fmt.Println(secret.Key, "=", expandedVariable) expandedSecrets = append(expandedSecrets, models.SingleEnvironmentVariable{ Key: secret.Key, Value: expandedVariable, diff --git a/cli/packages/util/secrets_test.go b/cli/packages/util/secrets_test.go index 02e0c0a83..513e4f7e3 100644 --- a/cli/packages/util/secrets_test.go +++ b/cli/packages/util/secrets_test.go @@ -7,61 +7,61 @@ import ( ) // References to self should return the value unaltered -// func Test_SubstituteSecrets_When_ReferenceToSelf(t *testing.T) { +func Test_SubstituteSecrets_When_ReferenceToSelf(t *testing.T) { -// var tests = []struct { -// Key string -// Value string -// ExpectedValue string -// }{ -// {Key: "A", Value: "${A}", ExpectedValue: "${A}"}, -// {Key: "A", Value: "${A} ${A}", ExpectedValue: "${A} ${A}"}, -// {Key: "A", Value: "${A}${A}", ExpectedValue: "${A}${A}"}, -// } + var tests = []struct { + Key string + Value string + ExpectedValue string + }{ + {Key: "A", Value: "${A}", ExpectedValue: "${A}"}, + {Key: "A", Value: "${A} ${A}", ExpectedValue: "${A} ${A}"}, + {Key: "A", Value: "${A}${A}", ExpectedValue: "${A}${A}"}, + } -// for _, test := range tests { -// secret := models.SingleEnvironmentVariable{ -// Key: test.Key, -// Value: test.Value, -// } + for _, test := range tests { + secret := models.SingleEnvironmentVariable{ + Key: test.Key, + Value: test.Value, + } -// secrets := []models.SingleEnvironmentVariable{secret} -// result := SubstituteSecrets(secrets) + secrets := []models.SingleEnvironmentVariable{secret} + result := SubstituteSecrets(secrets) -// if result[0].Value != test.ExpectedValue { -// t.Errorf("Test_SubstituteSecrets_When_ReferenceToSelf: expected %s but got %s for input %s", test.ExpectedValue, result[0].Value, test.Value) -// } + if result[0].Value != test.ExpectedValue { + t.Errorf("Test_SubstituteSecrets_When_ReferenceToSelf: expected %s but got %s for input %s", test.ExpectedValue, result[0].Value, test.Value) + } -// } -// } + } +} -// func Test_SubstituteSecrets_When_ReferenceDoesNotExist(t *testing.T) { +func Test_SubstituteSecrets_When_ReferenceDoesNotExist(t *testing.T) { -// var tests = []struct { -// Key string -// Value string -// ExpectedValue string -// }{ -// {Key: "A", Value: "${X}", ExpectedValue: "${X}"}, -// {Key: "A", Value: "${H}HELLO", ExpectedValue: "${H}HELLO"}, -// {Key: "A", Value: "${L}${S}", ExpectedValue: "${L}${S}"}, -// } + var tests = []struct { + Key string + Value string + ExpectedValue string + }{ + {Key: "A", Value: "${X}", ExpectedValue: "${X}"}, + {Key: "A", Value: "${H}HELLO", ExpectedValue: "${H}HELLO"}, + {Key: "A", Value: "${L}${S}", ExpectedValue: "${L}${S}"}, + } -// for _, test := range tests { -// secret := models.SingleEnvironmentVariable{ -// Key: test.Key, -// Value: test.Value, -// } + for _, test := range tests { + secret := models.SingleEnvironmentVariable{ + Key: test.Key, + Value: test.Value, + } -// secrets := []models.SingleEnvironmentVariable{secret} -// result := SubstituteSecrets(secrets) + secrets := []models.SingleEnvironmentVariable{secret} + result := SubstituteSecrets(secrets) -// if result[0].Value != test.ExpectedValue { -// t.Errorf("Test_SubstituteSecrets_When_ReferenceToSelf: expected %s but got %s for input %s", test.ExpectedValue, result[0].Value, test.Value) -// } + if result[0].Value != test.ExpectedValue { + t.Errorf("Test_SubstituteSecrets_When_ReferenceToSelf: expected %s but got %s for input %s", test.ExpectedValue, result[0].Value, test.Value) + } -// } -// } + } +} func Test_SubstituteSecrets_When_ReferenceDoesNotExist_And_Self_Referencing(t *testing.T) { @@ -71,14 +71,9 @@ func Test_SubstituteSecrets_When_ReferenceDoesNotExist_And_Self_Referencing(t *t ExpectedValue string }{ { - Key: "A", - Value: "*${A}* ${X}", - ExpectedValue: "*${A}*", - }, - { - Key: "H", - Value: "${X} >>>", - ExpectedValue: "*${A}*", + Key: "O", + Value: "${P} ==$$ ${X} ${UNKNOWN} ${A}", + ExpectedValue: "DOMAIN === ${A} DOMAIN >>> ==$$ DOMAIN ${UNKNOWN} ${A}", }, { Key: "X", @@ -86,25 +81,30 @@ func Test_SubstituteSecrets_When_ReferenceDoesNotExist_And_Self_Referencing(t *t ExpectedValue: "DOMAIN", }, { - Key: "P", - Value: "${X} === ${A} ${H}", - ExpectedValue: "DOMAIN", + Key: "A", + Value: "*${A}* ${X}", + ExpectedValue: "*${A}* DOMAIN", + }, + { + Key: "H", + Value: "${X} >>>", + ExpectedValue: "DOMAIN >>>", + }, + { + Key: "P", + Value: "DOMAIN === ${A} ${H}", + ExpectedValue: "DOMAIN === ${A} DOMAIN >>>", + }, + { + Key: "T", + Value: "${P} ==$$ ${X} ${UNKNOWN} ${A} ${P} ==$$ ${X} ${UNKNOWN} ${A}", + ExpectedValue: "DOMAIN === ${A} DOMAIN >>> ==$$ DOMAIN ${UNKNOWN} ${A} DOMAIN === ${A} DOMAIN >>> ==$$ DOMAIN ${UNKNOWN} ${A}", + }, + { + Key: "S", + Value: "${ SSS$$ ${HEY}", + ExpectedValue: "${ SSS$$ ${HEY}", }, - // { - // Key: "B", - // Value: "*${A}*TOKEN*${X}*", - // ExpectedValue: "*${A}*TOKEN*DOMAIN*", - // }, - // { - // Key: "C", - // Value: "*${A}* *${X}* *${B}* *${UNKNOWN}*", - // ExpectedValue: "*${A}* *DOMAIN* **${A}*TOKEN*DOMAIN** *${UNKNOWN}*", - // }, - // { - // Key: "W", - // Value: "*${W}* ${LOL $JK} *${C}* *${C}*", - // ExpectedValue: "*${W}* ${LOL $JK} **${A}* *DOMAIN* **${A}*TOKEN*DOMAIN** *${UNKNOWN}** **${A}* *DOMAIN* **${A}*TOKEN*DOMAIN** *${UNKNOWN}**", - // }, } secrets := []models.SingleEnvironmentVariable{} @@ -112,11 +112,49 @@ func Test_SubstituteSecrets_When_ReferenceDoesNotExist_And_Self_Referencing(t *t secrets = append(secrets, models.SingleEnvironmentVariable{Key: test.Key, Value: test.Value}) } - SubstituteSecrets(secrets) + results := SubstituteSecrets(secrets) - // if result[0].Value != test.ExpectedValue { - // t.Errorf("Test_SubstituteSecrets_When_ReferenceToSelf: expected %s but got %s for input %s", test.ExpectedValue, result[0].Value, test.Value) - // } - - // fmt.Println(result) + for index, expanded := range results { + if expanded.Value != tests[index].ExpectedValue { + t.Errorf("Test_SubstituteSecrets_When_ReferenceToSelf: expected [%s] but got [%s] for input [%s]", tests[index].ExpectedValue, expanded.Value, tests[index].Value) + } + } +} + +func Test_SubstituteSecrets_When_No_SubstituteNeeded(t *testing.T) { + + tests := []struct { + Key string + Value string + ExpectedValue string + }{ + { + Key: "DOMAIN", + Value: "infisical.com", + ExpectedValue: "infisical.com", + }, + { + Key: "API_KEY", + Value: "hdgsvjshcgkdckhevdkd", + ExpectedValue: "hdgsvjshcgkdckhevdkd", + }, + { + Key: "ENV", + Value: "PROD", + ExpectedValue: "PROD", + }, + } + + secrets := []models.SingleEnvironmentVariable{} + for _, test := range tests { + secrets = append(secrets, models.SingleEnvironmentVariable{Key: test.Key, Value: test.Value}) + } + + results := SubstituteSecrets(secrets) + + for index, expanded := range results { + if expanded.Value != tests[index].ExpectedValue { + t.Errorf("Test_SubstituteSecrets_When_ReferenceToSelf: expected [%s] but got [%s] for input [%s]", tests[index].ExpectedValue, expanded.Value, tests[index].Value) + } + } }