Files
attune/docs/parameters/dotenv-parameter-format.md

365 lines
7.7 KiB
Markdown

# DOTENV Parameter Format
## Overview
The DOTENV parameter format is used to pass action parameters securely via stdin in a shell-compatible format. This format is particularly useful for shell scripts that need to parse parameters without relying on external tools like `jq`.
## Format Specification
### Basic Format
Parameters are formatted as `key='value'` pairs, one per line:
```bash
url='https://example.com'
method='GET'
timeout='30'
verify_ssl='true'
```
### Nested Object Flattening
Nested JSON objects are automatically flattened using dot notation. This allows shell scripts to easily parse complex parameter structures.
**Input JSON:**
```json
{
"url": "https://example.com",
"headers": {
"Content-Type": "application/json",
"Authorization": "Bearer token123"
},
"query_params": {
"page": "1",
"size": "10"
}
}
```
**Output DOTENV:**
```bash
headers.Authorization='Bearer token123'
headers.Content-Type='application/json'
query_params.page='1'
query_params.size='10'
url='https://example.com'
```
### Empty Objects
Empty objects (`{}`) are omitted from the output entirely. They do not produce any dotenv entries.
**Input:**
```json
{
"url": "https://example.com",
"headers": {},
"query_params": {}
}
```
**Output:**
```bash
url='https://example.com'
```
### Arrays
Arrays are serialized as JSON strings:
**Input:**
```json
{
"tags": ["web", "api", "production"]
}
```
**Output:**
```bash
tags='["web","api","production"]'
```
### Special Characters
Single quotes in values are escaped using the shell-safe `'\''` pattern:
**Input:**
```json
{
"message": "It's working!"
}
```
**Output:**
```bash
message='It'\''s working!'
```
## Shell Script Parsing
### Basic Parameter Parsing
```bash
#!/bin/sh
# Read DOTENV-formatted parameters from stdin
while IFS= read -r line; do
case "$line" in
*"---ATTUNE_PARAMS_END---"*) break ;;
esac
[ -z "$line" ] && continue
key="${line%%=*}"
value="${line#*=}"
# Remove quotes
case "$value" in
\"*\") value="${value#\"}"; value="${value%\"}" ;;
\'*\') value="${value#\'}"; value="${value%\'}" ;;
esac
# Process parameters
case "$key" in
url) url="$value" ;;
method) method="$value" ;;
timeout) timeout="$value" ;;
esac
done
```
### Parsing Nested Objects
For flattened nested objects, use pattern matching on the key prefix:
```bash
# Create temporary files for nested data
headers_file=$(mktemp)
query_params_file=$(mktemp)
while IFS= read -r line; do
case "$line" in
*"---ATTUNE_PARAMS_END---"*) break ;;
esac
[ -z "$line" ] && continue
key="${line%%=*}"
value="${line#*=}"
# Remove quotes
case "$value" in
\'*\') value="${value#\'}"; value="${value%\'}" ;;
esac
# Process parameters
case "$key" in
url) url="$value" ;;
method) method="$value" ;;
headers.*)
# Extract nested key (e.g., "Content-Type" from "headers.Content-Type")
nested_key="${key#headers.}"
printf '%s: %s\n' "$nested_key" "$value" >> "$headers_file"
;;
query_params.*)
nested_key="${key#query_params.}"
printf '%s=%s\n' "$nested_key" "$value" >> "$query_params_file"
;;
esac
done
# Use the parsed data
if [ -s "$headers_file" ]; then
while IFS= read -r header; do
curl_args="$curl_args -H '$header'"
done < "$headers_file"
fi
```
## Configuration
### Action YAML Configuration
Specify DOTENV format in your action YAML:
```yaml
ref: mypack.myaction
entry_point: myaction.sh
parameter_delivery: stdin
parameter_format: dotenv # Use dotenv format
output_format: json
```
### Supported Formats
- `dotenv` - Shell-friendly key='value' format with nested object flattening
- `json` - Standard JSON format
- `yaml` - YAML format
### Supported Delivery Methods
- `stdin` - Parameters passed via stdin (recommended for security)
- `file` - Parameters written to a temporary file
## Security Considerations
### Why DOTENV + STDIN?
This combination provides several security benefits:
1. **No process list exposure**: Parameters don't appear in `ps aux` output
2. **No shell escaping issues**: Values are properly quoted
3. **Secret protection**: Sensitive values passed via stdin, not environment variables
4. **No external dependencies**: Pure POSIX shell parsing without `jq` or other tools
### Secret Handling
Secrets are passed separately via stdin after parameters. They are never included in environment variables or parameter files.
```bash
# Parameters are sent first
url='https://api.example.com'
---ATTUNE_PARAMS_END---
# Then secrets (as JSON)
{"api_key":"secret123","password":"hunter2"}
```
## Examples
### Example 1: HTTP Request Action
**Action Configuration:**
```yaml
ref: core.http_request
parameter_delivery: stdin
parameter_format: dotenv
```
**Execution Parameters:**
```json
{
"url": "https://api.example.com/users",
"method": "POST",
"headers": {
"Content-Type": "application/json",
"User-Agent": "Attune/1.0"
},
"query_params": {
"page": "1",
"limit": "10"
}
}
```
**Stdin Input:**
```bash
headers.Content-Type='application/json'
headers.User-Agent='Attune/1.0'
method='POST'
query_params.limit='10'
query_params.page='1'
url='https://api.example.com/users'
---ATTUNE_PARAMS_END---
```
### Example 2: Simple Shell Action
**Action Configuration:**
```yaml
ref: mypack.greet
parameter_delivery: stdin
parameter_format: dotenv
```
**Execution Parameters:**
```json
{
"name": "Alice",
"greeting": "Hello"
}
```
**Stdin Input:**
```bash
greeting='Hello'
name='Alice'
---ATTUNE_PARAMS_END---
```
## Troubleshooting
### Issue: Parameters Not Received
**Symptom:** Action receives empty or incorrect parameter values.
**Solution:** Ensure you're reading until the `---ATTUNE_PARAMS_END---` delimiter:
```bash
while IFS= read -r line; do
case "$line" in
*"---ATTUNE_PARAMS_END---"*) break ;; # Important!
esac
# ... parse line
done
```
### Issue: Nested Objects Not Parsed
**Symptom:** Headers or query params not being set correctly.
**Solution:** Use pattern matching to detect dotted keys:
```bash
case "$key" in
headers.*)
nested_key="${key#headers.}"
# Process nested key
;;
esac
```
### Issue: Special Characters Corrupted
**Symptom:** Values with single quotes are malformed.
**Solution:** The worker automatically escapes single quotes using `'\''`. Make sure to remove quotes correctly:
```bash
# Remove quotes (handles escaped quotes correctly)
case "$value" in
\'*\') value="${value#\'}"; value="${value%\'}" ;;
esac
```
## Best Practices
1. **Always read until delimiter**: Don't stop reading stdin early
2. **Handle empty objects**: Check if files are empty before processing
3. **Use temporary files**: For nested objects, write to temp files for easier processing
4. **Validate required parameters**: Check that required values are present
5. **Clean up temp files**: Use `trap` to ensure cleanup on exit
```bash
#!/bin/sh
set -e
# Setup cleanup
headers_file=$(mktemp)
trap "rm -f $headers_file" EXIT
# Parse parameters...
```
## Implementation Details
The parameter flattening is implemented in `crates/worker/src/runtime/parameter_passing.rs`:
- Nested objects are recursively flattened with dot notation
- Empty objects produce no output entries
- Arrays are JSON-serialized as strings
- Output is sorted alphabetically for consistency
- Single quotes are escaped using shell-safe `'\''` pattern
## See Also
- [Action Parameter Schema](../packs/pack-structure.md#parameters)
- [Secrets Management](../authentication/secrets-management.md)
- [Shell Runtime](../architecture/worker-service.md#shell-runtime)