Skip to content

fix(opencode): fail closed reviewer inspection - #2221

Merged
Alan-TheGentleman merged 4 commits into
mainfrom
fix/2076-opencode-reviewer-unsupported
Aug 2, 2026
Merged

fix(opencode): fail closed reviewer inspection#2221
Alan-TheGentleman merged 4 commits into
mainfrom
fix/2076-opencode-reviewer-unsupported

Conversation

@Alan-TheGentleman

@Alan-TheGentleman Alan-TheGentleman commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

🔗 Linked Issue

Closes #2076


🏷️ PR Type

  • type:bug — Bug fix

📝 Summary

  • Fails closed before launching immutable OpenCode reviewer inspection because OpenCode 1.18.10 cannot securely bind candidate-specific shell permissions to a child session.
  • Removes Bash capability and inspection allow rules from generated OpenCode reviewers.
  • Preserves Kilo, native inspect-candidate, and unrelated SDD behavior unchanged.

📂 Changes

Area Change
OpenCode review plugin Returns the existing typed unsupported outcome before preflight or reviewer launch.
Generated reviewer config Disables Bash and emits no inspection allow rules.
Windows runtime E2E Proves no reviewer subagent, redirected side effect, or review authority is created.
CI Pins OpenCode 1.18.10 and guards the exact runtime test name.

🧪 Test Plan

  • Focused OpenCode/Kilo configuration and plugin tests
  • Focused race tests
  • go test ./... -count=1
  • go build ./...
  • go vet ./...
  • go run ./internal/gofmtcheck
  • actionlint .github/workflows/ci.yml
  • Windows static compilation
  • Benchmark: N/A, this is an external OpenCode child-session capability boundary

✅ Contributor Checklist

  • Linked approved issue
  • Exactly one type:* label
  • 584 changed lines with maintainer-approved size:exception
  • Conventional commit, no attribution trailer
  • Documentation and runtime applicability reviewed

💬 Notes for Reviewers

The 584-line diff has a maintainer-approved size:exception: the fail-closed behavior, generated configuration, adversarial JSONL proof, armed launch detector, and real Windows runtime gate form one security unit.

This is a fail-closed successor to #2109, not a continuation of its wildcard shell-permission approach. The old contributor branch remains untouched. OpenCode stays policy-eligible, but immutable review transport remains disabled until a documented exact child-session binding exists.

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of unsupported immutable inspections by stopping safely before reviewer or command execution.
    • Prevented unauthorized edits, shell commands, alternate providers, and live-worktree access during bounded reviews.
    • Added clearer incomplete-inspection outcomes when secure inspection cannot be performed.
    • Ensured unsupported review capabilities are reported without exposing underlying system or filesystem details.
  • Tests

    • Added Windows coverage for reviewer rejection scenarios.
    • Expanded validation to confirm unsupported operations do not modify the worktree or create review authority.
    • Updated end-to-end testing to use OpenCode 1.18.10.

Copilot AI review requested due to automatic review settings August 2, 2026 00:15
@Alan-TheGentleman Alan-TheGentleman added the type:bug Bug fix label Aug 2, 2026
@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

OpenCode review tasks now reject unsupported immutable inspection before reviewer or native process launch. OpenCode receives denied Bash and edit permissions. KiloCode removes the OpenCode-only plugin. Windows E2E coverage verifies rejection and unchanged review state.

Changes

OpenCode unsupported inspection

Layer / File(s) Summary
Plugin preflight rejection
internal/assets/opencode/plugins/review-result-artifacts.ts, internal/assets/review_plugin_recovery_test.go, internal/assets/assets_test.go
The plugin emits UNSUPPORTED_CAPABILITY and stops unsupported or opaque preflight paths before reviewer or native process launch.
Adapter-specific reviewer and plugin configuration
internal/components/sdd/boundedreview.go, internal/components/sdd/inject.go, internal/components/sdd/inject_test.go, internal/components/sdd/review_ledger_contract_test.go, internal/cli/sync_test.go
OpenCode reviewers receive an unsupported-inspection prompt with Bash and edit permissions denied. KiloCode removes the OpenCode-only review plugin and retains shared plugins.
Windows runtime validation
internal/versions/versions.go, .github/workflows/ci.yml, e2e/organicruntime/opencode_reviewer_unsupported_e2e_test.go
OpenCode is pinned to 1.18.10. The Windows E2E test validates rejection before reviewer launch and checks event parsing, fixture setup, configuration generation, and environment replacement.

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

Sequence Diagram(s)

sequenceDiagram
  participant ReviewTask
  participant ReviewResultPlugin
  participant OpenCode
  participant NativeGit
  ReviewTask->>ReviewResultPlugin: validate immutable review binding
  ReviewResultPlugin-->>ReviewTask: return unsupported-capability
  ReviewResultPlugin--x OpenCode: do not launch reviewer
  ReviewResultPlugin--x NativeGit: do not run inspection process
