Skip to content

✨ feat(ci): add opencode-new-pr workflow for sequential task execution - #9

Closed
dianlight wants to merge 3 commits into
mainfrom
refactor/new_implemet_workflow
Closed

✨ feat(ci): add opencode-new-pr workflow for sequential task execution#9
dianlight wants to merge 3 commits into
mainfrom
refactor/new_implemet_workflow

Conversation

@dianlight

@dianlightdianlight commented Jul 7, 2026

Copy link
Copy Markdown
Owner

Add a new workflow that creates a PR from an approved issue, extracts task lists
from comments, creates CHANGELOG entries, and dispatches tasks to opencode-implement.yaml
sequentially. The implement workflow was refactored to accept a pull request number
and optional task description instead of an issue trigger.

Summary by CodeRabbit

  • New Features
    • Added a new orchestrator workflow that converts an approved issue into a fresh pull request populated with an ordered task checklist.
    • Enabled implementation to run either the full approved request or a single specified task via manual dispatch input.
  • Bug Fixes
    • Improved triage routing to use the new issue-to-PR creation flow before implementation.
    • Tightened implementation triggers to PR-only and fail-fast behavior for sequential task execution.
  • Documentation
    • Updated workflow documentation and introduced AGENTS.md to describe the revised automation pipelines and workflow behavior.

Add a new workflow that creates a PR from an approved issue, extracts
task lists
from comments, creates CHANGELOG entries, and dispatches tasks to
opencode-implement.yaml
sequentially. The implement workflow was refactored to accept a pull
request number
and optional task description instead of an issue trigger.
@coderabbitai

coderabbitaiBot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@dianlight, you've reached your PR review limit, so we couldn't start this review.

Next review available in:58 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1bb26f32-efce-4d34-a4c2-052d032f1eca

📥 Commits

Reviewing files that changed from the base of the PR and between 96dd448 and e34d33f.

📒 Files selected for processing (1)
  • .github/workflows/opencode-new-pr.yaml
📝 Walkthrough

Walkthrough

This PR adds an opencode-new-pr.yaml orchestrator workflow for issue-driven task extraction and PR creation, shifts opencode-implement.yaml to PR-scoped task execution, updates triage dispatch to use the orchestrator, and refreshes sync config, task mapping, and workflow documentation.

Changes

Orchestrated issue-to-PR implementation pipeline

Layer / File(s)Summary
New opencode-new-pr orchestrator workflow
.github/workflows/opencode-new-pr.yaml
New workflow with issue-number dispatch input, issue task-list extraction, CHANGELOG.md update, branch/PR creation, and sequential task dispatch with run polling.
opencode-implement.yaml PR-only scoping
.github/workflows/opencode-implement.yaml
Adds task-description input, changes concurrency to PR number, narrows trigger to open labeled PRs without awaiting-response, and rewrites prompt for PR checkout/task scoping.
Triage workflow dispatch and prompt updates
.github/workflows/opencode-triage-issue.yaml
Updates quick-approval labeling/dispatch to target opencode-new-pr.yaml, revises AI prompt to require checklist tasks and orchestrator dispatch instructions, and normalizes formatting.
Sync config, task map, and documentation updates
.github/sync.yml, config/workflow-task-map.yaml, .github/workflows/WORKFLOWS.md, AGENTS.md
Adds opencode-new-pr.yaml to synced workflows and task-type map, rewrites WORKFLOWS.md for the five-workflow pipeline, and adds new AGENTS.md documentation.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
participant Triage as opencode-triage-issue.yaml
participant Orchestrator as opencode-new-pr.yaml
participant GH as GitHub API
participant Implement as opencode-implement.yaml
Triage->>GH: label issue approved-for-implementation
Triage->>Orchestrator: gh workflow run opencode-new-pr.yaml (issue-number)
Orchestrator->>GH: fetch issue comments and extract task checklist
Orchestrator->>GH: prepend CHANGELOG.md entry
Orchestrator->>GH: create feature branch and open PR with task checklist
loop for each task sequentially
Orchestrator->>Implement: dispatch opencode-implement.yaml (pr-number, task-description)
Implement->>GH: checkout PR branch, implement task, push commit
Orchestrator->>GH: poll run status, stop on failure
end
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly matches the main change: adding the opencode-new-pr workflow for sequential task execution.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/new_implemet_workflow

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: Changes requested

🚨 3 · 🛠️ 3 · 💡 1

