Skip to content

Fix Slack notify prompt to use literal values, not $VAR#999

Merged
danbarr merged 1 commit into
mainfrom
fix-slack-notify-literal-prompt-values
Jun 30, 2026
Merged

Fix Slack notify prompt to use literal values, not $VAR#999
danbarr merged 1 commit into
mainfrom
fix-slack-notify-literal-prompt-values

Conversation

@danbarr

@danbarr danbarr commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Description

Root cause found and confirmed locally, not another guess this time.

Claude Code's permission matcher denies any Bash command containing an unexpanded shell variable ($PR_NUMBER, ${GH_REPO}, etc.), regardless of whether the rest of the command matches an allowedTools wildcard like Bash(gh:*). It can't statically verify that expanding an unknown variable won't smuggle in extra shell metacharacters, so it always falls back to "needs approval", which is impossible to satisfy with no human in the loop. The prompt told Claude to build its gh pr view command from env vars using exactly that shell-expansion syntax, so every attempt was denied no matter how it was quoted or wrapped, and Claude burned through all 30 turns trying workarounds (brace expansion, subshells, printenv, Python subprocess, writing a helper script) before timing out.

I reproduced this directly: ran the claude CLI locally with the literal prompt text and the same --allowedTools "Bash(gh:*),Write" --setting-sources user --max-turns 30, and got permission_denials: 19 and error_max_turns, denial #1 being the exact literal command from the prompt. The denial reason was "Contains simple_expansion".

Fix: interpolate the PR number, repo, URL, and workspace path directly into the prompt text via GitHub Actions expressions (${{ github.event.pull_request.number }}, etc.) instead of telling Claude to reference env vars in the Bash command. None of these four values are PR-content-controlled (they're trusted event/repository/runner context, not PR title/body), so embedding them directly carries no injection risk, the existing design already correctly avoids embedding actual PR content this way.

Verified the fix the same way: rendered the new prompt with PR #992's real values and ran it through the local claude CLI with identical flags. Result: num_turns: 3, permission_denials: 0, and a correctly-formed output JSON with accurate PR data and reviewer notes.

Type of change

  • Bug fix (typo, broken link, etc.)

Related issues/PRs

Follow-up to #994, #995, #996, #997, #998

Submitter checklist

Content and formatting

  • I have reviewed the content for technical accuracy
  • I have reviewed the content for spelling, grammar, and style

Reviewer checklist

Content

  • I have reviewed the content for technical accuracy
  • I have reviewed the content for spelling, grammar, and style

Claude Code's permission matcher denies any Bash command containing
an unexpanded shell variable (e.g. "$PR_NUMBER"), regardless of
whether the rest of the command matches an allowedTools wildcard
like Bash(gh:*). The prompt told Claude to build its gh command from
env vars using shell expansion, so every attempt was denied no
matter how it was quoted, and Claude burned all 30 turns retrying
variations before timing out.

Interpolate the PR number, repo, URL, and workspace path directly
into the prompt text via GitHub Actions expressions instead, so the
Bash command Claude runs contains literal values with no expansion.
None of these are PR-content-controlled (they come from trusted
event/repository context), so embedding them is safe.

Verified locally: ran the rendered prompt through the claude CLI
with the same allowedTools/model/max-turns and got num_turns=3,
permission_denials=0, and a correct output file.
Copilot AI review requested due to automatic review settings June 30, 2026 21:17
@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs-website Ready Ready Preview, Comment Jun 30, 2026 9:18pm

Request Review

@danbarr danbarr enabled auto-merge (squash) June 30, 2026 21:19
@danbarr danbarr disabled auto-merge June 30, 2026 21:56
@danbarr danbarr merged commit 9dcc02c into main Jun 30, 2026
4 checks passed
@danbarr danbarr deleted the fix-slack-notify-literal-prompt-values branch June 30, 2026 21:56
@danbarr danbarr removed the request for review from Copilot June 30, 2026 21:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant