diff --git a/.github/workflows/opencode-review.yml b/.github/workflows/opencode-review.yml index d9d3bede9..928e1ddc7 100644 --- a/.github/workflows/opencode-review.yml +++ b/.github/workflows/opencode-review.yml @@ -3916,9 +3916,13 @@ jobs: env: GH_TOKEN: ${{ steps.opencode_app_token.outputs.token || secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} CHECK_LOOKUP_GH_TOKEN: ${{ github.token }} - CODE_SCANNING_GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || steps.opencode_app_token.outputs.token || github.token }} + # The OpenCode app installation token is exchanged from api.opencode.ai + # and never carries security-events read, so it cannot read the + # code-scanning alerts API; github.token has security-events: read from + # this job's permissions block, so it is the same-repository fallback. + CODE_SCANNING_GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || github.token }} CONFIGURED_REVIEW_WRITE_TOKEN_SOURCE: ${{ steps.opencode_app_token.outputs.available == 'true' && 'opencode-app' || secrets.PR_REVIEW_MERGE_TOKEN != '' && 'PR_REVIEW_MERGE_TOKEN' || secrets.OPENCODE_APPROVE_TOKEN != '' && 'OPENCODE_APPROVE_TOKEN' || 'github-token' }} - CODE_SCANNING_TOKEN_SOURCE: ${{ secrets.PR_REVIEW_MERGE_TOKEN != '' && 'PR_REVIEW_MERGE_TOKEN' || secrets.OPENCODE_APPROVE_TOKEN != '' && 'OPENCODE_APPROVE_TOKEN' || steps.opencode_app_token.outputs.available == 'true' && 'opencode-app' || 'github-token' }} + CODE_SCANNING_TOKEN_SOURCE: ${{ secrets.PR_REVIEW_MERGE_TOKEN != '' && 'PR_REVIEW_MERGE_TOKEN' || secrets.OPENCODE_APPROVE_TOKEN != '' && 'OPENCODE_APPROVE_TOKEN' || 'github-token' }} GH_REPOSITORY: ${{ github.event.pull_request.base.repo.full_name || github.event.inputs.target_repository || github.repository }} STRIX_GITHUB_MODELS_TOKEN: ${{ secrets.STRIX_GITHUB_MODELS_TOKEN || github.token }} # Exposed so the "openai" provider in opencode.jsonc resolves during the diff --git a/tests/test_opencode_agent_contract.py b/tests/test_opencode_agent_contract.py index 5d52ca623..f478459eb 100644 --- a/tests/test_opencode_agent_contract.py +++ b/tests/test_opencode_agent_contract.py @@ -645,10 +645,21 @@ def test_workflow_provisions_sandbox_tool_and_reviewer_agent(): assert "collect_open_code_scanning_alerts" in workflow assert ( "CODE_SCANNING_GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || " - "secrets.OPENCODE_APPROVE_TOKEN || steps.opencode_app_token.outputs.token || " - "github.token }}" + "secrets.OPENCODE_APPROVE_TOKEN || github.token }}" ) in workflow + # The OpenCode app installation token never carries security-events read, so + # preferring it for the code-scanning alert lookup 403s ("Resource not + # accessible by integration") and defeats the model-unavailable fallback. + code_scanning_token_lines = [ + line for line in workflow.splitlines() if "CODE_SCANNING_GH_TOKEN:" in line + ] + assert code_scanning_token_lines + assert all("opencode_app_token" not in line for line in code_scanning_token_lines) assert "CODE_SCANNING_TOKEN_SOURCE" in workflow + code_scanning_source_lines = [ + line for line in workflow.splitlines() if "CODE_SCANNING_TOKEN_SOURCE:" in line + ] + assert all("opencode-app" not in line for line in code_scanning_source_lines) assert 'GH_TOKEN="$scan_token" timeout "$(check_lookup_api_timeout_seconds)s"' in workflow assert "Open code-scanning alert lookup skipped because no target-repository read token" in workflow assert "production source 또는 package manifest 변경이 없습니다" not in workflow