From 4729a9a717c079c0b4efb580a494f8c216264834 Mon Sep 17 00:00:00 2001 From: Matheus Nogueira Date: Wed, 6 May 2026 18:13:23 -0300 Subject: [PATCH 1/4] support multiple paths in `infisical run` --- packages/cmd/run.go | 67 +++++++++++++++++++++++++++++------------- packages/models/cli.go | 10 +++++++ 2 files changed, 57 insertions(+), 20 deletions(-) diff --git a/packages/cmd/run.go b/packages/cmd/run.go index fecbccb1..dc1c1425 100644 --- a/packages/cmd/run.go +++ b/packages/cmd/run.go @@ -121,7 +121,7 @@ var runCmd = &cobra.Command{ util.HandleError(err, "Unable to parse flag") } - secretsPath, err := cmd.Flags().GetString("path") + secretsPaths, err := cmd.Flags().GetStringArray("path") if err != nil { util.HandleError(err, "Unable to parse flag") } @@ -136,11 +136,11 @@ var runCmd = &cobra.Command{ util.HandleError(err, "Unable to parse flag") } - request := models.GetAllSecretsParameters{ + request := models.GetMultiPathSecretsParameters{ Environment: environmentName, WorkspaceId: projectId, TagSlugs: tagSlugs, - SecretsPath: secretsPath, + SecretsPaths: secretsPaths, IncludeImport: includeImports, Recursive: recursive, ExpandSecretReferences: shouldExpandSecrets, @@ -220,7 +220,7 @@ func init() { runCmd.Flags().Int("watch-interval", 10, "interval in seconds to check for secret changes") runCmd.Flags().StringP("command", "c", "", "chained commands to execute (e.g. \"npm install && npm run dev; echo ...\")") runCmd.Flags().StringP("tags", "t", "", "filter secrets by tag slugs ") - runCmd.Flags().String("path", "/", "get secrets within a folder path") + runCmd.Flags().StringArray("path", []string{"/"}, "get secrets within a folder path (can be specified multiple times, last path wins on conflicts)") runCmd.Flags().String("project-config-dir", "", "explicitly set the directory where the .infisical.json resides") } @@ -307,7 +307,7 @@ func waitForExitCommand(cmd *exec.Cmd) (int, error) { return waitStatus.ExitStatus(), nil } -func executeCommandWithWatchMode(commandFlag string, args []string, watchModeInterval int, request models.GetAllSecretsParameters, projectConfigDir string, secretOverriding bool, token *models.TokenDetails) { +func executeCommandWithWatchMode(commandFlag string, args []string, watchModeInterval int, request models.GetMultiPathSecretsParameters, projectConfigDir string, secretOverriding bool, token *models.TokenDetails) { var cmd *exec.Cmd var err error @@ -439,26 +439,44 @@ func executeCommandWithWatchMode(commandFlag string, args []string, watchModeInt } } -func fetchAndFormatSecretsForShell(request models.GetAllSecretsParameters, projectConfigDir string, secretOverriding bool, token *models.TokenDetails) (models.InjectableEnvironmentResult, error) { +func fetchSecrets(request models.GetMultiPathSecretsParameters, projectConfigDir string, secretOverriding bool, token *models.TokenDetails) ([]models.SingleEnvironmentVariable, error) { + var allSecrets []models.SingleEnvironmentVariable + + for _, path := range request.SecretsPaths { + params := models.GetAllSecretsParameters{ + Environment: request.Environment, + WorkspaceId: request.WorkspaceId, + TagSlugs: request.TagSlugs, + SecretsPath: path, + IncludeImport: request.IncludeImport, + Recursive: request.Recursive, + ExpandSecretReferences: request.ExpandSecretReferences, + } - if token != nil && token.Type == util.SERVICE_TOKEN_IDENTIFIER { - request.InfisicalToken = token.Token - } else if token != nil && token.Type == util.UNIVERSAL_AUTH_TOKEN_IDENTIFIER { - request.UniversalAuthAccessToken = token.Token - } + if token != nil && token.Type == util.SERVICE_TOKEN_IDENTIFIER { + params.InfisicalToken = token.Token + } else if token != nil && token.Type == util.UNIVERSAL_AUTH_TOKEN_IDENTIFIER { + params.UniversalAuthAccessToken = token.Token + } - secrets, err := util.GetAllEnvironmentVariables(request, projectConfigDir) + secrets, err := util.GetAllEnvironmentVariables(params, projectConfigDir) + if err != nil { + return nil, fmt.Errorf("failed to fetch secrets for path %q: %w", path, err) + } - if err != nil { - return models.InjectableEnvironmentResult{}, err - } + if secretOverriding { + secrets = util.OverrideSecrets(secrets, util.SECRET_TYPE_PERSONAL) + } else { + secrets = util.OverrideSecrets(secrets, util.SECRET_TYPE_SHARED) + } - if secretOverriding { - secrets = util.OverrideSecrets(secrets, util.SECRET_TYPE_PERSONAL) - } else { - secrets = util.OverrideSecrets(secrets, util.SECRET_TYPE_SHARED) + allSecrets = append(allSecrets, secrets...) } + return allSecrets, nil +} + +func formatSecretsForShell(secrets []models.SingleEnvironmentVariable) models.InjectableEnvironmentResult { secretsByKey := getSecretsByKeys(secrets) environmentVariables := make(map[string]string) @@ -487,5 +505,14 @@ func fetchAndFormatSecretsForShell(request models.GetAllSecretsParameters, proje Variables: env, ETag: util.GenerateETagFromSecrets(secrets), SecretsCount: len(secretsByKey), - }, nil + } +} + +func fetchAndFormatSecretsForShell(request models.GetMultiPathSecretsParameters, projectConfigDir string, secretOverriding bool, token *models.TokenDetails) (models.InjectableEnvironmentResult, error) { + secrets, err := fetchSecrets(request, projectConfigDir, secretOverriding, token) + if err != nil { + return models.InjectableEnvironmentResult{}, err + } + + return formatSecretsForShell(secrets), nil } diff --git a/packages/models/cli.go b/packages/models/cli.go index 0b8c117f..c701012a 100644 --- a/packages/models/cli.go +++ b/packages/models/cli.go @@ -113,6 +113,16 @@ type SymmetricEncryptionResult struct { AuthTag []byte `json:"AuthTag"` } +type GetMultiPathSecretsParameters struct { + Environment string + WorkspaceId string + TagSlugs string + SecretsPaths []string + IncludeImport bool + Recursive bool + ExpandSecretReferences bool +} + type GetAllSecretsParameters struct { Environment string EnvironmentPassedViaFlag bool From 8d11e6aef5678472fe173de6c5e23ab2490c66a5 Mon Sep 17 00:00:00 2001 From: Matheus Nogueira Date: Wed, 6 May 2026 18:27:41 -0300 Subject: [PATCH 2/4] fix ETag generation by removing duplicated secrets --- packages/cmd/run.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/cmd/run.go b/packages/cmd/run.go index dc1c1425..87616d12 100644 --- a/packages/cmd/run.go +++ b/packages/cmd/run.go @@ -440,7 +440,7 @@ func executeCommandWithWatchMode(commandFlag string, args []string, watchModeInt } func fetchSecrets(request models.GetMultiPathSecretsParameters, projectConfigDir string, secretOverriding bool, token *models.TokenDetails) ([]models.SingleEnvironmentVariable, error) { - var allSecrets []models.SingleEnvironmentVariable + secretsByKey := make(map[string]models.SingleEnvironmentVariable) for _, path := range request.SecretsPaths { params := models.GetAllSecretsParameters{ @@ -470,10 +470,17 @@ func fetchSecrets(request models.GetMultiPathSecretsParameters, projectConfigDir secrets = util.OverrideSecrets(secrets, util.SECRET_TYPE_SHARED) } - allSecrets = append(allSecrets, secrets...) + for _, s := range secrets { + secretsByKey[s.Key] = s + } + } + + result := make([]models.SingleEnvironmentVariable, 0, len(secretsByKey)) + for _, s := range secretsByKey { + result = append(result, s) } - return allSecrets, nil + return result, nil } func formatSecretsForShell(secrets []models.SingleEnvironmentVariable) models.InjectableEnvironmentResult { From 91cee7f797aba9243c73651b4cc4f9e2324eaf08 Mon Sep 17 00:00:00 2001 From: Matheus Nogueira Date: Wed, 6 May 2026 19:12:00 -0300 Subject: [PATCH 3/4] use array + OverrideSecrets --- packages/cmd/run.go | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/packages/cmd/run.go b/packages/cmd/run.go index 87616d12..588c1456 100644 --- a/packages/cmd/run.go +++ b/packages/cmd/run.go @@ -440,7 +440,7 @@ func executeCommandWithWatchMode(commandFlag string, args []string, watchModeInt } func fetchSecrets(request models.GetMultiPathSecretsParameters, projectConfigDir string, secretOverriding bool, token *models.TokenDetails) ([]models.SingleEnvironmentVariable, error) { - secretsByKey := make(map[string]models.SingleEnvironmentVariable) + var allSecrets []models.SingleEnvironmentVariable for _, path := range request.SecretsPaths { params := models.GetAllSecretsParameters{ @@ -464,23 +464,16 @@ func fetchSecrets(request models.GetMultiPathSecretsParameters, projectConfigDir return nil, fmt.Errorf("failed to fetch secrets for path %q: %w", path, err) } - if secretOverriding { - secrets = util.OverrideSecrets(secrets, util.SECRET_TYPE_PERSONAL) - } else { - secrets = util.OverrideSecrets(secrets, util.SECRET_TYPE_SHARED) - } - - for _, s := range secrets { - secretsByKey[s.Key] = s - } + allSecrets = append(allSecrets, secrets...) } - result := make([]models.SingleEnvironmentVariable, 0, len(secretsByKey)) - for _, s := range secretsByKey { - result = append(result, s) + if secretOverriding { + allSecrets = util.OverrideSecrets(allSecrets, util.SECRET_TYPE_PERSONAL) + } else { + allSecrets = util.OverrideSecrets(allSecrets, util.SECRET_TYPE_SHARED) } - return result, nil + return allSecrets, nil } func formatSecretsForShell(secrets []models.SingleEnvironmentVariable) models.InjectableEnvironmentResult { From c08e5fa77babe060814dd3049f7b295f7c22336b Mon Sep 17 00:00:00 2001 From: Matheus Nogueira Date: Wed, 6 May 2026 19:59:01 -0300 Subject: [PATCH 4/4] =?UTF-8?q?remove=20=E2=80=9Clast=20path=20wins?= =?UTF-8?q?=E2=80=9D=20as=20this=20is=20not=20true?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/cmd/run.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cmd/run.go b/packages/cmd/run.go index 588c1456..a011a4b6 100644 --- a/packages/cmd/run.go +++ b/packages/cmd/run.go @@ -220,7 +220,7 @@ func init() { runCmd.Flags().Int("watch-interval", 10, "interval in seconds to check for secret changes") runCmd.Flags().StringP("command", "c", "", "chained commands to execute (e.g. \"npm install && npm run dev; echo ...\")") runCmd.Flags().StringP("tags", "t", "", "filter secrets by tag slugs ") - runCmd.Flags().StringArray("path", []string{"/"}, "get secrets within a folder path (can be specified multiple times, last path wins on conflicts)") + runCmd.Flags().StringArray("path", []string{"/"}, "get secrets within a folder path (can be specified multiple times)") runCmd.Flags().String("project-config-dir", "", "explicitly set the directory where the .infisical.json resides") }