Most critical: opencode-new-pr.yaml:157 passes untrusted task descriptions from issue comments directly as gh workflow run -f arguments — a task containing " breaks argument parsing, potentially injecting unexpected flags or values. Combined with opencode-new-pr.yaml:118 suppressing git push errors and a 60-second poll race condition for dispatched runs, the orchestrator will silently fail under real-world queue delays or non-trivial task descriptions.

All three CRITICALs are in opencode-new-pr.yaml (the new file). The implement and triage refactors look sound.

Comment thread.github/workflows/opencode-new-pr.yaml Outdated
Comment thread.github/workflows/opencode-new-pr.yaml
Comment thread.github/workflows/opencode-new-pr.yaml Outdated
Comment thread.github/workflows/opencode-new-pr.yaml Outdated
Comment thread.github/workflows/opencode-new-pr.yaml Outdated
Comment thread.github/workflows/opencode-new-pr.yaml Outdated
Comment threadAGENTS.md

## Key labels (state machine)

| Label | Meaning |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 [NITPICK] Inaccurate statement about OpenCode API key for CHANGELOG creation

opencode-new-pr.yaml does not use the anomalyco/opencode/github action at all — CHANGELOG creation is done by a Python script, not by the opencode AI. OPENCODE_API_KEY is never set in that workflow.

Suggested change
| Label | Meaning |
-`opencode-new-pr.yaml` uses `GITHUB_TOKEN` for all API calls (branch creation, PR creation, commenting).

@github-actions

Copy link
Copy Markdown
Contributor

Review submitted. 3 CRITICAL, 3 QUALITY, 1 NITPICK — all findings in opencode-new-pr.yaml except one doc nitpick in AGENTS.md. The implement/triage refactors and doc updates are clean.

CRITICALs:

  1. Shell injection (opencode-new-pr.yaml:157) — untrusted task descriptions passed as gh workflow run -f arguments can break quoting
  2. Race condition (opencode-new-pr.yaml:160-172) — 60s poll timeout too tight; createdAt > $BEFORE misses same-second runs
  3. Error suppression (opencode-new-pr.yaml:118) — git push stderr hidden by 2>/dev/null

New%20session%20-%202026-07-07T20%3A59%3A49.520Z
opencode session | github run

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/opencode-new-pr.yaml:
- Around line 76-104: The CHANGELOG generation step currently writes and commits
the file directly via inline Python and git in the opencode-new-pr workflow, but
it needs to be routed through OpenCode using the OpenCode API key. Update the
workflow step that creates or updates CHANGELOG.md so it invokes the OpenCode
action/command with OPENCODE_API_KEY for changelog creation instead of doing the
file generation locally, while keeping GITHUB_TOKEN usage limited to the
existing API call steps. Reference the “Create or update CHANGELOG.md” step in
opencode-new-pr.yaml when making the change.
- Around line 106-127: The Create branch and pull request workflow step is
interpolating github.event.inputs.issue-number and the extract-tasks outputs
directly inside run:, which can allow shell injection before the script
executes. Move ISSUE_NUMBER, ISSUE_TITLE, and TASKS into env: for this step and
update the matching extract-tasks and execute-tasks assignments to read from
environment variables instead of inline expressions.
- Around line 28-31: The checkout step in the workflow is clearing git
credentials, so the later branch push will fail. Update the job around the
Checkout repository step and the push logic that uses git push origin "$BRANCH"
to restore authentication first by configuring git to use GITHUB_TOKEN before
pushing, or otherwise ensure credentials are available when the push runs.
- Around line 141-157: The sequential task runner in the workflow is embedding
untrusted workflow outputs directly inside shell literals, which can break the
script if a task contains quotes. Move the values sourced from
needs.create-pr.outputs.task-list, needs.create-pr.outputs.pr-number, and
github.ref_name into env variables on the step, then read those shell variables
inside the run block instead of assigning them with inline expansion.
In @.github/workflows/opencode-triage-issue.yaml:
- Around line 13-32: The debug job in opencode-triage-issue.yaml is vulnerable
because `github.event.comment.body` and `github.event.issue.labels.*.name` are
interpolated directly inside `run:` steps, allowing shell/template injection
from untrusted commenters. Update the `Debug auth info` and `Test condition
parts` steps to pass these values through `env:` and read them as shell
variables inside the script instead of embedding expressions inline, and keep
the logic in the existing workflow job names/steps. Also add a restrictive `if:`
gate similar to the `triage` job’s actor checks, and define an explicit minimal
`permissions:` block for the job.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9a90c349-e031-4cf5-b67d-25de414bdc87

