mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-06 06:26:42 +00:00
Add an export command
This commit is contained in:
@@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
|
||||||
|
*/
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/Infisical/infisical-merge/packages/models"
|
||||||
|
"github.com/Infisical/infisical-merge/packages/util"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
FormatDotenv string = "dotenv"
|
||||||
|
FormatJson string = "json"
|
||||||
|
FormatCSV string = "csv"
|
||||||
|
)
|
||||||
|
|
||||||
|
// exportCmd represents the export command
|
||||||
|
var exportCmd = &cobra.Command{
|
||||||
|
Use: "export",
|
||||||
|
Short: "Used to export environment variables to a file",
|
||||||
|
DisableFlagsInUseLine: true,
|
||||||
|
Example: "infisical export --env=prod --format=json",
|
||||||
|
Args: cobra.NoArgs,
|
||||||
|
PreRun: toggleDebug,
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
envName, err := cmd.Flags().GetString("env")
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln("Unable to parse the environment flag")
|
||||||
|
log.Debugln(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldExpandSecrets, err := cmd.Flags().GetBool("expand")
|
||||||
|
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")
|
||||||
|
log.Debugln(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
format, err := cmd.Flags().GetString("format")
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln("Unable to parse the format flag")
|
||||||
|
log.Debugln(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
envsFromApi, err := util.GetAllEnvironmentVariables(projectId, envName)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln("Something went wrong when pulling secrets using your Infisical token. Double check the token, project id or environment name (dev, prod, ect.)")
|
||||||
|
log.Debugln(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var output string
|
||||||
|
if shouldExpandSecrets {
|
||||||
|
substitutions := util.SubstituteSecrets(envsFromApi)
|
||||||
|
output, err = formatEnvs(envName, substitutions, format)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
output, err = formatEnvs(envName, envsFromApi, format)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.Print(output)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
rootCmd.AddCommand(exportCmd)
|
||||||
|
exportCmd.Flags().StringP("env", "e", "dev", "Set the environment (dev, prod, etc.) from which your secrets should be pulled from")
|
||||||
|
exportCmd.Flags().String("projectId", "", "The project ID from which your secrets should be pulled from")
|
||||||
|
exportCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets")
|
||||||
|
exportCmd.Flags().StringP("format", "f", "dotenv", "Set the format of the output file (dotenv, json, csv)")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format according to the format flag
|
||||||
|
func formatEnvs(_ string, envs []models.SingleEnvironmentVariable, format string) (string, error) {
|
||||||
|
switch strings.ToLower(format) {
|
||||||
|
case FormatDotenv:
|
||||||
|
return formatAsDotEnv(envs), nil
|
||||||
|
case FormatJson:
|
||||||
|
return formatAsJson(envs), nil
|
||||||
|
case FormatCSV:
|
||||||
|
return formatAsCSV(envs), nil
|
||||||
|
default:
|
||||||
|
return "", fmt.Errorf("invalid format flag: %s", format)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format environment variables as a CSV file
|
||||||
|
func formatAsCSV(envs []models.SingleEnvironmentVariable) string {
|
||||||
|
var csv string
|
||||||
|
csv += "Key,Value\n"
|
||||||
|
for _, env := range envs {
|
||||||
|
csv += fmt.Sprintf("%s,\"%s\"\n", env.Key, env.Value)
|
||||||
|
}
|
||||||
|
return csv
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format environment variables as a dotenv file
|
||||||
|
func formatAsDotEnv(envs []models.SingleEnvironmentVariable) string {
|
||||||
|
var dotenv string
|
||||||
|
for _, env := range envs {
|
||||||
|
dotenv += fmt.Sprintf("%s='%s'\n", env.Key, env.Value)
|
||||||
|
}
|
||||||
|
return dotenv
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format environment variables as a JSON file
|
||||||
|
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)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return string(json)
|
||||||
|
}
|
||||||
+5
-40
@@ -47,46 +47,11 @@ var runCmd = &cobra.Command{
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var envsFromApi []models.SingleEnvironmentVariable
|
envsFromApi, err := util.GetAllEnvironmentVariables(projectId, envName)
|
||||||
infisicalToken := os.Getenv(util.INFISICAL_TOKEN_NAME)
|
if err != nil {
|
||||||
if infisicalToken == "" {
|
log.Errorln("Something went wrong when pulling secrets using your Infisical token. Double check the token, project id or environment name (dev, prod, ect.)")
|
||||||
hasUserLoggedInbefore, loggedInUserEmail, err := util.IsUserLoggedIn()
|
log.Debugln(err)
|
||||||
if err != nil {
|
return
|
||||||
log.Info("Unexpected issue occurred while checking login status. To see more details, add flag --debug")
|
|
||||||
log.Debugln(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !hasUserLoggedInbefore {
|
|
||||||
log.Infoln("No logged in user. To login, please run command [infisical login]")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
userCreds, err := util.GetUserCredsFromKeyRing(loggedInUserEmail)
|
|
||||||
if err != nil {
|
|
||||||
log.Infoln("Unable to get user creds from key ring")
|
|
||||||
log.Debug(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !util.WorkspaceConfigFileExists() {
|
|
||||||
log.Infoln("Your project is not connected to a project yet. Run command [infisical init]")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
envsFromApi, err = util.GetSecretsFromAPIUsingCurrentLoggedInUser(envName, userCreds)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorln("Something went wrong when pulling secrets using your logged in credentials. If the issue persists, double check your project id/try logging in again.")
|
|
||||||
log.Debugln(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
envsFromApi, err = util.GetSecretsFromAPIUsingInfisicalToken(infisicalToken, envName, projectId)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorln("Something went wrong when pulling secrets using your Infisical token. Double check the token, project id or environment name (dev, prod, ect.)")
|
|
||||||
log.Debugln(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if shouldExpandSecrets {
|
if shouldExpandSecrets {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -184,6 +185,52 @@ func GetSecretsFromAPIUsingInfisicalToken(infisicalToken string, envName string,
|
|||||||
return listOfEnv, nil
|
return listOfEnv, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetAllEnvironmentVariables(projectId string, envName string) ([]models.SingleEnvironmentVariable, error) {
|
||||||
|
var envsFromApi []models.SingleEnvironmentVariable
|
||||||
|
infisicalToken := os.Getenv(INFISICAL_TOKEN_NAME)
|
||||||
|
if infisicalToken == "" {
|
||||||
|
hasUserLoggedInbefore, loggedInUserEmail, err := IsUserLoggedIn()
|
||||||
|
if err != nil {
|
||||||
|
log.Info("Unexpected issue occurred while checking login status. To see more details, add flag --debug")
|
||||||
|
log.Debugln(err)
|
||||||
|
return envsFromApi, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasUserLoggedInbefore {
|
||||||
|
log.Infoln("No logged in user. To login, please run command [infisical login]")
|
||||||
|
return envsFromApi, fmt.Errorf("user not logged in")
|
||||||
|
}
|
||||||
|
|
||||||
|
userCreds, err := GetUserCredsFromKeyRing(loggedInUserEmail)
|
||||||
|
if err != nil {
|
||||||
|
log.Infoln("Unable to get user creds from key ring")
|
||||||
|
log.Debug(err)
|
||||||
|
return envsFromApi, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !WorkspaceConfigFileExists() {
|
||||||
|
log.Infoln("Your project is not connected to a project yet. Run command [infisical init]")
|
||||||
|
return envsFromApi, fmt.Errorf("project not initialized")
|
||||||
|
}
|
||||||
|
|
||||||
|
envsFromApi, err = GetSecretsFromAPIUsingCurrentLoggedInUser(envName, userCreds)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln("Something went wrong when pulling secrets using your logged in credentials. If the issue persists, double check your project id/try logging in again.")
|
||||||
|
log.Debugln(err)
|
||||||
|
return envsFromApi, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
envsFromApi, err := GetSecretsFromAPIUsingInfisicalToken(infisicalToken, envName, projectId)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorln("Something went wrong when pulling secrets using your Infisical token. Double check the token, project id or environment name (dev, prod, ect.)")
|
||||||
|
log.Debugln(err)
|
||||||
|
return envsFromApi, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return envsFromApi, nil
|
||||||
|
}
|
||||||
|
|
||||||
func GetWorkSpacesFromAPI(userCreds models.UserCredentials) (workspaces []models.Workspace, err error) {
|
func GetWorkSpacesFromAPI(userCreds models.UserCredentials) (workspaces []models.Workspace, err error) {
|
||||||
// create http client
|
// create http client
|
||||||
httpClient := resty.New().
|
httpClient := resty.New().
|
||||||
|
|||||||
@@ -0,0 +1,33 @@
|
|||||||
|
---
|
||||||
|
title: "infisical export"
|
||||||
|
---
|
||||||
|
|
||||||
|
```bash
|
||||||
|
infisical export [options]
|
||||||
|
```
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
Export environment variables from the platform into a file format.
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
| Option | Description | Default value |
|
||||||
|
| ------------- | ----------------------------------------------------------------------------------------------------------- | ------------- |
|
||||||
|
| `--env` | Used to set the environment that secrets are pulled from. Accepted values: `dev`, `staging`, `test`, `prod` | `dev` |
|
||||||
|
| `--projectId` | Used to link a local project to the platform (required only if injecting via the service token method) | `None` |
|
||||||
|
| `--expand` | Parse shell parameter expansions in your secrets (e.g., `${DOMAIN}`) | `true` |
|
||||||
|
| `--format` | Format of the output file. Accepted values: `dotenv`, `csv` and `json` | `dotenv` |
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Export variables to a .env file
|
||||||
|
infisical export > .env
|
||||||
|
|
||||||
|
# Export variables to a CSV file
|
||||||
|
infisical export --format=csv > secrets.csv
|
||||||
|
|
||||||
|
# Export variables to a JSON file
|
||||||
|
infisical export --format=json > secrets.json
|
||||||
|
```
|
||||||
Reference in New Issue
Block a user