Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/opencode-review-dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7932,14 +7932,14 @@ jobs:
&& needs.validate-pr-metadata.outputs.target_repository != ''
&& needs.validate-pr-metadata.outputs.head_sha != ''
env:
GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || steps.opencode_app_token.outputs.token || github.token }}
GH_TOKEN: ${{ needs.validate-pr-metadata.outputs.target_repository == github.repository && github.token || secrets.PR_REVIEW_MERGE_TOKEN || secrets.OPENCODE_APPROVE_TOKEN || steps.opencode_app_token.outputs.token || github.token }}
GH_REPOSITORY: ${{ needs.validate-pr-metadata.outputs.target_repository }}
PR_NUMBER: ${{ needs.validate-pr-metadata.outputs.pr_number }}
PR_HEAD_SHA: ${{ needs.validate-pr-metadata.outputs.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 }}
COVERAGE_EVIDENCE_RESULT: ${{ needs.coverage-evidence.result }}
OPENCODE_STATUS_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' }}
OPENCODE_STATUS_TOKEN_SOURCE: ${{ needs.validate-pr-metadata.outputs.target_repository == github.repository && 'github-token' || 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' }}
Comment thread
seonghobae marked this conversation as resolved.
OPENCODE_CHANGED_FILES_FILE: ${{ runner.temp }}/opencode-changed-files.txt
OPENCODE_ARTIFACT_MANIFEST_SHA256: ${{ steps.seal_artifacts.outputs.manifest_sha256 }}
OPENCODE_SOURCE_WORKDIR: ${{ runner.temp }}/opencode-pr-head
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ Semantic Versioning where the repository publishes a release.

### Fixed

- Prefer the job-scoped `github.token` when the central OpenCode dispatch
publishes a commit status back to the same `.github` repository. The job's
declared `statuses: write` permission now reaches the endpoint instead of an
unrelated OpenCode App installation token that can lack commit-status write
permission; cross-repository status publication keeps the existing explicit
PAT/App credential chain.
- Publish only the sanitized cumulative Strix report tree, avoiding a later
copy of relative scanner output that could reintroduce known internal warning
text into uploaded security evidence.
Expand Down
49 changes: 49 additions & 0 deletions docs/doctoring/opencode-same-repository-status-credential.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# OpenCode same-repository status credential

## Operator outcome

An OpenCode repository-dispatch run targeting `ContextualWisdomLab/.github`
publishes its optional `opencode-review` commit status with the current job's
`github.token`. Cross-repository targets continue to use the configured PAT or
OpenCode App installation token, because `github.token` is limited to the
repository containing the workflow.

If status publication fails, inspect the logged token-source label and the
endpoint response. Do not weaken the formal exact-head Reviews API verdict or
branch protection: the commit status is complementary evidence.

## Root cause and decision

Run 32560612401 declared `statuses: write` for the OpenCode job but selected the
separate OpenCode App token for a same-repository status write. GitHub rejected
`POST /repos/ContextualWisdomLab/.github/statuses/{sha}` with HTTP 403 because
that installation token did not carry commit-status write permission.

The smallest repair is credential precedence at the existing publication
boundary. Same-repository publication uses `github.token`, whose effective
permissions are already narrowed by the job. Cross-repository publication
retains the established PAT/App chain and the existing neutral path when only a
repository-scoped workflow token is available. No new credential, permission,
provider, retry, or fallback abstraction is introduced.

This boundary supports SOC 2 and CSAP evidence expectations by preserving
least privilege, explicit credential provenance, exact-head status binding,
and an auditable failure instead of broadening the OpenCode App installation.

## Verification

- The contract test requires both `GH_TOKEN` and its logged source to select
`github-token` first only when the target equals the workflow repository.
- The existing cross-repository notice and fail-closed exact-head review path
remain unchanged.
- The complete Python, shell, compilation, docstring, and branch-coverage gates
remain mandatory before merge.

## APA 7th references

GitHub. (n.d.). *GITHUB_TOKEN*. GitHub Docs. Retrieved August 22, 2026, from
https://docs.github.com/en/actions/concepts/security/github_token

GitHub. (n.d.). *Permissions required for GitHub Apps*. GitHub Docs. Retrieved
August 22, 2026, from
https://docs.github.com/en/rest/authentication/permissions-required-for-github-apps
10 changes: 8 additions & 2 deletions tests/test_opencode_agent_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -2063,11 +2063,17 @@ def test_opencode_runs_merge_scheduler_after_review_without_repo_local_dispatch(
" - name: Dispatch Noema after current-head OpenCode approval", 1
)[0]
assert (
"GH_TOKEN: ${{ secrets.PR_REVIEW_MERGE_TOKEN || "
"GH_TOKEN: ${{ needs.validate-pr-metadata.outputs.target_repository == "
"github.repository && github.token || secrets.PR_REVIEW_MERGE_TOKEN || "
"secrets.OPENCODE_APPROVE_TOKEN || steps.opencode_app_token.outputs.token || "
"github.token }}"
) in status_step
assert "OPENCODE_STATUS_TOKEN_SOURCE" in status_step
assert (
"OPENCODE_STATUS_TOKEN_SOURCE: ${{ "
"needs.validate-pr-metadata.outputs.target_repository == github.repository && "
"'github-token' || secrets.PR_REVIEW_MERGE_TOKEN != '' && "
"'PR_REVIEW_MERGE_TOKEN'"
) in status_step
assert "steps.opencode_app_token.outputs.available == 'true' && 'opencode-app'" in status_step
assert "OPENCODE_CHANGED_FILES_FILE" in status_step
assert "OPENCODE_ARTIFACT_MANIFEST_SHA256" in status_step
Expand Down
2 changes: 1 addition & 1 deletion tests/test_pr_review_autofix_nvidia_nim_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
DOCTORING_RECORD = Path("docs/doctoring/hourly-nvidia-nim-autofix.md")
CHANGELOG = Path("CHANGELOG.md")
REVIEW_DISPATCH_WORKFLOW = Path(".github/workflows/opencode-review-dispatch.yml")
REVIEW_DISPATCH_BLOB_SHA = "ce7939845286be9668a01d5c640e867a8490ee5c"
REVIEW_DISPATCH_BLOB_SHA = "4df21856a67776a1fdb2cd51c12e9abf1372a442"


def _workflow_text(path: Path) -> str:
Expand Down
Loading