📥 Commits

Reviewing files that changed from the base of the PR and between 3c89cf9 and f1d0ecd.

📒 Files selected for processing (7)
  • .github/sync.yml
  • .github/workflows/WORKFLOWS.md
  • .github/workflows/opencode-implement.yaml
  • .github/workflows/opencode-new-pr.yaml
  • .github/workflows/opencode-triage-issue.yaml
  • AGENTS.md
  • config/workflow-task-map.yaml

Comment on lines +28 to +31
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
persist-credentials: false

@coderabbitaicoderabbitaiBotJul 7, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
file=".github/workflows/opencode-new-pr.yaml"
wc -l "$file"
sed -n '1,170p'"$file"| cat -n

Repository: dianlight/opencode-actions

Length of output: 8130


Re-enable git auth before the branch push.persist-credentials: false removes checkout’s git credentials, so git push origin "$BRANCH" will fail unless git is configured to use GITHUB_TOKEN first.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/opencode-new-pr.yaml around lines 28 - 31, The checkout
step in the workflow is clearing git credentials, so the later branch push will
fail. Update the job around the Checkout repository step and the push logic that
uses git push origin "$BRANCH" to restore authentication first by configuring
git to use GITHUB_TOKEN before pushing, or otherwise ensure credentials are
available when the push runs.

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/oc In @.github/workflows/opencode-new-pr.yaml around lines 28 - 31, The checkout
step in the workflow is clearing git credentials, so the later branch push will
fail. Update the job around the Checkout repository step and the push logic that
uses git push origin "$BRANCH" to restore authentication first by configuring
git to use GITHUB_TOKEN before pushing, or otherwise ensure credentials are
available when the push runs.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
file=".github/workflows/opencode-new-pr.yaml"
sed -n '1,132p'"$file"| cat -n

Length of output: 6368


Now I have the exact context needed to plan the fix.

@dianlight, here's the fix — since persist-credentials: false strips the checkout action's git credentials, we need to explicitly authenticate git before pushing. I'll configure the origin remote to use GH_TOKEN via an x-access-token credential right before the push in the "Create branch and pull request" step.

  • Add GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} (already present) and set git remote URL with token-based auth before git push in .github/workflows/opencode-new-pr.yaml.

This sets the origin remote URL to include an x-access-token credential derived from GH_TOKEN immediately before the push, so git push succeeds even though checkout didn't persist credentials. gh CLI calls elsewhere already work fine since they use GH_TOKEN directly and don't depend on git's credential store.


Failed to handle agent chat message. Please try again.

Comment on lines +76 to +104
- name: Create or update CHANGELOG.md
env:
ISSUE_NUMBER: ${{ github.event.inputs.issue-number }}
ISSUE_TITLE: ${{ steps.extract-tasks.outputs.issue-title }}
TASKS: ${{ steps.extract-tasks.outputs.task-list }}
run: |
python3 -c '
import json, os
changelog_path = "CHANGELOG.md"
issue_number = os.environ["ISSUE_NUMBER"]
issue_title = os.environ["ISSUE_TITLE"]
tasks = json.loads(os.environ.get("TASKS", "[]"))
entry = f"## [#{issue_number}] - {issue_title}\n\n### Added\n"
for task in tasks:
entry += f"- {task}\n"
entry += "\n"
if os.path.exists(changelog_path):
with open(changelog_path) as f:
content = f.read()
content = entry + content
else:
content = f"# Changelog\n\n{entry}"
with open(changelog_path, "w") as f:
f.write(content)
'
git config user.name "opencode-agent[bot]"
git config user.email "opencode-agent[bot]@users.noreply.github.com"
git add CHANGELOG.md
git commit -m "docs: add changelog entry for issue #$ISSUE_NUMBER" || echo "No changes to commit"

@coderabbitaicoderabbitaiBotJul 7, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

CHANGELOG creation should use the OpenCode API key, per guidelines.

This step builds and commits CHANGELOG.md directly with a Python heredoc and git, without invoking OpenCode. The repository guideline requires opencode-new-pr.yaml to use GITHUB_TOKEN for API calls (satisfied elsewhere) and an OpenCode API key for CHANGELOG creation. Please route the CHANGELOG generation through the OpenCode action with OPENCODE_API_KEY.

