diff --git a/.github/workflows/opencode-review.yml b/.github/workflows/opencode-review.yml index 72062c80..59204bcf 100644 --- a/.github/workflows/opencode-review.yml +++ b/.github/workflows/opencode-review.yml @@ -1473,7 +1473,7 @@ jobs: contents: read security-events: read models: read - statuses: read + statuses: write deployments: read pull-requests: write issues: write @@ -6498,6 +6498,41 @@ jobs: esac echo "::endgroup::" + - name: Publish workflow_dispatch OpenCode status + if: >- + always() + && github.event_name == 'workflow_dispatch' + && github.event.inputs.target_repository != '' + && steps.opencode_review_model_pool.outputs.review_status != '' + continue-on-error: true + env: + GH_TOKEN: ${{ github.token }} + GH_REPOSITORY: ${{ github.event.inputs.target_repository }} + PR_HEAD_SHA: ${{ github.event.inputs.pr_head_sha }} + RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + OPENCODE_MODEL_POOL_OUTCOME: ${{ steps.opencode_review_model_pool.outputs.review_status }} + run: | + set -euo pipefail + if [ -z "${PR_HEAD_SHA:-}" ]; then + echo "::warning::OpenCode workflow_dispatch status publication skipped because pr_head_sha was empty." + exit 0 + fi + + state="success" + description="OpenCode workflow_dispatch evidence passed for current head." + if [ "${OPENCODE_MODEL_POOL_OUTCOME:-}" != "success" ] && + [ "${OPENCODE_MODEL_POOL_OUTCOME:-}" != "exhausted" ]; then + state="failure" + description="OpenCode workflow_dispatch evidence did not produce approval evidence." + fi + + printf 'Publishing OpenCode workflow_dispatch status context opencode-review for %s at %s with state=%s.\n' "$GH_REPOSITORY" "$PR_HEAD_SHA" "$state" + gh api -X POST "repos/${GH_REPOSITORY}/statuses/${PR_HEAD_SHA}" \ + -f state="$state" \ + -f context="opencode-review" \ + -f target_url="$RUN_URL" \ + -f description="$description" >/dev/null + - name: Run merge scheduler after approval continue-on-error: true env: diff --git a/scripts/ci/test_strix_quick_gate.sh b/scripts/ci/test_strix_quick_gate.sh index 20b5cdf6..f7d512cc 100755 --- a/scripts/ci/test_strix_quick_gate.sh +++ b/scripts/ci/test_strix_quick_gate.sh @@ -469,6 +469,10 @@ assert_opencode_review_uses_codegraph_and_gpt5_fallback() { assert_file_contains "$workflow_file" 'COVERAGE_SOURCE_WORKDIR: ${{ github.workspace }}/pr-head' "opencode coverage measures the PR-head checkout explicitly" assert_file_contains "$workflow_file" "pr_head_ref:" "opencode workflow_dispatch carries the PR head branch required by current-head code-scanning verification" assert_file_contains "$workflow_file" 'github.event.inputs.pr_head_ref' "opencode review wires the PR head branch into current-head code-scanning verification" + assert_file_contains "$workflow_file" 'statuses: write' "opencode workflow_dispatch can publish GitHub Actions sourced current-head status evidence" + assert_file_contains "$workflow_file" "Publish workflow_dispatch OpenCode status" "opencode workflow_dispatch publishes same-head status evidence for required checks" + assert_file_contains "$workflow_file" 'context="opencode-review"' "opencode workflow_dispatch status uses the required OpenCode context" + assert_file_contains "$workflow_file" 'repos/${GH_REPOSITORY}/statuses/${PR_HEAD_SHA}' "opencode workflow_dispatch status targets the reviewed PR head" assert_file_contains "$workflow_file" "actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0" "opencode coverage cache uses the current Node 24 action runtime" assert_file_not_contains "$workflow_file" "actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57" "opencode coverage cache no longer emits the Node 20 deprecation warning" assert_file_not_contains "$workflow_file" 'ref: ${{ github.event.inputs.pr_head_sha }}' "opencode review must not checkout PR head into the trusted workflow workspace" diff --git a/tests/test_opencode_agent_contract.py b/tests/test_opencode_agent_contract.py index d483afde..709efa25 100644 --- a/tests/test_opencode_agent_contract.py +++ b/tests/test_opencode_agent_contract.py @@ -740,6 +740,11 @@ def test_opencode_runs_merge_scheduler_after_review_without_repo_local_dispatch( ) assert "Run merge scheduler after approval" in workflow + assert "Publish workflow_dispatch OpenCode status" in workflow + assert "statuses: write" in workflow + assert 'context="opencode-review"' in workflow + assert 'repos/${GH_REPOSITORY}/statuses/${PR_HEAD_SHA}' in workflow + assert "OpenCode workflow_dispatch evidence passed for current head." in workflow assert "python3 scripts/ci/pr_review_merge_scheduler.py" in workflow assert "gh workflow run pr-review-merge-scheduler.yml" not in workflow assert "github.event_name == 'pull_request_target'" in workflow