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
20 changes: 19 additions & 1 deletion amplifier-bundle/recipes/consensus-workflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -524,8 +524,26 @@ steps:

Commands to execute:
```bash
# NOTE: This pipeline mirrors default-workflow.yaml step-04-setup-worktree with a
# 30-char limit (vs 50). Keep both in sync on security patches. See Issue #2952.
# REQ-SEC-001 (tracked in #2974): single-quote wrapping mitigates word-splitting
# but does not prevent injection via single-quote chars in task_description.
# Full fix requires env-var injection in the recipe runner.
# Create branch name
BRANCH_NAME="feat/consensus-$(echo '{{task_description}}' | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | cut -c1-30)"
TASK_DESC=$(printf '%s' '{{task_description}}')
TASK_SLUG=$(printf '%s' "$TASK_DESC" | tr '\n\r' ' ' | tr '[:upper:]' '[:lower:]' | tr -s ' ' '-' | sed 's/[^a-z0-9-]//g' | sed 's/-\{2,\}/-/g' | sed 's/^-//;s/-$//' | cut -c1-30 | sed 's/-$//')
# Guard: empty slug (blank/all-symbol input) produces a trailing-hyphen branch that
# git check-ref-format accepts as valid but is undesirable. Catch it explicitly first.
if [ -z "$TASK_SLUG" ]; then
echo "WARNING: task_description produced an empty slug — falling back to task-unnamed" >&2
BRANCH_NAME="feat/task-unnamed-$(date +%s)"
else
BRANCH_NAME="feat/consensus-${TASK_SLUG}"
if ! git check-ref-format --branch "${BRANCH_NAME}" >/dev/null 2>&1; then
echo "WARNING: derived branch name '${BRANCH_NAME}' is invalid — falling back to task-unnamed" >&2
BRANCH_NAME="feat/task-unnamed-$(date +%s)"
fi
fi

# Create worktree
git worktree add "{{worktree_dir}}/$BRANCH_NAME" -b "$BRANCH_NAME"
Expand Down
42 changes: 39 additions & 3 deletions amplifier-bundle/recipes/default-workflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,46 @@ steps:
# Fetch latest refs
git fetch origin main >&2

# NOTE: This slug pipeline is duplicated in consensus-workflow.yaml step3-setup-worktree
# with a 30-char limit instead of 50. If you update this pipeline (e.g. security patch),
# update consensus-workflow.yaml in the same commit. See Issue #2952 for context.
#
# ACTION REQUIRED: File a dedicated security issue to audit the recipe runner's
# template substitution engine for single-quote escaping (REQ-SEC-001 audit).
# Until confirmed safe, user-provided values should be injected as env vars,
# not as inline template substitutions in single-quoted bash strings.
#
# Generate branch name — use printf to safely capture the shlex-quoted value
TASK_DESC=$(printf '%s' {{task_description}})
TASK_SLUG=$(echo "$TASK_DESC" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | sed 's/[^a-z0-9-]//g' | cut -c1-50)
BRANCH_NAME="{{branch_prefix}}/issue-{{issue_number}}-${TASK_SLUG}"
# Pipeline stages:
# 1. tr '\n\r' ' ' — CRLF normalisation: collapse multi-paragraph input to single line
# 2. tr '[:upper:]' '[:lower:]' — lowercase
# 3. tr -s ' ' '-' — squeeze runs of spaces into single hyphens
# 4. sed whitelist — strip non-alnum-hyphen (security: removes $, `, ;, &, |)
# 5. sed collapse — collapse consecutive hyphens (arises from stripped chars)
# 6. sed edge-trim — strip leading/trailing hyphens
# 7. cut -c1-50 — hard truncation to 50 chars
# 8. sed trailing — strip trailing hyphen that cut can introduce at position 50
# NOTE (REQ-SEC-001, tracked in issue #2974): {{task_description}} is injected via
# text substitution before shell parsing. Single-quote wrapping below prevents
# word-splitting and glob expansion but does NOT protect against a single-quote
# character in the input (which would terminate the string prematurely). Issue #2974
# tracks migrating to env-var injection in the recipe runner so values are never
# inlined into shell source.
TASK_DESC=$(printf '%s' '{{task_description}}')
TASK_SLUG=$(printf '%s' "$TASK_DESC" | tr '\n\r' ' ' | tr '[:upper:]' '[:lower:]' | tr -s ' ' '-' | sed 's/[^a-z0-9-]//g' | sed 's/-\{2,\}/-/g' | sed 's/^-//;s/-$//' | cut -c1-50 | sed 's/-$//')
# Guard: empty slug (blank/all-symbol input) produces a trailing-hyphen branch that
# git check-ref-format accepts as valid but is undesirable. Catch it explicitly first.
if [ -z "$TASK_SLUG" ]; then
echo "WARNING: task_description produced an empty slug — falling back to task-unnamed" >&2
BRANCH_NAME="{{branch_prefix}}/task-unnamed-$(date +%s)"
else
BRANCH_NAME="{{branch_prefix}}/issue-{{issue_number}}-${TASK_SLUG}"
# Validate with authoritative git ref checker; fall back to safe unique name on failure
if ! git check-ref-format --branch "${BRANCH_NAME}" >/dev/null 2>&1; then
echo "WARNING: derived branch name '${BRANCH_NAME}' is invalid — falling back to task-unnamed" >&2
BRANCH_NAME="{{branch_prefix}}/task-unnamed-$(date +%s)"
fi
fi
WORKTREE_PATH="{{repo_path}}/worktrees/${BRANCH_NAME}"

echo "Branch: ${BRANCH_NAME}" >&2
Expand Down
Loading
Loading