As per coding guidelines: "opencode-new-pr.yaml must use GITHUB_TOKEN for API calls and an OpenCode API key for CHANGELOG creation."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/opencode-new-pr.yaml around lines 76 - 104, The CHANGELOG
generation step currently writes and commits the file directly via inline Python
and git in the opencode-new-pr workflow, but it needs to be routed through
OpenCode using the OpenCode API key. Update the workflow step that creates or
updates CHANGELOG.md so it invokes the OpenCode action/command with
OPENCODE_API_KEY for changelog creation instead of doing the file generation
locally, while keeping GITHUB_TOKEN usage limited to the existing API call
steps. Reference the “Create or update CHANGELOG.md” step in
opencode-new-pr.yaml when making the change.

Source: Coding guidelines

Copy link
Copy Markdown
OwnerAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/oc follow suggestion

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
fd . .github/workflows -e yaml -e yml
echo"---implement---"
cat -n .github/workflows/opencode-implement.yaml
echo"---triage---"
cat -n .github/workflows/opencode-triage-issue.yaml
echo"---new-pr---"
cat -n .github/workflows/opencode-new-pr.yaml

Length of output: 25631


@dianlight, sure — here's the update to route CHANGELOG generation through the OpenCode action with OPENCODE_API_KEY, following the same pattern used in opencode-implement.yaml and opencode-triage-issue.yaml.

  • Replace the raw Python/git "Create or update CHANGELOG.md" step in .github/workflows/opencode-new-pr.yaml with an anomalyco/opencode/github action step that uses OPENCODE_API_KEY, instructing it to create/update the file and commit+push directly to the current branch.

Let me know if you'd like the model value aligned with a different one used elsewhere, or if you'd prefer the entry-dedup check omitted for simplicity.


  • 📌 Commit the changes to this branch

