From 9005d630f5f7a626ba882b4e8475dbbb935d1f78 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 29 Jul 2026 19:28:34 +0900 Subject: [PATCH 1/2] fix(review): expose coverage summary list read-only --- .github/workflows/opencode-review-dispatch.yml | 1 + scripts/ci/test_strix_quick_gate.sh | 1 + tests/test_opencode_agent_contract.py | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/.github/workflows/opencode-review-dispatch.yml b/.github/workflows/opencode-review-dispatch.yml index d79d9f60b..6a2bfb1d1 100644 --- a/.github/workflows/opencode-review-dispatch.yml +++ b/.github/workflows/opencode-review-dispatch.yml @@ -1293,6 +1293,7 @@ jobs: -type f \ -not -path '*/node_modules/*' \ -print >"$summary_list" + chmod 0444 "$summary_list" if [ ! -s "$summary_list" ]; then append "### JavaScript/TypeScript coverage threshold" diff --git a/scripts/ci/test_strix_quick_gate.sh b/scripts/ci/test_strix_quick_gate.sh index 6dae8aa92..ca04e6767 100755 --- a/scripts/ci/test_strix_quick_gate.sh +++ b/scripts/ci/test_strix_quick_gate.sh @@ -993,6 +993,7 @@ assert_opencode_review_uses_codegraph_and_gpt5_fallback() { assert_file_contains "$workflow_file" "JavaScript/TypeScript dependencies (npm ci, lifecycle hooks disabled)" "opencode coverage evidence installs npm workspace dependencies without lifecycle hooks before JS coverage" assert_file_contains "$workflow_file" "coverage/coverage-summary.json" "opencode coverage evidence reads JS coverage summaries instead of trusting test exit codes" assert_file_contains "$workflow_file" "coverage/coverage-final.json" "opencode coverage evidence supports Vitest Istanbul final coverage files" + assert_file_contains "$workflow_file" 'chmod 0444 "$summary_list"' "opencode coverage makes the root-created summary list readable by the unprivileged sandbox user" assert_file_contains "$workflow_file" "javascript_coverage_gate.py" "opencode coverage evidence delegates changed-source measurement to the tested central gate" assert_file_contains "$workflow_file" '--base-sha "$PR_BASE_SHA"' "opencode changed-source coverage is bound to the pull request base" assert_file_contains "$workflow_file" '--head-sha "$PR_HEAD_SHA"' "opencode changed-source coverage is bound to the current pull request head" diff --git a/tests/test_opencode_agent_contract.py b/tests/test_opencode_agent_contract.py index 3d1ca5618..80b6aff0b 100644 --- a/tests/test_opencode_agent_contract.py +++ b/tests/test_opencode_agent_contract.py @@ -397,6 +397,10 @@ def test_opencode_target_coverage_materializes_only_after_authorized_dispatch(): assert "pnpm offline install" in measure_step assert "--offline" in measure_step assert 'find "$COVERAGE_SOURCE_WORKDIR"' in measure_step + assert 'chmod 0444 "$summary_list"' in measure_step + assert measure_step.index('chmod 0444 "$summary_list"') < measure_step.index( + '--summary-list "$summary_list"' + ) assert '--repo-root "$COVERAGE_SOURCE_WORKDIR"' in measure_step assert "javascript_coverage_ran_any=1" in measure_step assert measure_step.count("check_javascript_coverage_thresholds") == 2 From 2c50ea41db9870320ae2466f1003903f1805f95c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 29 Jul 2026 19:41:30 +0900 Subject: [PATCH 2/2] test(review): scope coverage summary ordering contract --- tests/test_opencode_agent_contract.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/tests/test_opencode_agent_contract.py b/tests/test_opencode_agent_contract.py index 80b6aff0b..3c288932e 100644 --- a/tests/test_opencode_agent_contract.py +++ b/tests/test_opencode_agent_contract.py @@ -396,11 +396,20 @@ def test_opencode_target_coverage_materializes_only_after_authorized_dispatch(): assert '--store-dir "$writable_pnpm_store_dir"' in measure_step assert "pnpm offline install" in measure_step assert "--offline" in measure_step - assert 'find "$COVERAGE_SOURCE_WORKDIR"' in measure_step - assert 'chmod 0444 "$summary_list"' in measure_step - assert measure_step.index('chmod 0444 "$summary_list"') < measure_step.index( - '--summary-list "$summary_list"' + coverage_function_start = measure_step.index( + " check_javascript_coverage_thresholds() {\n" ) + coverage_function_end = measure_step.index( + "\n }\n", coverage_function_start + ) + coverage_function = measure_step[coverage_function_start:coverage_function_end] + summary_find = coverage_function.index('find "$COVERAGE_SOURCE_WORKDIR"') + summary_find_complete = coverage_function.index( + '-print >"$summary_list"', summary_find + ) + summary_chmod = coverage_function.index('chmod 0444 "$summary_list"') + summary_argument = coverage_function.index('--summary-list "$summary_list"') + assert summary_find < summary_find_complete < summary_chmod < summary_argument assert '--repo-root "$COVERAGE_SOURCE_WORKDIR"' in measure_step assert "javascript_coverage_ran_any=1" in measure_step assert measure_step.count("check_javascript_coverage_thresholds") == 2