Skip to content

fix(opencode): harden opencode plugin against abort, orphan, and arg edge cases - #728

Merged
lizhengfeng101 merged 1 commit into
alibaba:mainfrom
atharv-sys32:fix/opencode-plugin-robustness
Aug 5, 2026
Merged

fix(opencode): harden opencode plugin against abort, orphan, and arg edge cases#728
lizhengfeng101 merged 1 commit into
alibaba:mainfrom
atharv-sys32:fix/opencode-plugin-robustness

Conversation

@atharv-sys32

Copy link
Copy Markdown
Contributor

Fixes #702 (the six findings not covered by #717).

Implements M1, M2, M3, M4, L1, L2 from the issue:

  • M1: telemetry app.log failure no longer blocks tool registration
  • M2: context.abort.aborted guarded for hosts without an abort signal
  • M3: resume is now rejected alongside commit or a from/to range
  • M4: OCR spawns detached and the whole process group is killed on timeout/cancel, so git/LLM grandchildren cannot orphan
  • L1: empty stdout reads as no changes instead of a misleading invalid JSON error
  • L2: dead ReviewInput.repo field removed; cwd is passed as the repo arg directly

H1 is intentionally left to #717.

Tests: ran npm run check in plugins/open-code-review/opencode, all 21 tests pass. New tests cover each fix; the process-group test fails without the detached/kill-group change.

…edge cases

Address the six still-open findings from alibaba#702 in the opencode plugin:

- M1: wrap the telemetry app.log call so a failing log service no longer
  blocks tool registration
- M2: guard context.abort.aborted for hosts that omit an abort signal
- M3: reject resume combined with commit or a from/to range
- M4: spawn OCR in its own process group and kill the group on timeout
  or cancel so git/LLM grandchildren cannot orphan
- L1: treat empty stdout as no changes instead of misleading invalid JSON
- L2: drop the dead ReviewInput.repo field and pass cwd as the repo arg
  directly

Adds regression tests for each fix, including a process-group test that
asserts grandchildren are reaped on cancellation.
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

🔍 OpenCodeReview found 3 issue(s) in this PR.

  • ✅ Successfully posted inline: 3 comment(s)

Comment on lines +120 to +132
test("plugin still registers tools when the telemetry log call fails", async () => {
const hooks = await OpenCodeReviewPlugin({
client: {
app: {
log: async () => {
throw new Error("log service unavailable")
},
},
},
worktree: "/tmp/project",
})
assert.deepEqual(Object.keys(hooks.tool).sort(), ["ocr_health", "ocr_review"])
})

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.

[test · medium]
The test asserts that tools are registered when the telemetry log call fails, but it doesn't verify that the error was properly handled or that no unhandled promise rejection occurred. If the production code only catches the error synchronously but the log call is fire-and-forget async, the test could pass while an unhandled rejection still leaks. Consider adding an assertion that verifies the error was caught, such as checking that the promise resolved without throwing or listening for unhandled rejections during the test.

Comment on lines +421 to +427
test("ocr_review reports no output instead of invalid JSON when OCR prints nothing", async () => {
await withFakeOcr("", async (worktree) => {
const { hooks } = await loadPlugin(worktree)
const output = await hooks.tool.ocr_review.execute({}, toolContext(worktree))
assert.match(output, /No changes detected/)
})
})

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.

[test · low]
The test verifies that when OCR produces no output, the result matches /No changes detected/, but it doesn't explicitly assert that the output does NOT contain a JSON parse error message (which was the previous behavior being fixed). Consider adding a negative assertion to ensure the error message about invalid JSON is not present, making the test more robust against regressions.

Suggestion:

Suggested change
test("ocr_review reports no output instead of invalid JSON when OCR prints nothing", async () => {
await withFakeOcr("", async (worktree) => {
const { hooks } = await loadPlugin(worktree)
const output = await hooks.tool.ocr_review.execute({}, toolContext(worktree))
assert.match(output, /No changes detected/)
})
})
test("ocr_review reports no output instead of invalid JSON when OCR prints nothing", async () => {
await withFakeOcr("", async (worktree) => {
const { hooks } = await loadPlugin(worktree)
const output = await hooks.tool.ocr_review.execute({}, toolContext(worktree))
assert.match(output, /No changes detected/)
assert.doesNotMatch(output, /invalid JSON/i)
})
})

Comment on lines +465 to +485
test("ocr_health works when no abort signal is provided", async () => {
await withFakeOcr(
[
"if (process.argv[2] === 'version') {",
" console.log('OpenCodeReview 1.2.3')",
"} else {",
" console.error('missing LLM credentials')",
" process.exitCode = 7",
"}",
].join("\n"),
async (worktree) => {
const { hooks } = await loadPlugin(worktree)
const output = await hooks.tool.ocr_health.execute(
{},
{ worktree, directory: worktree },
)
assert.match(output, /OpenCodeReview 1\.2\.3/)
assert.match(output, /LLM connection check failed: missing LLM credentials/)
},
)
})

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.

[test · medium]
This test covers the no-abort-signal scenario for ocr_health, but the same scenario is not tested for ocr_review, which has more complex cancellation logic involving process group killing. If ocr_review also accesses abortSignal without a guard, it could crash in production when called without a signal. Consider adding a similar test for ocr_review to ensure both tools handle the absence of an abort signal gracefully.

@lizhengfeng101 lizhengfeng101 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

LGTM

@lizhengfeng101
lizhengfeng101 merged commit 927b710 into alibaba:main Aug 5, 2026
11 checks passed
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.

[plugin/opencode] 7 issues in plugins/open-code-review/opencode/open-code-review.ts (incl. timeoutMinutes never wired to process timeout)

2 participants