Comment on lines +106 to +127
- name: Create branch and pull request
id: create-pr
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
ISSUE_NUMBER="${{ github.event.inputs.issue-number }}"
ISSUE_TITLE="${{ steps.extract-tasks.outputs.issue-title }}"
TASKS='${{ steps.extract-tasks.outputs.task-list }}'
DEFAULT_BRANCH=$(gh repo view --json defaultBranch -q '.defaultBranch')
SAFE_TITLE=$(echo "$ISSUE_TITLE" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//' | head -c 30)
BRANCH="opencode/issue-${ISSUE_NUMBER}-${SAFE_TITLE}"
git checkout -b "$BRANCH"
git push origin "$BRANCH" 2>/dev/null || git push -u origin "$BRANCH"
PR_BODY="Closes #${ISSUE_NUMBER}\n\n## Description\n\n${ISSUE_TITLE}\n\n## Tasks\n"
while IFS= read -r task; do
PR_BODY="${PR_BODY}\n- [ ] ${task}"
done <<< "$(echo "$TASKS" | jq -r '.[]')"
PR_URL=$(gh pr create \
--base "$DEFAULT_BRANCH" \
--head "$BRANCH" \
--title "feat: implement #${ISSUE_NUMBER} - ${ISSUE_TITLE}" \
--body "$(echo -e "$PR_BODY")")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
# Locate the workflow and inspect the relevant sections.
git ls-files .github/workflows/opencode-new-pr.yaml
wc -l .github/workflows/opencode-new-pr.yaml
cat -n .github/workflows/opencode-new-pr.yaml | sed -n '1,220p'# Pull just the referenced areas for easier review.printf'\n--- around lines 30-45 ---\n'
cat -n .github/workflows/opencode-new-pr.yaml | sed -n '30,45p'printf'\n--- around lines 100-130 ---\n'
cat -n .github/workflows/opencode-new-pr.yaml | sed -n '100,130p'printf'\n--- around lines 140-155 ---\n'
cat -n .github/workflows/opencode-new-pr.yaml | sed -n '140,155p'

Repository: dianlight/opencode-actions

Length of output: 12492


Critical: move workflow inputs/outputs out of run:
github.event.inputs.issue-number, steps.extract-tasks.outputs.issue-title, and steps.extract-tasks.outputs.task-list are expanded before the shell runs, so a crafted issue title or task body can break out of the assignment and execute commands on the runner. Pass them through env: in this step and the matching extract-tasks/execute-tasks assignments.

🧰 Tools
🪛 zizmor (1.26.1)

[error] 111-111: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[info] 112-112: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[info] 113-113: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/opencode-new-pr.yaml around lines 106 - 127, The Create
branch and pull request workflow step is interpolating
github.event.inputs.issue-number and the extract-tasks outputs directly inside
run:, which can allow shell injection before the script executes. Move
ISSUE_NUMBER, ISSUE_TITLE, and TASKS into env: for this step and update the
matching extract-tasks and execute-tasks assignments to read from environment
variables instead of inline expressions.

Source: Linters/SAST tools

Comment on lines +141 to +157
- name: Execute each task sequentially
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
PR_NUMBER="${{ needs.create-pr.outputs.pr-number }}"
TASKS='${{ needs.create-pr.outputs.task-list }}'
REF="${{ github.ref_name }}"
echo "$TASKS" | jq -r '.[]' | while IFS= read -r task; do
echo ""
echo "=========================================="
echo "=== Implementing: $task ==="
echo "=========================================="
BEFORE=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
gh workflow run opencode-implement.yaml \
--ref "$REF" \
-f pull-request-number="$PR_NUMBER" \
-f "task-description=$task"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
git ls-files .github/workflows/opencode-new-pr.yaml
wc -l .github/workflows/opencode-new-pr.yaml
cat -n .github/workflows/opencode-new-pr.yaml | sed -n '120,190p'

Repository: dianlight/opencode-actions

Length of output: 3538


🏁 Script executed:

#!/bin/bashset -euo pipefail
cat -n .github/workflows/opencode-new-pr.yaml | sed -n '1,140p'

Repository: dianlight/opencode-actions

Length of output: 6573


🏁 Script executed:

python3 - <<'PY'import json, subprocess, textwrap, shlex, os, tempfile, pathlibtasks = json.dumps(["Bob's fix"])script = f"""#!/bin/bashset -eTASKS='{tasks}'echo "$TASKS""""print("SCRIPT:")print(script)p = subprocess.run(["bash", "-lc", script], capture_output=True, text=True)print("RETURN:", p.returncode)print("STDOUT:", p.stdout)print("STDERR:", p.stderr)PY

Repository: dianlight/opencode-actions

Length of output: 419


Move the workflow outputs out of the shell literal
TASKS comes from issue-comment text, and a task containing ' can break the TASKS='…' assignment and inject shell syntax. Pass needs.create-pr.outputs.* and github.ref_name via env: instead, then read them as shell variables.

🧰 Tools
🪛 zizmor (1.26.1)

[info] 145-145: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[info] 146-146: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 147-147: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/opencode-new-pr.yaml around lines 141 - 157, The
sequential task runner in the workflow is embedding untrusted workflow outputs
directly inside shell literals, which can break the script if a task contains
quotes. Move the values sourced from needs.create-pr.outputs.task-list,
needs.create-pr.outputs.pr-number, and github.ref_name into env variables on the
step, then read those shell variables inside the run block instead of assigning
them with inline expansion.

Comment on lines +13 to +32
runs-on: ubuntu-latest
steps:
- name: Debug auth info
run: |
echo "Comment user: ${{ github.event.comment.user.login }}"
echo "Author association: ${{ github.event.comment.author_association }}"
echo "Issue state: ${{ github.event.issue.state }}"
echo "Comment body: ${{ github.event.comment.body }}"
echo "Body length: ${{ github.event.comment.body.length }}"
echo "Contains /oc: $(echo '${{ github.event.comment.body }}' | grep -E '(^| )/oc' && echo 'yes' || echo 'no')"
echo "Has awaiting-response label: $(echo '${{ github.event.issue.labels.*.name }}' | grep -c 'opencode:awaiting-response' || echo '0')"

- name: Test condition parts
run: |
body_contains_oc=false
if echo "${{ github.event.comment.body }}" | grep -qE "(^/oc|^ /oc)"; then
body_contains_oc=true
fi
echo "Body starts/contains /oc: $body_contains_oc"
echo "Body length > 10: $([ ${#'${{ github.event.comment.body }}'} -gt 10 ] && echo 'yes' || echo 'no')"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Script injection via unsanitized github.event.comment.body in debug job.

Both steps interpolate ${{ github.event.comment.body }} (and github.event.issue.labels.*.name) directly into run: blocks. Since this job has no if: gate restricting triggering actors (unlike the triage job below, which checks author_association), any commenter can inject arbitrary shell via the comment body, leading to RCE on the runner / secret exfiltration. Flagged by actionlint and zizmor as template-injection. The job also has no permissions: block, so it inherits default (possibly broad) permissions — flagged by zizmor as excessive-permissions.

🔒️ Proposed fix using env-var indirection
 debug:
runs-on: ubuntu-latest
+ permissions: {}
steps:
- name: Debug auth info
+ env:+ COMMENT_BODY: ${{ github.event.comment.body }}+ COMMENT_USER: ${{ github.event.comment.user.login }}+ AUTHOR_ASSOCIATION: ${{ github.event.comment.author_association }}+ ISSUE_STATE: ${{ github.event.issue.state }}+ ISSUE_LABELS: ${{ toJSON(github.event.issue.labels.*.name) }}
run: |
- echo "Comment user: ${{ github.event.comment.user.login }}"- echo "Author association: ${{ github.event.comment.author_association }}"- echo "Issue state: ${{ github.event.issue.state }}"- echo "Comment body: ${{ github.event.comment.body }}"- echo "Body length: ${{ github.event.comment.body.length }}"- echo "Contains /oc: $(echo '${{ github.event.comment.body }}' | grep -E '(^| )/oc' && echo 'yes' || echo 'no')"- echo "Has awaiting-response label: $(echo '${{ github.event.issue.labels.*.name }}' | grep -c 'opencode:awaiting-response' || echo '0')"+ echo "Comment user: $COMMENT_USER"+ echo "Author association: $AUTHOR_ASSOCIATION"+ echo "Issue state: $ISSUE_STATE"+ echo "Comment body: $COMMENT_BODY"+ echo "Body length: ${`#COMMENT_BODY`}"+ echo "Contains /oc: $(echo "$COMMENT_BODY" | grep -E '(^| )/oc' && echo 'yes' || echo 'no')"+ echo "Has awaiting-response label: $(echo "$ISSUE_LABELS" | grep -c 'opencode:awaiting-response' || echo '0')"
- name: Test condition parts
+ env:+ COMMENT_BODY: ${{ github.event.comment.body }}
run: |
body_contains_oc=false
- if echo "${{ github.event.comment.body }}" | grep -qE "(^/oc|^ /oc)"; then+ if echo "$COMMENT_BODY" | grep -qE "(^/oc|^ /oc)"; then
body_contains_oc=true
fi
echo "Body starts/contains /oc: $body_contains_oc"
- echo "Body length > 10: $([ ${#'${{ github.event.comment.body }}'} -gt 10 ] && echo 'yes' || echo 'no')"+ echo "Body length > 10: $([ ${`#COMMENT_BODY`} -gt 10 ] && echo 'yes' || echo 'no')"
📝 Committable suggestion

‼️IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
runs-on: ubuntu-latest
steps:
- name: Debug auth info
run: |
echo "Comment user: ${{ github.event.comment.user.login }}"
echo "Author association: ${{ github.event.comment.author_association }}"
echo "Issue state: ${{ github.event.issue.state }}"
echo "Comment body: ${{ github.event.comment.body }}"
echo "Body length: ${{ github.event.comment.body.length }}"
echo "Contains /oc: $(echo '${{ github.event.comment.body }}' | grep -E '(^| )/oc' && echo 'yes' || echo 'no')"
echo "Has awaiting-response label: $(echo '${{ github.event.issue.labels.*.name }}' | grep -c 'opencode:awaiting-response' || echo '0')"
- name: Test condition parts
run: |
body_contains_oc=false
if echo "${{ github.event.comment.body }}" | grep -qE "(^/oc|^ /oc)"; then
body_contains_oc=true
fi
echo "Body starts/contains /oc: $body_contains_oc"
echo "Body length > 10: $([ ${#'${{ github.event.comment.body }}'} -gt 10 ] && echo 'yes' || echo 'no')"
runs-on: ubuntu-latest
permissions: {}
steps:
- name: Debug auth info
env:
COMMENT_BODY: ${{ github.event.comment.body }}
COMMENT_USER: ${{ github.event.comment.user.login }}
AUTHOR_ASSOCIATION: ${{ github.event.comment.author_association }}
ISSUE_STATE: ${{ github.event.issue.state }}
ISSUE_LABELS: ${{ toJSON(github.event.issue.labels.*.name) }}
run: |
echo "Comment user: $COMMENT_USER"
echo "Author association: $AUTHOR_ASSOCIATION"
echo "Issue state: $ISSUE_STATE"
echo "Comment body: $COMMENT_BODY"
echo "Body length: ${`#COMMENT_BODY`}"
echo "Contains /oc: $(echo "$COMMENT_BODY" | grep -E '(^| )/oc' && echo 'yes' || echo 'no')"
echo "Has awaiting-response label: $(echo "$ISSUE_LABELS" | grep -c 'opencode:awaiting-response' || echo '0')"
- name: Test condition parts
env:
COMMENT_BODY: ${{ github.event.comment.body }}
run: |
body_contains_oc=false
if echo "$COMMENT_BODY" | grep -qE "(^/oc|^ /oc)"; then
body_contains_oc=true
fi
echo "Body starts/contains /oc: $body_contains_oc"
echo "Body length > 10: $([ ${`#COMMENT_BODY`} -gt 10 ] && echo 'yes' || echo 'no')"
🧰 Tools
🪛 actionlint (1.7.12)

[error] 16-16: "github.event.comment.body" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details

(expression)


[error] 26-26: "github.event.comment.body" is potentially untrusted. avoid using it directly in inline scripts. instead, pass it through an environment variable. see https://docs.github.com/en/actions/reference/security/secure-use#good-practices-for-mitigating-script-injection-attacks for more details

(expression)

🪛 zizmor (1.26.1)

[warning] 12-32: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block

(excessive-permissions)


[error] 17-17: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 20-20: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 21-21: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 22-22: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 23-23: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 28-28: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)


