Skip to content

ci: add Qwen3.6-Plus PR review (static + opencode)#445

Open
arthrod wants to merge 7 commits into
mainfrom
ci/qwen-review
Open

ci: add Qwen3.6-Plus PR review (static + opencode)#445
arthrod wants to merge 7 commits into
mainfrom
ci/qwen-review

Conversation

@arthrod
Copy link
Copy Markdown
Collaborator

@arthrod arthrod commented May 30, 2026

User description

Self-hosted PR reviewer (Qwen3.6 Plus via Bailian). static job is advisory; opencode job runs independently. 🤖 Generated with Claude Code


PR Type

Enhancement


Description

  • Add self-hosted PR review workflow using Qwen3.6 Plus LLM

  • Implement independent static analysis job (Python/TS/Rust)

  • Configure opencode integration with Alibaba Bailian API

  • Enable concurrent PR reviews with automatic cancellation


Diagram Walkthrough

flowchart LR
  PR["Pull Request<br/>opened/sync/reopened"] --> STATIC["Static Analysis Job<br/>ruff/biome/cargo"]
  PR --> OPENCODE["OpenCode Job<br/>Qwen3.6 Plus Review"]
  STATIC --> REPORT["Advisory Report<br/>never blocks"]
  OPENCODE --> COMMENT["PR Comment<br/>grouped by severity"]
Loading

File Walkthrough

Relevant files
Configuration changes
qwen-review.yml
GitHub Actions workflow for Qwen3.6 PR review                       

.github/workflows/qwen-review.yml

  • Defines two independent CI jobs: static analysis and LLM review
  • Static job runs Python (ruff), TypeScript (biome/tsc), and Rust
    (cargo) checks with advisory-only reporting
  • OpenCode job executes Qwen3.6 Plus review via Alibaba Bailian API with
    structured prompt
  • Implements concurrency control to cancel in-progress reviews for same
    PR
  • Skips review for draft PRs and uses GitHub token for authentication
+116/-0 
opencode.json
OpenCode provider configuration for DashScope                       

opencode.json

  • Configures DashScope provider with Alibaba Bailian Coding Plan
    endpoint
  • Maps Qwen3.6 Plus model with OpenAI-compatible API interface
  • Sets up environment variable injection for API key management
  • Provides schema reference for opencode configuration validation
+18/-0   

Summary by Sourcery

Add a self-hosted pull request review workflow that runs advisory static analysis and an independent Qwen3.6 Plus LLM-based review via Alibaba Bailian through opencode.

Enhancements:

  • Introduce a static analysis CI job for Python, TypeScript/JavaScript, and Rust that reports issues without blocking merges.
  • Configure an opencode-based CI job that uses the Qwen3.6 Plus model to post structured PR review comments and skips draft PRs.
  • Enable concurrency control so that only the latest PR review run remains active for a given pull request.

CI:

  • Add a qwen-review GitHub Actions workflow with separate static and LLM review jobs triggered on pull request events.
  • Add opencode.json configuration to integrate with Alibaba Bailian DashScope using an OpenAI-compatible interface and secret-managed API keys.

