fix(opencode): allow governed free models for private repositories - #830
fix(opencode): allow governed free models for private repositories#830seonghobae wants to merge 37 commits into
Conversation
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.
|
Warning Review limit reached
Next review available in: 16 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (12)
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughPrivate 저장소의 익명 OpenCode 무료 모델 사용을 base 커밋 정책으로 제한했습니다. 모델 풀을 별도 구현으로 위임하고, 공급자별 자격 증명 격리, 실행 제어, fail-closed 테스트를 추가했습니다. ChangesOpenCode 거버넌스 및 실행 제어
Estimated code review effort: 4 (Complex) | ~75 minutes Possibly related issues
Possibly related PRs
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 상태 기록
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
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. Comment |
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.
There was a problem hiding this comment.
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
trap을install_provider_guard앞에 등록하십시오.현재
trap cleanup_provider_guard EXIT INT TERM은install_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 valueblob 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,repositoryfixture,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
📒 Files selected for processing (13)
CHANGELOG.mddocs/doctoring/opencode-private-free-model-policy.mddocs/examples/opencode-private-free-models.jsonscripts/ci/opencode_private_free_model_policy.pyscripts/ci/opencode_provider_guard.shscripts/ci/run_opencode_review_model_pool.shscripts/ci/run_opencode_review_model_pool_impl.shtests/test_opencode_delegated_runner_contract.pytests/test_opencode_private_free_model_policy_1.pytests/test_opencode_private_free_model_policy_2.pytests/test_opencode_private_free_model_policy_3.pytests/test_opencode_private_free_model_runner_contract.pytests/test_opencode_provider_guard.py
Expose every established central shell-gate marker at the stable model-pool entrypoint and verify the delegated implementation before any model process starts.
There was a problem hiding this comment.
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
📒 Files selected for processing (2)
scripts/ci/run_opencode_review_model_pool.shtests/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
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.
There was a problem hiding this comment.
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
📒 Files selected for processing (1)
tests/test_opencode_private_free_model_runner_contract.py
|
@opencode-agent address Exact-head bounded GREEN repair for The current branch already contains RED contracts in
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. |
|
@opencode-agent address Exact-head bounded GREEN repair for Current-head Strix Changed Path Quality CI run Two production defects are directly evidenced in the delegated stable implementation:
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, |
|
@opencode-agent address Same unchanged exact head
Do not alter candidate ordering or any other model identifier. Validate the documentation against |
|
@opencode-agent address Repair only the exact current head Exact-head Strix run
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. |
|
@opencode-agent address Repair only the exact current-head deterministic/review blockers on PR #830. Live head is Exact-head Strix Changed Path Quality CI run Make the smallest repair, limited to the delegated implementation, its focused regression only if needed to cover zero, and the doctoring list:
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. |
|
Perform a read-only formal review of exact current head 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 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 |
There was a problem hiding this comment.
Pull request overview
OpenCode cannot approve yet because required coverage evidence did not pass.
Review outcome
1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
-
Problem: The required coverage-evidence job result was
failure, so OpenCode cannot establish approval sufficiency for this head. -
Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.
-
Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports
successwith required evidence or explicit no-source not-applicable evidence. -
Regression test: Keep the approval branch checking
needs.coverage-evidence.result == successbefore posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present. -
Result: REQUEST_CHANGES
-
Reason: coverage-evidence result was
failure, so required test/docstring evidence was not proven for current head6cf29abc43e6a1891ea05de0a4283d8d5bf83098. -
Head SHA:
6cf29abc43e6a1891ea05de0a4283d8d5bf83098 -
Workflow run: 31273012550
-
Workflow attempt: 1
Coverage evidence
Coverage Decision
- Result: FAIL
- Test evidence: not proven passing
- Docstring evidence: not proven passing when configured
- Failure count: 1
Changed-File Evidence Map
flowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Changed file: CHANGELOG.md"]
S1 --> I1["repository behavior"]
I1 --> R1["Review risk: Changed file: CHANGELOG.md"]
R1 --> V1["required checks"]
Evidence --> S2["Docs (2 files)"]
S2 --> I2["operator or user guidance"]
I2 --> R2["Review risk: Docs (2 files)"]
R2 --> V2["docs review"]
Evidence --> S3["CI script (4 files)"]
S3 --> I3["review and security gate shell path"]
I3 --> R3["Review risk: CI script (4 files)"]
R3 --> V3["bash -n plus Strix self-test"]
Evidence --> S4["Test (6 files)"]
S4 --> I4["regression suite"]
I4 --> R4["Review risk: Test (6 files)"]
R4 --> V4["targeted test run"]
OpenCode Review Overview
Pull request overviewOpenCode cannot approve yet because required coverage evidence did not pass. Review outcome1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
Coverage evidenceCoverage Decision
Changed-File Evidence Mapflowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Changed file: CHANGELOG.md"]
S1 --> I1["repository behavior"]
I1 --> R1["Review risk: Changed file: CHANGELOG.md"]
R1 --> V1["required checks"]
Evidence --> S2["Docs (2 files)"]
S2 --> I2["operator or user guidance"]
I2 --> R2["Review risk: Docs (2 files)"]
R2 --> V2["docs review"]
Evidence --> S3["CI script (4 files)"]
S3 --> I3["review and security gate shell path"]
I3 --> R3["Review risk: CI script (4 files)"]
R3 --> V3["bash -n plus Strix self-test"]
Evidence --> S4["Test (8 files)"]
S4 --> I4["regression suite"]
I4 --> R4["Review risk: Test (8 files)"]
R4 --> V4["targeted test run"]
|
|
@opencode-agent address Exact-current-head RCA repair only. Re-fetch PR #830 immediately before writing and abort if any identity below moved:
RCA from exact-head Strix run
Feasibility screening:
Make only the minimal test-only changes necessary:
Acceptance: first rerun the four exact failing tests, then the focused private-free governance contract, provider-guard tests, complete repository pytest/coverage suite, Bash syntax, and Strix quick gate. Commit only an ordinary descendant commit on the existing branch if all intended focused tests are GREEN. Do not mark Ready/merge/approve/release; every new head must regenerate exact-head CI/security/review evidence. |
|
@opencode-agent address Exact-current-head bounded test-compatibility repair only. Re-fetch PR #830 immediately before writing and abort without writing if any identity moved:
RCA from predecessor exact-head Strix run Feasibility decision: do not add an inert old marker to production and do not weaken visibility/policy behavior. Make only the smallest test-side correction needed to assert the current delegated implementation contract. Prefer changing that stale assertion to the current Run the known failing contract first, then the complete repository suite, Strix quick gate, Python compilation, Bash syntax, and |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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 227-228: 참고 문헌의 조회 날짜를 현재 실제 날짜인 August 8, 2026으로 수정하세요. OpenCode
Zen 참고 문헌의 URL과 나머지 인용 형식은 그대로 유지하세요.
In `@scripts/ci/opencode_provider_guard.sh`:
- Around line 21-24: The model-value handling in
scripts/ci/opencode_provider_guard.sh must reject missing, selector-like, and
terminator arguments: when expect_model_value is set, treat -- as a missing
value and treat --model, -m, --model=*, and -m=* as duplicate-selector errors
instead of consuming them as the model. Extend
tests/test_opencode_provider_guard.py with these three input forms, verifying
exit code 64 and that no child process runs.
In `@scripts/ci/run_opencode_review_model_pool.sh`:
- Around line 111-121: Reject zero for OPENCODE_POOL_CYCLE_SLEEP_SECONDS by
changing its minimum validation value from 0 to 1 in
scripts/ci/run_opencode_review_model_pool.sh lines 111-121. Also update the
direct execution path in scripts/ci/run_opencode_review_model_pool_impl.sh lines
796-808 so cycle_sleep values less than or equal to 0 are restored to 60 before
the model-pool cycle sleep is used.
🪄 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: a06ada63-f56a-461e-bd82-7bccde1c5a0d
📒 Files selected for processing (9)
docs/doctoring/opencode-private-free-model-policy.mdscripts/ci/opencode_private_free_model_policy.pyscripts/ci/opencode_provider_guard.shscripts/ci/run_opencode_review_model_pool.shscripts/ci/run_opencode_review_model_pool_impl.shtests/test_opencode_model_pool_runner.pytests/test_opencode_private_free_model_policy_1.pytests/test_opencode_private_free_model_runner_contract.pytests/test_opencode_provider_guard.py
🚧 Files skipped from review as they are similar to previous changes (1)
- scripts/ci/opencode_private_free_model_policy.py
|
@opencode-agent address Supersede the earlier exact-head test-only handoff in comment
RCA from exact-head Strix run Fresh CodeRabbit review on this same head also exposed two valid fail-closed source defects:
Feasibility decision:
Implementation constraints:
Acceptance order: run the newly added RED cases first; then the exact failing agent-contract test, complete provider-guard tests, model-pool runner tests, private-free governance contract, Bash syntax for wrapper/implementation/guard, Python compilation, complete repository pytest/coverage/docstring gates, and |
There was a problem hiding this comment.
Pull request overview
OpenCode cannot approve yet because required coverage evidence did not pass.
Review outcome
1. HIGH .github/workflows/opencode-review.yml:1 - Coverage evidence did not prove required test/docstring evidence
-
Problem: The required coverage-evidence job result was
failure, so OpenCode cannot establish approval sufficiency for this head. -
Root cause: Automated approval is only valid when the same-head coverage-evidence job proves supported repository test suites passed and configured docstring gates passed or were advisory, or reports not applicable because no supported source files or package manifests exist. Missing, failed, skipped, unavailable, or unsupported-tooling test evidence is a blocker.
-
Fix: Install or configure the repository test/docstring evidence tooling when source files or package manifests exist, rerun the current-head coverage-evidence job, and approve only after it reports
successwith required evidence or explicit no-source not-applicable evidence. -
Regression test: Keep the approval branch checking
needs.coverage-evidence.result == successbefore posting APPROVE, and publish REQUEST_CHANGES when coverage-evidence blocker states such as cancelled, skipped, failed, unsupported-tooling, or below-100 evidence are present. -
Result: REQUEST_CHANGES
-
Reason: coverage-evidence result was
failure, so required test/docstring evidence was not proven for current heada18cd1a7a61dd5abaad8cf9deebcf3245158ac69. -
Head SHA:
a18cd1a7a61dd5abaad8cf9deebcf3245158ac69 -
Workflow run: 31284309359
-
Workflow attempt: 1
Coverage evidence
Coverage Decision
- Result: FAIL
- Test evidence: not proven passing
- Docstring evidence: not proven passing when configured
- Failure count: 1
Changed-File Evidence Map
flowchart LR
PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
Evidence --> S1["Changed file: CHANGELOG.md"]
S1 --> I1["repository behavior"]
I1 --> R1["Review risk: Changed file: CHANGELOG.md"]
R1 --> V1["required checks"]
Evidence --> S2["Docs (2 files)"]
S2 --> I2["operator or user guidance"]
I2 --> R2["Review risk: Docs (2 files)"]
R2 --> V2["docs review"]
Evidence --> S3["CI script (4 files)"]
S3 --> I3["review and security gate shell path"]
I3 --> R3["Review risk: CI script (4 files)"]
R3 --> V3["bash -n plus Strix self-test"]
Evidence --> S4["Test (8 files)"]
S4 --> I4["regression suite"]
I4 --> R4["Review risk: Test (8 files)"]
R4 --> V4["targeted test run"]
|
@opencode-agent address Repair only PR #830 at exact current head RCA: exact-head Strix run Feasibility: do not resurrect the obsolete literal in production, do not change wrapper governance, provider/catalog/credential logic, #624 retirement routing, workflows, branch protection, or any production file. The smallest verifiable remediation is test-only: keep the wrapper assertions that genuinely describe wrapper/governance behavior, read Run the focused failing test first, then the complete repository suite and Strix quick/quality contract appropriate to this branch. Commit an ordinary descendant commit only if the fail-first assertion becomes green without weakening any other test. Do not approve, merge, mark Draft, rebase, force-push, or synthesize review evidence. |
|
Please make exactly one test-only ownership repair on PR #830, and nothing else. Before writing, re-fetch and require all of these identities to remain unchanged: PR head RCA: Strix run Smallest accepted change: edit only Run the focused failing test first, then the complete repository suite and Strix/quality contracts available to you. Commit as an ordinary descendant only; no amend/rebase/force-push. Do not mark Ready, approve, merge, or alter branch protection. If any guard moved or a different writer becomes active, stop and report the live mismatch. |
Dismissed as stale predecessor-head infrastructure evidence. This review is anchored to 6cf29abc43e6a1891ea05de0a4283d8d5bf83098; the live PR head is c001fcb7979ed5ceef82f5eeaba97c184cc47d96, where the exact-head Strix, CodeQL, Python Security, SAST, Security Scan, Secret Scan, OSV, Scorecard, and SBOM workflows are all successful. Coverage/review infrastructure failure on an earlier head does not become a current source-code defect; a fresh exact-head semantic review remains required.
|
@coderabbitai review @cwl-noema-review @opencode-agent Review only exact current head |
🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
repo='ContextualWisdomLab/.github'
base='6eb06cdd08c79a06f7b390069d4ffa49e2eb7dba'
head='c001fcb7979ed5ceef82f5eeaba97c184cc47d96'
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' '== Requested commits =='
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' '== Changed-path statistics =='
git diff --stat "$base" "$head"
printf '%s\n' '== Source outlines =='
ast-grep outline scripts/ci/opencode_private_free_model_policy.py --items all
ast-grep outline scripts/ci/run_opencode_review_model_pool.sh --items all
ast-grep outline scripts/ci/run_opencode_review_model_pool_impl.sh --items all
ast-grep outline scripts/ci/opencode_provider_guard.sh --items all
printf '%s\n' '== Security-relevant symbols and direct OpenCode calls =='
rg -n -C 5 -P \
'evaluate_policy|require_policy_unchanged|policy_blob_entry|anonymous_free_candidates|OPENCODE_REPOSITORY_IS_PRIVATE|normalize_opencode_output|run_one_model_attempt|env_integer_or_default|OPENCODE_FATAL_ERROR_POLL_SECONDS|OPENCODE_POOL_CYCLE_SLEEP_SECONDS|OPENCODE_REAL_BIN|\bopencode\s+(run|export)\b|GITHUB_TOKEN|GH_TOKEN|ACTIONS_(ID_TOKEN|RUNTIME|CACHE|RESULTS)|STRIX_GITHUB_MODELS_TOKEN|OPENAI_API_KEY|NVIDIA(_NIM)?_API_KEY' \
scripts/ci .github/workflows
printf '%s\n' '== Relevant test outlines =='
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
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 allLength of output: 201933 🏁 Script executed: #!/bin/bash
set -euo pipefail
repo='ContextualWisdomLab/.github'
base='6eb06cdd08c79a06f7b390069d4ffa49e2eb7dba'
head='c001fcb7979ed5ceef82f5eeaba97c184cc47d96'
printf '%s\n' '== Live identity before detailed review =='
gh api "repos/${repo}/pulls/830" \
--jq '{state, base: .base.sha, head: .head.sha, updated_at}'
printf '%s\n' '== Policy checker =='
sed -n '1,285p' scripts/ci/opencode_private_free_model_policy.py
printf '%s\n' '== Governance wrapper =='
sed -n '1,260p' scripts/ci/run_opencode_review_model_pool.sh
printf '%s\n' '== Provider guard =='
sed -n '1,190p' scripts/ci/opencode_provider_guard.sh
printf '%s\n' '== Delegated normalization, credential execution, and cycle cadence =='
sed -n '20,95p;449,545p;780,815p' scripts/ci/run_opencode_review_model_pool_impl.sh
printf '%s\n' '== Failed-check diagnosis job environment and implementation =='
sed -n '4928,5010p;6248,6370p' .github/workflows/opencode-review-dispatch.yml
printf '%s\n' '== Review authority and merge-gate references =='
rg -n -C 5 -P \
'human|qualifying|automated|OpenCode App|same_head_opencode_approval_exists|approval|REQUEST_CHANGES|APPROVE|review_write_token|require.*approval' \
.github/workflows/opencode-review-dispatch.yml scripts/ci/pr_review_merge_scheduler.py docs
printf '%s\n' '== Candidate catalog consistency =='
rg -n -C 2 'anonymous_free_candidates|opencode-free/(nemotron-3-ultra-free|north-mini-code-free|qwen3\.6-plus-free)' \
scripts/ci docs tests .github/workflows/opencode-review-dispatch.yml
printf '%s\n' '== Focused diagnosis coverage =='
rg -n -C 8 -P 'failed-check diagnosis|diagnos|opencode_provider_guard|ACTIONS_RUNTIME|ACTIONS_CACHE|ACTIONS_RESULTS' \
tests scripts/ci .github/workflows/opencode-review-dispatch.yml
printf '%s\n' '== Live identity after detailed review =='
gh api "repos/${repo}/pulls/830" \
--jq '{state, base: .base.sha, head: .head.sha, updated_at}'Length of output: 202308
P1 — Apply provider credential isolation to failed-check diagnosis
The local
The selected diagnosis model is Route this path through The live PR remained on base
|
Problem and RCA
The central OpenCode review path historically used repository visibility as the proxy for anonymous/free-model eligibility. That is too coarse: a private repository can be intentionally public-equivalent, while absence of Actions secrets does not prove that tracked source, history, comments, fixtures, or generated review evidence are non-confidential.
A fresh exact-head review also exposed three distinct fail-closed defects in the first implementation: a private caller could bypass the immutable-base policy by pre-populating
opencode-free/*;git ls-tree -zoutput was reconstructed rather than requiring the real terminating NUL; and the static free alias list had drifted from the current OpenCode Zen zero-cost catalog. These are source defects and are being repaired on this branch rather than classified as reviewer-capacity or governance blockers.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 and reject a head that adds, removes, renames, chmods, or modifies its own policy. The opt-in takes effect only for a later PR after normal protected-base integration.
Never treat preconfigured
opencode-free/*text as authorization. Private or unverified callers have every anonymous candidate removed before policy evaluation; only the immutable base policy may re-enable them.Preserve public behavior only from positive visibility evidence: an explicit trusted
OPENCODE_REPOSITORY_IS_PRIVATE=false, or a credential-free successful Git read from a strictly validated public ContextualWisdomLab origin. Ambiguous, private, auth-required, malformed, or unavailable visibility evidence fails closed to the policy path.Synchronize the governed anonymous pool to the currently documented OpenCode Zen zero-cost aliases:
nemotron-3-ultra-free,deepseek-v4-flash-free,north-mini-code-free,laguna-s-2.1-free,ling-3.0-flash-free,big-pickle, andmimo-v2.5-free. Staleopencode-free/*aliases are filtered before provider execution.Scope every OpenCode subprocess to its selected provider credential. Anonymous/free and export execution receives no GitHub token, Actions OIDC/runtime/cache/results credential, NVIDIA/OpenAI/OpenRouter/OpenCode key, or unrelated provider secret.
Recognize both long and short OpenCode model selectors (
--model,--model=,-m,-m=), reject duplicate/missing selectors, and stop parsing at--.Require the trusted policy tree lookup to contain exactly one real NUL-terminated
git ls-tree -zrecord; truncated or extra records fail closed.Validate integer model-pool runtime/retry/cycle controls before Bash arithmetic or timeout consumption, with reviewed safe defaults.
Current governed free catalog
The wrapper allowlist is intentionally narrower than the generated provider configuration. The current primary Zen documentation identifies these seven zero-cost aliases:
opencode-free/nemotron-3-ultra-freeopencode-free/deepseek-v4-flash-freeopencode-free/north-mini-code-freeopencode-free/laguna-s-2.1-freeopencode-free/ling-3.0-flash-freeopencode-free/big-pickleopencode-free/mimo-v2.5-freeAliases previously labelled free for Hy3, MiniMax M3, GLM 5, Kimi K2.5, and Qwen3.6 Plus are not in the current documented zero-cost list and are no longer admitted by the wrapper. Catalog changes require a separately reviewable source change; the
opencode-free/*prefix alone is never trusted as pricing evidence.Security and governance properties
The canonical 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 proves absence of confidential facts. Secret Protection, push protection, generic/custom patterns, and CODEOWNERS remain defense in depth.The policy checker accepts only a regular non-executable
100644blob at the fixed path, strict UTF-8, at most 4,096 bytes, exact field types/values, and JSON without duplicate keys. It accepts only full 40-character base/head SHAs, ignores user/system Git configuration, disables hooks/filesystem monitors, and fails closed on missing, invalid, changed, malformed-tree, or unreadable policy state.Automated reviewer verdicts remain separate from the repository's qualifying counted independent human approval requirement. Reviewer rate limits or missing counted approval are governance/capacity evidence, not source defects and must not trigger speculative source patches.
Test-first repair after current-head review
The review-triggered repair was implemented test-first:
ls-tree -zNUL termination and extra-record rejection;-m/-m=aliases,--terminator, duplicate/missing model selector, and executable-boundary tests;Every new head invalidates predecessor-head checks/reviews. Current exact-head machine evidence is still regenerating after these repairs; queued/in-progress checks are not acceptance.
Operational acceptance
Code-level checks are necessary but not sufficient. Issue #833 remains the post-merge operational contract: separately merge the canonical policy into an authoritatively classified private low-risk canary, use a later PR to prove inherited-base activation, verify an actual
opencode-free/*selection and zero credential exposure, run a private negative control without policy, preserve keyed fallback/exhaustion fail-closed behavior, and demonstrate or deterministically rehearse rollback. If no private repository can be authoritatively classified as public-equivalent, keep the feature inactive rather than inventing eligibility.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, catalog filtering, visibility fail-closed path, and provider-scoped credential boundary rather than restoring blanket private exclusion or trusting candidate text.
Sources
Summary by CodeRabbit
새로운 기능
문서
테스트