[error] 32-32: code injection via template expansion (template-injection): may expand into attacker-controllable code

(template-injection)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.github/workflows/opencode-triage-issue.yaml around lines 13 - 32, The debug
job in opencode-triage-issue.yaml is vulnerable because
`github.event.comment.body` and `github.event.issue.labels.*.name` are
interpolated directly inside `run:` steps, allowing shell/template injection
from untrusted commenters. Update the `Debug auth info` and `Test condition
parts` steps to pass these values through `env:` and read them as shell
variables inside the script instead of embedding expressions inline, and keep
the logic in the existing workflow job names/steps. Also add a restrictive `if:`
gate similar to the `triage` job’s actor checks, and define an explicit minimal
`permissions:` block for the job.

Source: Linters/SAST tools

dianlightand others added 2 commits July 8, 2026 14:56
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: Changes requested

🚨 1 (new) · 10 open threads from prior reviews remain unaddressed

Most critical: The race-condition fix for the workflow-dispatch polling loop was applied without removing the old loop, leaving a for without a matching done (opencode-new-pr.yaml:160). The script will fail with a shell syntax error at runtime, blocking all sequential task execution. 10 prior threads (shell injection vectors in run: blocks, git push error suppression, commit error masking, PR body construction, branch truncation, AGENTS.md inaccuracy, missing git auth, CHANGELOG routing, triage debug injection) remain open.

