Problem
Passing structured data (JSON objects/arrays) from code steps to bash steps is unsafe and requires a 2-step workaround pattern.
Current workaround (102 instances in our codebase)
Every time a bash step needs a JSON payload, we:
- file-write step: Write JSON to a temp file (
/tmp/payload-{uuid}.json)
- bash step:
curl -d @/tmp/payload-{uuid}.json ...
This exists because Handlebars interpolation inside quoted bash strings breaks when the JSON contains quotes, newlines, or special characters. bash_step_regression.py (related: #50) enforces that no flow directly interpolates JSON templates inside quoted strings.
Example of the fragile pattern we're avoiding:
{
"type": "bash",
"bash": {
"command": "curl -d '{{$.steps.buildConfig.output.configJson}}' http://server/endpoint"
}
}
If configJson contains a single quote, the command breaks. If it contains a newline, the command breaks.
Proposed solution — environment variable injection with type awareness
{
"type": "bash",
"bash": {
"command": "curl -X POST $ENDPOINT -H 'Content-Type: application/json' -d @$PAYLOAD_FILE",
"env": {
"ENDPOINT": "{{$.steps.loadConfig.output.SERVER_URL}}/api/process",
"PAYLOAD_FILE": {
"json": "{{$.steps.buildConfig.output}}"
}
}
}
}
When env contains a { "json": "..." } value, the CLI:
- Serializes the value to JSON
- Writes it to a temp file
- Substitutes the env var with the temp file path
- Cleans up after step completion
For simpler cases (string values that need shell-safe escaping):
{
"env": {
"COMPANY_NAME": { "shell": "{{$.steps.data.output.name}}" }
}
}
Impact
Relationship to existing issues
This extends #50 (unsafe Handlebars in bash). #50 identified the problem; this proposes a concrete mechanism. The printf '%s' workaround from #50 handles simple strings but not structured JSON payloads, which is the more common case.
Problem
Passing structured data (JSON objects/arrays) from code steps to bash steps is unsafe and requires a 2-step workaround pattern.
Current workaround (102 instances in our codebase)
Every time a bash step needs a JSON payload, we:
/tmp/payload-{uuid}.json)curl -d @/tmp/payload-{uuid}.json ...This exists because Handlebars interpolation inside quoted bash strings breaks when the JSON contains quotes, newlines, or special characters.
bash_step_regression.py(related: #50) enforces that no flow directly interpolates JSON templates inside quoted strings.Example of the fragile pattern we're avoiding:
{ "type": "bash", "bash": { "command": "curl -d '{{$.steps.buildConfig.output.configJson}}' http://server/endpoint" } }If
configJsoncontains a single quote, the command breaks. If it contains a newline, the command breaks.Proposed solution — environment variable injection with type awareness
{ "type": "bash", "bash": { "command": "curl -X POST $ENDPOINT -H 'Content-Type: application/json' -d @$PAYLOAD_FILE", "env": { "ENDPOINT": "{{$.steps.loadConfig.output.SERVER_URL}}/api/process", "PAYLOAD_FILE": { "json": "{{$.steps.buildConfig.output}}" } } } }When
envcontains a{ "json": "..." }value, the CLI:For simpler cases (string values that need shell-safe escaping):
{ "env": { "COMPANY_NAME": { "shell": "{{$.steps.data.output.name}}" } } }Impact
Relationship to existing issues
This extends #50 (unsafe Handlebars in bash). #50 identified the problem; this proposes a concrete mechanism. The
printf '%s'workaround from #50 handles simple strings but not structured JSON payloads, which is the more common case.