arthrod and others added 7 commits May 4, 2026 23:57
…lay) (#357)

* feat(pagination): scaffold @platejs/pagination variant A (render-overlay) — refs #353

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(template): add OpenNext deploy + pagination toolbar button placeholder

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(pagination): apply inspector + CR feedback — refs #357

- move base bundle (header, footer, page break) to BasePaginationPlugin.plugins (Slate base)
- BasePaginationConfig key uses typeof KEYS.pagination
- drop degenerate <_V> generic on BasePaginationOptions
- add includeFootnoteSubPlugins option (default true) — opt-out for footnote coupling
- usePretextMeasurer uses useState so future ready flip re-renders
- drop @chenglou/pretext from dependencies until measurer lands

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(template): CR feedback — refs #365

- lint script: add explicit `eslint .` target
- lint:fix: chain `eslint . --fix` after biome
- pagination-toolbar-button: drop internal #357/#358 PR refs from user-facing toast

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(pagination): implement variant A — paginate, measurer, overlay, footnotes — refs #353 #357

Replace TODO stubs with full variant A:
- paginate(): bin-pack with manual page-break, oversized-block, header/footer/footnote-def exclusion
- allocateFootnotes(): per-page allocation by reference walk
- DOM-backed measurer with bounded LRU cache keyed by (nodeId, marksFingerprint, font, width)
- usePageLayout, PageOverlay (afterEditable, pointer-events: none), PageFrame chrome
- FootnotePortal hides in-flow definitions via injected CSS
- Editor API: getPages, getPageOf, getFootnotes
- Editor transforms: insertPageBreak, setHeader, setFooter
- 9 unit tests passing

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(template): wire real @platejs/pagination via vendored dist — refs #357 #365

Drop placeholder pagination kit. Vendor @platejs/pagination's built dist
under templates/plate-playground-template/vendor/platejs-pagination so the
template can consume the real plugin without npm publish:
- pagination-kit: PaginationPlugin.configure({ A4, 96px margins, 48 header/footer, 96 footnote well })
- pagination-toolbar-button: clicks editor.tf.pagination.insertPageBreak()
- vendor/.gitignore overrides repo **/dist so committed artifacts ship

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(pagination): visible page panel + resilient toolbar — refs #357 #365

PageOverlay: replace overlay-on-editor (z-index conflict, white-on-white)
with a fixed top-right card showing "Pages: N" plus PageFrame thumbnails.
Always visible regardless of editor theme.

Toolbar button: try editor.tf.pagination.insertPageBreak() first; fall back
to editor.tf.insertNodes({type:'pageBreak'}) so the action works even when
the plugin's transforms aren't bound (e.g. during HMR or kit ordering).
Drop the "plugin not loaded" toast.

Refresh vendored dist.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(pagination): KEYS resolution + reactive overlay + toggle preview — refs #353 #357 #365

Two bugs uncovered via dogfooding the deploy:

1. Plugin silently dropped from editor: source referenced KEYS.pagination
   and KEYS.pageBreak; both undefined in published platejs@53.0.3 → key
   resolved to undefined → editor filtered the plugin out. Fixed by
   replacing with local PAGINATION_KEY / PAGE_BREAK_KEY / etc. constants
   in lib/internal/keys.ts.

2. Overlay never re-rendered on edits: useEditorRef + useMemo([editor.children])
   misses Slate in-place mutations. Switched to useEditorValue +
   usePluginOption.

Also:
- previewVisible option + togglePreview() transform; toolbar button now
  toggles the side panel instead of inserting a break.
- PageFrame now renders mini-content per block (h1-h6 / blockquote / code /
  paragraph) so the preview is content-aware, not just empty page chrome.
- Refresh vendored dist + .gitignore dogfood-output.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(pagination): page config + header/footer toggles + settings dropdown — refs #357

Adds the next layer per the CR plan + agreed roadmap:

Plugin (lib):
- PageSize: union of preset key | { width, height } literal — registry escape hatch
- BasePaginationOptions: + headerVisible, footerVisible (defaults false)
- BasePaginationTransforms: + setPageSize, setMargins, toggleHeader, toggleFooter
- toggleHeader/toggleFooter inserts a top-level header/footer block at index 0 / N
  with placeholder text ("Header" / "Footer") and flips the visibility option;
  removeByType dedupes if normalization produced duplicates
- resolvePageSize handles both preset and literal forms; resolvePageRect clamps
  contentHeight/contentWidth to >= 0

Overlay (react):
- usePluginOption subscribes to pageSize, margins, headerVisible, footerVisible
  so the panel re-renders when any of them changes via toggle/setMargins/etc.

Template:
- pagination-toolbar-button: replaces the single click handler with a Radix
  DropdownMenu — sections for Display (preview/header/footer toggles), Page
  size (A4/Letter/Legal radio), Margins (narrow/default/wide presets)
- vendor:pagination script — copies packages/pagination/dist into the template's
  vendored package; addresses CR's "Vendored dist refresh" follow-up

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(pagination): apply CR/Gemini review — derived header/footer, normalizeNode, content cache, pt scaling — refs #357

Implements the agreed subset of the CR plan-conejo (comment 11) and the
Gemini + CR review feedback:

Architecture:
- Move page-state.ts from react/internal/ to lib/internal/ so the base
  Slate plugin's API can read pages without depending on React. Keeps
  imports flowing lib → react, never the other way.

Header/footer model:
- Drop headerVisible / footerVisible options. Derive presence from the
  doc itself (editor.children.some(n => n.type === HEADER_KEY)). Removes
  the option-vs-Slate-history asymmetry CR risk-flagged: undo of a
  toggleHeader call now correctly restores the header without leaving a
  stale option flag.
- Add api.pagination.hasHeader / hasFooter for consumers that don't want
  to walk children themselves.
- Toolbar dropdown checkboxes derive state via useEditorValue + same scan.

Invariants:
- Add overrideEditor → normalizeNode that runs at root path:
  enforceHeaderFooterInvariants drops duplicate header/footer blocks and
  re-positions the survivor (header at [0], footer at last index). Defends
  against paste/undo producing duplicates.

Measurement correctness:
- MeasureCacheKey gains a contentHash field; usePretextMeasurer hashes
  type + plain text per node and feeds it in. Cache now invalidates on
  in-place edits (Gemini + CR concern).
- collectPlainText stops inserting a space between adjacent leaves —
  bold-then-plain runs ("He" + "llo") were measured as "He llo", over-
  counting line breaks. Fixed.
- scaleFont uses /(\d+)(px|pt)/ and re-emits the matched unit so pt-sized
  fonts scale correctly for headings.
- resolvePageRect clamps contentWidth/Height to ≥ 0 (already in place,
  preserved when accepting the new PageSize union).

UI:
- PageOverlay's THUMB_SCALE is now computed via computeThumbScale(width)
  = min(0.18, 196/pageWidth) — scales custom landscape page sizes down
  to the panel width.
- React keys for the page list use `page-${pageIndex}` (stable).

Cleanup:
- marks-fingerprint: rename `sorted` → `segments` (CR nitpick — name
  reflected traversal order, not sort).

Tests: 11 pass (added contentHash + hashString cases).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* 📝 CodeRabbit Chat: Implement requested code changes

* Update packages/pagination/src/static/page-break-element-static.tsx

Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>

* refactor(pagination): split helpers into queries/transforms; KEYS via getType; plugin spec

Apply footnote-plugin best practices to BasePaginationPlugin:
- Extract queries (lib/queries) and transforms (lib/transforms) modules.
- Move BasePaginationConfig/Api/Transforms types to lib/types.
- Use editor.getType(KEYS.x) so consumer .configure({ node: { type } }) overrides flow through.
- Fix enforceHeaderFooterInvariants stale-index bug (collect → sort desc → remove → re-scan → move).
- Add base-pagination-plugins.spec covering plugin schema, API/transforms surface, toggle/set/insert behavior, and normalize invariants.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
* fix(markdown): respect resourceLink for bare autolinks (udecode#4972)

* Version Packages (udecode#4975)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* chore: update

---------

Co-authored-by: Arnau Jiménez <arnau@ajb.cat>
Co-authored-by: Ziad Beyens <ziad.beyens@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* fix(markdown): respect resourceLink for bare autolinks (udecode#4972)

* Version Packages (udecode#4975)

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* chore: update

---------

Co-authored-by: Arnau Jiménez <arnau@ajb.cat>
Co-authored-by: Ziad Beyens <ziad.beyens@gmail.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Supply-chain defense: packages must be 7+ days old before install. Adds [test] root="./packages" in monorepos.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 30, 2026

Warning

Review limit reached

@arthrod, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 9 minutes and 34 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

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.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c9da3292-fb71-49ea-a279-3e5c0e3820fb

📥 Commits

Reviewing files that changed from the base of the PR and between 8a712e1 and a47eb63.

📒 Files selected for processing (2)
  • .github/workflows/qwen-review.yml
  • opencode.json
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ci/qwen-review

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

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented May 30, 2026

Code Review by Qodo

🐞 Bugs (8) 📘 Rule violations (1)

Context used
✅ Compliance rules (platform): 300 rules

Grey Divider


Action required

1. Static prompt in opencode 📘 Rule violation ⌂ Architecture
Description
The new GitHub Actions workflow configures an opencode LLM prompt as a hardcoded static string
with no injected runtime state. This violates the requirement that system prompts be dynamically
constructed with runtime application state, which can reduce review quality and cause
context-missing outputs.
Code

.github/workflows/qwen-review.yml[R110-116]

Evidence
PR Compliance ID 822364 requires system prompts to dynamically inject runtime state; the workflow
sets prompt: | to a fully static block with no ${{ ... }} interpolation or other runtime data
injection.

Rule 822364: System prompts must include runtime application state, not be purely static
.github/workflows/qwen-review.yml[110-116]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `opencode` prompt is currently a static string and does not inject any runtime context (e.g., PR title/body, changed files, or other run-specific state).

## Issue Context
Compliance requires that system prompts include dynamically injected runtime application state rather than being purely static.

## Fix Focus Areas
- .github/workflows/qwen-review.yml[110-116]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Excess workflow permissions 🐞 Bug ⛨ Security
Description
The workflow grants pull-requests: write (and issues: read) at the workflow level, so the
static job inherits write-capable credentials it never uses, increasing impact if any step/tool is
compromised. Only the opencode job appears to require PR write access for posting a review
comment.
Code

.github/workflows/qwen-review.yml[R13-16]

Evidence
The workflow-level permissions apply to all jobs, but the static job only checks out code and runs
linters and does not call GitHub APIs; the only step that appears to need elevated rights is the
opencode action that posts review comments.

.github/workflows/qwen-review.yml[13-16]
.github/workflows/qwen-review.yml[28-86]
.github/workflows/qwen-review.yml[101-109]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The workflow-level `permissions:` grants `pull-requests: write` and `issues: read` to *all* jobs. The `static` job does not need these permissions, so it should run with minimal read-only permissions and only the `opencode` job should be granted write access.

## Issue Context
- `static` runs checkout + local linters only.
- `opencode` posts a PR review comment (needs `pull-requests: write`).

## Fix Focus Areas
- .github/workflows/qwen-review.yml[13-16]
- .github/workflows/qwen-review.yml[28-86]
- .github/workflows/qwen-review.yml[91-109]

## Suggested change
- Reduce top-level permissions to the minimum (e.g. `contents: read`).
- Add job-level permissions:
 - `static`: `contents: read`
 - `opencode`: `contents: read`, `pull-requests: write` (and `issues: read` only if truly required by the action).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Unpinned opencode action 🐞 Bug ⛨ Security
Description
The workflow runs anomalyco/opencode/github@latest, so the code executed in CI can change without
review and has access to DASHSCOPE_API_KEY plus PR write permissions. This creates a supply-chain
risk where a compromised/changed upstream action could exfiltrate secrets and post arbitrary PR
comments.
Code

.github/workflows/qwen-review.yml[R101-105]

Evidence
The opencode step uses an unpinned @latest action while also injecting DASHSCOPE_API_KEY and
operating under a workflow permission set that allows writing PR comments, increasing the impact if
the action’s code changes unexpectedly or is compromised.

.github/workflows/qwen-review.yml[13-18]
.github/workflows/qwen-review.yml[101-106]
opencode.json[7-10]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`anomalyco/opencode/github@latest` is an unpinned third-party GitHub Action. Because this job also receives `DASHSCOPE_API_KEY` and has `pull-requests: write`, any upstream change/compromise can immediately impact all PR runs.

## Issue Context
This workflow is intended to run automatically on PRs and post a review comment. That requires secrets and write permissions, which increases the blast radius of unpinned actions.

## Fix Focus Areas
- .github/workflows/qwen-review.yml[101-109]

## Suggested change
- Replace `anomalyco/opencode/github@latest` with a pinned immutable ref (prefer a full commit SHA; alternatively a specific, reviewed release tag).
- (Optional hardening) Move permissions to job-level and grant the minimum needed for `opencode` only (e.g., keep `pull-requests: write` there; keep `contents: read`; avoid granting other permissions to `static`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

4. Masked static failures 🐞 Bug ◔ Observability ⭐ New
Description
The static job forces success via || true, so lint/typecheck/format failures (and even tool
crashes) never appear as failed steps and are easy to miss, weakening CI’s regression signal. This
can lead to type/lint/format debt accumulating because PR authors will see a green job even when
checks are failing.
Code

.github/workflows/qwen-review.yml[R45-53]

Evidence
Multiple static-analysis commands explicitly append || true, guaranteeing exit code 0 regardless
of actual lint/typecheck failures, so the job appears successful even when checks fail.

.github/workflows/qwen-review.yml[45-53]
.github/workflows/qwen-review.yml[58-67]
.github/workflows/qwen-review.yml[73-82]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The `static` job uses `|| true` to suppress non-zero exits, which makes failures invisible in the Actions UI (everything looks green).

### Issue Context
This workflow intends to be advisory (non-blocking), but it should still surface failures clearly.

### Fix Focus Areas
- .github/workflows/qwen-review.yml[45-85]

### Suggested fix
- Remove `|| true` from the tool invocations.
- Instead, set `continue-on-error: true` at the step level (or split into separate steps per tool with `continue-on-error: true`). This keeps the job non-blocking while still showing step-level failure state.
- Optionally add a short job summary (via `$GITHUB_STEP_SUMMARY`) so results are visible without digging into raw logs.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Tool version drift 🐞 Bug ☼ Reliability ⭐ New
Description
The workflow runs Biome and TypeScript via bunx without pinning versions, which can diverge from
the repo’s pinned toolchain and produce inconsistent results between CI and local pnpm scripts.
This can cause unexpected diagnostics (or missed ones) depending on what bunx resolves at runtime.
Code

.github/workflows/qwen-review.yml[R58-67]

Evidence
The workflow invokes bunx for Biome and TypeScript without specifying a version, while the
repository explicitly pins @biomejs/biome and typescript in package.json, demonstrating a
potential mismatch between CI and the repo’s declared toolchain.

.github/workflows/qwen-review.yml[58-67]
package.json[76-78]
package.json[151-151]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The workflow executes tooling using `bunx` without tying it to the repository’s pinned versions, which risks CI running different Biome/TypeScript versions than the project.

### Issue Context
The repo pins `@biomejs/biome` and `typescript` in `package.json`, but the workflow invokes them via `bunx` without versions.

### Fix Focus Areas
- .github/workflows/qwen-review.yml[58-67]
- package.json[76-78]
- package.json[151-151]

### Suggested fix
Choose one approach:
1) **Use pinned versions explicitly**
  - `bunx --bun @biomejs/biome@2.3.6 ci --diagnostic-level=error .`
  - `bunx --bun typescript@6.0.2 tsc --noEmit`
2) **Use the repo toolchain**
  - Install dependencies (pnpm/bun install) and run `pnpm lint` / `pnpm typecheck` (or equivalent) so CI uses exactly what the repo declares.

Either approach prevents time-dependent tool resolution and keeps CI aligned with the project’s expected versions.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Missing job timeouts 🐞 Bug ☼ Reliability
Description
Neither static nor opencode sets timeout-minutes, so hung network downloads (uv/bun) or a
stalled external review step can tie up runners for a long time and delay PR feedback. Add explicit
timeouts per job to bound worst-case runtime.
Code

.github/workflows/qwen-review.yml[R28-31]

Evidence
Both jobs are defined without any timeout, and they run steps that can block on external network
calls (package/tool fetching and an external review action).

.github/workflows/qwen-review.yml[28-31]
.github/workflows/qwen-review.yml[37-67]
.github/workflows/qwen-review.yml[91-105]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Jobs do not specify `timeout-minutes`, so intermittent hangs can consume runner time for an extended period and stall PR signal.

## Issue Context
This workflow includes multiple network-dependent operations (tool installs and an external action call), which can occasionally hang.

## Fix Focus Areas
- .github/workflows/qwen-review.yml[28-31]
- .github/workflows/qwen-review.yml[37-67]
- .github/workflows/qwen-review.yml[91-105]

## Suggested change
Add reasonable timeouts, e.g.:
- `static: timeout-minutes: 10` (or 15)
- `opencode: timeout-minutes: 20` (or 30)
Adjust based on observed runtimes.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (2)
7. Unneeded id-token permission 🐞 Bug ⛨ Security
Description
The workflow grants id-token: write but no job step uses OIDC; keeping it unnecessarily increases
privileges available to all steps. If any third-party action is compromised, it could mint OIDC
tokens and expand impact beyond this repo.
Code

.github/workflows/qwen-review.yml[R13-18]

Evidence
id-token: write is granted at the workflow level, but the defined steps are limited to checkout,
linters, and opencode execution and do not reference any OIDC-based authentication action or token
usage.

.github/workflows/qwen-review.yml[13-18]
.github/workflows/qwen-review.yml[23-116]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The workflow requests `id-token: write` even though no step uses GitHub OIDC.

## Issue Context
This workflow runs third-party actions and handles secrets; least-privilege permissions reduce blast radius.

## Fix Focus Areas
- .github/workflows/qwen-review.yml[13-18]

## Suggested change
- Remove `id-token: write` from `permissions:` (or set it only on a job that actually uses OIDC, if added later).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. No secret/fork guard 🐞 Bug ☼ Reliability
Description
The opencode job runs on all non-draft pull_request events but requires
secrets.DASHSCOPE_API_KEY; for fork PRs (or repos without that secret configured) this job will
fail and create noisy red checks. This is avoidable by skipping the job when the secret isn’t
available and/or when the PR comes from a fork.
Code

.github/workflows/qwen-review.yml[R94-105]

Evidence
The workflow triggers on pull_request and the only job-level guard checks draft status, yet the
opencode step unconditionally reads secrets.DASHSCOPE_API_KEY, so missing secrets will lead to
runtime failure.

.github/workflows/qwen-review.yml[9-12]
.github/workflows/qwen-review.yml[94-105]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`opencode` depends on `secrets.DASHSCOPE_API_KEY` but is triggered for `pull_request` events without checking whether the secret is available (common for fork PRs).

## Issue Context
On fork PRs, repository secrets are typically not provided to workflows, so the opencode step will run with an empty API key and fail.

## Fix Focus Areas
- .github/workflows/qwen-review.yml[9-12]
- .github/workflows/qwen-review.yml[91-105]

## Suggested change
Update the job `if:` to also require the secret and/or non-fork PRs, e.g.:
```yaml
if: >-
 ${
   {
     !github.event.pull_request.draft &&
     secrets.DASHSCOPE_API_KEY != '' &&
     github.event.pull_request.head.repo.full_name == github.repository
   }
 }
```
(Use whichever predicate matches your contribution model; at minimum guard on `secrets.DASHSCOPE_API_KEY != ''`.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments

9. Checkout version inconsistency 🐞 Bug ⚙ Maintainability
Description
This workflow uses actions/checkout@v6 while other workflows in the repo use
actions/checkout@v4, creating unnecessary version divergence that makes CI behavior harder to
reason about across workflows. Align the checkout major version (or document why this workflow
intentionally differs).
Code

.github/workflows/qwen-review.yml[R32-35]

Evidence
The new workflow references actions/checkout@v6, while existing workflows in the same repo use
actions/checkout@v4, indicating an inconsistent standard for this critical dependency.

.github/workflows/qwen-review.yml[32-36]
.github/workflows/qwen-review.yml[96-100]
.github/workflows/ci.yml[71-75]
.github/workflows/changeset-auto-release.yml[18-23]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`qwen-review.yml` uses a different major version of `actions/checkout` than the rest of the repository’s workflows, increasing maintenance overhead and making workflow behavior less consistent.

## Issue Context
Most workflows in this repo reference `actions/checkout@v4`.

## Fix Focus Areas
- .github/workflows/qwen-review.yml[32-36]
- .github/workflows/qwen-review.yml[96-100]
- .github/workflows/ci.yml[71-75]

## Suggested change
- Switch `actions/checkout@v6` to the repo-standard `actions/checkout@v4`, or
- Add a short comment explaining why v6 is required specifically here.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Previous review results

Review updated until commit a47eb63

Results up to commit a47eb63


🐞 Bugs (3) 📘 Rule violations (0) 📎 Requirement gaps (0)


Action required
1. Unpinned opencode action 🐞 Bug ⛨ Security
Description
The workflow runs anomalyco/opencode/github@latest, so the code executed in CI can change without
review and has access to DASHSCOPE_API_KEY plus PR write permissions. This creates a supply-chain
risk where a compromised/changed upstream action could exfiltrate secrets and post arbitrary PR
comments.
Code

.github/workflows/qwen-review.yml[R101-105]

Evidence
The opencode step uses an unpinned @latest action while also injecting DASHSCOPE_API_KEY and
operating under a workflow permission set that allows writing PR comments, increasing the impact if
the action’s code changes unexpectedly or is compromised.

.github/workflows/qwen-review.yml[13-18]
.github/workflows/qwen-review.yml[101-106]
opencode.json[7-10]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`anomalyco/opencode/github@latest` is an unpinned third-party GitHub Action. Because this job also receives `DASHSCOPE_API_KEY` and has `pull-requests: write`, any upstream change/compromise can immediately impact all PR runs.

## Issue Context
This workflow is intended to run automatically on PRs and post a review comment. That requires secrets and write permissions, which increases the blast radius of unpinned actions.

## Fix Focus Areas
- .github/workflows/qwen-review.yml[101-109]

## Suggested change
- Replace `anomalyco/opencode/github@latest` with a pinned immutable ref (prefer a full commit SHA; alternatively a specific, reviewed release tag).
- (Optional hardening) Move permissions to job-level and grant the minimum needed for `opencode` only (e.g., keep `pull-requests: write` there; keep `contents: read`; avoid granting other permissions to `static`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended
2. Unneeded id-token permission 🐞 Bug ⛨ Security
Description
The workflow grants id-token: write but no job step uses OIDC; keeping it unnecessarily increases
privileges available to all steps. If any third-party action is compromised, it could mint OIDC
tokens and expand impact beyond this repo.
Code

.github/workflows/qwen-review.yml[R13-18]

Evidence
id-token: write is granted at the workflow level, but the defined steps are limited to checkout,
linters, and opencode execution and do not reference any OIDC-based authentication action or token
usage.

.github/workflows/qwen-review.yml[13-18]
.github/workflows/qwen-review.yml[23-116]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The workflow requests `id-token: write` even though no step uses GitHub OIDC.

## Issue Context
This workflow runs third-party actions and handles secrets; least-privilege permissions reduce blast radius.

## Fix Focus Areas
- .github/workflows/qwen-review.yml[13-18]

## Suggested change
- Remove `id-token: write` from `permissions:` (or set it only on a job that actually uses OIDC, if added later).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. No secret/fork guard 🐞 Bug ☼ Reliability
Description
The opencode job runs on all non-draft pull_request events but requires
secrets.DASHSCOPE_API_KEY; for fork PRs (or repos without that secret configured) this job will
fail and create noisy red checks. This is avoidable by skipping the job when the secret isn’t
available and/or when the PR comes from a fork.
Code

.github/workflows/qwen-review.yml[R94-105]

Evidence
The workflow triggers on pull_request and the only job-level guard checks draft status, yet the
opencode step unconditionally reads secrets.DASHSCOPE_API_KEY, so missing secrets will lead to
runtime failure.

.github/workflows/qwen-review.yml[9-12]
.github/workflows/qwen-review.yml[94-105]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`opencode` depends on `secrets.DASHSCOPE_API_KEY` but is triggered for `pull_request` events without checking whether the secret is available (common for fork PRs).

## Issue Context
On fork PRs, repository secrets are typically not provided to workflows, so the opencode step will run with an empty API key and fail.

## Fix Focus Areas
- .github/workflows/qwen-review.yml[9-12]
- .github/workflows/qwen-review.yml[91-105]

## Suggested change
Update the job `if:` to also require the secret and/or non-fork PRs, e.g.:
```yaml
if: >-
 ${
   {
     !github.event.pull_request.draft &&
     secrets.DASHSCOPE_API_KEY != '' &&
     github.event.pull_request.head.repo.full_name == github.repository
   }
 }
```
(Use whichever predicate matches your contribution model; at minimum guard on `secrets.DASHSCOPE_API_KEY != ''`.)

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Results up to commit a47eb63


🐞 Bugs (3) 📘 Rule violations (1) 📎 Requirement gaps (0)


Action required
1. Static prompt in opencode 📘 Rule violation ⌂ Architecture
Description
The new GitHub Actions workflow configures an opencode LLM prompt as a hardcoded static string
with no injected runtime state. This violates the requirement that system prompts be dynamically
constructed with runtime application state, which can reduce review quality and cause
context-missing outputs.
Code

.github/workflows/qwen-review.yml[R110-116]

Evidence
PR Compliance ID 822364 requires system prompts to dynamically inject runtime state; the workflow
sets prompt: | to a fully static block with no ${{ ... }} interpolation or other runtime data
injection.

Rule 822364: System prompts must include runtime application state, not be purely static
.github/workflows/qwen-review.yml[110-116]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The `opencode` prompt is currently a static string and does not inject any runtime context (e.g., PR title/body, changed files, or other run-specific state).

## Issue Context
Compliance requires that system prompts include dynamically injected runtime application state rather than being purely static.

## Fix Focus Areas
- .github/workflows/qwen-review.yml[110-116]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Excess workflow permissions 🐞 Bug ⛨ Security
Description
The workflow grants pull-requests: write (and issues: read) at the workflow level, so the
static job inherits write-capable credentials it never uses, increasing impact if any step/tool is
compromised. Only the opencode job appears to require PR write access for posting a review
comment.
Code

.github/workflows/qwen-review.yml[R13-16]

Evidence
The workflow-level permissions apply to all jobs, but the static job only checks out code and runs
linters and does not call GitHub APIs; the only step that appears to need elevated rights is the
opencode action that posts review comments.

.github/workflows/qwen-review.yml[13-16]
.github/workflows/qwen-review.yml[28-86]
.github/workflows/qwen-review.yml[101-109]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The workflow-level `permissions:` grants `pull-requests: write` and `issues: read` to *all* jobs. The `static` job does not need these permissions, so it should run with minimal read-only permissions and only the `opencode` job should be granted write access.

## Issue Context
- `static` runs checkout + local linters only.
- `opencode` posts a PR review comment (needs `pull-requests: write`).

## Fix Focus Areas
- .github/workflows/qwen-review.yml[13-16]
- .github/workflows/qwen-review.yml[28-86]
- .github/workflows/qwen-review.yml[91-109]

## Suggested change
- Reduce top-level permissions to the minimum (e.g. `contents: read`).
- Add job-level permissions:
 - `static`: `contents: read`
 - `opencode`: `contents: read`, `pull-requests: write` (and `issues: read` only if truly required by the action).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended
3. Missing job timeouts 🐞 Bug ☼ Reliability
Description
Neither static nor opencode sets timeout-minutes, so hung network downloads (uv/bun) or a
stalled external review step can tie up runners for a long time and delay PR feedback. Add explicit
timeouts per job to bound worst-case runtime.
Code

.github/workflows/qwen-review.yml[R28-31]

Evidence
Both jobs are defined without any timeout, and they run steps that can block on external network
calls (package/tool fetching and an external review action).

.github/workflows/qwen-review.yml[28-31]
.github/workflows/qwen-review.yml[37-67]
.github/workflows/qwen-review.yml[91-105]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Jobs do not specify `timeout-minutes`, so intermittent hangs can consume runner time for an extended period and stall PR signal.

## Issue Context
This workflow includes multiple network-dependent operations (tool installs and an external action call), which can occasionally hang.

## Fix Focus Areas
- .github/workflows/qwen-review.yml[28-31]
- .github/workflows/qwen-review.yml[37-67]
- .github/workflows/qwen-review.yml[91-105]

## Suggested change
Add reasonable timeouts, e.g.:
- `static: timeout-minutes: 10` (or 15)
- `opencode: timeout-minutes: 20` (or 30)
Adjust based on observed runtimes.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Advisory comments
4. Checkout version inconsistency 🐞 Bug ⚙ Maintainability
Description
This workflow uses actions/checkout@v6 while other workflows in the repo use
actions/checkout@v4, creating unnecessary version divergence that makes CI behavior harder to
reason about across workflows. Align the checkout major version (or document why this workflow
intentionally differs).
Code

.github/workflows/qwen-review.yml[R32-35]

Evidence
The new workflow references actions/checkout@v6, while existing workflows in the same repo use
actions/checkout@v4, indicating an inconsistent standard for this critical dependency.

.github/workflows/qwen-review.yml[32-36]
.github/workflows/qwen-review.yml[96-100]
.github/workflows/ci.yml[71-75]
.github/workflows/changeset-auto-release.yml[18-23]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`qwen-review.yml` uses a different major version of `actions/checkout` than the rest of the repository’s workflows, increasing maintenance overhead and making workflow behavior less consistent.

## Issue Context
Most workflows in this repo reference `actions/checkout@v4`.

## Fix Focus Areas
- .github/workflows/qwen-review.yml[32-36]
- .github/workflows/qwen-review.yml[96-100]
- .github/workflows/ci.yml[71-75]

## Suggested change
- Switch `actions/checkout@v6` to the repo-standard `actions/checkout@v4`, or
- Add a short comment explaining why v6 is required specifically here.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Qodo Logo

@sourcery-ai
Copy link
Copy Markdown

sourcery-ai Bot commented May 30, 2026

Reviewer's Guide

Adds a new GitHub Actions workflow to run advisory-only static analysis (Python/TS/Rust) and an independent Qwen3.6 Plus LLM-based PR review via opencode/DashScope, plus the corresponding opencode provider configuration.

Flow diagram for PR-triggered static and LLM review jobs

flowchart LR
  PR["PullRequest opened/sync/reopened/ready_for_review"]
  STATIC["Job static\nruff / biome+tsc / cargo"]
  OPC["Job opencode\nQwen3_6_Plus review"]
  REPORT["Static analysis output\n(advisory-only)"]
  COMMENT["PR review comment\n(grouped by severity)"]

  PR --> STATIC
  PR --> OPC
  STATIC --> REPORT
  OPC --> COMMENT
Loading

File-Level Changes

Change Details Files
Introduce qwen-review GitHub Actions workflow with separate static analysis and LLM review jobs, including concurrency and draft handling.
  • Define pull_request trigger for opened, synchronize, reopened, and ready_for_review events with appropriate permissions and concurrency settings to cancel in-progress runs for the same PR
  • Add a static analysis job that checks out the repo, installs uv and bun, and runs ruff, biome/tsc, and cargo fmt/clippy in advisory mode using conditional execution and `
Configure opencode to use DashScope/Qwen3.6 Plus via an OpenAI-compatible provider definition.
  • Add opencode.json configuration mapping the dashscope/qwen3.6-plus model to the Alibaba Bailian Coding Plan endpoint
  • Wire API key management via environment variable injection and include schema reference metadata for opencode validation
opencode.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new configuration file opencode.json to set up the DashScope provider. A review comment correctly points out that the model identifier qwen3.6-plus is invalid and suggests updating it to qwen-plus to avoid API errors.

Comment thread opencode.json
Comment on lines +12 to +14
"qwen3.6-plus": {
"name": "Qwen3.6 Plus"
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The model identifier qwen3.6-plus is invalid. Alibaba Cloud DashScope / Bailian does not have a model named qwen3.6-plus. The correct identifier for the Qwen Plus model is qwen-plus. Please update it to avoid API errors during execution.

Suggested change
"qwen3.6-plus": {
"name": "Qwen3.6 Plus"
}
"qwen-plus": {
"name": "Qwen Plus"
}

Copy link
Copy Markdown
Collaborator Author

@arthrod arthrod left a comment

Choose a reason for hiding this comment

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

Three issues found in the workflow, two blocking.

Blocking

actions/checkout@v6 doesn't exist — latest stable is v4. Both jobs will fail immediately on checkout. Change both occurrences to actions/checkout@v4.

bunx --bun typescript tsc --noEmit is wrong syntax. bunx resolves and runs the default binary of a package; the TypeScript package exposes tsc as that binary. Correct form: bunx tsc --noEmit. The current form passes tsc --noEmit as arguments to a non-existent typescript executable.

Should-fix

anomalyco/opencode/github@latest floats on a third-party action — supply chain risk. Pin to a specific release tag or commit SHA.


Generated by Claude Code

Copy link
Copy Markdown

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • The Rust static analysis step assumes cargo/rustup are available on the runner, which isn’t guaranteed on ubuntu-latest; consider adding an explicit Rust toolchain setup (e.g., actions-rs/toolchain) or guarding the Rust block with a command -v cargo >/dev/null check to avoid step failures when .rs files are present.
  • The opencode job relies on DASHSCOPE_API_KEY and a writable GITHUB_TOKEN, which won’t be available for PRs from forks; if you expect external contributions, you may want to gate this job to same-repo PRs (e.g., compare head repo to github.repository) or otherwise handle the missing-secret case explicitly.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The Rust static analysis step assumes `cargo`/`rustup` are available on the runner, which isn’t guaranteed on `ubuntu-latest`; consider adding an explicit Rust toolchain setup (e.g., actions-rs/toolchain) or guarding the Rust block with a `command -v cargo >/dev/null` check to avoid step failures when `.rs` files are present.
- The `opencode` job relies on `DASHSCOPE_API_KEY` and a writable `GITHUB_TOKEN`, which won’t be available for PRs from forks; if you expect external contributions, you may want to gate this job to same-repo PRs (e.g., compare head repo to `github.repository`) or otherwise handle the missing-secret case explicitly.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@arthrod arthrod closed this May 30, 2026
@arthrod arthrod reopened this May 30, 2026
@qodo-code-review
Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

Comment on lines +101 to +105
- name: Run opencode
uses: anomalyco/opencode/github@latest
env:
DASHSCOPE_API_KEY: ${{ secrets.DASHSCOPE_API_KEY }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Unpinned opencode action 🐞 Bug ⛨ Security

The workflow runs anomalyco/opencode/github@latest, so the code executed in CI can change without
review and has access to DASHSCOPE_API_KEY plus PR write permissions. This creates a supply-chain
risk where a compromised/changed upstream action could exfiltrate secrets and post arbitrary PR
comments.
Agent Prompt
## Issue description
`anomalyco/opencode/github@latest` is an unpinned third-party GitHub Action. Because this job also receives `DASHSCOPE_API_KEY` and has `pull-requests: write`, any upstream change/compromise can immediately impact all PR runs.

## Issue Context
This workflow is intended to run automatically on PRs and post a review comment. That requires secrets and write permissions, which increases the blast radius of unpinned actions.

## Fix Focus Areas
- .github/workflows/qwen-review.yml[101-109]

## Suggested change
- Replace `anomalyco/opencode/github@latest` with a pinned immutable ref (prefer a full commit SHA; alternatively a specific, reviewed release tag).
- (Optional hardening) Move permissions to job-level and grant the minimum needed for `opencode` only (e.g., keep `pull-requests: write` there; keep `contents: read`; avoid granting other permissions to `static`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented May 30, 2026

Code review by qodo was updated up to the latest commit a47eb63

Comment on lines +110 to +116
prompt: |
Review this pull request as a senior engineer. Be concise and specific.
- Flag correctness bugs, security issues, and data-loss risks first.
- Note Python / TypeScript / Rust issues a linter would miss (logic, API misuse, races).
- Call out missing tests for changed behavior.
- Skip nitpicks already covered by formatters/linters.
Post a single review comment grouped by severity (Blocking / Should-fix / Nit).
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

1. Static prompt in opencode 📘 Rule violation ⌂ Architecture

The new GitHub Actions workflow configures an opencode LLM prompt as a hardcoded static string
with no injected runtime state. This violates the requirement that system prompts be dynamically
constructed with runtime application state, which can reduce review quality and cause
context-missing outputs.
Agent Prompt
## Issue description
The `opencode` prompt is currently a static string and does not inject any runtime context (e.g., PR title/body, changed files, or other run-specific state).

## Issue Context
Compliance requires that system prompts include dynamically injected runtime application state rather than being purely static.

## Fix Focus Areas
- .github/workflows/qwen-review.yml[110-116]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +13 to +16
permissions:
contents: read
pull-requests: write
issues: read
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Excess workflow permissions 🐞 Bug ⛨ Security

The workflow grants pull-requests: write (and issues: read) at the workflow level, so the
static job inherits write-capable credentials it never uses, increasing impact if any step/tool is
compromised. Only the opencode job appears to require PR write access for posting a review
comment.
Agent Prompt
## Issue description
The workflow-level `permissions:` grants `pull-requests: write` and `issues: read` to *all* jobs. The `static` job does not need these permissions, so it should run with minimal read-only permissions and only the `opencode` job should be granted write access.

## Issue Context
- `static` runs checkout + local linters only.
- `opencode` posts a PR review comment (needs `pull-requests: write`).

## Fix Focus Areas
- .github/workflows/qwen-review.yml[13-16]
- .github/workflows/qwen-review.yml[28-86]
- .github/workflows/qwen-review.yml[91-109]

## Suggested change
- Reduce top-level permissions to the minimum (e.g. `contents: read`).
- Add job-level permissions:
  - `static`: `contents: read`
  - `opencode`: `contents: read`, `pull-requests: write` (and `issues: read` only if truly required by the action).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@qodo-code-review
Copy link
Copy Markdown

qodo-code-review Bot commented May 30, 2026

Code review by qodo was updated up to the latest commit a47eb63

@arthrod arthrod closed this May 30, 2026
@arthrod arthrod reopened this May 30, 2026
@qodo-code-review
Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@github-actions
Copy link
Copy Markdown

Review: PR #445 — ci: add Qwen3.6-Plus PR review

🔴 Blocking

1. actions/checkout@v6 does not exist — both jobs will fail on checkout.
The latest stable major is v4. Both .github/workflows/qwen-review.yml:32 and line 96 must use actions/checkout@v4.

2. bunx --bun typescript tsc --noEmit is invalid — will silently noop.
typesact is not a published package. The typescript package exposes tsc as its default binary, so the correct form is:

bunx tsc --noEmit

bunx typescript resolves the typescript package and tries to run a binary named typescript, which does not exist — the step fails silently due to || true, masking the error.
(.github/workflows/qwen-review.yml:66)

3. Model identifier qwen3.6-plus is likely invalid — API call will fail.
DashScope/Bailian's Qwen Plus model is exposed as qwen-plus. qwen3.6-plus is not a recognized model ID on the Bailian Coding Plan endpoint. Even via the custom baseURL, an unknown model returns a 400/404. Verify the correct model ID with your Bailian plan and update opencode.json:12.
(opencode.json:12, .github/workflows/qwen-review.yml:107)

4. Rust toolchain not installed — cargo / rustup not available on ubuntu-latest.
The Rust step runs rustup component add and cargo fmt/clippy, but ubuntu-latest runners do not include Rust by default. If .rs files exist, the entire step fails. Add dtolnay/rust-toolchain@stable or guard with a command -v cargo check.
(.github/workflows/qwen-review.yml:76-82)

🟡 Should-fix

5. Unpinned third-party action anomalyco/opencode/github@latest.
This job receives DASHSCOPE_API_KEY and has pull-requests: write. An upstream change to the action could exfiltrate secrets or post arbitrary comments. Pin to a specific release tag or commit SHA.
(.github/workflows/qwen-review.yml:102)

6. Permissions are overly broad at the workflow level.
pull-requests: write, issues: read, and id-token: write are granted to all jobs, but static needs none of them. Move permissions to the job level:

  • static: contents: read
  • opencode: contents: read, pull-requests: write
    Remove id-token: write — no step uses OIDC.
    (.github/workflows/qwen-review.yml:13-17)

7. No fork/secret guard on the opencode job.
Fork PRs do not receive secrets.DASHSCOPE_API_KEY, so the job will fail on external contributions. Add a check to the if: condition:

if: >-
  ${{
    !github.event.pull_request.draft &&
    github.event.pull_request.head.repo.full_name == github.repository &&
    secrets.DASHSCOPE_API_KEY != ''
  }}

(.github/workflows/qwen-review.yml:94)

8. No timeout-minutes on either job.
Hung network operations (uvx, bunx, cargo clippy, or the opencode action call) can tie up runners indefinitely. Add timeout-minutes: 10 to static and timeout-minutes: 20 to opencode.

9. Prompt is fully static — no runtime context injection.
The prompt does not include PR title, body, changed files, or diff. Review quality will be degraded because the LLM has no PR-specific context beyond what github provides at the action level. Inject at minimum: ${{ github.event.pull_request.title }} and ${{ github.event.pull_request.body }}.
(.github/workflows/qwen-review.yml:110-116)

10. actions/checkout version inconsistent with repo conventions.
Other workflows in this repo use actions/checkout@v4. Align (which also fixes issue #1 above).

⚪ Nit

11. fetch-depth: 0 in static job is unnecessary.
The steps use git ls-files which works with any depth. fetch-depth: 1 is sufficient and faster.
(.github/workflows/qwen-review.yml:35)

github run

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