Repository navigation
Modify start-pull-request.yml to pass label values through env instead of inline interpolation - #97
Conversation
…ation
start-pull-request.yml interpolated ${{ env.LABELS }}, ${{ env.ASSIGNEES }},
${{ env.NEW_BRANCH_NAME }} and ${{ github.event.issue.number }} directly into
run: script text. GitHub Actions substitutes these as text before the shell
runs, so a value containing $() or backticks would execute on the runner in a
job holding contents/issues/pull-requests write + id-token write. Not
currently exploitable (every label/branch-name producer today is a hardcoded
literal or numeric), but the safety was external to this file rather than
built into it.
Switched every run: step to reference the already-exported $GITHUB_ENV shell
variables directly instead, matching the pattern the file already used at
:47-49/:66-68.
Fixes #95
/code-review on #97 caught that --base "${{ github.event.repository.default_branch }}" was still spliced directly into run: script text — the same class the rest of this file was just fixed for. Git ref-name rules don't forbid $, backticks or parens in a branch name, so a renamed default branch could inject the same way. Added DEFAULT_BRANCH to the job-level env block alongside ISSUE_NUM/ ISSUE_TITLE and switched --base to reference it as a shell variable.
|
Code review (high effort) on 8841740 — no findings against this change. Verified each substitution is shell-equivalent to what it replaced: Two pre-existing defects sit on lines this PR touches. Neither is introduced by it and both are out of scope for #95 — recording them here so they're not lost, to be filed separately rather than expanding this PR:
|
sn0wm1ku
left a comment
There was a problem hiding this comment.
Code review on 8841740 — approve, no blocking findings.
Independently re-verified the diff against the file at head:
- Correctness of the substitution. Every
${{ }}removed fromrun:script text now reaches the shell as a real environment variable at its point of use:LABELS/ASSIGNEES/NEW_BRANCH_NAME/OPEN_LINKED_PR_LENGTHare written to$GITHUB_ENVby earlier steps, andREPO/ISSUE_NUM/ISSUE_TITLE/DEFAULT_BRANCHsit in the job-levelenv:block (withDEFAULT_BRANCHnewly added there —github.event.repository.default_branchis available on theissuestrigger). No${{ }}remains inside anyrun:block in this workflow. - The sink is closed. A value expanded from a shell variable is not re-scanned for
$()/backticks, so a metacharacter-bearing label name can no longer execute in a job holdingcontents/issues/pull-requests/id-token: write. This is the handbook's required shape — data must cross into an interpreter as data, not be concatenated into script text (application-security.md §3-9 "encode/parameterize at the sink", §3-10 command/template injection defences). - Scope is minimal and matches #95 exactly — the fix the issue proposed, nothing else (code-review.md §3-1: correct and minimal, KISS/YAGNI). CI (
run-tests) is green on head.
The two pre-existing defects on touched lines (unlabeled issue aborts gh pr create after the push, leaving an orphan branch; the idea/epic guard failing open when gh api errors under default no-pipefail shell) are already recorded in the thread and are correctly kept out of this PR — they predate it and belong in their own issue.
🤖 auto-posted by sn0wm1ku/ghDuty · co-authored by Claude (claude-opus-4-8)
1. Target
2. Specification / Test Plan
(Text here)
3. Additional Instructions / Notes for Shipping (optional)
N/A
4. Check before Review Request
5. Evidence
(Attach here before request review)