Compare commits

..

4 Commits

Author SHA1 Message Date
Daniel Hougaard
df3c58bc2a docs(sdks): Updated Go SDK docs 2024-06-16 08:48:26 +02:00
Vlad Matsiiako
db726128f1 Merge pull request #1980 from Infisical/daniel/ansible-docs
Docs: Ansible documentation
2024-06-15 08:59:44 -07:00
Maidul Islam
ae177343d5 patch date filter 2024-06-14 20:57:10 -04:00
Daniel Hougaard
0342ba0890 Update ansible.mdx 2024-06-15 02:45:11 +02:00
14 changed files with 466 additions and 586 deletions

View File

@@ -143,7 +143,8 @@ export const registerProjectRouter = async (server: FastifyZodProvider) => {
actorAuthMethod: req.permission.authMethod,
projectId: req.params.workspaceId,
...req.query,
startDate: req.query.endDate || getLastMidnightDateISO(),
endDate: req.query.endDate,
startDate: req.query.startDate || getLastMidnightDateISO(),
auditLogActor: req.query.actor,
actor: req.permission.type
});

View File

@@ -391,7 +391,6 @@ func CallCreateSecretsV3(httpClient *resty.Client, request CreateSecretV3Request
}
func CallDeleteSecretsV3(httpClient *resty.Client, request DeleteSecretV3Request) error {
var secretsResponse GetEncryptedSecretsV3Response
response, err := httpClient.
R().
@@ -567,39 +566,3 @@ func CallCreateDynamicSecretLeaseV1(httpClient *resty.Client, request CreateDyna
return createDynamicSecretLeaseResponse, nil
}
func CallCreateRawSecretsV3(httpClient *resty.Client, request CreateRawSecretV3Request) error {
response, err := httpClient.
R().
SetHeader("User-Agent", USER_AGENT).
SetBody(request).
Post(fmt.Sprintf("%v/v3/secrets/raw/%s", config.INFISICAL_URL, request.SecretName))
if err != nil {
return fmt.Errorf("CallCreateRawSecretsV3: Unable to complete api request [err=%w]", err)
}
if response.IsError() {
return fmt.Errorf("CallCreateRawSecretsV3: Unsuccessful response [%v %v] [status-code=%v] [response=%v]", response.Request.Method, response.Request.URL, response.StatusCode(), response.String())
}
return nil
}
func CallUpdateRawSecretsV3(httpClient *resty.Client, request UpdateRawSecretByNameV3Request) error {
response, err := httpClient.
R().
SetHeader("User-Agent", USER_AGENT).
SetBody(request).
Patch(fmt.Sprintf("%v/v3/secrets/raw/%s", config.INFISICAL_URL, request.SecretName))
if err != nil {
return fmt.Errorf("CallUpdateRawSecretsV3: Unable to complete api request [err=%w]", err)
}
if response.IsError() {
return fmt.Errorf("CallUpdateRawSecretsV3: Unsuccessful response [%v %v] [status-code=%v] [response=%v]", response.Request.Method, response.Request.URL, response.StatusCode(), response.String())
}
return nil
}

View File

@@ -161,14 +161,6 @@ type Secret struct {
PlainTextKey string `json:"plainTextKey"`
}
type RawSecret struct {
SecretKey string `json:"secretKey,omitempty"`
SecretValue string `json:"secretValue,omitempty"`
Type string `json:"type,omitempty"`
SecretComment string `json:"secretComment,omitempty"`
ID string `json:"id,omitempty"`
}
type GetEncryptedWorkspaceKeyRequest struct {
WorkspaceId string `json:"workspaceId"`
}
@@ -417,23 +409,12 @@ type CreateSecretV3Request struct {
SecretPath string `json:"secretPath"`
}
type CreateRawSecretV3Request struct {
SecretName string `json:"-"`
WorkspaceID string `json:"workspaceId"`
Type string `json:"type,omitempty"`
Environment string `json:"environment"`
SecretPath string `json:"secretPath,omitempty"`
SecretValue string `json:"secretValue"`
SecretComment string `json:"secretComment,omitempty"`
SkipMultilineEncoding bool `json:"skipMultilineEncoding,omitempty"`
}
type DeleteSecretV3Request struct {
SecretName string `json:"secretName"`
WorkspaceId string `json:"workspaceId"`
Environment string `json:"environment"`
Type string `json:"type,omitempty"`
SecretPath string `json:"secretPath,omitempty"`
Type string `json:"type"`
SecretPath string `json:"secretPath"`
}
type UpdateSecretByNameV3Request struct {
@@ -446,15 +427,6 @@ type UpdateSecretByNameV3Request struct {
SecretValueTag string `json:"secretValueTag"`
}
type UpdateRawSecretByNameV3Request struct {
SecretName string `json:"-"`
WorkspaceID string `json:"workspaceId"`
Environment string `json:"environment"`
SecretPath string `json:"secretPath,omitempty"`
SecretValue string `json:"secretValue"`
Type string `json:"type,omitempty"`
}
type GetSingleSecretByNameV3Request struct {
SecretName string `json:"secretName"`
WorkspaceId string `json:"workspaceId"`

View File

@@ -55,11 +55,6 @@ var exportCmd = &cobra.Command{
util.HandleError(err)
}
token, err := util.GetInfisicalToken(cmd)
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
format, err := cmd.Flags().GetString("format")
if err != nil {
util.HandleError(err)
@@ -75,6 +70,11 @@ var exportCmd = &cobra.Command{
util.HandleError(err, "Unable to parse flag")
}
token, err := util.GetInfisicalToken(cmd)
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
tagSlugs, err := cmd.Flags().GetString("tags")
if err != nil {
util.HandleError(err, "Unable to parse flag")
@@ -169,9 +169,9 @@ func init() {
exportCmd.Flags().StringP("format", "f", "dotenv", "Set the format of the output file (dotenv, json, csv)")
exportCmd.Flags().Bool("secret-overriding", true, "Prioritizes personal secrets, if any, with the same name over shared secrets")
exportCmd.Flags().Bool("include-imports", true, "Imported linked secrets")
exportCmd.Flags().String("token", "", "Fetch secrets using service token or machine identity access token")
exportCmd.Flags().String("token", "", "Fetch secrets using the Infisical Token")
exportCmd.Flags().StringP("tags", "t", "", "filter secrets by tag slugs")
exportCmd.Flags().String("projectId", "", "manually set the projectId to export secrets from")
exportCmd.Flags().String("projectId", "", "manually set the projectId to fetch secrets from")
exportCmd.Flags().String("path", "/", "get secrets within a folder path")
exportCmd.Flags().String("template", "", "The path to the template file used to render secrets")
}

View File

@@ -1,7 +1,6 @@
package cmd
import (
"errors"
"fmt"
"github.com/Infisical/infisical-merge/packages/models"
@@ -72,6 +71,10 @@ var getCmd = &cobra.Command{
var createCmd = &cobra.Command{
Use: "create",
Short: "Create a folder",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
util.RequireLogin()
util.RequireLocalWorkspaceFile()
},
Run: func(cmd *cobra.Command, args []string) {
environmentName, _ := cmd.Flags().GetString("env")
if !cmd.Flags().Changed("env") {
@@ -81,16 +84,6 @@ var createCmd = &cobra.Command{
}
}
token, err := util.GetInfisicalToken(cmd)
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
projectId, err := cmd.Flags().GetString("projectId")
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
folderPath, err := cmd.Flags().GetString("path")
if err != nil {
util.HandleError(err, "Unable to parse flag")
@@ -102,31 +95,19 @@ var createCmd = &cobra.Command{
}
if folderName == "" {
util.HandleError(errors.New("invalid folder name, folder name cannot be empty"))
util.HandleError(fmt.Errorf("Invalid folder name"), "Folder name cannot be empty")
}
workspaceFile, err := util.GetWorkSpaceFromFile()
if err != nil {
util.HandleError(err, "Unable to get workspace file")
}
if projectId == "" {
workspaceFile, err := util.GetWorkSpaceFromFile()
if err != nil {
util.HandleError(err, "Unable to get workspace file")
}
projectId = workspaceFile.WorkspaceId
}
params := models.CreateFolderParameters{
FolderName: folderName,
WorkspaceId: workspaceFile.WorkspaceId,
Environment: environmentName,
FolderPath: folderPath,
WorkspaceId: projectId,
}
if token != nil && (token.Type == util.SERVICE_TOKEN_IDENTIFIER || token.Type == util.UNIVERSAL_AUTH_TOKEN_IDENTIFIER) {
params.InfisicalToken = token.Token
}
_, err = util.CreateFolder(params)
@@ -143,6 +124,10 @@ var createCmd = &cobra.Command{
var deleteCmd = &cobra.Command{
Use: "delete",
Short: "Delete a folder",
PersistentPreRun: func(cmd *cobra.Command, args []string) {
util.RequireLogin()
util.RequireLocalWorkspaceFile()
},
Run: func(cmd *cobra.Command, args []string) {
environmentName, _ := cmd.Flags().GetString("env")
@@ -153,16 +138,6 @@ var deleteCmd = &cobra.Command{
}
}
token, err := util.GetInfisicalToken(cmd)
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
projectId, err := cmd.Flags().GetString("projectId")
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
folderPath, err := cmd.Flags().GetString("path")
if err != nil {
util.HandleError(err, "Unable to parse flag")
@@ -174,29 +149,21 @@ var deleteCmd = &cobra.Command{
}
if folderName == "" {
util.HandleError(errors.New("invalid folder name, folder name cannot be empty"))
util.HandleError(fmt.Errorf("Invalid folder name"), "Folder name cannot be empty")
}
if projectId == "" {
workspaceFile, err := util.GetWorkSpaceFromFile()
if err != nil {
util.HandleError(err, "Unable to get workspace file")
}
projectId = workspaceFile.WorkspaceId
workspaceFile, err := util.GetWorkSpaceFromFile()
if err != nil {
util.HandleError(err, "Unable to get workspace file")
}
params := models.DeleteFolderParameters{
FolderName: folderName,
WorkspaceId: projectId,
WorkspaceId: workspaceFile.WorkspaceId,
Environment: environmentName,
FolderPath: folderPath,
}
if token != nil && (token.Type == util.SERVICE_TOKEN_IDENTIFIER || token.Type == util.UNIVERSAL_AUTH_TOKEN_IDENTIFIER) {
params.InfisicalToken = token.Token
}
_, err = util.DeleteFolder(params)
if err != nil {
util.HandleError(err, "Unable to delete folder")

View File

@@ -237,8 +237,8 @@ func filterReservedEnvVars(env map[string]models.SingleEnvironmentVariable) {
func init() {
rootCmd.AddCommand(runCmd)
runCmd.Flags().String("token", "", "Fetch secrets using service token or machine identity access token")
runCmd.Flags().String("projectId", "", "manually set the project ID to fetch secrets from when using machine identity based auth")
runCmd.Flags().String("token", "", "Fetch secrets using the Infisical Token")
runCmd.Flags().String("projectId", "", "manually set the projectId to fetch folders from for machine identity")
runCmd.Flags().StringP("env", "e", "dev", "Set the environment (dev, prod, etc.) from which your secrets should be pulled from")
runCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets")
runCmd.Flags().Bool("include-imports", true, "Import linked secrets ")

View File

@@ -4,17 +4,23 @@ Copyright (c) 2023 Infisical Inc.
package cmd
import (
"crypto/sha256"
"encoding/base64"
"fmt"
"os"
"regexp"
"sort"
"strings"
"unicode"
"github.com/Infisical/infisical-merge/packages/api"
"github.com/Infisical/infisical-merge/packages/crypto"
"github.com/Infisical/infisical-merge/packages/models"
"github.com/Infisical/infisical-merge/packages/util"
"github.com/Infisical/infisical-merge/packages/visualize"
"github.com/go-resty/resty/v2"
"github.com/posthog/posthog-go"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
)
@@ -154,38 +160,211 @@ var secretsSetCmd = &cobra.Command{
}
}
token, err := util.GetInfisicalToken(cmd)
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
projectId, err := cmd.Flags().GetString("projectId")
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
secretsPath, err := cmd.Flags().GetString("path")
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
workspaceFile, err := util.GetWorkSpaceFromFile()
if err != nil {
util.HandleError(err, "Unable to get your local config details")
}
secretType, err := cmd.Flags().GetString("type")
if err != nil || (secretType != util.SECRET_TYPE_SHARED && secretType != util.SECRET_TYPE_PERSONAL) {
util.HandleError(err, "Unable to parse secret type")
}
var secretOperations []models.SecretSetOperation
if token != nil && (token.Type == util.SERVICE_TOKEN_IDENTIFIER || token.Type == util.UNIVERSAL_AUTH_TOKEN_IDENTIFIER) {
secretOperations, err = util.SetRawSecrets(args, secretType, environmentName, secretsPath, projectId, token)
} else {
util.RequireLogin()
util.RequireLocalWorkspaceFile()
secretOperations, err = util.SetEncryptedSecrets(args, secretType, environmentName, secretsPath)
loggedInUserDetails, err := util.GetCurrentLoggedInUserDetails()
if err != nil {
util.HandleError(err, "Unable to authenticate")
}
if loggedInUserDetails.LoginExpired {
util.PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again")
}
httpClient := resty.New().
SetAuthToken(loggedInUserDetails.UserCredentials.JTWToken).
SetHeader("Accept", "application/json")
request := api.GetEncryptedWorkspaceKeyRequest{
WorkspaceId: workspaceFile.WorkspaceId,
}
workspaceKeyResponse, err := api.CallGetEncryptedWorkspaceKey(httpClient, request)
if err != nil {
util.HandleError(err, "Unable to set secrets")
util.HandleError(err, "unable to get your encrypted workspace key")
}
encryptedWorkspaceKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.EncryptedKey)
encryptedWorkspaceKeySenderPublicKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.Sender.PublicKey)
encryptedWorkspaceKeyNonce, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.Nonce)
currentUsersPrivateKey, _ := base64.StdEncoding.DecodeString(loggedInUserDetails.UserCredentials.PrivateKey)
if len(currentUsersPrivateKey) == 0 || len(encryptedWorkspaceKeySenderPublicKey) == 0 {
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")
}
// decrypt workspace key
plainTextEncryptionKey := crypto.DecryptAsymmetric(encryptedWorkspaceKey, encryptedWorkspaceKeyNonce, encryptedWorkspaceKeySenderPublicKey, currentUsersPrivateKey)
infisicalTokenEnv := os.Getenv(util.INFISICAL_TOKEN_NAME)
// pull current secrets
secrets, err := util.GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName, SecretsPath: secretsPath, InfisicalToken: infisicalTokenEnv}, "")
if err != nil {
util.HandleError(err, "unable to retrieve secrets")
}
type SecretSetOperation struct {
SecretKey string
SecretValue string
SecretOperation string
}
secretsToCreate := []api.Secret{}
secretsToModify := []api.Secret{}
secretOperations := []SecretSetOperation{}
sharedSecretMapByName := make(map[string]models.SingleEnvironmentVariable, len(secrets))
personalSecretMapByName := make(map[string]models.SingleEnvironmentVariable, len(secrets))
for _, secret := range secrets {
if secret.Type == util.SECRET_TYPE_PERSONAL {
personalSecretMapByName[secret.Key] = secret
} else {
sharedSecretMapByName[secret.Key] = secret
}
}
for _, arg := range args {
splitKeyValueFromArg := strings.SplitN(arg, "=", 2)
if splitKeyValueFromArg[0] == "" || splitKeyValueFromArg[1] == "" {
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.PrintErrorMessageAndExit("keys of secrets cannot start with a number. Modify the key name(s) and try again")
}
// Key and value from argument
key := splitKeyValueFromArg[0]
value := splitKeyValueFromArg[1]
hashedKey := fmt.Sprintf("%x", sha256.Sum256([]byte(key)))
encryptedKey, err := crypto.EncryptSymmetric([]byte(key), []byte(plainTextEncryptionKey))
if err != nil {
util.HandleError(err, "unable to encrypt your secrets")
}
hashedValue := fmt.Sprintf("%x", sha256.Sum256([]byte(value)))
encryptedValue, err := crypto.EncryptSymmetric([]byte(value), []byte(plainTextEncryptionKey))
if err != nil {
util.HandleError(err, "unable to encrypt your secrets")
}
var existingSecret models.SingleEnvironmentVariable
var doesSecretExist bool
if secretType == util.SECRET_TYPE_SHARED {
existingSecret, doesSecretExist = sharedSecretMapByName[key]
} else {
existingSecret, doesSecretExist = personalSecretMapByName[key]
}
if doesSecretExist {
// case: secret exists in project so it needs to be modified
encryptedSecretDetails := api.Secret{
ID: existingSecret.ID,
SecretValueCiphertext: base64.StdEncoding.EncodeToString(encryptedValue.CipherText),
SecretValueIV: base64.StdEncoding.EncodeToString(encryptedValue.Nonce),
SecretValueTag: base64.StdEncoding.EncodeToString(encryptedValue.AuthTag),
SecretValueHash: hashedValue,
PlainTextKey: key,
Type: existingSecret.Type,
}
// Only add to modifications if the value is different
if existingSecret.Value != value {
secretsToModify = append(secretsToModify, encryptedSecretDetails)
secretOperations = append(secretOperations, SecretSetOperation{
SecretKey: key,
SecretValue: value,
SecretOperation: "SECRET VALUE MODIFIED",
})
} else {
// Current value is same as exisitng so no change
secretOperations = append(secretOperations, SecretSetOperation{
SecretKey: key,
SecretValue: value,
SecretOperation: "SECRET VALUE UNCHANGED",
})
}
} else {
// case: secret doesn't exist in project so it needs to be created
encryptedSecretDetails := api.Secret{
SecretKeyCiphertext: base64.StdEncoding.EncodeToString(encryptedKey.CipherText),
SecretKeyIV: base64.StdEncoding.EncodeToString(encryptedKey.Nonce),
SecretKeyTag: base64.StdEncoding.EncodeToString(encryptedKey.AuthTag),
SecretKeyHash: hashedKey,
SecretValueCiphertext: base64.StdEncoding.EncodeToString(encryptedValue.CipherText),
SecretValueIV: base64.StdEncoding.EncodeToString(encryptedValue.Nonce),
SecretValueTag: base64.StdEncoding.EncodeToString(encryptedValue.AuthTag),
SecretValueHash: hashedValue,
Type: secretType,
PlainTextKey: key,
}
secretsToCreate = append(secretsToCreate, encryptedSecretDetails)
secretOperations = append(secretOperations, SecretSetOperation{
SecretKey: key,
SecretValue: value,
SecretOperation: "SECRET CREATED",
})
}
}
for _, secret := range secretsToCreate {
createSecretRequest := api.CreateSecretV3Request{
WorkspaceID: workspaceFile.WorkspaceId,
Environment: environmentName,
SecretName: secret.PlainTextKey,
SecretKeyCiphertext: secret.SecretKeyCiphertext,
SecretKeyIV: secret.SecretKeyIV,
SecretKeyTag: secret.SecretKeyTag,
SecretValueCiphertext: secret.SecretValueCiphertext,
SecretValueIV: secret.SecretValueIV,
SecretValueTag: secret.SecretValueTag,
Type: secret.Type,
SecretPath: secretsPath,
}
err = api.CallCreateSecretsV3(httpClient, createSecretRequest)
if err != nil {
util.HandleError(err, "Unable to process new secret creations")
return
}
}
for _, secret := range secretsToModify {
updateSecretRequest := api.UpdateSecretByNameV3Request{
WorkspaceID: workspaceFile.WorkspaceId,
Environment: environmentName,
SecretValueCiphertext: secret.SecretValueCiphertext,
SecretValueIV: secret.SecretValueIV,
SecretValueTag: secret.SecretValueTag,
Type: secret.Type,
SecretPath: secretsPath,
}
err = api.CallUpdateSecretsV3(httpClient, updateSecretRequest, secret.PlainTextKey)
if err != nil {
util.HandleError(err, "Unable to process secret update request")
return
}
}
// Print secret operations
@@ -216,16 +395,6 @@ var secretsDeleteCmd = &cobra.Command{
}
}
token, err := util.GetInfisicalToken(cmd)
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
projectId, err := cmd.Flags().GetString("projectId")
if err != nil {
util.HandleError(err, "Unable to parse flag")
}
secretsPath, err := cmd.Flags().GetString("path")
if err != nil {
util.HandleError(err, "Unable to parse flag")
@@ -236,44 +405,33 @@ var secretsDeleteCmd = &cobra.Command{
util.HandleError(err, "Unable to parse flag")
}
httpClient := resty.New().
SetHeader("Accept", "application/json")
if projectId == "" {
workspaceFile, err := util.GetWorkSpaceFromFile()
if err != nil {
util.HandleError(err, "Unable to get local project details")
}
projectId = workspaceFile.WorkspaceId
loggedInUserDetails, err := util.GetCurrentLoggedInUserDetails()
if err != nil {
util.HandleError(err, "Unable to authenticate")
}
if token != nil && (token.Type == util.SERVICE_TOKEN_IDENTIFIER || token.Type == util.UNIVERSAL_AUTH_TOKEN_IDENTIFIER) {
httpClient.SetAuthToken(token.Token)
} else {
util.RequireLogin()
util.RequireLocalWorkspaceFile()
if loggedInUserDetails.LoginExpired {
util.PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again")
}
loggedInUserDetails, err := util.GetCurrentLoggedInUserDetails()
if err != nil {
util.HandleError(err, "Unable to authenticate")
}
if loggedInUserDetails.LoginExpired {
util.PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again")
}
httpClient.SetAuthToken(loggedInUserDetails.UserCredentials.JTWToken)
workspaceFile, err := util.GetWorkSpaceFromFile()
if err != nil {
util.HandleError(err, "Unable to get local project details")
}
for _, secretName := range args {
request := api.DeleteSecretV3Request{
WorkspaceId: projectId,
WorkspaceId: workspaceFile.WorkspaceId,
Environment: environmentName,
SecretName: secretName,
Type: secretType,
SecretPath: secretsPath,
}
httpClient := resty.New().
SetAuthToken(loggedInUserDetails.UserCredentials.JTWToken).
SetHeader("Accept", "application/json")
err = api.CallDeleteSecretsV3(httpClient, request)
if err != nil {
util.HandleError(err, "Unable to complete your delete request")
@@ -631,13 +789,13 @@ func getSecretsByKeys(secrets []models.SingleEnvironmentVariable) map[string]mod
}
func init() {
secretsGenerateExampleEnvCmd.Flags().String("token", "", "Fetch secrets using service token or machine identity access token")
secretsGenerateExampleEnvCmd.Flags().String("projectId", "", "manually set the projectId when using machine identity based auth")
secretsGenerateExampleEnvCmd.Flags().String("token", "", "Fetch secrets using the Infisical Token")
secretsGenerateExampleEnvCmd.Flags().String("projectId", "", "manually set the projectId to fetch folders from for machine identity")
secretsGenerateExampleEnvCmd.Flags().String("path", "/", "Fetch secrets from within a folder path")
secretsCmd.AddCommand(secretsGenerateExampleEnvCmd)
secretsGetCmd.Flags().String("token", "", "Fetch secrets using service token or machine identity access token")
secretsGetCmd.Flags().String("projectId", "", "manually set the project ID to fetch secrets from when using machine identity based auth")
secretsGetCmd.Flags().String("token", "", "Fetch secrets using the Infisical Token")
secretsGetCmd.Flags().String("projectId", "", "manually set the projectId to fetch folders from for machine identity")
secretsGetCmd.Flags().String("path", "/", "get secrets within a folder path")
secretsGetCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets")
secretsGetCmd.Flags().Bool("raw-value", false, "Returns only the value of secret, only works with one secret")
@@ -646,37 +804,41 @@ func init() {
secretsCmd.Flags().Bool("secret-overriding", true, "Prioritizes personal secrets, if any, with the same name over shared secrets")
secretsCmd.AddCommand(secretsSetCmd)
secretsSetCmd.Flags().String("token", "", "Fetch secrets using service token or machine identity access token")
secretsSetCmd.Flags().String("projectId", "", "manually set the project ID to for setting secrets when using machine identity based auth")
secretsSetCmd.Flags().String("path", "/", "set secrets within a folder path")
secretsSetCmd.Flags().String("type", util.SECRET_TYPE_SHARED, "the type of secret to create: personal or shared")
// Only supports logged in users (JWT auth)
secretsSetCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) {
util.RequireLogin()
util.RequireLocalWorkspaceFile()
}
secretsDeleteCmd.Flags().String("type", "personal", "the type of secret to delete: personal or shared (default: personal)")
secretsDeleteCmd.Flags().String("token", "", "Fetch secrets using service token or machine identity access token")
secretsDeleteCmd.Flags().String("projectId", "", "manually set the projectId to delete secrets from when using machine identity based auth")
secretsDeleteCmd.Flags().String("path", "/", "get secrets within a folder path")
secretsCmd.AddCommand(secretsDeleteCmd)
// Only supports logged in users (JWT auth)
secretsDeleteCmd.PersistentPreRun = func(cmd *cobra.Command, args []string) {
util.RequireLogin()
util.RequireLocalWorkspaceFile()
}
// *** Folders sub command ***
folderCmd.PersistentFlags().String("env", "dev", "Used to select the environment name on which actions should be taken on")
// Add getCmd, createCmd and deleteCmd flags here
getCmd.Flags().StringP("path", "p", "/", "The path from where folders should be fetched from")
getCmd.Flags().String("token", "", "Fetch secrets using service token or machine identity access token")
getCmd.Flags().String("projectId", "", "manually set the projectId to fetch folders from when using machine identity based auth")
getCmd.Flags().String("token", "", "Fetch folders using the infisical token")
getCmd.Flags().String("projectId", "", "manually set the projectId to fetch folders from for machine identity")
folderCmd.AddCommand(getCmd)
// Add createCmd flags here
createCmd.Flags().StringP("path", "p", "/", "Path to where the folder should be created")
createCmd.Flags().StringP("name", "n", "", "Name of the folder to be created in selected `--path`")
createCmd.Flags().String("token", "", "Fetch secrets using service token or machine identity access token")
createCmd.Flags().String("projectId", "", "manually set the project ID for creating folders in when using machine identity based auth")
folderCmd.AddCommand(createCmd)
// Add deleteCmd flags here
deleteCmd.Flags().StringP("path", "p", "/", "Path to the folder to be deleted")
deleteCmd.Flags().String("token", "", "Fetch secrets using service token or machine identity access token")
deleteCmd.Flags().String("projectId", "", "manually set the projectId to delete folders when using machine identity based auth")
deleteCmd.Flags().StringP("name", "n", "", "Name of the folder to be deleted within selected `--path`")
folderCmd.AddCommand(deleteCmd)
@@ -684,8 +846,8 @@ func init() {
// ** End of folders sub command
secretsCmd.Flags().String("token", "", "Fetch secrets using service token or machine identity access token")
secretsCmd.Flags().String("projectId", "", "manually set the projectId to fetch secrets when using machine identity based auth")
secretsCmd.Flags().String("token", "", "Fetch secrets using the Infisical Token")
secretsCmd.Flags().String("projectId", "", "manually set the projectId to fetch folders from for machine identity")
secretsCmd.PersistentFlags().String("env", "dev", "Used to select the environment name on which actions should be taken on")
secretsCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets")
secretsCmd.Flags().Bool("include-imports", true, "Imported linked secrets ")

View File

@@ -134,9 +134,3 @@ type MachineIdentityCredentials struct {
ClientId string
ClientSecret string
}
type SecretSetOperation struct {
SecretKey string
SecretValue string
SecretOperation string
}

View File

@@ -172,28 +172,19 @@ func GetFoldersViaMachineIdentity(accessToken string, workspaceId string, envSlu
// CreateFolder creates a folder in Infisical
func CreateFolder(params models.CreateFolderParameters) (models.SingleFolder, error) {
loggedInUserDetails, err := GetCurrentLoggedInUserDetails()
if err != nil {
return models.SingleFolder{}, err
}
// If no token is provided, we will try to get the token from the current logged in user
if params.InfisicalToken == "" {
RequireLogin()
RequireLocalWorkspaceFile()
loggedInUserDetails, err := GetCurrentLoggedInUserDetails()
if err != nil {
return models.SingleFolder{}, err
}
if loggedInUserDetails.LoginExpired {
PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again")
}
params.InfisicalToken = loggedInUserDetails.UserCredentials.JTWToken
if loggedInUserDetails.LoginExpired {
PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again")
}
// set up resty client
httpClient := resty.New()
httpClient.
SetAuthToken(params.InfisicalToken).
SetAuthToken(loggedInUserDetails.UserCredentials.JTWToken).
SetHeader("Accept", "application/json").
SetHeader("Content-Type", "application/json")
@@ -218,29 +209,19 @@ func CreateFolder(params models.CreateFolderParameters) (models.SingleFolder, er
}
func DeleteFolder(params models.DeleteFolderParameters) ([]models.SingleFolder, error) {
loggedInUserDetails, err := GetCurrentLoggedInUserDetails()
if err != nil {
return nil, err
}
// If no token is provided, we will try to get the token from the current logged in user
if params.InfisicalToken == "" {
RequireLogin()
RequireLocalWorkspaceFile()
loggedInUserDetails, err := GetCurrentLoggedInUserDetails()
if err != nil {
return nil, err
}
if loggedInUserDetails.LoginExpired {
PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again")
}
params.InfisicalToken = loggedInUserDetails.UserCredentials.JTWToken
if loggedInUserDetails.LoginExpired {
PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again")
}
// set up resty client
httpClient := resty.New()
httpClient.
SetAuthToken(params.InfisicalToken).
SetAuthToken(loggedInUserDetails.UserCredentials.JTWToken).
SetHeader("Accept", "application/json").
SetHeader("Content-Type", "application/json")

View File

@@ -1,7 +1,6 @@
package util
import (
"crypto/sha256"
"encoding/base64"
"encoding/json"
"errors"
@@ -10,7 +9,6 @@ import (
"path"
"regexp"
"strings"
"unicode"
"github.com/Infisical/infisical-merge/packages/api"
"github.com/Infisical/infisical-merge/packages/crypto"
@@ -808,336 +806,3 @@ func GetPlainTextWorkspaceKey(authenticationToken string, receiverPrivateKey str
return crypto.DecryptAsymmetric(encryptedWorkspaceKey, encryptedWorkspaceKeyNonce, encryptedWorkspaceKeySenderPublicKey, currentUsersPrivateKey), nil
}
func SetEncryptedSecrets(secretArgs []string, secretType string, environmentName string, secretsPath string) ([]models.SecretSetOperation, error) {
workspaceFile, err := GetWorkSpaceFromFile()
if err != nil {
return nil, fmt.Errorf("unable to get your local config details [err=%v]", err)
}
loggedInUserDetails, err := GetCurrentLoggedInUserDetails()
if err != nil {
return nil, fmt.Errorf("unable to authenticate [err=%v]", err)
}
if loggedInUserDetails.LoginExpired {
PrintErrorMessageAndExit("Your login session has expired, please run [infisical login] and try again")
}
httpClient := resty.New().
SetAuthToken(loggedInUserDetails.UserCredentials.JTWToken).
SetHeader("Accept", "application/json")
request := api.GetEncryptedWorkspaceKeyRequest{
WorkspaceId: workspaceFile.WorkspaceId,
}
workspaceKeyResponse, err := api.CallGetEncryptedWorkspaceKey(httpClient, request)
if err != nil {
return nil, fmt.Errorf("unable to get your encrypted workspace key [err=%v]", err)
}
encryptedWorkspaceKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.EncryptedKey)
encryptedWorkspaceKeySenderPublicKey, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.Sender.PublicKey)
encryptedWorkspaceKeyNonce, _ := base64.StdEncoding.DecodeString(workspaceKeyResponse.Nonce)
currentUsersPrivateKey, _ := base64.StdEncoding.DecodeString(loggedInUserDetails.UserCredentials.PrivateKey)
if len(currentUsersPrivateKey) == 0 || len(encryptedWorkspaceKeySenderPublicKey) == 0 {
log.Debug().Msgf("Missing credentials for generating plainTextEncryptionKey: [currentUsersPrivateKey=%s] [encryptedWorkspaceKeySenderPublicKey=%s]", currentUsersPrivateKey, encryptedWorkspaceKeySenderPublicKey)
PrintErrorMessageAndExit("Some required user credentials are missing to generate your [plainTextEncryptionKey]. Please run [infisical login] then try again")
}
// decrypt workspace key
plainTextEncryptionKey := crypto.DecryptAsymmetric(encryptedWorkspaceKey, encryptedWorkspaceKeyNonce, encryptedWorkspaceKeySenderPublicKey, currentUsersPrivateKey)
infisicalTokenEnv := os.Getenv(INFISICAL_TOKEN_NAME)
// pull current secrets
secrets, err := GetAllEnvironmentVariables(models.GetAllSecretsParameters{Environment: environmentName, SecretsPath: secretsPath, InfisicalToken: infisicalTokenEnv}, "")
if err != nil {
return nil, fmt.Errorf("unable to retrieve secrets [err=%v]", err)
}
secretsToCreate := []api.Secret{}
secretsToModify := []api.Secret{}
secretOperations := []models.SecretSetOperation{}
sharedSecretMapByName := make(map[string]models.SingleEnvironmentVariable, len(secrets))
personalSecretMapByName := make(map[string]models.SingleEnvironmentVariable, len(secrets))
for _, secret := range secrets {
if secret.Type == SECRET_TYPE_PERSONAL {
personalSecretMapByName[secret.Key] = secret
} else {
sharedSecretMapByName[secret.Key] = secret
}
}
for _, arg := range secretArgs {
splitKeyValueFromArg := strings.SplitN(arg, "=", 2)
if splitKeyValueFromArg[0] == "" || splitKeyValueFromArg[1] == "" {
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])) {
PrintErrorMessageAndExit("keys of secrets cannot start with a number. Modify the key name(s) and try again")
}
// Key and value from argument
key := splitKeyValueFromArg[0]
value := splitKeyValueFromArg[1]
hashedKey := fmt.Sprintf("%x", sha256.Sum256([]byte(key)))
encryptedKey, err := crypto.EncryptSymmetric([]byte(key), []byte(plainTextEncryptionKey))
if err != nil {
return nil, fmt.Errorf("unable to encrypt your secrets [err=%v]", err)
}
hashedValue := fmt.Sprintf("%x", sha256.Sum256([]byte(value)))
encryptedValue, err := crypto.EncryptSymmetric([]byte(value), []byte(plainTextEncryptionKey))
if err != nil {
return nil, fmt.Errorf("unable to encrypt your secrets [err=%v]", err)
}
var existingSecret models.SingleEnvironmentVariable
var doesSecretExist bool
if secretType == SECRET_TYPE_SHARED {
existingSecret, doesSecretExist = sharedSecretMapByName[key]
} else {
existingSecret, doesSecretExist = personalSecretMapByName[key]
}
if doesSecretExist {
// case: secret exists in project so it needs to be modified
encryptedSecretDetails := api.Secret{
ID: existingSecret.ID,
SecretValueCiphertext: base64.StdEncoding.EncodeToString(encryptedValue.CipherText),
SecretValueIV: base64.StdEncoding.EncodeToString(encryptedValue.Nonce),
SecretValueTag: base64.StdEncoding.EncodeToString(encryptedValue.AuthTag),
SecretValueHash: hashedValue,
PlainTextKey: key,
Type: existingSecret.Type,
}
// Only add to modifications if the value is different
if existingSecret.Value != value {
secretsToModify = append(secretsToModify, encryptedSecretDetails)
secretOperations = append(secretOperations, models.SecretSetOperation{
SecretKey: key,
SecretValue: value,
SecretOperation: "SECRET VALUE MODIFIED",
})
} else {
// Current value is same as exisitng so no change
secretOperations = append(secretOperations, models.SecretSetOperation{
SecretKey: key,
SecretValue: value,
SecretOperation: "SECRET VALUE UNCHANGED",
})
}
} else {
// case: secret doesn't exist in project so it needs to be created
encryptedSecretDetails := api.Secret{
SecretKeyCiphertext: base64.StdEncoding.EncodeToString(encryptedKey.CipherText),
SecretKeyIV: base64.StdEncoding.EncodeToString(encryptedKey.Nonce),
SecretKeyTag: base64.StdEncoding.EncodeToString(encryptedKey.AuthTag),
SecretKeyHash: hashedKey,
SecretValueCiphertext: base64.StdEncoding.EncodeToString(encryptedValue.CipherText),
SecretValueIV: base64.StdEncoding.EncodeToString(encryptedValue.Nonce),
SecretValueTag: base64.StdEncoding.EncodeToString(encryptedValue.AuthTag),
SecretValueHash: hashedValue,
Type: secretType,
PlainTextKey: key,
}
secretsToCreate = append(secretsToCreate, encryptedSecretDetails)
secretOperations = append(secretOperations, models.SecretSetOperation{
SecretKey: key,
SecretValue: value,
SecretOperation: "SECRET CREATED",
})
}
}
for _, secret := range secretsToCreate {
createSecretRequest := api.CreateSecretV3Request{
WorkspaceID: workspaceFile.WorkspaceId,
Environment: environmentName,
SecretName: secret.PlainTextKey,
SecretKeyCiphertext: secret.SecretKeyCiphertext,
SecretKeyIV: secret.SecretKeyIV,
SecretKeyTag: secret.SecretKeyTag,
SecretValueCiphertext: secret.SecretValueCiphertext,
SecretValueIV: secret.SecretValueIV,
SecretValueTag: secret.SecretValueTag,
Type: secret.Type,
SecretPath: secretsPath,
}
err = api.CallCreateSecretsV3(httpClient, createSecretRequest)
if err != nil {
return nil, fmt.Errorf("unable to process new secret creations [err=%v]", err)
}
}
for _, secret := range secretsToModify {
updateSecretRequest := api.UpdateSecretByNameV3Request{
WorkspaceID: workspaceFile.WorkspaceId,
Environment: environmentName,
SecretValueCiphertext: secret.SecretValueCiphertext,
SecretValueIV: secret.SecretValueIV,
SecretValueTag: secret.SecretValueTag,
Type: secret.Type,
SecretPath: secretsPath,
}
err = api.CallUpdateSecretsV3(httpClient, updateSecretRequest, secret.PlainTextKey)
if err != nil {
return nil, fmt.Errorf("unable to process secret update request [err=%v]", err)
}
}
return secretOperations, nil
}
func SetRawSecrets(secretArgs []string, secretType string, environmentName string, secretsPath string, projectId string, tokenDetails *models.TokenDetails) ([]models.SecretSetOperation, error) {
if tokenDetails == nil {
return nil, fmt.Errorf("unable to process set secret operations, token details are missing")
}
getAllEnvironmentVariablesRequest := models.GetAllSecretsParameters{Environment: environmentName, SecretsPath: secretsPath, WorkspaceId: projectId}
if tokenDetails.Type == UNIVERSAL_AUTH_TOKEN_IDENTIFIER {
getAllEnvironmentVariablesRequest.UniversalAuthAccessToken = tokenDetails.Token
} else {
getAllEnvironmentVariablesRequest.InfisicalToken = tokenDetails.Token
}
httpClient := resty.New().
SetAuthToken(tokenDetails.Token).
SetHeader("Accept", "application/json")
// pull current secrets
secrets, err := GetAllEnvironmentVariables(getAllEnvironmentVariablesRequest, "")
if err != nil {
return nil, fmt.Errorf("unable to retrieve secrets [err=%v]", err)
}
secretsToCreate := []api.RawSecret{}
secretsToModify := []api.RawSecret{}
secretOperations := []models.SecretSetOperation{}
sharedSecretMapByName := make(map[string]models.SingleEnvironmentVariable, len(secrets))
personalSecretMapByName := make(map[string]models.SingleEnvironmentVariable, len(secrets))
for _, secret := range secrets {
if secret.Type == SECRET_TYPE_PERSONAL {
personalSecretMapByName[secret.Key] = secret
} else {
sharedSecretMapByName[secret.Key] = secret
}
}
for _, arg := range secretArgs {
splitKeyValueFromArg := strings.SplitN(arg, "=", 2)
if splitKeyValueFromArg[0] == "" || splitKeyValueFromArg[1] == "" {
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])) {
PrintErrorMessageAndExit("keys of secrets cannot start with a number. Modify the key name(s) and try again")
}
// Key and value from argument
key := splitKeyValueFromArg[0]
value := splitKeyValueFromArg[1]
var existingSecret models.SingleEnvironmentVariable
var doesSecretExist bool
if secretType == SECRET_TYPE_SHARED {
existingSecret, doesSecretExist = sharedSecretMapByName[key]
} else {
existingSecret, doesSecretExist = personalSecretMapByName[key]
}
if doesSecretExist {
// case: secret exists in project so it needs to be modified
encryptedSecretDetails := api.RawSecret{
ID: existingSecret.ID,
SecretValue: value,
SecretKey: key,
Type: existingSecret.Type,
}
// Only add to modifications if the value is different
if existingSecret.Value != value {
secretsToModify = append(secretsToModify, encryptedSecretDetails)
secretOperations = append(secretOperations, models.SecretSetOperation{
SecretKey: key,
SecretValue: value,
SecretOperation: "SECRET VALUE MODIFIED",
})
} else {
// Current value is same as existing so no change
secretOperations = append(secretOperations, models.SecretSetOperation{
SecretKey: key,
SecretValue: value,
SecretOperation: "SECRET VALUE UNCHANGED",
})
}
} else {
// case: secret doesn't exist in project so it needs to be created
encryptedSecretDetails := api.RawSecret{
SecretKey: key,
SecretValue: value,
Type: secretType,
}
secretsToCreate = append(secretsToCreate, encryptedSecretDetails)
secretOperations = append(secretOperations, models.SecretSetOperation{
SecretKey: key,
SecretValue: value,
SecretOperation: "SECRET CREATED",
})
}
}
for _, secret := range secretsToCreate {
createSecretRequest := api.CreateRawSecretV3Request{
SecretName: secret.SecretKey,
SecretValue: secret.SecretValue,
Type: secret.Type,
SecretPath: secretsPath,
WorkspaceID: projectId,
Environment: environmentName,
}
err = api.CallCreateRawSecretsV3(httpClient, createSecretRequest)
if err != nil {
return nil, fmt.Errorf("unable to process new secret creations [err=%v]", err)
}
}
for _, secret := range secretsToModify {
updateSecretRequest := api.UpdateRawSecretByNameV3Request{
SecretName: secret.SecretKey,
SecretValue: secret.SecretValue,
SecretPath: secretsPath,
WorkspaceID: projectId,
Environment: environmentName,
Type: secret.Type,
}
err = api.CallUpdateRawSecretsV3(httpClient, updateSecretRequest)
if err != nil {
return nil, fmt.Errorf("unable to process secret update request [err=%v]", err)
}
}
return secretOperations, nil
}

View File

@@ -3,7 +3,48 @@ title: "Ansible"
description: "Learn how to use Infisical for secret management in Ansible."
---
The documentation for using Infisical to manage secrets in Ansible is currently available [here](https://galaxy.ansible.com/ui/repo/published/infisical/vault/).
You can find the Infisical Ansible collection on [Ansible Galaxy](https://galaxy.ansible.com/ui/repo/published/infisical/vault/).
This Ansible Infisical collection includes a variety of Ansible content to help automate the management of Infisical services. This collection is maintained by the Infisical team.
## Ansible version compatibility
Tested with the Ansible Core >= 2.12.0 versions, and the current development version of Ansible. Ansible Core versions prior to 2.12.0 have not been tested.
## Python version compatibility
This collection depends on the Infisical SDK for Python.
Requires Python 3.7 or greater.
## Installing this collection
You can install the Infisical collection with the Ansible Galaxy CLI:
```bash
$ ansible-galaxy collection install infisical.vault
```
The python module dependencies are not installed by ansible-galaxy. They can be manually installed using pip:
```bash
$ pip install infisical-python
```
## Using this collection
You can either call modules by their Fully Qualified Collection Name (FQCN), such as `infisical.vault.read_secrets`, or you can call modules by their short name if you list the `infisical.vault` collection in the playbook's collections keyword:
```bash
---
vars:
read_all_secrets_within_scope: "{{ lookup('infisical.vault.read_secrets', universal_auth_client_id='<>', universal_auth_client_secret='<>', project_id='<>', path='/', env_slug='dev', url='https://spotify.infisical.com') }}"
# [{ "key": "HOST", "value": "google.com" }, { "key": "SMTP", "value": "gmail.smtp.edu" }]
read_secret_by_name_within_scope: "{{ lookup('infisical.vault.read_secrets', universal_auth_client_id='<>', universal_auth_client_secret='<>', project_id='<>', path='/', env_slug='dev', secret_name='HOST', url='https://spotify.infisical.com') }}"
# [{ "key": "HOST", "value": "google.com" }]
```
## Troubleshoot

View File

@@ -25,15 +25,10 @@ import (
func main() {
client, err := infisical.NewInfisicalClient(infisical.Config{
client := infisical.NewInfisicalClient(infisical.Config{
SiteUrl: "https://app.infisical.com", // Optional, default is https://app.infisical.com
})
if err != nil {
fmt.Printf("Error: %v", err)
os.Exit(1)
}
_, err = client.Auth().UniversalAuthLogin("YOUR_CLIENT_ID", "YOUR_CLIENT_SECRET")
if err != nil {
@@ -74,14 +69,9 @@ $ go get github.com/infisical/go-sdk
Import the SDK and create a client instance.
```go
client, err := infisical.NewInfisicalClient(infisical.Config{
client := infisical.NewInfisicalClient(infisical.Config{
SiteUrl: "https://app.infisical.com", // Optional, default is https://api.infisical.com
})
if err != nil {
fmt.Printf("Error: %v", err)
os.Exit(1)
}
```
### ClientSettings methods
@@ -435,4 +425,146 @@ Delete a secret in Infisical.
The type of the secret. Valid options are "shared" or "personal". If not specified, the default value is "shared".
</ParamField>
</Expandable>
</ParamField>
## Working with folders
### client.Folders().List(options)
```go
folders, err := client.Folders().List(infisical.ListFoldersOptions{
ProjectID: "PROJECT_ID",
Environment: "dev",
Path: "/",
})
```
Retrieve all within the Infisical project and environment that client is connected to.
#### Parameters
<ParamField query="Parameters" type="object">
<Expandable title="properties">
<ParamField query="Environment" type="string" required>
The slug name (dev, prod, etc) of the environment from where folders should be fetched from.
</ParamField>
<ParamField query="ProjectID" type="string">
The project ID where the folder lives in.
</ParamField>
<ParamField query="Path" type="string" optional>
The path from where folders should be fetched from.
</ParamField>
</Expandable>
</ParamField>
### client.Folders().Create(options)
```go
folder, err := client.Folders().Create(infisical.CreateFolderOptions{
ProjectID: "PROJECT_ID",
Name: "new=folder-name",
Environment: "dev",
Path: "/",
})
```
Create a new folder in Infisical.
#### Parameters
<ParamField query="Parameters" type="object" optional>
<Expandable title="properties">
<ParamField query="ProjectID" type="string" required>
The ID of the project where the folder will be created.
</ParamField>
<ParamField query="Environment" type="string" required>
The slug name (dev, prod, etc) of the environment where the folder will be created.
</ParamField>
<ParamField query="Path" type="string" optional>
The path to create the folder in. The root path is `/`.
</ParamField>
<ParamField query="Name" type="string" optional>
The name of the folder to create.
</ParamField>
</Expandable>
</ParamField>
### client.Folders().Update(options)
```go
folder, err := client.Folders().Update(infisical.UpdateFolderOptions{
ProjectID: "PROJECT_ID",
Environment: "dev",
Path: "/",
FolderID: "FOLDER_ID_TO_UPDATE",
NewName: "new-folder-name",
})
```
Update an existing folder in Infisical.
#### Parameters
<ParamField query="Parameters" type="object" optional>
<Expandable title="properties">
<ParamField query="ProjectID" type="string" required>
The ID of the project where the folder will be updated.
</ParamField>
<ParamField query="Environment" type="string" required>
The slug name (dev, prod, etc) of the environment from where the folder lives in.
</ParamField>
<ParamField query="Path" type="string" optional>
The path from where the folder should be updated.
</ParamField>
<ParamField query="FolderID" type="string" required>
The ID of the folder to update.
</ParamField>
<ParamField query="NewName" type="string" required>
The new name of the folder.
</ParamField>
</Expandable>
</ParamField>
### client.Folders().Delete(options)
```go
deletedFolder, err := client.Folders().Delete(infisical.DeleteFolderOptions{
// Either folder ID or folder name is required.
FolderName: "name-of-folder-to-delete",
FolderID: "folder-id-to-delete",
ProjectID: "PROJECT_ID",
Environment: "dev",
Path: "/",
})
```
Delete a folder in Infisical.
#### Parameters
<ParamField query="Parameters" type="object" optional>
<Expandable title="properties">
<ParamField query="FolderName" type="string" optional>
The name of the folder to delete. Note that either `FolderName` or `FolderID` is required.
</ParamField>
<ParamField query="FolderID" type="string" optional>
The ID of the folder to delete. Note that either `FolderName` or `FolderID` is required.
</ParamField>
<ParamField query="ProjectID" type="string" required>
The ID of the project where the folder lives in.
</ParamField>
<ParamField query="Environment" type="string" required>
The slug name (dev, prod, etc) of the environment from where the folder lives in.
</ParamField>
<ParamField query="Path" type="string" optional>
The path from where the folder should be deleted.
</ParamField>
</Expandable>
</ParamField>

View File

@@ -179,8 +179,9 @@ export const LogsFilter = ({ control, reset }: Props) => {
<FormControl label="End date" errorText={error?.message} isError={Boolean(error)}>
<DatePicker
value={field.value || undefined}
onChange={(date) => {
onChange(date);
onChange={(pickedDate) => {
pickedDate?.setHours(23, 59, 59, 999); // we choose the end of today not the start of it (going off of aws cloud watch)
onChange(pickedDate);
setIsEndDatePickerOpen(false);
}}
popUpProps={{

View File

@@ -23,7 +23,8 @@ export const LogsSection = () => {
defaultValues: {
page: 1,
perPage: 10,
startDate: new Date(new Date().setDate(new Date().getDate() - 1))
startDate: new Date(new Date().setDate(new Date().getDate() - 1)), // day before today
endDate: new Date(new Date(Date.now()).setHours(23, 59, 59, 999)) // end of today
}
});