-f "$(echo "$task" | jq -R -s 'sub("\n$";"") | @json' | jq -r '"task-description=" + .') "
echo "Dispatched. Waiting for the run to appear..."
RUN_ID=""
for i in $(seq 1 20); do

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 [CRITICAL] Missing done — duplicate polling loops create a shell syntax error

The original 20-iteration polling loop (line 160) was replaced with a 100-iteration loop (line 172) to fix a race condition, but the old loop was never removed and its closing done is missing. The result is an unclosed for at line 160 that produces a bash syntax error at runtime, causing the entire execute-tasks job to fail before any task runs.

Suggested change
for i in $(seq 1 20); do
for i in $(seq 1 100); do
sleep 3
RUN_ID=$(gh run list \
--workflow=opencode-implement.yaml \
--limit 20 \
--json databaseId,createdAt \
-q "[.[] | select(.createdAt >= \"$BEFORE\")] | .[0].databaseId // empty" \
2>/dev/null)
if [ -n "$RUN_ID" ]; then
echo "Found run: $RUN_ID"
break
fi
done

(Replace lines 158–184 with just the single 100-iteration loop above.)

@github-actions

Copy link
Copy Markdown
Contributor

Review submitted. Summary of actions:

  • Resolved threads: None needed — 2 threads were already resolved (shell injection fix at line 157, race condition fix at line 184). The remaining 10 threads are still open and not visibly fixed in the current diff.

  • New finding (🚨 CRITICAL): opencode-new-pr.yaml:160-184 — the race-condition fix was applied without removing the original 20-iteration loop, leaving a for without its closing done. This creates a bash syntax error that will crash the execute-tasks job at runtime.

  • Event: REQUEST_CHANGES — the missing done alone blocks the entire sequential task execution pipeline.

New%20session%20-%202026-07-08T12%3A56%3A28.884Z
opencode session | github run

@github-actionsgithub-actionsBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verdict: Changes requested

🚨 2 · 🛠️ 1

No threads resolved — 0 of 7 open threads have fixes in the current diff.

Most critical: The old 20-iteration polling loop (line 183) was never removed when the 100-iteration loop was stacked on top, leaving a for without a done — a shell syntax error that kills execute-tasks. Separately, the old \n-based PR body code (lines 126–134) was left alongside the replacement, creating a broken gh pr create with unterminated $(...) that crashes create-pr.

