Skip to content

fix(opencode): allow governed free models for private repositories - #830

Open
seonghobae wants to merge 16 commits into
mainfrom
fix/opencode-private-free-opt-in-20260808
Open

fix(opencode): allow governed free models for private repositories#830
seonghobae wants to merge 16 commits into
mainfrom
fix/opencode-private-free-opt-in-20260808

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Problem

The central OpenCode review workflow currently prepends NVIDIA NIM and anonymous opencode-free/* candidates only when GitHub reports the target repository as public. A private repository therefore skips the free pool even when its tracked source is intentionally public-equivalent and contains no confidential data.

Repository visibility is not a sufficient data-classification signal, but the absence of configured Actions secrets is not sufficient either. Source, fixtures, history, and generated review evidence can still be confidential.

Solution

  • Add a fail-closed trusted-base policy at .github/opencode-private-free-models.json.

  • Require the exact canonical declaration:

    {
      "schema_version": 1,
      "allow_private_free_models": true,
      "repository_data_classification": "public_equivalent",
      "external_model_data_use_accepted": true
    }
  • Read the declaration from the exact immutable PR base commit.

  • Reject a PR that adds, removes, renames, chmods, or modifies its own policy; the opt-in takes effect only after the policy reaches the protected base branch and is used by a later PR.

  • Prepend all twelve anonymous free candidates already supported by the current central generated OpenCode configuration, then retain the existing keyed fallback pool.

  • Preserve the existing model-pool implementation byte-for-byte as run_opencode_review_model_pool_impl.sh; the original entrypoint becomes a small governance and credential-isolation wrapper while retaining the established static fail-closed source contract.

  • Validate the delegated stable implementation's established contract before invoking any model in a full central workflow materialization.

  • Scope every OpenCode subprocess to its selected provider credential. Anonymous free models, export commands, and unknown provider prefixes receive no provider key, GitHub token, Actions OIDC credential, or Actions runtime/cache/results credential.

  • Add an operator runbook, an example policy, CHANGELOG entries, and complete regression coverage.

Security properties

The policy checker accepts only a regular non-executable 100644 blob at the fixed path, strict UTF-8, at most 4,096 bytes, exact fields and values, and JSON without duplicate keys. It accepts only full 40-character base/head SHAs, ignores user/system Git configuration, disables hooks and filesystem monitors, and fails closed on missing, invalid, changed, or unreadable policy state.

The declaration means the repository owner accepts external free-model processing for tracked repository content classified as public_equivalent; it does not claim that secret scanning can prove the absence of every confidential fact. Secret Protection, push protection, generic/custom patterns, and CODEOWNERS remain defense-in-depth controls.

Verification

Local focused verification:

  • focused suite: 43 passed, 1 skipped
  • policy suite: 30 passed
  • policy checker: 142 statements / 38 branches, 100% statement and branch coverage
  • public module/class/function docstrings: 100%
  • Bash syntax, Python compilation, strict JSON, legacy central-runner source contract, delegated-runner failure boundary, and documentation checks: passed

The skipped test only checks that the twelve governed candidates are present in the full central workflow; the focused local fixture intentionally excludes that large workflow. All twelve candidates are present in current main, and the repository's existing test_strix_quick_gate.sh independently enforces the stable entrypoint markers on the exact hosted head.

Migration note

This focused change supersedes the overlapping private/free-model routing slice in draft PR #760. Any future rebase or decomposition of #760 must preserve this trusted-base opt-in and provider-scoped credential boundary rather than restoring the blanket private-repository exclusion.

Sources

Add an immutable trusted-base opt-in for private repositories classified as public-equivalent, preserve the existing model-pool implementation byte-for-byte behind a policy wrapper, and isolate every OpenCode subprocess to its selected provider credential.
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 7 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c1cb4f4a-58a8-46e2-b384-cbae832ff63c

📥 Commits

Reviewing files that changed from the base of the PR and between 6eb06cd and 9a9b3e0.

📒 Files selected for processing (13)
  • CHANGELOG.md
  • docs/doctoring/opencode-private-free-model-policy.md
  • docs/examples/opencode-private-free-models.json
  • scripts/ci/opencode_private_free_model_policy.py
  • scripts/ci/opencode_provider_guard.sh
  • scripts/ci/run_opencode_review_model_pool.sh
  • scripts/ci/run_opencode_review_model_pool_impl.sh
  • tests/test_opencode_delegated_runner_contract.py
  • tests/test_opencode_private_free_model_policy_1.py
  • tests/test_opencode_private_free_model_policy_2.py
  • tests/test_opencode_private_free_model_policy_3.py
  • tests/test_opencode_private_free_model_runner_contract.py
  • tests/test_opencode_provider_guard.py
📝 Walkthrough

Walkthrough

Private 저장소의 익명 OpenCode 무료 모델 사용 정책을 추가했습니다. 정책은 신뢰된 base 커밋에서만 활성화됩니다. 모델 풀을 별도 구현으로 위임하고, 공급자별 자격 증명 격리와 fail-closed 계약 테스트를 추가했습니다.

Changes

OpenCode 거버넌스 및 실행 제어

Layer / File(s) Summary
Private 무료 모델 정책 검증
scripts/ci/opencode_private_free_model_policy.py, docs/doctoring/opencode-private-free-model-policy.md, docs/examples/opencode-private-free-models.json, CHANGELOG.md, tests/test_opencode_private_free_model_policy_*.py
Base 커밋의 고정 정책 blob만 평가합니다. 정책 경로 변경, 잘못된 SHA, 잘못된 tree, 손상된 JSON, 중복 키, 잘못된 UTF-8 및 canonical 값은 거부합니다.
모델 풀 위임 및 무료 후보 제어
scripts/ci/run_opencode_review_model_pool.sh, tests/test_opencode_private_free_model_runner_contract.py, tests/test_opencode_delegated_runner_contract.py
Wrapper가 구현 계약과 정책 검사기를 확인한 뒤 sibling 구현을 실행합니다. 검증된 base 정책이 있을 때만 익명 무료 후보를 중복 없이 추가합니다.
공급자 자격 증명 격리
scripts/ci/opencode_provider_guard.sh, tests/test_opencode_provider_guard.py
선택된 공급자의 자격 증명만 OpenCode에 전달합니다. GitHub 및 Actions OIDC 자격 증명과 미선택 공급자 키는 제거합니다. 익명 모델, export, 알 수 없는 공급자는 자격 증명 없이 실행합니다.
위임된 모델 풀 실행
scripts/ci/run_opencode_review_model_pool_impl.sh
모델 출력 검증, 승인 게이트, 공급자 오류 분류, 재시도, 백오프, 후보 격리, 실행 시간·시도·예산 제한 및 exhausted 상태 기록을 구현합니다.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested reviewers: opencode-agent

Sequence Diagram(s)

sequenceDiagram
  participant Wrapper as run_opencode_review_model_pool.sh
  participant Policy as opencode_private_free_model_policy.py
  participant Guard as opencode_provider_guard.sh
  participant Pool as run_opencode_review_model_pool_impl.sh
  participant OpenCode as OpenCode
  Wrapper->>Policy: base/head 커밋으로 정책 평가
  Policy-->>Wrapper: 무료 모델 사용 허용 또는 거부
  Wrapper->>Guard: OpenCode 실행 wrapper 설치
  Wrapper->>Pool: 후보 목록과 실행 환경 전달
  Pool->>Guard: 선택된 모델 실행 요청
  Guard->>OpenCode: 정리된 자격 증명 환경으로 실행
  OpenCode-->>Pool: 모델 출력과 세션 결과 반환
  Pool-->>Wrapper: 성공, 재시도 또는 exhausted 상태 기록
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 65.79% 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 Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 비공개 저장소에서 거버넌스가 적용된 무료 모델을 허용하는 주요 변경 사항을 정확하고 간결하게 설명합니다.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/opencode-private-free-opt-in-20260808

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

Expand the governed private pool to every anonymous candidate already configured by the central workflow and retain the established fail-closed source contract while delegating runtime behavior to the unchanged implementation.
Keep the established central source-level contract visible at the stable entrypoint and fail closed on a truncated delegated implementation in full workflow materializations.

@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: 4

🧹 Nitpick comments (6)
tests/test_opencode_private_free_model_runner_contract.py (1)

206-221: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

이 테스트는 두 개의 독립된 차단 이유를 동시에 만족합니다.

base_has_policy=False이므로 정책 평가가 이미 거부됩니다. 동시에 후보 목록에 opencode-free/glm-5-free가 있어 candidate_list_contains_anonymous_free_model이 조기 반환합니다. 따라서 "기존 free 풀은 재정렬하지 않는다"는 계약이 단독으로 검증되지 않습니다. base_has_policy=True로 바꾸면 조기 반환 경로만 검증합니다.

💚 테스트 강화 제안
     source, base_sha, head_sha = create_source_repository(
         tmp_path,
-        base_has_policy=False,
+        base_has_policy=True,
         head_changes_policy=False,
     )
🤖 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 `@tests/test_opencode_private_free_model_runner_contract.py` around lines 206 -
221, Update test_existing_public_free_pool_is_not_reordered_or_duplicated to set
base_has_policy=True while keeping head_changes_policy=False, so the policy gate
passes and the test isolates the existing public free-pool ordering behavior
without triggering the anonymous free-model early return.
scripts/ci/run_opencode_review_model_pool.sh (2)

169-170: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

trapinstall_provider_guard 앞에 등록하십시오.

현재 trap cleanup_provider_guard EXIT INT TERMinstall_provider_guard 다음 줄에 있습니다. mktemp -d 성공 후 cp 또는 chmod가 실패하면 set -e가 스크립트를 종료합니다. 그 시점에는 trap이 아직 없으므로 임시 디렉터리가 남습니다. trap을 먼저 등록하면 모든 실패 경로에서 정리가 실행됩니다.

♻️ 순서 변경 제안
-install_provider_guard
 trap cleanup_provider_guard EXIT INT TERM
+install_provider_guard
🤖 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 `@scripts/ci/run_opencode_review_model_pool.sh` around lines 169 - 170,
Register the cleanup trap before calling install_provider_guard so
cleanup_provider_guard handles failures during temporary-directory setup,
including cp or chmod errors under set -e.

77-103: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

후보 목록 확장 시 glob 확장을 차단하십시오.

for candidate in ${OPENCODE_MODEL_CANDIDATES:-}는 인용을 생략하여 단어 분리를 의도합니다. 그러나 파일명 확장도 함께 활성화됩니다. 워크플로가 *, ?, [를 포함한 후보 문자열을 전달하면 후보 이름이 현재 디렉터리 파일명으로 치환될 수 있습니다. 두 함수를 set -f/set +f로 감싸거나, read -r -a로 배열을 만들면 확장이 차단됩니다.

🛡️ 제안
 candidate_list_contains_anonymous_free_model() {
-  local candidate
-  for candidate in ${OPENCODE_MODEL_CANDIDATES:-}; do
+  local candidate
+  local -a candidates
+  read -r -a candidates <<<"${OPENCODE_MODEL_CANDIDATES:-}"
+  for candidate in "${candidates[@]}"; do
     case "$candidate" in
       opencode-free/*)
         return 0
         ;;
     esac
   done
   return 1
 }
 
 prepend_unique_anonymous_free_candidates() {
   local combined=""
   local candidate
-  for candidate in $anonymous_free_candidates ${OPENCODE_MODEL_CANDIDATES:-}; do
+  local -a candidates
+  read -r -a candidates <<<"$anonymous_free_candidates ${OPENCODE_MODEL_CANDIDATES:-}"
+  for candidate in "${candidates[@]}"; do
     case " $combined " in
🤖 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 `@scripts/ci/run_opencode_review_model_pool.sh` around lines 77 - 103, Disable
pathname expansion while iterating over OPENCODE_MODEL_CANDIDATES in
candidate_list_contains_anonymous_free_model and
prepend_unique_anonymous_free_candidates, preserving intentional
whitespace-based word splitting. Restore the caller’s globbing state after each
function completes, including early returns, or use a read-based array approach
that prevents glob expansion without changing candidate parsing.
scripts/ci/opencode_private_free_model_policy.py (1)

176-177: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

blob SHA 검증에 커밋 SHA 패턴을 재사용합니다.

COMMIT_SHA_PATTERN은 40자 16진수만 허용합니다. SHA-256 오브젝트 포맷 저장소에서 git ls-tree는 64자 SHA를 반환합니다. 그 경우 정책 평가는 상태 2로 실패합니다. 현재 GitHub 호스팅 저장소는 SHA-1이므로 즉시 영향은 없습니다. 별도의 오브젝트 ID 패턴(40 또는 64자)을 사용하면 향후 마이그레이션에서 안전합니다.

🤖 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 `@scripts/ci/opencode_private_free_model_policy.py` around lines 176 - 177,
Update the validation around entry.object_sha in the policy evaluation flow to
use a dedicated object ID pattern that accepts valid 40- or 64-character
hexadecimal SHAs, rather than COMMIT_SHA_PATTERN. Keep the existing
PolicyEvaluationError and invalid-SHA handling unchanged.
scripts/ci/run_opencode_review_model_pool_impl.sh (1)

42-51: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

normalize_opencode_output은 호출 컨텍스트의 errexit 비활성화에 의존합니다.

set -euo pipefail이 활성 상태입니다. Line 44의 opencode_review_approve_gate.sh가 0이 아닌 상태로 끝나면, 조건 컨텍스트 밖에서는 errexit이 발동하여 Line 46의 rc=$?와 Line 50의 rm -f "$probe"가 실행되지 않습니다. 현재 유일한 호출 지점인 Line 536은 if ! 조건이므로 동작합니다. 향후 다른 위치에서 호출하면 임시 파일이 남고 폴백이 중단됩니다. 명시적으로 상태를 잡으면 호출 위치와 무관하게 안전합니다.

♻️ 제안
 	if python3 "$GITHUB_WORKSPACE/scripts/ci/opencode_review_normalize_output.py" \
 		"$HEAD_SHA" "$RUN_ID" "$RUN_ATTEMPT" "$probe"; then
-		bash "$GITHUB_WORKSPACE/scripts/ci/opencode_review_approve_gate.sh" \
-			"$HEAD_SHA" "$RUN_ID" "$RUN_ATTEMPT" "$probe" >/dev/null
-		rc=$?
+		rc=0
+		bash "$GITHUB_WORKSPACE/scripts/ci/opencode_review_approve_gate.sh" \
+			"$HEAD_SHA" "$RUN_ID" "$RUN_ATTEMPT" "$probe" >/dev/null || rc=$?
 	else
 		rc=1
 	fi
🤖 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 `@scripts/ci/run_opencode_review_model_pool_impl.sh` around lines 42 - 51,
Update the normalize_opencode_output flow around opencode_review_approve_gate.sh
so its nonzero status is captured explicitly without relying on an outer if or !
condition to suppress errexit. Ensure rc is assigned before cleanup, rm -f
"$probe" always runs, and the function returns the captured status for callers
regardless of invocation context.
tests/test_opencode_private_free_model_policy_1.py (1)

17-113: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

세 테스트 파일이 동일한 97줄 헤더를 복제합니다. 공유 헬퍼 모듈이 없어 모듈 로더, run, git, commit_all, write_policy, repository fixture, evaluate가 세 번 정의되었습니다. 정책 검사기 인터페이스가 바뀌면 세 곳을 모두 수정해야 합니다. tests/conftest.py 또는 전용 헬퍼 모듈로 추출하십시오.

  • tests/test_opencode_private_free_model_policy_1.py#L17-L113: 헬퍼와 fixture를 공유 모듈로 옮기고 import로 대체하십시오.
  • tests/test_opencode_private_free_model_policy_2.py#L17-L113: 동일한 공유 모듈을 import하도록 바꾸십시오.
  • tests/test_opencode_private_free_model_policy_3.py#L17-L113: 동일한 공유 모듈을 import하도록 바꾸십시오.

참고: 세 파일 모두 sys.modules["opencode_private_free_model_policy"]에 서로 다른 모듈 객체를 등록합니다. 공유 모듈로 통합하면 이 중복 등록도 사라집니다.

🤖 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 `@tests/test_opencode_private_free_model_policy_1.py` around lines 17 - 113,
Extract the duplicated module loader, run, git, commit_all, write_policy,
repository fixture, and evaluate helpers into one shared test helper module.
Update tests/test_opencode_private_free_model_policy_1.py#L17-L113,
tests/test_opencode_private_free_model_policy_2.py#L17-L113, and
tests/test_opencode_private_free_model_policy_3.py#L17-L113 to import the shared
helpers and remove their local definitions, including separate sys.modules
registrations for opencode_private_free_model_policy.
🤖 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 `@docs/doctoring/opencode-private-free-model-policy.md`:
- Around line 63-74: 문서의 모델 목록에서 1번, 3번, 12번 항목의 잘린 `-fre` 접미사를 `-free`로 수정해
`anonymous_free_candidates` 및 `EXPECTED_FREE_CANDIDATES`와 이름을 일치시키세요.

In `@scripts/ci/opencode_private_free_model_policy.py`:
- Around line 218-219: Update the validation around EXPECTED_POLICY to compare
JSON values with strict type sensitivity, so boolean true is not accepted as
numeric 1 and vice versa. Preserve the exact canonical declaration requirement
for every field, including schema_version and allow_private_free_models, while
retaining the existing PolicyDenied behavior for mismatches.

In `@scripts/ci/opencode_provider_guard.sh`:
- Around line 16-24: Update the argument scan around previous_argument and
model_candidate to recognize both “--model candidate” and “--model=candidate”
forms. Track occurrences explicitly and reject duplicate --model values before
provider credential removal, while preserving the existing candidate validation
and single-model behavior.

In `@scripts/ci/run_opencode_review_model_pool_impl.sh`:
- Line 463: Validate OPENCODE_FATAL_ERROR_POLL_SECONDS through the existing
env_integer_or_default helper when assigning fatal_poll_seconds, preserving the
default of 5 for unset or non-integer values. Ensure the validated value is used
by the sleep call in the kill -0 polling loop.

---

Nitpick comments:
In `@scripts/ci/opencode_private_free_model_policy.py`:
- Around line 176-177: Update the validation around entry.object_sha in the
policy evaluation flow to use a dedicated object ID pattern that accepts valid
40- or 64-character hexadecimal SHAs, rather than COMMIT_SHA_PATTERN. Keep the
existing PolicyEvaluationError and invalid-SHA handling unchanged.

In `@scripts/ci/run_opencode_review_model_pool_impl.sh`:
- Around line 42-51: Update the normalize_opencode_output flow around
opencode_review_approve_gate.sh so its nonzero status is captured explicitly
without relying on an outer if or ! condition to suppress errexit. Ensure rc is
assigned before cleanup, rm -f "$probe" always runs, and the function returns
the captured status for callers regardless of invocation context.

In `@scripts/ci/run_opencode_review_model_pool.sh`:
- Around line 169-170: Register the cleanup trap before calling
install_provider_guard so cleanup_provider_guard handles failures during
temporary-directory setup, including cp or chmod errors under set -e.
- Around line 77-103: Disable pathname expansion while iterating over
OPENCODE_MODEL_CANDIDATES in candidate_list_contains_anonymous_free_model and
prepend_unique_anonymous_free_candidates, preserving intentional
whitespace-based word splitting. Restore the caller’s globbing state after each
function completes, including early returns, or use a read-based array approach
that prevents glob expansion without changing candidate parsing.

In `@tests/test_opencode_private_free_model_policy_1.py`:
- Around line 17-113: Extract the duplicated module loader, run, git,
commit_all, write_policy, repository fixture, and evaluate helpers into one
shared test helper module. Update
tests/test_opencode_private_free_model_policy_1.py#L17-L113,
tests/test_opencode_private_free_model_policy_2.py#L17-L113, and
tests/test_opencode_private_free_model_policy_3.py#L17-L113 to import the shared
helpers and remove their local definitions, including separate sys.modules
registrations for opencode_private_free_model_policy.

In `@tests/test_opencode_private_free_model_runner_contract.py`:
- Around line 206-221: Update
test_existing_public_free_pool_is_not_reordered_or_duplicated to set
base_has_policy=True while keeping head_changes_policy=False, so the policy gate
passes and the test isolates the existing public free-pool ordering behavior
without triggering the anonymous free-model early return.
🪄 Autofix

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4ef09089-44f5-44d9-997c-fbf050bce76d

📥 Commits

Reviewing files that changed from the base of the PR and between 6eb06cd and 3362860.

📒 Files selected for processing (13)
  • CHANGELOG.md
  • docs/doctoring/opencode-private-free-model-policy.md
  • docs/examples/opencode-private-free-models.json
  • scripts/ci/opencode_private_free_model_policy.py
  • scripts/ci/opencode_provider_guard.sh
  • scripts/ci/run_opencode_review_model_pool.sh
  • scripts/ci/run_opencode_review_model_pool_impl.sh
  • tests/test_opencode_delegated_runner_contract.py
  • tests/test_opencode_private_free_model_policy_1.py
  • tests/test_opencode_private_free_model_policy_2.py
  • tests/test_opencode_private_free_model_policy_3.py
  • tests/test_opencode_private_free_model_runner_contract.py
  • tests/test_opencode_provider_guard.py

Comment thread docs/doctoring/opencode-private-free-model-policy.md Outdated
Comment thread scripts/ci/opencode_private_free_model_policy.py Outdated
Comment thread scripts/ci/opencode_provider_guard.sh
Comment thread scripts/ci/run_opencode_review_model_pool_impl.sh Outdated
Expose every established central shell-gate marker at the stable model-pool entrypoint and verify the delegated implementation before any model process starts.
@seonghobae
seonghobae enabled auto-merge (squash) August 8, 2026 09:59
@opencode-agent
opencode-agent Bot disabled auto-merge August 8, 2026 10:00

@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 `@tests/test_opencode_private_free_model_runner_contract.py`:
- Around line 275-280: In test_wrapper_preserves_every_quick_gate_runner_marker,
correct the undefined wrapper_tex reference in the marker assertion loop to use
the existing wrapper_text variable read from WRAPPER.
- Line 116: Update the test fixture’s candidate-selection logic to use
OPENCODE_MODEL_CANDIDATES exclusively, remove the unused
OPENCODE_MODD_CANDIDATES fallback, and capture/assert that the first candidate
is selected because the fake opencode does not validate --model. Also correct
the undefined wrapper_tex reference to wrapper_text.
🪄 Autofix

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 42094baf-07a5-4706-8dcb-044a8071e605

📥 Commits

Reviewing files that changed from the base of the PR and between 3362860 and 23eb9f7.

📒 Files selected for processing (2)
  • scripts/ci/run_opencode_review_model_pool.sh
  • tests/test_opencode_private_free_model_runner_contract.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/ci/run_opencode_review_model_pool.sh

Comment thread tests/test_opencode_private_free_model_runner_contract.py Outdated
Comment thread tests/test_opencode_private_free_model_runner_contract.py Outdated
Correct the exact-head regression test so the stable wrapper marker contract is evaluated without truncating the final identifier.
Restore the previously verified exact runner-contract test blob while retaining the live quick-gate assertions in the central shell gate itself.

@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 `@tests/test_opencode_private_free_model_runner_contract.py`:
- Line 237: 손상된 테스트 코드를 복구해 `for script in (...)` 구문이 `WRAPPER`와
`PROVIDER_GUARD`를 순회하도록 수정하고, 각 스크립트에 대해 Bash `-n` 구문 검증을 수행하게 하십시오. 변경 후 전체 테스트
스위트를 실행해 검증하십시오.
🪄 Autofix

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 0581ad70-cdc7-4c1b-90cf-b3c384e52202

📥 Commits

Reviewing files that changed from the base of the PR and between 23eb9f7 and 58de30c.

📒 Files selected for processing (1)
  • tests/test_opencode_private_free_model_runner_contract.py

Comment thread tests/test_opencode_private_free_model_runner_contract.py Outdated

Copy link
Copy Markdown
Contributor Author

@opencode-agent address

Exact-head bounded GREEN repair for e427cfb14dfc8ff0e678b25ea44662b3be3f74b3; target implementation blob scripts/ci/run_opencode_review_model_pool_impl.sh = 986982e9af3e65cf468f993d8e858d9e1edfc5c1. Abort without writing if either identity moved.

The current branch already contains RED contracts in tests/test_opencode_private_free_model_runner_contract.py for two still-valid CodeRabbit findings. Make only the minimal implementation changes needed to satisfy them:

  1. Assign fatal_poll_seconds through the existing env_integer_or_default OPENCODE_FATAL_ERROR_POLL_SECONDS 5 helper so malformed environment input cannot make sleep fail inside the set +e polling loop and busy-spin the runner.
  2. In normalize_opencode_output, capture a nonzero opencode_review_approve_gate.sh status explicitly (for example rc=0; ... || rc=$?) so cleanup of the temporary probe always executes regardless of invocation context; return the captured status unchanged.

Do not alter model selection, credentials, review semantics, timeout policy beyond this validation, or any unrelated file. Run the focused runner contract and the repository-authoritative exact-head suite before committing. Do not merge or synthesize approval.

Copy link
Copy Markdown
Contributor Author

@opencode-agent address

Exact-head bounded GREEN repair for e427cfb14dfc8ff0e678b25ea44662b3be3f74b3; scripts/ci/run_opencode_review_model_pool_impl.sh blob is 986982e9af3e65cf468f993d8e858d9e1edfc5c1. Do not write if either identity has moved.

Current-head Strix Changed Path Quality CI run 31253529097, job 93093433574, has one deterministic failure after the rest of the suite: 1 failed, 1026 passed, 16 subtests passed. The fail-first contract is tests/test_opencode_private_free_model_runner_contract.py::test_delegated_runner_validates_poll_interval_and_cleans_normalization_probe.

Two production defects are directly evidenced in the delegated stable implementation:

  1. run_one_model_attempt() currently uses fatal_poll_seconds="${OPENCODE_FATAL_ERROR_POLL_SECONDS:-5}". Invalid/empty/non-numeric user configuration can reach sleep or create a zero-second busy loop. Use the existing trusted helper exactly as the RED contract requires:
    fatal_poll_seconds="$(env_integer_or_default OPENCODE_FATAL_ERROR_POLL_SECONDS 5)".

  2. normalize_opencode_output() calls the approval gate under set -e and assigns rc=$? on the following line. A nonzero approval-gate result can therefore terminate before rm -f "$probe", leaking the temporary normalization probe. Preserve cleanup by initializing/capturing status with an explicit non-errexit conditional, matching the existing RED contract: the gate invocation must end with >/dev/null || rc=$?, then remove the probe and return the captured status. Do not turn a gate failure into success.

Make only these minimal production repairs plus any strictly necessary test/doc wording alignment. Do not weaken the fail-first assertions, do not change provider eligibility, credentials, wrapper policy, model order, secrets, workflows, or branch protection, and do not create temporary/self-modifying workflows.

Run the focused runner contract first, then the complete repository tests, bash scripts/ci/test_strix_quick_gate.sh, Bash syntax, Python compile/docstring/coverage gates, and exact-head security gates. Commit normally to this existing branch; do not merge or synthesize approval.

Copy link
Copy Markdown
Contributor Author

@opencode-agent address

Same unchanged exact head e427cfb14dfc8ff0e678b25ea44662b3be3f74b3: include the remaining unresolved current-head CodeRabbit documentation finding in the same bounded repair. In docs/doctoring/opencode-private-free-model-policy.md, correct only the three truncated candidate IDs so the operator runbook matches the executable/test contracts exactly:

  • opencode-free/nemotron-3-ultra-freopencode-free/nemotron-3-ultra-free
  • opencode-free/north-mini-code-freopencode-free/north-mini-code-free
  • opencode-free/qwen3.6-plus-freopencode-free/qwen3.6-plus-free

Do not alter candidate ordering or any other model identifier. Validate the documentation against anonymous_free_candidates and EXPECTED_FREE_CANDIDATES as part of the same exact-head run. Resolve the review thread only after the committed text is verified.

Copy link
Copy Markdown
Contributor Author

@opencode-agent address

Repair only the exact current head e427cfb14dfc8ff0e678b25ea44662b3be3f74b3 on protected base 6eb06cdd08c79a06f7b390069d4ffa49e2eb7dba. Immediately before any write, refetch the PR head/base and scripts/ci/run_opencode_review_model_pool_impl.sh; the exact current implementation blob is 986982e9af3e65cf468f993d8e858d9e1edfc5c1. If any identity moved, do not write and re-plan from the new state.

Exact-head Strix run 31253529097, job 93093433574, passed 1,026 tests and failed only test_delegated_runner_validates_poll_interval_and_cleans_normalization_probe. The permanent test already exposes two real fail-closed defects in the delegated runner; keep the test unchanged and make only these minimal production fixes:

  1. Replace the unvalidated fatal_poll_seconds="${OPENCODE_FATAL_ERROR_POLL_SECONDS:-5}" with fatal_poll_seconds="$(env_integer_or_default OPENCODE_FATAL_ERROR_POLL_SECONDS 5)", preventing malformed/empty hostile configuration from reaching sleep or creating a busy/failing poll loop.
  2. In normalize_opencode_output, preserve cleanup when opencode_review_approve_gate.sh returns nonzero under set -e by using the existing test-required form "$HEAD_SHA" "$RUN_ID" "$RUN_ATTEMPT" "$probe" >/dev/null || rc=$? (initialize/retain rc so rm -f "$probe" always executes before returning the gate status).

Do not change the trusted-base private/free-model policy, provider credential isolation, model list/order, reviewer identities or credentials, NVIDIA NIM behavior, branch protection, tests, or unrelated model-pool semantics. Do not add a temporary/write-capable repair workflow. Run the focused private-free-model runner contract first, then the complete central suite and Strix exact-head gate. Keep the branch unmerged; any new head requires fresh exact-head security/review evidence.

seonghobae commented Aug 8, 2026

Copy link
Copy Markdown
Contributor Author

@opencode-agent address

Repair only the exact current-head deterministic/review blockers on PR #830. Live head is e427cfb14dfc8ff0e678b25ea44662b3be3f74b3, protected base is 6eb06cdd08c79a06f7b390069d4ffa49e2eb7dba, scripts/ci/run_opencode_review_model_pool_impl.sh blob is 986982e9af3e65cf468f993d8e858d9e1edfc5c1, and docs/doctoring/opencode-private-free-model-policy.md blob is 59693a35485f70f414961db2922d9a499331d2ae. Abort without writing if any head/base/target-blob identity moves.

Exact-head Strix Changed Path Quality CI run 31253529097, job 93093433574, completed 1,026 tests plus 16 subtests with exactly one reported failure at tests/test_opencode_private_free_model_runner_contract.py::test_delegated_runner_validates_poll_interval_and_cleans_normalization_probe. Two current CodeRabbit threads on this same head are also valid: the fatal poll interval is unvalidated, and doctoring truncates three governed model IDs.

Make the smallest repair, limited to the delegated implementation, its focused regression only if needed to cover zero, and the doctoring list:

  1. In run_one_model_attempt, replace raw ${OPENCODE_FATAL_ERROR_POLL_SECONDS:-5} consumption with fatal_poll_seconds="$(env_integer_or_default OPENCODE_FATAL_ERROR_POLL_SECONDS 5)", then fail safe from zero as well ([ "$fatal_poll_seconds" -gt 0 ] || fatal_poll_seconds=5) so malformed, negative, or zero configuration cannot create a no-delay watcher loop. Preserve the existing sleep call and default 5 seconds. If the current regression does not cover zero, add one bounded focused assertion/test before the production change; do not weaken the existing RED assertion.
  2. In normalize_opencode_output, capture approval-gate rejection without relying on caller if ! context: set rc=0 before invoking opencode_review_approve_gate.sh, run the gate as ... "$probe" >/dev/null || rc=$?, then keep unconditional rm -f "$probe" and return "$rc". Do not convert normalization failure or gate rejection into success.
  3. In docs/doctoring/opencode-private-free-model-policy.md, correct only the three truncated governed IDs: nemotron-3-ultra-frenemotron-3-ultra-free, north-mini-code-frenorth-mini-code-free, and qwen3.6-plus-freqwen3.6-plus-free.

Do not modify wrapper governance, provider credential isolation, candidate ordering, workflows, permissions, CHANGELOG, unrelated tests, or any other file. Run the focused runner contract, relevant delegated-runner tests, Bash syntax, and doc/model-name consistency before committing, then let normal exact-head CI/security/Strix and review gates rerun. Do not mark Ready/merge/release, resolve unrelated threads, or synthesize approval.

Copy link
Copy Markdown
Contributor Author

@opencode-agent

Perform a read-only formal review of exact current head 9a9b3e061599c28905aed793fc803123a2615205 against protected base 6eb06cdd08c79a06f7b390069d4ffa49e2eb7dba for PR #830. Re-fetch both identities before review and do not write, address, merge, or synthesize approval if either moved.

RCA focus: the former blanket private-repository exclusion conflated repository visibility with data classification. Verify that the replacement is operationally realistic and fail-closed: anonymous opencode-free/* candidates activate only from an unchanged trusted-base canonical public_equivalent declaration; a PR cannot self-enable; anonymous/free and export subprocesses receive no provider secrets, GitHub token, Actions OIDC/runtime/cache/results credentials, or unrelated provider keys; private repositories without the trusted-base opt-in remain on the private-safe keyed path.

All exact-head GitHub Actions checks currently report success and all inline review threads are resolved/outdated. Review the current source and bounded evidence independently. Submit a formal APPROVE only if affirmative source-backed evidence supports the contract; otherwise submit source-anchored REQUEST_CHANGES. Do not treat secret-scan success alone as proof that repository content is public-equivalent.

Copy link
Copy Markdown
Contributor Author

Operational closure is tracked in #833. Code-level merge is not considered sufficient: after protected integration, the scheduled central loop must execute one opted-in private public_equivalent canary and one private negative control, verify provider/GitHub/Actions credential absence in the anonymous subprocess, preserve keyed fallback and review/merge gates, and demonstrate rollback or a deterministic rollback rehearsal. Auto-merge is enabled for this unchanged head, but it remains gated by a qualifying independent formal approval and normal repository protection.

Copy link
Copy Markdown
Contributor Author

@cwl-noema-review
@opencode-agent

Please perform independent review-only evaluation of exact current head 9a9b3e061599c28905aed793fc803123a2615205 against protected base 6eb06cdd08c79a06f7b390069d4ffa49e2eb7dba. Do not update the branch, merge, enable auto-merge, or weaken any gate. Re-read the exact head before publishing a formal review; if the head moved, abort this request as stale. Focus on the trusted-base public_equivalent opt-in, provider-credential isolation, fail-closed private-repository behavior, and the latest poll/probe cleanup fixes. A qualifying approval must be a real non-author formal review on this exact head; status-only/comment-only output is not approval.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please perform a fresh full review of unchanged exact head 9a9b3e061599c28905aed793fc803123a2615205. Earlier rate-limited and predecessor-head review evidence is not acceptance; verify the final base-to-head diff and report only current valid findings.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

@seonghobae I will perform a fresh full review of PR #830. I will evaluate the current base-to-head diff and report only findings that apply to the current head.

⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 4 minutes.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

The prior exact-head request was rate-limited and its stated cooldown has elapsed. Please now perform one fresh full review of unchanged head 9a9b3e061599c28905aed793fc803123a2615205 against base 6eb06cdd08c79a06f7b390069d4ffa49e2eb7dba. Do not treat predecessor-head findings as current; report only still-valid base-to-head findings.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

@seonghobae I will perform a fresh full review of PR #830. I will evaluate the current base-to-head diff and report only findings that apply to the current head.

⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 34 minutes.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Exact-current-head full review request for 9a9b3e061599c28905aed793fc803123a2615205. The previous organization rate-limit window reported at 2026-08-08 22:14 KST has elapsed. Please review the complete base 6eb06cdd08c79a06f7b390069d4ffa49e2eb7dba → head diff. Treat the trusted-base private/free-model policy, provider-scoped credential isolation, self-enablement denial, negative-control path, and fail-closed exhaustion behavior as security-critical. Do not infer approval from successful checks alone.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

@seonghobae I will perform a fresh full review of PR #830. I will verify the current base-to-head diff and report only findings that apply to the current head. I will examine trusted-base opt-in validation, credential isolation, self-enablement denial, negative-control behavior, and fail-closed exhaustion behavior.

⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 4 minutes.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

The reported organization review cooldown has now elapsed. Re-requesting one full review for unchanged exact head 9a9b3e061599c28905aed793fc803123a2615205 against base 6eb06cdd08c79a06f7b390069d4ffa49e2eb7dba. Please review the complete diff, with particular attention to trusted-base-only opt-in, PR self-enablement denial, private negative-control behavior, provider-scoped credential isolation, and fail-closed exhaustion. Do not infer approval from green CI alone.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

@seonghobae I will perform a fresh full review of PR #830. I will review the complete base-to-head diff and report only findings that apply to the current head. I will not infer approval from successful CI checks.

⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 1 minute.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please perform one fresh full review of exact head 9a9b3e061599c28905aed793fc803123a2615205 against protected base 6eb06cdd08c79a06f7b390069d4ffa49e2eb7dba. The previous organization cooldown has elapsed. Treat this as review-only evidence: do not mutate the branch, and do not treat advisory review as the counted independent human approval required by branch protection. Focus on the trusted-base public_equivalent opt-in, prohibition on PR self-enablement, and anonymous/free subprocess credential isolation. If review capacity is still unavailable, report the capacity condition once; no retry is required from this comment.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Live PR identity =='
gh api repos/ContextualWisdomLab/.github/pulls/830 \
  --jq '{number, state, base: .base.sha, head: .head.sha, updated_at}'

printf '%s\n' '== Local commit identities =='
git rev-parse HEAD
git rev-parse 6eb06cdd08c79a06f7b390069d4ffa49e2eb7dba^{commit}
git rev-parse 9a9b3e061599c28905aed793fc803123a2615205^{commit}

printf '%s\n' '== Changed files =='
git diff --name-status 6eb06cdd08c79a06f7b390069d4ffa49e2eb7dba 9a9b3e061599c28905aed793fc803123a2615205

printf '%s\n' '== Relevant file outlines =='
ast-grep outline scripts/ci/opencode_private_free_model_policy.py --items all
ast-grep outline tests/test_opencode_provider_guard.py --items all
ast-grep outline tests/test_opencode_private_free_model_runner_contract.py --items all

printf '%s\n' '== Relevant symbols and credential references =='
rg -n -C 3 --glob 'scripts/ci/*.sh' --glob 'scripts/ci/*.py' \
  'anonymous_free_candidates|evaluate_policy|require_policy_unchanged|policy_blob_entry|normalize_opencode_output|run_one_model_attempt|OPENCODE_FATAL_ERROR_POLL_SECONDS|OPENCODE_REAL_BIN|GITHUB_TOKEN|ACTIONS_ID_TOKEN|ACTIONS_RUNTIME|OPENCODE_' \
  scripts/ci

Length of output: 137696


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Policy checker =='
sed -n '1,290p' scripts/ci/opencode_private_free_model_policy.py

printf '%s\n' '== Wrapper =='
sed -n '1,260p' scripts/ci/run_opencode_review_model_pool.sh

printf '%s\n' '== Provider guard =='
sed -n '1,180p' scripts/ci/opencode_provider_guard.sh

printf '%s\n' '== Delegated runner: normalization and model execution =='
sed -n '1,70p;449,545p;760,815p' scripts/ci/run_opencode_review_model_pool_impl.sh

printf '%s\n' '== Focused runner contract =='
sed -n '1,310p' tests/test_opencode_private_free_model_runner_contract.py

printf '%s\n' '== Provider-guard contract =='
sed -n '1,240p' tests/test_opencode_provider_guard.py

printf '%s\n' '== Find workflow model-pool invocation =='
rg -n -C 18 --glob '*.yml' --glob '*.yaml' \
  'Run OpenCode PR Review model pool|OPENCODE_MODEL_CANDIDATES|is_private|opencode-free|run_opencode_review_model_pool' \
  .github

printf '%s\n' '== Policy tests: self-enablement and canonical policy =='
rg -n -C 12 --glob 'test_opencode_private_free_model_policy_*.py' \
  'self|unchanged|canonical|VALID_POLICY|duplicate|symlink|missing' tests

Length of output: 136034


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Direct OpenCode invocation sites =='
rg -n -C 4 -P '\bopencode\s+(run|export)\b|\bOPENCODE_REAL_BIN\b|install_provider_guard\b' \
  scripts/ci/run_opencode_review_model_pool.sh \
  scripts/ci/run_opencode_review_model_pool_impl.sh \
  scripts/ci/opencode_provider_guard.sh \
  .github/workflows/opencode-review-dispatch.yml

printf '%s\n' '== Complete model-pool environment and execution block =='
sed -n '4276,4395p' .github/workflows/opencode-review-dispatch.yml

printf '%s\n' '== Credential-like names present in changed scripts =='
rg -n -o --glob 'opencode_private_free_model_policy.py' --glob 'opencode_provider_guard.sh' \
  --glob 'run_opencode_review_model_pool*.sh' \
  '[A-Z][A-Z0-9_]*(TOKEN|KEY|SECRET|PASSWORD|CREDENTIAL|ACTIONS_[A-Z0-9_]+)' scripts/ci \
  | sort -u

printf '%s\n' '== Changed documentation candidate IDs =='
rg -n -C 1 'opencode-free/' docs/doctoring/opencode-private-free-model-policy.md

printf '%s\n' '== Current PR checks =='
gh pr checks 830 --repo ContextualWisdomLab/.github || true

printf '%s\n' '== Final live PR identity =='
gh api repos/ContextualWisdomLab/.github/pulls/830 \
  --jq '{base: .base.sha, head: .head.sha, state, updated_at}'

Length of output: 29726


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Failed-check diagnostic job environment =='
sed -n '4925,4985p' .github/workflows/opencode-review-dispatch.yml

printf '%s\n' '== Failed-check diagnostic model selection and OpenCode calls =='
sed -n '6220,6375p' .github/workflows/opencode-review-dispatch.yml

printf '%s\n' '== Diagnostic model variable definitions =='
rg -n -C 8 -P '(^|[[:space:]])MODEL=|MODEL:|model_candidate|failed-check diagnosis|diagnos' \
  .github/workflows/opencode-review-dispatch.yml | tail -n 260

printf '%s\n' '== All direct OpenCode execution commands in the workflow =='
rg -n -C 5 -P '\bopencode\s+(run|export)\b' .github/workflows/opencode-review-dispatch.yml

Length of output: 37474


@seonghobae REQUEST_CHANGES

P1 — Guard the failed-check diagnosis subprocess

The provider guard protects the model-pool subprocesses. It does not protect the direct failed-check diagnosis subprocess.

The job environment provides STRIX_GITHUB_MODELS_TOKEN, OPENAI_API_KEY, NVIDIA_API_KEY, and NVIDIA_NIM_API_KEY. It also inherits Actions runtime, cache, and results credentials. At Line 6332, the workflow starts opencode run directly. At Line 6347, it starts opencode export directly. These commands remove only GitHub tokens and the two OIDC variables. They do not remove unrelated provider credentials or Actions runtime credentials.

The selected model is github-models/deepseek/deepseek-v3-0324. This process must receive only STRIX_GITHUB_MODELS_TOKEN. It must not receive the OpenAI, NVIDIA, or Actions runtime credential set.

Route this diagnostic path through the same provider-credential guard, or apply an equivalent complete environment scrub before both commands. Keep the selected-provider-only rule for run and the zero-provider-credential rule for export.

The PR head and base remained the requested commits during this review. I did not mutate the branch or infer approval from the passing checks.

You are interacting with an AI system.

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please perform one fresh full review of exact current head 9a9b3e061599c28905aed793fc803123a2615205 against protected base 6eb06cdd08c79a06f7b390069d4ffa49e2eb7dba. The prior organization cooldown has elapsed. Revalidate the trusted-base private/free-model opt-in, PR self-enablement refusal, provider-scoped credential isolation, fail-closed negative path, and current tests/docs. Do not treat rate-limit/provider capacity as a source defect, and do not infer counted human approval from automated review.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='6eb06cdd08c79a06f7b390069d4ffa49e2eb7dba'
head='9a9b3e061599c28905aed793fc803123a2615205'
repo='ContextualWisdomLab/.github'

printf '%s\n' '== Live PR identity =='
gh api "repos/${repo}/pulls/830" \
  --jq '{state, base: .base.sha, head: .head.sha, updated_at}'

printf '%s\n' '== Local commit identity =='
git rev-parse "${base}^{commit}"
git rev-parse "${head}^{commit}"
git rev-parse HEAD

printf '%s\n' '== Changed paths =='
git diff --name-status "$base" "$head"

printf '%s\n' '== Complete changed-file diff statistics =='
git diff --stat "$base" "$head"

printf '%s\n' '== OpenCode direct execution sites and guard installation =='
rg -n -C 8 -P '\bopencode\s+(run|export)\b|OPENCODE_REAL_BIN|install_provider_guard|opencode_provider_guard' \
  scripts/ci .github/workflows

printf '%s\n' '== Credential variables in changed execution paths =='
rg -n -C 4 -P 'GITHUB_TOKEN|GH_TOKEN|ACTIONS_(ID_TOKEN|RUNTIME|CACHE|RESULTS)|STRIX_GITHUB_MODELS_TOKEN|OPENAI_API_KEY|NVIDIA(_NIM)?_API_KEY|OPENCODE_' \
  scripts/ci/opencode_provider_guard.sh \
  scripts/ci/run_opencode_review_model_pool.sh \
  scripts/ci/run_opencode_review_model_pool_impl.sh \
  .github/workflows/opencode-review-dispatch.yml

printf '%s\n' '== Policy checker structure =='
ast-grep outline scripts/ci/opencode_private_free_model_policy.py --items all

printf '%s\n' '== Changed policy and runner contracts =='
ast-grep outline tests/test_opencode_private_free_model_policy_1.py --items all
ast-grep outline tests/test_opencode_private_free_model_policy_2.py --items all
ast-grep outline tests/test_opencode_private_free_model_policy_3.py --items all
ast-grep outline tests/test_opencode_private_free_model_runner_contract.py --items all
ast-grep outline tests/test_opencode_provider_guard.py --items all

Length of output: 248306


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '== Trusted-base policy checker =='
sed -n '1,280p' scripts/ci/opencode_private_free_model_policy.py

printf '%s\n' '== Wrapper policy activation and guard setup =='
sed -n '80,195p' scripts/ci/run_opencode_review_model_pool.sh

printf '%s\n' '== Provider credential guard =='
sed -n '1,140p' scripts/ci/opencode_provider_guard.sh

printf '%s\n' '== Delegated runner: normalization and invocation =='
sed -n '430,540p' scripts/ci/run_opencode_review_model_pool_impl.sh
rg -n -A35 -B10 '^normalize_opencode_output\(\)' scripts/ci/run_opencode_review_model_pool_impl.sh

printf '%s\n' '== Failed-check diagnosis environment and complete function =='
sed -n '4928,4985p' .github/workflows/opencode-review-dispatch.yml
sed -n '6260,6370p' .github/workflows/opencode-review-dispatch.yml

printf '%s\n' '== Documentation candidate list =='
rg -n -C 2 'opencode-free/' docs/doctoring/opencode-private-free-model-policy.md

printf '%s\n' '== Current test assertions for policy, guard, and diagnosis =='
rg -n -C 5 -P 'diagnos|ACTIONS_RUNTIME|ACTIONS_CACHE|ACTIONS_RESULTS|STRIX_GITHUB_MODELS_TOKEN|OPENCODE_FATAL_ERROR_POLL_SECONDS|normalize_opencode_output|policy.*head|head.*policy' \
  tests/test_opencode_private_free_model_policy_*.py \
  tests/test_opencode_private_free_model_runner_contract.py \
  tests/test_opencode_provider_guard.py

printf '%s\n' '== Current PR checks =='
gh pr checks 830 --repo ContextualWisdomLab/.github || true

printf '%s\n' '== Final live PR identity =='
gh api repos/ContextualWisdomLab/.github/pulls/830 \
  --jq '{state, base: .base.sha, head: .head.sha, updated_at}'

Length of output: 61114


@seonghobae REQUEST_CHANGES

P1 — Apply credential isolation to failed-check diagnosis

The failed-check diagnosis subprocess bypasses scripts/ci/opencode_provider_guard.sh.

The job environment provides STRIX_GITHUB_MODELS_TOKEN, OPENAI_API_KEY, NVIDIA_API_KEY, and NVIDIA_NIM_API_KEY. The selected model is github-models/deepseek/deepseek-v3-0324. At Line 6332, the workflow runs opencode run directly. At Line 6347, it runs opencode export directly.

The local env -u commands remove GitHub and OIDC credentials. They do not remove OPENAI_API_KEY, NVIDIA_API_KEY, NVIDIA_NIM_API_KEY, ACTIONS_RUNTIME_TOKEN, ACTIONS_CACHE_URL, ACTIONS_RESULTS_URL, or ACTIONS_RUNTIME_URL. The diagnosis subprocess can therefore access unrelated provider and Actions credentials.

Route both commands through the provider guard, or apply the same complete scrub in this path. The run subprocess must retain only STRIX_GITHUB_MODELS_TOKEN. The export subprocess must retain no provider credential.

The trusted-base canonical policy check, self-enablement denial, private negative path, poll interval validation, normalization-probe cleanup, and documentation candidate IDs are correct on the reviewed head. The live base and head remained unchanged during this review. Passing checks do not remove this source-level credential-isolation defect.

⚠️ Action not completed

Review rate limited.


Your included review limit is currently reached under our Fair Usage Limits Policy. This review may still proceed through usage-based billing if eligible. Your next included review will be available in 7 minutes.

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