diff --git a/README.md b/README.md index 0331567ec..ff2d241bd 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ infisical

-

Open-source, E2EE, simple tool to manage secrets and configs across your team and infrastructure.

+

Open-source, end-to-end encrypted tool to manage secrets and configs across your team, devices, and infrastructure.

@@ -25,7 +25,7 @@ git commit activity - Cloudsmith downloads + Cloudsmith downloads Slack community channel @@ -42,7 +42,7 @@ [Korean language](i18n/README.ko.md) [Turkish language](i18n/README.tr.md) -**[Infisical](https://infisical.com)** is an open source, E2EE tool to help teams manage and sync secrets and configs across their development workflow and infrastructure. It's designed to be simple and take minutes to get going. +**[Infisical](https://infisical.com)** is an open source, end-to-end encrypted secret manager which you can use to centralize your API keys and configs. From Infisical, you can then distribute these secrets across your whole developemnt lifecycle - from development to production . It's designed to be simple and take minutes to get going. - **[User-Friendly Dashboard](https://infisical.com/docs/getting-started/dashboard/project)** to manage your team's secrets and configs within projects - **[Language-Agnostic CLI](https://infisical.com/docs/cli/overview)** that pulls and injects esecrets and configs into your local workflow @@ -56,8 +56,10 @@ - **[Point-in-time Secrets Recovery](https://infisical.com/docs/getting-started/dashboard/pit-recovery)** for rolling back to any snapshot of your secrets - **Role-based Access Controls** per environment - 🔜 **2FA** (next week) -- 🔜 **1-Click Deploy** to Digital Ocean and Heroku +- 🔜 **1-Click Deploy** to AWS - 🔜 **Automatic Secret Rotation** +- 🔜 **Smart Security Alerts** +- 🔜 **Secrets Rotation** - 🔜 **Slack & MS Teams** integrations And more. @@ -67,9 +69,8 @@ And more. To quickly get started, visit our [get started guide](https://infisical.com/docs/getting-started/introduction).

- - - + +

## 🔥 What's cool about this? @@ -98,13 +99,7 @@ Not sure where to get started? You can: - [GitHub Issues](https://github.com/Infisical/infisical-cli/issues) (For any bugs and errors you encounter using Infisical) - [Twitter](https://twitter.com/infisical) (Get news fast) -## 🌄 Status - -- [x] Public Alpha: Anyone can sign up over at [infisical.com](https://infisical.com) but there are some minor kinks. -- [ ] Public Beta: Stable enough for most non-enterprise use-cases. -- [ ] Public: Production-ready. - -## �🔌 Integrations +## 🔌 Integrations We're currently setting the foundation and building [integrations](https://infisical.com/docs/integrations/overview) so secrets can be synced everywhere. Any help is welcome! :) @@ -154,7 +149,7 @@ We're currently setting the foundation and building [integrations](https://infis - 🔜 AWS PS (https://github.com/Infisical/infisical/issues/286) + 🔜 Supabase @@ -194,8 +189,8 @@ We're currently setting the foundation and building [integrations](https://infis 🔜 TravisCI - - ✔️ Netlify + + ✔️ AWS Secrets Manager @@ -207,7 +202,9 @@ We're currently setting the foundation and building [integrations](https://infis 🔜 Bitbucket - 🔜 Supabase + + ✔️ AWS Parameter Store + @@ -223,7 +220,9 @@ We're currently setting the foundation and building [integrations](https://infis 🔜 Serverless - 🔜 AWS Lambda + + ✔️ Netlify + @@ -357,7 +356,7 @@ Infisical officially launched as v.1.0 on November 21st, 2022. There are a lot o - + ## 🌎 Translations diff --git a/cli/packages/cmd/init.go b/cli/packages/cmd/init.go index 413f61440..d5d9164ba 100644 --- a/cli/packages/cmd/init.go +++ b/cli/packages/cmd/init.go @@ -56,7 +56,7 @@ var initCmd = &cobra.Command{ workspaces := workspaceResponse.Workspaces if len(workspaces) == 0 { message := fmt.Sprintf("You don't have any projects created in Infisical. You must first create a project at %s", util.INFISICAL_TOKEN_NAME) - util.PrintMessageAndExit(message) + util.PrintErrorMessageAndExit(message) } var workspaceNames []string diff --git a/cli/packages/cmd/secrets.go b/cli/packages/cmd/secrets.go index 823505d7d..4bb8d0663 100644 --- a/cli/packages/cmd/secrets.go +++ b/cli/packages/cmd/secrets.go @@ -92,15 +92,13 @@ var secretsSetCmd = &cobra.Command{ PreRun: toggleDebug, Args: cobra.MinimumNArgs(1), Run: func(cmd *cobra.Command, args []string) { + util.RequireLocalWorkspaceFile() + environmentName, err := cmd.Flags().GetString("env") if err != nil { util.HandleError(err, "Unable to parse flag") } - if !util.IsSecretEnvironmentValid(environmentName) { - util.PrintMessageAndExit("You have entered a invalid environment name", "Environment names can only be prod, dev, test or staging") - } - workspaceFile, err := util.GetWorkSpaceFromFile() if err != nil { util.HandleError(err, "Unable to get your local config details") @@ -153,11 +151,11 @@ var secretsSetCmd = &cobra.Command{ for _, arg := range args { splitKeyValueFromArg := strings.SplitN(arg, "=", 2) if splitKeyValueFromArg[0] == "" || splitKeyValueFromArg[1] == "" { - util.PrintMessageAndExit("ensure that each secret has a none empty key and value. Modify the input and try again") + util.PrintErrorMessageAndExit("ensure that each secret has a none empty key and value. Modify the input and try again") } if unicode.IsNumber(rune(splitKeyValueFromArg[0][0])) { - util.PrintMessageAndExit("keys of secrets cannot start with a number. Modify the key name(s) and try again") + util.PrintErrorMessageAndExit("keys of secrets cannot start with a number. Modify the key name(s) and try again") } // Key and value from argument @@ -308,7 +306,7 @@ var secretsDeleteCmd = &cobra.Command{ if len(invalidSecretNamesThatDoNotExist) != 0 { message := fmt.Sprintf("secret name(s) [%v] does not exist in your project. To see which secrets exist run [infisical secrets]", strings.Join(invalidSecretNamesThatDoNotExist, ", ")) - util.PrintMessageAndExit(message) + util.PrintErrorMessageAndExit(message) } request := api.BatchDeleteSecretsBySecretIdsRequest{ @@ -337,11 +335,6 @@ func getSecretsByNames(cmd *cobra.Command, args []string) { util.HandleError(err, "Unable to parse flag") } - workspaceFileExists := util.WorkspaceConfigFileExistsInCurrentPath() - if !workspaceFileExists { - util.HandleError(err, "Unable to parse flag") - } - infisicalToken, err := cmd.Flags().GetString("token") if err != nil { util.HandleError(err, "Unable to parse flag") @@ -385,11 +378,6 @@ func generateExampleEnv(cmd *cobra.Command, args []string) { util.HandleError(err, "Unable to parse flag") } - workspaceFileExists := util.WorkspaceConfigFileExistsInCurrentPath() - if !workspaceFileExists { - util.HandleError(err, "Unable to parse flag") - } - infisicalToken, err := cmd.Flags().GetString("token") if err != nil { util.HandleError(err, "Unable to parse flag") @@ -406,6 +394,11 @@ func generateExampleEnv(cmd *cobra.Command, args []string) { } tagsHashToSecretKey := make(map[string]int) + slugsToFilerBy := make(map[string]int) + + for _, slug := range strings.Split(tagSlugs, ",") { + slugsToFilerBy[slug] = 1 + } type TagsAndSecrets struct { Secrets []models.SingleEnvironmentVariable @@ -422,6 +415,25 @@ func generateExampleEnv(cmd *cobra.Command, args []string) { return len(secrets[i].Tags) > len(secrets[j].Tags) }) + for i, secret := range secrets { + filteredTag := []struct { + ID string "json:\"_id\"" + Name string "json:\"name\"" + Slug string "json:\"slug\"" + Workspace string "json:\"workspace\"" + }{} + + for _, secretTag := range secret.Tags { + _, exists := slugsToFilerBy[secretTag.Slug] + if !exists { + filteredTag = append(filteredTag, secretTag) + } + } + + secret.Tags = filteredTag + secrets[i] = secret + } + for _, secret := range secrets { listOfTagSlugs := []string{} @@ -485,6 +497,8 @@ func generateExampleEnv(cmd *cobra.Command, args []string) { return len(listOfsecretDetails[i].Tags) < len(listOfsecretDetails[j].Tags) }) + tableOfContents := []string{} + fullyGeneratedDocuments := []string{} for _, secretDetails := range listOfsecretDetails { listOfKeyValue := []string{} @@ -525,11 +539,22 @@ func generateExampleEnv(cmd *cobra.Command, args []string) { heading := CenterString(strings.Join(listOfTagNames, " & "), 80) if len(listOfTagNames) == 0 { - fmt.Printf("\n%s \n", strings.Join(listOfKeyValue, "\n \n")) + fullyGeneratedDocuments = append(fullyGeneratedDocuments, fmt.Sprintf("\n%s \n", strings.Join(listOfKeyValue, "\n"))) } else { - fmt.Printf("\n\n\n%s \n%s \n", heading, strings.Join(listOfKeyValue, "\n \n")) + fullyGeneratedDocuments = append(fullyGeneratedDocuments, fmt.Sprintf("\n\n\n%s \n%s \n", heading, strings.Join(listOfKeyValue, "\n"))) + tableOfContents = append(tableOfContents, strings.ToUpper(strings.Join(listOfTagNames, " & "))) } } + + dashedList := []string{} + for _, item := range tableOfContents { + dashedList = append(dashedList, fmt.Sprintf("# - %s \n", item)) + } + if len(dashedList) > 0 { + fmt.Println(CenterString("TABLE OF CONTENTS", 80)) + fmt.Println(strings.Join(dashedList, "")) + } + fmt.Println(strings.Join(fullyGeneratedDocuments, "")) } func CenterString(s string, numStars int) string { diff --git a/cli/packages/models/cli.go b/cli/packages/models/cli.go index 1f86d6c8c..fca9ae0f2 100644 --- a/cli/packages/models/cli.go +++ b/cli/packages/models/cli.go @@ -39,7 +39,8 @@ type Workspace struct { } type WorkspaceConfigFile struct { - WorkspaceId string `json:"workspaceId"` + WorkspaceId string `json:"workspaceId"` + DefaultEnvironment string `json:"defaultEnvironment"` } type SymmetricEncryptionResult struct { diff --git a/cli/packages/util/helper.go b/cli/packages/util/helper.go index 3fd8853c4..2a7ac7317 100644 --- a/cli/packages/util/helper.go +++ b/cli/packages/util/helper.go @@ -65,29 +65,29 @@ func RequireLogin() { } if !currentUserDetails.IsUserLoggedIn { - PrintMessageAndExit("You must be logged in to run this command. To login, run [infisical login]") + PrintErrorMessageAndExit("You must be logged in to run this command. To login, run [infisical login]") } if currentUserDetails.LoginExpired { - PrintMessageAndExit("Your login expired, please login in again. To login, run [infisical login]") + PrintErrorMessageAndExit("Your login expired, please login in again. To login, run [infisical login]") } if currentUserDetails.UserCredentials.Email == "" && currentUserDetails.UserCredentials.JTWToken == "" && currentUserDetails.UserCredentials.PrivateKey == "" { - PrintMessageAndExit("One or more of your login details is empty. Please try logging in again via by running [infisical login]") + PrintErrorMessageAndExit("One or more of your login details is empty. Please try logging in again via by running [infisical login]") } } func RequireServiceToken() { serviceToken := os.Getenv(INFISICAL_TOKEN_NAME) if serviceToken == "" { - PrintMessageAndExit("No service token is found in your terminal") + PrintErrorMessageAndExit("No service token is found in your terminal") } } func RequireLocalWorkspaceFile() { workspaceFileExists := WorkspaceConfigFileExistsInCurrentPath() if !workspaceFileExists { - PrintMessageAndExit("It looks you have not yet connected this project to Infisical", "To do so, run [infisical init] then run your command again") + PrintErrorMessageAndExit("It looks you have not yet connected this project to Infisical", "To do so, run [infisical init] then run your command again") } workspaceFile, err := GetWorkSpaceFromFile() @@ -96,7 +96,7 @@ func RequireLocalWorkspaceFile() { } if workspaceFile.WorkspaceId == "" { - PrintMessageAndExit("Your project id is missing in your local config file. Please add it or run again [infisical init]") + PrintErrorMessageAndExit("Your project id is missing in your local config file. Please add it or run again [infisical init]") } } diff --git a/cli/packages/util/log.go b/cli/packages/util/log.go index 68144e074..4c11322c2 100644 --- a/cli/packages/util/log.go +++ b/cli/packages/util/log.go @@ -31,10 +31,10 @@ func PrintSuccessMessage(message string) { color.New(color.FgGreen).Println(message) } -func PrintMessageAndExit(messages ...string) { +func PrintErrorMessageAndExit(messages ...string) { if len(messages) > 0 { for _, message := range messages { - fmt.Println(message) + fmt.Fprintln(os.Stderr, message) } } @@ -42,5 +42,5 @@ func PrintMessageAndExit(messages ...string) { } func printError(e error) { - color.Red("Hmm, we ran into an error: %v", e) + color.New(color.FgRed).Fprintf(os.Stderr, "Hmm, we ran into an error: %v", e) } diff --git a/cli/packages/util/secrets.go b/cli/packages/util/secrets.go index 72f703b46..8caa07de4 100644 --- a/cli/packages/util/secrets.go +++ b/cli/packages/util/secrets.go @@ -131,6 +131,10 @@ func GetAllEnvironmentVariables(params models.GetAllSecretsParameters) ([]models return nil, err } + if workspaceFile.DefaultEnvironment != "" { + params.Environment = workspaceFile.DefaultEnvironment + } + // Verify environment err = ValidateEnvironmentName(params.Environment, workspaceFile.WorkspaceId, loggedInUserDetails.UserCredentials) if err != nil {