Prior review threads about shell injection vectors in run: blocks, missing git auth, CHANGELOG routing, triage debug injection, and AGENTS.md inaccuracy remain open.

-f "$(echo "$task" | jq -R -s 'sub("\n$";"") | @json' | jq -r '"task-description=" + .') "
echo "Dispatched. Waiting for the run to appear..."
RUN_ID=""
for i in $(seq 1 20); do

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 [CRITICAL] Missing done — orphaned for from incomplete race-condition fix

The old 20-iteration polling loop (line 183) was meant to be replaced by the 100-iteration loop (line 195). Instead of being removed, the old for was left without a closing done. The done at line 207 closes only the 100-iteration loop, so the first for is unclosed — a bash syntax error that will crash the entire execute-tasks job at runtime.

Suggested change
for i in $(seq 1 20); do
RUN_ID=""
for i in $(seq 1 100); do
sleep 3
RUN_ID=$(gh run list \
--workflow=opencode-implement.yaml \
--limit 20 \
--json databaseId,createdAt \
-q "[.[] | select(.createdAt >= \"$BEFORE\")] | .[0].databaseId // empty" \
2>/dev/null)
if [ -n "$RUN_ID" ]; then
echo "Found run: $RUN_ID"
break
fi
done

(Replace lines 182–207 with the single loop above.)

BRANCH="opencode/issue-${ISSUE_NUMBER}-${SAFE_TITLE}"
git checkout -b "$BRANCH"
git push -u origin "$BRANCH"
PR_BODY="Closes #${ISSUE_NUMBER}\n\n## Description\n\n${ISSUE_TITLE}\n\n## Tasks\n"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚨 [CRITICAL] Duplicate/incomplete PR creation code — shell parse error

Lines 126–134 contain leftover code from the \n-based PR body approach (thread #5). The \ continuation at line 133 joins with line 134 (PR_BODY="Closes #...), but the " opens a multi-line string that swallows lines 135–141 while $(...) is never closed with ). The replacement code at lines 134–150 correctly builds and creates the PR. The dead code at lines 126–134 must be removed.

Suggested change
PR_BODY="Closes #${ISSUE_NUMBER}\n\n## Description\n\n${ISSUE_TITLE}\n\n## Tasks\n"
DEFAULT_BRANCH=$(gh repo view --json defaultBranch -q '.defaultBranch')
SAFE_TITLE=$(echo "$ISSUE_TITLE" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//' | head -c 60)
BRANCH="opencode/issue-${ISSUE_NUMBER}-${SAFE_TITLE}"
git checkout -b "$BRANCH"
git push -u origin "$BRANCH"
PR_BODY="Closes #${ISSUE_NUMBER}

(Remove the old \n-based block, keeping the actual-newline version.)

- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
persist-credentials: false

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ [QUALITY] Missing git auth — push will fail (thread already open)

persist-credentials: false at line 31 disables the checkout action's credential helper. git push -u origin "$BRANCH" at line 125 will fail because no auth mechanism is configured. Add the token-based remote URL before the push, or set persist-credentials: true.

Suggested change
persist-credentials: false
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
persist-credentials: false
token: ${{ secrets.GITHUB_TOKEN }}

@github-actions

Copy link
Copy Markdown
Contributor

Review submitted. Summary:

Event: REQUEST_CHANGES — 2 CRITICAL, 1 QUALITY findings.

No threads resolved — all 7 open threads remain unaddressed in the current diff.

Findings:

  1. 🚨 Missing done (opencode-new-pr.yaml:183) — the old 20-iteration polling loop was left done-less when the 100-iteration fix was stacked on top. Shell syntax error crashes execute-tasks.
  2. 🚨 Duplicate PR creation code (opencode-new-pr.yaml:126–134) — the old \n-based PR_BODY code was never removed after the actual-newline version was added. The \ continuation creates an unterminated $(...) that crashes create-pr.
  3. 🛠️ Missing git auth (opencode-new-pr.yaml:31,125) — persist-credentials: false with no credential setup means git push will fail (previously reported, still unfixed).

New%20session%20-%202026-07-08T12%3A58%3A26.093Z
opencode session | github run

@dianlight

Copy link
Copy Markdown
OwnerAuthor

dead end

@dianlight
dianlight deleted the refactor/new_implemet_workflow branch July 11, 2026 09:49
Sign up for freeto 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

@dianlight