Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ APACHE 2.0 LICENSED DEPENDENCIES

- github.com/google/renameio/v2
License: Apache-2.0
URL: https://github.com/google/renameio/blob/v2.0.1/LICENSE
URL: https://github.com/google/renameio/blob/v2.0.2/LICENSE

- github.com/google/s2a-go
License: Apache-2.0
Expand Down Expand Up @@ -363,15 +363,15 @@ APACHE 2.0 LICENSED DEPENDENCIES

- github.com/open-policy-agent/opa
License: Apache-2.0
URL: https://github.com/open-policy-agent/opa/blob/v1.12.1/LICENSE
URL: https://github.com/open-policy-agent/opa/blob/v1.12.2/LICENSE

- github.com/open-policy-agent/opa/internal/gojsonschema
License: Apache-2.0
URL: https://github.com/open-policy-agent/opa/blob/v1.12.1/internal/gojsonschema/LICENSE-APACHE-2.0.txt
URL: https://github.com/open-policy-agent/opa/blob/v1.12.2/internal/gojsonschema/LICENSE-APACHE-2.0.txt

- github.com/open-policy-agent/opa/internal/semver
License: Apache-2.0
URL: https://github.com/open-policy-agent/opa/blob/v1.12.1/internal/semver/LICENSE
URL: https://github.com/open-policy-agent/opa/blob/v1.12.2/internal/semver/LICENSE

- github.com/opencontainers/go-digest
License: Apache-2.0
Expand Down Expand Up @@ -688,7 +688,7 @@ BSD LICENSED DEPENDENCIES

- github.com/open-policy-agent/opa/internal/edittree/bitvector
License: BSD-3-Clause
URL: https://github.com/open-policy-agent/opa/blob/v1.12.1/internal/edittree/bitvector/license.txt
URL: https://github.com/open-policy-agent/opa/blob/v1.12.2/internal/edittree/bitvector/license.txt

- github.com/pierrec/lz4/v4
License: BSD-3-Clause
Expand Down Expand Up @@ -1242,7 +1242,7 @@ MIT LICENSED DEPENDENCIES

- github.com/go-viper/mapstructure/v2
License: MIT
URL: https://github.com/go-viper/mapstructure/blob/v2.4.0/LICENSE
URL: https://github.com/go-viper/mapstructure/blob/v2.5.0/LICENSE

- github.com/gobwas/glob
License: MIT
Expand All @@ -1254,7 +1254,7 @@ MIT LICENSED DEPENDENCIES

- github.com/goccy/go-yaml
License: MIT
URL: https://github.com/goccy/go-yaml/blob/v1.19.1/LICENSE
URL: https://github.com/goccy/go-yaml/blob/v1.19.2/LICENSE

- github.com/golang-jwt/jwt/v4
License: MIT
Expand Down
8 changes: 4 additions & 4 deletions go.mod

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 8 additions & 8 deletions go.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

71 changes: 71 additions & 0 deletions internal/exec/workflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"mvdan.cc/sh/v3/shell"

errUtils "github.com/cloudposse/atmos/errors"
cfg "github.com/cloudposse/atmos/pkg/config"
Expand Down Expand Up @@ -240,6 +241,76 @@ func TestExecuteWorkflow(t *testing.T) {
}
}

// TestShellFieldsQuoteParsing verifies that shell.Fields correctly parses quoted arguments.
// This test documents the fix for the issue where -var="key=value" was incorrectly parsed.
func TestShellFieldsQuoteParsing(t *testing.T) {
tests := []struct {
name string
command string
expected []string
}{
{
name: "double quoted var flag",
command: `terraform plan mock -var="enabled=false" -s nonprod`,
expected: []string{
"terraform", "plan", "mock", "-var=enabled=false", "-s", "nonprod",
},
},
{
name: "single quoted var flag",
command: `terraform plan mock -var='enabled=false' -s nonprod`,
expected: []string{
"terraform", "plan", "mock", "-var=enabled=false", "-s", "nonprod",
},
},
{
name: "multiple var flags with different quote styles",
command: `terraform plan mock -var="enabled=false" -var='foo=bar' -s nonprod`,
expected: []string{
"terraform", "plan", "mock", "-var=enabled=false", "-var=foo=bar", "-s", "nonprod",
},
},
{
name: "var with spaces in value",
command: `terraform plan mock -var="message=hello world" -s nonprod`,
expected: []string{
"terraform", "plan", "mock", "-var=message=hello world", "-s", "nonprod",
},
},
{
name: "var with equals in value",
command: `terraform plan mock -var="message=key=value" -s nonprod`,
expected: []string{
"terraform", "plan", "mock", "-var=message=key=value", "-s", "nonprod",
},
},
{
name: "query flag with quoted expression",
command: `terraform plan --query '.settings.enabled == true' -s nonprod`,
expected: []string{
"terraform", "plan", "--query", ".settings.enabled == true", "-s", "nonprod",
},
},
{
name: "complex auto-generate-backend-file flag",
command: `terraform deploy tfstate-backend -var="access_roles_enabled=false" --stack core-usw1-root --auto-generate-backend-file=false`,
expected: []string{
"terraform", "deploy", "tfstate-backend", "-var=access_roles_enabled=false",
"--stack", "core-usw1-root", "--auto-generate-backend-file=false",
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Use shell.Fields which is what the fixed code uses
args, err := shell.Fields(tt.command, nil)
assert.NoError(t, err)
assert.Equal(t, tt.expected, args, "shell.Fields should correctly parse quoted arguments")
})
}
}

func TestCheckAndGenerateWorkflowStepNames(t *testing.T) {
tests := []struct {
name string
Expand Down
9 changes: 8 additions & 1 deletion internal/exec/workflow_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/huh"
"github.com/samber/lo"
"mvdan.cc/sh/v3/shell"

errUtils "github.com/cloudposse/atmos/errors"
"github.com/cloudposse/atmos/internal/tui/templates/term"
Expand Down Expand Up @@ -332,7 +333,13 @@ func ExecuteWorkflow(
commandName := fmt.Sprintf("%s-step-%d", workflow, stepIdx)
err = ExecuteShell(command, commandName, ".", stepEnv, dryRun)
case "atmos":
args := strings.Fields(command)
// Parse command using shell.Fields for proper quote handling.
// This correctly handles arguments like -var="foo=bar" by stripping quotes.
args, parseErr := shell.Fields(command, nil)
if parseErr != nil {
log.Debug("Shell parsing failed, falling back to strings.Fields", "error", parseErr, "command", command)
args = strings.Fields(command)
}

workflowStack := strings.TrimSpace(workflowDefinition.Stack)
stepStack := strings.TrimSpace(step.Stack)
Expand Down
Loading
Loading