mirror of
https://github.com/Infisical/infisical.git
synced 2025-03-25 14:05:03 +00:00
Merge pull request #90 from edgarrmondragon/feat/export-cmd
Add an `export` command
This commit is contained in:
140
cli/packages/cmd/export.go
Normal file
140
cli/packages/cmd/export.go
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
Copyright © 2022 NAME HERE <EMAIL ADDRESS>
|
||||
*/
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"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 > secrets.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(substitutions, format)
|
||||
if err != nil {
|
||||
log.Errorln(err)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
output, err = formatEnvs(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(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 {
|
||||
csvString := &strings.Builder{}
|
||||
writer := csv.NewWriter(csvString)
|
||||
writer.Write([]string{"Key", "Value"})
|
||||
for _, env := range envs {
|
||||
writer.Write([]string{env.Key, env.Value})
|
||||
}
|
||||
writer.Flush()
|
||||
return csvString.String()
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
@ -47,46 +47,11 @@ var runCmd = &cobra.Command{
|
||||
return
|
||||
}
|
||||
|
||||
var envsFromApi []models.SingleEnvironmentVariable
|
||||
infisicalToken := os.Getenv(util.INFISICAL_TOKEN_NAME)
|
||||
if infisicalToken == "" {
|
||||
hasUserLoggedInbefore, loggedInUserEmail, err := util.IsUserLoggedIn()
|
||||
if err != nil {
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
if shouldExpandSecrets {
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
@ -184,6 +185,52 @@ func GetSecretsFromAPIUsingInfisicalToken(infisicalToken string, envName string,
|
||||
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) {
|
||||
// create http client
|
||||
httpClient := resty.New().
|
||||
|
33
docs/cli/export.mdx
Normal file
33
docs/cli/export.mdx
Normal file
@ -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 determine from which infisical project your secrets will be exported from (only required 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