Loading

Possibly related issues

Possibly related PRs

Suggested reviewers: copilot, decode2

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.92% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed For [#2076], the PR disables unsupported OpenCode inspection before launch and adds Windows coverage for fail-closed behavior.
Out of Scope Changes check ✅ Passed The changes support [#2076] by updating OpenCode handling, tests, version pinning, CI coverage, and preserving Kilo behavior.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: OpenCode reviewer inspection now fails closed.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/2076-opencode-reviewer-unsupported

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.

Copilot AI 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.

Pull request overview

Disables immutable candidate inspection for OpenCode reviewers by failing closed before any reviewer subagent is launched, due to OpenCode 1.18.10’s inability to securely bind provider-injected dynamic values to a child-session Bash permission. This keeps other runtimes (notably Kilocode and native inspect-candidate) unchanged while preventing insecure or misleading “successful” inspection attempts.

Changes:

  • Make the OpenCode review-result plugin reject reviewer tasks up front with a typed unsupported-capability outcome (no reviewer launch).
  • Generate OpenCode reviewer agents without Bash capability and without inspection allow-rules; update prompt text to explicitly stop and return incomplete.
  • Add/adjust tests (including a Windows-only real OpenCode E2E proof) and pin OpenCode to 1.18.10 in both code and CI, with a guard that the E2E test name is present.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated no comments.

Show a summary per file
File Description
internal/assets/opencode/plugins/review-result-artifacts.ts Fail closed in tool.execute.before for reviewer tasks with a typed unsupported-capability error before any launch/capture path.
internal/components/sdd/inject.go Generate OpenCode reviewer agents as unsupported (no Bash, deny-only permissions, updated prompt) while preserving non-OpenCode behavior.
internal/components/sdd/boundedreview.go Add a dedicated unsupported-capability reviewer prompt builder for OpenCode.
internal/components/sdd/review_ledger_contract_test.go Update contract expectations for OpenCode reviewers (unsupported) and add a Kilocode settings baseline guard.
testdata/golden/sdd-opencode-multi-settings.golden Update golden settings to reflect deny-only Bash and unsupported prompt content.
internal/assets/review_plugin_recovery_test.go Update plugin recovery tests to assert “stop before launch/preflight” behavior and preserve existing recovery invariants where applicable.
internal/assets/assets_test.go Update plugin source contract assertions to match the new typed unsupported-capability path.
e2e/organicruntime/opencode_reviewer_unsupported_e2e_test.go Add a Windows-only real OpenCode E2E test proving no Bash side effects / no authority creation occurs.
internal/versions/versions.go Pin OpenCode runtime version to 1.18.10.
.github/workflows/ci.yml Install pinned OpenCode 1.18.10 and add a guard verifying the Windows E2E test is registered by name.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@coderabbitai coderabbitai Bot 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: 2

🤖 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/ci.yml:
- Line 233: Harden the pinned OpenCode installation step by adding integrity
verification for opencode-ai@1.18.10, preferably through a recorded package
integrity hash or a lockfile-based install. Preserve the exact version pin and
ensure the workflow fails if the downloaded package does not match the expected
integrity value.

In `@internal/components/sdd/review_ledger_contract_test.go`:
- Around line 389-390: Document both deterministic baseline changes in
internal/components/sdd/review_ledger_contract_test.go: add a short rationale
comment beside the standard and full-4R wantChars entries at lines 389-390,
noting that OpenCode reviewers now render the short unsupported-capability
prompt; also add a comment for
TestKilocodeReviewSettingsMatchCurrentMainBaseline at lines 231-246 describing
what the SHA-256 hash covers and how to regenerate want after a legitimate
Kilocode settings change.
🪄 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: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e460b7c2-aadc-47b7-939b-d06cb6729d3c

📥 Commits

Reviewing files that changed from the base of the PR and between 166dd2c and 86ea91b.

⛔ Files ignored due to path filters (1)
  • testdata/golden/sdd-opencode-multi-settings.golden is excluded by !testdata/**
📒 Files selected for processing (9)
  • .github/workflows/ci.yml
  • e2e/organicruntime/opencode_reviewer_unsupported_e2e_test.go
  • internal/assets/assets_test.go
  • internal/assets/opencode/plugins/review-result-artifacts.ts
  • internal/assets/review_plugin_recovery_test.go
  • internal/components/sdd/boundedreview.go
  • internal/components/sdd/inject.go
  • internal/components/sdd/review_ledger_contract_test.go
  • internal/versions/versions.go

Comment thread .github/workflows/ci.yml

- name: Install pinned OpenCode runtime
run: npm install --global opencode-ai@1.18.4
run: npm install --global opencode-ai@1.18.10

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 | 🔵 Trivial

Consider integrity verification for the pinned OpenCode install.

Static analysis flags npm install --global opencode-ai@1.18.10 as an ad-hoc package install outside a lockfile. The exact version pin limits drift, but the install still has no checksum or integrity verification against a compromised registry or mirror. Consider recording and verifying the package integrity hash, or using a lockfile-based install for this step, as a follow-up hardening item.

🧰 Tools
🪛 zizmor (1.28.0)

[warning] 233-233: ad-hoc installation of packages (adhoc-packages): installs a package outside of a lockfile

(adhoc-packages)

🤖 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/ci.yml at line 233, Harden the pinned OpenCode
installation step by adding integrity verification for opencode-ai@1.18.10,
preferably through a recorded package integrity hash or a lockfile-based
install. Preserve the exact version pin and ensure the workflow fails if the
downloaded package does not match the expected integrity value.

Source: Linters/SAST tools

Comment on lines +389 to +390
{name: "standard", agents: []string{"review-reliability"}, beforeChars: 42_301, wantChars: 13_855, maxCharacters: 18_500},
{name: "full-4R", agents: []string{"review-risk", "review-resilience", "review-readability", "review-reliability"}, beforeChars: 106_998, wantChars: 21_613, maxCharacters: 36_000},

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 | 🔵 Trivial | ⚡ Quick win

Document the rationale for both new baseline changes.

This test file has an established convention: every deterministic baseline change (SHA-256 hash, character-count pin) gets a short comment explaining what changed and why. Both new baseline values in this PR skip that convention.

  • internal/components/sdd/review_ledger_contract_test.go#L389-L390: add a short comment (following the style of the block ending at line 388) explaining that wantChars dropped because OpenCode reviewers now render the short unsupported-capability prompt instead of the full inspection recipe.
  • internal/components/sdd/review_ledger_contract_test.go#L231-L246: add a comment on TestKilocodeReviewSettingsMatchCurrentMainBaseline explaining what the SHA-256 hash covers and how to regenerate want when a legitimate Kilocode settings change occurs.
📍 Affects 1 file
  • internal/components/sdd/review_ledger_contract_test.go#L389-L390 (this comment)
  • internal/components/sdd/review_ledger_contract_test.go#L231-L246
🤖 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 `@internal/components/sdd/review_ledger_contract_test.go` around lines 389 -
390, Document both deterministic baseline changes in
internal/components/sdd/review_ledger_contract_test.go: add a short rationale
comment beside the standard and full-4R wantChars entries at lines 389-390,
noting that OpenCode reviewers now render the short unsupported-capability
prompt; also add a comment for
TestKilocodeReviewSettingsMatchCurrentMainBaseline at lines 231-246 describing
what the SHA-256 hash covers and how to regenerate want after a legitimate
Kilocode settings change.

@Alan-TheGentleman Alan-TheGentleman added the size:exception Maintainer-approved exception for PRs above the 400 changed-line review budget label Aug 2, 2026
Copilot AI review requested due to automatic review settings August 2, 2026 01:06

@coderabbitai coderabbitai Bot 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: 1

🤖 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 `@e2e/organicruntime/opencode_reviewer_unsupported_e2e_test.go`:
- Around line 130-133: Update the helper containing the tool-use rejection check
to record matching events instead of returning immediately, continue decoding
until io.EOF, and return the recorded rejection only after the complete stream
parses successfully. Ensure malformed trailing JSON returns the decoder error,
and add a test covering a valid rejection followed by "\n{" that expects an
error.
🪄 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: Repository UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: bbb0728c-fcca-403f-8534-d7c7e5a85a84

📥 Commits

Reviewing files that changed from the base of the PR and between 86ea91b and 47a03c1.

📒 Files selected for processing (4)
  • e2e/organicruntime/opencode_reviewer_unsupported_e2e_test.go
  • internal/assets/assets_test.go
  • internal/assets/opencode/plugins/review-result-artifacts.ts
  • internal/assets/review_plugin_recovery_test.go

Comment thread e2e/organicruntime/opencode_reviewer_unsupported_e2e_test.go Outdated

Copilot AI 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.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings August 2, 2026 01:46

Copilot AI 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.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.

Comment thread .github/workflows/ci.yml
Comment on lines +238 to +241
$tests = go test -list '^TestRealOpenCodeRejectsUnsupportedImmutableReviewerBash$' ./e2e/organicruntime
if ($LASTEXITCODE -ne 0 -or $tests -notcontains 'TestRealOpenCodeRejectsUnsupportedImmutableReviewerBash') {
throw 'Windows OpenCode reviewer rejection E2E is missing'
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:exception Maintainer-approved exception for PRs above the 400 changed-line review budget type:bug Bug fix

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(opencode): provider-bound review inspection is denied on Windows

2 participants